diff --git a/.eslint/typescript.eslintrc.cjs b/.eslint/typescript.eslintrc.cjs index 641970e2d..acabc7cd0 100644 --- a/.eslint/typescript.eslintrc.cjs +++ b/.eslint/typescript.eslintrc.cjs @@ -19,7 +19,7 @@ module.exports = { 'no-console': [ 'warn', { - allow: ['log', 'warn', 'error', 'assert'], + allow: ['log', 'warn', 'error', 'assert', 'table'], }, ], 'no-promise-executor-return': 'warn', @@ -28,12 +28,10 @@ module.exports = { 'no-useless-backreference': 'warn', 'require-atomic-updates': 'warn', 'array-callback-return': 'warn', - // "class-methods-use-this": "warn", 'default-case-last': 'warn', eqeqeq: ['warn', 'always'], 'grouped-accessor-pairs': 'warn', 'guard-for-in': 'warn', - // "max-classes-per-file": ["warn", 3], 'no-caller': 'warn', 'no-constructor-return': 'warn', 'no-div-regex': 'warn', @@ -74,42 +72,58 @@ module.exports = { 'no-restricted-imports': [ 'error', { - name: 'lodash', - message: 'Please use lodash-es instead.', + paths: [ + 'assert', + 'buffer', + 'child_process', + 'cluster', + 'crypto', + 'dgram', + 'dns', + 'domain', + 'events', + 'freelist', + 'fs', + 'http', + 'https', + 'module', + 'net', + 'os', + 'path', + 'punycode', + 'querystring', + 'readline', + 'repl', + 'smalloc', + 'stream', + 'string_decoder', + 'sys', + 'timers', + 'tls', + 'tracing', + 'tty', + 'url', + 'util', + 'vm', + 'zlib', + { + name: 'lodash', + message: 'Please use lodash-es instead.', + }, + { + name: 'class-validator', + importNames: ['isEmpty'], + message: + 'You probably want to import this from lodash-es instead.', + }, + ], + patterns: [ + { + group: ['*/dist/*'], + message: 'Please only import from the source.', + }, + ], }, - 'assert', - 'buffer', - 'child_process', - 'cluster', - 'crypto', - 'dgram', - 'dns', - 'domain', - 'events', - 'freelist', - 'fs', - 'http', - 'https', - 'module', - 'net', - 'os', - 'path', - 'punycode', - 'querystring', - 'readline', - 'repl', - 'smalloc', - 'stream', - 'string_decoder', - 'sys', - 'timers', - 'tls', - 'tracing', - 'tty', - 'url', - 'util', - 'vm', - 'zlib', ], 'no-useless-computed-key': ['warn', { enforceForClassMembers: true }], 'no-useless-rename': 'warn', @@ -151,7 +165,7 @@ module.exports = { markers: ['/'], }, ], - // disabled because @typescript-eslint implements them + // Disabled because @typescript-eslint implements them 'dot-notation': 'off', 'no-empty-function': 'off', 'no-unused-expressions': 'off', @@ -189,7 +203,6 @@ module.exports = { 'unicorn/no-zero-fractions': 'warn', 'unicorn/number-literal-case': 'warn', 'unicorn/numeric-separators-style': 'off', - // "unicorn/prefer-add-event-listener": "warn", 'unicorn/prefer-keyboard-event-key': 'warn', 'unicorn/prefer-array-flat-map': 'warn', 'unicorn/prefer-includes': 'warn', @@ -222,7 +235,7 @@ module.exports = { 'unicorn/prefer-array-flat': 'warn', 'unicorn/prefer-node-protocol': 'warn', 'unicorn/no-array-for-each': 'off', - // "unicorn/prevent-abbreviations": "warn", + 'unicorn/prefer-at': 'warn', 'unicorn/string-content': [ 'warn', { @@ -240,7 +253,8 @@ module.exports = { /** * @typescript-eslint */ - // "@typescript-eslint/array-type": "array-simple", + // TODO: false positive + // '@typescript-eslint/array-type': ['warn', 'array'], '@typescript-eslint/prefer-as-const': 'off', '@typescript-eslint/ban-tslint-comment': 'warn', '@typescript-eslint/class-literal-property-style': ['warn', 'fields'], @@ -265,7 +279,7 @@ module.exports = { ], '@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', - // "@typescript-eslint/explicit-member-accessibility": "warn", + '@typescript-eslint/explicit-member-accessibility': 'warn', '@typescript-eslint/member-ordering': [ 'warn', { @@ -304,7 +318,6 @@ module.exports = { 'warn', { ignoreArrowShorthand: true }, ], - // "@typescript-eslint/no-dynamic-delete": "warn", '@typescript-eslint/no-empty-interface': 'off', '@typescript-eslint/no-explicit-any': ['off'], '@typescript-eslint/no-extraneous-class': [ @@ -322,7 +335,8 @@ module.exports = { '@typescript-eslint/no-require-imports': 'warn', '@typescript-eslint/no-type-alias': 'off', '@typescript-eslint/no-unnecessary-boolean-literal-compare': 'warn', - // Because `object[key]` is always truthy for ts + // Disabled because of incorrect typings from libraries and + // checks after type assertions without `undefined` in the type '@typescript-eslint/no-unnecessary-condition': 'off', '@typescript-eslint/no-unnecessary-qualifier': 'warn', '@typescript-eslint/no-unnecessary-type-arguments': 'warn', @@ -336,14 +350,12 @@ module.exports = { '@typescript-eslint/prefer-nullish-coalescing': 'warn', '@typescript-eslint/prefer-optional-chain': 'warn', '@typescript-eslint/prefer-readonly': 'warn', - // "@typescript-eslint/prefer-readonly-parameter-types": "warn", '@typescript-eslint/prefer-reduce-type-parameter': 'warn', '@typescript-eslint/prefer-regexp-exec': 'warn', '@typescript-eslint/prefer-string-starts-ends-with': 'warn', '@typescript-eslint/prefer-ts-expect-error': 'warn', '@typescript-eslint/promise-function-async': 'warn', '@typescript-eslint/require-array-sort-compare': 'warn', - // "@typescript-eslint/strict-boolean-expressions": "warn", '@typescript-eslint/switch-exhaustiveness-check': 'warn', '@typescript-eslint/unified-signatures': 'warn', // Extension rules that should be used instead of the eslint ones: @@ -353,8 +365,7 @@ module.exports = { '@typescript-eslint/no-duplicate-imports': 'warn', '@typescript-eslint/no-empty-function': 'warn', '@typescript-eslint/no-implied-eval': 'warn', - // TODO: temprarely disable because of an runtime error: "TypeError: rules.FunctionExpression is not a function" - // '@typescript-eslint/no-invalid-this': 'warn', + '@typescript-eslint/no-invalid-this': 'warn', '@typescript-eslint/no-loop-func': 'warn', '@typescript-eslint/no-loss-of-precision': 'warn', '@typescript-eslint/no-redeclare': 'warn', @@ -386,7 +397,6 @@ module.exports = { ], '@typescript-eslint/no-misused-new': 'warn', '@typescript-eslint/no-non-null-assertion': 'off', - // "@typescript-eslint/no-param-reassign": "warn", '@typescript-eslint/no-unnecessary-type-assertion': 'off', }, }; diff --git a/.github/update-version.sh b/.github/update-version.sh new file mode 100644 index 000000000..ffd29e790 --- /dev/null +++ b/.github/update-version.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +function update_package() { + local tmpfile=`mktemp` + jq -M --indent 4 ".version = \"$2\"" "$1" > "$tmpfile" + cat "$tmpfile" > "$1" +} + +function update_swagger() { + yq eval --no-colors --indent 4 --inplace --output-format yaml ".info.version = \"$2\"" "$1" +} + +update_package "package.json" "$1" +update_package "shared/package.json" "$1" +update_package "frontend/package.json" "$1" +update_package "backend/package.json" "$1" +update_package "benchmark/package.json" "$1" + +update_swagger "docs/swagger.yml" "$1" diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml new file mode 100644 index 000000000..6bacf40f3 --- /dev/null +++ b/.github/workflows/create-release-pr.yml @@ -0,0 +1,63 @@ +name: Create Release PRs + +on: + workflow_dispatch: + inputs: + versionName: + description: 'Name of version (i.e. 1.2.3)' + required: true + +jobs: + create-release-branch: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Check out code + uses: actions/checkout@v3 + - name: Create release branch + run: git checkout -b release/v${{ github.event.inputs.versionName }} + - name: Initialize git config + run: | + git config user.name "GitHub Actions" + git config user.email noreply@github.com + - name: Update version in packages + run: bash .github/update-version.sh "${{ github.event.inputs.versionName }}" + - name: Update versions in package-locks + run: npm run setup:package-lock-only + - name: Update changelog + uses: thomaseizinger/keep-a-changelog-new-release@v1 + with: + version: ${{ github.event.inputs.versionName }} + - name: Commit updated version and changelog + run: git commit -a --message "Debug v${{ github.event.inputs.versionName }}" + - name: Push new branch + run: git push origin release/v${{ github.event.inputs.versionName }} + create-pull-requests: + runs-on: ubuntu-latest + needs: create-release-branch + permissions: + pull-requests: write + steps: + - name: Create pull request into main + uses: thomaseizinger/create-pull-request@1.3.0 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + head: release/v${{ github.event.inputs.versionName }} + base: main + title: Release v${{ github.event.inputs.versionName }} + reviewers: ${{ github.event.issue.user.login }} + body: | + This PR was created in response to a running workflow. + I've updated the version name and changelog. + - name: Create pull request into dev + uses: thomaseizinger/create-pull-request@1.3.0 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + head: release/v${{ github.event.inputs.versionName }} + base: dev + title: Release v${{ github.event.inputs.versionName }} into dev + reviewers: ${{ github.event.issue.user.login }} + body: | + This PR was created in response to a running workflow. + I've updated the version name and changelog. diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index d177a66af..0fd1820e5 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -1,6 +1,8 @@ name: Complete pipeline -on: push +on: + push: + workflow_dispatch: jobs: build: @@ -15,12 +17,12 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '16' - name: Cache node modules - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-node-modules env: cache-name: cache-node-modules @@ -32,7 +34,7 @@ jobs: backend/node_modules key: ${{ secrets.CACHE_VERSION }}-${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('package-lock.json') }} - name: Cache shared/dist - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-shared-dist env: cache-name: cache-shared-dist @@ -57,12 +59,12 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '16' - name: Cache node modules - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-node-modules env: cache-name: cache-node-modules @@ -74,7 +76,7 @@ jobs: backend/node_modules key: ${{ secrets.CACHE_VERSION }}-${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('package-lock.json') }} - name: Cache shared/dist - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-shared-dist env: cache-name: cache-shared-dist @@ -101,12 +103,12 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '16' - name: Cache node modules - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-node-modules env: cache-name: cache-node-modules @@ -118,7 +120,7 @@ jobs: backend/node_modules key: ${{ secrets.CACHE_VERSION }}-${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('package-lock.json') }} - name: Cache shared/dist - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-shared-dist env: cache-name: cache-shared-dist @@ -168,12 +170,12 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '16' - name: Cache node modules - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-node-modules env: cache-name: cache-node-modules @@ -185,7 +187,7 @@ jobs: backend/node_modules key: ${{ secrets.CACHE_VERSION }}-${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('package-lock.json') }} - name: Cache shared/dist - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-shared-dist env: cache-name: cache-shared-dist @@ -209,7 +211,7 @@ jobs: run: npm run merge-coverage if: always() - name: Upload coverage - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: always() with: name: coverage-output @@ -244,17 +246,17 @@ jobs: # Don't pull LFS to reduce bandwidth usage steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 # with: # lfs: 'true' - name: checkoutLFS - uses: actions/checkout@v2 + uses: actions/checkout@v3 # - run: git lfs pull - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: node-version: '16' - name: Cache node modules - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-node-modules env: cache-name: cache-node-modules @@ -266,7 +268,7 @@ jobs: backend/node_modules key: ${{ secrets.CACHE_VERSION }}-${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('package-lock.json') }} - name: Cache shared/dist - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-shared-dist env: cache-name: cache-shared-dist @@ -274,7 +276,7 @@ jobs: path: shared/dist key: ${{ secrets.CACHE_VERSION }}-${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('shared/src/**') }} - name: Cache Cypress binary - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-cypress with: path: ~/.cache/Cypress @@ -287,14 +289,15 @@ jobs: - name: Run migrations run: cd backend && npm run migration:run && cd .. - name: Run Cypress - uses: cypress-io/github-action@v2 + uses: cypress-io/github-action@v5 with: - start: npm run start:all - command: npm run cy:ci + start: npm --prefix .. -- run start:all + command: npm run cy:run + working-directory: frontend wait-on: 'http://localhost:4200/health, http://localhost:3201/api/health' - name: Archive cypress if: always() - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: cypress-output path: frontend/cypress-visual-screenshots @@ -313,20 +316,20 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: lfs: 'true' - name: checkoutLFS - uses: actions/checkout@v2 + uses: actions/checkout@v3 - run: git lfs pull # Source: https://docs.docker.com/ci-cd/github-actions/ - name: Login to docker - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Build and push - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v3 with: context: . file: docker/Dockerfile @@ -347,22 +350,57 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: lfs: 'true' - name: checkoutLFS - uses: actions/checkout@v2 + uses: actions/checkout@v3 + - name: Extract version + run: | + versionName=`jq -jM .version package.json` + echo "version_name=$versionName" >> "$GITHUB_ENV" - run: git lfs pull # Source: https://docs.docker.com/ci-cd/github-actions/ - name: Login to docker - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Build and push - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v3 with: context: . file: docker/Dockerfile push: true - tags: ${{ secrets.DOCKER_HUB_USERNAME }}/dfm:latest + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/dfm:latest , ${{ secrets.DOCKER_HUB_USERNAME }}/dfm:${{ env.version_name }} + + release-main: + timeout-minutes: 2 + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' + needs: [test, cypress] + permissions: + contents: write + steps: + - uses: actions/checkout@v3 + - name: Initialize mandatory git config + run: | + git config user.name "GitHub Actions" + git config user.email noreply@github.com + - name: Extract version + run: | + versionName=`jq -jM .version package.json` + echo "VERSION_NAME=$versionName" >> "$GITHUB_ENV" + - name: Extract release notes + id: extract_release_notes + uses: ffurrer2/extract-release-notes@v1 + - name: Create Release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: v${{ env.VERSION_NAME }} + release_name: v${{ env.VERSION_NAME }} + body: ${{ steps.extract_release_notes.outputs.release_notes }} + draft: false + prerelease: false diff --git a/.gitignore b/.gitignore index 657964f6a..61fd2d19f 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,10 @@ backend/coverage shared/coverage shared/tsconfig.build.tsbuildinfo + +benchmark/data/* +!benchmark/data/*.permanent.json + +.vscode/* +!.vscode/*.example +!.vscode/extensions.json diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000..a6ee44b04 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +install-links=false diff --git a/.prettierignore b/.prettierignore index 2098131c8..20069305f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,3 +5,6 @@ backend/src/database/migrations/ docker-compose.yml # same, but probably not needed .env.example + +# The states in here should not be touched by humans +benchmark/data diff --git a/.vscode/launch.json b/.vscode/launch.json.example similarity index 100% rename from .vscode/launch.json rename to .vscode/launch.json.example diff --git a/.vscode/settings.json b/.vscode/settings.json.example similarity index 100% rename from .vscode/settings.json rename to .vscode/settings.json.example diff --git a/.vscode/tasks.json b/.vscode/tasks.json.example similarity index 91% rename from .vscode/tasks.json rename to .vscode/tasks.json.example index 5fa17e1f7..3af102f51 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json.example @@ -17,6 +17,12 @@ "isBackground": true, "problemMatcher": [] }, + { + "label": "Start all but database", + "dependsOn": ["Start frontend", "Start backend", "Watch shared"], + "isBackground": true, + "problemMatcher": [] + }, { "label": "Run CI", "dependsOn": [ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..f06b2cd51 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,40 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project does **not** adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.2.3-test14] - 2023-02-23 + +### Added + +- A new team of contributors joined the project! +- Even better, we are happy to welcome a new partner: Johanniter Akademie NRW, Campus Münster der Johanniter-Unfall-Hilfe e.V. (JUH). +- Simulated regions are new elements on the map that behave similar to viewports. + - They have a flexible simulation framework for defining behaviors. + - These can contain personnel, vehicles, material and patients. +- Added customizable pages for imprint and privacy notice. +- The frontend now displays the current software version and shows a feedback button on most pages. +- Added [CHANGELOG.md](./CHANGELOG.md), a [release and versioning guide](./README.md#releases) and release actions. + +### Changed + +- Elements that are dragged to the map can be deleted or added to a transfer point directly instead of having to drop and move them. +- Various internal refactoring: + - Marked VS Code configs as examples. + - Introduced uniform abstract representation for positions. + - Added property for type distinction to all objects in the state. + - Moved lots of functionality from `OlMapManager` to feature managers. + +### Fixed + +- Moving the map no longer closes popups but can be closed with ESC. +- Minor dependency updates +- Updated deprecated actions + +[Unreleased]: https://github.com/Nils1729/digital-fuesim-manv/compare/1.2.3-test14...HEAD + +[1.2.3-test14]: https://github.com/Nils1729/digital-fuesim-manv/compare/01e8cac302299a200ecb97d4eaae7cd110db65b1...1.2.3-test14 diff --git a/README.md b/README.md index b430efbd7..9a48e082b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Digitale FüSim MANV +## If you're interested in the most recent stable release, please check out the [main](https://github.com/hpi-sam/digital-fuesim-manv/tree/main) branch. + This is the codebase for a digital implementation of the "FüSim MANV" (Führungssimulation Massenanfall von Verletzen), a German simulation system for training emergency medical services leadership personnel on how to manage [Mass Casualty Incidents](https://en.wikipedia.org/wiki/Mass-casualty_incident). **You can try it out at [https://fuesim-manv.de/](https://fuesim-manv.de/)**. @@ -16,7 +18,7 @@ The concept is as follows: - After the exercise is started, _patients_ that are not adequately treated by _personnel_ and _material_ can deteriorate and die. The goal of the _participants_ is to prevent the _patients_ from dying and transport them to the _hospitals_. To do this effectively they have to communicate with each other (via real radio devices, or remote via third-party services) and make the right decisions. - Afterward, the exercise can be evaluated via statistics and a "time-travel" feature. -This simulation has been designed in cooperation with and with support from the [Federal Academy for Civil Protection and Civil Defence](https://www.bbk.bund.de/DE/Themen/Akademie-BABZ/akademie-babz_node.html) of the [Federal Office of Civil Protection and Disaster Assistance Germany](https://www.bbk.bund.de/DE/Home/home_node.html), who are the original copyright holders of the analog "FüSim MANV" simulation system, and the [Malteser Hilfsdienst e.V. Berlin](https://www.malteser-berlin.de/). +This simulation has been designed in cooperation with and with support from the [Federal Academy for Civil Protection and Civil Defence](https://www.bbk.bund.de/DE/Themen/Akademie-BABZ/akademie-babz_node.html) of the [Federal Office of Civil Protection and Disaster Assistance Germany](https://www.bbk.bund.de/DE/Home/home_node.html), who are the original copyright holders of the analog "FüSim MANV" simulation system, and the [Malteser Hilfsdienst e.V. Berlin](https://www.malteser-berlin.de/) as well as the [Johanniter Akademie NRW, Campus Münster der Johanniter-Unfall-Hilfe e.V.](https://www.johanniter.de/bildungseinrichtungen/johanniter-akademie/johanniter-akademie-nordrhein-westfalen/standorte-der-akademie-in-nordrhein-westfalen/campus-muenster/) The simulation is implemented as a web application with an Angular frontend and NodeJS backend. @@ -24,8 +26,7 @@ This project is currently developed as a [bachelor project](https://hpi.de/en/st ## Links for collaborators -- [(internal) documentation](https://github.com/hpi-sam/BP2021HG1) -- [(internal) project-board](https://github.com/orgs/hpi-sam/projects/4). +- [(internal) Test scenarios](https://github.com/hpi-sam/digital-fuesim-manv_test-scenarios) ## Installation @@ -39,6 +40,7 @@ This project is currently developed as a [bachelor project](https://hpi.de/en/st You can (optionally) use a database for the persistence of exercise data. Look at the [relevant section](./backend/README.md#database) in the backend README for further information. Note that to not use the database you have to edit an environment variable, see the [relevant section](./backend/README.md#without-a-database). 8. (Optional) We have a list of recommended [vscode](https://code.visualstudio.com/) extensions. We strongly recommend you to use them if you are developing. You can see them via [the `@recommended` filter in the extensions panel](https://code.visualstudio.com/docs/editor/extension-marketplace#_recommended-extensions). +9. (Optional) We have prepared default settings, tasks and debug configurations for VS Code. You can find them in `.vscode/*.example`. Crete a copy of those files removing the `.example` and adjust them to your needs. The files without `.example`-Extensions are untracked so your adjustments won't be committed automatically. ### Gotchas @@ -50,6 +52,7 @@ If you want the best developer experience, make sure to always install dependenc If you are using [vscode](https://code.visualstudio.com/), you can run the [task](https://code.visualstudio.com/docs/editor/tasks) `Start all` to start everything in one go. Note that this _tries_ to start the database using `docker compose`. In case this fails please start the database in another way (see [this section in the backend README](./backend/README.md#database)). +If you're not using a database anyway, you could use the task `Start all but database` instead. ### Option 2 @@ -109,10 +112,9 @@ There are already the following [debug configurations](https://code.visualstudio - `Launch Frontend [Firefox]` (You have to install an extra extension) - `Debug Jest Tests` -In addition you can make use of the following browser extensions: +In addition, you can make use of the following browser extensions: - [Angular DevTools](https://chrome.google.com/webstore/detail/angular-devtools/ienfalfjdbdpebioblfackkekamfmbnh) -- [Redux DevTools Extension](https://github.com/zalmoxisus/redux-devtools-extension/) for [NgRx](https://ngrx.io/guide/store-devtools) ## Testing @@ -120,13 +122,15 @@ In addition you can make use of the following browser extensions: We are using [Jest](https://jestjs.io/) for our unit tests. -You can run it during development +You can run it during the development - from the terminal via `npm run test:watch` in the root, `/shared`, `/backend` or `/frontend` folder -- or via the [recommended vscode extension](https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest). +- or via the [recommended vscode extension](https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest). **(Note: this option is currently broken)** ### End to end tests +**Note: We don't really have end-to-end tests yet.** + We are using [cypress](https://www.npmjs.com/package/cypress) to run the end-to-end tests. You can find the code under `/frontend/cypress` in the repository. #### Running the tests @@ -145,6 +149,11 @@ If a test fails a new screenshot is taken and put in the `comparison` folder. If the new screenshot is the new desired result, then you only have to move it in the `baseline` folder and replace the old reference screenshot with the same name. In the `diff` folder you can see the changes between the baseline and the comparison screenshot. +## Benchmarking + +You can run the benchmarks via `npm run benchmark` in the root folder. +Look at the [benchmark readme](./benchmark/README.md) for more information. + ## Styleguide - names are never unique, ids are @@ -165,44 +174,70 @@ In the `diff` folder you can see the changes between the baseline and the compar */ ``` - You should use the keyword `TODO` to mark things that need to be done later. Whether an issue should be created is an individual decision. + - You are encouraged to add expiration conditions to your TODOs. Eslint will complain as soon as the condition is met. See [here](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/expiring-todo-comments.md) for more information. + ```ts + // TODO [engine:node@>=8]: We can use async/await now. + // TODO [typescript@>=4.9]: Use satisfies https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html#the-satisfies-operator + ``` + +## Releases + +### Versions + +Version numbers follow the pattern `${major}.${minor}.${patch}`. `major`, `minor` and `patch` are decimal numbers without leading zeroes, similar to [SemVer](https://semver.org/). But since we do not have a public API, we do not adhere to SemVer. +The major version is updated for breaking changes, i.e. old state exports of configured exercises that have never been started, cannot be imported. +The minor version is updated with every release on `main`. State exports of configured exercises from older minor versions that have never been started must successfully import and started exercises should be importable and behave consistently with older versions, although this is not strictly required. +The patch versions is incremented if and only if critical issues on `main` are being fixed during a milestone. -# Architecture +Every time a part of the version number is updated, all numbers to the right are reset to zero. +For each new release, pull requests both to `main` and `dev` are created from the same `release/` branch. For scheduled releases, such PRs are created by the `Create Release PR` workflow. + +### Workflows + +With every significant PR into `dev`, the change must be briefly described in [CHANGELOG.md](./CHANGELOG.md). Pay attention to [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +The `Create Release PR` workflow accepts a new version number and prepares two PRs, one into `dev` and one into `main`. It also updates the version number in all relevant source files and moves the `Unreleased` section in [CHANGELOG.md](./CHANGELOG.md) to a release heading, creating a new `Unreleased` section. + +Upon pushing to `main` or `dev`, GitHub Actions will build and push docker containers to Docker Hub tagged `latest` and `dev`. `latest` is additionally tagged with the current version number on `main` and a GitHub release is created. + +## Architecture This repository is a monorepo that consists of the following packages: - [frontend](./frontend) the browser-based client application ([Angular](https://angular.io/)) - [backend](./backend) the server-side application ([NodeJs](https://nodejs.org/)) -- [shared](./shared) the shared code that is used by both frontend and backend +- [benchmark](./benchmark/) benchmarks and tests some parts of the application +- [shared](./shared) the shared code that is used by the frontend, backend and the benchmark package Each package has its own `README.md` file with additional documentation. Please check them out before you start working on the project. One server can host multiple _exercises_. Multiple clients can join an exercise. A client can only join one exercise at a time. -## State management and synchronization +### State management and synchronization This is a real-time application. Each client is connected to the server via a [WebSocket connection](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API). This means you can send and listen for events over a two-way communication channel. Via [socket.io](https://socket.io/docs) it is also possible to make use of a more classic request-response API via [acknowledgments](https://socket.io/docs/v4/emitting-events/#acknowledgements). -### State, actions and reducers +#### State, actions and reducers We borrow these core concepts from [Redux](https://redux.js.org/). -#### What is an immutable JSON object? +##### What is an immutable JSON object? A JSON object is an object whose properties are only the primitives `string`, `number`, `boolean` or `null` or another JSON object or an array of any of these (only state - no `functions`). Any object reference can't occur more than once anywhere in a JSON object (including nested objects). This means especially that no circular references are possible. [An immutable object is an object whose state cannot be modified after it is created](https://en.wikipedia.org/wiki/Immutable_object). In the code immutability is conveyed via typescripts [readonly](https://www.typescriptlang.org/docs/handbook/2/objects.html#readonly-properties) and the helper type `Immutable`. -#### State +##### State A state is an immutable JSON object. Each client as well as the server has a global state for an exercise. The single point of truth for all states of an exercise is the server. All these states should be synchronized. You can find the exercise state [here](./shared/src/state.ts). -#### Action +##### Action An action is an immutable JSON object that describes what should change in a state. The changes described by each action are [atomic]() - this means either all or none of the changes described by an action are applied. @@ -210,7 +245,7 @@ Actions cannot be applied in parallel. The order of actions is important. It is a bad practice to encode part of the state in the action (or values derived/calculated from it). Instead, you should only read the state in the accompanying reducer. -#### Reducer +##### Reducer A reducer is a [pure function](https://en.wikipedia.org/wiki/Pure_function) (no side effects!) that takes a state and an action of a specific type and returns a new state where the changes described in the action are applied. A state can only be modified by a reducer. @@ -218,7 +253,7 @@ To be able to apply certain optimizations, it is advisable (but not necessary or You can find all exercise actions and reducers [here](./shared/src/store/action-reducers). Please orient yourself on the already implemented actions, and don't forget to register them in [shared/src/store/action-reducers/action-reducers.ts](shared/src/store/action-reducers/action-reducers.ts) -### Immutability +#### Immutability It isn't necessary to copy the whole immutable object by value if it should be updated. Instead, only the objects that were modified should be shallow copied recursively. [Immer](https://immerjs.github.io/immer/) provides a simple way to do this. @@ -227,7 +262,7 @@ Because the state is immutable and reducers (should) only update the properties To save a state it is enough to save its reference. Therefore it is very performant as well. If the state would have to be changed, a new reference is created as the state is immutable. -### Large values (WIP) +#### Large values (WIP) Large values (images, large text, binary, etc.) are not directly stored in the state. Instead, the store only contains UUIDs that identify the blob. The blob can be retrieved via a separate (yet to be implemented) REST API. @@ -237,7 +272,7 @@ If an action would add a new blobId to the state, the blob should have previousl A blob should only be downloaded on demand (lazy) and cached. -### Synchronisation +#### Synchronisation 1. A client gets a snapshot of the state from the server via `getState`. 2. Any time an action is applied on the server, it is sent to all clients via `performAction` and applied to them too. Due to the maintained packet ordering via a WebSocket and the fact that the synchronization of the state in the backend works synchronously, it is impossible for a client to receive actions out of order or receive actions already included in the state received by `getState`. @@ -245,22 +280,20 @@ A blob should only be downloaded on demand (lazy) and cached. 4. If the proposal was accepted, the action is applied on the server and sent to all clients via `performAction`. 5. The server responds to a proposal with a response that indicates a success or rejection via an [acknowledgment](https://socket.io/docs/v4/emitting-events/#acknowledgements). A successful response is always sent after the `performAction` was broadcasted. -### Optimistic updates +#### Optimistic updates A consequence of the synchronization strategy described before is that it takes one roundtrip from the client to the server and back to get the correct state on the client that initiated the action. This can lead to a bad user experience because of high latency. This is where optimistic updates come into play. We just assume optimistically that the proposed action will be applied on the server. Therefore we can apply the action on the client directly without waiting for a `performAction` from the server. -If the server rejects the proposal or a race condition occurs, the client corrects its state again. -In our case the [optimisticActionHandler](./frontend/src/app/core/optimistic-action-handler.ts) encapsulates this functionality. +If the server rejects the proposal or a race condition occurs, the client corrects its state again. In our case, the [optimisticActionHandler](./frontend/src/app/core/optimistic-action-handler.ts) encapsulates this functionality. The state in the frontend is not guaranteed to be correct. It is only guaranteed to automatically correct itself. If you need to read from the state to change it, you should do this inside the action reducer because the `currentState` passed into a reducer is always guaranteed to be correct. -### Performance considerations +#### Performance considerations -- Do _not_ save a very large JS primitve (a large string like a base64 encoded image) in a part of the state that is often modified (like the root). This primitive would be copied on each change. Instead, the primitive should be saved as part of a separate object. This makes use of the performance benefits of shallow copies. - Currently, every client maintains the whole state, and every action is sent to all clients. There is no way to only subscribe to a part of the state and only receive updates for that part. ## Licenses and Attributions @@ -274,6 +307,83 @@ If you need to read from the state to change it, you should do this inside the a + + + + + +
+ + +
+ Lukas Hagen +
+
+ 💻 + 👀 +
+ Student 2022/23 +
+ + +
+ Nils Hanff +
+
+ 💻 + 👀 +
+ Student 2022/23 +
+ + +
+ Benildur Nickel +
+
+ 💻 + 👀 +
+ Student 2022/23 +
+ + +
+ Lukas Radermacher +
+
+ 💻 + 👀 +
+ Student 2022/23 +
Student 2021/22
📆
- Supervisor 2021/22 + Supervisor 2021-23
@@ -375,7 +486,7 @@ If you need to read from the state to change it, you should do this inside the a
📆
- Supervisor 2021/22 + Supervisor 2021-23
diff --git a/backend/.npmrc b/backend/.npmrc new file mode 100644 index 000000000..a6ee44b04 --- /dev/null +++ b/backend/.npmrc @@ -0,0 +1 @@ +install-links=false diff --git a/backend/README.md b/backend/README.md index e9faca3af..41d55de4e 100644 --- a/backend/README.md +++ b/backend/README.md @@ -99,11 +99,6 @@ If you want to, you can also disable the database. Set the environment variable `DFM_USE_DB` (in [`../.env`](../.env)) to `false` to achieve this. Note however that this results in a) all history being saved in memory instead of on disk, and b) once the backend exits, for whatever reason, all data is gone forever. -### Migrations - -We use [state migrations](./src/database/state-migrations/) to convert outdated states to new versions. -Look at [`migrations.ts`](./src/database/state-migrations/migrations.ts) for more information. - ### Note on long term storage The current setup when using a database is that no exercises get deleted unless anyone deletes them from the UI (or, more precisely, using the HTTP request `DELETE /api/exercises/:exerciseId`). diff --git a/backend/package-lock.json b/backend/package-lock.json index 5372753d2..18f95fd82 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-backend", - "version": "0.0.0", + "version": "1.2.3-test14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-backend", - "version": "0.0.0", + "version": "1.2.3-test14", "dependencies": { "class-transformer": "^0.5.1", "class-validator": "^0.14.0", @@ -24,22 +24,22 @@ "devDependencies": { "@types/cors": "^2.8.13", "@types/express": "^4.17.15", - "@types/jest": "^29.2.4", + "@types/jest": "^29.2.5", "@types/lodash-es": "^4.17.6", "@types/node": "^16", "@types/supertest": "^2.0.12", - "@typescript-eslint/eslint-plugin": "5.47.0", - "@typescript-eslint/parser": "5.47.0", - "eslint": "^8.30.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-unicorn": "^45.0.2", "jest": "^29.3.1", "nodemon": "^2.0.20", "socket.io-client": "^4.5.4", - "ts-jest": "^29.0.3", + "ts-jest": "^29.0.5", "ts-node": "^10.9.1", - "typescript": "~4.8.2" + "typescript": "~4.9.4" }, "engines": { "node": ">=16", @@ -48,11 +48,12 @@ }, "../shared": { "name": "digital-fuesim-manv-shared", - "version": "0.0.0", + "version": "1.2.3-test14", "dependencies": { + "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", - "immer": "^9.0.16", + "immer": "^9.0.17", "lodash-es": "^4.17.21", "rbush": "^3.0.1", "rbush-knn": "github:mourner/rbush-knn", @@ -60,22 +61,22 @@ "uuid": "^9.0.0" }, "devDependencies": { - "@types/jest": "^29.2.4", + "@types/jest": "^29.2.5", "@types/lodash-es": "^4.17.6", "@types/rbush": "^3.0.0", "@types/uuid": "^9.0.0", "@types/validator": "^13.7.10", - "@typescript-eslint/eslint-plugin": "5.47.0", - "@typescript-eslint/parser": "5.47.0", - "eslint": "^8.30.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-total-functions": "6.0.0", "eslint-plugin-unicorn": "^45.0.2", "jest": "^29.3.1", - "ts-jest": "^29.0.3", + "ts-jest": "^29.0.5", "ts-node": "^10.9.1", - "typescript": "~4.8.2" + "typescript": "~4.9.4" }, "engines": { "node": ">=16", @@ -743,9 +744,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz", - "integrity": "sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -1460,9 +1461,9 @@ } }, "node_modules/@types/jest": { - "version": "29.2.4", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.4.tgz", - "integrity": "sha512-PipFB04k2qTRPePduVLTRiPzQfvMeLwUN3Z21hsAKaB/W9IIzgB2pizCL466ftJlcyZqnHoC9ZHpxLGl3fS86A==", + "version": "29.2.5", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz", + "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -1593,14 +1594,14 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.0.tgz", - "integrity": "sha512-AHZtlXAMGkDmyLuLZsRpH3p4G/1iARIwc/T0vIem2YB+xW6pZaXYXzCBnZSF/5fdM97R9QqZWZ+h3iW10XgevQ==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", + "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/type-utils": "5.47.0", - "@typescript-eslint/utils": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/type-utils": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", @@ -1626,14 +1627,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.47.0.tgz", - "integrity": "sha512-udPU4ckK+R1JWCGdQC4Qa27NtBg7w020ffHqGyAK8pAgOVuNw7YaKXGChk+udh+iiGIJf6/E/0xhVXyPAbsczw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz", + "integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/typescript-estree": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", "debug": "^4.3.4" }, "engines": { @@ -1653,13 +1654,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.0.tgz", - "integrity": "sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0" + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1670,13 +1671,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.47.0.tgz", - "integrity": "sha512-1J+DFFrYoDUXQE1b7QjrNGARZE6uVhBqIvdaXTe5IN+NmEyD68qXR1qX1g2u4voA+nCaelQyG8w30SAOihhEYg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", + "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.47.0", - "@typescript-eslint/utils": "5.47.0", + "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -1697,9 +1698,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.0.tgz", - "integrity": "sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1710,13 +1711,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.0.tgz", - "integrity": "sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1737,16 +1738,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.47.0.tgz", - "integrity": "sha512-U9xcc0N7xINrCdGVPwABjbAKqx4GK67xuMV87toI+HUqgXj26m6RBp9UshEXcTrgCkdGYFzgKLt8kxu49RilDw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", + "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/typescript-estree": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -1763,12 +1764,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.0.tgz", - "integrity": "sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/types": "5.48.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -1980,6 +1981,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -2605,9 +2624,9 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "node_modules/cookiejar": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz", - "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==" + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==" }, "node_modules/cors": { "version": "2.8.5", @@ -2999,12 +3018,12 @@ } }, "node_modules/eslint": { - "version": "8.30.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.30.0.tgz", - "integrity": "sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ==", + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", + "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.4.0", + "@eslint/eslintrc": "^1.4.1", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -3055,9 +3074,9 @@ } }, "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==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", + "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -3067,13 +3086,14 @@ } }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, "dependencies": { "debug": "^3.2.7", - "resolve": "^1.20.0" + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { @@ -3112,23 +3132,25 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "version": "2.27.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.4.tgz", + "integrity": "sha512-Z1jVt1EGKia1X9CnBCkpAOhWy8FgQ7OmJ/IblEkT82yrFU/xJaxwujaTzLWqigewwynRQ9mmHfX9MtAfhxm0sA==", "dev": true, "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.0", + "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", "has": "^1.0.3", - "is-core-module": "^2.8.1", + "is-core-module": "^2.11.0", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", "tsconfig-paths": "^3.14.1" }, "engines": { @@ -3139,12 +3161,12 @@ } }, "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "node_modules/eslint-plugin-import/node_modules/doctrine": { @@ -3159,11 +3181,14 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } }, "node_modules/eslint-plugin-unicorn": { "version": "45.0.2", @@ -5092,9 +5117,9 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -6065,9 +6090,9 @@ "dev": true }, "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==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz", + "integrity": "sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==", "dev": true, "engines": { "node": ">=6" @@ -7041,15 +7066,15 @@ } }, "node_modules/ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", + "version": "29.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz", + "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==", "dev": true, "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^29.0.0", - "json5": "^2.2.1", + "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", @@ -7139,9 +7164,9 @@ } }, "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "dependencies": { "minimist": "^1.2.0" @@ -7338,9 +7363,9 @@ } }, "node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "devOptional": true, "bin": { "tsc": "bin/tsc", diff --git a/backend/package.json b/backend/package.json index df7285997..f9317fb45 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-backend", - "version": "0.0.0", + "version": "1.2.3-test14", "type": "module", "scripts": { "start:once:linux-macos": "NODE_ENV=production node --experimental-specifier-resolution=node dist/src/index.js", @@ -49,21 +49,21 @@ "devDependencies": { "@types/cors": "^2.8.13", "@types/express": "^4.17.15", - "@types/jest": "^29.2.4", + "@types/jest": "^29.2.5", "@types/lodash-es": "^4.17.6", "@types/node": "^16", "@types/supertest": "^2.0.12", - "@typescript-eslint/eslint-plugin": "5.47.0", - "@typescript-eslint/parser": "5.47.0", - "eslint": "^8.30.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-unicorn": "^45.0.2", "jest": "^29.3.1", "nodemon": "^2.0.20", "socket.io-client": "^4.5.4", - "ts-jest": "^29.0.3", + "ts-jest": "^29.0.5", "ts-node": "^10.9.1", - "typescript": "~4.8.2" + "typescript": "~4.9.4" } } diff --git a/backend/src/database/migrate-in-database.ts b/backend/src/database/migrate-in-database.ts new file mode 100644 index 000000000..83501e4dc --- /dev/null +++ b/backend/src/database/migrate-in-database.ts @@ -0,0 +1,94 @@ +import type { UUID } from 'digital-fuesim-manv-shared'; +import { applyMigrations } from 'digital-fuesim-manv-shared'; +import type { EntityManager } from 'typeorm'; +import { RestoreError } from '../utils/restore-error'; +import { ActionWrapperEntity } from './entities/action-wrapper.entity'; +import { ExerciseWrapperEntity } from './entities/exercise-wrapper.entity'; + +export async function migrateInDatabase( + exerciseId: UUID, + entityManager: EntityManager +): Promise { + const exercise = await entityManager.findOne(ExerciseWrapperEntity, { + where: { id: exerciseId }, + }); + if (exercise === null) { + throw new RestoreError( + 'Cannot find exercise to convert in database', + exerciseId + ); + } + const initialState = JSON.parse(exercise.initialStateString); + const currentState = JSON.parse(exercise.currentStateString); + const actions = ( + await entityManager.find(ActionWrapperEntity, { + where: { exercise: { id: exerciseId } }, + select: { actionString: true }, + order: { index: 'ASC' }, + }) + ).map((action) => JSON.parse(action.actionString)); + const newVersion = applyMigrations(exercise.stateVersion, { + currentState, + history: { + initialState, + actions, + }, + }); + exercise.stateVersion = newVersion; + // Save exercise wrapper + const patch: Partial = { + stateVersion: exercise.stateVersion, + }; + patch.initialStateString = JSON.stringify(initialState); + patch.currentStateString = JSON.stringify(currentState); + await entityManager.update( + ExerciseWrapperEntity, + { id: exerciseId }, + patch + ); + // Save actions + if (actions !== undefined) { + let patchedActionsIndex = 0; + const indicesToRemove: number[] = []; + const actionsToUpdate: { + previousIndex: number; + newIndex: number; + actionString: string; + }[] = []; + actions.forEach((action, i) => { + if (action === null) { + indicesToRemove.push(i); + return; + } + actionsToUpdate.push({ + previousIndex: i, + newIndex: patchedActionsIndex++, + actionString: JSON.stringify(action), + }); + }); + if (indicesToRemove.length > 0) { + await entityManager + .createQueryBuilder() + .delete() + .from(ActionWrapperEntity) + // eslint-disable-next-line unicorn/string-content + .where('index IN (:...ids)', { ids: indicesToRemove }) + .execute(); + } + if (actionsToUpdate.length > 0) { + await Promise.all( + actionsToUpdate.map( + async ({ previousIndex, newIndex, actionString }) => + entityManager.update( + ActionWrapperEntity, + { + index: previousIndex, + exercise: { id: exerciseId }, + }, + { actionString, index: newIndex } + ) + ) + ); + } + } +} diff --git a/backend/src/database/state-migrations/impossible-migration.ts b/backend/src/database/state-migrations/impossible-migration.ts deleted file mode 100644 index 0de739d2d..000000000 --- a/backend/src/database/state-migrations/impossible-migration.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { UUID } from 'digital-fuesim-manv-shared'; -import { RestoreError } from '../../utils/restore-error'; -import type { Migration } from './migrations'; - -export const impossibleMigration: Migration = { - actions: (initialState, actions) => { - throw new RestoreError( - 'The migration is not possible', - (initialState as { id?: UUID }).id ?? 'unknown' - ); - }, - state: (state) => { - throw new RestoreError( - 'The migration is not possible', - (state as { id?: UUID }).id ?? 'unknown' - ); - }, -}; diff --git a/backend/src/database/state-migrations/migrations.ts b/backend/src/database/state-migrations/migrations.ts deleted file mode 100644 index 5cf3450e8..000000000 --- a/backend/src/database/state-migrations/migrations.ts +++ /dev/null @@ -1,227 +0,0 @@ -import type { - UUID, - StateExport, - Mutable, - ExerciseAction, -} from 'digital-fuesim-manv-shared'; -import { - cloneDeepMutable, - ExerciseState, - applyAllActions, -} from 'digital-fuesim-manv-shared'; -import type { EntityManager } from 'typeorm'; -import { RestoreError } from '../../utils/restore-error'; -import { ActionWrapperEntity } from '../entities/action-wrapper.entity'; -import { ExerciseWrapperEntity } from '../entities/exercise-wrapper.entity'; -import { addMapImageZIndex13 } from './13-add-map-image-zindex'; -import { updateEocLog3 } from './3-update-eoc-log'; -import { removeSetParticipantIdAction4 } from './4-remove-set-participant-id-action'; -import { removeStatistics5 } from './5-remove-statistics'; -import { removeStateHistory6 } from './6-remove-state-history'; -import { addPatientRemarks7 } from './7-add-patient-remarks'; -import { treatmentSystemImprovements8 } from './8-treatment-system-improvements'; -import { removeIsBeingTreated9 } from './9-remove-is-being-treated'; -import { renameDeleteTransferAction10 } from './10-rename-delete-transfer-action'; -import { addMapImageIsLocked11 } from './11-add-map-image-is-locked'; -import { renameIncorrectPatientImages12 } from './12-rename-incorrect-patient-images'; -import { impossibleMigration } from './impossible-migration'; -import { addPersonnelAndMaterialToState14 } from './14-add-personnel-and-material-templates-to-state'; - -/** - * Such a function gets the already migrated initial state of the exercise and an array of all actions (not yet migrated). - * It is expected that afterwards the actions in the provided array are migrated. - * It is not allowed to modify the order of the actions, to add an action or to remove an action. - * To indicate that an action should be removed it can be replaced by `null`. - * It may throw a {@link RestoreError} when a migration is not possible. - */ -type MigrateActionsFunction = ( - initialState: object, - actions: (object | null)[] -) => void; - -/** - * Such a function gets the not yet migrated state and is expected to mutate it to a migrated version. - * It may throw a {@link RestoreError} when a migration is not possible. - */ -type MigrateStateFunction = (state: object) => void; - -export interface Migration { - actions: MigrateActionsFunction | null; - state: MigrateStateFunction | null; -} - -// TODO: It'd probably be better not to export this -export const migrations: { - [key: number]: Migration; -} = { - 2: impossibleMigration, - 3: updateEocLog3, - 4: removeSetParticipantIdAction4, - 5: removeStatistics5, - 6: removeStateHistory6, - 7: addPatientRemarks7, - 8: treatmentSystemImprovements8, - 9: removeIsBeingTreated9, - 10: renameDeleteTransferAction10, - 11: addMapImageIsLocked11, - 12: renameIncorrectPatientImages12, - 13: addMapImageZIndex13, - 14: addPersonnelAndMaterialToState14, -}; - -export async function migrateInDatabase( - exerciseId: UUID, - entityManager: EntityManager -): Promise { - const exercise = await entityManager.findOne(ExerciseWrapperEntity, { - where: { id: exerciseId }, - }); - if (exercise === null) { - throw new RestoreError( - 'Cannot find exercise to convert in database', - exerciseId - ); - } - const initialState = JSON.parse(exercise.initialStateString); - const currentState = JSON.parse(exercise.currentStateString); - const actions = ( - await entityManager.find(ActionWrapperEntity, { - where: { exercise: { id: exerciseId } }, - select: { actionString: true }, - order: { index: 'ASC' }, - }) - ).map((action) => JSON.parse(action.actionString)); - const newVersion = applyMigrations(exercise.stateVersion, { - currentState, - history: { - initialState, - actions, - }, - }); - exercise.stateVersion = newVersion; - // Save exercise wrapper - const patch: Partial = { - stateVersion: exercise.stateVersion, - }; - patch.initialStateString = JSON.stringify(initialState); - patch.currentStateString = JSON.stringify(currentState); - await entityManager.update( - ExerciseWrapperEntity, - { id: exerciseId }, - patch - ); - // Save actions - if (actions !== undefined) { - let patchedActionsIndex = 0; - const indicesToRemove: number[] = []; - const actionsToUpdate: { - previousIndex: number; - newIndex: number; - actionString: string; - }[] = []; - actions.forEach((action, i) => { - if (action === null) { - indicesToRemove.push(i); - return; - } - actionsToUpdate.push({ - previousIndex: i, - newIndex: patchedActionsIndex++, - actionString: JSON.stringify(action), - }); - }); - if (indicesToRemove.length > 0) { - await entityManager - .createQueryBuilder() - .delete() - .from(ActionWrapperEntity) - // eslint-disable-next-line unicorn/string-content - .where('index IN (:...ids)', { ids: indicesToRemove }) - .execute(); - } - if (actionsToUpdate.length > 0) { - await Promise.all( - actionsToUpdate.map( - async ({ previousIndex, newIndex, actionString }) => - entityManager.update( - ActionWrapperEntity, - { - index: previousIndex, - exercise: { id: exerciseId }, - }, - { actionString, index: newIndex } - ) - ) - ); - } - } -} - -export function migrateStateExport( - stateExportToMigrate: StateExport -): Mutable { - const stateExport = cloneDeepMutable(stateExportToMigrate); - const propertiesToMigrate = { - currentState: stateExport.currentState, - history: stateExport.history - ? { - initialState: stateExport.history.initialState, - actions: stateExport.history.actionHistory, - } - : undefined, - }; - const newVersion = applyMigrations( - stateExport.dataVersion, - propertiesToMigrate - ); - stateExport.dataVersion = newVersion; - stateExport.currentState = propertiesToMigrate.currentState; - if (stateExport.history) { - stateExport.history.actionHistory = - // Remove actions that are marked to be removed by the migrations - propertiesToMigrate.history!.actions.filter( - (action) => action !== null - ); - } - return stateExport; -} - -/** - * Migrates {@link propertiesToMigrate} to the newest version ({@link ExerciseState.currentStateVersion}) - * by mutating them. - * - * @returns The new state version - */ -function applyMigrations( - currentStateVersion: number, - propertiesToMigrate: { - currentState: object; - history?: { initialState: object; actions: (object | null)[] }; - } -): number { - const targetVersion = ExerciseState.currentStateVersion; - for (let i = currentStateVersion + 1; i <= targetVersion; i++) { - const stateMigration = migrations[i]!.state; - if (stateMigration !== null) { - if (propertiesToMigrate.history) - stateMigration(propertiesToMigrate.history.initialState); - else stateMigration(propertiesToMigrate.currentState); - } - if (!propertiesToMigrate.history) continue; - const actionMigration = migrations[i]!.actions; - if (actionMigration !== null) { - actionMigration( - propertiesToMigrate.history.initialState, - propertiesToMigrate.history.actions - ); - } - } - if (propertiesToMigrate.history) - propertiesToMigrate.currentState = applyAllActions( - propertiesToMigrate.history.initialState as ExerciseState, - propertiesToMigrate.history.actions.filter( - (action) => action !== null - ) as ExerciseAction[] - ); - return targetVersion; -} diff --git a/backend/src/exercise/exercise-wrapper.ts b/backend/src/exercise/exercise-wrapper.ts index f0ff834cf..73a50ea2d 100644 --- a/backend/src/exercise/exercise-wrapper.ts +++ b/backend/src/exercise/exercise-wrapper.ts @@ -1,33 +1,33 @@ -import type { EntityManager } from 'typeorm'; -import { LessThan } from 'typeorm'; import type { ExerciseAction, - StateExport, ExerciseIds, + ExerciseTimeline, Role, + StateExport, UUID, - ExerciseTimeline, } from 'digital-fuesim-manv-shared'; import { - ExerciseState, - cloneDeepMutable, applyAction, - ReducerError, + cloneDeepMutable, + ExerciseState, reduceExerciseState, - validateExerciseState, + ReducerError, validateExerciseAction, + validateExerciseState, } from 'digital-fuesim-manv-shared'; -import { IncrementIdGenerator } from '../utils/increment-id-generator'; -import { ValidationErrorWrapper } from '../utils/validation-error-wrapper'; +import type { EntityManager } from 'typeorm'; +import { LessThan } from 'typeorm'; +import { Config } from '../config'; +import type { ActionWrapperEntity } from '../database/entities/action-wrapper.entity'; import { ExerciseWrapperEntity } from '../database/entities/exercise-wrapper.entity'; +import { migrateInDatabase } from '../database/migrate-in-database'; import { NormalType } from '../database/normal-type'; import type { DatabaseService } from '../database/services/database-service'; -import { Config } from '../config'; +import { pushAll, removeAll } from '../utils/array'; +import { IncrementIdGenerator } from '../utils/increment-id-generator'; import { RestoreError } from '../utils/restore-error'; import { UserReadableIdGenerator } from '../utils/user-readable-id-generator'; -import type { ActionWrapperEntity } from '../database/entities/action-wrapper.entity'; -import { migrateInDatabase } from '../database/state-migrations/migrations'; -import { pushAll, removeAll } from '../utils/array'; +import { ValidationErrorWrapper } from '../utils/validation-error-wrapper'; import { ActionWrapper } from './action-wrapper'; import type { ClientWrapper } from './client-wrapper'; import { exerciseMap } from './exercise-map'; diff --git a/backend/src/exercise/patient-ticking.ts b/backend/src/exercise/patient-ticking.ts index 1f6039936..de3f323ab 100644 --- a/backend/src/exercise/patient-ticking.ts +++ b/backend/src/exercise/patient-ticking.ts @@ -7,7 +7,6 @@ import type { import { getElement, healthPointsDefaults, - isAlive, Patient, } from 'digital-fuesim-manv-shared'; @@ -29,7 +28,7 @@ export function patientTick( return ( Object.values(state.patients) // Only look at patients that are alive and have a position, i.e. are not in a vehicle - .filter((patient) => isAlive(patient.health) && patient.position) + .filter((patient) => Patient.canBeTreated(patient)) .map((patient) => { // update the time a patient is being treated, to check for pretriage later const treatmentTime = Patient.isTreatedByPersonnel(patient) diff --git a/backend/src/exercise/websocket-handler/secure-on.ts b/backend/src/exercise/websocket-handler/secure-on.ts index 25f2ffa53..a14e5c678 100644 --- a/backend/src/exercise/websocket-handler/secure-on.ts +++ b/backend/src/exercise/websocket-handler/secure-on.ts @@ -1,5 +1,7 @@ import type { ClientToServerEvents } from 'digital-fuesim-manv-shared'; +// eslint-disable-next-line no-restricted-imports import type { SocketReservedEventsMap } from 'socket.io/dist/socket'; +// eslint-disable-next-line no-restricted-imports import type { ReservedOrUserEventNames, ReservedOrUserListener, diff --git a/backend/src/fuesim-server.spec.ts b/backend/src/fuesim-server.spec.ts index 0d4cd3528..ae28339a5 100644 --- a/backend/src/fuesim-server.spec.ts +++ b/backend/src/fuesim-server.spec.ts @@ -38,6 +38,7 @@ describe('Exercise saving', () => { alarmGroup: { alarmGroupVehicles: {}, id: uuid(), + type: 'alarmGroup', name: 'Alarm Group', }, }, diff --git a/backend/src/utils/import-exercise.ts b/backend/src/utils/import-exercise.ts index a1d34d1e8..54ca04939 100644 --- a/backend/src/utils/import-exercise.ts +++ b/backend/src/utils/import-exercise.ts @@ -1,12 +1,12 @@ import { plainToInstance } from 'class-transformer'; import type { ExerciseIds } from 'digital-fuesim-manv-shared'; import { + migrateStateExport, ReducerError, StateExport, validateExerciseExport, } from 'digital-fuesim-manv-shared'; import type { DatabaseService } from '../database/services/database-service'; -import { migrateStateExport } from '../database/state-migrations/migrations'; import { ExerciseWrapper } from '../exercise/exercise-wrapper'; import type { HttpResponse } from '../exercise/http-handler/utils'; diff --git a/benchmark/.eslintrc.json b/benchmark/.eslintrc.json new file mode 100644 index 000000000..4509eeec6 --- /dev/null +++ b/benchmark/.eslintrc.json @@ -0,0 +1,21 @@ +{ + "root": true, + "overrides": [ + { + "files": ["*.ts", "*.js"], + "parserOptions": { + "project": ["tsconfig.json"], + "createDefaultProgram": true, + // TODO: No idea why eslint seems to look for the tsconfig in the root directory instead of relative to this config + // It doesn't seem to do this in "shared" + "tsconfigRootDir": "./benchmark" + }, + "parser": "@typescript-eslint/parser", + "extends": [ + "../.eslint/typescript.eslintrc.cjs", + "../.eslint/total-functions.eslintrc.cjs", + "prettier" + ] + } + ] +} diff --git a/benchmark/.gitignore b/benchmark/.gitignore new file mode 100644 index 000000000..29637c64e --- /dev/null +++ b/benchmark/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +data/* +!data/*.permanent.json diff --git a/benchmark/.npmrc b/benchmark/.npmrc new file mode 100644 index 000000000..a6ee44b04 --- /dev/null +++ b/benchmark/.npmrc @@ -0,0 +1 @@ +install-links=false diff --git a/benchmark/README.md b/benchmark/README.md new file mode 100644 index 000000000..89655a918 --- /dev/null +++ b/benchmark/README.md @@ -0,0 +1,21 @@ +# Benchmarks + +This package contains benchmarks that can be used to + +- track and compare the performance of different exerciseExports +- check different exerciseExports and the current reducers for correctness +- test migrations on different exerciseExports +- run custom benchmarks and tests - good for fast prototyping + +## Running the benchmarks + +The benchmarks are run on all exerciseExports in [`data/`](data/). +To test custom or confidential exerciseExports, add them to the [`data/`](data/) folder. Only exerciseExports ending with `.permanent.json` are tracked by git. +The benchmarks can be run with `npm run benchmark`. + +## Architecture + +The entry point to the benchmarks is [`src/app.ts`](src/app.ts). + +If you want to check the implementation of a specific benchmark or want to add a new one look in [`src/steps.ts`](src/steps.ts). +To add a new benchmark, add a new step to the `steps` array in [`src/steps.ts`](src/steps.ts) and modify the stepState. diff --git a/benchmark/data/empty-state-version-14.permanent.json b/benchmark/data/empty-state-version-14.permanent.json new file mode 100644 index 000000000..97efd5bb5 --- /dev/null +++ b/benchmark/data/empty-state-version-14.permanent.json @@ -0,0 +1 @@ +{"fileVersion":1,"dataVersion":14,"type":"complete","currentState":{"id":"c1bffad0-e5d3-49ef-930e-21a9a2d1c5d0","currentTime":0,"currentStatus":"notStarted","viewports":{},"vehicles":{},"personnel":{},"patients":{},"materials":{},"mapImages":{},"transferPoints":{},"hospitals":{},"hospitalPatients":{},"alarmGroups":{},"clients":{"1a4d8d3f-3a6d-47af-9a23-bfc814d1b559":{"id":"1a4d8d3f-3a6d-47af-9a23-bfc814d1b559","name":"","role":"trainer","isInWaitingRoom":false}},"patientCategories":[{"name":{"firstField":{"colorCode":"X","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"6868cf32-ae03-45c7-a9c7-0f0ade65b03b","biometricInformation":{"sex":"female","externalFeatures":"blaue Augen, rothaarig, 1,69 m","age":16},"pretriageInformation":{"injuries":"Prellmarke an der Stirn; blutende Wunde am linken Unterarm","bodyCheck":"leichte Schmerzen beim Auftreten im rechten Sprunggelenk; Schwanger; sonst o.B.","breathing":"unauffällig","awareness":"leicht verwirrt","pulse":"79; gut tastbar","skin":"unauffällig","pain":"leichte","pupils":"isocor","psyche":"ängstlich","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]}},"startingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"X","behaviourCode":"D"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"ac7c0497-583c-4622-b064-842b117be2d2","biometricInformation":{"sex":"female","externalFeatures":"braune Haare, braune Augen, 1,72 m","age":35},"pretriageInformation":{"injuries":"keine äußeren Verletzungen sichtbar","bodyCheck":"Pat. ist teilnahmslos; keine Kooperation bei der Untersuchung","breathing":"unauffällig","awareness":"verwirrt","pulse":"82; Puls gut tastbar","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"535508d9-4a42-4981-87e0-b3609e953a1d":{"id":"535508d9-4a42-4981-87e0-b3609e953a1d","functionParameters":{"constantChange":-6.944444444444445,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":50000}]}},"startingHealthStateId":"535508d9-4a42-4981-87e0-b3609e953a1d","health":100000},{"id":"1b3dbb5f-501f-4d64-9772-beb5077917bf","biometricInformation":{"sex":"male","externalFeatures":"1,89 m, Vollbart, blond, blauäugig","age":25},"pretriageInformation":{"injuries":"keine äußeren Verletzungen zu sehen","bodyCheck":"Pat. ist nahezu hysterisch; es besteht keine Kooperation bei Untersuchung","breathing":"unauffällig","awareness":"wach aber verwirrt","pulse":"94","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"hysterisch","hearing":"schwerhörig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"7d9d3abc-fbf9-4838-9907-f97d952921b2":{"id":"7d9d3abc-fbf9-4838-9907-f97d952921b2","functionParameters":{"constantChange":-6.313131313131313,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":50000}]}},"startingHealthStateId":"7d9d3abc-fbf9-4838-9907-f97d952921b2","health":100000},{"id":"719964b6-1be7-4489-84a0-0cc78f71ae78","biometricInformation":{"sex":"female","externalFeatures":"1,76m, hellblond, blaue Augen, Brille","age":35},"pretriageInformation":{"injuries":"äußerlich keine Verletzungen","bodyCheck":"keine Kooperation bei Untersuchung; Pat. hysterisch und verwirrt","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"95","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"hysterisch","hearing":"schwerhörig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"a242b15a-1651-40f9-b91f-41256e64e278":{"id":"a242b15a-1651-40f9-b91f-41256e64e278","functionParameters":{"constantChange":-5.787037037037037,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":50000}]}},"startingHealthStateId":"a242b15a-1651-40f9-b91f-41256e64e278","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"D"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"21a4b49c-9334-4f2e-8e44-728b89dfe002","biometricInformation":{"sex":"female","externalFeatures":"braune Haare, braune Augen, 1,79 m, adipös","age":50},"pretriageInformation":{"injuries":"leichte Augenverletzung rechts","bodyCheck":"Pat. wirkt apathisch; keine Kooperation bei Untersuchung; Prellung Unterschenkel rechts; starke Schmerzen nur beim Auftreten","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"83; Puls flach","skin":"unauffällig","pain":"stark, aber nur beim Auftreten","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"9aaf7336-75ca-4850-82e5-a1607efd6a7f":{"id":"9aaf7336-75ca-4850-82e5-a1607efd6a7f","functionParameters":{"constantChange":-9.920634920634921,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a6905bd4-506a-4559-9b09-e68fbbb63c4e","maximumHealth":50000}]},"a6905bd4-506a-4559-9b09-e68fbbb63c4e":{"id":"a6905bd4-506a-4559-9b09-e68fbbb63c4e","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34","earliestTime":720000}]},"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34":{"id":"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34","functionParameters":{"constantChange":48.611111111111114,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"9aaf7336-75ca-4850-82e5-a1607efd6a7f","health":100000},{"id":"b9dea356-e5e9-464d-a0cd-350d495c59c1","biometricInformation":{"sex":"female","externalFeatures":"1,59 m, blaue Augen, graue Haare","age":65},"pretriageInformation":{"injuries":"äußerlich keine Verletzungen","bodyCheck":"leichter Druckschmerzen im linkes Bein","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"89","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"2a650e54-6c69-42cd-acfd-7b1da8ea767c":{"id":"2a650e54-6c69-42cd-acfd-7b1da8ea767c","functionParameters":{"constantChange":-8.680555555555555,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a6905bd4-506a-4559-9b09-e68fbbb63c4e","maximumHealth":50000}]},"a6905bd4-506a-4559-9b09-e68fbbb63c4e":{"id":"a6905bd4-506a-4559-9b09-e68fbbb63c4e","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34","earliestTime":720000}]},"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34":{"id":"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34","functionParameters":{"constantChange":48.611111111111114,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"2a650e54-6c69-42cd-acfd-7b1da8ea767c","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"D"},"secondField":{"colorCode":"X","behaviourCode":"D"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"786a06fa-53a5-4bc9-a003-5bbda97fba68","biometricInformation":{"sex":"male","externalFeatures":"Spitzbart, blaue Augen, blonde Haare, 182 cm","age":52},"pretriageInformation":{"injuries":"leicht blutende Wunde an der linken Hand, evt. Glassplitter in der Tiefe sichtbar; Prellmarke rechte Schläfe","bodyCheck":"leichte Schmerzen beim Auftreten im linken Fuß","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"85; Puls gut tastbar","skin":"unauffällig","pain":"leichte","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"9dea5618-e952-4ace-b209-0a9dfd25039d":{"id":"9dea5618-e952-4ace-b209-0a9dfd25039d","functionParameters":{"constantChange":-34.72222222222222,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"1bcda560-31ad-4b62-9204-92909a863a18","maximumHealth":50000}]},"1bcda560-31ad-4b62-9204-92909a863a18":{"id":"1bcda560-31ad-4b62-9204-92909a863a18","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"2affe314-2858-46b3-b058-aa5df912496e","earliestTime":1440000}]},"2affe314-2858-46b3-b058-aa5df912496e":{"id":"2affe314-2858-46b3-b058-aa5df912496e","functionParameters":{"constantChange":16.203703703703702,"notarztModifier":48.611111111111114,"notSanModifier":48.611111111111114,"rettSanModifier":48.611111111111114},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"9dea5618-e952-4ace-b209-0a9dfd25039d","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"Y","behaviourCode":"B"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"8be494f4-2ed0-4f79-bcb2-f491499f604f","biometricInformation":{"sex":"female","externalFeatures":"1,66 m, blond, blaue Augen","age":30},"pretriageInformation":{"injuries":"Zeigefingeramputation rechts","bodyCheck":"dezenter Druckschmerzen im rechten Bein","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"98; rhythmisch","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"ängstlich","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"9f2c922b-6b2c-40e0-8a2d-699df90fd564":{"id":"9f2c922b-6b2c-40e0-8a2d-699df90fd564","functionParameters":{"constantChange":-7.716049382716049,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"91fb3035-8aa2-4a44-b5d1-447f32fc1ba4","maximumHealth":50000}]},"91fb3035-8aa2-4a44-b5d1-447f32fc1ba4":{"id":"91fb3035-8aa2-4a44-b5d1-447f32fc1ba4","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":90.27777777777777,"notSanModifier":41.666666666666664,"rettSanModifier":41.666666666666664},"nextStateConditions":[{"matchingHealthStateId":"73e03d5d-ec75-434f-b975-d9369587dee4","earliestTime":720000}]},"73e03d5d-ec75-434f-b975-d9369587dee4":{"id":"73e03d5d-ec75-434f-b975-d9369587dee4","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":69.44444444444444,"notSanModifier":69.44444444444444,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":100000},{"matchingHealthStateId":"590514f7-bad9-4762-b06d-dd54a67ad2ad","earliestTime":720000}]},"590514f7-bad9-4762-b06d-dd54a67ad2ad":{"id":"590514f7-bad9-4762-b06d-dd54a67ad2ad","functionParameters":{"constantChange":-69.44444444444444,"notarztModifier":93.05555555555556,"notSanModifier":93.05555555555556,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"9f2c922b-6b2c-40e0-8a2d-699df90fd564","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"D"},"secondField":{"colorCode":"Z","behaviourCode":"B"},"thirdField":{"colorCode":"Z","behaviourCode":"C"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"7d8db924-24b6-43a4-a1a9-b3acd7785329","biometricInformation":{"sex":"female","externalFeatures":"graue Haare, blaue Augen, 1,69 m, Brille","age":76},"pretriageInformation":{"injuries":"keine äußeren Verletzungen","bodyCheck":"dezenter Druckschmerzen im linken Bein in Höhe der Patella","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"97; Puls gut tastbar","skin":"warm, rot","pain":"keine","pupils":"isocor","psyche":"sehr aufgeregt","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"b3671073-e1b2-43fb-9d20-499ddf8f15d9":{"id":"b3671073-e1b2-43fb-9d20-499ddf8f15d9","functionParameters":{"constantChange":-17.36111111111111,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"03e6df66-9069-4fe4-b887-6feeb251f4bd","maximumHealth":50000}]},"03e6df66-9069-4fe4-b887-6feeb251f4bd":{"id":"03e6df66-9069-4fe4-b887-6feeb251f4bd","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"8300f7bf-05b9-4f46-9098-ecb7eda9775d","maximumHealth":20000}]},"8300f7bf-05b9-4f46-9098-ecb7eda9775d":{"id":"8300f7bf-05b9-4f46-9098-ecb7eda9775d","functionParameters":{"constantChange":-27.77777777777778,"notarztModifier":27.77777777777778,"notSanModifier":27.77777777777778,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"3e8874cd-6f2a-452e-9259-c905ab7e6e57","earliestTime":2880000}]},"3e8874cd-6f2a-452e-9259-c905ab7e6e57":{"id":"3e8874cd-6f2a-452e-9259-c905ab7e6e57","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"b3671073-e1b2-43fb-9d20-499ddf8f15d9","health":100000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"db84352c-c0e2-4c72-b404-f8838c2f7e56","biometricInformation":{"sex":"male","externalFeatures":"dunkle Haare, braune Augen, Muttermal Stirn, 165 cm","age":14},"pretriageInformation":{"injuries":"Kunststofffremdkörper linker Oberarm; Schulterfraktur links; Luxationsfraktur rechtes Handgelenk","bodyCheck":"Risswunde am Hinterkopf; Hüftprellung rechts","breathing":"unauffällig","awareness":"wach, orientiert","pulse":"124; Puls kräftig","skin":"unauffällig","pain":"starke","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"98e5d181-6472-489b-8ecf-24f195ccaa00":{"id":"98e5d181-6472-489b-8ecf-24f195ccaa00","functionParameters":{"constantChange":4.444444444444445,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"98e5d181-6472-489b-8ecf-24f195ccaa00","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"B"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"9c72ee24-1dba-4ab9-a2b4-302d22659e21","biometricInformation":{"sex":"male","externalFeatures":"blaue Augen, weiße Haare, 174 cm","age":72},"pretriageInformation":{"injuries":"Fehlstellung linker Oberarm; offene Fraktur Unterarm links; große Platzwunde Kopf; Handquetschung links; Dialysepatient","bodyCheck":"Schlüsselbeinfraktur rechts; Thoraxprellung auf der gleichen Seite","breathing":"unauffällig","awareness":"wach und orientiert","pulse":"122; Puls kräftig","skin":"unauffällig","pain":"starke","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"3ef8fb89-cf33-45c8-bbdc-86bccf7b20c5":{"id":"3ef8fb89-cf33-45c8-bbdc-86bccf7b20c5","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"676414f6-f8e2-40b6-9c81-b666a9156572","earliestTime":2880000}]},"676414f6-f8e2-40b6-9c81-b666a9156572":{"id":"676414f6-f8e2-40b6-9c81-b666a9156572","functionParameters":{"constantChange":0,"notarztModifier":22.22222222222222,"notSanModifier":22.22222222222222,"rettSanModifier":22.22222222222222},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"3ef8fb89-cf33-45c8-bbdc-86bccf7b20c5","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"B"},"secondField":{"colorCode":"Y","behaviourCode":"A"},"thirdField":{"colorCode":"Y","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"63c7f1c7-2c5b-4e1a-8427-91c67216d0d1","biometricInformation":{"sex":"male","externalFeatures":"Vollbart, blond, blaue Augen, 1,87 m","age":55},"pretriageInformation":{"injuries":"Prellmarke Unterschenkel rechts; Fehlstellung rechtes Sprunggelenk; Wunde Unterarm rechts","bodyCheck":"Druckschmerz rechte Hüfte; Prellung Unterschenkel links","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"123; Puls flach","skin":"kaltschweißig","pain":"starke","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"54443596-73be-426d-9ef7-96fbc3bf4839":{"id":"54443596-73be-426d-9ef7-96fbc3bf4839","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"ab5b1286-1904-42a0-a9e1-2ddea8579ce6","earliestTime":2880000}]},"ab5b1286-1904-42a0-a9e1-2ddea8579ce6":{"id":"ab5b1286-1904-42a0-a9e1-2ddea8579ce6","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":41.666666666666664,"notSanModifier":41.666666666666664,"rettSanModifier":41.666666666666664},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":33000}]}},"startingHealthStateId":"54443596-73be-426d-9ef7-96fbc3bf4839","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"A"},"secondField":{"colorCode":"Y","behaviourCode":"B"},"thirdField":{"colorCode":"Y","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"1713df33-edcb-45c0-9136-f03c563e312c","biometricInformation":{"sex":"male","externalFeatures":"Glatze, graublaue Augen, Brille, 174 cm","age":57},"pretriageInformation":{"injuries":"leicht blutende Wunde Unterarm links; grobe Fehlstellung rechtes Sprunggelenk; Prellmarke Unterschenkel rechts","bodyCheck":"Druckschmerz linke Hüfte; Prellung Unterschenkel links; Schmerzen im Genitalbereich","breathing":"unauffällig","awareness":"wach aber verwirrt","pulse":"122; Puls kräftig","skin":"kaltschweißig","pain":"starke","pupils":"isocor","psyche":"hysterisch","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]}},"startingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"D"},"secondField":{"colorCode":"Y","behaviourCode":"B"},"thirdField":{"colorCode":"Y","behaviourCode":"B"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"154647a0-aa9c-4887-a7b3-c1b03e018c3d","biometricInformation":{"sex":"female","externalFeatures":"graue Haare, Brille, braune Augen, ca. 1,70 m","age":71},"pretriageInformation":{"injuries":"rechte Hand stark schmerzhaft; kleine blutende Platzwunde am Kopf; Glasfremdkörper am ganzen rechten Arm; unstillbares Nasenbluten","bodyCheck":"Thoraxprellung links; Schlüsselbeinfraktur links","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"132; Puls kräftig","skin":"kühl, blass","pain":"starke","pupils":"isocor","psyche":"aggressiv","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"ec613c7e-b8f0-4f20-a25f-83858af6243d":{"id":"ec613c7e-b8f0-4f20-a25f-83858af6243d","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"e485a8a1-d6e3-4283-9c33-7a79d0bf9fc2","maximumHealth":20000}]},"e485a8a1-d6e3-4283-9c33-7a79d0bf9fc2":{"id":"e485a8a1-d6e3-4283-9c33-7a79d0bf9fc2","functionParameters":{"constantChange":20.833333333333332,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"6bfd72c1-059e-485d-a397-501ccf5e4531","minimumHealth":50000}]},"6bfd72c1-059e-485d-a397-501ccf5e4531":{"id":"6bfd72c1-059e-485d-a397-501ccf5e4531","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"6fe239b8-b8a0-47f2-8608-59dc11401221","earliestTime":2160000}]},"6fe239b8-b8a0-47f2-8608-59dc11401221":{"id":"6fe239b8-b8a0-47f2-8608-59dc11401221","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":41.666666666666664,"notSanModifier":41.666666666666664,"rettSanModifier":41.666666666666664},"nextStateConditions":[{"matchingHealthStateId":"e5f07410-b137-4be2-8676-bf413bc559c5","earliestTime":720000}]},"e5f07410-b137-4be2-8676-bf413bc559c5":{"id":"e5f07410-b137-4be2-8676-bf413bc559c5","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":41.666666666666664,"notSanModifier":41.666666666666664,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"6e24dba3-b987-4266-ba76-3d9d06501315","earliestTime":720000}]},"6e24dba3-b987-4266-ba76-3d9d06501315":{"id":"6e24dba3-b987-4266-ba76-3d9d06501315","functionParameters":{"constantChange":-69.44444444444444,"notarztModifier":69.44444444444444,"notSanModifier":69.44444444444444,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":50000},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"ec613c7e-b8f0-4f20-a25f-83858af6243d","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"C"},"secondField":{"colorCode":"Z","behaviourCode":"C"},"thirdField":{"colorCode":"V","behaviourCode":"E"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"9abdfe8f-ac7c-4a42-9d0c-3a1ec5e09238","biometricInformation":{"sex":"female","externalFeatures":"grüne Augen, grauhaarig, 1,68 m, adipös, Brille","age":51},"pretriageInformation":{"injuries":"starke Schmerzen am linken Sprunggelenk; Prellmarke und Schürfwunde linker Unterschenkel","bodyCheck":"Beckenprellung, Fraktur nicht auszuschließen","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"97; Puls gut tastbar","skin":"kaltschweißig","pain":"stärkste","pupils":"isocor","psyche":"hysterisch","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"02156cc6-b3f0-4041-a079-ba95b387c1a0":{"id":"02156cc6-b3f0-4041-a079-ba95b387c1a0","functionParameters":{"constantChange":-10.416666666666666,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a31b9df5-7993-4a34-8851-b474ea23c094","maximumHealth":20000}]},"a31b9df5-7993-4a34-8851-b474ea23c094":{"id":"a31b9df5-7993-4a34-8851-b474ea23c094","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"02156cc6-b3f0-4041-a079-ba95b387c1a0","health":50000}]},{"name":{"firstField":{"colorCode":"Z","behaviourCode":"B"},"secondField":{"colorCode":"Z","behaviourCode":"A"},"thirdField":{"colorCode":"Z","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"afdd27cc-2281-468f-a0d8-a8bc187b8e18","biometricInformation":{"sex":"male","externalFeatures":"1,86 m, Glatze, braune Augen, Brille","age":60},"pretriageInformation":{"injuries":"Prellmarken linker Thorax; offene Oberarmfraktur rechts","bodyCheck":"Rippenserienfraktur li.; Beckenprellung rechts; Hämatom hinter dem rechten Ohr; einseitig hebender Thorax rechts","breathing":"flache Schonatmung","awareness":"somnolent","pulse":"134; Puls fadenförmig","skin":"zyanotisch","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"c6a9af9e-a8b5-4eb4-940a-879cd4416538":{"id":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","earliestTime":2160000}]}},"startingHealthStateId":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","health":20000},{"id":"11357873-6d12-41ce-a7dd-129fadd9fc20","biometricInformation":{"sex":"male","externalFeatures":"1,84 m, braune Augen, Brille, braune Haare","age":15},"pretriageInformation":{"injuries":"Weichteilquetschung rechter Unterschenkel, mäßig blutend, aber schon deutlicher Blutverlust","bodyCheck":"Oberschenkelfraktur rechts; kleiner Eisenfremdkörper in der linken Hand","breathing":"flache Atmung","awareness":"somnolent","pulse":"154; Puls fadenförmig","skin":"grau marmoriert","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"c6a9af9e-a8b5-4eb4-940a-879cd4416538":{"id":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","earliestTime":2160000}]}},"startingHealthStateId":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","health":20000},{"id":"686cd1dd-d265-48f7-93d3-94928056a3e7","biometricInformation":{"sex":"female","externalFeatures":"1,75 m, blonde Haare, blaue Augen, Brille, extrem adipös","age":50},"pretriageInformation":{"injuries":"Kopfplatzwunde über dem Ohr; Prellmarke Stirn; Gesicht blutverschmiert","bodyCheck":"Unterarmfraktur rechts","breathing":"Atemwegsverlegung","awareness":"bewusstlos, Massenbewegungen auf Schmerz","pulse":"85; gut tastbar","skin":"tief zyanotisch","pain":"entfällt","pupils":"rechts weit","psyche":"entfällt","hearing":"entfällt","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"c6a9af9e-a8b5-4eb4-940a-879cd4416538":{"id":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","earliestTime":2160000}]}},"startingHealthStateId":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","health":20000},{"id":"5d9ff1e5-10ae-4910-940f-3eb37f4bc5f7","biometricInformation":{"sex":"female","externalFeatures":"1,72 m, braune Augen, blonde Haare","age":25},"pretriageInformation":{"injuries":"offene Fraktur rechter Unterschenkel, nur noch mäßig blutend, aber schon großer Blutverlust; Wunde linke Schläfe; schwanger ca. 36 SSW","bodyCheck":"schulternahe Oberarmfraktur rechts; linke Hand mit Fehlstellung im Handgelenk","breathing":"flache Atmung","awareness":"somnolent","pulse":"150; Puls fadenförmig","skin":"grau marmoriert","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"c6a9af9e-a8b5-4eb4-940a-879cd4416538":{"id":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","earliestTime":2160000}]}},"startingHealthStateId":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","health":20000}]},{"name":{"firstField":{"colorCode":"Z","behaviourCode":"B"},"secondField":{"colorCode":"Z","behaviourCode":"C"},"thirdField":{"colorCode":"V","behaviourCode":"E"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"8f87e7fc-3226-466c-bee7-ba04a93d8637","biometricInformation":{"sex":"female","externalFeatures":"graue Haare, Brille, grüne Augen, ca. 1,60 m","age":80},"pretriageInformation":{"injuries":"große Weichteilquetschung linker Unterschenkel, nur noch mäßig blutend; aber schon deutlicher Blutverlust","bodyCheck":"Oberarmfraktur rechts; fraglicher Fremdkörper rechte Hand in Wunde; blutende Prellmarke am Hinterkopf","breathing":"flache Atmung","awareness":"somnolent","pulse":"132; fadenförmig","skin":"grau marmoriert","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"b0c3cbcf-448a-4eb4-8c71-4a94d338a531":{"id":"b0c3cbcf-448a-4eb4-8c71-4a94d338a531","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"d51fc779-8d12-44cc-96cc-ec689c41ff02","earliestTime":2160000}]},"d51fc779-8d12-44cc-96cc-ec689c41ff02":{"id":"d51fc779-8d12-44cc-96cc-ec689c41ff02","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"7ae2585b-9256-40e7-9408-83df0720a70c","earliestTime":1440000}]},"7ae2585b-9256-40e7-9408-83df0720a70c":{"id":"7ae2585b-9256-40e7-9408-83df0720a70c","functionParameters":{"constantChange":-9.25925925925926,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"b0c3cbcf-448a-4eb4-8c71-4a94d338a531","health":20000}]},{"name":{"firstField":{"colorCode":"Z","behaviourCode":"C"},"secondField":{"colorCode":"Z","behaviourCode":"C"},"thirdField":{"colorCode":"V","behaviourCode":"E"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"4382691d-53ea-4eeb-931e-146a5e35ea85","biometricInformation":{"sex":"male","externalFeatures":"1,78m, Bart, schwarzhaarig, braune Augen","age":50},"pretriageInformation":{"injuries":"Teil-Amputation rechter Unterarm, spritzend blutend; schon großer Blutverlust","bodyCheck":"geschlossene Oberschenkelfraktur links; Metallfremdkörper rechter Unterschenkel","breathing":"flache Atmung","awareness":"somnolent","pulse":"145; fadenförmig","skin":"grau marmoriert","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"b72fa6f0-eacc-43a9-a7a7-7764107d17b1":{"id":"b72fa6f0-eacc-43a9-a7a7-7764107d17b1","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"7ae2585b-9256-40e7-9408-83df0720a70c","earliestTime":2160000}]},"7ae2585b-9256-40e7-9408-83df0720a70c":{"id":"7ae2585b-9256-40e7-9408-83df0720a70c","functionParameters":{"constantChange":-9.25925925925926,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"b72fa6f0-eacc-43a9-a7a7-7764107d17b1","health":20000}]},{"name":{"firstField":{"colorCode":"Z","behaviourCode":"C"},"secondField":{"colorCode":"V","behaviourCode":"E"},"thirdField":{"colorCode":"V","behaviourCode":"E"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"3c407f4b-012a-4314-a50b-2e334110284e","biometricInformation":{"sex":"female","externalFeatures":"1,64 m, blaue Augen, blond","age":55},"pretriageInformation":{"injuries":"starke Schmerzen im gesamten Abdomen mit gespannter Bauchdecke","bodyCheck":"Prellmarken und Wunde linke Flanke; Rippenserienfraktur links","breathing":"schwere Atemnot 30/min.","awareness":"wach, verwirrt","pulse":"114; flach","skin":"kühl, blass","pain":"starke Bauchschmerzen","pupils":"isocor","psyche":"ängstlich","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"7ae2585b-9256-40e7-9408-83df0720a70c":{"id":"7ae2585b-9256-40e7-9408-83df0720a70c","functionParameters":{"constantChange":-9.25925925925926,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"7ae2585b-9256-40e7-9408-83df0720a70c","health":20000}]}],"vehicleTemplates":[{"id":"5ac07da0-c7dc-43ef-94ee-af023966eeeb","vehicleType":"RTW","name":"RTW ???","image":{"url":"/assets/rtw-vehicle.png","height":100,"aspectRatio":2.211377245508982},"patientCapacity":1,"personnel":["notSan","rettSan"],"materials":["standard"]},{"id":"a3d76307-35d8-47ee-8fda-7445c65bf909","vehicleType":"KTW","name":"KTW ???","image":{"url":"/assets/ktw-vehicle.png","height":100,"aspectRatio":2.0470588235294116},"patientCapacity":1,"personnel":["san","rettSan"],"materials":["standard"]},{"id":"a6e71070-6b57-45d3-8863-800428e006f4","vehicleType":"KTW (KatSchutz)","name":"KTW (KatSchutz) ???","image":{"url":"/assets/ktw-vehicle.png","height":100,"aspectRatio":2.0470588235294116},"patientCapacity":2,"personnel":["san","rettSan"],"materials":["standard"]},{"id":"3d7d1950-20a0-4625-a3c0-1dd9d5c7ccc0","vehicleType":"GW-San","name":"GW-San ???","image":{"url":"/assets/gwSan-vehicle.png","height":120,"aspectRatio":2.021018593371059},"patientCapacity":0,"personnel":["gf","rettSan","rettSan","san","san","notarzt"],"materials":["big","big","big","big"]},{"id":"fc8782ac-9567-4bcd-8a5a-8d31f608f03d","vehicleType":"NEF","name":"NEF ???","image":{"url":"/assets/nef-vehicle.png","height":70,"aspectRatio":2.4120194910665944},"patientCapacity":0,"personnel":["notarzt","notSan"],"materials":["standard"]},{"id":"c0690dad-e6be-452f-85e0-2dd942241315","vehicleType":"Tragetrupp","name":"Tragetrupp ???","image":{"url":"/assets/carrying-unit.svg","height":210,"aspectRatio":1},"patientCapacity":1,"personnel":[],"materials":[]},{"id":"cad2cc9b-a624-4020-aa5f-180ed0160f33","vehicleType":"RTH","name":"RTH ???","image":{"url":"/assets/rth-vehicle.svg","height":300,"aspectRatio":2.3846153846153846},"patientCapacity":1,"personnel":["notarzt","notSan"],"materials":["standard"]}],"materialTemplates":{"standard":{"materialType":"standard","canCaterFor":{"red":2,"yellow":0,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":5.5,"image":{"url":"/assets/material.svg","height":40,"aspectRatio":1}},"big":{"materialType":"big","canCaterFor":{"red":2,"yellow":2,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":10,"image":{"url":"/assets/material.svg","height":56,"aspectRatio":1}}},"personnelTemplates":{"san":{"personnelType":"san","canCaterFor":{"red":0,"yellow":0,"green":5,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":5.5,"image":{"url":"/assets/san-personnel.svg","height":80,"aspectRatio":1}},"rettSan":{"personnelType":"rettSan","canCaterFor":{"red":1,"yellow":2,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":5.5,"image":{"url":"/assets/rettSan-personnel.svg","height":80,"aspectRatio":1}},"notSan":{"personnelType":"notSan","canCaterFor":{"red":2,"yellow":1,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":5.5,"image":{"url":"/assets/notSan-personnel.svg","height":80,"aspectRatio":1}},"notarzt":{"personnelType":"notarzt","canCaterFor":{"red":2,"yellow":2,"green":2,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":15,"image":{"url":"/assets/notarzt-personnel.svg","height":80,"aspectRatio":1}},"gf":{"personnelType":"gf","canCaterFor":{"red":0,"yellow":0,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":0,"treatmentRange":0,"image":{"url":"/assets/gf-personnel.svg","height":80,"aspectRatio":1}}},"mapImageTemplates":[{"id":"90db6ee0-b8ba-4131-bc87-264fc218fa8f","name":"Feuer","image":{"url":"/assets/fire.svg","height":427,"aspectRatio":0.7330210772833724}},{"id":"9b27ad1c-d1d0-4bd1-9e93-e62d50969085","name":"Brennendes Haus","image":{"url":"/assets/house-fire.svg","height":623,"aspectRatio":0.6308186195826645}}],"eocLog":[],"participantId":"657034","spatialTrees":{"materials":{"spatialTreeAsJSON":{"children":[],"height":1,"leaf":true,"minX":null,"minY":null,"maxX":null,"maxY":null}},"patients":{"spatialTreeAsJSON":{"children":[],"height":1,"leaf":true,"minX":null,"minY":null,"maxX":null,"maxY":null}},"personnel":{"spatialTreeAsJSON":{"children":[],"height":1,"leaf":true,"minX":null,"minY":null,"maxX":null,"maxY":null}}},"configuration":{"pretriageEnabled":true,"bluePatientsEnabled":false,"tileMapProperties":{"tileUrl":"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}","maxZoom":20}}},"history":{"actionHistory":[{"type":"[Client] Add client","client":{"id":"1a4d8d3f-3a6d-47af-9a23-bfc814d1b559","name":"","role":"trainer","isInWaitingRoom":false}}],"initialState":{"id":"c1bffad0-e5d3-49ef-930e-21a9a2d1c5d0","currentTime":0,"currentStatus":"notStarted","viewports":{},"vehicles":{},"personnel":{},"patients":{},"materials":{},"mapImages":{},"transferPoints":{},"hospitals":{},"hospitalPatients":{},"alarmGroups":{},"clients":{},"patientCategories":[{"name":{"firstField":{"colorCode":"X","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"6868cf32-ae03-45c7-a9c7-0f0ade65b03b","biometricInformation":{"sex":"female","externalFeatures":"blaue Augen, rothaarig, 1,69 m","age":16},"pretriageInformation":{"injuries":"Prellmarke an der Stirn; blutende Wunde am linken Unterarm","bodyCheck":"leichte Schmerzen beim Auftreten im rechten Sprunggelenk; Schwanger; sonst o.B.","breathing":"unauffällig","awareness":"leicht verwirrt","pulse":"79; gut tastbar","skin":"unauffällig","pain":"leichte","pupils":"isocor","psyche":"ängstlich","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]}},"startingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"X","behaviourCode":"D"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"ac7c0497-583c-4622-b064-842b117be2d2","biometricInformation":{"sex":"female","externalFeatures":"braune Haare, braune Augen, 1,72 m","age":35},"pretriageInformation":{"injuries":"keine äußeren Verletzungen sichtbar","bodyCheck":"Pat. ist teilnahmslos; keine Kooperation bei der Untersuchung","breathing":"unauffällig","awareness":"verwirrt","pulse":"82; Puls gut tastbar","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"535508d9-4a42-4981-87e0-b3609e953a1d":{"id":"535508d9-4a42-4981-87e0-b3609e953a1d","functionParameters":{"constantChange":-6.944444444444445,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":50000}]}},"startingHealthStateId":"535508d9-4a42-4981-87e0-b3609e953a1d","health":100000},{"id":"1b3dbb5f-501f-4d64-9772-beb5077917bf","biometricInformation":{"sex":"male","externalFeatures":"1,89 m, Vollbart, blond, blauäugig","age":25},"pretriageInformation":{"injuries":"keine äußeren Verletzungen zu sehen","bodyCheck":"Pat. ist nahezu hysterisch; es besteht keine Kooperation bei Untersuchung","breathing":"unauffällig","awareness":"wach aber verwirrt","pulse":"94","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"hysterisch","hearing":"schwerhörig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"7d9d3abc-fbf9-4838-9907-f97d952921b2":{"id":"7d9d3abc-fbf9-4838-9907-f97d952921b2","functionParameters":{"constantChange":-6.313131313131313,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":50000}]}},"startingHealthStateId":"7d9d3abc-fbf9-4838-9907-f97d952921b2","health":100000},{"id":"719964b6-1be7-4489-84a0-0cc78f71ae78","biometricInformation":{"sex":"female","externalFeatures":"1,76m, hellblond, blaue Augen, Brille","age":35},"pretriageInformation":{"injuries":"äußerlich keine Verletzungen","bodyCheck":"keine Kooperation bei Untersuchung; Pat. hysterisch und verwirrt","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"95","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"hysterisch","hearing":"schwerhörig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"a242b15a-1651-40f9-b91f-41256e64e278":{"id":"a242b15a-1651-40f9-b91f-41256e64e278","functionParameters":{"constantChange":-5.787037037037037,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":50000}]}},"startingHealthStateId":"a242b15a-1651-40f9-b91f-41256e64e278","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"D"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"21a4b49c-9334-4f2e-8e44-728b89dfe002","biometricInformation":{"sex":"female","externalFeatures":"braune Haare, braune Augen, 1,79 m, adipös","age":50},"pretriageInformation":{"injuries":"leichte Augenverletzung rechts","bodyCheck":"Pat. wirkt apathisch; keine Kooperation bei Untersuchung; Prellung Unterschenkel rechts; starke Schmerzen nur beim Auftreten","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"83; Puls flach","skin":"unauffällig","pain":"stark, aber nur beim Auftreten","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"9aaf7336-75ca-4850-82e5-a1607efd6a7f":{"id":"9aaf7336-75ca-4850-82e5-a1607efd6a7f","functionParameters":{"constantChange":-9.920634920634921,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a6905bd4-506a-4559-9b09-e68fbbb63c4e","maximumHealth":50000}]},"a6905bd4-506a-4559-9b09-e68fbbb63c4e":{"id":"a6905bd4-506a-4559-9b09-e68fbbb63c4e","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34","earliestTime":720000}]},"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34":{"id":"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34","functionParameters":{"constantChange":48.611111111111114,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"9aaf7336-75ca-4850-82e5-a1607efd6a7f","health":100000},{"id":"b9dea356-e5e9-464d-a0cd-350d495c59c1","biometricInformation":{"sex":"female","externalFeatures":"1,59 m, blaue Augen, graue Haare","age":65},"pretriageInformation":{"injuries":"äußerlich keine Verletzungen","bodyCheck":"leichter Druckschmerzen im linkes Bein","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"89","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"2a650e54-6c69-42cd-acfd-7b1da8ea767c":{"id":"2a650e54-6c69-42cd-acfd-7b1da8ea767c","functionParameters":{"constantChange":-8.680555555555555,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a6905bd4-506a-4559-9b09-e68fbbb63c4e","maximumHealth":50000}]},"a6905bd4-506a-4559-9b09-e68fbbb63c4e":{"id":"a6905bd4-506a-4559-9b09-e68fbbb63c4e","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34","earliestTime":720000}]},"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34":{"id":"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34","functionParameters":{"constantChange":48.611111111111114,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"2a650e54-6c69-42cd-acfd-7b1da8ea767c","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"D"},"secondField":{"colorCode":"X","behaviourCode":"D"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"786a06fa-53a5-4bc9-a003-5bbda97fba68","biometricInformation":{"sex":"male","externalFeatures":"Spitzbart, blaue Augen, blonde Haare, 182 cm","age":52},"pretriageInformation":{"injuries":"leicht blutende Wunde an der linken Hand, evt. Glassplitter in der Tiefe sichtbar; Prellmarke rechte Schläfe","bodyCheck":"leichte Schmerzen beim Auftreten im linken Fuß","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"85; Puls gut tastbar","skin":"unauffällig","pain":"leichte","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"9dea5618-e952-4ace-b209-0a9dfd25039d":{"id":"9dea5618-e952-4ace-b209-0a9dfd25039d","functionParameters":{"constantChange":-34.72222222222222,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"1bcda560-31ad-4b62-9204-92909a863a18","maximumHealth":50000}]},"1bcda560-31ad-4b62-9204-92909a863a18":{"id":"1bcda560-31ad-4b62-9204-92909a863a18","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"2affe314-2858-46b3-b058-aa5df912496e","earliestTime":1440000}]},"2affe314-2858-46b3-b058-aa5df912496e":{"id":"2affe314-2858-46b3-b058-aa5df912496e","functionParameters":{"constantChange":16.203703703703702,"notarztModifier":48.611111111111114,"notSanModifier":48.611111111111114,"rettSanModifier":48.611111111111114},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"9dea5618-e952-4ace-b209-0a9dfd25039d","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"Y","behaviourCode":"B"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"8be494f4-2ed0-4f79-bcb2-f491499f604f","biometricInformation":{"sex":"female","externalFeatures":"1,66 m, blond, blaue Augen","age":30},"pretriageInformation":{"injuries":"Zeigefingeramputation rechts","bodyCheck":"dezenter Druckschmerzen im rechten Bein","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"98; rhythmisch","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"ängstlich","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"9f2c922b-6b2c-40e0-8a2d-699df90fd564":{"id":"9f2c922b-6b2c-40e0-8a2d-699df90fd564","functionParameters":{"constantChange":-7.716049382716049,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"91fb3035-8aa2-4a44-b5d1-447f32fc1ba4","maximumHealth":50000}]},"91fb3035-8aa2-4a44-b5d1-447f32fc1ba4":{"id":"91fb3035-8aa2-4a44-b5d1-447f32fc1ba4","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":90.27777777777777,"notSanModifier":41.666666666666664,"rettSanModifier":41.666666666666664},"nextStateConditions":[{"matchingHealthStateId":"73e03d5d-ec75-434f-b975-d9369587dee4","earliestTime":720000}]},"73e03d5d-ec75-434f-b975-d9369587dee4":{"id":"73e03d5d-ec75-434f-b975-d9369587dee4","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":69.44444444444444,"notSanModifier":69.44444444444444,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":100000},{"matchingHealthStateId":"590514f7-bad9-4762-b06d-dd54a67ad2ad","earliestTime":720000}]},"590514f7-bad9-4762-b06d-dd54a67ad2ad":{"id":"590514f7-bad9-4762-b06d-dd54a67ad2ad","functionParameters":{"constantChange":-69.44444444444444,"notarztModifier":93.05555555555556,"notSanModifier":93.05555555555556,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"9f2c922b-6b2c-40e0-8a2d-699df90fd564","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"D"},"secondField":{"colorCode":"Z","behaviourCode":"B"},"thirdField":{"colorCode":"Z","behaviourCode":"C"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"7d8db924-24b6-43a4-a1a9-b3acd7785329","biometricInformation":{"sex":"female","externalFeatures":"graue Haare, blaue Augen, 1,69 m, Brille","age":76},"pretriageInformation":{"injuries":"keine äußeren Verletzungen","bodyCheck":"dezenter Druckschmerzen im linken Bein in Höhe der Patella","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"97; Puls gut tastbar","skin":"warm, rot","pain":"keine","pupils":"isocor","psyche":"sehr aufgeregt","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"b3671073-e1b2-43fb-9d20-499ddf8f15d9":{"id":"b3671073-e1b2-43fb-9d20-499ddf8f15d9","functionParameters":{"constantChange":-17.36111111111111,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"03e6df66-9069-4fe4-b887-6feeb251f4bd","maximumHealth":50000}]},"03e6df66-9069-4fe4-b887-6feeb251f4bd":{"id":"03e6df66-9069-4fe4-b887-6feeb251f4bd","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"8300f7bf-05b9-4f46-9098-ecb7eda9775d","maximumHealth":20000}]},"8300f7bf-05b9-4f46-9098-ecb7eda9775d":{"id":"8300f7bf-05b9-4f46-9098-ecb7eda9775d","functionParameters":{"constantChange":-27.77777777777778,"notarztModifier":27.77777777777778,"notSanModifier":27.77777777777778,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"3e8874cd-6f2a-452e-9259-c905ab7e6e57","earliestTime":2880000}]},"3e8874cd-6f2a-452e-9259-c905ab7e6e57":{"id":"3e8874cd-6f2a-452e-9259-c905ab7e6e57","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"b3671073-e1b2-43fb-9d20-499ddf8f15d9","health":100000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"db84352c-c0e2-4c72-b404-f8838c2f7e56","biometricInformation":{"sex":"male","externalFeatures":"dunkle Haare, braune Augen, Muttermal Stirn, 165 cm","age":14},"pretriageInformation":{"injuries":"Kunststofffremdkörper linker Oberarm; Schulterfraktur links; Luxationsfraktur rechtes Handgelenk","bodyCheck":"Risswunde am Hinterkopf; Hüftprellung rechts","breathing":"unauffällig","awareness":"wach, orientiert","pulse":"124; Puls kräftig","skin":"unauffällig","pain":"starke","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"98e5d181-6472-489b-8ecf-24f195ccaa00":{"id":"98e5d181-6472-489b-8ecf-24f195ccaa00","functionParameters":{"constantChange":4.444444444444445,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"98e5d181-6472-489b-8ecf-24f195ccaa00","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"B"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"9c72ee24-1dba-4ab9-a2b4-302d22659e21","biometricInformation":{"sex":"male","externalFeatures":"blaue Augen, weiße Haare, 174 cm","age":72},"pretriageInformation":{"injuries":"Fehlstellung linker Oberarm; offene Fraktur Unterarm links; große Platzwunde Kopf; Handquetschung links; Dialysepatient","bodyCheck":"Schlüsselbeinfraktur rechts; Thoraxprellung auf der gleichen Seite","breathing":"unauffällig","awareness":"wach und orientiert","pulse":"122; Puls kräftig","skin":"unauffällig","pain":"starke","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"3ef8fb89-cf33-45c8-bbdc-86bccf7b20c5":{"id":"3ef8fb89-cf33-45c8-bbdc-86bccf7b20c5","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"676414f6-f8e2-40b6-9c81-b666a9156572","earliestTime":2880000}]},"676414f6-f8e2-40b6-9c81-b666a9156572":{"id":"676414f6-f8e2-40b6-9c81-b666a9156572","functionParameters":{"constantChange":0,"notarztModifier":22.22222222222222,"notSanModifier":22.22222222222222,"rettSanModifier":22.22222222222222},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"3ef8fb89-cf33-45c8-bbdc-86bccf7b20c5","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"B"},"secondField":{"colorCode":"Y","behaviourCode":"A"},"thirdField":{"colorCode":"Y","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"63c7f1c7-2c5b-4e1a-8427-91c67216d0d1","biometricInformation":{"sex":"male","externalFeatures":"Vollbart, blond, blaue Augen, 1,87 m","age":55},"pretriageInformation":{"injuries":"Prellmarke Unterschenkel rechts; Fehlstellung rechtes Sprunggelenk; Wunde Unterarm rechts","bodyCheck":"Druckschmerz rechte Hüfte; Prellung Unterschenkel links","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"123; Puls flach","skin":"kaltschweißig","pain":"starke","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"54443596-73be-426d-9ef7-96fbc3bf4839":{"id":"54443596-73be-426d-9ef7-96fbc3bf4839","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"ab5b1286-1904-42a0-a9e1-2ddea8579ce6","earliestTime":2880000}]},"ab5b1286-1904-42a0-a9e1-2ddea8579ce6":{"id":"ab5b1286-1904-42a0-a9e1-2ddea8579ce6","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":41.666666666666664,"notSanModifier":41.666666666666664,"rettSanModifier":41.666666666666664},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":33000}]}},"startingHealthStateId":"54443596-73be-426d-9ef7-96fbc3bf4839","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"A"},"secondField":{"colorCode":"Y","behaviourCode":"B"},"thirdField":{"colorCode":"Y","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"1713df33-edcb-45c0-9136-f03c563e312c","biometricInformation":{"sex":"male","externalFeatures":"Glatze, graublaue Augen, Brille, 174 cm","age":57},"pretriageInformation":{"injuries":"leicht blutende Wunde Unterarm links; grobe Fehlstellung rechtes Sprunggelenk; Prellmarke Unterschenkel rechts","bodyCheck":"Druckschmerz linke Hüfte; Prellung Unterschenkel links; Schmerzen im Genitalbereich","breathing":"unauffällig","awareness":"wach aber verwirrt","pulse":"122; Puls kräftig","skin":"kaltschweißig","pain":"starke","pupils":"isocor","psyche":"hysterisch","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]}},"startingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"D"},"secondField":{"colorCode":"Y","behaviourCode":"B"},"thirdField":{"colorCode":"Y","behaviourCode":"B"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"154647a0-aa9c-4887-a7b3-c1b03e018c3d","biometricInformation":{"sex":"female","externalFeatures":"graue Haare, Brille, braune Augen, ca. 1,70 m","age":71},"pretriageInformation":{"injuries":"rechte Hand stark schmerzhaft; kleine blutende Platzwunde am Kopf; Glasfremdkörper am ganzen rechten Arm; unstillbares Nasenbluten","bodyCheck":"Thoraxprellung links; Schlüsselbeinfraktur links","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"132; Puls kräftig","skin":"kühl, blass","pain":"starke","pupils":"isocor","psyche":"aggressiv","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"ec613c7e-b8f0-4f20-a25f-83858af6243d":{"id":"ec613c7e-b8f0-4f20-a25f-83858af6243d","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"e485a8a1-d6e3-4283-9c33-7a79d0bf9fc2","maximumHealth":20000}]},"e485a8a1-d6e3-4283-9c33-7a79d0bf9fc2":{"id":"e485a8a1-d6e3-4283-9c33-7a79d0bf9fc2","functionParameters":{"constantChange":20.833333333333332,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"6bfd72c1-059e-485d-a397-501ccf5e4531","minimumHealth":50000}]},"6bfd72c1-059e-485d-a397-501ccf5e4531":{"id":"6bfd72c1-059e-485d-a397-501ccf5e4531","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"6fe239b8-b8a0-47f2-8608-59dc11401221","earliestTime":2160000}]},"6fe239b8-b8a0-47f2-8608-59dc11401221":{"id":"6fe239b8-b8a0-47f2-8608-59dc11401221","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":41.666666666666664,"notSanModifier":41.666666666666664,"rettSanModifier":41.666666666666664},"nextStateConditions":[{"matchingHealthStateId":"e5f07410-b137-4be2-8676-bf413bc559c5","earliestTime":720000}]},"e5f07410-b137-4be2-8676-bf413bc559c5":{"id":"e5f07410-b137-4be2-8676-bf413bc559c5","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":41.666666666666664,"notSanModifier":41.666666666666664,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"6e24dba3-b987-4266-ba76-3d9d06501315","earliestTime":720000}]},"6e24dba3-b987-4266-ba76-3d9d06501315":{"id":"6e24dba3-b987-4266-ba76-3d9d06501315","functionParameters":{"constantChange":-69.44444444444444,"notarztModifier":69.44444444444444,"notSanModifier":69.44444444444444,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":50000},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"ec613c7e-b8f0-4f20-a25f-83858af6243d","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"C"},"secondField":{"colorCode":"Z","behaviourCode":"C"},"thirdField":{"colorCode":"V","behaviourCode":"E"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"9abdfe8f-ac7c-4a42-9d0c-3a1ec5e09238","biometricInformation":{"sex":"female","externalFeatures":"grüne Augen, grauhaarig, 1,68 m, adipös, Brille","age":51},"pretriageInformation":{"injuries":"starke Schmerzen am linken Sprunggelenk; Prellmarke und Schürfwunde linker Unterschenkel","bodyCheck":"Beckenprellung, Fraktur nicht auszuschließen","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"97; Puls gut tastbar","skin":"kaltschweißig","pain":"stärkste","pupils":"isocor","psyche":"hysterisch","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"02156cc6-b3f0-4041-a079-ba95b387c1a0":{"id":"02156cc6-b3f0-4041-a079-ba95b387c1a0","functionParameters":{"constantChange":-10.416666666666666,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a31b9df5-7993-4a34-8851-b474ea23c094","maximumHealth":20000}]},"a31b9df5-7993-4a34-8851-b474ea23c094":{"id":"a31b9df5-7993-4a34-8851-b474ea23c094","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"02156cc6-b3f0-4041-a079-ba95b387c1a0","health":50000}]},{"name":{"firstField":{"colorCode":"Z","behaviourCode":"B"},"secondField":{"colorCode":"Z","behaviourCode":"A"},"thirdField":{"colorCode":"Z","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"afdd27cc-2281-468f-a0d8-a8bc187b8e18","biometricInformation":{"sex":"male","externalFeatures":"1,86 m, Glatze, braune Augen, Brille","age":60},"pretriageInformation":{"injuries":"Prellmarken linker Thorax; offene Oberarmfraktur rechts","bodyCheck":"Rippenserienfraktur li.; Beckenprellung rechts; Hämatom hinter dem rechten Ohr; einseitig hebender Thorax rechts","breathing":"flache Schonatmung","awareness":"somnolent","pulse":"134; Puls fadenförmig","skin":"zyanotisch","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"c6a9af9e-a8b5-4eb4-940a-879cd4416538":{"id":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","earliestTime":2160000}]}},"startingHealthStateId":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","health":20000},{"id":"11357873-6d12-41ce-a7dd-129fadd9fc20","biometricInformation":{"sex":"male","externalFeatures":"1,84 m, braune Augen, Brille, braune Haare","age":15},"pretriageInformation":{"injuries":"Weichteilquetschung rechter Unterschenkel, mäßig blutend, aber schon deutlicher Blutverlust","bodyCheck":"Oberschenkelfraktur rechts; kleiner Eisenfremdkörper in der linken Hand","breathing":"flache Atmung","awareness":"somnolent","pulse":"154; Puls fadenförmig","skin":"grau marmoriert","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"c6a9af9e-a8b5-4eb4-940a-879cd4416538":{"id":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","earliestTime":2160000}]}},"startingHealthStateId":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","health":20000},{"id":"686cd1dd-d265-48f7-93d3-94928056a3e7","biometricInformation":{"sex":"female","externalFeatures":"1,75 m, blonde Haare, blaue Augen, Brille, extrem adipös","age":50},"pretriageInformation":{"injuries":"Kopfplatzwunde über dem Ohr; Prellmarke Stirn; Gesicht blutverschmiert","bodyCheck":"Unterarmfraktur rechts","breathing":"Atemwegsverlegung","awareness":"bewusstlos, Massenbewegungen auf Schmerz","pulse":"85; gut tastbar","skin":"tief zyanotisch","pain":"entfällt","pupils":"rechts weit","psyche":"entfällt","hearing":"entfällt","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"c6a9af9e-a8b5-4eb4-940a-879cd4416538":{"id":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","earliestTime":2160000}]}},"startingHealthStateId":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","health":20000},{"id":"5d9ff1e5-10ae-4910-940f-3eb37f4bc5f7","biometricInformation":{"sex":"female","externalFeatures":"1,72 m, braune Augen, blonde Haare","age":25},"pretriageInformation":{"injuries":"offene Fraktur rechter Unterschenkel, nur noch mäßig blutend, aber schon großer Blutverlust; Wunde linke Schläfe; schwanger ca. 36 SSW","bodyCheck":"schulternahe Oberarmfraktur rechts; linke Hand mit Fehlstellung im Handgelenk","breathing":"flache Atmung","awareness":"somnolent","pulse":"150; Puls fadenförmig","skin":"grau marmoriert","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"c6a9af9e-a8b5-4eb4-940a-879cd4416538":{"id":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","earliestTime":2160000}]}},"startingHealthStateId":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","health":20000}]},{"name":{"firstField":{"colorCode":"Z","behaviourCode":"B"},"secondField":{"colorCode":"Z","behaviourCode":"C"},"thirdField":{"colorCode":"V","behaviourCode":"E"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"8f87e7fc-3226-466c-bee7-ba04a93d8637","biometricInformation":{"sex":"female","externalFeatures":"graue Haare, Brille, grüne Augen, ca. 1,60 m","age":80},"pretriageInformation":{"injuries":"große Weichteilquetschung linker Unterschenkel, nur noch mäßig blutend; aber schon deutlicher Blutverlust","bodyCheck":"Oberarmfraktur rechts; fraglicher Fremdkörper rechte Hand in Wunde; blutende Prellmarke am Hinterkopf","breathing":"flache Atmung","awareness":"somnolent","pulse":"132; fadenförmig","skin":"grau marmoriert","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"b0c3cbcf-448a-4eb4-8c71-4a94d338a531":{"id":"b0c3cbcf-448a-4eb4-8c71-4a94d338a531","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"d51fc779-8d12-44cc-96cc-ec689c41ff02","earliestTime":2160000}]},"d51fc779-8d12-44cc-96cc-ec689c41ff02":{"id":"d51fc779-8d12-44cc-96cc-ec689c41ff02","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"7ae2585b-9256-40e7-9408-83df0720a70c","earliestTime":1440000}]},"7ae2585b-9256-40e7-9408-83df0720a70c":{"id":"7ae2585b-9256-40e7-9408-83df0720a70c","functionParameters":{"constantChange":-9.25925925925926,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"b0c3cbcf-448a-4eb4-8c71-4a94d338a531","health":20000}]},{"name":{"firstField":{"colorCode":"Z","behaviourCode":"C"},"secondField":{"colorCode":"Z","behaviourCode":"C"},"thirdField":{"colorCode":"V","behaviourCode":"E"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"4382691d-53ea-4eeb-931e-146a5e35ea85","biometricInformation":{"sex":"male","externalFeatures":"1,78m, Bart, schwarzhaarig, braune Augen","age":50},"pretriageInformation":{"injuries":"Teil-Amputation rechter Unterarm, spritzend blutend; schon großer Blutverlust","bodyCheck":"geschlossene Oberschenkelfraktur links; Metallfremdkörper rechter Unterschenkel","breathing":"flache Atmung","awareness":"somnolent","pulse":"145; fadenförmig","skin":"grau marmoriert","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"b72fa6f0-eacc-43a9-a7a7-7764107d17b1":{"id":"b72fa6f0-eacc-43a9-a7a7-7764107d17b1","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"7ae2585b-9256-40e7-9408-83df0720a70c","earliestTime":2160000}]},"7ae2585b-9256-40e7-9408-83df0720a70c":{"id":"7ae2585b-9256-40e7-9408-83df0720a70c","functionParameters":{"constantChange":-9.25925925925926,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"b72fa6f0-eacc-43a9-a7a7-7764107d17b1","health":20000}]},{"name":{"firstField":{"colorCode":"Z","behaviourCode":"C"},"secondField":{"colorCode":"V","behaviourCode":"E"},"thirdField":{"colorCode":"V","behaviourCode":"E"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"3c407f4b-012a-4314-a50b-2e334110284e","biometricInformation":{"sex":"female","externalFeatures":"1,64 m, blaue Augen, blond","age":55},"pretriageInformation":{"injuries":"starke Schmerzen im gesamten Abdomen mit gespannter Bauchdecke","bodyCheck":"Prellmarken und Wunde linke Flanke; Rippenserienfraktur links","breathing":"schwere Atemnot 30/min.","awareness":"wach, verwirrt","pulse":"114; flach","skin":"kühl, blass","pain":"starke Bauchschmerzen","pupils":"isocor","psyche":"ängstlich","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"7ae2585b-9256-40e7-9408-83df0720a70c":{"id":"7ae2585b-9256-40e7-9408-83df0720a70c","functionParameters":{"constantChange":-9.25925925925926,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"7ae2585b-9256-40e7-9408-83df0720a70c","health":20000}]}],"vehicleTemplates":[{"id":"5ac07da0-c7dc-43ef-94ee-af023966eeeb","vehicleType":"RTW","name":"RTW ???","image":{"url":"/assets/rtw-vehicle.png","height":100,"aspectRatio":2.211377245508982},"patientCapacity":1,"personnel":["notSan","rettSan"],"materials":["standard"]},{"id":"a3d76307-35d8-47ee-8fda-7445c65bf909","vehicleType":"KTW","name":"KTW ???","image":{"url":"/assets/ktw-vehicle.png","height":100,"aspectRatio":2.0470588235294116},"patientCapacity":1,"personnel":["san","rettSan"],"materials":["standard"]},{"id":"a6e71070-6b57-45d3-8863-800428e006f4","vehicleType":"KTW (KatSchutz)","name":"KTW (KatSchutz) ???","image":{"url":"/assets/ktw-vehicle.png","height":100,"aspectRatio":2.0470588235294116},"patientCapacity":2,"personnel":["san","rettSan"],"materials":["standard"]},{"id":"3d7d1950-20a0-4625-a3c0-1dd9d5c7ccc0","vehicleType":"GW-San","name":"GW-San ???","image":{"url":"/assets/gwSan-vehicle.png","height":120,"aspectRatio":2.021018593371059},"patientCapacity":0,"personnel":["gf","rettSan","rettSan","san","san","notarzt"],"materials":["big","big","big","big"]},{"id":"fc8782ac-9567-4bcd-8a5a-8d31f608f03d","vehicleType":"NEF","name":"NEF ???","image":{"url":"/assets/nef-vehicle.png","height":70,"aspectRatio":2.4120194910665944},"patientCapacity":0,"personnel":["notarzt","notSan"],"materials":["standard"]},{"id":"c0690dad-e6be-452f-85e0-2dd942241315","vehicleType":"Tragetrupp","name":"Tragetrupp ???","image":{"url":"/assets/carrying-unit.svg","height":210,"aspectRatio":1},"patientCapacity":1,"personnel":[],"materials":[]},{"id":"cad2cc9b-a624-4020-aa5f-180ed0160f33","vehicleType":"RTH","name":"RTH ???","image":{"url":"/assets/rth-vehicle.svg","height":300,"aspectRatio":2.3846153846153846},"patientCapacity":1,"personnel":["notarzt","notSan"],"materials":["standard"]}],"materialTemplates":{"standard":{"materialType":"standard","canCaterFor":{"red":2,"yellow":0,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":5.5,"image":{"url":"/assets/material.svg","height":40,"aspectRatio":1}},"big":{"materialType":"big","canCaterFor":{"red":2,"yellow":2,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":10,"image":{"url":"/assets/material.svg","height":56,"aspectRatio":1}}},"personnelTemplates":{"san":{"personnelType":"san","canCaterFor":{"red":0,"yellow":0,"green":5,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":5.5,"image":{"url":"/assets/san-personnel.svg","height":80,"aspectRatio":1}},"rettSan":{"personnelType":"rettSan","canCaterFor":{"red":1,"yellow":2,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":5.5,"image":{"url":"/assets/rettSan-personnel.svg","height":80,"aspectRatio":1}},"notSan":{"personnelType":"notSan","canCaterFor":{"red":2,"yellow":1,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":5.5,"image":{"url":"/assets/notSan-personnel.svg","height":80,"aspectRatio":1}},"notarzt":{"personnelType":"notarzt","canCaterFor":{"red":2,"yellow":2,"green":2,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":15,"image":{"url":"/assets/notarzt-personnel.svg","height":80,"aspectRatio":1}},"gf":{"personnelType":"gf","canCaterFor":{"red":0,"yellow":0,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":0,"treatmentRange":0,"image":{"url":"/assets/gf-personnel.svg","height":80,"aspectRatio":1}}},"mapImageTemplates":[{"id":"90db6ee0-b8ba-4131-bc87-264fc218fa8f","name":"Feuer","image":{"url":"/assets/fire.svg","height":427,"aspectRatio":0.7330210772833724}},{"id":"9b27ad1c-d1d0-4bd1-9e93-e62d50969085","name":"Brennendes Haus","image":{"url":"/assets/house-fire.svg","height":623,"aspectRatio":0.6308186195826645}}],"eocLog":[],"participantId":"657034","spatialTrees":{"materials":{"spatialTreeAsJSON":{"children":[],"height":1,"leaf":true,"minX":null,"minY":null,"maxX":null,"maxY":null}},"patients":{"spatialTreeAsJSON":{"children":[],"height":1,"leaf":true,"minX":null,"minY":null,"maxX":null,"maxY":null}},"personnel":{"spatialTreeAsJSON":{"children":[],"height":1,"leaf":true,"minX":null,"minY":null,"maxX":null,"maxY":null}}},"configuration":{"pretriageEnabled":true,"bluePatientsEnabled":false,"tileMapProperties":{"tileUrl":"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}","maxZoom":20}}}}} \ No newline at end of file diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json new file mode 100644 index 000000000..d2299c71f --- /dev/null +++ b/benchmark/package-lock.json @@ -0,0 +1,3523 @@ +{ + "name": "digital-fuesim-manv-benchmark", + "version": "1.2.3-test14", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "digital-fuesim-manv-benchmark", + "version": "1.2.3-test14", + "dependencies": { + "digital-fuesim-manv-shared": "file:../shared", + "immer": "^9.0.17", + "lodash-es": "^4.17.21" + }, + "devDependencies": { + "@types/lodash-es": "^4.17.6", + "@types/node": "^16", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", + "eslint-plugin-total-functions": "6.0.0", + "eslint-plugin-unicorn": "^45.0.2", + "ts-node": "^10.9.1", + "typescript": "~4.9.4" + }, + "engines": { + "node": ">=16", + "npm": ">=8" + } + }, + "../shared": { + "name": "digital-fuesim-manv-shared", + "version": "1.2.3-test14", + "dependencies": { + "@noble/hashes": "^1.2.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", + "immer": "^9.0.17", + "lodash-es": "^4.17.21", + "rbush": "^3.0.1", + "rbush-knn": "github:mourner/rbush-knn", + "reflect-metadata": "^0.1.13", + "uuid": "^9.0.0" + }, + "devDependencies": { + "@types/jest": "^29.2.5", + "@types/lodash-es": "^4.17.6", + "@types/rbush": "^3.0.0", + "@types/uuid": "^9.0.0", + "@types/validator": "^13.7.10", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", + "eslint-plugin-total-functions": "6.0.0", + "eslint-plugin-unicorn": "^45.0.2", + "jest": "^29.3.1", + "ts-jest": "^29.0.5", + "ts-node": "^10.9.1", + "typescript": "~4.9.4" + }, + "engines": { + "node": ">=16", + "npm": ">=8" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.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==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "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==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "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": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "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": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.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": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.1.2.tgz", + "integrity": "sha512-7qELuQWWjVDdVsFQ5+beUl+KPczrEDA7S3zM4QUd/bJl7oXgsmpXaEVqrRTnOBqenOV4rWf2kVZk2Ot085zPWA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "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/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "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", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@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, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@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": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.14.191", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", + "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", + "dev": true + }, + "node_modules/@types/lodash-es": { + "version": "4.17.6", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz", + "integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", + "dev": true + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", + "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/type-utils": "5.48.1", + "@typescript-eslint/utils": "5.48.1", + "debug": "^4.3.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "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/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "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/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "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/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", + "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "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/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "eslint-visitor-keys": "^3.3.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/experimental-utils": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.46.1.tgz", + "integrity": "sha512-M79mkB+wOuiBG8jzOVNA2h5izOip5CNPZV1K3tvE/qry/1Oh/bnKYhNWQNiH2h9O3B73YK60GmiqrUpprnQ5sQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "5.46.1" + }, + "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/parser": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz", + "integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", + "debug": "^4.3.4" + }, + "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/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "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/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "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/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "eslint-visitor-keys": "^3.3.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/scope-manager": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.46.1.tgz", + "integrity": "sha512-iOChVivo4jpwUdrJZyXSMrEIM/PvsbbDOX1y3UCKjSgWn+W89skxWaYXACQfxmIGhPVpRWK/VWPYc+bad6smIA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/visitor-keys": "5.46.1" + }, + "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.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", + "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/utils": "5.48.1", + "debug": "^4.3.4", + "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/type-utils/node_modules/@typescript-eslint/scope-manager": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" + }, + "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/node_modules/@typescript-eslint/types": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "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/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "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/type-utils/node_modules/@typescript-eslint/utils": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", + "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "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/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "eslint-visitor-keys": "^3.3.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/types": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.1.tgz", + "integrity": "sha512-Z5pvlCaZgU+93ryiYUwGwLl9AQVB/PQ1TsJ9NZ/gHzZjN7g9IAn6RSDkpCV8hqTwAiaj6fmCcKSQeBPlIpW28w==", + "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.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.46.1.tgz", + "integrity": "sha512-j9W4t67QiNp90kh5Nbr1w92wzt+toiIsaVPnEblB2Ih2U9fqBTyqV9T3pYWZBRt6QoMh/zVWP59EpuCjc4VRBg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/visitor-keys": "5.46.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "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.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.46.1.tgz", + "integrity": "sha512-RBdBAGv3oEpFojaCYT4Ghn4775pdjvwfDOfQ2P6qzNVgQOVrnSPe5/Pb88kv7xzYQjoio0eKHKB9GJ16ieSxvA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.46.1", + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/typescript-estree": "5.46.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "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.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.1.tgz", + "integrity": "sha512-jczZ9noovXwy59KjRTk1OftT78pwygdcmCuBf8yMoWt/8O8l+6x2LSEze0E4TeepXK4MezW3zGSyoDRZK7Y9cg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.46.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/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, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/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": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/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": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "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/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/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/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ci-info": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", + "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", + "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/clean-regexp/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": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "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": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "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": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "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/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/digital-fuesim-manv-shared": { + "resolved": "../shared", + "link": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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": ">=6.0.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.5.tgz", + "integrity": "sha512-7h8MM2EQhsCA7pU/Nv78qOXFpD8Rhqd12gYiSJVkrH9+e8VuA8JlPJK/hQjjlLv6pJvx/z1iRFKzYb0XT/RuAQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "unbox-primitive": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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": "8.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", + "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "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.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "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" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", + "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.27.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.4.tgz", + "integrity": "sha512-Z1jVt1EGKia1X9CnBCkpAOhWy8FgQ7OmJ/IblEkT82yrFU/xJaxwujaTzLWqigewwynRQ9mmHfX9MtAfhxm0sA==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.0", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", + "has": "^1.0.3", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-total-functions": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-total-functions/-/eslint-plugin-total-functions-6.0.0.tgz", + "integrity": "sha512-ZgNAclR/IZcYFT7xPyvG5Iwf7HFPm1FSSSHGNq0Fs0JgKlQ1+0SWk5WWSDFDON2RUdzezKOGQpfatDt7ud2CPg==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "^5.27.1", + "@typescript-eslint/experimental-utils": "^5.27.1", + "@typescript-eslint/parser": "^5.27.1", + "tsutils": "^3.17.1" + }, + "peerDependencies": { + "eslint": "^8.17.0", + "typescript": "^4.7.3" + } + }, + "node_modules/eslint-plugin-unicorn": { + "version": "45.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-45.0.2.tgz", + "integrity": "sha512-Y0WUDXRyGDMcKLiwgL3zSMpHrXI00xmdyixEGIg90gHnj0PcHY4moNv3Ppje/kDivdAy5vUeUr7z211ImPv2gw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.19.1", + "@eslint-community/eslint-utils": "^4.1.2", + "ci-info": "^3.6.1", + "clean-regexp": "^1.0.0", + "esquery": "^1.4.0", + "indent-string": "^4.0.0", + "is-builtin-module": "^3.2.0", + "jsesc": "^3.0.2", + "lodash": "^4.17.21", + "pluralize": "^8.0.0", + "read-pkg-up": "^7.0.1", + "regexp-tree": "^0.1.24", + "regjsparser": "^0.9.1", + "safe-regex": "^2.1.1", + "semver": "^7.3.8", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" + }, + "peerDependencies": { + "eslint": ">=8.28.0" + } + }, + "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": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "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": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "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": ">=10" + } + }, + "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": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "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, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "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, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "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": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "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": ">=4.0" + } + }, + "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": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "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": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@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/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-glob": "^4.0.1" + }, + "engines": { + "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": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "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": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "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/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "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/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/ignore": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "9.0.17", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.17.tgz", + "integrity": "sha512-+hBruaLSQvkPfxRiTLK/mi4vLH+/VQS6z2KJahdoxlleFOI8ARqzOF17uy12eFDlqWmPoygwc5evgwcp+dlHhg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "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/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "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": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "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/internal-slot": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", + "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-builtin-module": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", + "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-sdsl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "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": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "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": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "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/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "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/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-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "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.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "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/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "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/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/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "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/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-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "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-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/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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/punycode": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz", + "integrity": "sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==", + "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/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/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/read-pkg-up/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/read-pkg-up/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/read-pkg-up/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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/regexp-tree": { + "version": "0.1.24", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.24.tgz", + "integrity": "sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw==", + "dev": true, + "bin": { + "regexp-tree": "bin/regexp-tree" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/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-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/safe-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz", + "integrity": "sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==", + "dev": true, + "dependencies": { + "regexp-tree": "~0.1.1" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/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.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", + "dev": true + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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/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/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/ljharb" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "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/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "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/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/typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/which": { + "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-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "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/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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" + } + } + } +} diff --git a/benchmark/package.json b/benchmark/package.json new file mode 100644 index 000000000..3a3c83b7e --- /dev/null +++ b/benchmark/package.json @@ -0,0 +1,35 @@ +{ + "name": "digital-fuesim-manv-benchmark", + "version": "1.2.3-test14", + "type": "module", + "scripts": { + "lint": "eslint --max-warnings 0 --ignore-path .gitignore \"./**/*.{ts,js,yml,html}\"", + "lint:fix": "eslint --ignore-path .gitignore --fix \"./**/*.{ts,js,yml,html}\"", + "benchmark:linux-macos": "NODE_ENV=production node --experimental-specifier-resolution=node --loader ts-node/esm src/app.ts", + "benchmark:windows": "set NODE_ENV=production&& node --experimental-specifier-resolution=node --loader ts-node/esm src/app.ts", + "benchmark": "(pwd && npm run benchmark:linux-macos) || npm run benchmark:windows" + }, + "private": true, + "engines": { + "node": ">=16", + "npm": ">=8" + }, + "dependencies": { + "immer": "^9.0.17", + "lodash-es": "^4.17.21", + "digital-fuesim-manv-shared": "file:../shared" + }, + "devDependencies": { + "@types/lodash-es": "^4.17.6", + "@types/node": "^16", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", + "eslint-plugin-total-functions": "6.0.0", + "eslint-plugin-unicorn": "^45.0.2", + "ts-node": "^10.9.1", + "typescript": "~4.9.4" + } +} diff --git a/benchmark/src/app.ts b/benchmark/src/app.ts new file mode 100644 index 000000000..465d3a526 --- /dev/null +++ b/benchmark/src/app.ts @@ -0,0 +1,99 @@ +import { promises as fs } from 'node:fs'; +import os from 'node:os'; +import { countBy } from 'lodash-es'; +import { print } from './print'; +import { steps, StepState } from './steps'; + +// Print some information about the system +console.log(` +System Information: + OS: ${os.version()} ${os.release()} + CPUs: ${Object.entries(countBy(os.cpus(), (cpu) => cpu.model)) + .map(([model, count]) => `${count} × ${model}`) + .join(', ')} + RAM: ${Math.round(os.totalmem() / 1024 / 1024)}MB + Node.js: ${process.version} + +`); + +const pathToData = 'data'; + +const filenames = await fs.readdir(pathToData); +const fileBenchmarkResults: BenchmarkResult[] = []; + +for (const filename of filenames) { + // eslint-disable-next-line no-await-in-loop + const benchmarkResult = await benchmarkFile(filename); + print('\n\n'); + if (benchmarkResult) { + fileBenchmarkResults.push(benchmarkResult); + } +} + +// Print the end results to the console +print('\n'); +console.table( + fileBenchmarkResults + .map((result) => ({ + fileName: result.fileName, + fileSize: `${(result.fileSize / 1024 / 1024).toPrecision(2)}MB`, + ...steps + .map((step) => step.getColumnToPrint(result.stepState)) + .reduce((columns, column) => ({ ...columns, ...column }), {}), + })) + // We don't want an extra column for the array index + .reduce<{ [fileName: string]: any }>((table, { fileName, ...rest }) => { + table[fileName] = rest; + return table; + }, {}) +); + +interface BenchmarkResult { + fileName: string; + /** + * Size of the file in bytes + */ + fileSize: number; + /** + * Not all steps results must be included in this state, as some steps might not be run because of an error in a previous step + */ + stepState: StepState; +} + +async function benchmarkFile( + fileName: string +): Promise { + const path = `${pathToData}/${fileName}`; + let data; + try { + // eslint-disable-next-line no-await-in-loop + data = await fs.readFile(path, 'utf8'); + } catch { + print(`Could not read file ${fileName}\n`, 'red'); + return; + } + const fileSize = (await fs.stat(path)).size; + print(`${fileName}\n`, 'blue'); + let parsedData; + try { + parsedData = JSON.parse(data); + } catch { + print('Error while parsing state export\n', 'red'); + return; + } + + const stepState = new StepState(parsedData); + for (const step of steps) { + try { + step.run(stepState); + } catch (error: any) { + print(`${error}\n`, 'red'); + break; + } + } + return { + fileName, + fileSize, + stepState, + }; +} diff --git a/benchmark/src/benchmark-step.ts b/benchmark/src/benchmark-step.ts new file mode 100644 index 000000000..73ed70dc2 --- /dev/null +++ b/benchmark/src/benchmark-step.ts @@ -0,0 +1,46 @@ +import type { BenchmarkValue } from './benchmark'; +import { benchmark } from './benchmark'; +import { print } from './print'; +import { Step } from './step'; + +/** + * A benchmark step is time measured and run multiple times + * The printed out value is the time it took to run the benchmark + */ +export class BenchmarkStep< + // TS will error during transpiling with "Type parameter 'Value' has a circular constraint.", if we use BenchmarkValue here + State extends { [Key in Name]?: BenchmarkValue | undefined }, + Name extends string & keyof State = string & keyof State, + Value extends NonNullable extends BenchmarkValue + ? T + : never = NonNullable extends BenchmarkValue + ? T + : never +> extends Step { + constructor( + name: Name, + /** + * Will be run multiple times and must therefore be deterministic + */ + private readonly functionToBenchmark: (state: State) => Value + ) { + super(name, true); + } + + protected runStep(stepState: State) { + print(` ${this.name}:`.padEnd(30, ' ')); + const endResult = benchmark(() => this.functionToBenchmark(stepState), { + onAfterIteration: (benchmarkValue) => + print(this.formatValue(benchmarkValue).padEnd(10, ' ')), + onNonDeterministicError: () => + print(' Not deterministic!', 'red'), + }); + print('\n'); + // TODO: I couldn't get the typings to work here correctly + return endResult as NonNullable; + } + + protected formatValue(value: BenchmarkValue) { + return `${Math.round(value.time)}ms`; + } +} diff --git a/benchmark/src/benchmark.ts b/benchmark/src/benchmark.ts new file mode 100644 index 000000000..67a08b483 --- /dev/null +++ b/benchmark/src/benchmark.ts @@ -0,0 +1,81 @@ +import { defaults, isEqual } from 'lodash-es'; + +export interface BenchmarkValue { + /** + * The value returned by the benchmarked function + */ + value: T; + /** + * The average time it took to run the function in ms + */ + time: number; +} + +/** + * @param functionToBenchmark the deterministic function that should be benchmarked, it will be run multiple times + * @param options additional options for the benchmark, the defaults for the respective properties are {@link defaultOptions} + */ +export function benchmark( + functionToBenchmark: () => Value, + options: BenchmarkOptions = {} +): BenchmarkValue { + // eslint-disable-next-line no-param-reassign + options = defaults(options, defaultOptions); + const benchmarkStepValues: BenchmarkValue[] = []; + for (let i = 0; i < options.numberOfIterations!; i++) { + const benchmarkStepValue = runBenchmarkOnce(functionToBenchmark); + benchmarkStepValues.push(benchmarkStepValue); + options.onAfterIteration?.(benchmarkStepValue); + } + if ( + benchmarkStepValues.length > 1 && + benchmarkStepValues.some( + ({ value }) => !isEqual(benchmarkStepValues[0]!.value, value) + ) + ) { + options.onNonDeterministicError?.(benchmarkStepValues); + } + return { + value: benchmarkStepValues[0]!.value, + time: + benchmarkStepValues.reduce( + (timeSum, { time }) => timeSum + time, + 0 + ) / options.numberOfIterations!, + }; +} + +function runBenchmarkOnce( + functionToBenchmark: () => Value +): BenchmarkValue { + const startTime = performance.now(); + const value = functionToBenchmark(); + const endTime = performance.now(); + return { + value, + time: endTime - startTime, + }; +} + +interface BenchmarkOptions { + /** + * The number of times the function to benchmark should be run + */ + numberOfIterations?: number; + /** + * Will be called after each iteration + * @param benchmarkValue the BenchmarkValue of the function to benchmark in this iteration + */ + onAfterIteration?: (benchmarkValue: BenchmarkValue) => void; + /** + * Will be called once if any of the iterations returned a different value than the first iteration (by value) + * @param benchmarkValues the BenchmarkValues of the function to benchmark in all iterations + */ + onNonDeterministicError?: ( + benchmarkValues: BenchmarkValue[] + ) => void; +} + +const defaultOptions: BenchmarkOptions = { + numberOfIterations: 3, +}; diff --git a/benchmark/src/calculation-step.ts b/benchmark/src/calculation-step.ts new file mode 100644 index 000000000..a310e354e --- /dev/null +++ b/benchmark/src/calculation-step.ts @@ -0,0 +1,29 @@ +import { Step } from './step'; + +/** + * A calculation step can be used to calculate new values from the state. + * The printed out value is the return value of the calculation function + */ +export class CalculationStep< + State extends { + [StepName: string]: any | undefined; + }, + Name extends keyof State = keyof State, + Value extends State[Name] = State[Name] +> extends Step { + constructor( + name: Name, + public readonly calculate: (state: State) => Value, + printColumn = true + ) { + super(name, printColumn); + } + + public runStep(stepState: State) { + return this.calculate(stepState); + } + + public formatValue(value: Value) { + return value; + } +} diff --git a/benchmark/src/print.ts b/benchmark/src/print.ts new file mode 100644 index 000000000..660907554 --- /dev/null +++ b/benchmark/src/print.ts @@ -0,0 +1,32 @@ +/** + * Prints a string to the console + * + * Be aware that this function does not add a newline at the end. + * This means that you can create multicolor lines by calling this function multiple times. + * ```` + * print('Hello ', 'red'); + * print('World!\n', 'green'); + * ``` + */ +export function print( + text: string, + color: keyof typeof colorEscapeCodes | null = null +) { + process.stdout.write( + `${color ? colorEscapeCodes[color] : ''}${text}${resetCode}` + ); +} + +// See https://stackoverflow.com/a/41407246/104380 +const colorEscapeCodes = { + blue: '\x1B[34m', + cyan: '\x1B[36m', + gray: '\x1B[90m', + green: '\x1B[32m', + magenta: '\x1B[35m', + red: '\x1B[31m', + white: '\x1B[37m', + yellow: '\x1B[33m', +}; + +const resetCode = '\x1B[0m'; diff --git a/benchmark/src/step.ts b/benchmark/src/step.ts new file mode 100644 index 000000000..bf2af8bed --- /dev/null +++ b/benchmark/src/step.ts @@ -0,0 +1,43 @@ +export abstract class Step< + State extends { + [StepName: string]: any | undefined; + }, + Name extends keyof State = keyof State, + Value extends State[Name] = State[Name] +> { + constructor( + public readonly name: Name, + /** + * Whether a column with the values of this step should be added to the printed table at the end + */ + private readonly printColumn: boolean + ) {} + + protected abstract runStep(state: State): NonNullable; + + /** + * This function is expected to modify the state. + * It can throw an error to stop all steps that come after it. + * It can print out information to the console. + */ + public run(state: State) { + state[this.name] = this.runStep(state); + } + + protected abstract formatValue(value: NonNullable): any; + + public getColumnToPrint(state: State): { + [columnName: string]: any; + } { + const value = state[this.name]; + return this.printColumn + ? { + [this.name]: + value === undefined + ? // If the value is undefined, the step was not run (probably because of an error in a previous step) + undefined + : this.formatValue(value), + } + : {}; + } +} diff --git a/benchmark/src/steps.ts b/benchmark/src/steps.ts new file mode 100644 index 000000000..eb1ec7341 --- /dev/null +++ b/benchmark/src/steps.ts @@ -0,0 +1,264 @@ +import type { + ExerciseAction, + ExerciseState, + StateExport, +} from 'digital-fuesim-manv-shared'; +import { + applyAction, + cloneDeepMutable, + migrateStateExport, + reduceExerciseState, + sortObject, + StrictObject, + validateExerciseExport, +} from 'digital-fuesim-manv-shared'; +import produce, { freeze } from 'immer'; +import { isEqual } from 'lodash-es'; +import type { BenchmarkValue } from './benchmark'; +import { benchmark } from './benchmark'; +import { BenchmarkStep } from './benchmark-step'; +import { CalculationStep } from './calculation-step'; +import { print } from './print'; +import type { Step } from './step'; + +export class StepState { + /** + * The end result of the state export migration + */ + public readonly migrate?: BenchmarkValue; + /** + * The end result of the exercise validation + * The value is an array of the errors + */ + public readonly validateExercise?: BenchmarkValue< + ReturnType + >; + /** + * The frozen state of the exercise + */ + public readonly freezeState?: { + initialState: ExerciseState; + actionHistory: readonly ExerciseAction[]; + }; + // There are three different ways to create the end state of the exercise + public readonly newImmerDraft?: BenchmarkValue; + public readonly sameImmerDraft?: BenchmarkValue; + public readonly noImmerDraft?: BenchmarkValue; + /** + * Whether the end states of all three methods to create them are equal + */ + public readonly endStatesAreEqual?: boolean; + /** + * The total benchmarked time it took to execute one action of each type in ms + * (sum of all benchmarked times) + * Sorted by time (descending) + */ + public readonly benchmarkActions?: { + [Key in ExerciseAction['type']]?: number; + }; + /** + * A string with the most expensive action in the exercise (by total summed-up time) and a representation of the respective time + */ + public readonly mostExpensiveAction?: string; + /** + * The number of actions of each type + * Sorted by amount (descending) + */ + public readonly numberOfActionsPerType?: { + [Key in ExerciseAction['type']]?: number; + }; + /** + * The number of actions in the exercise + */ + // The key is used as the column-name in the table, therefore the weird name + public readonly '#actions'?: number; + + constructor(public readonly data: StateExport) {} +} + +/** + * The steps are executed for each state export. + * The steps are executed in the order they are defined. + * The result of each step is stored in `stepState[stateName]`. + * Each step can only access the results of the previous steps. + *`stepState.data` is always available. + * + * Steps can print to the console and throw errors to stop the execution of the specific exercise-state. + * In addition, at the end of the benchmark, there is a summary of the results in the form of a table. + * A lot of this is specified in the individual step classes. + */ +export const steps: Step[] = [ + new BenchmarkStep( + 'migrate', + ({ data }) => migrateStateExport(data) as StateExport + ), + new BenchmarkStep('validateExercise', ({ migrate: migratedValues }) => + validateExerciseExport(migratedValues!.value) + ), + new CalculationStep( + 'freezeState', + ({ migrate: migratedValues }) => { + if (!migratedValues?.value.history) { + throw new Error('State export is missing history'); + } + const history = migratedValues.value.history; + freeze(history, true); + return history; + }, + false + ), + new BenchmarkStep('newImmerDraft', ({ freezeState }) => { + const { actionHistory, initialState } = freezeState!; + + // Apply each action on a new immer draft + return actionHistory.reduce( + (state, action) => reduceExerciseState(state, action), + initialState + ); + }), + new BenchmarkStep('sameImmerDraft', ({ freezeState }) => { + const { actionHistory, initialState } = freezeState!; + + // Apply all action on the same immer draft + return produce(initialState, (draftState) => { + for (const action of actionHistory) { + applyAction(draftState, action); + } + }); + }), + new BenchmarkStep('noImmerDraft', ({ freezeState }) => { + const { actionHistory, initialState } = freezeState!; + + // Apply all action on the same immer draft + return actionHistory.reduce( + (state, action) => applyAction(state, action), + cloneDeepMutable(initialState) + ); + }), + new CalculationStep( + 'endStatesAreEqual', + ({ newImmerDraft, sameImmerDraft, noImmerDraft }) => { + const endStatesAreEqual = + isEqual(newImmerDraft!.value, sameImmerDraft!.value) && + isEqual(newImmerDraft!.value, noImmerDraft!.value); + if (!endStatesAreEqual) { + print( + ` The endStates of the previous three steps are not equal! + This most likely means that a reducer is either not deterministic or makes some assumptions about immer specific stuff (use of "original()"). + To further debug this, you should log the endStates of the respective exercises and can compare them directly in vscode via "Compare file with". +`, + 'red' + ); + } + return endStatesAreEqual; + }, + false + ), + + new CalculationStep( + 'benchmarkActions', + ({ freezeState }) => { + print(` benchmarkActions: `); + const { actionHistory, initialState } = freezeState!; + const totalTimePerAction: { + [Key in ExerciseAction['type']]?: number; + } = {}; + let currentState = initialState; + for (const action of actionHistory) { + // eslint-disable-next-line @typescript-eslint/no-loop-func + const { value: newState, time } = benchmark(() => + reduceExerciseState(currentState, action) + ); + + currentState = newState; + totalTimePerAction[action.type] = + (totalTimePerAction[action.type] ?? 0) + time; + } + const sortedTotalTimePerAction = sortObject( + totalTimePerAction, + ([, timeA], [, timeB]) => timeB! - timeA! + ); + print( + // In the object are only entries we explicitly set -> no need to check for undefined + ( + StrictObject.entries(sortedTotalTimePerAction) as [ + ExerciseAction['type'], + number + ][] + ) + .map(([type, time]) => `${type}: ${time.toFixed(2)}ms`) + .join(', ') + ); + print(`\n`); + return sortedTotalTimePerAction; + }, + false + ), + new CalculationStep( + 'mostExpensiveAction', + ({ benchmarkActions, newImmerDraft }) => { + const mostExpensiveAction = StrictObject.entries( + benchmarkActions! + )[0]; + if (!mostExpensiveAction) { + return `No actions`; + } + const summedUpExerciseTime = + StrictObject.values(benchmarkActions!).reduce( + // In the object are only entries we explicitly set + (totalTime, timePerAction) => totalTime! + timePerAction!, + 0 + ) ?? 0; + const summedUpVsDirectTime = + summedUpExerciseTime / newImmerDraft!.time; + if (summedUpVsDirectTime > 1.1 || summedUpVsDirectTime < 0.9) { + print( + ` The summed up time of all actions is ${summedUpVsDirectTime.toFixed( + 2 + )} times the time of the direct benchmark ("newImmerDraft").\n`, + 'yellow' + ); + } + + return `${mostExpensiveAction[0]} ${( + (mostExpensiveAction[1]! / summedUpExerciseTime) * + 100 + ).toFixed(2)}%`; + } + ), + new CalculationStep( + 'numberOfActionsPerType', + ({ freezeState }) => { + print(` numberOfActionsPerType: `); + const { actionHistory } = freezeState!; + const numberOfActionsPerType: { + [Key in ExerciseAction['type']]?: number; + } = {}; + for (const action of actionHistory) { + numberOfActionsPerType[action.type] = + (numberOfActionsPerType[action.type] ?? 0) + 1; + } + const sortedNumberOfActionsPerType = sortObject( + numberOfActionsPerType, + ([, amountA], [, amountB]) => amountB! - amountA! + ); + print( + // In the object are only entries we explicitly set -> no need to check for undefined + ( + StrictObject.entries(sortedNumberOfActionsPerType) as [ + ExerciseAction['type'], + number + ][] + ) + .map(([type, amount]) => `${type}: ${amount}`) + .join(', ') + ); + return sortedNumberOfActionsPerType; + }, + false + ), + new CalculationStep( + '#actions', + ({ freezeState }) => freezeState!.actionHistory.length + ), +]; diff --git a/benchmark/tsconfig.json b/benchmark/tsconfig.json new file mode 100644 index 000000000..95b1850a6 --- /dev/null +++ b/benchmark/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "strict": true, + "noUncheckedIndexedAccess": true, + "module": "ESNext", + "target": "ESNext", + "declaration": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "esModuleInterop": true, + "outDir": "./dist", + "sourceMap": true, + "moduleResolution": "node", + "declarationMap": true, + "rootDir": "./src", + "skipLibCheck": true, + "types": ["node"] + }, + "references": [], + "include": ["src/**/*"], + "exclude": ["node_modules"] +} diff --git a/docker-compose.yml b/docker-compose.yml index 0cffe9704..610b7c785 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,6 +18,10 @@ services: - .env volumes: - dfm-data:/${DFM_PERSISTENT_DATA_PATH} + # To overwrite the contents of the about pages, mount a directory into the container + # The directory can contain imprint.html, privacy.html and license.html + # Example + # - ./about:/usr/local/app/frontend/dist/digital-fuesim-manv/assets/about db: image: postgres:14 container_name: dfm_postgres diff --git a/docker/nginx/locations b/docker/nginx/locations index e041da004..609378103 100644 --- a/docker/nginx/locations +++ b/docker/nginx/locations @@ -1,12 +1,19 @@ # Frontend + root /usr/local/app/frontend/dist/digital-fuesim-manv; + error_page 404 /index.html; + error_page 403 /index.html; + + location /assets/about { + # Requests to this location should not fall back to index.html + } + location / { - alias /usr/local/app/frontend/dist/digital-fuesim-manv/; try_files $uri $uri/ /index.html; } # API location /api { - proxy_pass http://localhost:3201; + proxy_pass http://localhost:3201; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; @@ -14,10 +21,10 @@ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; include conf.d/upload-limit; - } + } # Websocket - location /socket.io { + location /socket.io { proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_pass http://localhost:3200; @@ -28,4 +35,4 @@ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; include conf.d/upload-limit; - } + } diff --git a/docs/swagger.yml b/docs/swagger.yml index 9e5d85c9f..78cdec709 100644 --- a/docs/swagger.yml +++ b/docs/swagger.yml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: Digital Fuesim MANV HTTP API description: HTTP API of the digital-fuesim-manv project - version: 0.0.0 + version: 1.2.3-test14 paths: /api/health: get: @@ -38,7 +38,6 @@ paths: application/json: schema: $ref: '#/components/schemas/ErrorResponse' - /api/exercise/{exerciseId}: parameters: - $ref: '#/components/parameters/ExerciseId' @@ -68,7 +67,6 @@ paths: application/json: schema: $ref: '#/components/schemas/ErrorResponse' - /api/exercise/{exerciseId}/history: parameters: - $ref: '#/components/parameters/ExerciseId' diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json index 57dcba438..722c4bc07 100644 --- a/frontend/.eslintrc.json +++ b/frontend/.eslintrc.json @@ -1,6 +1,6 @@ { "root": true, - "ignorePatterns": "index.html", + "ignorePatterns": ["index.html", "**/assets/about/*.html"], "overrides": [ { "files": ["*.ts", "*.js"], diff --git a/frontend/.npmrc b/frontend/.npmrc new file mode 100644 index 000000000..a6ee44b04 --- /dev/null +++ b/frontend/.npmrc @@ -0,0 +1 @@ +install-links=false diff --git a/frontend/README.md b/frontend/README.md index 7b1fafa4c..1c0cfb571 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -110,7 +110,7 @@ The [ExerciseMapComponent](src/app/pages/exercises/exercise/shared/exercise-map/ The [OlMapManager](src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts) manages all the OpenLayers stuff and renders the map on the canvas. The map consists of different layers. Each layer only displays one kind of element. How an element in this layer should be rendered and what interactions are possible is defined in the [specific ElementFeatureManagers](src/app/pages/exercises/exercise/shared/exercise-map/feature-managers). -They all inherit from [ElementFeatureManager](src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-feature-manager.ts) and make mostly use of `Helper` classes to add additional functionality via composition. +The feature managers for features that should be moveable by the user extend [MoveableFeatureManager](src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts), which is the central point for all movement logic. They have a custom API that allows reacting to changes in an element ([ElementManager](src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts)) and an API that allows for interaction with other elements via the OlMapManager ([FeatureManager](src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts)). ## Action proposals diff --git a/frontend/cypress/plugins/index.ts b/frontend/cypress/plugins/index.ts index a06120efd..8ff4dd822 100644 --- a/frontend/cypress/plugins/index.ts +++ b/frontend/cypress/plugins/index.ts @@ -1,4 +1,5 @@ // @ts-expect-error there is no type definition for this package yet +// eslint-disable-next-line no-restricted-imports import * as cypressImageDiffPlugin from 'cypress-image-diff-js/dist/plugin'; // eslint-disable-next-line @typescript-eslint/no-empty-function diff --git a/frontend/cypress/support/commands.ts b/frontend/cypress/support/commands.ts index 4e45085a9..210f5e025 100644 --- a/frontend/cypress/support/commands.ts +++ b/frontend/cypress/support/commands.ts @@ -42,6 +42,7 @@ // -- This will overwrite an existing command -- // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) // @ts-expect-error there is no type definition for this package yet +// eslint-disable-next-line no-restricted-imports import * as cypressImageDiffCommand from 'cypress-image-diff-js/dist/command'; cypressImageDiffCommand(); diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ea8ce0d3c..b43064d4f 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,31 +1,31 @@ { "name": "digital-fuesim-manv-frontend", - "version": "0.0.0", + "version": "1.2.3-test14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-frontend", - "version": "0.0.0", - "dependencies": { - "@angular/animations": "~15.0.4", - "@angular/common": "~15.0.4", - "@angular/compiler": "~15.0.4", - "@angular/core": "~15.0.4", - "@angular/forms": "~15.0.4", - "@angular/material": "^15.0.3", - "@angular/platform-browser": "~15.0.4", - "@angular/platform-browser-dynamic": "~15.0.4", - "@angular/router": "~15.0.4", - "@ng-bootstrap/ng-bootstrap": "^14.0.0", + "version": "1.2.3-test14", + "dependencies": { + "@angular/animations": "~15.1.0", + "@angular/common": "~15.1.0", + "@angular/compiler": "~15.1.0", + "@angular/core": "~15.1.0", + "@angular/forms": "~15.1.0", + "@angular/material": "^15.1.0", + "@angular/platform-browser": "~15.1.0", + "@angular/platform-browser-dynamic": "~15.1.0", + "@angular/router": "~15.1.0", + "@ng-bootstrap/ng-bootstrap": "^14.0.1", "@ngrx/store": "^15.1.0", "bootstrap": "^5.2.3", - "bootstrap-icons": "^1.10.2", - "chart.js": "^4.1.1", + "bootstrap-icons": "^1.10.3", + "chart.js": "^4.1.2", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "digital-fuesim-manv-shared": "file:../shared", - "immer": "^9.0.16", + "immer": "^9.0.17", "lodash-es": "4.17.21", "ol": "^7.2.2", "rxjs": "~7.8.0", @@ -33,32 +33,32 @@ "tslib": "^2.4.1" }, "devDependencies": { - "@angular-devkit/build-angular": "^15.0.4", + "@angular-devkit/build-angular": "^15.1.1", "@angular-eslint/builder": "15.1.0", "@angular-eslint/eslint-plugin": "15.1.0", "@angular-eslint/eslint-plugin-template": "15.1.0", "@angular-eslint/schematics": "15.1.0", "@angular-eslint/template-parser": "15.1.0", - "@angular/cli": "~15.0.4", - "@angular/compiler-cli": "~15.0.4", + "@angular/cli": "~15.1.1", + "@angular/compiler-cli": "~15.1.0", "@types/chart.js": "^2.9.37", - "@types/jest": "^29.2.4", + "@types/jest": "^29.2.5", "@types/lodash-es": "^4.17.6", - "@types/node": "^18", - "@typescript-eslint/eslint-plugin": "5.47.0", - "@typescript-eslint/parser": "5.47.0", + "@types/node": "^16", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", "cypress": "^9.5.3", "cypress-image-diff-js": "^1.21.1", - "eslint": "^8.30.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-rxjs": "^5.0.2", "eslint-plugin-rxjs-angular": "^2.0.0", "eslint-plugin-unicorn": "^45.0.2", "jest": "^29.3.1", "lodash": "^4.17.21", - "ts-jest": "^29.0.3", - "typescript": "~4.8.2" + "ts-jest": "^29.0.5", + "typescript": "~4.9.4" }, "engines": { "node": ">=16", @@ -67,11 +67,12 @@ }, "../shared": { "name": "digital-fuesim-manv-shared", - "version": "0.0.0", + "version": "1.2.3-test14", "dependencies": { + "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", - "immer": "^9.0.16", + "immer": "^9.0.17", "lodash-es": "^4.17.21", "rbush": "^3.0.1", "rbush-knn": "github:mourner/rbush-knn", @@ -79,22 +80,22 @@ "uuid": "^9.0.0" }, "devDependencies": { - "@types/jest": "^29.2.4", + "@types/jest": "^29.2.5", "@types/lodash-es": "^4.17.6", "@types/rbush": "^3.0.0", "@types/uuid": "^9.0.0", "@types/validator": "^13.7.10", - "@typescript-eslint/eslint-plugin": "5.47.0", - "@typescript-eslint/parser": "5.47.0", - "eslint": "^8.30.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-total-functions": "6.0.0", "eslint-plugin-unicorn": "^45.0.2", "jest": "^29.3.1", - "ts-jest": "^29.0.3", + "ts-jest": "^29.0.5", "ts-node": "^10.9.1", - "typescript": "~4.8.2" + "typescript": "~4.9.4" }, "engines": { "node": ">=16", @@ -103,8 +104,7 @@ }, "node_modules/@ampproject/remapping": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.1.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -114,12 +114,12 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1500.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1500.4.tgz", - "integrity": "sha512-U9RQueICmmNk9c2zQjUN8qi/+H6kO2VKqeyuh3Vwj6yj4lQEINf1SNX8Ba9UFH/rxNo64iFM0k5x5vX0VajvCw==", + "version": "0.1501.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1501.1.tgz", + "integrity": "sha512-2uDa/+nVGwQ5X6UJtB14V37SbD/64WSg0hKyX5z1yp6wYrSuk7PWV8hddIsiYM3aIT5wTGqfLil6NkV4G/BzQw==", "dev": true, "dependencies": { - "@angular-devkit/core": "15.0.4", + "@angular-devkit/core": "15.1.1", "rxjs": "6.6.7" }, "engines": { @@ -147,37 +147,37 @@ "dev": true }, "node_modules/@angular-devkit/build-angular": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-15.0.4.tgz", - "integrity": "sha512-F1KyaZEIWcVP2xIIiu3ZnH+FzuEehR9rli1F566dPijbll8EnknnItEugFtVhyoaVTh8eJmm1SfsoQrneMbrsg==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-15.1.1.tgz", + "integrity": "sha512-9eziOA4uZwIg8OYjebkKz/yqQ1WIqajGrXr/goaAKcKhr8BprWXs5NhkIzMrELekA/dZOkR6Gpwz8d/XwplCww==", "dev": true, "dependencies": { "@ampproject/remapping": "2.2.0", - "@angular-devkit/architect": "0.1500.4", - "@angular-devkit/build-webpack": "0.1500.4", - "@angular-devkit/core": "15.0.4", - "@babel/core": "7.20.2", - "@babel/generator": "7.20.4", + "@angular-devkit/architect": "0.1501.1", + "@angular-devkit/build-webpack": "0.1501.1", + "@angular-devkit/core": "15.1.1", + "@babel/core": "7.20.12", + "@babel/generator": "7.20.7", "@babel/helper-annotate-as-pure": "7.18.6", - "@babel/plugin-proposal-async-generator-functions": "7.20.1", - "@babel/plugin-transform-async-to-generator": "7.18.6", + "@babel/plugin-proposal-async-generator-functions": "7.20.7", + "@babel/plugin-transform-async-to-generator": "7.20.7", "@babel/plugin-transform-runtime": "7.19.6", "@babel/preset-env": "7.20.2", - "@babel/runtime": "7.20.1", - "@babel/template": "7.18.10", + "@babel/runtime": "7.20.7", + "@babel/template": "7.20.7", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "15.0.4", + "@ngtools/webpack": "15.1.1", "ansi-colors": "4.1.3", "autoprefixer": "10.4.13", - "babel-loader": "9.1.0", + "babel-loader": "9.1.2", "babel-plugin-istanbul": "6.1.1", "browserslist": "4.21.4", - "cacache": "17.0.2", + "cacache": "17.0.4", "chokidar": "3.5.3", "copy-webpack-plugin": "11.0.0", "critters": "0.0.16", "css-loader": "6.7.3", - "esbuild-wasm": "0.15.13", + "esbuild-wasm": "0.16.17", "glob": "8.0.3", "https-proxy-agent": "5.0.1", "inquirer": "8.2.4", @@ -187,27 +187,27 @@ "less-loader": "11.1.0", "license-webpack-plugin": "4.0.2", "loader-utils": "3.2.1", - "magic-string": "0.26.7", - "mini-css-extract-plugin": "2.6.1", + "magic-string": "0.27.0", + "mini-css-extract-plugin": "2.7.2", "open": "8.4.0", "ora": "5.4.1", "parse5-html-rewriting-stream": "6.0.1", "piscina": "3.2.0", - "postcss": "8.4.19", - "postcss-loader": "7.0.1", + "postcss": "8.4.21", + "postcss-loader": "7.0.2", "resolve-url-loader": "5.0.0", "rxjs": "6.6.7", - "sass": "1.56.1", + "sass": "1.57.1", "sass-loader": "13.2.0", "semver": "7.3.8", "source-map-loader": "4.0.1", "source-map-support": "0.5.21", - "terser": "5.15.1", + "terser": "5.16.1", "text-table": "0.2.0", "tree-kill": "1.2.2", "tslib": "2.4.1", "webpack": "5.75.0", - "webpack-dev-middleware": "5.3.3", + "webpack-dev-middleware": "6.0.1", "webpack-dev-server": "4.11.1", "webpack-merge": "5.8.0", "webpack-subresource-integrity": "5.1.0" @@ -218,7 +218,7 @@ "yarn": ">= 1.13.0" }, "optionalDependencies": { - "esbuild": "0.15.13" + "esbuild": "0.16.17" }, "peerDependencies": { "@angular/compiler-cli": "^15.0.0", @@ -229,7 +229,7 @@ "ng-packagr": "^15.0.0", "protractor": "^7.0.0", "tailwindcss": "^2.0.0 || ^3.0.0", - "typescript": "~4.8.2" + "typescript": ">=4.8.2 <5.0" }, "peerDependenciesMeta": { "@angular/localize": { @@ -255,11 +255,49 @@ } } }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", + "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.12", + "@babel/types": "^7.20.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@angular-devkit/build-angular/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, + "license": "Apache-2.0", "dependencies": { "tslib": "^1.9.0" }, @@ -269,17 +307,16 @@ }, "node_modules/@angular-devkit/build-angular/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 + "dev": true, + "license": "0BSD" }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1500.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1500.4.tgz", - "integrity": "sha512-ay2vHMfyhaPDkzEISlRV1ZiTD/VCUunW+uRfNIzo9/o83UjTKVcqYUOUOvbIbrsb6JbQoNY+DwkES5frG1UmnA==", + "version": "0.1501.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1501.1.tgz", + "integrity": "sha512-b2Vyhx3JRHi179kSB/zc7G+/uuWq7S/7pZAau0Ry17N6Ihg2BwpLxBe0mvKcDecLmw+1ozBv2WLRCnxKXLZ4mw==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1500.4", + "@angular-devkit/architect": "0.1501.1", "rxjs": "6.6.7" }, "engines": { @@ -311,12 +348,12 @@ "dev": true }, "node_modules/@angular-devkit/core": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.0.4.tgz", - "integrity": "sha512-4ITpRAevd652SxB+qNesIQ9qfbm7wT5UBU5kJOPPwGL77I21g8CQpkmV1n5VSacPvC9Zbz90feOWexf7w7JzcA==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.1.1.tgz", + "integrity": "sha512-wss76zfw4oPHs+Dd0OIbLv8os/BXDkDErj9hCjBbycQN768EqF8z7EBNGy6SKHYhmfXJy9REUkEgt9qPMJb4CQ==", "dev": true, "dependencies": { - "ajv": "8.11.0", + "ajv": "8.12.0", "ajv-formats": "2.1.1", "jsonc-parser": "3.2.0", "rxjs": "6.6.7", @@ -355,14 +392,14 @@ "dev": true }, "node_modules/@angular-devkit/schematics": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-15.0.4.tgz", - "integrity": "sha512-/gXiLFS0+xFdx6wPoBpe/c6/K9I5edMpaASqPf4XheKtrsSvL+qTlIi3nsbfItzOiDXbaBmlbxGfkMHz/yg0Ig==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-15.1.1.tgz", + "integrity": "sha512-ullwoxFT9aMhQR2aNwb/66A6l4HTgp4I6thbBywt86nn+ZGbJCzLKRdv2vmYh9JaxZYh1pydxWjKLEUdlycKXg==", "dev": true, "dependencies": { - "@angular-devkit/core": "15.0.4", + "@angular-devkit/core": "15.1.1", "jsonc-parser": "3.2.0", - "magic-string": "0.26.7", + "magic-string": "0.27.0", "ora": "5.4.1", "rxjs": "6.6.7" }, @@ -392,9 +429,8 @@ }, "node_modules/@angular-eslint/builder": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-15.1.0.tgz", - "integrity": "sha512-MoPeJv4a1wSoFj8fVA01hFb+QQke2t74CSVuc6o4EqkWI0tYMM1Wg19fPtTZnj4spkGA82j2mf/tazKGRe/nrw==", "dev": true, + "license": "MIT", "peerDependencies": { "eslint": "^7.20.0 || ^8.0.0", "typescript": "*" @@ -402,15 +438,13 @@ }, "node_modules/@angular-eslint/bundled-angular-compiler": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-15.1.0.tgz", - "integrity": "sha512-zcOx+PnYuVDIG3wd/JVzCYdEUarKGtgIcN4iU9ZF+BVk5e8i9cbD3U8U3EDJKbrrokbFl9GBBJMCOa6XYTGJwQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@angular-eslint/eslint-plugin": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-15.1.0.tgz", - "integrity": "sha512-3RRDnxaCEI5DdKq3hipXvrxctPPssrUXnNbgczJRIJ3cssr4ndobCSNqUSepA6vWj5mWe7w+nnh4vgfhZ5keig==", "dev": true, + "license": "MIT", "dependencies": { "@angular-eslint/utils": "15.1.0", "@typescript-eslint/utils": "5.44.0" @@ -422,9 +456,8 @@ }, "node_modules/@angular-eslint/eslint-plugin-template": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-15.1.0.tgz", - "integrity": "sha512-WofUNiLcO/oprnzswkF+u1PC6ulmqB/m7fNKMMnbExMYuK1P38gjp59FW7E+2Ivz+A4/8a5xV+U+cy3oRgh4NQ==", "dev": true, + "license": "MIT", "dependencies": { "@angular-eslint/bundled-angular-compiler": "15.1.0", "@angular-eslint/utils": "15.1.0", @@ -440,9 +473,8 @@ }, "node_modules/@angular-eslint/schematics": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-15.1.0.tgz", - "integrity": "sha512-BJm7FFVCad8TV8Gtwq+FbgtLGvjJDlpt5Rne1hCd4nCr8vlQZxSWVwnTHRkAs+qd5dYn3p7bGcKZxEZzeVkWjA==", "dev": true, + "license": "MIT", "dependencies": { "@angular-eslint/eslint-plugin": "15.1.0", "@angular-eslint/eslint-plugin-template": "15.1.0", @@ -456,9 +488,8 @@ }, "node_modules/@angular-eslint/template-parser": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-15.1.0.tgz", - "integrity": "sha512-ctcA7OAV1wwFByW1te3uZwzySuIRlo8NblG5yUtgU5BXt3nXwIDwoSr3tvI2dRHobNHcXVQcOFVzyOdXD/vsIg==", "dev": true, + "license": "MIT", "dependencies": { "@angular-eslint/bundled-angular-compiler": "15.1.0", "eslint-scope": "^7.0.0" @@ -470,9 +501,8 @@ }, "node_modules/@angular-eslint/utils": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-15.1.0.tgz", - "integrity": "sha512-Vt59o7wq3UOgHSCrOaHg0SgxgbAGhG0ofNQwd7sLqNP2/w/90dWY2jwWXIVSuZ+BmfVj3wgNi3KujbSWJP1cfg==", "dev": true, + "license": "MIT", "dependencies": { "@angular-eslint/bundled-angular-compiler": "15.1.0", "@typescript-eslint/utils": "5.44.0" @@ -483,9 +513,9 @@ } }, "node_modules/@angular/animations": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-15.0.4.tgz", - "integrity": "sha512-fOqf7fHX9aspIUmlOsig8ZyZlalU+eIBsUgu4QpH9+vfQzGCJcKIjPClW4Yb7rkNlyLlfQqaICOxG9gOxuEI7Q==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-15.1.0.tgz", + "integrity": "sha512-uBw1iQVJ3QS5e/gypsD7M50O//9GvpphgGqt9ZClknyD8dxO/YryEB+Kt4GNvNQxRKhRTksD8r4KaodukdQ15w==", "dependencies": { "tslib": "^2.3.0" }, @@ -493,13 +523,13 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/core": "15.0.4" + "@angular/core": "15.1.0" } }, "node_modules/@angular/cdk": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-15.0.3.tgz", - "integrity": "sha512-iRLV6V6ksIshDL8Cdn1+DUNTRLqj+DAqmYTWYCEvH4qU6o0XSeXrAHNW5zNFqWgCZbmWt03G5jOBWBNaxa9QKw==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-15.1.0.tgz", + "integrity": "sha512-6X9k/OT+L6nu1ndKTX4zsSxXR8/C6CyzVY+iIytBUZ8qYaZ6kZ385YlDHyNB9x70GaC5hJkOvR0ZVupz57x0bg==", "peer": true, "dependencies": { "tslib": "^2.3.0" @@ -514,25 +544,25 @@ } }, "node_modules/@angular/cli": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-15.0.4.tgz", - "integrity": "sha512-dQEus458EvBYZuM10UPO/1BYshV3cprY4os6uQj6YLdEwOogElkAedUILgtTYOo3jrwc+qjefHVJbz6R+xJCOg==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-15.1.1.tgz", + "integrity": "sha512-539I3B5yTasaX/EQrXZyXOc9eZUyVBxMWiGj3/bmlCsft7/Y8J+A92uftjxIO4P8lYWzSdSxFT3Bu1zI1b6yzw==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1500.4", - "@angular-devkit/core": "15.0.4", - "@angular-devkit/schematics": "15.0.4", - "@schematics/angular": "15.0.4", + "@angular-devkit/architect": "0.1501.1", + "@angular-devkit/core": "15.1.1", + "@angular-devkit/schematics": "15.1.1", + "@schematics/angular": "15.1.1", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.3", "ini": "3.0.1", "inquirer": "8.2.4", "jsonc-parser": "3.2.0", - "npm-package-arg": "9.1.2", + "npm-package-arg": "10.1.0", "npm-pick-manifest": "8.0.1", "open": "8.4.0", "ora": "5.4.1", - "pacote": "15.0.6", + "pacote": "15.0.8", "resolve": "1.22.1", "semver": "7.3.8", "symbol-observable": "4.0.0", @@ -548,9 +578,9 @@ } }, "node_modules/@angular/common": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-15.0.4.tgz", - "integrity": "sha512-0x/2IhaetJqfXMeQ4DlRnOTzGWD0OvOeKORyi0q7WXPxSoD9MUezQHGmzkc5lK9tDYE9cNYyQfkUBcbJT/k6MA==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-15.1.0.tgz", + "integrity": "sha512-O0JKOeJ7dFcd/mnnfm4xQOYTAc+yL+OrRpGte7z84lKPU2fupLpGW/30tHUy1TXixsANyTLC3cTVXTY5szPdqg==", "dependencies": { "tslib": "^2.3.0" }, @@ -558,14 +588,14 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/core": "15.0.4", + "@angular/core": "15.1.0", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-15.0.4.tgz", - "integrity": "sha512-KtxgRJUGZamOXpIILFG2FTUW+bbc2phi/o6955/Q4LR1HOICQrYEy8PrT1Gp+lVXFKgDG+6cb01lH14LoBQvyw==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-15.1.0.tgz", + "integrity": "sha512-+ky5Cvgps725Q/KdgsYzi/fe9LbT5ujhZoT9N5k+tYTJsepMUrpExFwMFkWrdMUYTK7DaxC9ufjZ4WZmHVhFoA==", "dependencies": { "tslib": "^2.3.0" }, @@ -573,7 +603,7 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/core": "15.0.4" + "@angular/core": "15.1.0" }, "peerDependenciesMeta": { "@angular/core": { @@ -582,11 +612,11 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-15.0.4.tgz", - "integrity": "sha512-e6Jt4qkIiyqBg8ZlpcQaQtQ5OAnfl8gfkJnIwSvvCg0mPCJv+ZkQAL5s3SpzzM5jd7Nr0jBq3zd2Fv0eKW2ayw==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-15.1.0.tgz", + "integrity": "sha512-mKeXolM/plP9ebkHy3YGxHx0Yg63d09S0QCpdIcmvrbJpaPeM2D1SAkbDpO46T4BsfgfWHtSYByb5JcesrYrpQ==", "dependencies": { - "@babel/core": "^7.17.2", + "@babel/core": "7.19.3", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^3.0.0", "convert-source-map": "^1.5.1", @@ -606,25 +636,51 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/compiler": "15.0.4", - "typescript": ">=4.8.2 <4.9" + "@angular/compiler": "15.1.0", + "typescript": ">=4.8.2 <5.0" } }, - "node_modules/@angular/compiler-cli/node_modules/magic-string": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", - "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "node_modules/@angular/compiler-cli/node_modules/@babel/core": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz", + "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.3", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.0", + "@babel/helpers": "^7.19.0", + "@babel/parser": "^7.19.3", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.3", + "@babel/types": "^7.19.3", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" } }, "node_modules/@angular/core": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-15.0.4.tgz", - "integrity": "sha512-Xf8Nuu0iM/VjQHPS4A0jufqTYZCfiGqc0iAD7j9zM3TD6caQ3OP4mxXVYYTpIG+APKel38+Gol8cpQB/8PVbqQ==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-15.1.0.tgz", + "integrity": "sha512-HiwctuR73MuLoLeP35j9xF8/SIg7ELx+iHZtp/TBfoH+LOmjWbdrAdVAPTbqnxvK0aJG+527dhgC6tBOXgBTcg==", "dependencies": { "tslib": "^2.3.0" }, @@ -637,9 +693,9 @@ } }, "node_modules/@angular/forms": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-15.0.4.tgz", - "integrity": "sha512-3Ft/p2ug/zp2p0g2rhLq9v/5F1G11xa+YujAKL5kOFa0zUoroDG6n4b6VEcsGWmDE9NR7Vkiys9rHckiJUluHg==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-15.1.0.tgz", + "integrity": "sha512-MUAbruJng0iG/cHhCkDNrh31Y54upgBUjjkE4DnoHv138Wa7vba+GMYv2tTrs4rPWnB9vPziZgI0xIi/oSGxzg==", "dependencies": { "tslib": "^2.3.0" }, @@ -647,16 +703,16 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "15.0.4", - "@angular/core": "15.0.4", - "@angular/platform-browser": "15.0.4", + "@angular/common": "15.1.0", + "@angular/core": "15.1.0", + "@angular/platform-browser": "15.1.0", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/localize": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-15.0.4.tgz", - "integrity": "sha512-IuvsPT5fUyf5yn58yzXbD/Mxk3MAbVbI78CRKN2CWew6jTXuiVmaxu4cbL/a2PHhq1led318PAdCMk//Dz4Ddg==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-15.1.0.tgz", + "integrity": "sha512-BTEBMKqS4F8lK4rIsydRsxMbQ1hFnDZTZoifT33dmmOworWFJCGryYw0ZCTkeBtCnkRGgnr1aOTIHTvJPFIMiA==", "peer": true, "dependencies": { "@babel/core": "7.19.3", @@ -672,14 +728,13 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/compiler": "15.0.4", - "@angular/compiler-cli": "15.0.4" + "@angular/compiler": "15.1.0", + "@angular/compiler-cli": "15.1.0" } }, "node_modules/@angular/localize/node_modules/@babel/core": { "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz", - "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==", + "license": "MIT", "peer": true, "dependencies": { "@ampproject/remapping": "^2.1.0", @@ -708,70 +763,69 @@ }, "node_modules/@angular/localize/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "license": "ISC", "peer": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@angular/material": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-15.0.3.tgz", - "integrity": "sha512-x7c6Uc9SnQW0AGTFJZFMQHP80YzmrExtrNn5vYUyWB9QFiNM+jcsqAsSEoGhABU/G5xs8fd40Fj7o2HBixQ0fw==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/auto-init": "15.0.0-canary.7971d6ad5.0", - "@material/banner": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/button": "15.0.0-canary.7971d6ad5.0", - "@material/card": "15.0.0-canary.7971d6ad5.0", - "@material/checkbox": "15.0.0-canary.7971d6ad5.0", - "@material/chips": "15.0.0-canary.7971d6ad5.0", - "@material/circular-progress": "15.0.0-canary.7971d6ad5.0", - "@material/data-table": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dialog": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/drawer": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/fab": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/floating-label": "15.0.0-canary.7971d6ad5.0", - "@material/form-field": "15.0.0-canary.7971d6ad5.0", - "@material/icon-button": "15.0.0-canary.7971d6ad5.0", - "@material/image-list": "15.0.0-canary.7971d6ad5.0", - "@material/layout-grid": "15.0.0-canary.7971d6ad5.0", - "@material/line-ripple": "15.0.0-canary.7971d6ad5.0", - "@material/linear-progress": "15.0.0-canary.7971d6ad5.0", - "@material/list": "15.0.0-canary.7971d6ad5.0", - "@material/menu": "15.0.0-canary.7971d6ad5.0", - "@material/menu-surface": "15.0.0-canary.7971d6ad5.0", - "@material/notched-outline": "15.0.0-canary.7971d6ad5.0", - "@material/radio": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/segmented-button": "15.0.0-canary.7971d6ad5.0", - "@material/select": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/slider": "15.0.0-canary.7971d6ad5.0", - "@material/snackbar": "15.0.0-canary.7971d6ad5.0", - "@material/switch": "15.0.0-canary.7971d6ad5.0", - "@material/tab": "15.0.0-canary.7971d6ad5.0", - "@material/tab-bar": "15.0.0-canary.7971d6ad5.0", - "@material/tab-indicator": "15.0.0-canary.7971d6ad5.0", - "@material/tab-scroller": "15.0.0-canary.7971d6ad5.0", - "@material/textfield": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tooltip": "15.0.0-canary.7971d6ad5.0", - "@material/top-app-bar": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-15.1.0.tgz", + "integrity": "sha512-H/SBpsjf4rzSwep9er1QUh45rSsXiWh8b/HZxCP61lJSnWDUsLP1r+icLtKBAHYMpsrJHSdrgOx1do9IG2K1uQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/auto-init": "15.0.0-canary.fd95ca7ef.0", + "@material/banner": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/button": "15.0.0-canary.fd95ca7ef.0", + "@material/card": "15.0.0-canary.fd95ca7ef.0", + "@material/checkbox": "15.0.0-canary.fd95ca7ef.0", + "@material/chips": "15.0.0-canary.fd95ca7ef.0", + "@material/circular-progress": "15.0.0-canary.fd95ca7ef.0", + "@material/data-table": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dialog": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/drawer": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/fab": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/floating-label": "15.0.0-canary.fd95ca7ef.0", + "@material/form-field": "15.0.0-canary.fd95ca7ef.0", + "@material/icon-button": "15.0.0-canary.fd95ca7ef.0", + "@material/image-list": "15.0.0-canary.fd95ca7ef.0", + "@material/layout-grid": "15.0.0-canary.fd95ca7ef.0", + "@material/line-ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/linear-progress": "15.0.0-canary.fd95ca7ef.0", + "@material/list": "15.0.0-canary.fd95ca7ef.0", + "@material/menu": "15.0.0-canary.fd95ca7ef.0", + "@material/menu-surface": "15.0.0-canary.fd95ca7ef.0", + "@material/notched-outline": "15.0.0-canary.fd95ca7ef.0", + "@material/radio": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/segmented-button": "15.0.0-canary.fd95ca7ef.0", + "@material/select": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/slider": "15.0.0-canary.fd95ca7ef.0", + "@material/snackbar": "15.0.0-canary.fd95ca7ef.0", + "@material/switch": "15.0.0-canary.fd95ca7ef.0", + "@material/tab": "15.0.0-canary.fd95ca7ef.0", + "@material/tab-bar": "15.0.0-canary.fd95ca7ef.0", + "@material/tab-indicator": "15.0.0-canary.fd95ca7ef.0", + "@material/tab-scroller": "15.0.0-canary.fd95ca7ef.0", + "@material/textfield": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tooltip": "15.0.0-canary.fd95ca7ef.0", + "@material/top-app-bar": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.3.0" }, "peerDependencies": { "@angular/animations": "^15.0.0 || ^16.0.0", - "@angular/cdk": "15.0.3", + "@angular/cdk": "15.1.0", "@angular/common": "^15.0.0 || ^16.0.0", "@angular/core": "^15.0.0 || ^16.0.0", "@angular/forms": "^15.0.0 || ^16.0.0", @@ -780,9 +834,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-15.0.4.tgz", - "integrity": "sha512-SOLrzh9AsHzhfre95ShvHd0hBcyEcFftJuAaU+35L4GiOAY+CznFuJUq4LjITCMQDHGzdpUlRjoUyJRQFmlvXQ==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-15.1.0.tgz", + "integrity": "sha512-yuJweAR+rJhWWHM4Im3Iy6S4+W3OtcVHijcqrxfVxiA9ZHbDw/jpYDi06ZZIgfnNyGWi5/BzJbHvxH3b0lAo5Q==", "dependencies": { "tslib": "^2.3.0" }, @@ -790,9 +844,9 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/animations": "15.0.4", - "@angular/common": "15.0.4", - "@angular/core": "15.0.4" + "@angular/animations": "15.1.0", + "@angular/common": "15.1.0", + "@angular/core": "15.1.0" }, "peerDependenciesMeta": { "@angular/animations": { @@ -801,9 +855,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-15.0.4.tgz", - "integrity": "sha512-SCUxsfJAHXnAyo2ulmfqs3vGnB/tWNKe+G2KKshrSLyCYIJ3UgpsoPAo1mGih64qo8TWOQk9PJgrlVEB2DoWYg==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-15.1.0.tgz", + "integrity": "sha512-ukyycXkuu4Ah/35cbN4pEB91D2PK5eZVbJ+liCD6uRb4UI3X+QVg6Qz6MoIctVAlTV6tWK20T81zoux9SzWKsg==", "dependencies": { "tslib": "^2.3.0" }, @@ -811,16 +865,16 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "15.0.4", - "@angular/compiler": "15.0.4", - "@angular/core": "15.0.4", - "@angular/platform-browser": "15.0.4" + "@angular/common": "15.1.0", + "@angular/compiler": "15.1.0", + "@angular/core": "15.1.0", + "@angular/platform-browser": "15.1.0" } }, "node_modules/@angular/router": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-15.0.4.tgz", - "integrity": "sha512-6cBUu1kSigORGpWq+Wc3hTLRQcJvtlaZ5OFOIzKGiBEPgezn/AzrWHi/bEccWLZAVFhbUOhcRn9GwudqiqX6+A==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-15.1.0.tgz", + "integrity": "sha512-78ItVVXOYdu/RRxruHwSmtNxEP2clx+afHKrkwc4e7/6uxVr4rl0VQhO6qHYme/bBtbLIcBZGJoSyoUg/xUSvQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -828,22 +882,20 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "15.0.4", - "@angular/core": "15.0.4", - "@angular/platform-browser": "15.0.4", + "@angular/common": "15.1.0", + "@angular/core": "15.1.0", + "@angular/platform-browser": "15.1.0", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@assemblyscript/loader": { "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", - "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/@babel/code-frame": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "license": "MIT", "dependencies": { "@babel/highlight": "^7.18.6" }, @@ -853,16 +905,14 @@ }, "node_modules/@babel/compat-data": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz", - "integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz", - "integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==", + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", @@ -890,18 +940,17 @@ }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.20.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.4.tgz", - "integrity": "sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", + "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", "dependencies": { - "@babel/types": "^7.20.2", + "@babel/types": "^7.20.7", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -911,8 +960,7 @@ }, "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -924,9 +972,8 @@ }, "node_modules/@babel/helper-annotate-as-pure": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.18.6" }, @@ -936,9 +983,8 @@ }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", - "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-explode-assignable-expression": "^7.18.6", "@babel/types": "^7.18.9" @@ -948,13 +994,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", - "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", "dependencies": { - "@babel/compat-data": "^7.20.0", + "@babel/compat-data": "^7.20.5", "@babel/helper-validator-option": "^7.18.6", "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", "semver": "^6.3.0" }, "engines": { @@ -964,19 +1011,30 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, "node_modules/@babel/helper-create-class-features-plugin": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.5.tgz", - "integrity": "sha512-3RCdA/EmEaikrhayahwToF0fpweU/8o2p8vhc1c/1kftHOdTKuC65kik/TLc+qfbS8JKw4qqJbne4ovICDhmww==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", "@babel/helper-environment-visitor": "^7.18.9", @@ -995,9 +1053,8 @@ }, "node_modules/@babel/helper-create-regexp-features-plugin": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz", - "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", "regexpu-core": "^5.2.1" @@ -1011,9 +1068,8 @@ }, "node_modules/@babel/helper-define-polyfill-provider": { "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.17.7", "@babel/helper-plugin-utils": "^7.16.7", @@ -1028,26 +1084,23 @@ }, "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-environment-visitor": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-explode-assignable-expression": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", - "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.18.6" }, @@ -1057,8 +1110,7 @@ }, "node_modules/@babel/helper-function-name": { "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "license": "MIT", "dependencies": { "@babel/template": "^7.18.10", "@babel/types": "^7.19.0" @@ -1069,8 +1121,7 @@ }, "node_modules/@babel/helper-hoist-variables": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "license": "MIT", "dependencies": { "@babel/types": "^7.18.6" }, @@ -1080,9 +1131,8 @@ }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", - "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.18.9" }, @@ -1092,8 +1142,7 @@ }, "node_modules/@babel/helper-module-imports": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "license": "MIT", "dependencies": { "@babel/types": "^7.18.6" }, @@ -1102,18 +1151,18 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", - "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", "@babel/helper-simple-access": "^7.20.2", "@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.1", - "@babel/types": "^7.20.2" + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" }, "engines": { "node": ">=6.9.0" @@ -1121,9 +1170,8 @@ }, "node_modules/@babel/helper-optimise-call-expression": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.18.6" }, @@ -1133,18 +1181,16 @@ }, "node_modules/@babel/helper-plugin-utils": { "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", - "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", "@babel/helper-environment-visitor": "^7.18.9", @@ -1160,9 +1206,8 @@ }, "node_modules/@babel/helper-replace-supers": { "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", - "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-member-expression-to-functions": "^7.18.9", @@ -1176,8 +1221,7 @@ }, "node_modules/@babel/helper-simple-access": { "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "license": "MIT", "dependencies": { "@babel/types": "^7.20.2" }, @@ -1187,9 +1231,8 @@ }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", - "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.20.0" }, @@ -1199,8 +1242,7 @@ }, "node_modules/@babel/helper-split-export-declaration": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "license": "MIT", "dependencies": { "@babel/types": "^7.18.6" }, @@ -1210,33 +1252,29 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", - "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-function-name": "^7.19.0", "@babel/template": "^7.18.10", @@ -1248,13 +1286,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz", - "integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz", + "integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==", "dependencies": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5" + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7" }, "engines": { "node": ">=6.9.0" @@ -1262,8 +1300,7 @@ }, "node_modules/@babel/highlight": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", @@ -1274,9 +1311,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", + "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1286,9 +1323,8 @@ }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", - "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -1301,9 +1337,8 @@ }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", - "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", @@ -1317,13 +1352,13 @@ } }, "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.1.tgz", - "integrity": "sha512-Gh5rchzSwE4kC+o/6T8waD0WHEQIsDmjltY8WnWRXHUdH8axZhuH86Ov9M72YhJfDrZseQwuuWaaIT/TmePp3g==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", + "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-plugin-utils": "^7.20.2", "@babel/helper-remap-async-to-generator": "^7.18.9", "@babel/plugin-syntax-async-generators": "^7.8.4" }, @@ -1336,9 +1371,8 @@ }, "node_modules/@babel/plugin-proposal-class-properties": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1352,9 +1386,8 @@ }, "node_modules/@babel/plugin-proposal-class-static-block": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", - "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6", @@ -1369,9 +1402,8 @@ }, "node_modules/@babel/plugin-proposal-dynamic-import": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", - "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-dynamic-import": "^7.8.3" @@ -1385,9 +1417,8 @@ }, "node_modules/@babel/plugin-proposal-export-namespace-from": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", - "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" @@ -1401,9 +1432,8 @@ }, "node_modules/@babel/plugin-proposal-json-strings": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", - "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-json-strings": "^7.8.3" @@ -1417,9 +1447,8 @@ }, "node_modules/@babel/plugin-proposal-logical-assignment-operators": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", - "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" @@ -1433,9 +1462,8 @@ }, "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", - "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" @@ -1449,9 +1477,8 @@ }, "node_modules/@babel/plugin-proposal-numeric-separator": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", - "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-numeric-separator": "^7.10.4" @@ -1465,9 +1492,8 @@ }, "node_modules/@babel/plugin-proposal-object-rest-spread": { "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.2.tgz", - "integrity": "sha512-Ks6uej9WFK+fvIMesSqbAto5dD8Dz4VuuFvGJFKgIGSkJuRGcrwGECPA1fDgQK3/DbExBJpEkTeYeB8geIFCSQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.20.1", "@babel/helper-compilation-targets": "^7.20.0", @@ -1484,9 +1510,8 @@ }, "node_modules/@babel/plugin-proposal-optional-catch-binding": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" @@ -1500,9 +1525,8 @@ }, "node_modules/@babel/plugin-proposal-optional-chaining": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", - "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", @@ -1517,9 +1541,8 @@ }, "node_modules/@babel/plugin-proposal-private-methods": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1533,9 +1556,8 @@ }, "node_modules/@babel/plugin-proposal-private-property-in-object": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz", - "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", "@babel/helper-create-class-features-plugin": "^7.20.5", @@ -1551,9 +1573,8 @@ }, "node_modules/@babel/plugin-proposal-unicode-property-regex": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1567,9 +1588,8 @@ }, "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1579,9 +1599,8 @@ }, "node_modules/@babel/plugin-syntax-bigint": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1591,9 +1610,8 @@ }, "node_modules/@babel/plugin-syntax-class-properties": { "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -1603,9 +1621,8 @@ }, "node_modules/@babel/plugin-syntax-class-static-block": { "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -1618,9 +1635,8 @@ }, "node_modules/@babel/plugin-syntax-dynamic-import": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1630,9 +1646,8 @@ }, "node_modules/@babel/plugin-syntax-export-namespace-from": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.3" }, @@ -1642,9 +1657,8 @@ }, "node_modules/@babel/plugin-syntax-import-assertions": { "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", - "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.19.0" }, @@ -1657,9 +1671,8 @@ }, "node_modules/@babel/plugin-syntax-import-meta": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -1669,9 +1682,8 @@ }, "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1681,9 +1693,8 @@ }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -1696,9 +1707,8 @@ }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -1708,9 +1718,8 @@ }, "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1720,9 +1729,8 @@ }, "node_modules/@babel/plugin-syntax-numeric-separator": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -1732,9 +1740,8 @@ }, "node_modules/@babel/plugin-syntax-object-rest-spread": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1744,9 +1751,8 @@ }, "node_modules/@babel/plugin-syntax-optional-catch-binding": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1756,9 +1762,8 @@ }, "node_modules/@babel/plugin-syntax-optional-chaining": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1768,9 +1773,8 @@ }, "node_modules/@babel/plugin-syntax-private-property-in-object": { "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -1783,9 +1787,8 @@ }, "node_modules/@babel/plugin-syntax-top-level-await": { "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -1798,9 +1801,8 @@ }, "node_modules/@babel/plugin-syntax-typescript": { "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.19.0" }, @@ -1813,9 +1815,8 @@ }, "node_modules/@babel/plugin-transform-arrow-functions": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", - "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -1827,14 +1828,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", - "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", + "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-remap-async-to-generator": "^7.18.6" + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1845,9 +1846,8 @@ }, "node_modules/@babel/plugin-transform-block-scoped-functions": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", - "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -1860,9 +1860,8 @@ }, "node_modules/@babel/plugin-transform-block-scoping": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.5.tgz", - "integrity": "sha512-WvpEIW9Cbj9ApF3yJCjIEEf1EiNJLtXagOrL5LNWEZOo3jv8pmPoYTSNJQvqej8OavVlgOoOPw6/htGZro6IkA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2" }, @@ -1875,9 +1874,8 @@ }, "node_modules/@babel/plugin-transform-classes": { "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.2.tgz", - "integrity": "sha512-9rbPp0lCVVoagvtEyQKSo5L8oo0nQS/iif+lwlAz29MccX2642vWDlSZK+2T2buxbopotId2ld7zZAzRfz9j1g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", "@babel/helper-compilation-targets": "^7.20.0", @@ -1898,9 +1896,8 @@ }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", - "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9" }, @@ -1913,9 +1910,8 @@ }, "node_modules/@babel/plugin-transform-destructuring": { "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.2.tgz", - "integrity": "sha512-mENM+ZHrvEgxLTBXUiQ621rRXZes3KWUv6NdQlrnr1TkWVw+hUjQBZuP2X32qKlrlG2BzgR95gkuCRSkJl8vIw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2" }, @@ -1928,9 +1924,8 @@ }, "node_modules/@babel/plugin-transform-dotall-regex": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", - "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1944,9 +1939,8 @@ }, "node_modules/@babel/plugin-transform-duplicate-keys": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", - "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9" }, @@ -1959,9 +1953,8 @@ }, "node_modules/@babel/plugin-transform-exponentiation-operator": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", - "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1975,9 +1968,8 @@ }, "node_modules/@babel/plugin-transform-for-of": { "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", - "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -1990,9 +1982,8 @@ }, "node_modules/@babel/plugin-transform-function-name": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", - "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.18.9", "@babel/helper-function-name": "^7.18.9", @@ -2007,9 +1998,8 @@ }, "node_modules/@babel/plugin-transform-literals": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", - "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9" }, @@ -2022,9 +2012,8 @@ }, "node_modules/@babel/plugin-transform-member-expression-literals": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", - "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -2037,9 +2026,8 @@ }, "node_modules/@babel/plugin-transform-modules-amd": { "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz", - "integrity": "sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.19.6", "@babel/helper-plugin-utils": "^7.19.0" @@ -2053,9 +2041,8 @@ }, "node_modules/@babel/plugin-transform-modules-commonjs": { "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz", - "integrity": "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.19.6", "@babel/helper-plugin-utils": "^7.19.0", @@ -2070,9 +2057,8 @@ }, "node_modules/@babel/plugin-transform-modules-systemjs": { "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz", - "integrity": "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-module-transforms": "^7.19.6", @@ -2088,9 +2074,8 @@ }, "node_modules/@babel/plugin-transform-modules-umd": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", - "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -2104,9 +2089,8 @@ }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", - "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.20.5", "@babel/helper-plugin-utils": "^7.20.2" @@ -2120,9 +2104,8 @@ }, "node_modules/@babel/plugin-transform-new-target": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", - "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -2135,9 +2118,8 @@ }, "node_modules/@babel/plugin-transform-object-super": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", - "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/helper-replace-supers": "^7.18.6" @@ -2151,9 +2133,8 @@ }, "node_modules/@babel/plugin-transform-parameters": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.5.tgz", - "integrity": "sha512-h7plkOmcndIUWXZFLgpbrh2+fXAi47zcUX7IrOQuZdLD0I0KvjJ6cvo3BEcAOsDOcZhVKGJqv07mkSqK0y2isQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2" }, @@ -2166,9 +2147,8 @@ }, "node_modules/@babel/plugin-transform-property-literals": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", - "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -2181,9 +2161,8 @@ }, "node_modules/@babel/plugin-transform-regenerator": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", - "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", "regenerator-transform": "^0.15.1" @@ -2197,9 +2176,8 @@ }, "node_modules/@babel/plugin-transform-reserved-words": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", - "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -2212,9 +2190,8 @@ }, "node_modules/@babel/plugin-transform-runtime": { "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", - "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.18.6", "@babel/helper-plugin-utils": "^7.19.0", @@ -2232,18 +2209,16 @@ }, "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/plugin-transform-shorthand-properties": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", - "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -2256,9 +2231,8 @@ }, "node_modules/@babel/plugin-transform-spread": { "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", - "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.19.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" @@ -2272,9 +2246,8 @@ }, "node_modules/@babel/plugin-transform-sticky-regex": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", - "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -2287,9 +2260,8 @@ }, "node_modules/@babel/plugin-transform-template-literals": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", - "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9" }, @@ -2302,9 +2274,8 @@ }, "node_modules/@babel/plugin-transform-typeof-symbol": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", - "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9" }, @@ -2317,9 +2288,8 @@ }, "node_modules/@babel/plugin-transform-unicode-escapes": { "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", - "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9" }, @@ -2332,9 +2302,8 @@ }, "node_modules/@babel/plugin-transform-unicode-regex": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", - "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -2348,9 +2317,8 @@ }, "node_modules/@babel/preset-env": { "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz", - "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.20.1", "@babel/helper-compilation-targets": "^7.20.0", @@ -2437,18 +2405,16 @@ }, "node_modules/@babel/preset-env/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/preset-modules": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", @@ -2461,43 +2427,43 @@ } }, "node_modules/@babel/runtime": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.1.tgz", - "integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz", + "integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==", "dev": true, "dependencies": { - "regenerator-runtime": "^0.13.10" + "regenerator-runtime": "^0.13.11" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", - "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz", + "integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==", "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", + "@babel/generator": "^7.20.7", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.5", - "@babel/types": "^7.20.5", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -2505,36 +2471,10 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", - "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", - "dependencies": { - "@babel/types": "^7.20.5", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", "dependencies": { "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", @@ -2546,15 +2486,13 @@ }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@colors/colors": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=0.1.90" @@ -2562,9 +2500,8 @@ }, "node_modules/@cypress/request": { "version": "2.88.10", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz", - "integrity": "sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -2591,9 +2528,8 @@ }, "node_modules/@cypress/xvfb": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", - "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.1.0", "lodash.once": "^4.1.1" @@ -2601,26 +2537,24 @@ }, "node_modules/@cypress/xvfb/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "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, + "license": "MIT", "engines": { "node": ">=10.0.0" } }, "node_modules/@esbuild/android-arm": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.13.tgz", - "integrity": "sha512-RY2fVI8O0iFUNvZirXaQ1vMvK0xhCcl0gqRj74Z6yEiO1zAUa7hbsdwZM1kzqbxHK7LFyMizipfXT3JME+12Hw==", + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", + "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==", "cpu": [ "arm" ], @@ -2633,110 +2567,429 @@ "node": ">=12" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.13.tgz", - "integrity": "sha512-+BoyIm4I8uJmH/QDIH0fu7MG0AEx9OXEDXnqptXCwKOlOqZiS4iraH1Nr7/ObLMokW3sOCeBNyD68ATcV9b9Ag==", + "node_modules/@esbuild/android-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz", + "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==", "cpu": [ - "loong64" + "arm64" ], "dev": true, "optional": true, "os": [ - "linux" + "android" ], "engines": { "node": ">=12" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.1.2.tgz", - "integrity": "sha512-7qELuQWWjVDdVsFQ5+beUl+KPczrEDA7S3zM4QUd/bJl7oXgsmpXaEVqrRTnOBqenOV4rWf2kVZk2Ot085zPWA==", + "node_modules/@esbuild/android-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz", + "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "node": ">=12" } }, - "node_modules/@eslint/eslintrc": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz", - "integrity": "sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz", + "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=12" } }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz", + "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/node_modules/globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz", + "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/@eslint/eslintrc/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==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz", + "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz", + "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz", + "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz", + "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz", + "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz", + "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz", + "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz", + "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz", + "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz", + "integrity": "sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", + "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", + "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", + "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz", + "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz", + "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", + "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/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": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/node_modules/globals": { + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/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": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/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==", @@ -2762,9 +3015,8 @@ }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", @@ -2776,9 +3028,8 @@ }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -2789,15 +3040,13 @@ }, "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 + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, + "license": "ISC", "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -2811,18 +3060,16 @@ }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/console": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.3.1.tgz", - "integrity": "sha512-IRE6GD47KwcqA09RIWrabKdHPiKDGgtAL31xDxbi/RjQMsr+lY+ppxmHwY0dUEV3qvvxZzoe5Hl0RXZJOjQNUg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.3.1", "@types/node": "*", @@ -2837,9 +3084,8 @@ }, "node_modules/@jest/console/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2852,9 +3098,8 @@ }, "node_modules/@jest/console/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2868,9 +3113,8 @@ }, "node_modules/@jest/console/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2880,24 +3124,21 @@ }, "node_modules/@jest/console/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jest/console/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/console/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -2907,9 +3148,8 @@ }, "node_modules/@jest/core": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.3.1.tgz", - "integrity": "sha512-0ohVjjRex985w5MmO5L3u5GR1O30DexhBSpuwx2P+9ftyqHdJXnk7IUWiP80oHMvt7ubHCJHxV0a0vlKVuZirw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.3.1", "@jest/reporters": "^29.3.1", @@ -2954,9 +3194,8 @@ }, "node_modules/@jest/core/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2969,9 +3208,8 @@ }, "node_modules/@jest/core/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2985,9 +3223,8 @@ }, "node_modules/@jest/core/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2997,24 +3234,21 @@ }, "node_modules/@jest/core/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jest/core/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/core/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -3024,9 +3258,8 @@ }, "node_modules/@jest/environment": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.3.1.tgz", - "integrity": "sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==", "dev": true, + "license": "MIT", "dependencies": { "@jest/fake-timers": "^29.3.1", "@jest/types": "^29.3.1", @@ -3039,9 +3272,8 @@ }, "node_modules/@jest/expect": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-QivM7GlSHSsIAWzgfyP8dgeExPRZ9BIe2LsdPyEhCGkZkoyA+kGsoIzbKAfZCvvRzfZioKwPtCZIt5SaoxYCvg==", "dev": true, + "license": "MIT", "dependencies": { "expect": "^29.3.1", "jest-snapshot": "^29.3.1" @@ -3052,9 +3284,8 @@ }, "node_modules/@jest/expect-utils": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz", - "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==", "dev": true, + "license": "MIT", "dependencies": { "jest-get-type": "^29.2.0" }, @@ -3064,9 +3295,8 @@ }, "node_modules/@jest/fake-timers": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.3.1.tgz", - "integrity": "sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.3.1", "@sinonjs/fake-timers": "^9.1.2", @@ -3081,9 +3311,8 @@ }, "node_modules/@jest/globals": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.3.1.tgz", - "integrity": "sha512-cTicd134vOcwO59OPaB6AmdHQMCtWOe+/DitpTZVxWgMJ+YvXL1HNAmPyiGbSHmF/mXVBkvlm8YYtQhyHPnV6Q==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.3.1", "@jest/expect": "^29.3.1", @@ -3096,9 +3325,8 @@ }, "node_modules/@jest/reporters": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.3.1.tgz", - "integrity": "sha512-GhBu3YFuDrcAYW/UESz1JphEAbvUjaY2vShRZRoRY1mxpCMB3yGSJ4j9n0GxVlEOdCf7qjvUfBCrTUUqhVfbRA==", "dev": true, + "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "^29.3.1", @@ -3139,9 +3367,8 @@ }, "node_modules/@jest/reporters/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -3154,9 +3381,8 @@ }, "node_modules/@jest/reporters/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3170,9 +3396,8 @@ }, "node_modules/@jest/reporters/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -3182,15 +3407,13 @@ }, "node_modules/@jest/reporters/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jest/reporters/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -3208,18 +3431,16 @@ }, "node_modules/@jest/reporters/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/reporters/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -3229,9 +3450,8 @@ }, "node_modules/@jest/schemas": { "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", "dev": true, + "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -3241,9 +3461,8 @@ }, "node_modules/@jest/source-map": { "version": "29.2.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.2.0.tgz", - "integrity": "sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.15", "callsites": "^3.0.0", @@ -3255,9 +3474,8 @@ }, "node_modules/@jest/test-result": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.3.1.tgz", - "integrity": "sha512-qeLa6qc0ddB0kuOZyZIhfN5q0e2htngokyTWsGriedsDhItisW7SDYZ7ceOe57Ii03sL988/03wAcBh3TChMGw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.3.1", "@jest/types": "^29.3.1", @@ -3270,9 +3488,8 @@ }, "node_modules/@jest/test-sequencer": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.3.1.tgz", - "integrity": "sha512-IqYvLbieTv20ArgKoAMyhLHNrVHJfzO6ARZAbQRlY4UGWfdDnLlZEF0BvKOMd77uIiIjSZRwq3Jb3Fa3I8+2UA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/test-result": "^29.3.1", "graceful-fs": "^4.2.9", @@ -3285,9 +3502,8 @@ }, "node_modules/@jest/transform": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.3.1.tgz", - "integrity": "sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^29.3.1", @@ -3311,9 +3527,8 @@ }, "node_modules/@jest/transform/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -3326,9 +3541,8 @@ }, "node_modules/@jest/transform/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3342,9 +3556,8 @@ }, "node_modules/@jest/transform/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -3354,30 +3567,26 @@ }, "node_modules/@jest/transform/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jest/transform/node_modules/convert-source-map": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jest/transform/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/transform/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -3387,9 +3596,8 @@ }, "node_modules/@jest/types": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", - "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/schemas": "^29.0.0", "@types/istanbul-lib-coverage": "^2.0.0", @@ -3404,9 +3612,8 @@ }, "node_modules/@jest/types/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -3419,9 +3626,8 @@ }, "node_modules/@jest/types/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3435,9 +3641,8 @@ }, "node_modules/@jest/types/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -3447,24 +3652,21 @@ }, "node_modules/@jest/types/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jest/types/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/types/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -3474,8 +3676,7 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.0.0", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -3486,25 +3687,22 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -3512,9 +3710,8 @@ }, "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -3526,13 +3723,11 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "3.1.0", "@jridgewell/sourcemap-codec": "1.4.14" @@ -3540,8 +3735,7 @@ }, "node_modules/@kurkle/color": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.1.tgz", - "integrity": "sha512-hW0GwZj06z/ZFUW2Espl7toVDjghJN+EKqyXzPSV8NV89d5BYp5rRMBJoc+aUN0x5OXDMeRQHazejr2Xmqj2tw==" + "license": "MIT" }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.4", @@ -3551,16 +3745,13 @@ }, "node_modules/@mapbox/jsonlint-lines-primitives": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", - "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", "engines": { "node": ">= 0.6" } }, "node_modules/@mapbox/mapbox-gl-style-spec": { "version": "13.27.0", - "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-style-spec/-/mapbox-gl-style-spec-13.27.0.tgz", - "integrity": "sha512-wQSJCGRyf7pWknQgeGBArHEk8898UcI1BnAam7IRa3AGmHRFzlJ6DzoU24Hld9zJ0tgkNQ7OP5sJT/9hKHzavg==", + "license": "ISC", "dependencies": { "@mapbox/jsonlint-lines-primitives": "~2.0.2", "@mapbox/point-geometry": "^0.1.0", @@ -3580,766 +3771,767 @@ }, "node_modules/@mapbox/point-geometry": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", - "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==" + "license": "ISC" }, "node_modules/@mapbox/unitbezier": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz", - "integrity": "sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==" + "license": "BSD-2-Clause" }, "node_modules/@material/animation": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/animation/-/animation-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-nOCOgzp/Vdgloyw/SjFCEtpcxXWtXUjvX+JCVg7o+EEtaGLBQdgjJUj5lt+RQ6e9r0eiMYKJ6l1+1TGGebsIfA==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-zMUnqghXPj65NpEHw7n70qZ2Epaue7Y/aue+EWrWYiaQo5a0zxNttYyc5XTw0KOqfHyB9Yz4wO9BTQDCKWSWtg==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/auto-init": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/auto-init/-/auto-init-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-JmST/NkQpdJ1+nyAU8qbV1eRXbOwvpaTRy096Y5mOK1CeUsagUyrKkCeLsO56pmvayxnOIkJCOhH/8gzIsmiJA==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/auto-init/-/auto-init-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-CrsCatcRWu6MbZZ83wcA2e591ag2mrqbFg8lioAkOU/XypGRgObVH7mK/Jih0LTHsZrvjIq3MNJZirkpZifb2g==", "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/banner": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/banner/-/banner-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-OA23YGt9qTz5i+FdGgk4QpRkmby/w+k12YMlL7u+TmwWIiGom2AaOy/DbBCr2/uNJEJ6o0h+wcNBEmGe7bJutw==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/button": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/banner/-/banner-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-lplDzQjQGbImfr+IYkO0USpgDsWx/vk0e6qg71jwd23m75NOZG6Pv0U1gtL2LLVr4hgedbLq/gqKSilsZkKxZQ==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/button": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/base": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/base/-/base-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-wXgoWl8NG4BZ2U8MCg4BLQLNla3IdyxBJIMSsJ1qvP2YswmG9HXTkS8y9mHTAhzzQEFQtlwDOyp4Ntq2Ep4WZA==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-pIdMbChPElwv8bsyKvd4yY1lVbpD7RJfzfPhzI6Rpud01+fAYSon3K0oTruZgMR9nRLVC83qEPFlWXGXRLvY1w==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/button": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/button/-/button-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-lyV4unJUG/onzNSLL5TjTGJxscBReG6+lNBvGSfgCafW2bfHW278BbqPDbPr52ONe6vg5INptZJ6bZx4FStGIQ==", - "dependencies": { - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/focus-ring": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/button/-/button-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-EG32mxhJZmiWJAvQ1CFsAd95NQfbxFNnmRIphNfvER3koy+zEKVB7CjVAXK3XCptlvSfbn5384qfAJKYsK9HsA==", + "dependencies": { + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/focus-ring": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/card": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/card/-/card-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-0YNba4Keg+a0U4JK+siLDbTyO13s40hm88kX7uQ46SmsQlY3fbMsdOpX9+y/PaOkOXIJIgX6g+c7ASM7c/6Zyw==", - "dependencies": { - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/card/-/card-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-t+fe6ICrFzY681+qGUwHrzHGv44Hn4xldv7VCQW7jxzqvz3pa/w3deDYnVdrzLVHLntzvuTbvJEzcqmC53vQFA==", + "dependencies": { + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/checkbox": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/checkbox/-/checkbox-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-RSFJhMtU28BhXWyQHMrThqkGMtYb16JOuKkZ54bc1AzIndQnniQoGpkb5tHx1hOCGhOUyAGVh/w8BHczWRsLbw==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/focus-ring": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/checkbox/-/checkbox-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-UPxRSildKAqnucLpB4Oh2KdAYeypjzveFFPMkWY3d/p7W6bgTmMg249jLAIFrcudBjPgrMem6J7DPBMiicud4A==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/focus-ring": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/chips": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/chips/-/chips-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-W8e90cxnERoP/OvsYSSkjP/HEeogYH1YJVBemKfTOQyAAMh3DmetBGdO6Gdf65/Jt7iYrvab5IPn0D7DWoMZlQ==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/checkbox": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/focus-ring": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/chips/-/chips-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-M7bfcCicB58k9nSvIlsR0FYM5ahhwh25IK1ybVKWBvtCDD4dyXVgeIc+e+u9E/i8e2KVzCMclwX1P6xocHJx7w==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/checkbox": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/focus-ring": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "safevalues": "^0.3.4", "tslib": "^2.1.0" } }, "node_modules/@material/circular-progress": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/circular-progress/-/circular-progress-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-dE66rFNI9T2khLejoTyONQZqnHjUXsmdzDx1lI3qO918gtdkwdBVWvFm0U7+1VdHAB9sjP4o+mVL/3rNss2Jtg==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/progress-indicator": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/circular-progress/-/circular-progress-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-lsM+X5cnvvrqsdsVoxl4lySShw9w6CK7Q55VGfR2Pwd7oqid4bZX1uOOgpz7WHUxT4AOJ6PX/iHDClueEx8lrA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/progress-indicator": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/data-table": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/data-table/-/data-table-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-JIg3GqnWGoiP5OXRkM7xjpoYIcal3a2vcvx8qUBK8rJZUXXShMcrFD8bpoEK+VIo7NXp5oR3baR3g063sTmv7g==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/checkbox": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/icon-button": "15.0.0-canary.7971d6ad5.0", - "@material/linear-progress": "15.0.0-canary.7971d6ad5.0", - "@material/list": "15.0.0-canary.7971d6ad5.0", - "@material/menu": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/select": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/data-table/-/data-table-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-eg2ohraF8LLva1rAWrJ6R5Ei06k7tp1azewL46rtRulJGjBJHCUfkstfxx21S/PdX7CsPyWwPoWDCxgk2zo1Sw==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/checkbox": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/icon-button": "15.0.0-canary.fd95ca7ef.0", + "@material/linear-progress": "15.0.0-canary.fd95ca7ef.0", + "@material/list": "15.0.0-canary.fd95ca7ef.0", + "@material/menu": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/select": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/density": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/density/-/density-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-JfRRdyewKuVGDLTxm0Bn/5MFgkPHo5fZ0JU6kCqI+SdOER/ceRti6xJtNfgV/lBPqstftARcKv116nQRy2085Q==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/density/-/density-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-3scwdXi0xIVL6CZSGVWTxg935zomwMlqEBt0/BdxG96YJ0p+G0Rxb6TVfuzld/isD9Fx8XufV+wNkx0riZ30Vg==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/dialog": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/dialog/-/dialog-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-P7+nNN1YdPISSOIECyECiYNcmAJn4ezogpkcGkGBKc0KZAzG47Y1prgLNFaHat5mE20GjLL50M7T4SU7F64dqA==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/button": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/icon-button": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/dialog/-/dialog-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-szjN6QewCVN3ucnZSjfolDlUZdk5smmNRhX4RnF/OTF/6n41D3iHFTVNws10idWzBC3zZX1L9ZY910nsYy5xHA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/button": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/icon-button": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/dom": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/dom/-/dom-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-h+KV0egRy7zniZElzDW5duh/VDZUTO9SmMeC8FFiqJMvPe3V8xcH0zB+jL67hueLqFixSSJebbdXMbVce4nwOA==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/dom/-/dom-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-+JjOY81x3d3TlwCztSr4BRxUeEHcg5kwtlbT9Zy/UgdqNStrlTCMeTzRyLNifFnztFzoaWIc6MtF3rLelA/k6Q==", "dependencies": { - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/drawer": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/drawer/-/drawer-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-LYuriNp3lecXXIj3lK22z0ym5bGHHIturofEV60BK9uHi4baBWS/ovTPAw5T8YvpADv5kyidg4mkgkPY9Ydexg==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/list": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/drawer/-/drawer-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-cRSHHU03Q502iJr0iEQFYEhdsIC+Gms43qXmAnjLFUs1EPDxlf/tKiJnvQX6QI03Z5PBoiArCRFjd3/uTvp2KA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/list": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/elevation": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-M9SZKJI5wjbOwq0o8eknDrI27YE63wLg8qJHLvJWrWXdlm6yN0INilihExzmGHXpVHQ6sUdI4oyoAx1qr+vorQ==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-16UkRgq3weby4XaUnL1sUNdRnHgcqBEzCH8bF3JdrrnwqdH/PW74oH+MsXEVctbEsIR8s6rzldcD/0Wqlr/gnQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/fab": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/fab/-/fab-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-G58ZFK7M9r9xkLFP0Gufh1VKdcvRcTvYwEjBuG3+XOMDMjFzCDEMY4c54RG+tbwIiHmB8lw1Yl/dN3kFVc3kTA==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/focus-ring": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/fab/-/fab-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-f6RiL76LnjNchF8FscPVOwx/q7QL8pmE+He0oT/OWWF0BK88V7ZOjNgItR1dJAXvl0fkh9LssPNkmxtHubH79Q==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/focus-ring": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/feature-targeting": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/feature-targeting/-/feature-targeting-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-xH8pdvB5oKO6OTY61vEs44eQJQY3GTobpzaxp+CIBH0UMobSl5KFee+j7MxpEbTkRGtMqWkzAA+vviT8hvmH+A==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/feature-targeting/-/feature-targeting-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-Mv1BXAOhbkvwFYPU2DdiVe45Sy5JKgU5aHdkKzOu5LwyirejwvsDMnmqt22no2Q6qbh0vYeAwpdMEUWUt5JvYg==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/floating-label": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/floating-label/-/floating-label-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-Tjv2xnYr+VvsojRbRBVVmjxmut/y4hJrRCBMjU1982cTUYQlfqMaM7BUObt49jwRBKDLr2NjM+fwNIo0//YItA==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/floating-label/-/floating-label-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-/kJMw+HJHza7BDzfqOMTmKK1MLeN3rD5tv0O+sM9zPlgsVNWIXDjQp/nWP+muqoxY4VZary9WPkz9gq0HMkKbg==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/focus-ring": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/focus-ring/-/focus-ring-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-xutZrHnrfnKftU3HUS9em8wO5Nb4zbnRrwDCGi3xnFR7bFP4u2J2ZUnVpO+RZfjr3A9l8chDavlFCL5HMfzt4A==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/focus-ring/-/focus-ring-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-xhpcqd70vSgUZFZJ2RHKoJkvEKhtg9sOehkd+MRRmm0JmDPSPFcJHEzRB1B99XVDhNWhculbMYH7Gtw+yu6C/g==", "dependencies": { - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0" + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0" } }, "node_modules/@material/form-field": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/form-field/-/form-field-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-N0UnlZ7j3GT4DGmMgJYMl9etOh7rsQjCjRRATWSnuAel+ir4a5HvLj9xQUyp0tlYuu9ZizB8ZOwbAz/XCiU94Q==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/form-field/-/form-field-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-sWXmwxjfihJbv+O43dseY5Tp/i5IAa9l7D2W6guqavrdkUvUgPO4sHXqyBpd3IGaUgtI0wxgWc7kdShbjeyblw==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/icon-button": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/icon-button/-/icon-button-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-BT+tHdRviY1o/yBgtX5NxfS7LfQtQSf7DiZfgP9eExSU5fDA6AfqJfZHyJdLmJCtFZbzlxJ0PBmt44NSlI2/DA==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/focus-ring": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/icon-button/-/icon-button-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-cMFLVP2QruX4deWrVZ0YuQoykY1gIHcijgkJdzuwCSLhsWPvdEeNTWEifz1mVchIJdZNqLbTtYpevM+gSH6Fxg==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/focus-ring": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/image-list": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/image-list/-/image-list-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-FrBosWy9VnqWYDR8XkQPt8cE6MPNq5g7oEvULImmqjRxhktTJCPfDZSWHpjLpAvU0quYZZprPDRrwM3qw69z/A==", - "dependencies": { - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/image-list/-/image-list-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-wd+9m5crO7xBoi8/n6OknGA0KiwxDhPAX8dvkc6dM2plSUwa4HNKfjHQiBPaGCiHsO6v5MWZg2uYSheh2Mgw/w==", + "dependencies": { + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/layout-grid": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/layout-grid/-/layout-grid-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-H4KEhaGaIuGHd3jKJqaoZkynJjqfyti4QhG6wiTt774Lv4Uri1+ZBxQ8FAFShEvETM2pfBy4mEECi/+M4V2ZTA==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/layout-grid/-/layout-grid-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-ye2uJ9bjzl1YUwWsuy7OyQagYs0f+RbRC/EMX4Q8TJyk3FnVdqhDBsKcIjPB4ncx7KGG3QW62/MQlqFehx09lw==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/line-ripple": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/line-ripple/-/line-ripple-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-f4tcd82xu1OT0wAVT/kHiWDmJy9fRt9QA5b+v81fTSVFK41mYpxy8jIQ5gdoIvY/0BWLh4HzUejG6j98AkyLEQ==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/line-ripple/-/line-ripple-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-a5pmIjv0p7v85xNkbXCJFnQqrWVHucyCmXTVj5iJlR1vsqyUR6WN3vJ6F7yFJOhDMEYXZlqSvcTbZCTibR62IQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/linear-progress": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/linear-progress/-/linear-progress-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-3HlEEPv+RrtGPxq06QzCOAZoNJ8q6UtOOkRxh+buQy1F+Uv0n4BdmvUYsHZaSTn+kSlFMzIKDtRjUG2i7b4/hg==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/progress-indicator": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/linear-progress/-/linear-progress-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-Qxjhnia8Yy4VgJlLJgcUD1rcItAmyCYELQxrHhyB0mzmAYwYWgMGoDb+mWqHHKTWXPT1gsJHVmJ9bDq2ZH0JNA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/progress-indicator": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/list": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/list/-/list-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-rYg3cM41MJTSNoFOj8IzF1CpPFK9DDlTFMbERFakRHB1QsfnebxkuoAyI8j5G/pDdvkeAmDbz4tbKK8yJdifRw==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/list/-/list-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-/MqMEidpTA/RSzdUirDSxp0BdUM3D8I1D79EXTopjLROtuqU3rKAGIuXfZopPV7t0j3vBXBLW3cv96iEAkN/pw==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/menu": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/menu/-/menu-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-Xa+tXk8kMFMhdOYrIre1ye4L23i4LzEn48FN398742m1K/VY/IxAuslyQ5CmX77CxkOqbQFqwUarUTod0rEwjw==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/list": "15.0.0-canary.7971d6ad5.0", - "@material/menu-surface": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/menu/-/menu-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-mJ7RNZxUeHnlv/XKwOOGbyekU0blKhUo/0d0mDHi0//VVsjZbiD1wbL2lgtQoUUwvwMxtrDE0v0/OF0AQ1unqg==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/list": "15.0.0-canary.fd95ca7ef.0", + "@material/menu-surface": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/menu-surface": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/menu-surface/-/menu-surface-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-7sRmwY7+a3gB5GM6Vl0sZzVVW3iu6QNW79vRias6nZKJMXbE/JDWnhcgkl9QkxvUolBIJ0y1ChgZyntO8Val/g==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/menu-surface/-/menu-surface-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-6jLY+JCcfGJKTEOKLztyp5VW1Y0Hnj6mkei6poAIZfRO6TTRE4qsdm5Yrlpo3XyRITBZYjS3M7jwz0n2naDMzQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/notched-outline": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/notched-outline/-/notched-outline-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-kMUDUqZ7ztvnwqCENZukztyA0oGZhY/mqd/WIaqRhIU58Q2mnDM6Vfd9fifeM61rIMnXHER2fvjjFzim50mw4g==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/floating-label": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/notched-outline/-/notched-outline-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-pZbDnLBNPIi/2zHzrjx92wmW77mibBrEZMyEa2ir6WfeumJY4fEgfRYiixfvwg7qBDoCAz9eNxA2aPO4ngJ0Jw==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/floating-label": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/progress-indicator": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/progress-indicator/-/progress-indicator-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-CRQAM2C1weVKVr8rQeQTrOISmTupXw+l9sfpdIx8tQ14fOebZFcEbW9LRRvDAMmUNZF6W6pwL74+zk46DYIKBg==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/progress-indicator/-/progress-indicator-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-BrQ3ngFdf6Ig/lpuqAMKwOvjHXy4uiIij45ASFgF0RbVphSdKmzuZVgDZoibcCL4kbhP5CGc5G8kbpOIdmWXHA==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/radio": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/radio/-/radio-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-wpiLuHQtpMb846SSYvG2NQJl/wUi1NbVlCV+uGHSv5LFnbe10e537KFpjtjaDi/Y6e42bUxj8njN5cEZ3NfBUg==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/focus-ring": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/radio/-/radio-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-DY0ypAxKpCBtZ2C79iPOvnXZc25OdRtc8qEHHydvNnzm1OJv56vPUvOBVhxFZj5xr4OWcAMwLZF+HiGGwZ1HgA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/focus-ring": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/ripple": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-S9S8260lwHreEgvOqg3EM0DF0y8ThuN9fFPVb+cCOAPzCn4Z2tO1pcvPfAmY8yZA7QIx9c5pt6Ci+q44LzPEYA==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-md5MGooh3z4NnMXUuFtmiuJk30+MEm9Qns40qus7MUFQDVJ8/nLefwp3HgJQvxkwIB6WKUWaVN7K4KPo5lO0FA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/rtl": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-G02MQTQxHPhNlAIoOToCalxSba48VZ+CdrqkWr53eBb/P1I6Do0drMElqNmO5CYS5G/8AEScXmfJ0xSq92ABew==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-PuPdboompahdk37OXo8osyAZFOXhmMncq/PrgFNKzBSYjFCRuxYP2JzhFT90ytRUClB9Vso5DCLTX2xun1qAwA==", "dependencies": { - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/segmented-button": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/segmented-button/-/segmented-button-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-qu9nfKkPAxv6YFFObZAXHgaC0qq8i4Cr2lUbOQdL0E9HmKG+IE9ILualGJrAl2LOpCSJdwA0CjOuv2IsrscpHA==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/segmented-button/-/segmented-button-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-dn5VvyWnLVUo0x9CeFNrwV+NC896Ha9+jbHwMvJ44oaNorVf8OQHQDDPSj2d2Pjox3BCdf+FUU7Bx7f6cwU+XQ==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/select": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/select/-/select-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-MgbztOBl0Y7UHVPUTuXoAAYfBh+bwbRW9lkK/EJQ4YQrmZB/0L14S7feqh52JhFXVhjFzeYPFMQg+uP2hhHSpg==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/floating-label": "15.0.0-canary.7971d6ad5.0", - "@material/line-ripple": "15.0.0-canary.7971d6ad5.0", - "@material/list": "15.0.0-canary.7971d6ad5.0", - "@material/menu": "15.0.0-canary.7971d6ad5.0", - "@material/menu-surface": "15.0.0-canary.7971d6ad5.0", - "@material/notched-outline": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/select/-/select-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-8GcR11MOXR2EESTIUhm3wY3MSegBSBZ1vfo1KZEFRu75v4QfZAfrr3HF05zQoWaT6GvtAPXcKh3vwmkJSXDs6Q==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/floating-label": "15.0.0-canary.fd95ca7ef.0", + "@material/line-ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/list": "15.0.0-canary.fd95ca7ef.0", + "@material/menu": "15.0.0-canary.fd95ca7ef.0", + "@material/menu-surface": "15.0.0-canary.fd95ca7ef.0", + "@material/notched-outline": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/shape": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/shape/-/shape-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-mlsNFWKOK38ECoB1onCFpi8HKRGgrElk0YioF3V0Joszp1HVV2Fn+SWoKg2LwWHaJet4iBYtNoCbQC6dH2YBeA==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-+nJg/Pv8I9ZT1c3d4b0ZJp66HzLO25DEKWqmyyzifHsuwLK0u9eeN02UguMXqNvPIBPsR2fciwBgJNcuEv+WGA==", "dependencies": { - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/slider": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/slider/-/slider-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-OjbxB3vwZvhbTGP8EGLWoXyodbTMuwkvoFdblEiZtWrrPL0Us5hg/20n8VfUQ0N+c00mElsEv79Jsx+B0iTV+Q==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/slider/-/slider-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-W8yBQrKfOjFD/cZWn543L0JjFBsPAyRMHkQzN0qw89AAR/SK4cw3b6sRoJqEHIPY6aZDWBYW1bESi09WM4lpZA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/snackbar": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/snackbar/-/snackbar-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-svNOI1Kwu9Mg259SNTaGgyJqETRIPwQPkxYhHvWT4vYiHQkJJJe9kFBcIKi+sdTxqqoMZxyjC2SwS/1mkU4/xg==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/button": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/icon-button": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/snackbar/-/snackbar-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-bIf0Je1aMYSlkqfceVViJGWWX/BAqzAhiBVvurvKdRoBTezMrAqEimjQOXu4O2fHiLHmKEsO7c0B3dpobM2fmA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/button": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/icon-button": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/switch": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/switch/-/switch-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-WBsTIq0NwccMAbt9YFcU1vhcmFOVpNDeZ9gNMJypk19ZiqDcZBZNDx0JmceRqTYrCxndqVwfD25qK0jFVplK9g==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/focus-ring": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/switch/-/switch-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-skiw+HbrUh9qh1x8Jl1hNdmzqwPKzHnvJayHC7o6M4HXpIkcBFtvYrUXUc5/XQ9cqd2Nyh7i74aDGlp47fa5fQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/focus-ring": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", "safevalues": "^0.3.4", "tslib": "^2.1.0" } }, "node_modules/@material/tab": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/tab/-/tab-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-hmqRl9s7g1/8KpZ5rqANxUXrHi4PYO3GsGhASrYrB99/5ZX1ghdCGwEN1Lp9ntKIgZjd1s6qtzccBtmnW+boXA==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/focus-ring": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/tab-indicator": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/tab/-/tab-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-pv1qil6xu2e07cAptSd8i/ejYd+nSEzgg6/p+1AXZewlqdq3eHmufXvhZOw7FajIm/nwlRKyuChSPhlPYt+rNg==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/focus-ring": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/tab-indicator": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/tab-bar": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/tab-bar/-/tab-bar-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-hEMnb2C1yOQPbqdFCTCuyMmjcqO4QIvPKAsbquAwOZc0tz/U88tzmfuhv1k77FB2hbESwN9sPpImU0g4Lrvfhw==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/tab": "15.0.0-canary.7971d6ad5.0", - "@material/tab-indicator": "15.0.0-canary.7971d6ad5.0", - "@material/tab-scroller": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/tab-bar/-/tab-bar-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-URYYOwzoRiJJtqdgufl6dNUJphdLgrmfW0e9YvSJlusfAx6SsmbTykTvrRshVRZuoJSsyAAHPHxRY747gmjd8w==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/tab": "15.0.0-canary.fd95ca7ef.0", + "@material/tab-indicator": "15.0.0-canary.fd95ca7ef.0", + "@material/tab-scroller": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/tab-indicator": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/tab-indicator/-/tab-indicator-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-0X2tJf0E+CwL5Bx3Fqxi5Uuj1BgncKqd4yFpWE7cv8IZHphNReSOrCcSgUwUfirmee6MqkQ4Drk51Pf4ANj2OA==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/tab-indicator/-/tab-indicator-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-59HZhI2VNhxL1j8yNhu+wt8X2d2lLfMSpng2plf5LXSXnuowzSA+SxL3xvU5SeRg9ovrREH0udEgD7ob0ktmQQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/tab-scroller": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/tab-scroller/-/tab-scroller-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-//Ih8ZPx92PLQwXhFzv6YCQc5xW2IH84GdIeJrdBNcQN6wgbQNsbU7h9m6jymtpWQgvvLY8E0+2qkNcnWejnag==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/tab": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/tab-scroller/-/tab-scroller-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-xb/o8MOw5gHCwlCr9gA2Z7pRrqjYIxj+6a62PMe75h9avm5kHG+h38LbdaNIjPpCeNbvhpoPRUUpAMAyHHcuGA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/tab": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/textfield": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/textfield/-/textfield-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-n9aWMZGyE2GBTr2Tx6n4hLp08uyIo1/xNqcZ0Kx2tKK1spPgTgp+g2fEKImGnnbfiCTJPNrcJ8bQ+Vy7Dp0n3Q==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/floating-label": "15.0.0-canary.7971d6ad5.0", - "@material/line-ripple": "15.0.0-canary.7971d6ad5.0", - "@material/notched-outline": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/textfield/-/textfield-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-Tk9Ck9vnHQXGjTky6Pl3W0BYmsHa4yXfTZrtrveA3R9Ix/f1LxcVR/4o39i5VMIZQNIXlAVa1hIRgjpEcx3VtA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/floating-label": "15.0.0-canary.fd95ca7ef.0", + "@material/line-ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/notched-outline": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/theme": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/theme/-/theme-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-4YUyQo4SOatHHH15/h2LBIyxmVxtefo+QC8bRopF13f/qq5lHpX/stK6chf1OR/z9BUxnNHZWXd2LG5SvJGs9Q==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-Ho0DWUZ/JZ+NkzgdJGc5QHarTOcaqm0RnibAW/y+0BgQCgVYNQHbQ2oZjqr2u+pCOC9n2T7GVdvm4z+0xF312Q==", "dependencies": { - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/tokens": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/tokens/-/tokens-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-tRa/Uki/moIP6f/QJPrad2jHbSZ5NB5TRSfAS1NZof0KNFjW8n2lJVpgcgD+f1NENin3dWM4NpfJwxulGlWE7g==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/tokens/-/tokens-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-N0KbJD9BwriCR2ZcUz3kgdM1lQYixqTSFe/kU+4mdAWBZhEsE8s6S6x3qzDatYLtLIKfGgWXyG+duHtoS5iFag==", "dependencies": { - "@material/elevation": "15.0.0-canary.7971d6ad5.0" + "@material/elevation": "15.0.0-canary.fd95ca7ef.0" } }, "node_modules/@material/tooltip": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/tooltip/-/tooltip-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-gidVGZOGmJUNDxm3ZorNZMAFmbeFmJ+6DH2F45hi1iU/GflfyvMfvbG2VvPFGYj84YAKHs799yAjidvk1nSZZg==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/button": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/tooltip/-/tooltip-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-mbn/dBh8hYczaxds+e5MtmQ3Gd0frH9F0EAD6EQLKnuRirBrBQ6s5zhs/u7ta2wzG1pqCZTONjW8k+uZL+OpCA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/button": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "safevalues": "^0.3.4", "tslib": "^2.1.0" } }, "node_modules/@material/top-app-bar": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/top-app-bar/-/top-app-bar-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-ztvglUBK0y4LDHD8xhvNGCpbsHYoAVtI06cJHu5G241WD5wAmseEnLMY+ty86FHMzs796PzhUqUmahEHeBNlEg==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/top-app-bar/-/top-app-bar-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-ovVxOFL6/TXxjxr3IkA7Qvdy5DuhfN19BUJVbaFVwCFhnmOFEF549CKtM1TnxyExAggGVBIitwD0gK/Ao63FWg==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/touch-target": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/touch-target/-/touch-target-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-aT8GyRfH0TJuF53HWKga+vuwJbJ/euN6T8CS/+RP5F/rjzWwxSd8RtyBmVUzBjVzOxr6Os+El0c3TFfEDxRdAg==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/touch-target/-/touch-target-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-0fjs8kDRws+W34zg6rTBgnqQFHvAZ1kp5be5wPA3e5Io5YIrRaD2APz9dofEfgNnSN/EoQQI/IAWwv+a4WbJRQ==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/typography": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/typography/-/typography-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-4J5qPXbCS3wMtGl0AJIj/M9rUxHR7fRX3IKtfOyvra10lZbr4qma+4g0+t+O9cPzcCBS1NwPkJ/E4t+ijEa6gA==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-OihvVBCvb3R9sg197ZLRSZSQaAE4wzGiIDzpajibuxbuaHzOwcSNt782Kqz27xy5uBQ0r/iQb4SdU877NQfUXw==", "dependencies": { - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@ng-bootstrap/ng-bootstrap": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-14.0.0.tgz", - "integrity": "sha512-QOYt1MBqAVVrjYSIf4gGXzRRJFzVKuD7ya2yFmeqN0YV2t3kB+IfUaNlfT3PTakHxLOS9ujLXeDiaTps5ST5TA==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-14.0.1.tgz", + "integrity": "sha512-JF4U4IIix+g6VBFfG8stf0Un5K//ypoN+pTuRs6kjUhsHBsa2m7yKE6bCe3fMhatFZFr2fcSswDzRUnAUiHhWg==", "dependencies": { "tslib": "^2.3.0" }, @@ -4354,8 +4546,7 @@ }, "node_modules/@ngrx/store": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-15.1.0.tgz", - "integrity": "sha512-Wxjme7yJnxD6il6fGZdFTdSs9gL+6OFW8/II9vApFokUb0E7UQBm8RYb9dYJ2IQJvWXwO+2ItSaecRUZgt39kA==", + "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, @@ -4365,9 +4556,9 @@ } }, "node_modules/@ngtools/webpack": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-15.0.4.tgz", - "integrity": "sha512-+1riOTohRHhN2N8Y+usHFtNz+Rt6q/44puj9rwjlKwWIA+6qxAv3kQhVHivVaU3bCAB9B/3jAxSuZTNHk0wgTg==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-15.1.1.tgz", + "integrity": "sha512-pHkVE4IfIGcrIqxxrBQJV62GBqXF+LU4sPY5MLNWIfKSctW6AdTVoO9ilx8pclaFJkMLkPMbrmfGosYw47L+lg==", "dev": true, "engines": { "node": "^14.20.0 || ^16.13.0 || >=18.10.0", @@ -4376,15 +4567,14 @@ }, "peerDependencies": { "@angular/compiler-cli": "^15.0.0", - "typescript": "~4.8.2", + "typescript": ">=4.8.2 <5.0", "webpack": "^5.54.0" } }, "node_modules/@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, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -4395,18 +4585,16 @@ }, "node_modules/@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, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/@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, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -4447,15 +4635,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/@npmcli/git/node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/@npmcli/git/node_modules/which": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", @@ -4570,13 +4749,11 @@ }, "node_modules/@petamoriken/float16": { "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.7.0.tgz", - "integrity": "sha512-g7w35q4bt7MoM3nZKrk5COiIO+qevZjjS7bJO5pYrB0ZKABUXFBOgr2VBY66LmeI3FzkH5AZ+1uNmNHYjeuUjQ==" + "license": "MIT" }, "node_modules/@popperjs/core": { "version": "2.11.6", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", - "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", + "license": "MIT", "peer": true, "funding": { "type": "opencollective", @@ -4584,13 +4761,13 @@ } }, "node_modules/@schematics/angular": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-15.0.4.tgz", - "integrity": "sha512-4l4WZlr9MnhXo2B7eLczttgkeq8Agm3zfiX0trYkOdYqLtzOKxPiI+RrZSsfIDmmLSE1EillZ3PtDImMzAgQPg==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-15.1.1.tgz", + "integrity": "sha512-Ujo4vt/r3WzIhGn2I2Lt3eOTWSsVxoXfcXxFRuxl3cil/9mH1X66hDTQ2DVYiXPFGcQMjcNaDwlQxyor4yGbqA==", "dev": true, "dependencies": { - "@angular-devkit/core": "15.0.4", - "@angular-devkit/schematics": "15.0.4", + "@angular-devkit/core": "15.1.1", + "@angular-devkit/schematics": "15.1.1", "jsonc-parser": "3.2.0" }, "engines": { @@ -4601,32 +4778,28 @@ }, "node_modules/@sinclair/typebox": { "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@sinonjs/commons": { "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^1.7.0" } }, "node_modules/@socket.io/component-emitter": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", - "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + "license": "MIT" }, "node_modules/@tootallnate/once": { "version": "2.0.0", @@ -4639,9 +4812,8 @@ }, "node_modules/@types/babel__core": { "version": "7.1.20", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", - "integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0", @@ -4652,18 +4824,16 @@ }, "node_modules/@types/babel__generator": { "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" @@ -4671,9 +4841,8 @@ }, "node_modules/@types/babel__traverse": { "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.3.0" } @@ -4699,9 +4868,8 @@ }, "node_modules/@types/chart.js": { "version": "2.9.37", - "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.37.tgz", - "integrity": "sha512-9bosRfHhkXxKYfrw94EmyDQcdjMaQPkU1fH2tDxu8DWXxf1mjzWQAV4laJF51ZbC2ycYwNDvIm1rGez8Bug0vg==", "dev": true, + "license": "MIT", "dependencies": { "moment": "^2.10.2" } @@ -4727,9 +4895,8 @@ }, "node_modules/@types/eslint": { "version": "8.4.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", - "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -4737,9 +4904,8 @@ }, "node_modules/@types/eslint-scope": { "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", "dev": true, + "license": "MIT", "dependencies": { "@types/eslint": "*", "@types/estree": "*" @@ -4747,9 +4913,8 @@ }, "node_modules/@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 + "dev": true, + "license": "MIT" }, "node_modules/@types/express": { "version": "4.17.15", @@ -4764,9 +4929,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.31", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", - "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", + "version": "4.17.32", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.32.tgz", + "integrity": "sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==", "dev": true, "dependencies": { "@types/node": "*", @@ -4776,9 +4941,8 @@ }, "node_modules/@types/graceful-fs": { "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -4794,32 +4958,29 @@ }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" } }, "node_modules/@types/istanbul-reports": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" } }, "node_modules/@types/jest": { - "version": "29.2.4", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.4.tgz", - "integrity": "sha512-PipFB04k2qTRPePduVLTRiPzQfvMeLwUN3Z21hsAKaB/W9IIzgB2pizCL466ftJlcyZqnHoC9ZHpxLGl3fS86A==", + "version": "29.2.5", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz", + "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -4828,27 +4989,23 @@ }, "node_modules/@types/json-schema": { "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/json5": { "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/lodash": { "version": "4.14.191", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", - "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/lodash-es": { "version": "4.17.6", - "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz", - "integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==", "dev": true, + "license": "MIT", "dependencies": { "@types/lodash": "*" } @@ -4860,16 +5017,15 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.11.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.15.tgz", - "integrity": "sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw==", + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", "dev": true }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -4879,9 +5035,8 @@ }, "node_modules/@types/prettier": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/qs": { "version": "6.9.7", @@ -4903,9 +5058,8 @@ }, "node_modules/@types/semver": { "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/serve-index": { "version": "1.9.1", @@ -4928,15 +5082,13 @@ }, "node_modules/@types/sinonjs__fake-timers": { "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", - "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", - "dev": true + "dev": true, + "license": "MIT" }, "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 + "dev": true, + "license": "MIT" }, "node_modules/@types/sockjs": { "version": "0.3.33", @@ -4949,19 +5101,17 @@ }, "node_modules/@types/stack-utils": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/validator": { "version": "13.7.10", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.10.tgz", - "integrity": "sha512-t1yxFAR2n0+VO6hd/FJ9F2uezAZVWHLmpmlJzm1eX03+H7+HsuTAp7L8QJs+2pQCfWkP1+EXsGK9Z9v7o/qPVQ==" + "license": "MIT" }, "node_modules/@types/ws": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", - "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", "dev": true, "dependencies": { "@types/node": "*" @@ -4969,38 +5119,35 @@ }, "node_modules/@types/yargs": { "version": "17.0.17", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.17.tgz", - "integrity": "sha512-72bWxFKTK6uwWJAVT+3rF6Jo6RTojiJ27FQo8Rf60AL+VZbzoVPnMFhKsUnbjR8A3BTCYQ7Mv3hnl8T0A+CX9g==", "dev": true, + "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/yauzl": { "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "@types/node": "*" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.0.tgz", - "integrity": "sha512-AHZtlXAMGkDmyLuLZsRpH3p4G/1iARIwc/T0vIem2YB+xW6pZaXYXzCBnZSF/5fdM97R9QqZWZ+h3iW10XgevQ==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", + "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/type-utils": "5.47.0", - "@typescript-eslint/utils": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/type-utils": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", @@ -5026,13 +5173,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.0.tgz", - "integrity": "sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0" + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -5043,13 +5190,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.47.0.tgz", - "integrity": "sha512-1J+DFFrYoDUXQE1b7QjrNGARZE6uVhBqIvdaXTe5IN+NmEyD68qXR1qX1g2u4voA+nCaelQyG8w30SAOihhEYg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", + "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.47.0", - "@typescript-eslint/utils": "5.47.0", + "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -5070,9 +5217,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.0.tgz", - "integrity": "sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -5083,13 +5230,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.0.tgz", - "integrity": "sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -5110,16 +5257,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.47.0.tgz", - "integrity": "sha512-U9xcc0N7xINrCdGVPwABjbAKqx4GK67xuMV87toI+HUqgXj26m6RBp9UshEXcTrgCkdGYFzgKLt8kxu49RilDw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", + "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/typescript-estree": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -5136,12 +5283,12 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.0.tgz", - "integrity": "sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/types": "5.48.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -5176,9 +5323,8 @@ }, "node_modules/@typescript-eslint/experimental-utils": { "version": "5.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.46.1.tgz", - "integrity": "sha512-M79mkB+wOuiBG8jzOVNA2h5izOip5CNPZV1K3tvE/qry/1Oh/bnKYhNWQNiH2h9O3B73YK60GmiqrUpprnQ5sQ==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/utils": "5.46.1" }, @@ -5195,9 +5341,8 @@ }, "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/utils": { "version": "5.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.46.1.tgz", - "integrity": "sha512-RBdBAGv3oEpFojaCYT4Ghn4775pdjvwfDOfQ2P6qzNVgQOVrnSPe5/Pb88kv7xzYQjoio0eKHKB9GJ16ieSxvA==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", @@ -5221,9 +5366,8 @@ }, "node_modules/@typescript-eslint/experimental-utils/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, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -5234,22 +5378,21 @@ }, "node_modules/@typescript-eslint/experimental-utils/node_modules/estraverse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.47.0.tgz", - "integrity": "sha512-udPU4ckK+R1JWCGdQC4Qa27NtBg7w020ffHqGyAK8pAgOVuNw7YaKXGChk+udh+iiGIJf6/E/0xhVXyPAbsczw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz", + "integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/typescript-estree": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", "debug": "^4.3.4" }, "engines": { @@ -5269,13 +5412,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.0.tgz", - "integrity": "sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0" + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -5286,9 +5429,9 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.0.tgz", - "integrity": "sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -5299,13 +5442,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.0.tgz", - "integrity": "sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -5326,12 +5469,12 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.0.tgz", - "integrity": "sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/types": "5.48.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -5344,9 +5487,8 @@ }, "node_modules/@typescript-eslint/scope-manager": { "version": "5.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.46.1.tgz", - "integrity": "sha512-iOChVivo4jpwUdrJZyXSMrEIM/PvsbbDOX1y3UCKjSgWn+W89skxWaYXACQfxmIGhPVpRWK/VWPYc+bad6smIA==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.46.1", "@typescript-eslint/visitor-keys": "5.46.1" @@ -5361,9 +5503,8 @@ }, "node_modules/@typescript-eslint/type-utils": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.44.0.tgz", - "integrity": "sha512-A1u0Yo5wZxkXPQ7/noGkRhV4J9opcymcr31XQtOzcc5nO/IHN2E2TPMECKWYpM3e6olWEM63fq/BaL1wEYnt/w==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/typescript-estree": "5.44.0", "@typescript-eslint/utils": "5.44.0", @@ -5388,9 +5529,8 @@ }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.44.0.tgz", - "integrity": "sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -5401,9 +5541,8 @@ }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.44.0.tgz", - "integrity": "sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "5.44.0", "@typescript-eslint/visitor-keys": "5.44.0", @@ -5428,9 +5567,8 @@ }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.44.0.tgz", - "integrity": "sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.44.0", "eslint-visitor-keys": "^3.3.0" @@ -5445,9 +5583,8 @@ }, "node_modules/@typescript-eslint/types": { "version": "5.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.1.tgz", - "integrity": "sha512-Z5pvlCaZgU+93ryiYUwGwLl9AQVB/PQ1TsJ9NZ/gHzZjN7g9IAn6RSDkpCV8hqTwAiaj6fmCcKSQeBPlIpW28w==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -5458,9 +5595,8 @@ }, "node_modules/@typescript-eslint/typescript-estree": { "version": "5.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.46.1.tgz", - "integrity": "sha512-j9W4t67QiNp90kh5Nbr1w92wzt+toiIsaVPnEblB2Ih2U9fqBTyqV9T3pYWZBRt6QoMh/zVWP59EpuCjc4VRBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "5.46.1", "@typescript-eslint/visitor-keys": "5.46.1", @@ -5485,9 +5621,8 @@ }, "node_modules/@typescript-eslint/utils": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.44.0.tgz", - "integrity": "sha512-fMzA8LLQ189gaBjS0MZszw5HBdZgVwxVFShCO3QN+ws3GlPkcy9YuS3U4wkT6su0w+Byjq3mS3uamy9HE4Yfjw==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", @@ -5511,9 +5646,8 @@ }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.44.0.tgz", - "integrity": "sha512-2pKml57KusI0LAhgLKae9kwWeITZ7IsZs77YxyNyIVOwQ1kToyXRaJLl+uDEXzMN5hnobKUOo2gKntK9H1YL8g==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.44.0", "@typescript-eslint/visitor-keys": "5.44.0" @@ -5528,9 +5662,8 @@ }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.44.0.tgz", - "integrity": "sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -5541,9 +5674,8 @@ }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.44.0.tgz", - "integrity": "sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "5.44.0", "@typescript-eslint/visitor-keys": "5.44.0", @@ -5568,9 +5700,8 @@ }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.44.0.tgz", - "integrity": "sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.44.0", "eslint-visitor-keys": "^3.3.0" @@ -5585,9 +5716,8 @@ }, "node_modules/@typescript-eslint/utils/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, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -5598,18 +5728,16 @@ }, "node_modules/@typescript-eslint/utils/node_modules/estraverse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/@typescript-eslint/visitor-keys": { "version": "5.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.1.tgz", - "integrity": "sha512-jczZ9noovXwy59KjRTk1OftT78pwygdcmCuBf8yMoWt/8O8l+6x2LSEze0E4TeepXK4MezW3zGSyoDRZK7Y9cg==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.46.1", "eslint-visitor-keys": "^3.3.0" @@ -5624,9 +5752,8 @@ }, "node_modules/@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, + "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.11.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.1" @@ -5634,27 +5761,23 @@ }, "node_modules/@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 + "dev": true, + "license": "MIT" }, "node_modules/@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 + "dev": true, + "license": "MIT" }, "node_modules/@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 + "dev": true, + "license": "MIT" }, "node_modules/@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, + "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.11.1", "@webassemblyjs/helper-api-error": "1.11.1", @@ -5663,15 +5786,13 @@ }, "node_modules/@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 + "dev": true, + "license": "MIT" }, "node_modules/@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, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/helper-buffer": "1.11.1", @@ -5681,33 +5802,29 @@ }, "node_modules/@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, + "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@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, + "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@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 + "dev": true, + "license": "MIT" }, "node_modules/@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, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/helper-buffer": "1.11.1", @@ -5721,9 +5838,8 @@ }, "node_modules/@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, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.1", @@ -5734,9 +5850,8 @@ }, "node_modules/@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, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/helper-buffer": "1.11.1", @@ -5746,9 +5861,8 @@ }, "node_modules/@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, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/helper-api-error": "1.11.1", @@ -5760,9 +5874,8 @@ }, "node_modules/@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, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.11.1", "@xtuc/long": "4.2.2" @@ -5770,27 +5883,23 @@ }, "node_modules/@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 + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@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 + "dev": true, + "license": "Apache-2.0" }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/abab": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/abbrev": { "version": "1.1.1", @@ -5813,9 +5922,8 @@ }, "node_modules/acorn": { "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -5825,9 +5933,8 @@ }, "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, + "license": "MIT", "peerDependencies": { "acorn": "^8" } @@ -5843,9 +5950,8 @@ }, "node_modules/adjust-sourcemap-loader": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", - "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", "dev": true, + "license": "MIT", "dependencies": { "loader-utils": "^2.0.0", "regex-parser": "^2.2.11" @@ -5856,9 +5962,8 @@ }, "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, + "license": "MIT", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -5870,9 +5975,8 @@ }, "node_modules/agent-base": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dev": true, + "license": "MIT", "dependencies": { "debug": "4" }, @@ -5896,9 +6000,8 @@ }, "node_modules/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, + "license": "MIT", "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -5908,9 +6011,9 @@ } }, "node_modules/ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -5925,9 +6028,8 @@ }, "node_modules/ajv-formats": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^8.0.0" }, @@ -5942,9 +6044,8 @@ }, "node_modules/ajv-keywords": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" }, @@ -5954,18 +6055,16 @@ }, "node_modules/ansi-colors": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "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==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -5990,16 +6089,14 @@ }, "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==", + "license": "MIT", "engines": { "node": ">=8" } }, "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==", + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -6009,8 +6106,7 @@ }, "node_modules/anymatch": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -6027,8 +6123,6 @@ }, "node_modules/arch": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", "dev": true, "funding": [ { @@ -6043,7 +6137,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/are-we-there-yet": { "version": "3.0.1", @@ -6060,24 +6155,21 @@ }, "node_modules/arg": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/argparse": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, + "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } }, "node_modules/aria-query": { "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "deep-equal": "^2.0.5" } @@ -6090,9 +6182,8 @@ }, "node_modules/array-includes": { "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -6109,17 +6200,33 @@ }, "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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/array.prototype.flat": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", @@ -6136,56 +6243,48 @@ }, "node_modules/asn1": { "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": "~2.1.0" } }, "node_modules/assert-plus": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } }, "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==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/async": { "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/at-least-node": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true, + "license": "ISC", "engines": { "node": ">= 4.0.0" } }, "node_modules/autoprefixer": { "version": "10.4.13", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", - "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", "dev": true, "funding": [ { @@ -6197,6 +6296,7 @@ "url": "https://tidelift.com/funding/github/npm/autoprefixer" } ], + "license": "MIT", "dependencies": { "browserslist": "^4.21.4", "caniuse-lite": "^1.0.30001426", @@ -6217,9 +6317,8 @@ }, "node_modules/available-typed-arrays": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -6229,33 +6328,29 @@ }, "node_modules/aws-sign2": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "*" } }, "node_modules/aws4": { "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/axobject-query": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", - "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "deep-equal": "^2.0.5" } }, "node_modules/babel-jest": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz", - "integrity": "sha512-aard+xnMoxgjwV70t0L6wkW/3HQQtV+O0PEimxKgzNqCJnbYmroPojdP2tqKSOAt8QAKV/uSZU8851M7B5+fcA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/transform": "^29.3.1", "@types/babel__core": "^7.1.14", @@ -6274,9 +6369,8 @@ }, "node_modules/babel-jest/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -6289,9 +6383,8 @@ }, "node_modules/babel-jest/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -6305,9 +6398,8 @@ }, "node_modules/babel-jest/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -6317,24 +6409,21 @@ }, "node_modules/babel-jest/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/babel-jest/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/babel-jest/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -6343,9 +6432,9 @@ } }, "node_modules/babel-loader": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.0.tgz", - "integrity": "sha512-Antt61KJPinUMwHwIIz9T5zfMgevnfZkEVWYDWlG888fgdvRRGD0JTuf/fFozQnfT+uq64sk1bmdHDy/mOEWnA==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.2.tgz", + "integrity": "sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA==", "dev": true, "dependencies": { "find-cache-dir": "^3.3.2", @@ -6361,9 +6450,8 @@ }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -6377,9 +6465,8 @@ }, "node_modules/babel-plugin-jest-hoist": { "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.2.0.tgz", - "integrity": "sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", @@ -6392,9 +6479,8 @@ }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.17.7", "@babel/helper-define-polyfill-provider": "^0.3.3", @@ -6406,18 +6492,16 @@ }, "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/babel-plugin-polyfill-corejs3": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.3.3", "core-js-compat": "^3.25.1" @@ -6428,9 +6512,8 @@ }, "node_modules/babel-plugin-polyfill-regenerator": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.3.3" }, @@ -6440,9 +6523,8 @@ }, "node_modules/babel-preset-current-node-syntax": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", @@ -6463,9 +6545,8 @@ }, "node_modules/babel-preset-jest": { "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.2.0.tgz", - "integrity": "sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==", "dev": true, + "license": "MIT", "dependencies": { "babel-plugin-jest-hoist": "^29.2.0", "babel-preset-current-node-syntax": "^1.0.0" @@ -6479,13 +6560,10 @@ }, "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==" + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true, "funding": [ { @@ -6500,7 +6578,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/batch": { "version": "0.6.1", @@ -6510,18 +6589,16 @@ }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "tweetnacl": "^0.14.3" } }, "node_modules/bent": { "version": "7.3.12", - "resolved": "https://registry.npmjs.org/bent/-/bent-7.3.12.tgz", - "integrity": "sha512-T3yrKnVGB63zRuoco/7Ybl7BwwGZR0lceoVG5XmQyMIH9s19SV5m+a8qam4if0zQuAmOQTyPTPmsQBdAorGK3w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "bytesish": "^0.4.1", "caseless": "~0.12.0", @@ -6530,26 +6607,23 @@ }, "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, + "license": "MIT", "engines": { "node": "*" } }, "node_modules/binary-extensions": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/bl": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, + "license": "MIT", "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -6558,15 +6632,13 @@ }, "node_modules/blob-util": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", - "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/bluebird": { "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/body-parser": { "version": "1.20.1", @@ -6641,9 +6713,9 @@ } }, "node_modules/bonjour-service": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.14.tgz", - "integrity": "sha512-HIMbgLnk1Vqvs6B4Wq5ep7mxvj9sGz5d1JJyDNSGNIdA/w2MCz6GTjWTdjqOJV1bEPj+6IkxDvWNFKEBxNt4kQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.0.tgz", + "integrity": "sha512-LVRinRB3k1/K0XzZ2p58COnWvkQknIY6sf0zF2rpErvcJXpMBttEPQSxK+HEXSS9VmpZlDoDnQWv8ftJT20B0Q==", "dev": true, "dependencies": { "array-flatten": "^2.1.2", @@ -6654,14 +6726,11 @@ }, "node_modules/boolbase": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/bootstrap": { "version": "5.2.3", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.3.tgz", - "integrity": "sha512-cEKPM+fwb3cT8NzQZYEu4HilJ3anCrWqh3CHAok1p9jXqMPsPTBhU25fBckEJHJ/p+tTxTFTsFQGM+gaHpi3QQ==", "funding": [ { "type": "github", @@ -6672,20 +6741,20 @@ "url": "https://opencollective.com/bootstrap" } ], + "license": "MIT", "peerDependencies": { "@popperjs/core": "^2.11.6" } }, "node_modules/bootstrap-icons": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.10.2.tgz", - "integrity": "sha512-PTPYadRn1AMGr+QTSxe4ZCc+Wzv9DGZxbi3lNse/dajqV31n2/wl/7NX78ZpkvFgRNmH4ogdIQPQmxAfhEV6nA==" + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.10.3.tgz", + "integrity": "sha512-7Qvj0j0idEm/DdX9Q0CpxAnJYqBCFCiUI6qzSPYfERMcokVuV9Mdm/AJiVZI8+Gawe4h/l6zFcOzvV7oXCZArw==" }, "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, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6693,8 +6762,7 @@ }, "node_modules/braces": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "license": "MIT", "dependencies": { "fill-range": "^7.0.1" }, @@ -6704,8 +6772,6 @@ }, "node_modules/browserslist": { "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", "funding": [ { "type": "opencollective", @@ -6716,6 +6782,7 @@ "url": "https://tidelift.com/funding/github/npm/browserslist" } ], + "license": "MIT", "dependencies": { "caniuse-lite": "^1.0.30001400", "electron-to-chromium": "^1.4.251", @@ -6731,9 +6798,8 @@ }, "node_modules/bs-logger": { "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", "dev": true, + "license": "MIT", "dependencies": { "fast-json-stable-stringify": "2.x" }, @@ -6743,17 +6809,14 @@ }, "node_modules/bser": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" } }, "node_modules/buffer": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, "funding": [ { @@ -6769,6 +6832,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -6776,24 +6840,21 @@ }, "node_modules/buffer-crc32": { "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, "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 + "dev": true, + "license": "MIT" }, "node_modules/builtin-modules": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -6821,21 +6882,20 @@ }, "node_modules/bytesish": { "version": "0.4.4", - "resolved": "https://registry.npmjs.org/bytesish/-/bytesish-0.4.4.tgz", - "integrity": "sha512-i4uu6M4zuMUiyfZN4RU2+i9+peJh//pXhd9x1oSe1LBkZ3LEbCoygu8W0bXTukU1Jme2txKuotpCZRaC3FLxcQ==", - "dev": true + "dev": true, + "license": "(Apache-2.0 AND MIT)" }, "node_modules/cacache": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.2.tgz", - "integrity": "sha512-rYUs2x4OjSgCQND7nTrh21AHIBFgd7s/ctAYvU3a8u+nK+R5YaX/SFPDYz4Azz7SGL6+6L9ZZWI4Kawpb7grzQ==", + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.4.tgz", + "integrity": "sha512-Z/nL3gU+zTUjz5pCA5vVjYM8pmaw2kxM7JEiE0fv3w77Wj+sFbi70CrBruUWH0uNcEdvLDixFpgA2JM4F4DBjA==", "dev": true, "dependencies": { "@npmcli/fs": "^3.1.0", - "fs-minipass": "^2.1.0", + "fs-minipass": "^3.0.0", "glob": "^8.0.1", "lru-cache": "^7.7.1", - "minipass": "^3.1.6", + "minipass": "^4.0.0", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", @@ -6851,18 +6911,16 @@ }, "node_modules/cachedir": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", - "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "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, + "license": "MIT", "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -6873,26 +6931,22 @@ }, "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, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/camelcase": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { "version": "1.0.30001439", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz", - "integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==", "funding": [ { "type": "opencollective", @@ -6902,18 +6956,17 @@ "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/caseless": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/chalk": { "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -6925,23 +6978,21 @@ }, "node_modules/char-regex": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } }, "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 + "dev": true, + "license": "MIT" }, "node_modules/chart.js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.1.1.tgz", - "integrity": "sha512-P0pCosNXp+LR8zO/QTkZKT6Hb7p0DPFtypEeVOf+6x06hX13NIb75R0DXUA4Ksx/+48chDQKtCCmRCviQRTqsA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.1.2.tgz", + "integrity": "sha512-9L1w6WLPq6ztiWVVOYtDtpo0CUsBKDWPrUEdwChAyzczaikqeSwNKEv3QpJ7EO4ICcLSi6UDVhgvcnUhRJidRA==", "dependencies": { "@kurkle/color": "^0.3.0" }, @@ -6951,23 +7002,21 @@ }, "node_modules/check-more-types": { "version": "2.24.0", - "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", - "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/chokidar": { "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "funding": [ { "type": "individual", "url": "https://paulmillr.com/funding/" } ], + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -6995,37 +7044,32 @@ }, "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, + "license": "MIT", "engines": { "node": ">=6.0" } }, "node_modules/ci-info": { "version": "3.7.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", - "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/cjs-module-lexer": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/class-transformer": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", - "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" + "license": "MIT" }, "node_modules/class-validator": { "version": "0.14.0", - "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.0.tgz", - "integrity": "sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A==", + "license": "MIT", "dependencies": { "@types/validator": "^13.7.10", "libphonenumber-js": "^1.10.14", @@ -7034,9 +7078,8 @@ }, "node_modules/clean-regexp": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", - "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", "dev": true, + "license": "MIT", "dependencies": { "escape-string-regexp": "^1.0.5" }, @@ -7046,18 +7089,16 @@ }, "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, + "license": "MIT", "engines": { "node": ">=6" } }, "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==", "dev": true, + "license": "MIT", "dependencies": { "restore-cursor": "^3.1.0" }, @@ -7067,9 +7108,8 @@ }, "node_modules/cli-spinners": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", - "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -7079,9 +7119,8 @@ }, "node_modules/cli-table3": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", - "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", "dev": true, + "license": "MIT", "dependencies": { "string-width": "^4.2.0" }, @@ -7094,9 +7133,8 @@ }, "node_modules/cli-truncate": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", "dev": true, + "license": "MIT", "dependencies": { "slice-ansi": "^3.0.0", "string-width": "^4.2.0" @@ -7110,17 +7148,15 @@ }, "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, + "license": "ISC", "engines": { "node": ">= 10" } }, "node_modules/cliui": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -7132,18 +7168,16 @@ }, "node_modules/clone": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } }, "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, + "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4", "kind-of": "^6.0.2", @@ -7155,9 +7189,8 @@ }, "node_modules/co": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, + "license": "MIT", "engines": { "iojs": ">= 1.0.0", "node": ">= 0.12.0" @@ -7165,22 +7198,19 @@ }, "node_modules/collect-v8-coverage": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true + "dev": true, + "license": "MIT" }, "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==", + "license": "MIT", "dependencies": { "color-name": "1.1.3" } }, "node_modules/color-name": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "license": "MIT" }, "node_modules/color-support": { "version": "1.1.3", @@ -7193,24 +7223,21 @@ }, "node_modules/colorette": { "version": "2.0.19", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/colors": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.1.90" } }, "node_modules/combined-stream": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -7220,18 +7247,16 @@ }, "node_modules/commander": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/common-tags": { "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -7295,9 +7320,8 @@ }, "node_modules/concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/connect-history-api-fallback": { "version": "2.0.0", @@ -7337,8 +7361,7 @@ }, "node_modules/convert-source-map": { "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + "license": "MIT" }, "node_modules/cookie": { "version": "0.5.0", @@ -7357,9 +7380,8 @@ }, "node_modules/copy-anything": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", - "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", "dev": true, + "license": "MIT", "dependencies": { "is-what": "^3.14.1" }, @@ -7369,9 +7391,8 @@ }, "node_modules/copy-webpack-plugin": { "version": "11.0.0", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", - "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", "dev": true, + "license": "MIT", "dependencies": { "fast-glob": "^3.2.11", "glob-parent": "^6.0.1", @@ -7393,9 +7414,8 @@ }, "node_modules/copy-webpack-plugin/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, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -7405,9 +7425,8 @@ }, "node_modules/copy-webpack-plugin/node_modules/globby": { "version": "13.1.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", - "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==", "dev": true, + "license": "MIT", "dependencies": { "dir-glob": "^3.0.1", "fast-glob": "^3.2.11", @@ -7424,9 +7443,8 @@ }, "node_modules/copy-webpack-plugin/node_modules/slash": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -7436,9 +7454,8 @@ }, "node_modules/core-js-compat": { "version": "3.26.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.1.tgz", - "integrity": "sha512-622/KzTudvXCDLRw70iHW4KKs1aGpcRcowGWyYJr2DEBfRrd6hNJybxSWJFuZYD4ma86xhrwDDHxmDaIq4EA8A==", "dev": true, + "license": "MIT", "dependencies": { "browserslist": "^4.21.4" }, @@ -7449,9 +7466,8 @@ }, "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": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cosmiconfig": { "version": "7.1.0", @@ -7471,9 +7487,8 @@ }, "node_modules/critters": { "version": "0.0.16", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", - "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", "dev": true, + "license": "Apache-2.0", "dependencies": { "chalk": "^4.1.0", "css-select": "^4.2.0", @@ -7485,9 +7500,8 @@ }, "node_modules/critters/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -7500,9 +7514,8 @@ }, "node_modules/critters/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -7516,9 +7529,8 @@ }, "node_modules/critters/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7528,30 +7540,26 @@ }, "node_modules/critters/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/critters/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/critters/node_modules/parse5": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/critters/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7561,9 +7569,8 @@ }, "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, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -7575,9 +7582,8 @@ }, "node_modules/css-loader": { "version": "6.7.3", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", - "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.19", @@ -7601,9 +7607,8 @@ }, "node_modules/css-select": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.0.1", @@ -7617,9 +7622,8 @@ }, "node_modules/css-what": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">= 6" }, @@ -7629,14 +7633,12 @@ }, "node_modules/csscolorparser": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz", - "integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==" + "license": "MIT" }, "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, + "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -7646,10 +7648,9 @@ }, "node_modules/cypress": { "version": "9.7.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.7.0.tgz", - "integrity": "sha512-+1EE1nuuuwIt/N1KXRR2iWHU+OiIt7H28jJDyyI4tiUftId/DrXYEwoDa5+kH2pki1zxnA0r6HrUGHV5eLbF5Q==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { "@cypress/request": "^2.88.10", "@cypress/xvfb": "^1.2.4", @@ -7703,9 +7704,8 @@ }, "node_modules/cypress-image-diff-js": { "version": "1.22.0", - "resolved": "https://registry.npmjs.org/cypress-image-diff-js/-/cypress-image-diff-js-1.22.0.tgz", - "integrity": "sha512-ugCXZF6mVcp+TQQBrb2xARgFsnS5Mt3MCVpAr/fiF/GG7usuuiJWbHqQ+98H0kIoPIvFJzC5Nzf6VZ1+zycHLw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5", "arg": "^4.1.1", @@ -7725,24 +7725,21 @@ }, "node_modules/cypress-recurse": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/cypress-recurse/-/cypress-recurse-1.24.0.tgz", - "integrity": "sha512-yH2XF71go+muxWjUbF7onNK0rzoVn27gzOPMTV3thg+Nv//jK2tV/z4hF0FWv88O3CAtmh7JZWhVNqFq4ghMZg==", "dev": true, + "license": "MIT", "dependencies": { "humanize-duration": "^3.27.3" } }, "node_modules/cypress/node_modules/@types/node": { "version": "14.18.34", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.34.tgz", - "integrity": "sha512-hcU9AIQVHmPnmjRK+XUUYlILlr9pQrsqSrwov/JK1pnf3GTQowVBhx54FbvM0AU/VXGH4i3+vgXS5EguR7fysA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cypress/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -7755,9 +7752,8 @@ }, "node_modules/cypress/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -7771,9 +7767,8 @@ }, "node_modules/cypress/node_modules/chalk/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7783,9 +7778,8 @@ }, "node_modules/cypress/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7795,24 +7789,21 @@ }, "node_modules/cypress/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cypress/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/cypress/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7825,9 +7816,8 @@ }, "node_modules/dashdash": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0" }, @@ -7837,14 +7827,12 @@ }, "node_modules/dayjs": { "version": "1.11.7", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", - "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/debug": { "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -7859,9 +7847,8 @@ }, "node_modules/decamelize": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz", - "integrity": "sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -7871,15 +7858,13 @@ }, "node_modules/dedent": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/deep-equal": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.1.0.tgz", - "integrity": "sha512-2pxgvWu3Alv1PoWEyVg7HS8YhGlUFUV7N5oOvfL6d+7xAmLSemMwv/c8Zv/i9KFzxV5Kt5CAvQc70fLwVuf4UA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "es-get-iterator": "^1.1.2", @@ -7903,15 +7888,13 @@ }, "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 + "dev": true, + "license": "MIT" }, "node_modules/deepmerge": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7974,9 +7957,8 @@ }, "node_modules/defaults": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "dev": true, + "license": "MIT", "dependencies": { "clone": "^1.0.2" }, @@ -7986,18 +7968,16 @@ }, "node_modules/define-lazy-prop": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/define-properties": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", "dev": true, + "license": "MIT", "dependencies": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -8011,9 +7991,8 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -8035,8 +8014,7 @@ }, "node_modules/dependency-graph": { "version": "0.11.0", - "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", - "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "license": "MIT", "engines": { "node": ">= 0.6.0" } @@ -8053,9 +8031,8 @@ }, "node_modules/detect-newline": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -8068,9 +8045,8 @@ }, "node_modules/diff-sequences": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", - "integrity": "sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -8081,9 +8057,8 @@ }, "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, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -8111,9 +8086,8 @@ }, "node_modules/doctrine": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -8123,9 +8097,8 @@ }, "node_modules/dom-serializer": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -8137,21 +8110,19 @@ }, "node_modules/domelementtype": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/fb55" } - ] + ], + "license": "BSD-2-Clause" }, "node_modules/domhandler": { "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.2.0" }, @@ -8164,9 +8135,8 @@ }, "node_modules/domutils": { "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", @@ -8178,14 +8148,12 @@ }, "node_modules/earcut": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", - "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" + "license": "ISC" }, "node_modules/ecc-jsbn": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, + "license": "MIT", "dependencies": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -8199,14 +8167,12 @@ }, "node_modules/electron-to-chromium": { "version": "1.4.284", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", - "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + "license": "ISC" }, "node_modules/emittery": { "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -8216,14 +8182,12 @@ }, "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==" + "license": "MIT" }, "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, + "license": "MIT", "engines": { "node": ">= 4" } @@ -8262,17 +8226,15 @@ }, "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, + "license": "MIT", "dependencies": { "once": "^1.4.0" } }, "node_modules/engine.io-client": { "version": "6.2.3", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.3.tgz", - "integrity": "sha512-aXPtgF1JS3RuuKcpSrBtimSjYvrbhKW9froICH4s0F3XQWLxsKNxqzG39nnvQZQnva4CMvUK63T7shevxRyYHw==", + "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1", @@ -8283,17 +8245,15 @@ }, "node_modules/engine.io-parser": { "version": "5.0.4", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", - "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", + "license": "MIT", "engines": { "node": ">=10.0.0" } }, "node_modules/enhanced-resolve": { "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -8304,9 +8264,8 @@ }, "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==", "dev": true, + "license": "MIT", "dependencies": { "ansi-colors": "^4.1.1" }, @@ -8316,9 +8275,8 @@ }, "node_modules/entities": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "dev": true, + "license": "BSD-2-Clause", "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } @@ -8340,9 +8298,8 @@ }, "node_modules/errno": { "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "prr": "~1.0.1" @@ -8353,18 +8310,16 @@ }, "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, + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, "node_modules/es-abstract": { "version": "1.20.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.5.tgz", - "integrity": "sha512-7h8MM2EQhsCA7pU/Nv78qOXFpD8Rhqd12gYiSJVkrH9+e8VuA8JlPJK/hQjjlLv6pJvx/z1iRFKzYb0XT/RuAQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", @@ -8401,9 +8356,8 @@ }, "node_modules/es-get-iterator": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", - "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.0", @@ -8420,24 +8374,21 @@ }, "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 + "dev": true, + "license": "MIT" }, "node_modules/es-shim-unscopables": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", "dev": true, + "license": "MIT", "dependencies": { "has": "^1.0.3" } }, "node_modules/es-to-primitive": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, + "license": "MIT", "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -8451,379 +8402,58 @@ } }, "node_modules/esbuild": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.13.tgz", - "integrity": "sha512-Cu3SC84oyzzhrK/YyN4iEVy2jZu5t2fz66HEOShHURcjSkOSAVL8C/gfUT+lDJxkVHpg8GZ10DD0rMHRPqMFaQ==", + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz", + "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==", "dev": true, "hasInstallScript": true, "optional": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.15.13", - "@esbuild/linux-loong64": "0.15.13", - "esbuild-android-64": "0.15.13", - "esbuild-android-arm64": "0.15.13", - "esbuild-darwin-64": "0.15.13", - "esbuild-darwin-arm64": "0.15.13", - "esbuild-freebsd-64": "0.15.13", - "esbuild-freebsd-arm64": "0.15.13", - "esbuild-linux-32": "0.15.13", - "esbuild-linux-64": "0.15.13", - "esbuild-linux-arm": "0.15.13", - "esbuild-linux-arm64": "0.15.13", - "esbuild-linux-mips64le": "0.15.13", - "esbuild-linux-ppc64le": "0.15.13", - "esbuild-linux-riscv64": "0.15.13", - "esbuild-linux-s390x": "0.15.13", - "esbuild-netbsd-64": "0.15.13", - "esbuild-openbsd-64": "0.15.13", - "esbuild-sunos-64": "0.15.13", - "esbuild-windows-32": "0.15.13", - "esbuild-windows-64": "0.15.13", - "esbuild-windows-arm64": "0.15.13" - } - }, - "node_modules/esbuild-android-64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.13.tgz", - "integrity": "sha512-yRorukXBlokwTip+Sy4MYskLhJsO0Kn0/Fj43s1krVblfwP+hMD37a4Wmg139GEsMLl+vh8WXp2mq/cTA9J97g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.13.tgz", - "integrity": "sha512-TKzyymLD6PiVeyYa4c5wdPw87BeAiTXNtK6amWUcXZxkV51gOk5u5qzmDaYSwiWeecSNHamFsaFjLoi32QR5/w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.13.tgz", - "integrity": "sha512-WAx7c2DaOS6CrRcoYCgXgkXDliLnFv3pQLV6GeW1YcGEZq2Gnl8s9Pg7ahValZkpOa0iE/ojRVQ87sbUhF1Cbg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.13.tgz", - "integrity": "sha512-U6jFsPfSSxC3V1CLiQqwvDuj3GGrtQNB3P3nNC3+q99EKf94UGpsG9l4CQ83zBs1NHrk1rtCSYT0+KfK5LsD8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.13.tgz", - "integrity": "sha512-whItJgDiOXaDG/idy75qqevIpZjnReZkMGCgQaBWZuKHoElDJC1rh7MpoUgupMcdfOd+PgdEwNQW9DAE6i8wyA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.13.tgz", - "integrity": "sha512-6pCSWt8mLUbPtygv7cufV0sZLeylaMwS5Fznj6Rsx9G2AJJsAjQ9ifA+0rQEIg7DwJmi9it+WjzNTEAzzdoM3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-32": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.13.tgz", - "integrity": "sha512-VbZdWOEdrJiYApm2kkxoTOgsoCO1krBZ3quHdYk3g3ivWaMwNIVPIfEE0f0XQQ0u5pJtBsnk2/7OPiCFIPOe/w==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.13.tgz", - "integrity": "sha512-rXmnArVNio6yANSqDQlIO4WiP+Cv7+9EuAHNnag7rByAqFVuRusLbGi2697A5dFPNXoO//IiogVwi3AdcfPC6A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.13.tgz", - "integrity": "sha512-Ac6LpfmJO8WhCMQmO253xX2IU2B3wPDbl4IvR0hnqcPrdfCaUa2j/lLMGTjmQ4W5JsJIdHEdW12dG8lFS0MbxQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.13.tgz", - "integrity": "sha512-alEMGU4Z+d17U7KQQw2IV8tQycO6T+rOrgW8OS22Ua25x6kHxoG6Ngry6Aq6uranC+pNWNMB6aHFPh7aTQdORQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.13.tgz", - "integrity": "sha512-47PgmyYEu+yN5rD/MbwS6DxP2FSGPo4Uxg5LwIdxTiyGC2XKwHhHyW7YYEDlSuXLQXEdTO7mYe8zQ74czP7W8A==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.13.tgz", - "integrity": "sha512-z6n28h2+PC1Ayle9DjKoBRcx/4cxHoOa2e689e2aDJSaKug3jXcQw7mM+GLg+9ydYoNzj8QxNL8ihOv/OnezhA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-riscv64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.13.tgz", - "integrity": "sha512-+Lu4zuuXuQhgLUGyZloWCqTslcCAjMZH1k3Xc9MSEJEpEFdpsSU0sRDXAnk18FKOfEjhu4YMGaykx9xjtpA6ow==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-s390x": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.13.tgz", - "integrity": "sha512-BMeXRljruf7J0TMxD5CIXS65y7puiZkAh+s4XFV9qy16SxOuMhxhVIXYLnbdfLrsYGFzx7U9mcdpFWkkvy/Uag==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.13.tgz", - "integrity": "sha512-EHj9QZOTel581JPj7UO3xYbltFTYnHy+SIqJVq6yd3KkCrsHRbapiPb0Lx3EOOtybBEE9EyqbmfW1NlSDsSzvQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.13.tgz", - "integrity": "sha512-nkuDlIjF/sfUhfx8SKq0+U+Fgx5K9JcPq1mUodnxI0x4kBdCv46rOGWbuJ6eof2n3wdoCLccOoJAbg9ba/bT2w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-sunos-64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.13.tgz", - "integrity": "sha512-jVeu2GfxZQ++6lRdY43CS0Tm/r4WuQQ0Pdsrxbw+aOrHQPHV0+LNOLnvbN28M7BSUGnJnHkHm2HozGgNGyeIRw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-wasm": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.15.13.tgz", - "integrity": "sha512-0am8fvHKACwofWQxtZLTMv4mDiDwUrdt0DyRaQ2r7YWIpkmpg4GWYy0EyW+gPjiPHzkZKqN9d3UYsZGgvaAASw==", - "dev": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-32": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.13.tgz", - "integrity": "sha512-XoF2iBf0wnqo16SDq+aDGi/+QbaLFpkiRarPVssMh9KYbFNCqPLlGAWwDvxEVz+ywX6Si37J2AKm+AXq1kC0JA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.13.tgz", - "integrity": "sha512-Et6htEfGycjDrtqb2ng6nT+baesZPYQIW+HUEHK4D1ncggNrDNk3yoboYQ5KtiVrw/JaDMNttz8rrPubV/fvPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], + "bin": { + "esbuild": "bin/esbuild" + }, "engines": { "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.16.17", + "@esbuild/android-arm64": "0.16.17", + "@esbuild/android-x64": "0.16.17", + "@esbuild/darwin-arm64": "0.16.17", + "@esbuild/darwin-x64": "0.16.17", + "@esbuild/freebsd-arm64": "0.16.17", + "@esbuild/freebsd-x64": "0.16.17", + "@esbuild/linux-arm": "0.16.17", + "@esbuild/linux-arm64": "0.16.17", + "@esbuild/linux-ia32": "0.16.17", + "@esbuild/linux-loong64": "0.16.17", + "@esbuild/linux-mips64el": "0.16.17", + "@esbuild/linux-ppc64": "0.16.17", + "@esbuild/linux-riscv64": "0.16.17", + "@esbuild/linux-s390x": "0.16.17", + "@esbuild/linux-x64": "0.16.17", + "@esbuild/netbsd-x64": "0.16.17", + "@esbuild/openbsd-x64": "0.16.17", + "@esbuild/sunos-x64": "0.16.17", + "@esbuild/win32-arm64": "0.16.17", + "@esbuild/win32-ia32": "0.16.17", + "@esbuild/win32-x64": "0.16.17" } }, - "node_modules/esbuild-windows-arm64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.13.tgz", - "integrity": "sha512-3bv7tqntThQC9SWLRouMDmZnlOukBhOCTlkzNqzGCmrkCJI7io5LLjwJBOVY6kOUlIvdxbooNZwjtBvj+7uuVg==", - "cpu": [ - "arm64" - ], + "node_modules/esbuild-wasm": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.16.17.tgz", + "integrity": "sha512-Tn7NuMqRcM+T/qCOxbQRq0qrwWl1sUWp6ARfJRakE8Bepew6zata4qrKgH2YqovNC5e/2fcTa7o+VL/FAOZC1Q==", "dev": true, - "optional": true, - "os": [ - "win32" - ], + "bin": { + "esbuild": "bin/esbuild" + }, "engines": { "node": ">=12" } }, "node_modules/escalade": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "license": "MIT", "engines": { "node": ">=6" } @@ -8836,19 +8466,18 @@ }, "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": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/eslint": { - "version": "8.30.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.30.0.tgz", - "integrity": "sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ==", + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", + "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.4.0", + "@eslint/eslintrc": "^1.4.1", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -8899,9 +8528,9 @@ } }, "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==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", + "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -8912,9 +8541,8 @@ }, "node_modules/eslint-etc": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-etc/-/eslint-etc-5.2.0.tgz", - "integrity": "sha512-Gcm/NMa349FOXb1PEEfNMMyIANuorIc2/mI5Vfu1zENNsz+FBVhF62uY6gPUCigm/xDOc8JOnl+71WGnlzlDag==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/experimental-utils": "^5.0.0", "tsutils": "^3.17.1", @@ -8926,13 +8554,14 @@ } }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, "dependencies": { "debug": "^3.2.7", - "resolve": "^1.20.0" + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { @@ -8946,9 +8575,8 @@ }, "node_modules/eslint-module-utils": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", - "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.2.7" }, @@ -8963,31 +8591,32 @@ }, "node_modules/eslint-module-utils/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "version": "2.27.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.4.tgz", + "integrity": "sha512-Z1jVt1EGKia1X9CnBCkpAOhWy8FgQ7OmJ/IblEkT82yrFU/xJaxwujaTzLWqigewwynRQ9mmHfX9MtAfhxm0sA==", "dev": true, "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.0", + "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", "has": "^1.0.3", - "is-core-module": "^2.8.1", + "is-core-module": "^2.11.0", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", "tsconfig-paths": "^3.14.1" }, "engines": { @@ -8998,19 +8627,18 @@ } }, "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "node_modules/eslint-plugin-import/node_modules/doctrine": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -9018,17 +8646,19 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } }, "node_modules/eslint-plugin-rxjs": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-rxjs/-/eslint-plugin-rxjs-5.0.2.tgz", - "integrity": "sha512-Q2wsEHWInhZ3uz5df+YbD4g/NPQqAeYHjJuEsxqgVS+XAsYCuVE2pj9kADdMFy4GsQy2jt7KP+TOrnq1i6bI5Q==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/experimental-utils": "^5.0.0", "common-tags": "^1.8.0", @@ -9047,9 +8677,8 @@ }, "node_modules/eslint-plugin-rxjs-angular": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-rxjs-angular/-/eslint-plugin-rxjs-angular-2.0.0.tgz", - "integrity": "sha512-MalcYcEHOK2NT+avWSI1PsUilwGx6cprMQdw9jJRlCTkIvsUvCGFD1eTqQKVImwkK8+te732v9VsP/XcXlKZqA==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/experimental-utils": "^5.0.0", "common-tags": "^1.8.0", @@ -9064,9 +8693,8 @@ }, "node_modules/eslint-plugin-unicorn": { "version": "45.0.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-45.0.2.tgz", - "integrity": "sha512-Y0WUDXRyGDMcKLiwgL3zSMpHrXI00xmdyixEGIg90gHnj0PcHY4moNv3Ppje/kDivdAy5vUeUr7z211ImPv2gw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.19.1", "@eslint-community/eslint-utils": "^4.1.2", @@ -9097,9 +8725,8 @@ }, "node_modules/eslint-plugin-unicorn/node_modules/jsesc": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -9109,9 +8736,8 @@ }, "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, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -9122,9 +8748,8 @@ }, "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, + "license": "MIT", "dependencies": { "eslint-visitor-keys": "^2.0.0" }, @@ -9140,27 +8765,24 @@ }, "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, + "license": "Apache-2.0", "engines": { "node": ">=10" } }, "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, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/eslint/node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -9174,9 +8796,8 @@ }, "node_modules/eslint/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -9189,15 +8810,13 @@ }, "node_modules/eslint/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 + "dev": true, + "license": "Python-2.0" }, "node_modules/eslint/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -9211,9 +8830,8 @@ }, "node_modules/eslint/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -9223,15 +8841,13 @@ }, "node_modules/eslint/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/eslint/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, + "license": "MIT", "engines": { "node": ">=10" }, @@ -9241,9 +8857,8 @@ }, "node_modules/eslint/node_modules/find-up": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -9257,9 +8872,8 @@ }, "node_modules/eslint/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, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -9269,9 +8883,8 @@ }, "node_modules/eslint/node_modules/globals": { "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -9284,18 +8897,16 @@ }, "node_modules/eslint/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/eslint/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, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -9305,15 +8916,13 @@ }, "node_modules/eslint/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 + "dev": true, + "license": "MIT" }, "node_modules/eslint/node_modules/locate-path": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -9326,9 +8935,8 @@ }, "node_modules/eslint/node_modules/p-locate": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -9341,9 +8949,8 @@ }, "node_modules/eslint/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -9353,9 +8960,8 @@ }, "node_modules/eslint/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, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -9382,9 +8988,8 @@ }, "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, + "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -9395,9 +9000,8 @@ }, "node_modules/esquery": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -9407,9 +9011,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==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -9419,18 +9022,16 @@ }, "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, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/esutils": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -9446,15 +9047,13 @@ }, "node_modules/eventemitter-asyncresource": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", - "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/eventemitter2": { "version": "6.4.9", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", - "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/eventemitter3": { "version": "4.0.7", @@ -9464,18 +9063,16 @@ }, "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, + "license": "MIT", "engines": { "node": ">=0.8.x" } }, "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, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.0", "get-stream": "^5.0.0", @@ -9496,9 +9093,8 @@ }, "node_modules/executable": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", "dev": true, + "license": "MIT", "dependencies": { "pify": "^2.2.0" }, @@ -9508,8 +9104,6 @@ }, "node_modules/exit": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true, "engines": { "node": ">= 0.8.0" @@ -9517,9 +9111,8 @@ }, "node_modules/expect": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/expect-utils": "^29.3.1", "jest-get-type": "^29.2.0", @@ -9620,15 +9213,13 @@ }, "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 + "dev": true, + "license": "MIT" }, "node_modules/external-editor": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", "dev": true, + "license": "MIT", "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", @@ -9640,9 +9231,8 @@ }, "node_modules/external-editor/node_modules/tmp": { "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, + "license": "MIT", "dependencies": { "os-tmpdir": "~1.0.2" }, @@ -9652,9 +9242,8 @@ }, "node_modules/extract-zip": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", @@ -9672,24 +9261,21 @@ }, "node_modules/extsprintf": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true, "engines": [ "node >=0.6.0" - ] + ], + "license": "MIT" }, "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 + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -9703,21 +9289,18 @@ }, "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 + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fastq": { "version": "1.14.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", - "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } @@ -9736,27 +9319,24 @@ }, "node_modules/fb-watchman": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "bser": "2.1.1" } }, "node_modules/fd-slicer": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, + "license": "MIT", "dependencies": { "pend": "~1.2.0" } }, "node_modules/figures": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, + "license": "MIT", "dependencies": { "escape-string-regexp": "^1.0.5" }, @@ -9769,9 +9349,8 @@ }, "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, + "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -9781,8 +9360,7 @@ }, "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==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -9842,9 +9420,8 @@ }, "node_modules/find-up": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -9855,9 +9432,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==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.1.0", "rimraf": "^3.0.2" @@ -9868,9 +9444,8 @@ }, "node_modules/flatted": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/follow-redirects": { "version": "1.15.2", @@ -9894,27 +9469,24 @@ }, "node_modules/for-each": { "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "dev": true, + "license": "MIT", "dependencies": { "is-callable": "^1.1.3" } }, "node_modules/forever-agent": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "*" } }, "node_modules/form-data": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dev": true, + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -9935,9 +9507,8 @@ }, "node_modules/fraction.js": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", "dev": true, + "license": "MIT", "engines": { "node": "*" }, @@ -9957,9 +9528,8 @@ }, "node_modules/fs-extra": { "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, + "license": "MIT", "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -9971,15 +9541,15 @@ } }, "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.0.tgz", + "integrity": "sha512-EUojgQaSPy6sxcqcZgQv6TVF6jiKvurji3AxhAivs/Ep4O1UpS8TusaxpybfFHZ2skRhLqzk6WR8nqNYIMMDeA==", "dev": true, "dependencies": { - "minipass": "^3.0.0" + "minipass": "^4.0.0" }, "engines": { - "node": ">= 8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/fs-monkey": { @@ -9990,33 +9560,17 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } + "license": "ISC" }, "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 + "dev": true, + "license": "MIT" }, "node_modules/function.prototype.name": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -10032,9 +9586,8 @@ }, "node_modules/functions-have-names": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -10060,16 +9613,14 @@ }, "node_modules/gensync": { "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/geotiff": { "version": "2.0.7", - "resolved": "https://registry.npmjs.org/geotiff/-/geotiff-2.0.7.tgz", - "integrity": "sha512-FKvFTNowMU5K6lHYY2f83d4lS2rsCNdpUC28AX61x9ZzzqPNaWFElWv93xj0eJFaNyOYA63ic5OzJ88dHpoA5Q==", + "license": "MIT", "dependencies": { "@petamoriken/float16": "^3.4.7", "lerc": "^3.0.0", @@ -10085,17 +9636,15 @@ }, "node_modules/get-caller-file": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-intrinsic": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -10107,18 +9656,16 @@ }, "node_modules/get-package-type": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.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==", "dev": true, + "license": "MIT", "dependencies": { "pump": "^3.0.0" }, @@ -10131,9 +9678,8 @@ }, "node_modules/get-symbol-description": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -10147,26 +9693,23 @@ }, "node_modules/getos": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", - "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", "dev": true, + "license": "MIT", "dependencies": { "async": "^3.2.0" } }, "node_modules/getpass": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0" } }, "node_modules/glob": { "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -10183,8 +9726,7 @@ }, "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==", + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -10194,22 +9736,19 @@ }, "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 + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/glob/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/glob/node_modules/minimatch": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", - "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -10219,9 +9758,8 @@ }, "node_modules/global-dirs": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", - "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", "dev": true, + "license": "MIT", "dependencies": { "ini": "2.0.0" }, @@ -10234,26 +9772,23 @@ }, "node_modules/global-dirs/node_modules/ini": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/globals": { "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/globby": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -10271,9 +9806,8 @@ }, "node_modules/gopd": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -10283,15 +9817,13 @@ }, "node_modules/graceful-fs": { "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/grapheme-splitter": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/handle-thing": { "version": "2.0.1", @@ -10301,9 +9833,8 @@ }, "node_modules/handlebars": { "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.0", @@ -10322,18 +9853,16 @@ }, "node_modules/handlebars/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, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/has": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.1" }, @@ -10343,26 +9872,23 @@ }, "node_modules/has-bigints": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-flag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/has-property-descriptors": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.1" }, @@ -10372,9 +9898,8 @@ }, "node_modules/has-symbols": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -10384,9 +9909,8 @@ }, "node_modules/has-tostringtag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.2" }, @@ -10405,9 +9929,8 @@ }, "node_modules/hdr-histogram-js": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", - "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", "dev": true, + "license": "BSD", "dependencies": { "@assemblyscript/loader": "^0.10.1", "base64-js": "^1.2.0", @@ -10416,26 +9939,24 @@ }, "node_modules/hdr-histogram-js/node_modules/pako": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true + "dev": true, + "license": "(MIT AND Zlib)" }, "node_modules/hdr-histogram-percentiles-obj": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", - "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hosted-git-info": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", - "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/hpack.js": { @@ -10494,14 +10015,13 @@ }, "node_modules/html-escaper": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "node_modules/http-deceiver": { @@ -10595,9 +10115,8 @@ }, "node_modules/http-signature": { "version": "1.3.6", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", - "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0", "jsprim": "^2.0.2", @@ -10609,9 +10128,8 @@ }, "node_modules/https-proxy-agent": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, + "license": "MIT", "dependencies": { "agent-base": "6", "debug": "4" @@ -10622,18 +10140,16 @@ }, "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, + "license": "Apache-2.0", "engines": { "node": ">=8.12.0" } }, "node_modules/humanize-duration": { "version": "3.27.3", - "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.27.3.tgz", - "integrity": "sha512-iimHkHPfIAQ8zCDQLgn08pRqSVioyWvnGfaQ8gond2wf7Jq2jJ+24ykmnRyiz3fIldcn4oUuQXpjqKLhSVR7lw==", - "dev": true + "dev": true, + "license": "Unlicense" }, "node_modules/humanize-ms": { "version": "1.2.1", @@ -10646,9 +10162,8 @@ }, "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, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -10658,9 +10173,8 @@ }, "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, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -10670,8 +10184,6 @@ }, "node_modules/ieee754": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "funding": [ { "type": "github", @@ -10685,13 +10197,13 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "BSD-3-Clause" }, "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, + "license": "MIT", "engines": { "node": ">= 4" } @@ -10718,9 +10230,9 @@ } }, "node_modules/ignore-walk/node_modules/minimatch": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", - "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -10731,9 +10243,8 @@ }, "node_modules/image-size": { "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", "dev": true, + "license": "MIT", "optional": true, "bin": { "image-size": "bin/image-size.js" @@ -10743,9 +10254,9 @@ } }, "node_modules/immer": { - "version": "9.0.16", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz", - "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==", + "version": "9.0.17", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.17.tgz", + "integrity": "sha512-+hBruaLSQvkPfxRiTLK/mi4vLH+/VQS6z2KJahdoxlleFOI8ARqzOF17uy12eFDlqWmPoygwc5evgwcp+dlHhg==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -10753,9 +10264,8 @@ }, "node_modules/immutable": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", - "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/import-fresh": { "version": "3.3.0", @@ -10784,9 +10294,8 @@ }, "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, + "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -10803,18 +10312,16 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "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, + "license": "MIT", "engines": { "node": ">=8" } @@ -10827,8 +10334,7 @@ }, "node_modules/inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -10836,23 +10342,20 @@ }, "node_modules/inherits": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "license": "ISC" }, "node_modules/ini": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", - "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", "dev": true, + "license": "ISC", "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/inquirer": { "version": "8.2.4", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", - "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -10876,9 +10379,8 @@ }, "node_modules/inquirer/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -10891,9 +10393,8 @@ }, "node_modules/inquirer/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -10907,9 +10408,8 @@ }, "node_modules/inquirer/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -10919,24 +10419,21 @@ }, "node_modules/inquirer/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/inquirer/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/inquirer/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -10946,9 +10443,8 @@ }, "node_modules/internal-slot": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", - "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3", "has": "^1.0.3", @@ -10975,9 +10471,8 @@ }, "node_modules/is-arguments": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -10991,15 +10486,13 @@ }, "node_modules/is-arrayish": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-bigint": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dev": true, + "license": "MIT", "dependencies": { "has-bigints": "^1.0.1" }, @@ -11009,8 +10502,7 @@ }, "node_modules/is-binary-path": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -11020,9 +10512,8 @@ }, "node_modules/is-boolean-object": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -11036,9 +10527,8 @@ }, "node_modules/is-builtin-module": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", - "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", "dev": true, + "license": "MIT", "dependencies": { "builtin-modules": "^3.3.0" }, @@ -11051,9 +10541,8 @@ }, "node_modules/is-callable": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -11063,9 +10552,8 @@ }, "node_modules/is-ci": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", "dev": true, + "license": "MIT", "dependencies": { "ci-info": "^3.2.0" }, @@ -11075,9 +10563,8 @@ }, "node_modules/is-core-module": { "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, + "license": "MIT", "dependencies": { "has": "^1.0.3" }, @@ -11087,9 +10574,8 @@ }, "node_modules/is-date-object": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -11102,9 +10588,8 @@ }, "node_modules/is-docker": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, + "license": "MIT", "bin": { "is-docker": "cli.js" }, @@ -11117,33 +10602,29 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", "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==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/is-generator-fn": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "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==", + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -11153,9 +10634,8 @@ }, "node_modules/is-installed-globally": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", "dev": true, + "license": "MIT", "dependencies": { "global-dirs": "^3.0.0", "is-path-inside": "^3.0.2" @@ -11169,9 +10649,8 @@ }, "node_modules/is-interactive": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -11184,18 +10663,16 @@ }, "node_modules/is-map": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-negative-zero": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -11205,17 +10682,15 @@ }, "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==", + "license": "MIT", "engines": { "node": ">=0.12.0" } }, "node_modules/is-number-object": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -11228,9 +10703,8 @@ }, "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, + "license": "MIT", "engines": { "node": ">=8" } @@ -11249,9 +10723,8 @@ }, "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, + "license": "MIT", "dependencies": { "isobject": "^3.0.1" }, @@ -11261,9 +10734,8 @@ }, "node_modules/is-regex": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -11277,18 +10749,16 @@ }, "node_modules/is-set": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-shared-array-buffer": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2" }, @@ -11298,9 +10768,8 @@ }, "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, + "license": "MIT", "engines": { "node": ">=8" }, @@ -11310,9 +10779,8 @@ }, "node_modules/is-string": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -11325,9 +10793,8 @@ }, "node_modules/is-symbol": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.2" }, @@ -11340,9 +10807,8 @@ }, "node_modules/is-typed-array": { "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", @@ -11359,15 +10825,13 @@ }, "node_modules/is-typedarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-unicode-supported": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -11377,18 +10841,16 @@ }, "node_modules/is-weakmap": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-weakref": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2" }, @@ -11398,9 +10860,8 @@ }, "node_modules/is-weakset": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -11411,15 +10872,13 @@ }, "node_modules/is-what": { "version": "3.14.1", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-wsl": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, + "license": "MIT", "dependencies": { "is-docker": "^2.0.0" }, @@ -11429,45 +10888,39 @@ }, "node_modules/isarray": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/isobject": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/isstream": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-instrument": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -11481,18 +10934,16 @@ }, "node_modules/istanbul-lib-instrument/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/istanbul-lib-report": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^3.0.0", @@ -11504,18 +10955,16 @@ }, "node_modules/istanbul-lib-report/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-report/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -11525,9 +10974,8 @@ }, "node_modules/istanbul-lib-source-maps": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", @@ -11539,18 +10987,16 @@ }, "node_modules/istanbul-lib-source-maps/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, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/istanbul-reports": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -11561,9 +11007,8 @@ }, "node_modules/jest": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.3.1.tgz", - "integrity": "sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/core": "^29.3.1", "@jest/types": "^29.3.1", @@ -11587,9 +11032,8 @@ }, "node_modules/jest-changed-files": { "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.2.0.tgz", - "integrity": "sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==", "dev": true, + "license": "MIT", "dependencies": { "execa": "^5.0.0", "p-limit": "^3.1.0" @@ -11600,9 +11044,8 @@ }, "node_modules/jest-changed-files/node_modules/execa": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -11623,9 +11066,8 @@ }, "node_modules/jest-changed-files/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, + "license": "MIT", "engines": { "node": ">=10" }, @@ -11635,18 +11077,16 @@ }, "node_modules/jest-changed-files/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, + "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } }, "node_modules/jest-circus": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.3.1.tgz", - "integrity": "sha512-wpr26sEvwb3qQQbdlmei+gzp6yoSSoSL6GsLPxnuayZSMrSd5Ka7IjAvatpIernBvT2+Ic6RLTg+jSebScmasg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.3.1", "@jest/expect": "^29.3.1", @@ -11674,9 +11114,8 @@ }, "node_modules/jest-circus/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -11689,9 +11128,8 @@ }, "node_modules/jest-circus/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -11705,9 +11143,8 @@ }, "node_modules/jest-circus/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -11717,24 +11154,21 @@ }, "node_modules/jest-circus/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-circus/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-circus/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -11744,9 +11178,8 @@ }, "node_modules/jest-cli": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.3.1.tgz", - "integrity": "sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/core": "^29.3.1", "@jest/test-result": "^29.3.1", @@ -11778,9 +11211,8 @@ }, "node_modules/jest-cli/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -11793,9 +11225,8 @@ }, "node_modules/jest-cli/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -11809,9 +11240,8 @@ }, "node_modules/jest-cli/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -11821,24 +11251,21 @@ }, "node_modules/jest-cli/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-cli/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-cli/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -11848,9 +11275,8 @@ }, "node_modules/jest-config": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.3.1.tgz", - "integrity": "sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/test-sequencer": "^29.3.1", @@ -11893,9 +11319,8 @@ }, "node_modules/jest-config/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -11908,9 +11333,8 @@ }, "node_modules/jest-config/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -11924,9 +11348,8 @@ }, "node_modules/jest-config/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -11936,15 +11359,13 @@ }, "node_modules/jest-config/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-config/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -11962,18 +11383,16 @@ }, "node_modules/jest-config/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-config/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -11983,9 +11402,8 @@ }, "node_modules/jest-diff": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", - "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.3.1", @@ -11998,9 +11416,8 @@ }, "node_modules/jest-diff/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12013,9 +11430,8 @@ }, "node_modules/jest-diff/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12029,9 +11445,8 @@ }, "node_modules/jest-diff/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12041,24 +11456,21 @@ }, "node_modules/jest-diff/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-diff/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-diff/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12068,9 +11480,8 @@ }, "node_modules/jest-docblock": { "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.2.0.tgz", - "integrity": "sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A==", "dev": true, + "license": "MIT", "dependencies": { "detect-newline": "^3.0.0" }, @@ -12080,9 +11491,8 @@ }, "node_modules/jest-each": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.3.1.tgz", - "integrity": "sha512-qrZH7PmFB9rEzCSl00BWjZYuS1BSOH8lLuC0azQE9lQrAx3PWGKHTDudQiOSwIy5dGAJh7KA0ScYlCP7JxvFYA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.3.1", "chalk": "^4.0.0", @@ -12096,9 +11506,8 @@ }, "node_modules/jest-each/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12111,9 +11520,8 @@ }, "node_modules/jest-each/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12127,9 +11535,8 @@ }, "node_modules/jest-each/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12139,24 +11546,21 @@ }, "node_modules/jest-each/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-each/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-each/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12166,9 +11570,8 @@ }, "node_modules/jest-environment-node": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.3.1.tgz", - "integrity": "sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.3.1", "@jest/fake-timers": "^29.3.1", @@ -12183,18 +11586,16 @@ }, "node_modules/jest-get-type": { "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", - "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-haste-map": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.3.1.tgz", - "integrity": "sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.3.1", "@types/graceful-fs": "^4.1.3", @@ -12217,9 +11618,8 @@ }, "node_modules/jest-leak-detector": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.3.1.tgz", - "integrity": "sha512-3DA/VVXj4zFOPagGkuqHnSQf1GZBmmlagpguxEERO6Pla2g84Q1MaVIB3YMxgUaFIaYag8ZnTyQgiZ35YEqAQA==", "dev": true, + "license": "MIT", "dependencies": { "jest-get-type": "^29.2.0", "pretty-format": "^29.3.1" @@ -12230,9 +11630,8 @@ }, "node_modules/jest-matcher-utils": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz", - "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "jest-diff": "^29.3.1", @@ -12245,9 +11644,8 @@ }, "node_modules/jest-matcher-utils/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12260,9 +11658,8 @@ }, "node_modules/jest-matcher-utils/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12276,9 +11673,8 @@ }, "node_modules/jest-matcher-utils/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12288,24 +11684,21 @@ }, "node_modules/jest-matcher-utils/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-matcher-utils/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-matcher-utils/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12315,9 +11708,8 @@ }, "node_modules/jest-message-util": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", - "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.3.1", @@ -12335,9 +11727,8 @@ }, "node_modules/jest-message-util/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12350,9 +11741,8 @@ }, "node_modules/jest-message-util/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12366,9 +11756,8 @@ }, "node_modules/jest-message-util/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12378,24 +11767,21 @@ }, "node_modules/jest-message-util/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-message-util/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-message-util/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12405,9 +11791,8 @@ }, "node_modules/jest-mock": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.3.1.tgz", - "integrity": "sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.3.1", "@types/node": "*", @@ -12419,9 +11804,8 @@ }, "node_modules/jest-pnp-resolver": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -12436,18 +11820,16 @@ }, "node_modules/jest-regex-util": { "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz", - "integrity": "sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-resolve": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.3.1.tgz", - "integrity": "sha512-amXJgH/Ng712w3Uz5gqzFBBjxV8WFLSmNjoreBGMqxgCz5cH7swmBZzgBaCIOsvb0NbpJ0vgaSFdJqMdT+rADw==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", @@ -12465,9 +11847,8 @@ }, "node_modules/jest-resolve-dependencies": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.3.1.tgz", - "integrity": "sha512-Vk0cYq0byRw2WluNmNWGqPeRnZ3p3hHmjJMp2dyyZeYIfiBskwq4rpiuGFR6QGAdbj58WC7HN4hQHjf2mpvrLA==", "dev": true, + "license": "MIT", "dependencies": { "jest-regex-util": "^29.2.0", "jest-snapshot": "^29.3.1" @@ -12478,9 +11859,8 @@ }, "node_modules/jest-resolve/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12493,9 +11873,8 @@ }, "node_modules/jest-resolve/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12509,9 +11888,8 @@ }, "node_modules/jest-resolve/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12521,24 +11899,21 @@ }, "node_modules/jest-resolve/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-resolve/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-resolve/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12548,9 +11923,8 @@ }, "node_modules/jest-runner": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.3.1.tgz", - "integrity": "sha512-oFvcwRNrKMtE6u9+AQPMATxFcTySyKfLhvso7Sdk/rNpbhg4g2GAGCopiInk1OP4q6gz3n6MajW4+fnHWlU3bA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.3.1", "@jest/environment": "^29.3.1", @@ -12580,9 +11954,8 @@ }, "node_modules/jest-runner/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12595,9 +11968,8 @@ }, "node_modules/jest-runner/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12611,9 +11983,8 @@ }, "node_modules/jest-runner/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12623,33 +11994,29 @@ }, "node_modules/jest-runner/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-runner/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-runner/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, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/jest-runner/node_modules/source-map-support": { "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -12657,9 +12024,8 @@ }, "node_modules/jest-runner/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12669,9 +12035,8 @@ }, "node_modules/jest-runtime": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.3.1.tgz", - "integrity": "sha512-jLzkIxIqXwBEOZx7wx9OO9sxoZmgT2NhmQKzHQm1xwR1kNW/dn0OjxR424VwHHf1SPN6Qwlb5pp1oGCeFTQ62A==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.3.1", "@jest/fake-timers": "^29.3.1", @@ -12702,9 +12067,8 @@ }, "node_modules/jest-runtime/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12717,9 +12081,8 @@ }, "node_modules/jest-runtime/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12733,9 +12096,8 @@ }, "node_modules/jest-runtime/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12745,15 +12107,13 @@ }, "node_modules/jest-runtime/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-runtime/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -12771,18 +12131,16 @@ }, "node_modules/jest-runtime/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-runtime/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12792,9 +12150,8 @@ }, "node_modules/jest-snapshot": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.3.1.tgz", - "integrity": "sha512-+3JOc+s28upYLI2OJM4PWRGK9AgpsMs/ekNryUV0yMBClT9B1DF2u2qay8YxcQd338PPYSFNb0lsar1B49sLDA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", @@ -12827,9 +12184,8 @@ }, "node_modules/jest-snapshot/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12842,9 +12198,8 @@ }, "node_modules/jest-snapshot/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12858,9 +12213,8 @@ }, "node_modules/jest-snapshot/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12870,24 +12224,21 @@ }, "node_modules/jest-snapshot/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-snapshot/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-snapshot/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12897,9 +12248,8 @@ }, "node_modules/jest-util": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", - "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.3.1", "@types/node": "*", @@ -12914,9 +12264,8 @@ }, "node_modules/jest-util/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12929,9 +12278,8 @@ }, "node_modules/jest-util/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12945,9 +12293,8 @@ }, "node_modules/jest-util/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12957,24 +12304,21 @@ }, "node_modules/jest-util/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-util/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-util/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12984,9 +12328,8 @@ }, "node_modules/jest-validate": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.3.1.tgz", - "integrity": "sha512-N9Lr3oYR2Mpzuelp1F8negJR3YE+L1ebk1rYA5qYo9TTY3f9OWdptLoNSPP9itOCBIRBqjt/S5XHlzYglLN67g==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.3.1", "camelcase": "^6.2.0", @@ -13001,9 +12344,8 @@ }, "node_modules/jest-validate/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -13016,9 +12358,8 @@ }, "node_modules/jest-validate/node_modules/camelcase": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -13028,9 +12369,8 @@ }, "node_modules/jest-validate/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -13044,9 +12384,8 @@ }, "node_modules/jest-validate/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -13056,24 +12395,21 @@ }, "node_modules/jest-validate/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-validate/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-validate/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -13083,9 +12419,8 @@ }, "node_modules/jest-watcher": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.3.1.tgz", - "integrity": "sha512-RspXG2BQFDsZSRKGCT/NiNa8RkQ1iKAjrO0//soTMWx/QUt+OcxMqMSBxz23PYGqUuWm2+m2mNNsmj0eIoOaFg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/test-result": "^29.3.1", "@jest/types": "^29.3.1", @@ -13102,9 +12437,8 @@ }, "node_modules/jest-watcher/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -13117,9 +12451,8 @@ }, "node_modules/jest-watcher/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -13133,9 +12466,8 @@ }, "node_modules/jest-watcher/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -13145,24 +12477,21 @@ }, "node_modules/jest-watcher/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-watcher/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-watcher/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -13172,9 +12501,8 @@ }, "node_modules/jest-worker": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz", - "integrity": "sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "jest-util": "^29.3.1", @@ -13187,18 +12515,16 @@ }, "node_modules/jest-worker/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -13211,9 +12537,8 @@ }, "node_modules/js-sdsl": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", - "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", "dev": true, + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/js-sdsl" @@ -13221,14 +12546,12 @@ }, "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==" + "license": "MIT" }, "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, + "license": "MIT", "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -13239,14 +12562,12 @@ }, "node_modules/jsbn": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jsesc": { "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -13256,43 +12577,37 @@ }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true + "dev": true, + "license": "(AFL-2.1 OR BSD-3-Clause)" }, "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 + "dev": true, + "license": "MIT" }, "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": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stringify-pretty-compact": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-2.0.0.tgz", - "integrity": "sha512-WRitRfs6BGq4q8gTgOy4ek7iPFXjbra0H3PmDLKm2xnZ+Gh1HUhiKGgCZkSPNULlP7mvfu6FV/mOLhCarspADQ==" + "license": "MIT" }, "node_modules/json-stringify-safe": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/json5": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz", - "integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -13302,15 +12617,13 @@ }, "node_modules/jsonc-parser": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jsonfile": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -13329,12 +12642,11 @@ }, "node_modules/jsprim": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", - "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", "dev": true, "engines": [ "node >=0.6.0" ], + "license": "MIT", "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -13344,59 +12656,52 @@ }, "node_modules/karma-source-map-support": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", - "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", "dev": true, + "license": "MIT", "dependencies": { "source-map-support": "^0.5.5" } }, "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, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/kleur": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/klona": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", - "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/lazy-ass": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", - "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", "dev": true, + "license": "MIT", "engines": { "node": "> 0.8" } }, "node_modules/lerc": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lerc/-/lerc-3.0.0.tgz", - "integrity": "sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww==" + "license": "Apache-2.0" }, "node_modules/less": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", - "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -13420,9 +12725,8 @@ }, "node_modules/less-loader": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz", - "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==", "dev": true, + "license": "MIT", "dependencies": { "klona": "^2.0.4" }, @@ -13440,9 +12744,8 @@ }, "node_modules/less/node_modules/make-dir": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "pify": "^4.0.1", @@ -13454,9 +12757,8 @@ }, "node_modules/less/node_modules/pify": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=6" @@ -13464,9 +12766,8 @@ }, "node_modules/less/node_modules/semver": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true, + "license": "ISC", "optional": true, "bin": { "semver": "bin/semver" @@ -13474,9 +12775,8 @@ }, "node_modules/less/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, + "license": "BSD-3-Clause", "optional": true, "engines": { "node": ">=0.10.0" @@ -13484,18 +12784,16 @@ }, "node_modules/leven": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "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, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -13506,14 +12804,12 @@ }, "node_modules/libphonenumber-js": { "version": "1.10.15", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.15.tgz", - "integrity": "sha512-sLeVLmWX17VCKKulc+aDIRHS95TxoTsKMRJi5s5gJdwlqNzMWcBCtSHHruVyXjqfi67daXM2SnLf2juSrdx5Sg==" + "license": "MIT" }, "node_modules/license-webpack-plugin": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", - "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", "dev": true, + "license": "ISC", "dependencies": { "webpack-sources": "^3.0.0" }, @@ -13528,15 +12824,13 @@ }, "node_modules/lines-and-columns": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/listr2": { "version": "3.14.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", - "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", "dev": true, + "license": "MIT", "dependencies": { "cli-truncate": "^2.1.0", "colorette": "^2.0.16", @@ -13561,27 +12855,24 @@ }, "node_modules/loader-runner": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.11.5" } }, "node_modules/loader-utils": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 12.13.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, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -13591,44 +12882,37 @@ }, "node_modules/lodash": { "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash-es": { "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + "license": "MIT" }, "node_modules/lodash.debounce": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.memoize": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true + "dev": true, + "license": "MIT" }, "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 + "dev": true, + "license": "MIT" }, "node_modules/lodash.once": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -13642,9 +12926,8 @@ }, "node_modules/log-symbols/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -13657,9 +12940,8 @@ }, "node_modules/log-symbols/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -13673,9 +12955,8 @@ }, "node_modules/log-symbols/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -13685,24 +12966,21 @@ }, "node_modules/log-symbols/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/log-symbols/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/log-symbols/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -13712,9 +12990,8 @@ }, "node_modules/log-update": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-escapes": "^4.3.0", "cli-cursor": "^3.1.0", @@ -13730,9 +13007,8 @@ }, "node_modules/log-update/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -13745,9 +13021,8 @@ }, "node_modules/log-update/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -13757,15 +13032,13 @@ }, "node_modules/log-update/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/log-update/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", @@ -13780,9 +13053,8 @@ }, "node_modules/log-update/node_modules/wrap-ansi": { "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -13802,12 +13074,11 @@ } }, "node_modules/magic-string": { - "version": "0.26.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", - "integrity": "sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==", - "dev": true, + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", "dependencies": { - "sourcemap-codec": "^1.4.8" + "@jridgewell/sourcemap-codec": "^1.4.13" }, "engines": { "node": ">=12" @@ -13815,9 +13086,8 @@ }, "node_modules/make-dir": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^6.0.0" }, @@ -13830,18 +13100,16 @@ }, "node_modules/make-dir/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/make-error": { "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/make-fetch-happen": { "version": "10.2.1", @@ -13889,27 +13157,51 @@ "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", "dev": true, "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/make-fetch-happen/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=8" } }, "node_modules/make-fetch-happen/node_modules/ssri": { @@ -13950,17 +13242,15 @@ }, "node_modules/makeerror": { "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" } }, "node_modules/mapbox-to-css-font": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/mapbox-to-css-font/-/mapbox-to-css-font-2.4.1.tgz", - "integrity": "sha512-QQ/iKiM43DM9+aujTL45Iz5o7gDeSFmy4LPl3HZmNcwCE++NxGazf+yFpY+wCb+YS23sDa1ghpo3zrNFOcHlow==" + "license": "BSD-2-Clause" }, "node_modules/media-typer": { "version": "0.3.0", @@ -13972,9 +13262,9 @@ } }, "node_modules/memfs": { - "version": "3.4.12", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.12.tgz", - "integrity": "sha512-BcjuQn6vfqP+k100e0E9m61Hyqa//Brp+I3f0OBmN0ATHlFA8vx3Lt8z57R3u2bPqe3WGDBC+nF72fTH7isyEw==", + "version": "3.4.13", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.13.tgz", + "integrity": "sha512-omTM41g3Skpvx5dSYeZIbXKcXoAVc/AoMNwn9TKx++L/gaen/+4TTttmu8ZSch5vfVJ8uJvGbroTsIlslRg6lg==", "dev": true, "dependencies": { "fs-monkey": "^1.0.3" @@ -13991,15 +13281,13 @@ }, "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 + "dev": true, + "license": "MIT" }, "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, + "license": "MIT", "engines": { "node": ">= 8" } @@ -14015,9 +13303,8 @@ }, "node_modules/micromatch": { "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -14028,9 +13315,8 @@ }, "node_modules/mime": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -14040,18 +13326,16 @@ }, "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, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "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, + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -14061,26 +13345,24 @@ }, "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, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/min-indent": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/mini-css-extract-plugin": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", - "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz", + "integrity": "sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==", "dev": true, "dependencies": { "schema-utils": "^4.0.0" @@ -14104,9 +13386,8 @@ }, "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, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -14116,16 +13397,15 @@ }, "node_modules/minimist": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz", + "integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==", "dev": true, "dependencies": { "yallist": "^4.0.0" @@ -14146,6 +13426,18 @@ "node": ">= 8" } }, + "node_modules/minipass-collect/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/minipass-fetch": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", @@ -14163,6 +13455,18 @@ "encoding": "^0.1.13" } }, + "node_modules/minipass-fetch/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/minipass-flush": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", @@ -14175,6 +13479,18 @@ "node": ">= 8" } }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/minipass-json-stream": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", @@ -14185,6 +13501,18 @@ "minipass": "^3.0.0" } }, + "node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/minipass-pipeline": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", @@ -14197,6 +13525,18 @@ "node": ">=8" } }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/minipass-sized": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", @@ -14209,6 +13549,18 @@ "node": ">=8" } }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", @@ -14222,6 +13574,18 @@ "node": ">= 8" } }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -14236,17 +13600,15 @@ }, "node_modules/moment": { "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, "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==" + "license": "MIT" }, "node_modules/multicast-dns": { "version": "7.2.5", @@ -14263,15 +13625,13 @@ }, "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 + "dev": true, + "license": "ISC" }, "node_modules/nanoid": { "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", "dev": true, + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -14281,21 +13641,18 @@ }, "node_modules/natural-compare": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/natural-compare-lite": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/needle": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", - "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "debug": "^3.2.6", @@ -14311,9 +13668,8 @@ }, "node_modules/needle/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "ms": "^2.1.1" @@ -14321,9 +13677,8 @@ }, "node_modules/needle/node_modules/iconv-lite": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -14343,31 +13698,8 @@ }, "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/nice-napi": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", - "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "!win32" - ], - "dependencies": { - "node-addon-api": "^3.0.0", - "node-gyp-build": "^4.2.2" - } - }, - "node_modules/node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true, - "optional": true + "license": "MIT" }, "node_modules/node-forge": { "version": "1.3.1", @@ -14379,9 +13711,9 @@ } }, "node_modules/node-gyp": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.0.tgz", - "integrity": "sha512-A6rJWfXFz7TQNjpldJ915WFb1LnhO4lIve3ANPbWreuEoLoKlFT3sxIepPBkLhM27crW8YmN+pjlgbasH6cH/Q==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz", + "integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==", "dev": true, "dependencies": { "env-paths": "^2.2.0", @@ -14399,19 +13731,7 @@ "node-gyp": "bin/node-gyp.js" }, "engines": { - "node": "^12.22 || ^14.13 || >=16" - } - }, - "node_modules/node-gyp-build": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", - "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==", - "dev": true, - "optional": true, - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" + "node": "^12.13 || ^14.13 || >=16" } }, "node_modules/node-gyp/node_modules/glob": { @@ -14436,14 +13756,12 @@ }, "node_modules/node-int64": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/node-releases": { "version": "2.0.7", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.7.tgz", - "integrity": "sha512-EJ3rzxL9pTWPjk5arA0s0dgXpnyiAbJDE6wHT62g7VsgrgQgmmZ+Ru++M1BFofncWja+Pnn3rEr3fieRySAdKQ==" + "license": "MIT" }, "node_modules/nopt": { "version": "6.0.0", @@ -14475,31 +13793,17 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/normalize-package-data/node_modules/hosted-git-info": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", - "dev": true, - "dependencies": { - "lru-cache": "^7.5.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "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==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/normalize-range": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -14538,18 +13842,18 @@ } }, "node_modules/npm-package-arg": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", - "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", + "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", "dev": true, "dependencies": { - "hosted-git-info": "^5.0.0", - "proc-log": "^2.0.1", + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", "semver": "^7.3.5", - "validate-npm-package-name": "^4.0.0" + "validate-npm-package-name": "^5.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm-packlist": { @@ -14579,54 +13883,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm-pick-manifest/node_modules/hosted-git-info": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", - "dev": true, - "dependencies": { - "lru-cache": "^7.5.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-pick-manifest/node_modules/npm-package-arg": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", - "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^6.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-pick-manifest/node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-pick-manifest/node_modules/validate-npm-package-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", - "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", - "dev": true, - "dependencies": { - "builtins": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/npm-registry-fetch": { "version": "14.0.3", "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.3.tgz", @@ -14645,18 +13901,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm-registry-fetch/node_modules/hosted-git-info": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", - "dev": true, - "dependencies": { - "lru-cache": "^7.5.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { "version": "11.0.2", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.2.tgz", @@ -14676,84 +13920,35 @@ "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/minipass": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz", - "integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm-registry-fetch/node_modules/minipass-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", - "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", - "dev": true, - "dependencies": { - "minipass": "^4.0.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/npm-registry-fetch/node_modules/npm-package-arg": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", - "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^6.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm-registry-fetch/node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/validate-npm-package-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", - "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "node_modules/npm-registry-fetch/node_modules/minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", "dev": true, "dependencies": { - "builtins": "^5.0.0" + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" } }, "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, + "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -14778,9 +13973,8 @@ }, "node_modules/nth-check": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -14790,18 +13984,16 @@ }, "node_modules/object-inspect": { "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object-is": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -14815,18 +14007,16 @@ }, "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, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/object.assign": { "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -14842,9 +14032,8 @@ }, "node_modules/object.values": { "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -14865,8 +14054,7 @@ }, "node_modules/ol": { "version": "7.2.2", - "resolved": "https://registry.npmjs.org/ol/-/ol-7.2.2.tgz", - "integrity": "sha512-eqJ1hhVQQ3Ap4OhYq9DRu5pz9RMpLhmoTauDoIqpn7logVi1AJE+lXjEHrPrTSuZYjtFbMgqr07sxoLNR65nrw==", + "license": "BSD-2-Clause", "dependencies": { "earcut": "^2.2.3", "geotiff": "^2.0.7", @@ -14881,8 +14069,7 @@ }, "node_modules/ol-mapbox-style": { "version": "9.2.4", - "resolved": "https://registry.npmjs.org/ol-mapbox-style/-/ol-mapbox-style-9.2.4.tgz", - "integrity": "sha512-Q+G1YvYcC2XSZm9UcrSkW4hxe1K3YFTKBM7FmGhsfXaqty1wRTbsDCLUx7RBAC08RPIaPl0IkHs6SRdJx3BwsQ==", + "license": "BSD-2-Clause", "dependencies": { "@mapbox/mapbox-gl-style-spec": "^13.23.1", "mapbox-to-css-font": "^2.4.1" @@ -14911,17 +14098,15 @@ }, "node_modules/once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", "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, + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -14934,9 +14119,8 @@ }, "node_modules/open": { "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", "dev": true, + "license": "MIT", "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", @@ -14951,9 +14135,8 @@ }, "node_modules/optionator": { "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, + "license": "MIT", "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -14968,9 +14151,8 @@ }, "node_modules/ora": { "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "dev": true, + "license": "MIT", "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", @@ -14991,9 +14173,8 @@ }, "node_modules/ora/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -15006,9 +14187,8 @@ }, "node_modules/ora/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -15022,9 +14202,8 @@ }, "node_modules/ora/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -15034,24 +14213,21 @@ }, "node_modules/ora/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ora/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/ora/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -15061,24 +14237,21 @@ }, "node_modules/os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/ospath": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", - "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==", - "dev": true + "dev": true, + "license": "MIT" }, "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, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -15091,9 +14264,8 @@ }, "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, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -15103,9 +14275,8 @@ }, "node_modules/p-locate/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, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -15118,9 +14289,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, + "license": "MIT", "dependencies": { "aggregate-error": "^3.0.0" }, @@ -15155,17 +14325,16 @@ }, "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, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/pacote": { - "version": "15.0.6", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.0.6.tgz", - "integrity": "sha512-dQwcz/sME7QIL+cdrw/jftQfMMXxSo17i2kJ/gnhBhUvvBAsxoBu1lw9B5IzCH/Ce8CvEkG/QYZ6txzKfn0bTw==", + "version": "15.0.8", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.0.8.tgz", + "integrity": "sha512-UlcumB/XS6xyyIMwg/WwMAyUmga+RivB5KgkRwA1hZNtrx+0Bt41KxHCvg1kr0pZ/ZeD8qjhW4fph6VaYRCbLw==", "dev": true, "dependencies": { "@npmcli/git": "^4.0.0", @@ -15173,8 +14342,8 @@ "@npmcli/promise-spawn": "^6.0.1", "@npmcli/run-script": "^6.0.0", "cacache": "^17.0.0", - "fs-minipass": "^2.1.0", - "minipass": "^3.1.6", + "fs-minipass": "^3.0.0", + "minipass": "^4.0.0", "npm-package-arg": "^10.0.0", "npm-packlist": "^7.0.0", "npm-pick-manifest": "^8.0.0", @@ -15193,58 +14362,9 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/pacote/node_modules/hosted-git-info": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", - "dev": true, - "dependencies": { - "lru-cache": "^7.5.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/pacote/node_modules/npm-package-arg": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", - "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^6.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/pacote/node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/pacote/node_modules/validate-npm-package-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", - "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", - "dev": true, - "dependencies": { - "builtins": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/pako": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", - "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" + "license": "(MIT AND Zlib)" }, "node_modules/parent-module": { "version": "1.0.1", @@ -15260,14 +14380,12 @@ }, "node_modules/parse-headers": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", - "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==" + "license": "MIT" }, "node_modules/parse-json": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -15283,9 +14401,8 @@ }, "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, + "license": "MIT", "engines": { "node": ">= 0.10" } @@ -15305,9 +14422,8 @@ }, "node_modules/parse5-html-rewriting-stream": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", - "integrity": "sha512-vwLQzynJVEfUlURxgnf51yAJDQTtVpNyGD8tKi2Za7m+akukNHxCcUQMAa/mUGLhCeicFdpy7Tlvj8ZNKadprg==", "dev": true, + "license": "MIT", "dependencies": { "parse5": "^6.0.1", "parse5-sax-parser": "^6.0.1" @@ -15315,39 +14431,34 @@ }, "node_modules/parse5-html-rewriting-stream/node_modules/parse5": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/parse5-htmlparser2-tree-adapter": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", "dev": true, + "license": "MIT", "dependencies": { "parse5": "^6.0.1" } }, "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/parse5-sax-parser": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz", - "integrity": "sha512-kXX+5S81lgESA0LsDuGjAlBybImAChYRMT+/uKCEXFBFOeEhS52qUCydGhU3qLRD8D9DVjaUo821WK7DM4iCeg==", "dev": true, + "license": "MIT", "dependencies": { "parse5": "^6.0.1" } }, "node_modules/parse5-sax-parser/node_modules/parse5": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/parse5/node_modules/entities": { "version": "4.4.0", @@ -15373,36 +14484,32 @@ }, "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, + "license": "MIT", "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": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, + "license": "MIT", "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, + "license": "MIT", "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 + "dev": true, + "license": "MIT" }, "node_modules/path-to-regexp": { "version": "0.1.7", @@ -15412,17 +14519,15 @@ }, "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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/pbf": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz", - "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==", + "license": "BSD-3-Clause", "dependencies": { "ieee754": "^1.1.12", "resolve-protobuf-schema": "^2.1.0" @@ -15433,25 +14538,21 @@ }, "node_modules/pend": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/performance-now": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/picocolors": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -15461,27 +14562,24 @@ }, "node_modules/pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/pirates": { "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/piscina": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", - "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", "dev": true, + "license": "MIT", "dependencies": { "eventemitter-asyncresource": "^1.0.0", "hdr-histogram-js": "^2.0.1", @@ -15493,9 +14591,8 @@ }, "node_modules/pixelmatch": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.3.0.tgz", - "integrity": "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==", "dev": true, + "license": "ISC", "dependencies": { "pngjs": "^6.0.0" }, @@ -15505,18 +14602,16 @@ }, "node_modules/pixelmatch/node_modules/pngjs": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", - "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.13.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, + "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -15526,26 +14621,24 @@ }, "node_modules/pluralize": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/pngjs": { "version": "3.4.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", - "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", "dev": true, + "license": "MIT", "engines": { "node": ">=4.0.0" } }, "node_modules/postcss": { - "version": "8.4.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", - "integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==", + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", "dev": true, "funding": [ { @@ -15567,14 +14660,14 @@ } }, "node_modules/postcss-loader": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.1.tgz", - "integrity": "sha512-VRviFEyYlLjctSM93gAZtcJJ/iSkPZ79zWbN/1fSH+NisBByEiVLqpdVDrPLVSi8DX0oJo12kL/GppTBdKVXiQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.2.tgz", + "integrity": "sha512-fUJzV/QH7NXUAqV8dWJ9Lg4aTkDCezpTS5HgJ2DvqznexTbSTxgi/dTECvTZ15BwKTtk8G/bqI/QTu2HPd3ZCg==", "dev": true, "dependencies": { "cosmiconfig": "^7.0.0", "klona": "^2.0.5", - "semver": "^7.3.7" + "semver": "^7.3.8" }, "engines": { "node": ">= 14.15.0" @@ -15590,9 +14683,8 @@ }, "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, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -15602,9 +14694,8 @@ }, "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, + "license": "MIT", "dependencies": { "icss-utils": "^5.0.0", "postcss-selector-parser": "^6.0.2", @@ -15619,9 +14710,8 @@ }, "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, + "license": "ISC", "dependencies": { "postcss-selector-parser": "^6.0.4" }, @@ -15634,9 +14724,8 @@ }, "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, + "license": "ISC", "dependencies": { "icss-utils": "^5.0.0" }, @@ -15649,9 +14738,8 @@ }, "node_modules/postcss-selector-parser": { "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", - "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -15662,24 +14750,21 @@ }, "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 + "dev": true, + "license": "MIT" }, "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, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/pretty-bytes": { "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -15689,9 +14774,8 @@ }, "node_modules/pretty-format": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/schemas": "^29.0.0", "ansi-styles": "^5.0.0", @@ -15703,9 +14787,8 @@ }, "node_modules/pretty-format/node_modules/ansi-styles": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -15714,12 +14797,12 @@ } }, "node_modules/proc-log": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", - "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/process-nextick-args": { @@ -15749,9 +14832,8 @@ }, "node_modules/prompts": { "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, + "license": "MIT", "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -15762,8 +14844,7 @@ }, "node_modules/protocol-buffers-schema": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", - "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==" + "license": "MIT" }, "node_modules/proxy-addr": { "version": "2.0.7", @@ -15789,28 +14870,24 @@ }, "node_modules/proxy-from-env": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", - "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/prr": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/psl": { "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true + "dev": true, + "license": "MIT" }, "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, + "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -15818,26 +14895,22 @@ }, "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, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/qs": { "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.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": [ { @@ -15852,12 +14925,12 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/quick-lru": { "version": "6.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.1.tgz", - "integrity": "sha512-S27GBT+F0NTRiehtbrgaSE1idUAJ5bX8dPAQTdylEyNlrdcH5X4Lz7Edz3DYzecbsCluD5zO8ZNEe04z3D3u6Q==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -15867,14 +14940,12 @@ }, "node_modules/quickselect": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", - "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + "license": "ISC" }, "node_modules/randombytes": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } @@ -15914,17 +14985,15 @@ }, "node_modules/rbush": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz", - "integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==", + "license": "MIT", "dependencies": { "quickselect": "^2.0.0" } }, "node_modules/react-is": { "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/read-package-json": { "version": "6.0.0", @@ -15974,9 +15043,8 @@ }, "node_modules/read-pkg": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "dev": true, + "license": "MIT", "dependencies": { "@types/normalize-package-data": "^2.4.0", "normalize-package-data": "^2.5.0", @@ -15989,9 +15057,8 @@ }, "node_modules/read-pkg-up": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^4.1.0", "read-pkg": "^5.2.0", @@ -16006,24 +15073,21 @@ }, "node_modules/read-pkg-up/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==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" } }, "node_modules/read-pkg/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 + "dev": true, + "license": "ISC" }, "node_modules/read-pkg/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, + "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -16033,27 +15097,24 @@ }, "node_modules/read-pkg/node_modules/semver": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } }, "node_modules/read-pkg/node_modules/type-fest": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" } }, "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, + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -16065,8 +15126,7 @@ }, "node_modules/readdirp": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -16076,20 +15136,17 @@ }, "node_modules/reflect-metadata": { "version": "0.1.13", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + "license": "Apache-2.0" }, "node_modules/regenerate": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regenerate-unicode-properties": { "version": "10.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", "dev": true, + "license": "MIT", "dependencies": { "regenerate": "^1.4.2" }, @@ -16099,39 +15156,34 @@ }, "node_modules/regenerator-runtime": { "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regenerator-transform": { "version": "0.15.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", - "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.4" } }, "node_modules/regex-parser": { "version": "2.2.11", - "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", - "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regexp-tree": { "version": "0.1.24", - "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.24.tgz", - "integrity": "sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw==", "dev": true, + "license": "MIT", "bin": { "regexp-tree": "bin/regexp-tree" } }, "node_modules/regexp.prototype.flags": { "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -16146,9 +15198,8 @@ }, "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, + "license": "MIT", "engines": { "node": ">=8" }, @@ -16158,9 +15209,8 @@ }, "node_modules/regexpu-core": { "version": "5.2.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", - "integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==", "dev": true, + "license": "MIT", "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.1.0", @@ -16175,15 +15225,13 @@ }, "node_modules/regjsgen": { "version": "0.7.1", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", - "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regjsparser": { "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "jsesc": "~0.5.0" }, @@ -16193,8 +15241,6 @@ }, "node_modules/regjsparser/node_modules/jsesc": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", "dev": true, "bin": { "jsesc": "bin/jsesc" @@ -16202,35 +15248,31 @@ }, "node_modules/request-progress": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", - "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", "dev": true, + "license": "MIT", "dependencies": { "throttleit": "^1.0.0" } }, "node_modules/require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", "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, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/requireindex": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", - "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.5" } @@ -16243,9 +15285,8 @@ }, "node_modules/resolve": { "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dev": true, + "license": "MIT", "dependencies": { "is-core-module": "^2.9.0", "path-parse": "^1.0.7", @@ -16260,9 +15301,8 @@ }, "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, + "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -16272,26 +15312,23 @@ }, "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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/resolve-protobuf-schema": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", - "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "license": "MIT", "dependencies": { "protocol-buffers-schema": "^3.3.1" } }, "node_modules/resolve-url-loader": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", - "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", "dev": true, + "license": "MIT", "dependencies": { "adjust-sourcemap-loader": "^4.0.0", "convert-source-map": "^1.7.0", @@ -16305,9 +15342,8 @@ }, "node_modules/resolve-url-loader/node_modules/loader-utils": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, + "license": "MIT", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -16319,27 +15355,24 @@ }, "node_modules/resolve-url-loader/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, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/resolve.exports": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } }, "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, + "license": "MIT", "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -16359,9 +15392,8 @@ }, "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, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -16369,15 +15401,13 @@ }, "node_modules/rfdc": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true + "dev": true, + "license": "MIT" }, "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, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -16390,9 +15420,8 @@ }, "node_modules/rimraf/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -16410,17 +15439,14 @@ }, "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, + "license": "MIT", "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": [ { @@ -16436,28 +15462,26 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, "node_modules/rw": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + "license": "BSD-3-Clause" }, "node_modules/rxjs": { "version": "7.8.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", - "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/rxjs-report-usage": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/rxjs-report-usage/-/rxjs-report-usage-1.0.6.tgz", - "integrity": "sha512-omv1DIv5z1kV+zDAEjaDjWSkx8w5TbFp5NZoPwUipwzYVcor/4So9ZU3bUyQ1c8lxY5Q0Es/ztWW7PGjY7to0Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.10.3", "@babel/traverse": "^7.10.3", @@ -16473,9 +15497,8 @@ }, "node_modules/rxjs-report-usage/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -16488,9 +15511,8 @@ }, "node_modules/rxjs-report-usage/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, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -16504,9 +15526,8 @@ }, "node_modules/rxjs-report-usage/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -16516,15 +15537,13 @@ }, "node_modules/rxjs-report-usage/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/rxjs-report-usage/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -16542,18 +15561,16 @@ }, "node_modules/rxjs-report-usage/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/rxjs-report-usage/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -16563,8 +15580,6 @@ }, "node_modules/safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true, "funding": [ { @@ -16579,22 +15594,21 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safe-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz", - "integrity": "sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==", "dev": true, + "license": "MIT", "dependencies": { "regexp-tree": "~0.1.1" } }, "node_modules/safe-regex-test": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", @@ -16606,9 +15620,8 @@ }, "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 + "dev": true, + "license": "MIT" }, "node_modules/safevalues": { "version": "0.3.4", @@ -16616,9 +15629,9 @@ "integrity": "sha512-LRneZZRXNgjzwG4bDQdOTSbze3fHm1EAKN/8bePxnlEZiBmkYEDggaHbuvHI9/hoqHbGfsEA7tWS9GhYHZBBsw==" }, "node_modules/sass": { - "version": "1.56.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.56.1.tgz", - "integrity": "sha512-VpEyKpyBPCxE7qGDtOcdJ6fFbcpOM+Emu7uZLxVrkX8KVU/Dp5UF7WLvzqRuUhB6mqqQt1xffLoG+AndxTZrCQ==", + "version": "1.57.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.57.1.tgz", + "integrity": "sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -16634,9 +15647,8 @@ }, "node_modules/sass-loader": { "version": "13.2.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.0.tgz", - "integrity": "sha512-JWEp48djQA4nbZxmgC02/Wh0eroSUutulROUusYJO9P9zltRbNN80JCBHqRGzjd4cmZCa/r88xgfkjGD0TXsHg==", "dev": true, + "license": "MIT", "dependencies": { "klona": "^2.0.4", "neo-async": "^2.6.2" @@ -16672,16 +15684,14 @@ }, "node_modules/sax": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, + "license": "ISC", "optional": true }, "node_modules/schema-utils": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.8.0", @@ -16716,8 +15726,7 @@ }, "node_modules/semver": { "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -16730,8 +15739,7 @@ }, "node_modules/semver/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==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -16795,9 +15803,8 @@ }, "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, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } @@ -16900,9 +15907,8 @@ }, "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, + "license": "MIT", "dependencies": { "kind-of": "^6.0.2" }, @@ -16912,9 +15918,8 @@ }, "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, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -16924,18 +15929,16 @@ }, "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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/side-channel": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -16947,30 +15950,26 @@ }, "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 + "dev": true, + "license": "ISC" }, "node_modules/sisteransi": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/slash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/slice-ansi": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", @@ -16982,9 +15981,8 @@ }, "node_modules/slice-ansi/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, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -16997,9 +15995,8 @@ }, "node_modules/slice-ansi/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -17009,9 +16006,8 @@ }, "node_modules/slice-ansi/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/smart-buffer": { "version": "4.2.0", @@ -17025,8 +16021,7 @@ }, "node_modules/socket.io-client": { "version": "4.5.4", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.4.tgz", - "integrity": "sha512-ZpKteoA06RzkD32IbqILZ+Cnst4xewU7ZYK12aS1mzHftFFjpoMz69IuhP/nL25pJfao/amoPI527KnuhFm01g==", + "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.2", @@ -17039,8 +16034,7 @@ }, "node_modules/socket.io-parser": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", - "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", + "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" @@ -17090,24 +16084,18 @@ }, "node_modules/sort-asc": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/sort-asc/-/sort-asc-0.1.0.tgz", - "integrity": "sha512-jBgdDd+rQ+HkZF2/OHCmace5dvpos/aWQpcxuyRs9QUbPRnkEJmYVo81PIGpjIdpOcsnJ4rGjStfDHsbn+UVyw==", "engines": { "node": ">=0.10.0" } }, "node_modules/sort-desc": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/sort-desc/-/sort-desc-0.1.1.tgz", - "integrity": "sha512-jfZacW5SKOP97BF5rX5kQfJmRVZP5/adDUTY8fCSPvNcXDVpUEe2pr/iKGlcyZzchRJZrswnp68fgk3qBXgkJw==", "engines": { "node": ">=0.10.0" } }, "node_modules/sort-object": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/sort-object/-/sort-object-0.3.2.tgz", - "integrity": "sha512-aAQiEdqFTTdsvUFxXm3umdo04J7MRljoVGbBlkH7BgNsMvVNAJyGj7C/wV1A8wHWAJj/YikeZbfuCKqhggNWGA==", "dependencies": { "sort-asc": "^0.1.0", "sort-desc": "^0.1.1" @@ -17127,18 +16115,16 @@ }, "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, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-loader": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.1.tgz", - "integrity": "sha512-oqXpzDIByKONVY8g1NUPOTQhe0UTU5bWUl32GSkqK2LjJj0HmwTMVKxcUip0RgAYhY1mqgOxjbQM48a0mmeNfA==", "dev": true, + "license": "MIT", "dependencies": { "abab": "^2.0.6", "iconv-lite": "^0.6.3", @@ -17157,9 +16143,8 @@ }, "node_modules/source-map-loader/node_modules/iconv-lite": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -17169,9 +16154,8 @@ }, "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, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -17179,25 +16163,16 @@ }, "node_modules/source-map-support/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", - "dev": true - }, "node_modules/spdx-correct": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -17205,15 +16180,13 @@ }, "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 + "dev": true, + "license": "CC-BY-3.0" }, "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, + "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -17221,9 +16194,8 @@ }, "node_modules/spdx-license-ids": { "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", - "dev": true + "dev": true, + "license": "CC0-1.0" }, "node_modules/spdy": { "version": "4.0.2", @@ -17257,15 +16229,13 @@ }, "node_modules/sprintf-js": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/sshpk": { "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", "dev": true, + "license": "MIT", "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -17298,23 +16268,10 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/ssri/node_modules/minipass": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz", - "integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/stack-utils": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, + "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -17324,9 +16281,8 @@ }, "node_modules/stack-utils/node_modules/escape-string-regexp": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -17342,18 +16298,16 @@ }, "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, + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } }, "node_modules/string-length": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, + "license": "MIT", "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -17364,8 +16318,7 @@ }, "node_modules/string-width": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -17377,9 +16330,8 @@ }, "node_modules/string.prototype.trimend": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -17391,9 +16343,8 @@ }, "node_modules/string.prototype.trimstart": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -17405,8 +16356,7 @@ }, "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==", + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -17416,27 +16366,24 @@ }, "node_modules/strip-bom": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "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, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/strip-indent": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "dev": true, + "license": "MIT", "dependencies": { "min-indent": "^1.0.0" }, @@ -17446,9 +16393,8 @@ }, "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, + "license": "MIT", "engines": { "node": ">=8" }, @@ -17458,8 +16404,7 @@ }, "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==", + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -17469,9 +16414,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, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -17481,18 +16425,16 @@ }, "node_modules/symbol-observable": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", - "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10" } }, "node_modules/tapable": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -17514,10 +16456,22 @@ "node": ">=10" } }, - "node_modules/tar/node_modules/minipass": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz", - "integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==", + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, "dependencies": { "yallist": "^4.0.0" @@ -17527,9 +16481,9 @@ } }, "node_modules/terser": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", - "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", + "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.2", @@ -17546,9 +16500,8 @@ }, "node_modules/terser-webpack-plugin": { "version": "5.3.6", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", - "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.14", "jest-worker": "^27.4.5", @@ -17580,9 +16533,8 @@ }, "node_modules/terser-webpack-plugin/node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -17596,27 +16548,24 @@ }, "node_modules/terser-webpack-plugin/node_modules/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, + "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } }, "node_modules/terser-webpack-plugin/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, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/terser-webpack-plugin/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, + "license": "MIT", "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -17628,15 +16577,13 @@ }, "node_modules/terser-webpack-plugin/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 + "dev": true, + "license": "MIT" }, "node_modules/terser-webpack-plugin/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, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -17652,9 +16599,8 @@ }, "node_modules/terser-webpack-plugin/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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -17667,15 +16613,13 @@ }, "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 + "dev": true, + "license": "MIT" }, "node_modules/test-exclude": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, + "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -17687,9 +16631,8 @@ }, "node_modules/test-exclude/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -17707,21 +16650,18 @@ }, "node_modules/text-table": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/throttleit": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "integrity": "sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/through": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/thunky": { "version": "1.1.0", @@ -17731,9 +16671,8 @@ }, "node_modules/tmp": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", "dev": true, + "license": "MIT", "dependencies": { "rimraf": "^3.0.0" }, @@ -17743,22 +16682,19 @@ }, "node_modules/tmpl": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/to-fast-properties": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "license": "MIT", "engines": { "node": ">=4" } }, "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==", + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -17777,9 +16713,8 @@ }, "node_modules/tough-cookie": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "psl": "^1.1.28", "punycode": "^2.1.1" @@ -17790,23 +16725,22 @@ }, "node_modules/tree-kill": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, + "license": "MIT", "bin": { "tree-kill": "cli.js" } }, "node_modules/ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", + "version": "29.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz", + "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==", "dev": true, "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^29.0.0", - "json5": "^2.2.1", + "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", @@ -17842,9 +16776,8 @@ }, "node_modules/tsconfig-paths": { "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.1", @@ -17853,9 +16786,9 @@ } }, "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "dependencies": { "minimist": "^1.2.0" @@ -17866,23 +16799,20 @@ }, "node_modules/tsconfig-paths/node_modules/strip-bom": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/tslib": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + "license": "0BSD" }, "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, + "license": "MIT", "dependencies": { "tslib": "^1.8.1" }, @@ -17895,9 +16825,8 @@ }, "node_modules/tsutils-etc": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/tsutils-etc/-/tsutils-etc-1.4.1.tgz", - "integrity": "sha512-6UPYgc7OXcIW5tFxlsZF3OVSBvDInl/BkS3Xsu64YITXk7WrnWTVByKWPCThFDBp5gl5IGHOzGMdQuDCE7OL4g==", "dev": true, + "license": "MIT", "dependencies": { "@types/yargs": "^17.0.0", "yargs": "^17.0.0" @@ -17913,15 +16842,13 @@ }, "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 + "dev": true, + "license": "0BSD" }, "node_modules/tunnel-agent": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" }, @@ -17931,15 +16858,13 @@ }, "node_modules/tweetnacl": { "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true + "dev": true, + "license": "Unlicense" }, "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, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -17949,18 +16874,16 @@ }, "node_modules/type-detect": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "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, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -17983,14 +16906,13 @@ }, "node_modules/typed-assert": { "version": "1.0.9", - "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", - "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -18001,9 +16923,8 @@ }, "node_modules/uglify-js": { "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", "dev": true, + "license": "BSD-2-Clause", "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" @@ -18014,9 +16935,8 @@ }, "node_modules/unbox-primitive": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-bigints": "^1.0.2", @@ -18029,18 +16949,16 @@ }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/unicode-match-property-ecmascript": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, + "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" @@ -18051,18 +16969,16 @@ }, "node_modules/unicode-match-property-value-ecmascript": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/unicode-property-aliases-ecmascript": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -18093,9 +17009,8 @@ }, "node_modules/universalify": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10.0.0" } @@ -18111,17 +17026,14 @@ }, "node_modules/untildify": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/update-browserslist-db": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "funding": [ { "type": "opencollective", @@ -18132,6 +17044,7 @@ "url": "https://tidelift.com/funding/github/npm/browserslist" } ], + "license": "MIT", "dependencies": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -18145,18 +17058,16 @@ }, "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, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } }, "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", @@ -18169,18 +17080,16 @@ }, "node_modules/uuid": { "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/v8-to-istanbul": { "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", "dev": true, + "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -18192,30 +17101,28 @@ }, "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, + "license": "Apache-2.0", "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "node_modules/validate-npm-package-name": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", - "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", "dev": true, "dependencies": { "builtins": "^5.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/validator": { "version": "13.7.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", - "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", + "license": "MIT", "engines": { "node": ">= 0.10" } @@ -18231,12 +17138,11 @@ }, "node_modules/verror": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "engines": [ "node >=0.6.0" ], + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -18245,18 +17151,16 @@ }, "node_modules/walker": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" } }, "node_modules/watchpack": { "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", "dev": true, + "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -18276,23 +17180,20 @@ }, "node_modules/wcwidth": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, + "license": "MIT", "dependencies": { "defaults": "^1.0.3" } }, "node_modules/web-worker": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz", - "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==" + "license": "Apache-2.0" }, "node_modules/webpack": { "version": "5.75.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", - "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^0.0.51", @@ -18336,26 +17237,26 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.0.1.tgz", + "integrity": "sha512-PZPZ6jFinmqVPJZbisfggDiC+2EeGZ1ZByyMP5sOFJcPPWSexalISz+cvm+j+oYPT7FIJyxT76esjnw9DhE5sw==", "dev": true, "dependencies": { "colorette": "^2.0.10", - "memfs": "^3.4.3", + "memfs": "^3.4.12", "mime-types": "^2.1.31", "range-parser": "^1.2.1", "schema-utils": "^4.0.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 14.15.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "webpack": "^5.0.0" } }, "node_modules/webpack-dev-server": { @@ -18413,17 +17314,40 @@ } } }, + "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz", + "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==", "dev": true, "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -18436,9 +17360,8 @@ }, "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, + "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", "wildcard": "^2.0.0" @@ -18449,18 +17372,16 @@ }, "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, + "license": "MIT", "engines": { "node": ">=10.13.0" } }, "node_modules/webpack-subresource-integrity": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", - "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", "dev": true, + "license": "MIT", "dependencies": { "typed-assert": "^1.0.8" }, @@ -18479,9 +17400,8 @@ }, "node_modules/webpack/node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -18495,18 +17415,16 @@ }, "node_modules/webpack/node_modules/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, + "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } }, "node_modules/webpack/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, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -18517,24 +17435,21 @@ }, "node_modules/webpack/node_modules/estraverse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/webpack/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 + "dev": true, + "license": "MIT" }, "node_modules/webpack/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, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -18573,9 +17488,8 @@ }, "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, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -18588,9 +17502,8 @@ }, "node_modules/which-boxed-primitive": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, + "license": "MIT", "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -18604,9 +17517,8 @@ }, "node_modules/which-collection": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", "dev": true, + "license": "MIT", "dependencies": { "is-map": "^2.0.1", "is-set": "^2.0.1", @@ -18619,9 +17531,8 @@ }, "node_modules/which-typed-array": { "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", @@ -18648,29 +17559,25 @@ }, "node_modules/wildcard": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", - "dev": true + "dev": true, + "license": "MIT" }, "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, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/wordwrap": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/wrap-ansi": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -18685,8 +17592,7 @@ }, "node_modules/wrap-ansi/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==", + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -18699,8 +17605,7 @@ }, "node_modules/wrap-ansi/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==", + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -18710,19 +17615,16 @@ }, "node_modules/wrap-ansi/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==" + "license": "MIT" }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "license": "ISC" }, "node_modules/write-file-atomic": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -18733,8 +17635,7 @@ }, "node_modules/ws": { "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -18753,29 +17654,24 @@ }, "node_modules/xml-utils": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.3.0.tgz", - "integrity": "sha512-i4PIrX33Wd66dvwo4syicwlwmnr6wuvvn4f2ku9hA67C2Uk62Xubczuhct+Evnd12/DV71qKNeDdJwES8HX1RA==" + "license": "CC0-1.0" }, "node_modules/xmlhttprequest-ssl": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", - "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", "engines": { "node": ">=0.4.0" } }, "node_modules/y18n": { "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "license": "ISC" }, "node_modules/yaml": { "version": "1.10.2", @@ -18788,8 +17684,7 @@ }, "node_modules/yargs": { "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -18805,17 +17700,15 @@ }, "node_modules/yargs-parser": { "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/yauzl": { "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, + "license": "MIT", "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" @@ -18823,9 +17716,8 @@ }, "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, + "license": "MIT", "engines": { "node": ">=10" }, @@ -18835,8 +17727,7 @@ }, "node_modules/zone.js": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.12.0.tgz", - "integrity": "sha512-XtC+I5dXU14HrzidAKBNMqneIVUykLEAA1x+v4KVrd6AUPWlwYORF8KgsVqvgdHiKZ4BkxxjvYi/ksEixTPR0Q==", + "license": "MIT", "peer": true, "dependencies": { "tslib": "^2.3.0" diff --git a/frontend/package.json b/frontend/package.json index f9ec1bfe1..ad26fcb5c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-frontend", - "version": "0.0.0", + "version": "1.2.3-test14", "type": "module", "scripts": { "cy:open": "cypress open", @@ -24,24 +24,24 @@ "npm": ">=8" }, "dependencies": { - "@angular/animations": "~15.0.4", - "@angular/common": "~15.0.4", - "@angular/compiler": "~15.0.4", - "@angular/core": "~15.0.4", - "@angular/forms": "~15.0.4", - "@angular/material": "^15.0.3", - "@angular/platform-browser": "~15.0.4", - "@angular/platform-browser-dynamic": "~15.0.4", - "@angular/router": "~15.0.4", - "@ng-bootstrap/ng-bootstrap": "^14.0.0", + "@angular/animations": "~15.1.0", + "@angular/common": "~15.1.0", + "@angular/compiler": "~15.1.0", + "@angular/core": "~15.1.0", + "@angular/forms": "~15.1.0", + "@angular/material": "^15.1.0", + "@angular/platform-browser": "~15.1.0", + "@angular/platform-browser-dynamic": "~15.1.0", + "@angular/router": "~15.1.0", + "@ng-bootstrap/ng-bootstrap": "^14.0.1", "@ngrx/store": "^15.1.0", "bootstrap": "^5.2.3", - "bootstrap-icons": "^1.10.2", - "chart.js": "^4.1.1", + "bootstrap-icons": "^1.10.3", + "chart.js": "^4.1.2", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "digital-fuesim-manv-shared": "file:../shared", - "immer": "^9.0.16", + "immer": "^9.0.17", "lodash-es": "4.17.21", "ol": "^7.2.2", "rxjs": "~7.8.0", @@ -49,31 +49,31 @@ "tslib": "^2.4.1" }, "devDependencies": { - "@angular-devkit/build-angular": "^15.0.4", + "@angular-devkit/build-angular": "^15.1.1", "@angular-eslint/builder": "15.1.0", "@angular-eslint/eslint-plugin": "15.1.0", "@angular-eslint/eslint-plugin-template": "15.1.0", "@angular-eslint/schematics": "15.1.0", "@angular-eslint/template-parser": "15.1.0", - "@angular/cli": "~15.0.4", - "@angular/compiler-cli": "~15.0.4", + "@angular/cli": "~15.1.1", + "@angular/compiler-cli": "~15.1.0", "@types/chart.js": "^2.9.37", - "@types/jest": "^29.2.4", + "@types/jest": "^29.2.5", "@types/lodash-es": "^4.17.6", - "@types/node": "^18", - "@typescript-eslint/eslint-plugin": "5.47.0", - "@typescript-eslint/parser": "5.47.0", + "@types/node": "^16", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", "cypress": "^9.5.3", "cypress-image-diff-js": "^1.21.1", - "eslint": "^8.30.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-rxjs": "^5.0.2", "eslint-plugin-rxjs-angular": "^2.0.0", "eslint-plugin-unicorn": "^45.0.2", "jest": "^29.3.1", "lodash": "^4.17.21", - "ts-jest": "^29.0.3", - "typescript": "~4.8.2" + "ts-jest": "^29.0.5", + "typescript": "~4.9.4" } } diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 72d59dba0..ab0bba4a3 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -1,6 +1,7 @@ import { NgModule } from '@angular/core'; import type { Routes } from '@angular/router'; import { RouterModule } from '@angular/router'; +import { AboutModule } from './pages/about/about.module'; import { Error404Component } from './pages/error-404/error-404.component'; import { HealthPageComponent } from './pages/health/health-page/health-page.component'; import { LandingPageComponent } from './pages/landing-page/landing-page/landing-page.component'; @@ -10,6 +11,10 @@ const routes: Routes = [ path: '', component: LandingPageComponent, }, + { + path: 'about', + loadChildren: () => AboutModule, + }, { path: 'exercises', // eslint-disable-next-line @typescript-eslint/promise-function-async diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 8489d7e93..3a649cb7c 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -15,6 +15,7 @@ import { LandingPageModule } from './pages/landing-page/landing-page.module'; import { SharedModule } from './shared/shared.module'; import { appReducers } from './state/app.reducer'; import type { AppState } from './state/app.state'; +import { AboutModule } from './pages/about/about.module'; @NgModule({ declarations: [AppComponent, HealthPageComponent], @@ -30,6 +31,7 @@ import type { AppState } from './state/app.state'; SharedModule, ConfirmationModalModule, MessagesModule, + AboutModule, ], providers: [], bootstrap: [AppComponent], diff --git a/frontend/src/app/core/exercise.service.ts b/frontend/src/app/core/exercise.service.ts index a64c2aeb4..2e9de72de 100644 --- a/frontend/src/app/core/exercise.service.ts +++ b/frontend/src/app/core/exercise.service.ts @@ -54,28 +54,11 @@ export class ExerciseService { ...socketIoTransports, }); - private readonly optimisticActionHandler = new OptimisticActionHandler< + private optimisticActionHandler?: OptimisticActionHandler< ExerciseAction, ExerciseState, SocketResponse - >( - (exercise) => - this.store.dispatch(createSetExerciseStateAction(exercise)), - () => selectStateSnapshot(selectExerciseState, this.store), - (action) => this.store.dispatch(createApplyServerActionAction(action)), - async (action) => { - const response = await new Promise((resolve) => { - this.socket.emit('proposeAction', action, resolve); - }); - if (!response.success) { - this.messageService.postError({ - title: 'Fehler beim Senden der Aktion', - error: response.message, - }); - } - return response; - } - ); + >; constructor( private readonly store: Store, @@ -83,7 +66,7 @@ export class ExerciseService { ) { this.socket.on('performAction', (action: ExerciseAction) => { freeze(action, true); - this.optimisticActionHandler.performAction(action); + this.optimisticActionHandler?.performAction(action); }); this.socket.on('disconnect', (reason) => { if (reason === 'io client disconnect') { @@ -156,7 +139,32 @@ export class ExerciseService { clientName ) ); - // Only start them after the correct state is in the store + // Only do this after the correct state is in the store + this.optimisticActionHandler = new OptimisticActionHandler< + ExerciseAction, + ExerciseState, + SocketResponse + >( + (exercise) => + this.store.dispatch(createSetExerciseStateAction(exercise)), + () => selectStateSnapshot(selectExerciseState, this.store), + (action) => + this.store.dispatch(createApplyServerActionAction(action)), + async (action) => { + const response = await new Promise( + (resolve) => { + this.socket.emit('proposeAction', action, resolve); + } + ); + if (!response.success) { + this.messageService.postError({ + title: 'Fehler beim Senden der Aktion', + error: response.message, + }); + } + return response; + } + ); this.startNotifications(); return true; } @@ -167,6 +175,7 @@ export class ExerciseService { public leaveExercise() { this.socket.disconnect(); this.stopNotifications(); + this.optimisticActionHandler = undefined; this.store.dispatch(createLeaveExerciseAction()); } @@ -178,7 +187,8 @@ export class ExerciseService { public async proposeAction(action: ExerciseAction, optimistic = false) { if ( selectStateSnapshot(selectExerciseStateMode, this.store) !== - 'exercise' + 'exercise' || + this.optimisticActionHandler === undefined ) { // Especially during timeTravel, buttons that propose actions are only deactivated via best effort this.messageService.postError({ diff --git a/frontend/src/app/core/messages/message.service.ts b/frontend/src/app/core/messages/message.service.ts index b95244001..20a23727d 100644 --- a/frontend/src/app/core/messages/message.service.ts +++ b/frontend/src/app/core/messages/message.service.ts @@ -84,7 +84,7 @@ export class MessageService { ...(type === 'toast' ? this.toastMessages : this.alertMessages), ]; // Set/update the newest message - let newestMessage: Message | undefined = messages[messages.length - 1]; + let newestMessage: Message | undefined = messages.at(-1); if (!newestMessage || !isEqual(newestMessage.config, config)) { newestMessage = new Message(config, timeout); firstValueFrom(newestMessage.destroyed$).then(() => { diff --git a/frontend/src/app/core/time-travel-helper.ts b/frontend/src/app/core/time-travel-helper.ts index c96909420..b964e11eb 100644 --- a/frontend/src/app/core/time-travel-helper.ts +++ b/frontend/src/app/core/time-travel-helper.ts @@ -38,9 +38,6 @@ export class TimeTravelHelper { * @param exerciseTime The time to travel to, if it isn't in the timeConstraints, it will be clamped appropriately */ public async jumpToTime(exerciseTime: number): Promise { - if (!this.timeConstraints || !this.timeJumpHelper) { - throw new Error('Start the time travel before jumping to a time!'); - } const clampedTime = Math.max( this.timeConstraints.start, Math.min(this.timeConstraints.end, exerciseTime) diff --git a/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.html b/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.html new file mode 100644 index 000000000..6d37bf282 --- /dev/null +++ b/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.html @@ -0,0 +1,29 @@ +
+

Digitale FüSim MANV

+

{{ pageTitle }}

+ +

+ Zurück zur vorherigen Seite | + Zur Startseite +

+ +
+ +

+ Sie können den Inhalt der Seite unter + frontend/src/assets/about/{{ contentFile }} bearbeiten. +

+

+ Falls Sie das Docker-Deployment verwenden, finden Sie in der + docker-compose.yml Beispiel-Datei eine Anleitung, wie + Sie Inhalte für diese Seite bereitstellen können. +

+
+ +
+ +
+
diff --git a/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.scss b/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.ts b/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.ts new file mode 100644 index 000000000..2a15041b0 --- /dev/null +++ b/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.ts @@ -0,0 +1,45 @@ +import { Location as NgLocation } from '@angular/common'; +import { HttpClient } from '@angular/common/http'; +import type { OnInit } from '@angular/core'; +import { Component, Input } from '@angular/core'; +import type { Observable } from 'rxjs'; + +@Component({ + selector: 'app-about-placeholder', + templateUrl: './about-placeholder.component.html', + styleUrls: ['./about-placeholder.component.scss'], +}) +export class AboutPlaceholderComponent implements OnInit { + content$!: Observable; + + /** + * The title of the page shown as h2 headline. + */ + @Input() pageTitle = ''; + + /** + * The filename in the assets/about/ directory where the page content should be loaded from. + */ + @Input() contentFile = ''; + + constructor( + private readonly location: NgLocation, + private readonly http: HttpClient + ) {} + + ngOnInit(): void { + this.content$ = this.http.get(`assets/about/${this.contentFile}`, { + responseType: 'text', + }); + } + + back(event: MouseEvent): void { + event.preventDefault(); + + if (history.length > 1) { + this.location.back(); + } else { + window.close(); + } + } +} diff --git a/frontend/src/app/pages/about/about-routing.module.ts b/frontend/src/app/pages/about/about-routing.module.ts new file mode 100644 index 000000000..8da5c5cf8 --- /dev/null +++ b/frontend/src/app/pages/about/about-routing.module.ts @@ -0,0 +1,32 @@ +import { NgModule } from '@angular/core'; +import type { Routes } from '@angular/router'; +import { RouterModule } from '@angular/router'; +import { ImprintComponent } from './imprint/imprint.component'; +import { LicenseComponent } from './license/license.component'; +import { PrivacyComponent } from './privacy/privacy.component'; + +const routes: Routes = [ + { + path: 'imprint', + component: ImprintComponent, + }, + { + path: 'license', + component: LicenseComponent, + }, + { + path: 'privacy', + component: PrivacyComponent, + }, + { + path: '', + redirectTo: 'imprint', + pathMatch: 'full', + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class AboutRoutingModule {} diff --git a/frontend/src/app/pages/about/about.module.ts b/frontend/src/app/pages/about/about.module.ts new file mode 100644 index 000000000..8166f0aad --- /dev/null +++ b/frontend/src/app/pages/about/about.module.ts @@ -0,0 +1,20 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { SharedModule } from 'src/app/shared/shared.module'; +import { AboutRoutingModule } from './about-routing.module'; +import { ImprintComponent } from './imprint/imprint.component'; +import { PrivacyComponent } from './privacy/privacy.component'; +import { LicenseComponent } from './license/license.component'; +import { AboutPlaceholderComponent } from './about-placeholder/about-placeholder.component'; + +@NgModule({ + declarations: [ + ImprintComponent, + PrivacyComponent, + LicenseComponent, + AboutPlaceholderComponent, + ], + imports: [CommonModule, AboutRoutingModule, SharedModule], +}) +export class AboutModule {} diff --git a/frontend/src/app/pages/about/imprint/imprint.component.html b/frontend/src/app/pages/about/imprint/imprint.component.html new file mode 100644 index 000000000..c5b47d09f --- /dev/null +++ b/frontend/src/app/pages/about/imprint/imprint.component.html @@ -0,0 +1 @@ + diff --git a/frontend/src/app/pages/about/imprint/imprint.component.scss b/frontend/src/app/pages/about/imprint/imprint.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/pages/about/imprint/imprint.component.ts b/frontend/src/app/pages/about/imprint/imprint.component.ts new file mode 100644 index 000000000..7acdad8f7 --- /dev/null +++ b/frontend/src/app/pages/about/imprint/imprint.component.ts @@ -0,0 +1,8 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-imprint', + templateUrl: './imprint.component.html', + styleUrls: ['./imprint.component.scss'], +}) +export class ImprintComponent {} diff --git a/frontend/src/app/pages/about/license/license.component.html b/frontend/src/app/pages/about/license/license.component.html new file mode 100644 index 000000000..b9b0839ed --- /dev/null +++ b/frontend/src/app/pages/about/license/license.component.html @@ -0,0 +1 @@ + diff --git a/frontend/src/app/pages/about/license/license.component.scss b/frontend/src/app/pages/about/license/license.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/pages/about/license/license.component.ts b/frontend/src/app/pages/about/license/license.component.ts new file mode 100644 index 000000000..8b2641fc9 --- /dev/null +++ b/frontend/src/app/pages/about/license/license.component.ts @@ -0,0 +1,8 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-license', + templateUrl: './license.component.html', + styleUrls: ['./license.component.scss'], +}) +export class LicenseComponent {} diff --git a/frontend/src/app/pages/about/privacy/privacy.component.html b/frontend/src/app/pages/about/privacy/privacy.component.html new file mode 100644 index 000000000..d24c3b101 --- /dev/null +++ b/frontend/src/app/pages/about/privacy/privacy.component.html @@ -0,0 +1 @@ + diff --git a/frontend/src/app/pages/about/privacy/privacy.component.scss b/frontend/src/app/pages/about/privacy/privacy.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/pages/about/privacy/privacy.component.ts b/frontend/src/app/pages/about/privacy/privacy.component.ts new file mode 100644 index 000000000..4a584f5c6 --- /dev/null +++ b/frontend/src/app/pages/about/privacy/privacy.component.ts @@ -0,0 +1,8 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-privacy', + templateUrl: './privacy.component.html', + styleUrls: ['./privacy.component.scss'], +}) +export class PrivacyComponent {} diff --git a/frontend/src/app/pages/error-404/error-404.component.html b/frontend/src/app/pages/error-404/error-404.component.html index ecb51e696..511d339e9 100644 --- a/frontend/src/app/pages/error-404/error-404.component.html +++ b/frontend/src/app/pages/error-404/error-404.component.html @@ -12,5 +12,9 @@

Seite nicht gefunden!

+ +
+ +
diff --git a/frontend/src/app/pages/error-404/error-404.module.ts b/frontend/src/app/pages/error-404/error-404.module.ts index 5262349dc..94b04865c 100644 --- a/frontend/src/app/pages/error-404/error-404.module.ts +++ b/frontend/src/app/pages/error-404/error-404.module.ts @@ -1,10 +1,11 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; +import { SharedModule } from 'src/app/shared/shared.module'; import { Error404Component } from './error-404.component'; @NgModule({ - imports: [CommonModule, RouterModule], + imports: [CommonModule, RouterModule, SharedModule], declarations: [Error404Component], exports: [Error404Component], }) diff --git a/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.html b/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.html index b1ae522c6..8d8a06777 100644 --- a/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.html +++ b/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.html @@ -3,7 +3,7 @@ class="p-2 d-flex flex-column" style="height: 100vh" > -
+

Übung: {{ @@ -36,34 +36,70 @@

Übung wieder beitreten -
- - -
+
+
- + +
+ + +
+
+ + Feedback + +

diff --git a/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.ts b/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.ts index c856ac27e..bfdbc7e2d 100644 --- a/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.ts +++ b/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.ts @@ -23,6 +23,7 @@ import { } from 'src/app/state/application/selectors/exercise.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import { selectOwnClient } from 'src/app/state/application/selectors/shared.selectors'; +import Package from 'package.json'; @Component({ selector: 'app-exercise', @@ -39,6 +40,8 @@ export class ExerciseComponent implements OnDestroy { public readonly timeConstraints$ = this.store.select(selectTimeConstraints); public readonly ownClient$ = this.store.select(selectOwnClient); + readonly version: string = Package.version; + constructor( private readonly store: Store, private readonly apiService: ApiService, diff --git a/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts b/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts index 532ee10d0..a813a6f22 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts @@ -1,8 +1,11 @@ import { Injectable } from '@angular/core'; import { Store } from '@ngrx/store'; import type { + // eslint-disable-next-line @typescript-eslint/no-shadow + Element, ImageProperties, MapImageTemplate, + PatientCategory, VehicleTemplate, } from 'digital-fuesim-manv-shared'; import { @@ -12,9 +15,14 @@ import { PatientTemplate, TransferPoint, Viewport, + SimulatedRegion, + MapPosition, } from 'digital-fuesim-manv-shared'; -import type { PatientCategory } from 'digital-fuesim-manv-shared/dist/models/patient-category'; +import type { Feature } from 'ol'; +import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; +import type { Pixel } from 'ol/pixel'; +import type VectorSource from 'ol/source/Vector'; import { ExerciseService } from 'src/app/core/exercise.service'; import type { AppState } from 'src/app/state/app.state'; import { @@ -22,6 +30,7 @@ import { selectPersonnelTemplates, } from 'src/app/state/application/selectors/exercise.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; +import type { FeatureManager } from '../exercise-map/utility/feature-manager'; @Injectable({ providedIn: 'root', @@ -31,20 +40,37 @@ import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; */ export class DragElementService { private olMap?: OlMap; + layerFeatureManagerDictionary?: Map< + VectorLayer, + FeatureManager + >; constructor( private readonly exerciseService: ExerciseService, private readonly store: Store ) {} - public registerMap(map: OlMap) { - this.olMap = map; + public registerMap(olMap: OlMap) { + this.olMap = olMap; + } + + public registerLayerFeatureManagerDictionary( + layerFeatureManagerDictionary: Map< + VectorLayer, + FeatureManager + > + ) { + this.layerFeatureManagerDictionary = layerFeatureManagerDictionary; } public unregisterMap() { this.olMap = undefined; } + public unregisterLayerFeatureManagerDictionary() { + this.layerFeatureManagerDictionary = undefined; + } + private dragElement?: HTMLImageElement; private imageDimensions?: { width: number; height: number }; private transferringTemplate?: TransferTemplate; @@ -131,31 +157,38 @@ export class DragElementService { return; } // Get the position of the mouse on the map - const [x, y] = this.olMap.getCoordinateFromPixel( - this.olMap.getEventPixel(event) - ) as [number, number]; + const pixel = this.olMap.getEventPixel(event); + const [x, y] = this.olMap.getCoordinateFromPixel(pixel) as [ + number, + number + ]; const position = { x, y }; // create the element + let createdElement: Element | null = null; switch (this.transferringTemplate.type) { case 'vehicle': - this.exerciseService.proposeAction( - { - type: '[Vehicle] Add vehicle', - ...createVehicleParameters( - this.transferringTemplate.template, - selectStateSnapshot( - selectMaterialTemplates, - this.store - ), - selectStateSnapshot( - selectPersonnelTemplates, - this.store - ), - position + { + const params = createVehicleParameters( + this.transferringTemplate.template, + selectStateSnapshot( + selectMaterialTemplates, + this.store ), - }, - true - ); + selectStateSnapshot( + selectPersonnelTemplates, + this.store + ), + position + ); + this.exerciseService.proposeAction( + { + ...params, + type: '[Vehicle] Add vehicle', + }, + true + ); + createdElement = params.vehicle; + } break; case 'patient': { @@ -167,72 +200,141 @@ export class DragElementService { .patientTemplates.length ) ]!, - this.transferringTemplate.template.name + this.transferringTemplate.template.name, + MapPosition.create(position) ); this.exerciseService.proposeAction( { type: '[Patient] Add patient', - patient: { - ...patient, - position, - }, + patient, }, true ); + createdElement = patient; } break; - case 'viewport': { - // This ratio has been determined by trial and error - const height = Viewport.image.height / 23.5; - const width = height * Viewport.image.aspectRatio; - this.exerciseService.proposeAction( - { - type: '[Viewport] Add viewport', - viewport: Viewport.create( - { - x: position.x - width / 2, - y: position.y + height / 2, - }, - { - height, - width, - }, - 'Einsatzabschnitt' - ), - }, - true - ); + case 'viewport': + { + // This ratio has been determined by trial and error + const height = Viewport.image.height / 23.5; + const width = height * Viewport.image.aspectRatio; + const viewport = Viewport.create( + { + x: position.x - width / 2, + y: position.y + height / 2, + }, + { + height, + width, + }, + 'Einsatzabschnitt' + ); + this.exerciseService.proposeAction( + { + type: '[Viewport] Add viewport', + viewport, + }, + true + ); + createdElement = viewport; + } break; - } + case 'mapImage': { const template = this.transferringTemplate.template.image; + const mapImage = MapImage.create( + position, + template, + false, + 0 + ); this.exerciseService.proposeAction({ type: '[MapImage] Add MapImage', - mapImage: MapImage.create(position, template, false, 0), + mapImage, }); + createdElement = mapImage; } break; case 'transferPoint': - this.exerciseService.proposeAction( - { - type: '[TransferPoint] Add TransferPoint', - transferPoint: TransferPoint.create( - position, - {}, - {}, - '???', - '???' - ), - }, - true - ); + { + const transferPoint = TransferPoint.create( + position, + {}, + {}, + '???', + '???' + ); + this.exerciseService.proposeAction( + { + type: '[TransferPoint] Add TransferPoint', + transferPoint, + }, + true + ); + createdElement = transferPoint; + } break; + case 'simulatedRegion': + { + // This ratio has been determined by trial and error + const height = SimulatedRegion.image.height / 23.5; + const width = height * SimulatedRegion.image.aspectRatio; + const simulatedRegion = SimulatedRegion.create( + { + x: position.x - width / 2, + y: position.y + height / 2, + }, + { + height, + width, + }, + 'Einsatzabschnitt ???' + ); + this.exerciseService.proposeAction( + { + type: '[SimulatedRegion] Add simulated region', + simulatedRegion, + }, + true + ); + createdElement = simulatedRegion; + } + break; + default: break; } + + this.executeDropSideEffects(pixel, createdElement); }; + private executeDropSideEffects( + pixel: Pixel, + createdElement: Element | null + ) { + if ( + createdElement === null || + !this.olMap || + !this.layerFeatureManagerDictionary + ) { + return; + } + this.olMap.forEachFeatureAtPixel(pixel, (droppedOnFeature, layer) => { + // Skip layer when unset + if (layer === null || !this.layerFeatureManagerDictionary) { + return; + } + // We stop propagating the event as soon as the onFeatureDropped function returns true + return this.layerFeatureManagerDictionary + .get(layer as VectorLayer)! + .onFeatureDrop( + createdElement as Element, + droppedOnFeature as Feature + ); + }); + } + /** * * @returns wether {@link coordinates} are in {@link element} @@ -260,6 +362,12 @@ type TransferTemplate = type: 'patient'; template: PatientCategory; } + | { + type: 'simulatedRegion'; + template: { + image: ImageProperties; + }; + } | { type: 'transferPoint'; template: { diff --git a/frontend/src/app/pages/exercises/exercise/shared/core/statistics/statistics.service.ts b/frontend/src/app/pages/exercises/exercise/shared/core/statistics/statistics.service.ts index 530c82ddb..dc54695d2 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/core/statistics/statistics.service.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/core/statistics/statistics.service.ts @@ -1,17 +1,21 @@ import { Injectable } from '@angular/core'; import { Store } from '@ngrx/store'; +import { + isNotInVehicle, + currentCoordinatesOf, + isOnMap, + loopTroughTime, + uuid, + Viewport, + isNotInTransfer, +} from 'digital-fuesim-manv-shared'; import type { + Personnel, Client, ExerciseState, Patient, Vehicle, } from 'digital-fuesim-manv-shared'; -import { - loopTroughTime, - Personnel, - uuid, - Viewport, -} from 'digital-fuesim-manv-shared'; import { countBy } from 'lodash-es'; import { ReplaySubject } from 'rxjs'; import { ApiService } from 'src/app/core/api.service'; @@ -108,18 +112,27 @@ export class StatisticsService { ), Object.values(draftState.patients).filter( (patient) => - patient.position && - Viewport.isInViewport(viewport, patient.position) + isOnMap(patient) && + Viewport.isInViewport( + viewport, + currentCoordinatesOf(patient) + ) ), Object.values(draftState.vehicles).filter( (vehicle) => - vehicle.position && - Viewport.isInViewport(viewport, vehicle.position) + isOnMap(vehicle) && + Viewport.isInViewport( + viewport, + currentCoordinatesOf(vehicle) + ) ), Object.values(draftState.personnel).filter( (personnel) => - personnel.position && - Viewport.isInViewport(viewport, personnel.position) + isOnMap(personnel) && + Viewport.isInViewport( + viewport, + currentCoordinatesOf(personnel) + ) ) ), ]) @@ -148,8 +161,8 @@ export class StatisticsService { personnel: countBy( personnel.filter( (_personnel) => - !Personnel.isInVehicle(_personnel) && - _personnel.transfer === undefined + isNotInVehicle(_personnel) && + isNotInTransfer(_personnel) ), (_personnel) => _personnel.personnelType ), diff --git a/frontend/src/app/pages/exercises/exercise/shared/editor-panel/create-image-template-modal/create-image-template-modal.component.ts b/frontend/src/app/pages/exercises/exercise/shared/editor-panel/create-image-template-modal/create-image-template-modal.component.ts index 11a6aead7..134360443 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/editor-panel/create-image-template-modal/create-image-template-modal.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/editor-panel/create-image-template-modal/create-image-template-modal.component.ts @@ -35,6 +35,7 @@ export class CreateImageTemplateModalComponent { type: '[MapImageTemplate] Add mapImageTemplate', mapImageTemplate: { id: uuid(), + type: 'mapImageTemplate', image: { url, height, diff --git a/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts b/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts index ef6929b26..0b70f0a33 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts @@ -3,6 +3,7 @@ import { Component } from '@angular/core'; import { Store } from '@ngrx/store'; import type { AlarmGroup, UUID } from 'digital-fuesim-manv-shared'; import { + MapCoordinates, AlarmGroupStartPoint, createVehicleParameters, TransferPoint, @@ -94,7 +95,15 @@ export class SendAlarmGroupInterfaceComponent implements OnDestroy { selectStateSnapshot( selectPersonnelTemplates, this.store - ) + ), + // TODO: This position is not correct but needs to be provided. + // Here one should use a Position with the Transfer. + // But this is part of later Refactoring. + // We need the Transfer to be created before the Vehicle is created, + // else we need to provide a Position that is immediately overwritten by the Add to Transfer Action. + // This is done here + // Good Thing is, it is irrelevant, because the correctPosition is set immediately after this is called. + MapCoordinates.create(0, 0) ); return [ @@ -106,7 +115,7 @@ export class SendAlarmGroupInterfaceComponent implements OnDestroy { }), this.exerciseService.proposeAction({ type: '[Transfer] Add to transfer', - elementType: 'vehicles', + elementType: vehicleParameters.vehicle.type, elementId: vehicleParameters.vehicle.id, startPoint: AlarmGroupStartPoint.create( alarmGroup.name, diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.html b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.html index 53b241efb..917f38959 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.html +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.html @@ -25,7 +25,7 @@ (currentRole$ | async) !== 'participant' && (restrictedToViewport$ | async) === undefined " - (click)="olMapManager?.tryToFitViewToViewports()" + (click)="olMapManager?.tryToFitViewForOverview()" class="btn btn-sm btn-light" title="Alle Ansichten anzeigen" > diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.ts index 3064e3746..3e17cc37e 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.ts @@ -49,23 +49,27 @@ export class ExerciseMapComponent implements AfterViewInit, OnDestroy { ) {} ngAfterViewInit(): void { + this.popupManager = new PopupManager( + this.popoverContent, + this.popoverContainer.nativeElement + ); // run outside angular zone for better performance this.ngZone.runOutsideAngular(() => { this.olMapManager = new OlMapManager( this.store, this.exerciseService, this.openLayersContainer.nativeElement, - this.popoverContainer.nativeElement, this.ngZone, - this.transferLinesService + this.transferLinesService, + this.popupManager! ); this.dragElementService.registerMap(this.olMapManager.olMap); + this.dragElementService.registerLayerFeatureManagerDictionary( + this.olMapManager.layerFeatureManagerDictionary + ); }); - this.popupManager = new PopupManager( - this.olMapManager!.popupOverlay, - this.popoverContent - ); - this.olMapManager!.changePopup$.pipe( + + this.popupManager!.changePopup$.pipe( takeUntil(this.destroy$) ).subscribe((options) => { // Because changePopup$ is coming from outside the angular zone, we need to wrap it in a zone @@ -98,5 +102,6 @@ export class ExerciseMapComponent implements AfterViewInit, OnDestroy { ngOnDestroy(): void { this.destroy$.next(); this.dragElementService.unregisterMap(); + this.dragElementService.unregisterLayerFeatureManagerDictionary(); } } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.module.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.module.ts index 64b114b16..d95b361d1 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.module.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.module.ts @@ -14,6 +14,7 @@ import { ViewportPopupComponent } from './shared/viewport-popup/viewport-popup.c import { PersonnelPopupComponent } from './shared/personnel-popup/personnel-popup.component'; import { MaterialPopupComponent } from './shared/material-popup/material-popup.component'; import { CaterCapacityComponent } from './shared/cater-capacity/cater-capacity.component'; +import { SimulatedRegionPopupComponent } from './shared/simulated-region-popup/simulated-region-popup.component'; @NgModule({ declarations: [ @@ -27,6 +28,7 @@ import { CaterCapacityComponent } from './shared/cater-capacity/cater-capacity.c PersonnelPopupComponent, MaterialPopupComponent, CaterCapacityComponent, + SimulatedRegionPopupComponent, ], imports: [ CommonModule, diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts index 388e360ee..d122347e4 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts @@ -1,40 +1,68 @@ +import type { Type, NgZone } from '@angular/core'; +import type { Store } from '@ngrx/store'; import type { MapBrowserEvent } from 'ol'; import { Feature } from 'ol'; import LineString from 'ol/geom/LineString'; import type { TranslateEvent } from 'ol/interaction/Translate'; import type VectorLayer from 'ol/layer/Vector'; import type VectorSource from 'ol/source/Vector'; +import type { Subject } from 'rxjs'; import { rgbColorPalette } from 'src/app/shared/functions/colors'; import type { CateringLine } from 'src/app/shared/types/catering-line'; +import type { AppState } from 'src/app/state/app.state'; +import { selectVisibleCateringLines } from 'src/app/state/application/selectors/shared.selectors'; +import type OlMap from 'ol/Map'; +// eslint-disable-next-line @typescript-eslint/no-shadow +import type { Element } from 'digital-fuesim-manv-shared'; import type { FeatureManager } from '../utility/feature-manager'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; +import type { OpenPopupOptions } from '../utility/popup-manager'; import { LineStyleHelper } from '../utility/style-helper/line-style-helper'; import { ElementManager } from './element-manager'; export class CateringLinesFeatureManager - extends ElementManager< - CateringLine, - LineString, - Feature, - ReadonlySet - > - implements FeatureManager> + extends ElementManager + implements FeatureManager { - readonly type = 'cateringLines'; - readonly unsupportedChangeProperties = new Set(['id'] as const); - private readonly lineStyleHelper = new LineStyleHelper( (feature) => ({ color: rgbColorPalette.cyan, }), 0.05 ); + public readonly layer: VectorLayer>; - constructor(public readonly layer: VectorLayer>) { + constructor( + private readonly store: Store, + private readonly olMap: OlMap + ) { super(); - layer.setStyle((feature, currentZoom) => + this.layer = super.createElementLayer(); + this.layer.setStyle((feature, currentZoom) => this.lineStyleHelper.getStyle(feature as Feature, currentZoom) ); } + togglePopup$?: Subject>> | undefined; + register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ) { + this.olMap.addLayer(this.layer); + mapInteractionsManager.addFeatureLayer(this.layer); + this.togglePopup$?.subscribe(changePopup$); + // Propagate the changes on an element to the featureManager + this.registerChangeHandlers( + this.store.select(selectVisibleCateringLines), + destroy$, + ngZone, + (element) => this.onElementCreated(element), + (element) => this.onElementDeleted(element), + (oldElement, newElement) => + this.onElementChanged(oldElement, newElement) + ); + } public isFeatureTranslatable(feature: Feature) { return false; @@ -84,9 +112,9 @@ export class CateringLinesFeatureManager ) {} onFeatureDrop( - dropEvent: TranslateEvent, - droppedFeature: Feature, - droppedOnFeature: Feature + droppedElement: Element, + droppedOnFeature: Feature, + dropEvent?: TranslateEvent ) { return false; } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts index 79938177d..aa517f222 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts @@ -1,33 +1,60 @@ +import type { Type, NgZone } from '@angular/core'; import type { Store } from '@ngrx/store'; -import type { UUID } from 'digital-fuesim-manv-shared'; import type { MapBrowserEvent, View } from 'ol'; import { Feature } from 'ol'; import { getTopRight } from 'ol/extent'; import { Point } from 'ol/geom'; import type { TranslateEvent } from 'ol/interaction/Translate'; -import type VectorLayer from 'ol/layer/Vector'; +import VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; +import VectorSource from 'ol/source/Vector'; import Icon from 'ol/style/Icon'; import Style from 'ol/style/Style'; +import type { Subject } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; import type { AppState } from 'src/app/state/app.state'; -import { selectExerciseState } from 'src/app/state/application/selectors/exercise.selectors'; +import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; +// eslint-disable-next-line @typescript-eslint/no-shadow +import type { Element } from 'digital-fuesim-manv-shared'; import type { FeatureManager } from '../utility/feature-manager'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; +import type { OpenPopupOptions } from '../utility/popup-manager'; function calculateTopRightViewPoint(view: View) { const extent = getTopRight(view.calculateExtent()); return new Point([extent[0]!, extent[1]!]); } -export class DeleteFeatureManager implements FeatureManager> { +export class DeleteFeatureManager implements FeatureManager { + readonly layer: VectorLayer>; constructor( private readonly store: Store, - public readonly layer: VectorLayer>, private readonly olMap: OlMap, private readonly exerciseService: ExerciseService ) { + this.layer = new VectorLayer({ + // These two settings prevent clipping during animation/interaction but cause a performance hit -> disable if needed + updateWhileAnimating: true, + updateWhileInteracting: true, + renderBuffer: 250, + source: new VectorSource(), + }); + } + togglePopup$?: Subject>> | undefined; + register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ) { + this.olMap.addLayer(this.layer); + mapInteractionsManager.addFeatureLayer(this.layer); + if (selectStateSnapshot(selectCurrentRole, this.store) === 'trainer') { + this.makeVisible(); + } + } + public makeVisible() { this.layer.setStyle( new Style({ image: new Icon({ @@ -49,6 +76,7 @@ export class DeleteFeatureManager implements FeatureManager> { ); }); } + public onFeatureClicked( event: MapBrowserEvent, feature: Feature @@ -60,51 +88,57 @@ export class DeleteFeatureManager implements FeatureManager> { } public onFeatureDrop( - dropEvent: TranslateEvent, - droppedFeature: Feature, - droppedOnFeature: Feature + droppedElement: Element, + droppedOnFeature: Feature, + dropEvent?: TranslateEvent ) { - const id = droppedFeature.getId() as UUID; - const exerciseState = selectStateSnapshot( - selectExerciseState, - this.store - ); - // We expect the id to be globally unique - if (exerciseState.patients[id]) { - this.exerciseService.proposeAction({ - type: '[Patient] Remove patient', - patientId: id, - }); - return true; - } - if (exerciseState.vehicles[id]) { - this.exerciseService.proposeAction({ - type: '[Vehicle] Remove vehicle', - vehicleId: id, - }); - return true; - } - if (exerciseState.mapImages[id]) { - this.exerciseService.proposeAction({ - type: '[MapImage] Remove MapImage', - mapImageId: id, - }); - return true; + const id = droppedElement.id; + switch (droppedElement.type) { + case 'patient': { + this.exerciseService.proposeAction({ + type: '[Patient] Remove patient', + patientId: id, + }); + return true; + } + case 'vehicle': { + this.exerciseService.proposeAction({ + type: '[Vehicle] Remove vehicle', + vehicleId: id, + }); + return true; + } + case 'mapImage': { + this.exerciseService.proposeAction({ + type: '[MapImage] Remove MapImage', + mapImageId: id, + }); + return true; + } + case 'viewport': { + this.exerciseService.proposeAction({ + type: '[Viewport] Remove viewport', + viewportId: id, + }); + return true; + } + case 'transferPoint': { + this.exerciseService.proposeAction({ + type: '[TransferPoint] Remove TransferPoint', + transferPointId: id, + }); + return true; + } + case 'simulatedRegion': { + this.exerciseService.proposeAction({ + type: '[SimulatedRegion] Remove simulated region', + simulatedRegionId: id, + }); + return true; + } + default: { + return false; + } } - if (exerciseState.viewports[id]) { - this.exerciseService.proposeAction({ - type: '[Viewport] Remove viewport', - viewportId: id, - }); - return true; - } - if (exerciseState.transferPoints[id]) { - this.exerciseService.proposeAction({ - type: '[TransferPoint] Remove TransferPoint', - transferPointId: id, - }); - return true; - } - return false; } } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-feature-manager.ts deleted file mode 100644 index 6d817ddfe..000000000 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-feature-manager.ts +++ /dev/null @@ -1,197 +0,0 @@ -import type { - ExerciseState, - Position, - Size, - UUID, -} from 'digital-fuesim-manv-shared'; -import { isArray } from 'lodash-es'; -import type { MapBrowserEvent } from 'ol'; -import { Feature } from 'ol'; -import type { Coordinate } from 'ol/coordinate'; -import { LineString } from 'ol/geom'; -import Point from 'ol/geom/Point'; -import type { TranslateEvent } from 'ol/interaction/Translate'; -import type VectorLayer from 'ol/layer/Vector'; -import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; -import { Subject } from 'rxjs'; -import type { WithPosition } from '../../utility/types/with-position'; -import type { FeatureManager } from '../utility/feature-manager'; -import type { Coordinates } from '../utility/movement-animator'; -import { MovementAnimator } from '../utility/movement-animator'; -import type { OpenPopupOptions } from '../utility/popup-manager'; -import { TranslateInteraction } from '../utility/translate-interaction'; -import { ElementManager } from './element-manager'; - -export interface PositionableElement { - readonly id: UUID; - readonly position: Position; -} - -export interface ResizableElement extends PositionableElement { - size: Size; -} - -function isLineString( - feature: Feature -): feature is Feature { - return feature.getGeometry()!.getType() === 'LineString'; -} - -export function isCoordinateArray( - coordinates: Coordinate | Coordinate[] -): coordinates is Coordinate[] { - return isArray(coordinates[0]); -} - -export const createPoint = (element: WithPosition): Feature => - new Feature(new Point([element.position.x, element.position.y])); - -export const createLineString = ( - element: ResizableElement -): Feature => - new Feature(new LineString(getCoordinateArray(element))); - -export function getCoordinateArray(element: ResizableElement) { - return [ - [element.position.x, element.position.y], - [element.position.x + element.size.width, element.position.y], - [ - element.position.x + element.size.width, - element.position.y - element.size.height, - ], - [element.position.x, element.position.y - element.size.height], - [element.position.x, element.position.y], - ]; -} - -/** - * The base class for all element feature managers. - * * manages the position of the element - * * manages the default interactions of the element - */ -export abstract class ElementFeatureManager< - Element extends PositionableElement, - FeatureType extends LineString | Point = Point, - ElementFeature extends Feature = Feature - > - extends ElementManager< - Element, - FeatureType, - ElementFeature, - ReadonlySet - > - implements FeatureManager -{ - abstract override readonly type: keyof ExerciseState; - public readonly togglePopup$ = new Subject>(); - protected readonly movementAnimator = new MovementAnimator( - this.olMap, - this.layer - ); - constructor( - protected readonly olMap: OlMap, - public readonly layer: VectorLayer>, - private readonly proposeMovementAction: ( - newPosition: FeatureType extends Point ? Position : Position[], - element: Element - ) => void, - private readonly createElement: (element: Element) => ElementFeature - ) { - super(); - } - - override unsupportedChangeProperties: ReadonlySet = new Set( - [] as const - ); - createFeature(element: Element): ElementFeature { - const elementFeature = this.createElement(element); - elementFeature.setId(element.id); - this.layer.getSource()!.addFeature(elementFeature); - TranslateInteraction.onTranslateEnd( - elementFeature, - (newPosition) => { - this.proposeMovementAction(newPosition, element); - } - ); - return elementFeature; - } - - isFeatureTranslatable(feature: ElementFeature) { - return true; - } - - deleteFeature(element: Element, elementFeature: ElementFeature): void { - this.layer.getSource()!.removeFeature(elementFeature); - this.movementAnimator.stopMovementAnimation(elementFeature); - } - - changeFeature( - oldElement: Element, - newElement: Element, - // It is too much work to correctly type this param with {@link unsupportedChangeProperties} - changedProperties: ReadonlySet, - elementFeature: ElementFeature - ): void { - if (changedProperties.has('position')) { - const newFeature = this.getFeatureFromElement(newElement); - if (!newFeature) { - throw new TypeError('newFeature undefined'); - } - this.movementAnimator.animateFeatureMovement( - elementFeature, - (isLineString(newFeature) - ? (newFeature.getGeometry()! as LineString).getCoordinates() - : [ - newElement.position.x, - newElement.position.y, - ]) as Coordinates - ); - } - // If the style has updated, we need to redraw the feature - elementFeature.changed(); - } - - getFeatureFromElement(element: Element): ElementFeature | undefined { - return ( - (this.layer - .getSource()! - .getFeatureById(element.id) as ElementFeature | null) ?? - undefined - ); - } - - public getCenter(feature: ElementFeature): Coordinate { - const coordinates = feature.getGeometry()!.getCoordinates(); - if (!isCoordinateArray(coordinates)) { - return coordinates; - } - // We need index 0 and 2 for the center - if (coordinates.length < 3) { - throw new Error(`Unexpectedly short array: ${coordinates}`); - } - return [ - coordinates[0]![0]! + - (coordinates[2]![0]! - coordinates[0]![0]!) / 2, - coordinates[0]![1]! + - (coordinates[2]![1]! - coordinates[0]![1]!) / 2, - ]; - } - - public onFeatureClicked( - event: MapBrowserEvent, - feature: ElementFeature - // eslint-disable-next-line @typescript-eslint/no-empty-function - ): void {} - - /** - * The standard implementation is to ignore these events. - */ - public onFeatureDrop( - dropEvent: TranslateEvent, - droppedFeature: Feature, - droppedOnFeature: ElementFeature - ): boolean { - return false; - } -} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts index 4fae9eb95..e4ffc9f14 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts @@ -1,37 +1,30 @@ +import type { NgZone } from '@angular/core'; import type { ImmutableJsonObject } from 'digital-fuesim-manv-shared'; import type { Feature } from 'ol'; -import type { LineString, Point } from 'ol/geom'; +import type { Geometry, Point } from 'ol/geom'; +import VectorLayer from 'ol/layer/Vector'; +import VectorSource from 'ol/source/Vector'; +import type { Observable, Subject } from 'rxjs'; +import { pairwise, startWith, takeUntil } from 'rxjs'; +import { handleChanges } from 'src/app/shared/functions/handle-changes'; import { generateChangedProperties } from '../utility/generate-changed-properties'; /** * Provides an Api to update a feature based on changes to an element (patient, vehicle, etc.). * * {@link Element} is the immutable JSON object (Patient, Vehicle, etc.) - * {@link ElementFeature} is the OpenLayers Feature that should be rendered to represent the {@link Element}. + * {@link Feature} is the OpenLayers Feature that should be rendered to represent the {@link Element}. */ export abstract class ElementManager< Element extends ImmutableJsonObject, - FeatureType extends LineString | Point, - ElementFeature extends Feature, - UnsupportedChangeProperties extends ReadonlySet, - SupportedChangeProperties extends Exclude< - ReadonlySet, - UnsupportedChangeProperties - > = Exclude, UnsupportedChangeProperties> + FeatureType extends Geometry > { - /** - * When an element gets (dragged &) dropped, this identifies the type of the dropped element. - * @example `patients` - */ - abstract readonly type: string; - /** * This should be called if a new element is added. */ public onElementCreated(element: Element) { const feature = this.createFeature(element); - feature.set(featureKeys.type, this.type); - feature.set(featureKeys.value, element); + feature.set(featureElementKey, element); } /** @@ -48,10 +41,6 @@ export abstract class ElementManager< /** * This should be called if an element is changed. - * - * The best way to reflect the changes on the feature is mostly to update the already created feature directly. This is done in {@link changeFeature}. - * But, because this requires extra code for each changed property, it is not feasible to do for all properties. - * If any property in {@link unsupportedChangeProperties} has changed, we deleted the old feature and create a new one instead. */ public onElementChanged(oldElement: Element, newElement: Element): void { const elementFeature = this.getFeatureFromElement(oldElement); @@ -64,12 +53,7 @@ export abstract class ElementManager< oldElement, newElement ); - if (!this.areAllPropertiesSupported(changedProperties)) { - this.onElementDeleted(oldElement); - this.onElementCreated(newElement); - return; - } - elementFeature.set(featureKeys.value, newElement); + elementFeature.set(featureElementKey, newElement); this.changeFeature( oldElement, newElement, @@ -78,68 +62,76 @@ export abstract class ElementManager< ); } - public recreateFeature(element: Element) { - this.onElementDeleted(element); - this.onElementCreated(element); - } - /** * Adds a new feature representing the {@link element} to the map. */ - abstract createFeature(element: Element): ElementFeature; + abstract createFeature(element: Element): Feature; /** * Delete the {@link elementFeature} representing the {@link element} from the map. */ abstract deleteFeature( element: Element, - elementFeature: ElementFeature + elementFeature: Feature ): void; /** - * The properties of {@link Element} for which custom changes cannot be handled in {@link changeFeature}. - */ - abstract readonly unsupportedChangeProperties: UnsupportedChangeProperties; - /** - * This method must only be called if no properties in {@link unsupportedChangeProperties} are different between the two elements * @param changedProperties The properties that have changed between the {@link oldElement} and the {@link newElement} * @param elementFeature The openLayers feature that should be updated to reflect the changes */ abstract changeFeature( oldElement: Element, newElement: Element, - changedProperties: SupportedChangeProperties, - elementFeature: ElementFeature + changedProperties: ReadonlySet, + elementFeature: Feature ): void; abstract getFeatureFromElement( element: Element - ): ElementFeature | undefined; + ): Feature | undefined; public getElementFromFeature(feature: Feature) { - return { - type: feature.get(featureKeys.type), - value: feature.get(featureKeys.value), - }; + return feature.get(featureElementKey); + } + /** + * @param renderBuffer The size of the largest symbol, line width or label on the highest zoom level. + */ + protected createElementLayer( + renderBuffer = 250 + ) { + return new VectorLayer({ + // These two settings prevent clipping during animation/interaction but cause a performance hit -> disable if needed + updateWhileAnimating: true, + updateWhileInteracting: true, + renderBuffer, + source: new VectorSource(), + }); } - private areAllPropertiesSupported( - changedProperties: ReadonlySet - ): changedProperties is SupportedChangeProperties { - for (const changedProperty of changedProperties) { - if (this.unsupportedChangeProperties.has(changedProperty)) { - return false; - } - } - return true; + protected registerChangeHandlers( + elementDictionary$: Observable<{ [id: string]: Element }>, + destroy$: Subject, + ngZone: NgZone, + createHandler?: (newElement: Element) => void, + deleteHandler?: (deletedElement: Element) => void, + changeHandler?: (oldElement: Element, newElement: Element) => void + ) { + elementDictionary$ + .pipe(startWith({}), pairwise(), takeUntil(destroy$)) + .subscribe(([oldElementDictionary, newElementDictionary]) => { + // run outside angular zone for better performance + ngZone.runOutsideAngular(() => { + handleChanges(oldElementDictionary, newElementDictionary, { + createHandler, + deleteHandler, + changeHandler, + }); + }); + }); } } /** * The keys of the feature, where the type and most recent value of the respective element are saved to */ -const featureKeys = { - value: 'elementValue', - // TODO: In the future the type should be saved in the element itself - type: 'elementType', -}; +export const featureElementKey = 'element'; diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts index 43d58bc70..4e1d81f6a 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts @@ -1,35 +1,52 @@ +import type { Type, NgZone } from '@angular/core'; import type { Store } from '@ngrx/store'; import type { MapImage, UUID } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; import type Point from 'ol/geom/Point'; -import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; +import type { Subject } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; import type { AppState } from 'src/app/state/app.state'; -import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; +import { + selectCurrentRole, + selectVisibleMapImages, +} from 'src/app/state/application/selectors/shared.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import { MapImagePopupComponent } from '../shared/map-image-popup/map-image-popup.component'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; +import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; +import type { OpenPopupOptions } from '../utility/popup-manager'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; -import { createPoint, ElementFeatureManager } from './element-feature-manager'; +import { MoveableFeatureManager } from './moveable-feature-manager'; -export class MapImageFeatureManager extends ElementFeatureManager { - readonly type = 'mapImages'; +export class MapImageFeatureManager extends MoveableFeatureManager { + public register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ): void { + super.registerFeatureElementManager( + this.store.select(selectVisibleMapImages), + changePopup$, + destroy$, + ngZone, + mapInteractionsManager + ); + } private readonly imageStyleHelper = new ImageStyleHelper( - (feature) => this.getElementFromFeature(feature)!.value.image + (feature) => (this.getElementFromFeature(feature) as MapImage).image ); private readonly popupHelper = new ImagePopupHelper(this.olMap, this.layer); constructor( olMap: OlMap, - layer: VectorLayer>, exerciseService: ExerciseService, private readonly store: Store ) { super( olMap, - layer, (targetPosition, mapImage) => { exerciseService.proposeAction({ type: '[MapImage] Move MapImage', @@ -37,7 +54,8 @@ export class MapImageFeatureManager extends ElementFeatureManager { targetPosition, }); }, - createPoint + new PointGeometryHelper(), + 10_000 ); this.layer.setStyle((feature, resolution) => { const style = this.imageStyleHelper.getStyle( @@ -45,7 +63,8 @@ export class MapImageFeatureManager extends ElementFeatureManager { resolution ); style.setZIndex( - this.getElementFromFeature(feature as Feature)!.value.zIndex + (this.getElementFromFeature(feature as Feature) as MapImage) + .zIndex ); return style; }); @@ -68,12 +87,10 @@ export class MapImageFeatureManager extends ElementFeatureManager { } override isFeatureTranslatable(feature: Feature): boolean { - const mapImage = this.getElementFromFeature(feature).value as MapImage; + const mapImage = this.getElementFromFeature(feature) as MapImage; return ( selectStateSnapshot(selectCurrentRole, this.store) === 'trainer' && !mapImage.isLocked ); } - - override unsupportedChangeProperties = new Set(['id', 'image'] as const); } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts index b6da79e5a..cfca5500b 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts @@ -1,28 +1,43 @@ +import type { Type, NgZone } from '@angular/core'; +import type { Store } from '@ngrx/store'; import type { Material, UUID } from 'digital-fuesim-manv-shared'; import { normalZoom } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; -import type Point from 'ol/geom/Point'; -import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; +import type { Subject } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; -import type { WithPosition } from '../../utility/types/with-position'; +import type { AppState } from 'src/app/state/app.state'; +import { selectVisibleMaterials } from 'src/app/state/application/selectors/shared.selectors'; import { MaterialPopupComponent } from '../shared/material-popup/material-popup.component'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; +import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; +import type { OpenPopupOptions } from '../utility/popup-manager'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; import { NameStyleHelper } from '../utility/style-helper/name-style-helper'; -import { createPoint, ElementFeatureManager } from './element-feature-manager'; +import { MoveableFeatureManager } from './moveable-feature-manager'; -export class MaterialFeatureManager extends ElementFeatureManager< - WithPosition -> { - readonly type = 'materials'; +export class MaterialFeatureManager extends MoveableFeatureManager { + public register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ): void { + super.registerFeatureElementManager( + this.store.select(selectVisibleMaterials), + changePopup$, + destroy$, + ngZone, + mapInteractionsManager + ); + } private readonly imageStyleHelper = new ImageStyleHelper( - (feature) => this.getElementFromFeature(feature)!.value.image + (feature) => (this.getElementFromFeature(feature) as Material).image ); private readonly nameStyleHelper = new NameStyleHelper( (feature) => { - const material = this.getElementFromFeature(feature)!.value; + const material = this.getElementFromFeature(feature) as Material; return { name: material.vehicleName, offsetY: material.image.height / 2 / normalZoom, @@ -36,12 +51,11 @@ export class MaterialFeatureManager extends ElementFeatureManager< constructor( olMap: OlMap, - layer: VectorLayer>, + private readonly store: Store, exerciseService: ExerciseService ) { super( olMap, - layer, (targetPosition, material) => { exerciseService.proposeAction({ type: '[Material] Move material', @@ -49,7 +63,7 @@ export class MaterialFeatureManager extends ElementFeatureManager< targetPosition, }); }, - createPoint + new PointGeometryHelper() ); this.layer.setStyle((feature, resolution) => [ this.nameStyleHelper.getStyle(feature as Feature, resolution), @@ -57,8 +71,6 @@ export class MaterialFeatureManager extends ElementFeatureManager< ]); } - override unsupportedChangeProperties = new Set(['id', 'image'] as const); - public override onFeatureClicked( event: MapBrowserEvent, feature: Feature diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts new file mode 100644 index 000000000..af8277d30 --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts @@ -0,0 +1,164 @@ +import type { MapBrowserEvent, Feature } from 'ol'; +import type Point from 'ol/geom/Point'; +import type { TranslateEvent } from 'ol/interaction/Translate'; +import type VectorLayer from 'ol/layer/Vector'; +import type OlMap from 'ol/Map'; +import type VectorSource from 'ol/source/Vector'; +import type { Observable } from 'rxjs'; +import { Subject } from 'rxjs'; +import type { NgZone } from '@angular/core'; +// eslint-disable-next-line @typescript-eslint/no-shadow +import type { UUID, Element } from 'digital-fuesim-manv-shared'; +import type { FeatureManager } from '../utility/feature-manager'; +import { MovementAnimator } from '../utility/movement-animator'; +import type { + GeometryHelper, + GeometryWithCoordinates, + PositionableElement, + Positions, +} from '../utility/geometry-helper'; +import type { OpenPopupOptions } from '../utility/popup-manager'; +import { TranslateInteraction } from '../utility/translate-interaction'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; +import { ElementManager } from './element-manager'; + +/** + * Manages the position of the element. + * Manages the default interactions of the element. + * Automatically redraws a feature (= reevaluates its style function) when an element property has changed. + */ +export abstract class MoveableFeatureManager< + ManagedElement extends PositionableElement, + FeatureType extends GeometryWithCoordinates = Point + > + extends ElementManager + implements FeatureManager +{ + public readonly togglePopup$ = new Subject>(); + protected movementAnimator: MovementAnimator; + public layer: VectorLayer>; + constructor( + protected readonly olMap: OlMap, + private readonly proposeMovementAction: ( + newPosition: Positions, + element: ManagedElement + ) => void, + protected readonly geometryHelper: GeometryHelper< + FeatureType, + ManagedElement + >, + renderBuffer?: number + ) { + super(); + this.layer = super.createElementLayer(renderBuffer); + this.movementAnimator = this.createMovementAnimator(); + } + + createMovementAnimator() { + return new MovementAnimator( + this.olMap, + this.layer, + this.geometryHelper.interpolateCoordinates, + this.geometryHelper.getFeatureCoordinates + ); + } + + createFeature(element: ManagedElement): Feature { + const elementFeature = this.geometryHelper.create(element); + elementFeature.setId(element.id); + this.layer.getSource()!.addFeature(elementFeature); + TranslateInteraction.onTranslateEnd( + elementFeature, + (newPosition) => { + this.proposeMovementAction(newPosition, element); + }, + this.geometryHelper.getFeaturePosition + ); + return elementFeature; + } + + isFeatureTranslatable(feature: Feature) { + return true; + } + + deleteFeature( + element: ManagedElement, + elementFeature: Feature + ): void { + this.layer.getSource()!.removeFeature(elementFeature); + elementFeature.dispose(); + this.movementAnimator.stopMovementAnimation(elementFeature); + } + + changeFeature( + oldElement: ManagedElement, + newElement: ManagedElement, + changedProperties: ReadonlySet, + elementFeature: Feature + ): void { + if (changedProperties.has('position')) { + this.movementAnimator.animateFeatureMovement( + elementFeature, + this.geometryHelper.getElementCoordinates(newElement) + ); + } + // Redraw the feature to reevaluate its style function + elementFeature.changed(); + } + + getFeatureFromElement( + element: ManagedElement + ): Feature | undefined { + return ( + (this.layer + .getSource()! + .getFeatureById(element.id) as Feature | null) ?? + undefined + ); + } + + public onFeatureClicked( + event: MapBrowserEvent, + feature: Feature + // eslint-disable-next-line @typescript-eslint/no-empty-function + ): void {} + + /** + * The standard implementation is to ignore these events. + */ + public onFeatureDrop( + droppedElement: Element, + droppedOnFeature: Feature, + dropEvent?: TranslateEvent + ): boolean { + return false; + } + + public abstract register( + changePopup$: Subject | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ): void; + + protected registerFeatureElementManager( + elementDictionary$: Observable<{ [id: UUID]: ManagedElement }>, + changePopup$: Subject | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ) { + this.olMap.addLayer(this.layer); + mapInteractionsManager.addFeatureLayer(this.layer); + this.togglePopup$?.subscribe(changePopup$); + this.registerChangeHandlers( + elementDictionary$, + destroy$, + ngZone, + (element) => this.onElementCreated(element), + (element) => this.onElementDeleted(element), + (oldElement, newElement) => + this.onElementChanged(oldElement, newElement) + ); + } +} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts index e2ff69fee..344e4282f 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts @@ -1,31 +1,44 @@ +import type { Type, NgZone } from '@angular/core'; import type { Store } from '@ngrx/store'; import type { UUID } from 'digital-fuesim-manv-shared'; import { Patient } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; -import type Point from 'ol/geom/Point'; -import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; import { Fill, Stroke } from 'ol/style'; +import type { Subject } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; import type { AppState } from 'src/app/state/app.state'; import { selectConfiguration } from 'src/app/state/application/selectors/exercise.selectors'; +import { selectVisiblePatients } from 'src/app/state/application/selectors/shared.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; -import type { WithPosition } from '../../utility/types/with-position'; import { PatientPopupComponent } from '../shared/patient-popup/patient-popup.component'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; +import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; +import type { OpenPopupOptions } from '../utility/popup-manager'; import { CircleStyleHelper } from '../utility/style-helper/circle-style-helper'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; -import { createPoint, ElementFeatureManager } from './element-feature-manager'; +import { MoveableFeatureManager } from './moveable-feature-manager'; -export class PatientFeatureManager extends ElementFeatureManager< - WithPosition -> { - readonly type = 'patients'; +export class PatientFeatureManager extends MoveableFeatureManager { + public register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ): void { + super.registerFeatureElementManager( + this.store.select(selectVisiblePatients), + changePopup$, + destroy$, + ngZone, + mapInteractionsManager + ); + } private readonly popupHelper = new ImagePopupHelper(this.olMap, this.layer); private readonly imageStyleHelper = new ImageStyleHelper((feature) => { - const patient = this.getElementFromFeature(feature)!.value; + const patient = this.getElementFromFeature(feature) as Patient; return { ...patient.image, rotation: patient.pretriageInformation.isWalkable @@ -36,7 +49,7 @@ export class PatientFeatureManager extends ElementFeatureManager< private readonly circleStyleHelper = new CircleStyleHelper( (feature) => { - const patient = this.getElementFromFeature(feature)!.value; + const patient = this.getElementFromFeature(feature) as Patient; const configuration = selectStateSnapshot( selectConfiguration, this.store @@ -59,8 +72,8 @@ export class PatientFeatureManager extends ElementFeatureManager< }, 0.025, (feature) => - this.getElementFromFeature(feature)!.value.pretriageInformation - .isWalkable + (this.getElementFromFeature(feature) as Patient) + .pretriageInformation.isWalkable ? [0, 0.25] : [-0.25, 0] ); @@ -68,12 +81,10 @@ export class PatientFeatureManager extends ElementFeatureManager< constructor( private readonly store: Store, olMap: OlMap, - layer: VectorLayer>, exerciseService: ExerciseService ) { super( olMap, - layer, (targetPosition, patient) => { exerciseService.proposeAction({ type: '[Patient] Move patient', @@ -81,7 +92,7 @@ export class PatientFeatureManager extends ElementFeatureManager< targetPosition, }); }, - createPoint + new PointGeometryHelper() ); this.layer.setStyle((feature, resolution) => [ this.imageStyleHelper.getStyle(feature as Feature, resolution), @@ -101,6 +112,4 @@ export class PatientFeatureManager extends ElementFeatureManager< }) ); } - - override unsupportedChangeProperties = new Set(['id', 'image'] as const); } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts index 3d42f47ee..861d70390 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts @@ -1,28 +1,43 @@ +import type { Type, NgZone } from '@angular/core'; +import type { Store } from '@ngrx/store'; import type { Personnel, UUID } from 'digital-fuesim-manv-shared'; import { normalZoom } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; -import type Point from 'ol/geom/Point'; -import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; +import type { Subject } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; -import type { WithPosition } from '../../utility/types/with-position'; +import type { AppState } from 'src/app/state/app.state'; +import { selectVisiblePersonnel } from 'src/app/state/application/selectors/shared.selectors'; import { PersonnelPopupComponent } from '../shared/personnel-popup/personnel-popup.component'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; +import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; +import type { OpenPopupOptions } from '../utility/popup-manager'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; import { NameStyleHelper } from '../utility/style-helper/name-style-helper'; -import { createPoint, ElementFeatureManager } from './element-feature-manager'; +import { MoveableFeatureManager } from './moveable-feature-manager'; -export class PersonnelFeatureManager extends ElementFeatureManager< - WithPosition -> { - readonly type = 'personnel'; +export class PersonnelFeatureManager extends MoveableFeatureManager { + public register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ): void { + super.registerFeatureElementManager( + this.store.select(selectVisiblePersonnel), + changePopup$, + destroy$, + ngZone, + mapInteractionsManager + ); + } private readonly imageStyleHelper = new ImageStyleHelper( - (feature) => this.getElementFromFeature(feature)!.value.image + (feature) => (this.getElementFromFeature(feature) as Personnel).image ); private readonly nameStyleHelper = new NameStyleHelper( (feature) => { - const personnel = this.getElementFromFeature(feature)!.value; + const personnel = this.getElementFromFeature(feature) as Personnel; return { name: personnel.vehicleName, offsetY: personnel.image.height / 2 / normalZoom, @@ -36,12 +51,11 @@ export class PersonnelFeatureManager extends ElementFeatureManager< constructor( olMap: OlMap, - layer: VectorLayer>, + private readonly store: Store, exerciseService: ExerciseService ) { super( olMap, - layer, (targetPosition, personnel) => { exerciseService.proposeAction({ type: '[Personnel] Move personnel', @@ -49,7 +63,7 @@ export class PersonnelFeatureManager extends ElementFeatureManager< targetPosition, }); }, - createPoint + new PointGeometryHelper() ); this.layer.setStyle((feature, resolution) => [ @@ -58,8 +72,6 @@ export class PersonnelFeatureManager extends ElementFeatureManager< ]); } - override unsupportedChangeProperties = new Set(['id', 'image'] as const); - public override onFeatureClicked( event: MapBrowserEvent, feature: Feature diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts new file mode 100644 index 000000000..08a3ddd40 --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts @@ -0,0 +1,198 @@ +import type { Store } from '@ngrx/store'; +import type { + UUID, + SimulatedRegion, + // eslint-disable-next-line @typescript-eslint/no-shadow + Element, +} from 'digital-fuesim-manv-shared'; + +import { MapCoordinates, Size } from 'digital-fuesim-manv-shared'; +import type { Feature, MapBrowserEvent } from 'ol'; +import type { TranslateEvent } from 'ol/interaction/Translate'; +import type { Polygon } from 'ol/geom'; +import type OlMap from 'ol/Map'; +import { Fill } from 'ol/style'; +import Stroke from 'ol/style/Stroke'; +import Style from 'ol/style/Style'; +import type { ExerciseService } from 'src/app/core/exercise.service'; +import type { AppState } from 'src/app/state/app.state'; +import { + selectCurrentRole, + selectVisibleSimulatedRegions, +} from 'src/app/state/application/selectors/shared.selectors'; +import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; +import type { Type, NgZone } from '@angular/core'; +import type { Subject } from 'rxjs'; +import { SimulatedRegionPopupComponent } from '../shared/simulated-region-popup/simulated-region-popup.component'; +import { calculatePopupPositioning } from '../utility/calculate-popup-positioning'; +import type { FeatureManager } from '../utility/feature-manager'; +import { PolygonGeometryHelper } from '../utility/polygon-geometry-helper'; +import { ResizeRectangleInteraction } from '../utility/resize-rectangle-interaction'; +import type { OpenPopupOptions } from '../utility/popup-manager'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; +import { MoveableFeatureManager } from './moveable-feature-manager'; + +export class SimulatedRegionFeatureManager + extends MoveableFeatureManager + implements FeatureManager +{ + public register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ): void { + super.registerFeatureElementManager( + this.store.select(selectVisibleSimulatedRegions), + changePopup$, + destroy$, + ngZone, + mapInteractionsManager + ); + mapInteractionsManager.addTrainerInteraction( + new ResizeRectangleInteraction(this.layer.getSource()!) + ); + } + constructor( + olMap: OlMap, + private readonly exerciseService: ExerciseService, + private readonly store: Store + ) { + super( + olMap, + (targetPositions, simulatedRegion) => { + exerciseService.proposeAction({ + type: '[SimulatedRegion] Move simulated region', + simulatedRegionId: simulatedRegion.id, + targetPosition: targetPositions[0]![0]!, + }); + }, + new PolygonGeometryHelper() + ); + this.layer.setStyle(this.style); + } + + private readonly style = new Style({ + fill: new Fill({ + color: '#808080cc', + }), + stroke: new Stroke({ + color: '#cccc00', + width: 2, + }), + }); + + override createFeature(element: SimulatedRegion): Feature { + const feature = super.createFeature(element); + ResizeRectangleInteraction.onResize( + feature, + ({ topLeftCoordinate, scale }) => { + const currentElement = this.getElementFromFeature( + feature + ) as SimulatedRegion; + this.exerciseService.proposeAction( + { + type: '[SimulatedRegion] Resize simulated region', + simulatedRegionId: element.id, + targetPosition: MapCoordinates.create( + topLeftCoordinate[0]!, + topLeftCoordinate[1]! + ), + newSize: Size.create( + currentElement.size.width * scale.x, + currentElement.size.height * scale.y + ), + }, + true + ); + } + ); + return feature; + } + + override changeFeature( + oldElement: SimulatedRegion, + newElement: SimulatedRegion, + changedProperties: ReadonlySet, + elementFeature: Feature + ): void { + if ( + changedProperties.has('position') || + changedProperties.has('size') + ) { + this.movementAnimator.animateFeatureMovement( + elementFeature, + this.geometryHelper.getElementCoordinates(newElement) + ); + } + // If the style has updated, we need to redraw the feature + elementFeature.changed(); + } + + public override onFeatureDrop( + droppedElement: Element, + droppedOnFeature: Feature, + dropEvent?: TranslateEvent + ) { + const droppedOnSimulatedRegion = this.getElementFromFeature( + droppedOnFeature + ) as SimulatedRegion; + if (!droppedElement || !droppedOnSimulatedRegion) { + console.error('Could not find element for the features'); + return false; + } + if ( + ['vehicle', 'personnel', 'material', 'patient'].includes( + droppedElement.type + ) + ) { + this.exerciseService.proposeAction( + { + type: '[SimulatedRegion] Add Element', + simulatedRegionId: droppedOnSimulatedRegion.id, + elementToBeAddedType: droppedElement.type as + | 'material' + | 'patient' + | 'personnel' + | 'vehicle', + elementToBeAddedId: droppedElement.id, + }, + true + ); + return true; + } + return false; + } + + public override onFeatureClicked( + event: MapBrowserEvent, + feature: Feature + ): void { + super.onFeatureClicked(event, feature); + if (selectStateSnapshot(selectCurrentRole, this.store) !== 'trainer') { + return; + } + const zoom = this.olMap.getView().getZoom()!; + const margin = 10 / zoom; + + this.togglePopup$.next({ + component: SimulatedRegionPopupComponent, + context: { + simulatedRegionId: feature.getId() as UUID, + }, + // We want the popup to be centered on the mouse position + ...calculatePopupPositioning( + event.coordinate, + { + height: margin, + width: margin, + }, + this.olMap.getView().getCenter()! + ), + }); + } + + public override isFeatureTranslatable(feature: Feature): boolean { + return selectStateSnapshot(selectCurrentRole, this.store) === 'trainer'; + } +} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts index 999de802b..c003671f1 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts @@ -1,3 +1,5 @@ +import type { Type, NgZone } from '@angular/core'; +import type { Store } from '@ngrx/store'; import type { MapBrowserEvent } from 'ol'; import { Feature } from 'ol'; import LineString from 'ol/geom/LineString'; @@ -6,25 +8,34 @@ import type VectorLayer from 'ol/layer/Vector'; import type VectorSource from 'ol/source/Vector'; import Stroke from 'ol/style/Stroke'; import Style from 'ol/style/Style'; +import type { Subject } from 'rxjs'; import type { TransferLine } from 'src/app/shared/types/transfer-line'; +import type { AppState } from 'src/app/state/app.state'; +import { selectTransferLines } from 'src/app/state/application/selectors/exercise.selectors'; +import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; +import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; +import type OlMap from 'ol/Map'; +// eslint-disable-next-line @typescript-eslint/no-shadow +import type { Element } from 'digital-fuesim-manv-shared'; +import type { TransferLinesService } from '../../core/transfer-lines.service'; import type { FeatureManager } from '../utility/feature-manager'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; +import type { OpenPopupOptions } from '../utility/popup-manager'; import { ElementManager } from './element-manager'; export class TransferLinesFeatureManager - extends ElementManager< - TransferLine, - LineString, - Feature, - ReadonlySet - > - implements FeatureManager> + extends ElementManager + implements FeatureManager { - readonly type = 'transferLines'; - readonly unsupportedChangeProperties = new Set(['id'] as const); - - constructor(public readonly layer: VectorLayer>) { + public readonly layer: VectorLayer>; + constructor( + private readonly store: Store, + private readonly transferLinesService: TransferLinesService, + private readonly olMap: OlMap + ) { super(); - layer.setStyle( + this.layer = this.createElementLayer(); + this.layer.setStyle( new Style({ stroke: new Stroke({ color: '#fd7e14', @@ -34,6 +45,33 @@ export class TransferLinesFeatureManager }) ); } + togglePopup$?: Subject>> | undefined; + register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ) { + this.olMap.addLayer(this.layer); + mapInteractionsManager.addFeatureLayer(this.layer); + this.togglePopup$?.subscribe(changePopup$); + if (selectStateSnapshot(selectCurrentRole, this.store) === 'trainer') { + this.registerChangeHandlers( + this.store.select(selectTransferLines), + destroy$, + ngZone, + (element) => this.onElementCreated(element), + (element) => this.onElementDeleted(element), + (oldElement, newElement) => + this.onElementChanged(oldElement, newElement) + ); + this.transferLinesService.displayTransferLines$.subscribe( + (display) => { + this.layer.setVisible(display); + } + ); + } + } createFeature(element: TransferLine): Feature { const feature = new Feature( @@ -79,9 +117,9 @@ export class TransferLinesFeatureManager ) {} onFeatureDrop( - dropEvent: TranslateEvent, - droppedFeature: Feature, - droppedOnFeature: Feature + droppedElement: Element, + droppedOnFeature: Feature, + dropEvent?: TranslateEvent ) { return false; } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts index 3682c6c10..fafe48c84 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts @@ -1,36 +1,40 @@ +import type { NgZone } from '@angular/core'; import type { Store } from '@ngrx/store'; -import type { UUID } from 'digital-fuesim-manv-shared'; +// eslint-disable-next-line @typescript-eslint/no-shadow +import type { UUID, Element } from 'digital-fuesim-manv-shared'; import { TransferPoint, TransferStartPoint } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; import type Point from 'ol/geom/Point'; import type { TranslateEvent } from 'ol/interaction/Translate'; -import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; +import type { Subject } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; import type { AppState } from 'src/app/state/app.state'; -import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; +import { + selectCurrentRole, + selectVisibleTransferPoints, +} from 'src/app/state/application/selectors/shared.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import { ChooseTransferTargetPopupComponent } from '../shared/choose-transfer-target-popup/choose-transfer-target-popup.component'; import { TransferPointPopupComponent } from '../shared/transfer-point-popup/transfer-point-popup.component'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; +import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; +import type { OpenPopupOptions } from '../utility/popup-manager'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; import { NameStyleHelper } from '../utility/style-helper/name-style-helper'; -import { createPoint, ElementFeatureManager } from './element-feature-manager'; +import { MoveableFeatureManager } from './moveable-feature-manager'; -export class TransferPointFeatureManager extends ElementFeatureManager { - readonly type = 'transferPoints'; +export class TransferPointFeatureManager extends MoveableFeatureManager { private readonly popupHelper = new ImagePopupHelper(this.olMap, this.layer); constructor( olMap: OlMap, - layer: VectorLayer>, private readonly store: Store, private readonly exerciseService: ExerciseService ) { super( olMap, - layer, (targetPosition, transferPoint) => { exerciseService.proposeAction({ type: '[TransferPoint] Move TransferPoint', @@ -38,9 +42,10 @@ export class TransferPointFeatureManager extends ElementFeatureManager [ + this.layer.setStyle((thisFeature, currentZoom) => [ this.imageStyleHelper.getStyle( thisFeature as Feature, currentZoom @@ -52,6 +57,21 @@ export class TransferPointFeatureManager extends ElementFeatureManager | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ) { + super.registerFeatureElementManager( + this.store.select(selectVisibleTransferPoints), + changePopup$, + destroy$, + ngZone, + mapInteractionsManager + ); + } + private readonly imageStyleHelper = new ImageStyleHelper( (feature: Feature) => ({ url: TransferPoint.image.url, @@ -61,7 +81,8 @@ export class TransferPointFeatureManager extends ElementFeatureManager ({ - name: this.getElementFromFeature(feature)!.value.internalName, + name: (this.getElementFromFeature(feature) as TransferPoint) + .internalName, offsetY: 0, }), 0.2, @@ -69,20 +90,20 @@ export class TransferPointFeatureManager extends ElementFeatureManager, - droppedOnFeature: Feature + droppedElement: Element, + droppedOnFeature: Feature, + dropEvent?: TranslateEvent ) { // TODO: droppedElement isn't necessarily a transfer point -> fix getElementFromFeature typings - const droppedElement = this.getElementFromFeature(droppedFeature); - const droppedOnTransferPoint: TransferPoint = - this.getElementFromFeature(droppedOnFeature)!.value!; + const droppedOnTransferPoint = this.getElementFromFeature( + droppedOnFeature + ) as TransferPoint; if (!droppedElement || !droppedOnTransferPoint) { console.error('Could not find element for the features'); return false; } if ( - droppedElement.type !== 'vehicles' && + droppedElement.type !== 'vehicle' && droppedElement.type !== 'personnel' ) { return false; @@ -106,7 +127,7 @@ export class TransferPointFeatureManager extends ElementFeatureManager): boolean { return selectStateSnapshot(selectCurrentRole, this.store) === 'trainer'; } - - override unsupportedChangeProperties = new Set([ - 'id', - 'internalName', - ] as const); } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts index 0a6e489f2..aa8fb8675 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts @@ -1,30 +1,50 @@ -import type { UUID, Vehicle } from 'digital-fuesim-manv-shared'; +import type { Type, NgZone } from '@angular/core'; +import type { Store } from '@ngrx/store'; +import type { + UUID, + Vehicle, + // eslint-disable-next-line @typescript-eslint/no-shadow + Element, +} from 'digital-fuesim-manv-shared'; import { normalZoom } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; import type Point from 'ol/geom/Point'; import type { TranslateEvent } from 'ol/interaction/Translate'; -import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; +import type { Subject } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; -import type { WithPosition } from '../../utility/types/with-position'; +import type { AppState } from 'src/app/state/app.state'; +import { selectVisibleVehicles } from 'src/app/state/application/selectors/shared.selectors'; import { VehiclePopupComponent } from '../shared/vehicle-popup/vehicle-popup.component'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; +import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; +import type { OpenPopupOptions } from '../utility/popup-manager'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; import { NameStyleHelper } from '../utility/style-helper/name-style-helper'; -import { createPoint, ElementFeatureManager } from './element-feature-manager'; - -export class VehicleFeatureManager extends ElementFeatureManager< - WithPosition -> { - readonly type = 'vehicles'; +import { MoveableFeatureManager } from './moveable-feature-manager'; +export class VehicleFeatureManager extends MoveableFeatureManager { + public register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ): void { + super.registerFeatureElementManager( + this.store.select(selectVisibleVehicles), + changePopup$, + destroy$, + ngZone, + mapInteractionsManager + ); + } private readonly imageStyleHelper = new ImageStyleHelper( - (feature) => this.getElementFromFeature(feature)!.value.image + (feature) => (this.getElementFromFeature(feature) as Vehicle).image ); private readonly nameStyleHelper = new NameStyleHelper( (feature) => { - const vehicle = this.getElementFromFeature(feature)!.value; + const vehicle = this.getElementFromFeature(feature) as Vehicle; return { name: vehicle.name, offsetY: vehicle.image.height / 2 / normalZoom, @@ -37,12 +57,11 @@ export class VehicleFeatureManager extends ElementFeatureManager< constructor( olMap: OlMap, - layer: VectorLayer>, + private readonly store: Store, private readonly exerciseService: ExerciseService ) { super( olMap, - layer, (targetPosition, vehicle) => { exerciseService.proposeAction({ type: '[Vehicle] Move vehicle', @@ -50,7 +69,8 @@ export class VehicleFeatureManager extends ElementFeatureManager< targetPosition, }); }, - createPoint + new PointGeometryHelper(), + 1000 ); this.layer.setStyle((feature, resolution) => [ this.nameStyleHelper.getStyle(feature as Feature, resolution), @@ -59,36 +79,32 @@ export class VehicleFeatureManager extends ElementFeatureManager< } public override onFeatureDrop( - dropEvent: TranslateEvent, - droppedFeature: Feature, - droppedOnFeature: Feature + droppedElement: Element, + droppedOnFeature: Feature, + dropEvent?: TranslateEvent ) { - const droppedElement = this.getElementFromFeature(droppedFeature); const droppedOnVehicle = this.getElementFromFeature( droppedOnFeature - ) as { - type: 'vehicles'; - value: Vehicle; - }; + ) as Vehicle; if (!droppedElement || !droppedOnVehicle) { console.error('Could not find element for the features'); return false; } if ( (droppedElement.type === 'personnel' && - droppedOnVehicle.value.personnelIds[droppedElement.value.id]) || - (droppedElement.type === 'materials' && - droppedOnVehicle.value.materialIds[droppedElement.value.id]) || - (droppedElement.type === 'patients' && - Object.keys(droppedOnVehicle.value.patientIds).length < - droppedOnVehicle.value.patientCapacity) + droppedOnVehicle.personnelIds[droppedElement.id]) || + (droppedElement.type === 'material' && + droppedOnVehicle.materialIds[droppedElement.id]) || + (droppedElement.type === 'patient' && + Object.keys(droppedOnVehicle.patientIds).length < + droppedOnVehicle.patientCapacity) ) { // TODO: user feedback (e.g. toast) this.exerciseService.proposeAction( { type: '[Vehicle] Load vehicle', - vehicleId: droppedOnVehicle.value.id, - elementToBeLoadedId: droppedElement.value.id, + vehicleId: droppedOnVehicle.id, + elementToBeLoadedId: droppedElement.id, elementToBeLoadedType: droppedElement.type, }, true @@ -98,8 +114,6 @@ export class VehicleFeatureManager extends ElementFeatureManager< return false; } - override unsupportedChangeProperties = new Set(['id', 'image'] as const); - public override onFeatureClicked( event: MapBrowserEvent, feature: Feature diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts index 2179e0d90..5e41c5af1 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts @@ -1,27 +1,29 @@ +import type { Type, NgZone } from '@angular/core'; import type { Store } from '@ngrx/store'; import type { UUID } from 'digital-fuesim-manv-shared'; -import { Size, Viewport } from 'digital-fuesim-manv-shared'; +import { MapCoordinates, Size, Viewport } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; import type { Coordinate } from 'ol/coordinate'; -import type LineString from 'ol/geom/LineString'; -import type VectorLayer from 'ol/layer/Vector'; +import type { Polygon } from 'ol/geom'; import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; import Stroke from 'ol/style/Stroke'; import Style from 'ol/style/Style'; +import type { Subject } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; import type { AppState } from 'src/app/state/app.state'; -import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; +import { + selectCurrentRole, + selectVisibleViewports, +} from 'src/app/state/application/selectors/shared.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import { ViewportPopupComponent } from '../shared/viewport-popup/viewport-popup.component'; import { calculatePopupPositioning } from '../utility/calculate-popup-positioning'; import type { FeatureManager } from '../utility/feature-manager'; -import { ModifyHelper } from '../utility/modify-helper'; -import { - createLineString, - ElementFeatureManager, - getCoordinateArray, -} from './element-feature-manager'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; +import { PolygonGeometryHelper } from '../utility/polygon-geometry-helper'; +import type { OpenPopupOptions } from '../utility/popup-manager'; +import { ResizeRectangleInteraction } from '../utility/resize-rectangle-interaction'; +import { MoveableFeatureManager } from './moveable-feature-manager'; export function isInViewport( coordinate: Coordinate, @@ -34,78 +36,78 @@ export function isInViewport( } export class ViewportFeatureManager - extends ElementFeatureManager - implements FeatureManager> + extends MoveableFeatureManager + implements FeatureManager { - readonly type = 'viewports'; - - override unsupportedChangeProperties = new Set(['id'] as const); - + public register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ): void { + super.registerFeatureElementManager( + this.store.select(selectVisibleViewports), + changePopup$, + destroy$, + ngZone, + mapInteractionsManager + ); + mapInteractionsManager.addTrainerInteraction( + new ResizeRectangleInteraction(this.layer.getSource()!) + ); + } constructor( olMap: OlMap, - layer: VectorLayer>, private readonly exerciseService: ExerciseService, private readonly store: Store ) { super( olMap, - layer, (targetPositions, viewport) => { exerciseService.proposeAction({ type: '[Viewport] Move viewport', viewportId: viewport.id, - targetPosition: targetPositions[0]!, + targetPosition: targetPositions[0]![0]!, }); }, - createLineString + new PolygonGeometryHelper() ); this.layer.setStyle(this.style); } - private readonly modifyHelper = new ModifyHelper(); private readonly style = new Style({ - geometry(thisFeature) { - const modifyGeometry = thisFeature.get('modifyGeometry'); - return modifyGeometry - ? modifyGeometry.geometry - : thisFeature.getGeometry(); - }, + fill: undefined, stroke: new Stroke({ color: '#fafaff', width: 2, }), }); - override createFeature(element: Viewport): Feature { + override createFeature(element: Viewport): Feature { const feature = super.createFeature(element); - this.modifyHelper.onModifyEnd(feature, (newPositions) => { - // Skip when not all coordinates are properly set. - if ( - !newPositions.every( - (position) => - Number.isFinite(position.x) && - Number.isFinite(position.y) - ) - ) { - const viewport = this.getElementFromFeature(feature)!.value; - this.recreateFeature(viewport); - return; + ResizeRectangleInteraction.onResize( + feature, + ({ topLeftCoordinate, scale }) => { + const currentElement = this.getElementFromFeature( + feature + ) as Viewport; + this.exerciseService.proposeAction( + { + type: '[Viewport] Resize viewport', + viewportId: element.id, + targetPosition: MapCoordinates.create( + topLeftCoordinate[0]!, + topLeftCoordinate[1]! + ), + newSize: Size.create( + currentElement.size.width * scale.x, + currentElement.size.height * scale.y + ), + }, + true + ); } - const lineString = newPositions; - - // We expect the viewport LineString to have 4 points. - const topLeft = lineString[0]!; - const bottomRight = lineString[2]!; - this.exerciseService.proposeAction({ - type: '[Viewport] Resize viewport', - viewportId: element.id, - targetPosition: topLeft, - newSize: Size.create( - bottomRight.x - topLeft.x, - topLeft.y - bottomRight.y - ), - }); - }); + ); return feature; } @@ -113,19 +115,15 @@ export class ViewportFeatureManager oldElement: Viewport, newElement: Viewport, changedProperties: ReadonlySet, - elementFeature: Feature + elementFeature: Feature ): void { if ( changedProperties.has('position') || changedProperties.has('size') ) { - const newFeature = this.getFeatureFromElement(newElement); - if (!newFeature) { - throw new TypeError('newFeature undefined'); - } this.movementAnimator.animateFeatureMovement( elementFeature, - getCoordinateArray(newElement) + this.geometryHelper.getElementCoordinates(newElement) ); } // If the style has updated, we need to redraw the feature @@ -159,4 +157,8 @@ export class ViewportFeatureManager ), }); } + + public override isFeatureTranslatable(feature: Feature): boolean { + return selectStateSnapshot(selectCurrentRole, this.store) === 'trainer'; + } } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/choose-transfer-target-popup/choose-transfer-target-popup.component.html b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/choose-transfer-target-popup/choose-transfer-target-popup.component.html index b015592ad..d92e204c7 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/choose-transfer-target-popup/choose-transfer-target-popup.component.html +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/choose-transfer-target-popup/choose-transfer-target-popup.component.html @@ -21,7 +21,7 @@ [transferPointId]="reachableTransferPoint.id" > - +
+
+ Simulierter Bereich {{ simulatedRegion.name }} + +
+
+ +
+ + + +
+
+
+ diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/simulated-region-popup/simulated-region-popup.component.scss b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/simulated-region-popup/simulated-region-popup.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/simulated-region-popup/simulated-region-popup.component.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/simulated-region-popup/simulated-region-popup.component.ts new file mode 100644 index 000000000..25ac51351 --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/simulated-region-popup/simulated-region-popup.component.ts @@ -0,0 +1,43 @@ +import type { OnInit } from '@angular/core'; +import { Component, EventEmitter, Output } from '@angular/core'; +import { Store } from '@ngrx/store'; +import type { UUID, SimulatedRegion } from 'digital-fuesim-manv-shared'; +import type { Observable } from 'rxjs'; +import { ExerciseService } from 'src/app/core/exercise.service'; +import type { AppState } from 'src/app/state/app.state'; +import { createSelectSimulatedRegion } from 'src/app/state/application/selectors/exercise.selectors'; +import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; + +@Component({ + selector: 'app-simulated-region-popup', + templateUrl: './simulated-region-popup.component.html', + styleUrls: ['./simulated-region-popup.component.scss'], +}) +export class SimulatedRegionPopupComponent implements OnInit { + // These properties are only set after OnInit + public simulatedRegionId!: UUID; + + @Output() readonly closePopup = new EventEmitter(); + + public simulatedRegion$?: Observable; + public readonly currentRole$ = this.store.select(selectCurrentRole); + + constructor( + private readonly store: Store, + private readonly exerciseService: ExerciseService + ) {} + + ngOnInit() { + this.simulatedRegion$ = this.store.select( + createSelectSimulatedRegion(this.simulatedRegionId) + ); + } + + public renameSimulatedRegion(newName: string) { + this.exerciseService.proposeAction({ + type: '[SimulatedRegion] Rename simulatedRegion', + simulatedRegionId: this.simulatedRegionId, + newName, + }); + } +} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/vehicle-popup/vehicle-popup.component.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/vehicle-popup/vehicle-popup.component.ts index fc13ff075..fb887ace0 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/vehicle-popup/vehicle-popup.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/vehicle-popup/vehicle-popup.component.ts @@ -2,7 +2,7 @@ import type { OnInit } from '@angular/core'; import { Component, EventEmitter, Output } from '@angular/core'; import { Store } from '@ngrx/store'; import type { UUID, Vehicle } from 'digital-fuesim-manv-shared'; -import { Material, Patient, Personnel } from 'digital-fuesim-manv-shared'; +import { isInVehicle } from 'digital-fuesim-manv-shared'; import type { Observable } from 'rxjs'; import { combineLatest, map, switchMap } from 'rxjs'; import { ExerciseService } from 'src/app/core/exercise.service'; @@ -45,23 +45,21 @@ export class VehiclePopupComponent implements PopupComponent, OnInit { ).map((materialId) => this.store .select(createSelectMaterial(materialId)) - .pipe(map((material) => Material.isInVehicle(material))) + .pipe(map((material) => isInVehicle(material))) ); const personnelAreInVehicle$ = Object.keys( _vehicle.personnelIds ).map((personnelId) => this.store .select(createSelectPersonnel(personnelId)) - .pipe( - map((personnel) => Personnel.isInVehicle(personnel)) - ) + .pipe(map((personnel) => isInVehicle(personnel))) ); const patientsAreInVehicle$ = Object.keys( _vehicle.patientIds ).map((patientId) => this.store .select(createSelectPatient(patientId)) - .pipe(map((patient) => Patient.isInVehicle(patient))) + .pipe(map((patient) => isInVehicle(patient))) ); return combineLatest([ ...materialsAreInVehicle$, @@ -70,7 +68,7 @@ export class VehiclePopupComponent implements PopupComponent, OnInit { ]); }), map((areInVehicle) => - areInVehicle.every((isInVehicle) => !isInVehicle) + areInVehicle.every((isInAVehicle) => !isInAVehicle) ) ); } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts index 1f1ff45d1..008f84c82 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts @@ -1,14 +1,19 @@ +import type { NgZone } from '@angular/core'; import type { Feature, MapBrowserEvent } from 'ol'; +import type { Geometry } from 'ol/geom'; import type { TranslateEvent } from 'ol/interaction/Translate'; import type VectorLayer from 'ol/layer/Vector'; import type VectorSource from 'ol/source/Vector'; import type { Subject } from 'rxjs'; +// eslint-disable-next-line @typescript-eslint/no-shadow +import type { Element } from 'digital-fuesim-manv-shared'; +import type { OlMapInteractionsManager } from './ol-map-interactions-manager'; import type { OpenPopupOptions } from './popup-manager'; /** * The Api to interact with a feature */ -export interface FeatureManager> { +export interface FeatureManager { readonly layer: VectorLayer; /** @@ -23,13 +28,13 @@ export interface FeatureManager> { */ onFeatureClicked: ( event: MapBrowserEvent, - feature: ElementFeature + feature: Feature ) => void; /** * @returns whether the feature can be moved by the user */ - isFeatureTranslatable: (feature: ElementFeature) => boolean; + isFeatureTranslatable: (feature: Feature) => boolean; /** * @param dropEvent The drop event that triggered the call @@ -38,8 +43,15 @@ export interface FeatureManager> { * @returns wether the event should not propagate further (to the features behind {@link droppedOnFeature}). */ onFeatureDrop: ( - dropEvent: TranslateEvent, - droppedFeature: Feature, - droppedOnFeature: ElementFeature + droppedElement: Element, + droppedOnFeature: Feature, + dropEvent?: TranslateEvent ) => boolean; + + register: ( + changePopup$: Subject | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ) => void; } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/geometry-helper.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/geometry-helper.ts new file mode 100644 index 000000000..c73200b8a --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/geometry-helper.ts @@ -0,0 +1,76 @@ +import type { + MapCoordinates, + Position, + Size, + UUID, +} from 'digital-fuesim-manv-shared'; +import type { Feature } from 'ol'; +import type { Coordinate } from 'ol/coordinate'; +import type { Geometry } from 'ol/geom'; + +export interface PositionableElement { + readonly id: UUID; + readonly position: Position; +} + +export type ResizableElement = PositionableElement & { + size: Size; +}; + +export type GeometryWithCoordinates = Geometry & { + getCoordinates: () => unknown; + setCoordinates: (coordinates: any[]) => void; +}; +/** + * Typescript doesn't error when T doesn't satisfy + * getCoordinates: () => unknown. + * Instead, the inferred type is null. We exclude this type + * to exchange it with never + */ +export type Coordinates = Exclude< + ReturnType, + null +>; + +type ArrayElement = ArrayType extends readonly (infer ElementType)[] + ? ElementType + : never; + +type SubstituteCoordinateForPoint = T extends Coordinate + ? MapCoordinates + : T extends Array> + ? SubstituteCoordinateForPoint>[] + : never; + +export type Positions = + SubstituteCoordinateForPoint>; + +export interface CoordinatePair { + startPosition: Coordinates; + endPosition: Coordinates; +} + +export interface GeometryHelper< + T extends GeometryWithCoordinates, + Element extends PositionableElement = PositionableElement +> { + create: (element: Element) => Feature; + getElementCoordinates: (element: Element) => Coordinates; + getFeatureCoordinates: (feature: Feature) => Coordinates; + interpolateCoordinates: ( + positions: CoordinatePair, + progress: number + ) => Coordinates; + getFeaturePosition: (feature: Feature) => Positions; +} + +export const interpolate = ( + startCoordinate: Coordinate, + endCoordinate: Coordinate, + lerpFactor: number +): Coordinate => [ + startCoordinate[0]! + + (endCoordinate[0]! - startCoordinate[0]!) * lerpFactor, + startCoordinate[1]! + + (endCoordinate[1]! - startCoordinate[1]!) * lerpFactor, +]; diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/modify-helper.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/modify-helper.ts deleted file mode 100644 index beeb5ccc2..000000000 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/modify-helper.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { calculateDistance, Position } from 'digital-fuesim-manv-shared'; -import type { Feature } from 'ol'; -import type { Coordinate } from 'ol/coordinate'; -import type { LineString } from 'ol/geom'; -import type { Modify } from 'ol/interaction'; - -function coordinateToPosition(coordinate: Coordinate): Position { - return Position.create(coordinate[0]!, coordinate[1]!); -} - -export type CornerName = 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topRight'; - -function getNearestCoordinateName( - referencePosition: Coordinate, - coordinates: { [name in CornerName]: Coordinate } -): CornerName { - if (Object.keys(coordinates).length === 0) { - throw new TypeError('Expected at least one coordinate'); - } - return Object.entries(coordinates) - .map( - ([name, coordinate]) => - [ - name, - calculateDistance( - coordinateToPosition(referencePosition), - coordinateToPosition(coordinate) - ), - ] as [CornerName, number] - ) - .sort( - ([, leftDistance], [, rightDistance]) => - leftDistance - rightDistance - ) - .map(([name]) => name)[0]!; -} - -export interface ModifyGeometry { - geometry: LineString; - modifyCorner: CornerName; -} - -/** - * Modifies (moves) a feature to a new position. - */ -export class ModifyHelper { - /** - * If a feature should make use of any of the helper functions in this class, - * it's layer should have a modifyInteraction that is registered via this method. - */ - public static registerModifyEvents( - modifyInteraction: Modify - ) { - // These event don't propagate to anything else by default. - // We therefore have to propagate them manually to the specific features. - modifyInteraction.on('modifystart', (event) => { - event.features.forEach((featureLike) => { - const feature = featureLike as Feature; - feature.dispatchEvent(event); - const featureGeometry = feature.getGeometry() as T; - const coordinates = featureGeometry.getCoordinates(); - // We need at least 4 coordinates - if (coordinates.length < 4) { - throw new Error( - `Got unexpected short coordinates array: ${coordinates}` - ); - } - const mousePosition = event.mapBrowserEvent.coordinate; - const corner = getNearestCoordinateName(mousePosition, { - topLeft: coordinates[0]!, - topRight: coordinates[1]!, - bottomRight: coordinates[2]!, - bottomLeft: coordinates[3]!, - }); - const modifyGeometry: ModifyGeometry = { - // We need to clone the geometry to be able to properly resize it - geometry: featureGeometry.clone(), - modifyCorner: corner, - }; - feature.set('modifyGeometry', modifyGeometry, true); - }); - }); - modifyInteraction.on('modifyend', (event) => { - event.features.forEach((featureLike) => { - const feature = featureLike as Feature; - feature.dispatchEvent(event); - const modifyGeometry = feature.get('modifyGeometry'); - if (modifyGeometry) { - feature.setGeometry(modifyGeometry.geometry); - feature.unset('modifyGeometry', true); - } - }); - }); - } - - public onModifyEnd( - feature: Feature, - callback: (newCoordinates: Position[]) => void - ) { - feature.addEventListener('modifyend', (event) => { - const modifyGeometry = feature.get( - 'modifyGeometry' - ) as ModifyGeometry; - // The end coordinates in the event are the mouse coordinates and not the feature coordinates. - const coordinates = modifyGeometry.geometry.getCoordinates(); - callback( - coordinates.map((coordinate) => - Position.create(coordinate[0]!, coordinate[1]!) - ) - ); - }); - } - - // TODO: add more functionality (highlighting, etc.) -} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/movement-animator.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/movement-animator.ts index ea7f248bb..2a8945414 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/movement-animator.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/movement-animator.ts @@ -4,25 +4,18 @@ import type OlMap from 'ol/Map'; import type RenderEvent from 'ol/render/Event'; import type { Feature } from 'ol'; import { getVectorContext } from 'ol/render'; -import type Point from 'ol/geom/Point'; import type { UUID } from 'digital-fuesim-manv-shared'; -import { isArray, isEqual } from 'lodash-es'; -import type { LineString } from 'ol/geom'; -import type { Coordinate } from 'ol/coordinate'; - -export type Coordinates = T extends Point - ? Coordinate - : Coordinate[]; - -interface CoordinatePair { - startPosition: T; - endPosition: T; -} +import { isEqual } from 'lodash-es'; +import type { + Coordinates, + CoordinatePair, + GeometryWithCoordinates, +} from './geometry-helper'; /** * Animates the movement of a feature to a new position. */ -export class MovementAnimator { +export class MovementAnimator { /** * The time in milliseconds how long the moving animation should take */ @@ -30,7 +23,12 @@ export class MovementAnimator { constructor( private readonly olMap: OlMap, - private readonly layer: VectorLayer + private readonly layer: VectorLayer, + private readonly interpolateCoordinates: ( + positions: CoordinatePair, + progress: number + ) => Coordinates, + private readonly getCoordinates: (feature: Feature) => Coordinates ) {} /** @@ -52,12 +50,8 @@ export class MovementAnimator { endPosition: Coordinates ) { const startTime = Date.now(); - const featureGeometry = feature.getGeometry()!; - const startPosition = - featureGeometry.getCoordinates() as Coordinates; - // Stop an ongoing movement animation - this.stopMovementAnimation(feature as Feature); - // We don't have to animate this + const startPosition = this.getCoordinates(feature); + this.stopMovementAnimation(feature); if (isEqual(startPosition, endPosition)) { return; } @@ -76,25 +70,6 @@ export class MovementAnimator { this.olMap.render(); } - private isCoordinateArrayPair( - coordinates: CoordinatePair> - ): coordinates is CoordinatePair> { - return isArray(coordinates.startPosition[0]); - } - - private interpolate( - startCoordinate: Coordinate, - endCoordinate: Coordinate, - lerpFactor: number - ): Coordinate { - return [ - startCoordinate[0]! + - (endCoordinate[0]! - startCoordinate[0]!) * lerpFactor, - startCoordinate[1]! + - (endCoordinate[1]! - startCoordinate[1]!) * lerpFactor, - ]; - } - private setCoordinates(featureGeometry: T, coordinates: Coordinates) { // The ol typings are incorrect featureGeometry.setCoordinates(coordinates as any); @@ -107,7 +82,7 @@ export class MovementAnimator { private animationTick( event: RenderEvent, startTime: number, - positions: CoordinatePair>, + positions: CoordinatePair, feature: Feature ) { const featureGeometry = feature.getGeometry()!; @@ -124,33 +99,7 @@ export class MovementAnimator { this.olMap.render(); return; } - // If we have coordinate arrays, there must be at least as many endCoordinates as startCoordinates - if ( - this.isCoordinateArrayPair(positions) && - positions.startPosition.length > positions.endPosition.length - ) { - throw new Error( - `Got unexpected too few endPositions: ${JSON.stringify( - positions - )}` - ); - } - // The next position is calculated by a linear interpolation between the start and end position(s) - const nextPosition = ( - this.isCoordinateArrayPair(positions) - ? positions.startPosition.map((startPos, index) => - this.interpolate( - startPos, - positions.endPosition[index]!, - progress - ) - ) - : this.interpolate( - positions.startPosition as Coordinates, - positions.endPosition as Coordinates, - progress - ) - ) as Coordinates; + const nextPosition = this.interpolateCoordinates(positions, progress); this.setCoordinates(featureGeometry, nextPosition); getVectorContext(event).drawGeometry(featureGeometry); this.olMap.render(); diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-interactions-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-interactions-manager.ts new file mode 100644 index 000000000..a942112f7 --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-interactions-manager.ts @@ -0,0 +1,182 @@ +import type VectorLayer from 'ol/layer/Vector'; +import type VectorSource from 'ol/source/Vector'; +import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; +import type { Interaction } from 'ol/interaction'; +import { defaults as defaultInteractions } from 'ol/interaction'; +import type { Subject } from 'rxjs'; +import { combineLatest, takeUntil } from 'rxjs'; +import { selectExerciseStatus } from 'src/app/state/application/selectors/exercise.selectors'; +import type { Feature } from 'ol'; +import { Collection } from 'ol'; +import type OlMap from 'ol/Map'; +import type { AppState } from 'src/app/state/app.state'; +import type { Store } from '@ngrx/store'; +import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; +import type { ExerciseStatus, Role } from 'digital-fuesim-manv-shared'; +import type { TranslateEvent } from 'ol/interaction/Translate'; +import type { Pixel } from 'ol/pixel'; +import { featureElementKey } from '../feature-managers/element-manager'; +import { TranslateInteraction } from './translate-interaction'; +import type { PopupManager } from './popup-manager'; +import type { FeatureManager } from './feature-manager'; + +export class OlMapInteractionsManager { + private readonly featureLayers: VectorLayer[] = []; + private readonly trainerInteractions: Interaction[] = []; + private translateInteraction: TranslateInteraction = + new TranslateInteraction(); + private participantInteractions: Interaction[] = []; + private interactions: Collection = + new Collection(); + private lastStatus: ExerciseStatus | undefined; + private lastRole: Role | 'timeTravel' | undefined; + + constructor( + private readonly mapInteractions: Collection, + private readonly store: Store, + private readonly popupManager: PopupManager, + private readonly olMap: OlMap, + private readonly layerFeatureManagerDictionary: Map< + VectorLayer, + FeatureManager + >, + private readonly destroy$: Subject + ) { + this.updateInteractions(); + this.registerInteractionEnablementHandler(); + } + + public addFeatureLayer(layer: VectorLayer) { + this.featureLayers.push(layer); + this.syncInteractionsAndHandler(); + } + + public addTrainerInteraction(interaction: Interaction) { + this.trainerInteractions.push(interaction); + this.syncInteractionsAndHandler(); + } + + private syncInteractionsAndHandler() { + this.updateInteractions(); + this.registerDropHandler(); + this.applyInteractions(); + this.updateInteractionEnablement(this.lastStatus, this.lastRole); + } + + private updateTranslateInteraction() { + this.translateInteraction = new TranslateInteraction({ + layers: this.featureLayers, + hitTolerance: 10, + filter: (feature, layer) => { + const featureManager = this.layerFeatureManagerDictionary.get( + layer as VectorLayer + ); + return featureManager === undefined + ? false + : featureManager.isFeatureTranslatable(feature); + }, + }); + } + + private updateParticipantInteractions() { + this.participantInteractions = [this.translateInteraction]; + } + + private updateInteractions() { + this.updateTranslateInteraction(); + this.updateParticipantInteractions(); + this.interactions = defaultInteractions({ + pinchRotate: false, + altShiftDragRotate: false, + keyboard: true, + }).extend( + selectStateSnapshot(selectCurrentRole, this.store) === 'trainer' + ? [...this.participantInteractions, ...this.trainerInteractions] + : [...this.participantInteractions] + ); + } + + private applyInteractions() { + this.mapInteractions.clear(); + // We just want to modify this for the Map not do anything with it after so we ignore the returned value + // eslint-disable-next-line rxjs/no-ignored-observable + this.mapInteractions.extend(this.interactions.getArray()); + } + + // Register handlers that disable or enable certain interactions + private registerInteractionEnablementHandler() { + combineLatest([ + this.store.select(selectExerciseStatus), + this.store.select(selectCurrentRole), + ]) + .pipe(takeUntil(this.destroy$)) + .subscribe(([status, currentRole]) => { + this.updateInteractionEnablement(status, currentRole); + }); + } + + // this shows a paused overlay and disables interactions for participants when the exercise is paused + private updateInteractionEnablement( + status: ExerciseStatus | undefined, + currentRole: Role | 'timeTravel' | undefined + ) { + this.lastRole = currentRole; + this.lastStatus = status; + const isPausedAndParticipant = + status !== 'running' && currentRole === 'participant'; + const areInteractionsActive = + !isPausedAndParticipant && currentRole !== 'timeTravel'; + this.participantInteractions.forEach((interaction) => { + interaction.setActive(areInteractionsActive); + }); + this.popupManager.setPopupsEnabled(!isPausedAndParticipant); + this.getOlViewportElement().style.filter = isPausedAndParticipant + ? 'brightness(50%)' + : ''; + } + + private registerDropHandler() { + this.translateInteraction.on('translateend', (event) => { + const pixel = this.olMap.getPixelFromCoordinate(event.coordinate); + const droppedFeature: Feature = event.features.getArray()[0]!; + this.handleTranslateEnd(pixel, droppedFeature, event); + }); + } + + private handleTranslateEnd( + pixel: Pixel, + droppedFeature: Feature, + event: TranslateEvent + ) { + this.olMap.forEachFeatureAtPixel(pixel, (droppedOnFeature, layer) => { + // Skip layer when unset + if (layer === null) { + return; + } + + // Do not drop a feature on itself + if (droppedFeature === droppedOnFeature) { + return; + } + + // We stop propagating the event as soon as the onFeatureDropped function returns true + return this.layerFeatureManagerDictionary + .get(layer as VectorLayer)! + .onFeatureDrop( + this.getElementFromFeature(droppedFeature), + droppedOnFeature as Feature, + event + ); + }); + } + + private getOlViewportElement(): HTMLElement { + return this.olMap + .getTargetElement() + .querySelectorAll('.ol-viewport')[0] as HTMLElement; + } + + private getElementFromFeature(feature: Feature) { + return feature.get(featureElementKey); + } +} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts index f387e0c38..d04cb7d0e 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts @@ -1,55 +1,32 @@ import type { NgZone } from '@angular/core'; import type { Store } from '@ngrx/store'; -import type { - ImmutableJsonObject, - MergeIntersection, - UUID, +import { + upperLeftCornerOf, + lowerRightCornerOf, } from 'digital-fuesim-manv-shared'; -import type { Feature } from 'ol'; -import { Overlay, View } from 'ol'; -import { primaryAction, shiftKeyOnly } from 'ol/events/condition'; -import type Geometry from 'ol/geom/Geometry'; -import type LineString from 'ol/geom/LineString'; -import type Point from 'ol/geom/Point'; -import { defaults as defaultInteractions } from 'ol/interaction'; -import TileLayer from 'ol/layer/Tile'; -import VectorLayer from 'ol/layer/Vector'; +import { Collection, View } from 'ol'; +import type { Interaction } from 'ol/interaction'; +import type VectorLayer from 'ol/layer/Vector'; import OlMap from 'ol/Map'; -import VectorSource from 'ol/source/Vector'; -import XYZ from 'ol/source/XYZ'; -import type { Observable } from 'rxjs'; -import { combineLatest, pairwise, startWith, Subject, takeUntil } from 'rxjs'; +import type VectorSource from 'ol/source/Vector'; +import { Subject, takeUntil } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; -import { handleChanges } from 'src/app/shared/functions/handle-changes'; import type { AppState } from 'src/app/state/app.state'; import { - selectExerciseStatus, - selectTileMapProperties, - selectTransferLines, + selectSimulatedRegion, selectViewports, } from 'src/app/state/application/selectors/exercise.selectors'; -import { - selectCurrentRole, - selectRestrictedViewport, - selectVisibleCateringLines, - selectVisibleMapImages, - selectVisibleMaterials, - selectVisiblePatients, - selectVisiblePersonnel, - selectVisibleTransferPoints, - selectVisibleVehicles, - selectVisibleViewports, -} from 'src/app/state/application/selectors/shared.selectors'; +import { selectRestrictedViewport } from 'src/app/state/application/selectors/shared.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import type { TransferLinesService } from '../../core/transfer-lines.service'; import { startingPosition } from '../../starting-position'; import { CateringLinesFeatureManager } from '../feature-managers/catering-lines-feature-manager'; import { DeleteFeatureManager } from '../feature-managers/delete-feature-manager'; -import type { ElementManager } from '../feature-managers/element-manager'; import { MapImageFeatureManager } from '../feature-managers/map-images-feature-manager'; import { MaterialFeatureManager } from '../feature-managers/material-feature-manager'; import { PatientFeatureManager } from '../feature-managers/patient-feature-manager'; import { PersonnelFeatureManager } from '../feature-managers/personnel-feature-manager'; +import { SimulatedRegionFeatureManager } from '../feature-managers/simulated-region-feature-manager'; import { TransferLinesFeatureManager } from '../feature-managers/transfer-lines-feature-manager'; import { TransferPointFeatureManager } from '../feature-managers/transfer-point-feature-manager'; import { VehicleFeatureManager } from '../feature-managers/vehicle-feature-manager'; @@ -58,27 +35,21 @@ import { ViewportFeatureManager, } from '../feature-managers/viewport-feature-manager'; import type { FeatureManager } from './feature-manager'; -import { ModifyHelper } from './modify-helper'; -import type { OpenPopupOptions } from './popup-manager'; -import { TranslateInteraction } from './translate-interaction'; -import { createViewportModify } from './viewport-modify'; +import type { PopupManager } from './popup-manager'; +import { OlMapInteractionsManager } from './ol-map-interactions-manager'; +import { SatelliteLayerManager } from './satellite-layer-manager'; /** * This class should run outside the Angular zone for performance reasons. */ + export class OlMapManager { + private readonly _olMap: OlMap; + private featureManagers: FeatureManager[]; + private readonly mapInteractionsManager: OlMapInteractionsManager; + private static readonly defaultZoom = 20; private readonly destroy$ = new Subject(); - public readonly olMap: OlMap; - /** - * If this subject emits options, the specified popup should be toggled. - * If it emits undefined, the currently open popup should be closed. - */ - public readonly changePopup$ = new Subject< - OpenPopupOptions | undefined - >(); - - public readonly popupOverlay: Overlay; /** * key: the layer that is passed to the featureManager, that is saved in the value * ```ts @@ -87,108 +58,28 @@ export class OlMapManager { * featureManager.layer === layer * ``` */ - private readonly layerFeatureManagerDictionary = new Map< + public readonly layerFeatureManagerDictionary = new Map< VectorLayer, FeatureManager >(); - private static readonly defaultZoom = 20; - constructor( private readonly store: Store, private readonly exerciseService: ExerciseService, private readonly openLayersContainer: HTMLDivElement, - private readonly popoverContainer: HTMLDivElement, private readonly ngZone: NgZone, - transferLinesService: TransferLinesService + private readonly transferLinesService: TransferLinesService, + private readonly popupManager: PopupManager ) { - // Layers - const satelliteLayer = new TileLayer({ - preload: Number.POSITIVE_INFINITY, - }); - this.store - .select(selectTileMapProperties) - .pipe(takeUntil(this.destroy$)) - .subscribe((tileMapProperties) => { - satelliteLayer.setSource( - new XYZ({ - url: tileMapProperties.tileUrl, - maxZoom: tileMapProperties.maxZoom, - // We want to keep the tiles cached if we are zooming in and out fast - cacheSize: 1000, - }) - ); - }); - const transferPointLayer = this.createElementLayer(600); - const vehicleLayer = this.createElementLayer(1000); - const cateringLinesLayer = this.createElementLayer(); - const transferLinesLayer = this.createElementLayer(); - const patientLayer = this.createElementLayer(); - const personnelLayer = this.createElementLayer(); - const materialLayer = this.createElementLayer(); - const viewportLayer = this.createElementLayer(); - const mapImagesLayer = this.createElementLayer(10_000); - const deleteFeatureLayer = this.createElementLayer(); - this.popupOverlay = new Overlay({ - element: this.popoverContainer, - }); - - // The order in this array represents the order of the layers on the map (last element is on top) - const featureLayers = [ - deleteFeatureLayer, - mapImagesLayer, - transferLinesLayer, - transferPointLayer, - vehicleLayer, - cateringLinesLayer, - patientLayer, - personnelLayer, - materialLayer, - viewportLayer, - ]; - - // Interactions - const translateInteraction = new TranslateInteraction({ - layers: featureLayers, - hitTolerance: 10, - filter: (feature, layer) => { - const featureManager = this.layerFeatureManagerDictionary.get( - layer as VectorLayer - ); - return featureManager === undefined - ? false - : featureManager.isFeatureTranslatable(feature); - }, - }); - const viewportModify = createViewportModify(viewportLayer); - - const viewportTranslate = new TranslateInteraction({ - layers: [viewportLayer], - condition: (event) => primaryAction(event) && !shiftKeyOnly(event), - hitTolerance: 10, - }); - - ModifyHelper.registerModifyEvents(viewportModify); - - const alwaysInteractions = [translateInteraction]; - const customInteractions = - selectStateSnapshot(selectCurrentRole, this.store) === 'trainer' - ? [...alwaysInteractions, viewportTranslate, viewportModify] - : alwaysInteractions; - - this.olMap = new OlMap({ - interactions: defaultInteractions({ - pinchRotate: false, - altShiftDragRotate: false, - keyboard: true, - }).extend(customInteractions), + this._olMap = new OlMap({ + interactions: new Collection(), // We use Angular buttons instead controls: [], target: this.openLayersContainer, // Note: The order of this array determines the order of the objects on the map. // The most bottom objects must be at the top of the array. - layers: [satelliteLayer, ...featureLayers], - overlays: [this.popupOverlay], + layers: [], + overlays: [this.popupManager.popupOverlay], view: new View({ center: [startingPosition.x, startingPosition.y], zoom: OlMapManager.defaultZoom, @@ -199,136 +90,44 @@ export class OlMapManager { }), }); - // FeatureManagers - if (selectStateSnapshot(selectCurrentRole, this.store) === 'trainer') { - this.registerFeatureElementManager( - new TransferLinesFeatureManager(transferLinesLayer), - this.store.select(selectTransferLines) - ); - transferLinesService.displayTransferLines$.subscribe((display) => { - transferLinesLayer.setVisible(display); - }); - - const deleteHelper = new DeleteFeatureManager( - this.store, - deleteFeatureLayer, - this.olMap, - this.exerciseService - ); - this.layerFeatureManagerDictionary.set( - deleteFeatureLayer, - deleteHelper - ); - } - this.registerFeatureElementManager( - new TransferPointFeatureManager( - this.olMap, - transferPointLayer, - this.store, - this.exerciseService - ), - this.store.select(selectVisibleTransferPoints) - ); - - this.registerFeatureElementManager( - new PatientFeatureManager( - this.store, - this.olMap, - patientLayer, - this.exerciseService - ), - this.store.select(selectVisiblePatients) - ); - - this.registerFeatureElementManager( - new VehicleFeatureManager( - this.olMap, - vehicleLayer, - this.exerciseService - ), - this.store.select(selectVisibleVehicles) - ); - - this.registerFeatureElementManager( - new PersonnelFeatureManager( - this.olMap, - personnelLayer, - this.exerciseService - ), - this.store.select(selectVisiblePersonnel) - ); + this.featureManagers = []; + this.initializeFeatureManagers(); - this.registerFeatureElementManager( - new MaterialFeatureManager( - this.olMap, - materialLayer, - this.exerciseService - ), - this.store.select(selectVisibleMaterials) + this.mapInteractionsManager = new OlMapInteractionsManager( + this.olMap.getInteractions(), + store, + popupManager, + this.olMap, + this.layerFeatureManagerDictionary, + this.destroy$ ); - this.registerFeatureElementManager( - new MapImageFeatureManager( - this.olMap, - mapImagesLayer, - this.exerciseService, - this.store - ), - this.store.select(selectVisibleMapImages) + const satelliteLayerManager = new SatelliteLayerManager( + store, + this.destroy$ ); - this.registerFeatureElementManager( - new CateringLinesFeatureManager(cateringLinesLayer), - this.store.select(selectVisibleCateringLines) - ); + this.olMap.getLayers().clear(); + this.olMap.addLayer(satelliteLayerManager.satelliteLayer); - this.registerFeatureElementManager( - new ViewportFeatureManager( - this.olMap, - viewportLayer, - this.exerciseService, - this.store - ), - this.store.select(selectVisibleViewports) - ); + // the mapInteractionsManager needs to be set and the satelliteLayer needs to be added before this is possible + this.registerFeatureManagers(); - this.registerPopupTriggers(translateInteraction); - this.registerDropHandler(translateInteraction); - this.registerDropHandler(viewportTranslate); this.registerViewportRestriction(); - // Register handlers that disable or enable certain interactions - combineLatest([ - this.store.select(selectExerciseStatus), - this.store.select(selectCurrentRole), - ]) - .pipe(takeUntil(this.destroy$)) - .subscribe(([status, currentRole]) => { - const showPausedOverlay = - status !== 'running' && currentRole === 'participant'; - customInteractions.forEach((interaction) => { - interaction.setActive( - !showPausedOverlay && currentRole !== 'timeTravel' - ); - }); - this.setPopupsEnabled(!showPausedOverlay); - this.getOlViewportElement().style.filter = showPausedOverlay - ? 'brightness(50%)' - : ''; - }); + popupManager.registerPopupTriggers( + this.olMap, + openLayersContainer, + this.layerFeatureManagerDictionary + ); } - private popupsEnabled = true; - private setPopupsEnabled(enabled: boolean) { - this.popupsEnabled = enabled; - if (!enabled) { - // Close all open popups - this.changePopup$.next(undefined); - } + public get olMap(): OlMap { + return this._olMap; } private registerViewportRestriction() { - this.tryToFitViewToViewports(false); + this.tryToFitViewForOverview(false); this.store .select(selectRestrictedViewport) .pipe(takeUntil(this.destroy$)) @@ -343,11 +142,13 @@ export class OlMapManager { } const center = view.getCenter()!; const previousZoom = view.getZoom()!; + const targetUpperLeftCorner = upperLeftCornerOf(viewport); + const targetLowerRightCorner = lowerRightCornerOf(viewport); const targetExtent = [ - viewport.position.x, - viewport.position.y - viewport.size.height, - viewport.position.x + viewport.size.width, - viewport.position.y, + targetUpperLeftCorner.x, + targetLowerRightCorner.y, + targetLowerRightCorner.x, + targetUpperLeftCorner.y, ]; view.fit(targetExtent); const matchingZoom = view.getZoom()!; @@ -363,137 +164,10 @@ export class OlMapManager { }); } - private registerFeatureElementManager< - Element extends ImmutableJsonObject, - T extends MergeIntersection< - ElementManager & FeatureManager - > - >( - featureManager: T, - elementDictionary$: Observable<{ [id: UUID]: Element }> - ) { - this.layerFeatureManagerDictionary.set( - featureManager.layer, - featureManager - ); - featureManager.togglePopup$?.subscribe(this.changePopup$); - // Propagate the changes on an element to the featureManager - elementDictionary$ - .pipe(startWith({}), pairwise(), takeUntil(this.destroy$)) - .subscribe(([oldElementDictionary, newElementDictionary]) => { - // run outside angular zone for better performance - this.ngZone.runOutsideAngular(() => { - handleChanges(oldElementDictionary, newElementDictionary, { - createHandler: (element) => - featureManager.onElementCreated(element), - deleteHandler: (element) => - featureManager.onElementDeleted(element), - changeHandler: (oldElement, newElement) => - featureManager.onElementChanged( - oldElement, - newElement - ), - }); - }); - }); - } - - private registerPopupTriggers(translateInteraction: TranslateInteraction) { - this.olMap.on('singleclick', (event) => { - if (!this.popupsEnabled) { - return; - } - this.olMap.forEachFeatureAtPixel( - event.pixel, - (feature, layer) => { - // Skip layer when unset - if (layer === null) { - return false; - } - this.layerFeatureManagerDictionary - .get( - layer as VectorLayer< - VectorSource - > - )! - .onFeatureClicked( - event, - feature as Feature - ); - // we only want the top one -> a truthy return breaks this loop - return true; - }, - { hitTolerance: 10 } - ); - if (!this.olMap!.hasFeatureAtPixel(event.pixel)) { - this.changePopup$.next(undefined); - } - }); - - // Automatically close the popup - translateInteraction.on('translating', (event) => { - if ( - event.coordinate[0] === event.startCoordinate[0] && - event.coordinate[1] === event.startCoordinate[1] - ) { - return; - } - this.changePopup$.next(undefined); - }); - this.olMap.getView().on(['change:resolution', 'change:center'], () => { - this.changePopup$.next(undefined); - }); - } - - private registerDropHandler(translateInteraction: TranslateInteraction) { - translateInteraction.on('translateend', (event) => { - const pixel = this.olMap.getPixelFromCoordinate(event.coordinate); - this.olMap.forEachFeatureAtPixel(pixel, (feature, layer) => { - // Skip layer when unset - if (layer === null) { - return; - } - // We stop propagating the event as soon as the onFeatureDropped function returns true - return this.layerFeatureManagerDictionary - .get( - layer as VectorLayer> - )! - .onFeatureDrop( - event, - event.features.getArray()[0] as Feature< - LineString | Point - >, - feature as Feature - ); - }); - }); - } - /** - * @param renderBuffer The size of the largest symbol, line width or label on the highest zoom level. + * Sets the map's view to see all viewports and simulated regions. */ - private createElementLayer( - renderBuffer = 250 - ) { - return new VectorLayer({ - // These two settings prevent clipping during animation/interaction but cause a performance hit -> disable if needed - updateWhileAnimating: true, - updateWhileInteracting: true, - renderBuffer, - source: new VectorSource(), - }); - } - - private getOlViewportElement(): HTMLElement { - return this.olMap - .getTargetElement() - .querySelectorAll('.ol-viewport')[0] as HTMLElement; - } - - /** - * Sets the map's view to see all viewports. - */ - public tryToFitViewToViewports(animate = true) { + public tryToFitViewForOverview(animate = true) { if ( selectStateSnapshot(selectRestrictedViewport, this.store) !== undefined @@ -501,29 +175,28 @@ export class OlMapManager { // We are restricted to a viewport -> you can't fit the view return; } - const viewports = Object.values( - selectStateSnapshot(selectViewports, this.store) - ); + const elements = [ + ...Object.values(selectStateSnapshot(selectViewports, this.store)), + ...Object.values( + selectStateSnapshot(selectSimulatedRegion, this.store) + ), + ]; const view = this.olMap.getView(); - if (viewports.length === 0) { + if (elements.length === 0) { view.setCenter([startingPosition.x, startingPosition.y]); return; } const minX = Math.min( - ...viewports.map((viewport) => viewport.position.x) + ...elements.map((element) => upperLeftCornerOf(element).x) ); const minY = Math.min( - ...viewports.map( - (viewport) => viewport.position.y - viewport.size.height - ) + ...elements.map((element) => lowerRightCornerOf(element).y) ); const maxX = Math.max( - ...viewports.map( - (viewport) => viewport.position.x + viewport.size.width - ) + ...elements.map((element) => lowerRightCornerOf(element).x) ); const maxY = Math.max( - ...viewports.map((viewport) => viewport.position.y) + ...elements.map((element) => upperLeftCornerOf(element).y) ); const padding = 25; view.fit([minX, minY, maxX, maxY], { @@ -543,7 +216,100 @@ export class OlMapManager { public destroy() { this.destroy$.next(); - this.olMap?.dispose(); - this.olMap?.setTarget(undefined); + this.olMap.dispose(); + this.olMap.setTarget(undefined); + } + + // This lets featureManagers register themselves and adds them to the layerFeatureManagerDictionary + + private registerFeatureManagers() { + this.featureManagers.forEach((featureManager) => { + this.layerFeatureManagerDictionary.set( + featureManager.layer, + featureManager + ); + featureManager.register( + this.popupManager.changePopup$, + this.destroy$, + this.ngZone, + this.mapInteractionsManager + ); + }); + } + + private initializeFeatureManagers() { + const transferLinesFeatureManager = new TransferLinesFeatureManager( + this.store, + this.transferLinesService, + this.olMap + ); + const transferPointFeatureManager = new TransferPointFeatureManager( + this.olMap, + this.store, + this.exerciseService + ); + const patientFeatureManager = new PatientFeatureManager( + this.store, + this.olMap, + this.exerciseService + ); + const vehicleFeatureManager = new VehicleFeatureManager( + this.olMap, + this.store, + this.exerciseService + ); + const personnelFeatureManager = new PersonnelFeatureManager( + this.olMap, + this.store, + this.exerciseService + ); + const materialFeatureManager = new MaterialFeatureManager( + this.olMap, + this.store, + this.exerciseService + ); + const mapImageFeatureManager = new MapImageFeatureManager( + this.olMap, + this.exerciseService, + this.store + ); + const cateringLinesFeatureManager = new CateringLinesFeatureManager( + this.store, + this.olMap + ); + + const viewportFeatureManager = new ViewportFeatureManager( + this.olMap, + this.exerciseService, + this.store + ); + const simulatedRegionFeatureManager = new SimulatedRegionFeatureManager( + this.olMap, + this.exerciseService, + this.store + ); + + const deleteFeatureManager = new DeleteFeatureManager( + this.store, + this.olMap, + this.exerciseService + ); + + // Register the Feature Managers in the correct Order + // The order represents the order of the layers on the map (last element is on top) + + this.featureManagers = [ + deleteFeatureManager, + simulatedRegionFeatureManager, + mapImageFeatureManager, + transferLinesFeatureManager, + transferPointFeatureManager, + vehicleFeatureManager, + cateringLinesFeatureManager, + patientFeatureManager, + personnelFeatureManager, + materialFeatureManager, + viewportFeatureManager, + ]; } } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/point-geometry-helper.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/point-geometry-helper.ts new file mode 100644 index 000000000..a9c65dee8 --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/point-geometry-helper.ts @@ -0,0 +1,39 @@ +import type { WithPosition } from 'digital-fuesim-manv-shared'; +import { + MapCoordinates, + currentCoordinatesOf, +} from 'digital-fuesim-manv-shared'; +import { Feature } from 'ol'; +import { Point } from 'ol/geom'; +import type { + CoordinatePair, + Coordinates, + GeometryHelper, + Positions, +} from './geometry-helper'; +import { interpolate } from './geometry-helper'; + +export class PointGeometryHelper implements GeometryHelper { + create = (element: WithPosition): Feature => + new Feature(new Point(this.getElementCoordinates(element))); + + getElementCoordinates = (element: WithPosition): Coordinates => [ + currentCoordinatesOf(element).x, + currentCoordinatesOf(element).y, + ]; + + getFeatureCoordinates = (feature: Feature): Coordinates => + feature.getGeometry()!.getCoordinates(); + + interpolateCoordinates = ( + positions: CoordinatePair, + progress: number + ): Coordinates => + interpolate(positions.startPosition, positions.endPosition, progress); + + getFeaturePosition = (feature: Feature): Positions => + MapCoordinates.create( + this.getFeatureCoordinates(feature)[0]!, + this.getFeatureCoordinates(feature)[1]! + ); +} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/polygon-geometry-helper.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/polygon-geometry-helper.ts new file mode 100644 index 000000000..29fc313d5 --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/polygon-geometry-helper.ts @@ -0,0 +1,66 @@ +import { + currentCoordinatesOf, + MapCoordinates, +} from 'digital-fuesim-manv-shared'; +import { Feature } from 'ol'; +import { Polygon } from 'ol/geom'; +import type { + CoordinatePair, + Coordinates, + GeometryHelper, + Positions, + ResizableElement, +} from './geometry-helper'; +import { interpolate } from './geometry-helper'; + +export class PolygonGeometryHelper + implements GeometryHelper +{ + create = (element: ResizableElement): Feature => + new Feature(new Polygon(this.getElementCoordinates(element))); + + getElementCoordinates = ( + element: ResizableElement + ): Coordinates => [ + [ + [currentCoordinatesOf(element).x, currentCoordinatesOf(element).y], + [ + currentCoordinatesOf(element).x + element.size.width, + currentCoordinatesOf(element).y, + ], + [ + currentCoordinatesOf(element).x + element.size.width, + currentCoordinatesOf(element).y - element.size.height, + ], + [ + currentCoordinatesOf(element).x, + currentCoordinatesOf(element).y - element.size.height, + ], + [currentCoordinatesOf(element).x, currentCoordinatesOf(element).y], + ], + ]; + + getFeatureCoordinates = (feature: Feature): Coordinates => + feature.getGeometry()!.getCoordinates(); + + interpolateCoordinates = ( + positions: CoordinatePair, + progress: number + ): Coordinates => + positions.startPosition.map((coordinates, coordinatesIndex) => + coordinates.map((startCoordinate, coordinateIndex) => + interpolate( + startCoordinate, + positions.endPosition[coordinatesIndex]![coordinateIndex]!, + progress + ) + ) + ); + + getFeaturePosition = (feature: Feature): Positions => + this.getFeatureCoordinates(feature).map((coordinates) => + coordinates.map((coordinate) => + MapCoordinates.create(coordinate[0]!, coordinate[1]!) + ) + ); +} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/popup-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/popup-manager.ts index d2d87e97a..4aa9af2c9 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/popup-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/popup-manager.ts @@ -5,22 +5,87 @@ import type { ViewContainerRef, } from '@angular/core'; import { isEqual } from 'lodash-es'; -import type { Overlay } from 'ol'; +import type { Feature } from 'ol'; +import { Overlay } from 'ol'; +import type VectorLayer from 'ol/layer/Vector'; +import type VectorSource from 'ol/source/Vector'; import { Subject, takeUntil } from 'rxjs'; +import type OlMap from 'ol/Map'; import type { Positioning } from '../../utility/types/positioning'; +import type { FeatureManager } from './feature-manager'; /** * A class that manages the creation and destruction of a single popup with freely customizable content * that should appear on the {@link popupOverlay}. */ export class PopupManager { + /** + * If this subject emits options, the specified popup should be toggled. + * If it emits undefined, the currently open popup should be closed. + */ + public readonly changePopup$ = new Subject< + OpenPopupOptions | undefined + >(); + + public readonly popupOverlay: Overlay; private readonly destroy$ = new Subject(); private currentlyOpenPopupOptions?: OpenPopupOptions; + private popupsEnabled = true; constructor( - private readonly popupOverlay: Overlay, - private readonly popoverContent: ViewContainerRef - ) {} + private readonly popoverContent: ViewContainerRef, + private readonly popoverContainer: HTMLDivElement + ) { + this.popupOverlay = new Overlay({ + element: this.popoverContainer, + }); + } + public setPopupsEnabled(enabled: boolean) { + this.popupsEnabled = enabled; + if (!enabled) { + // Close all open popups + this.changePopup$.next(undefined); + } + } + + public registerPopupTriggers( + olMap: OlMap, + openLayersContainer: HTMLDivElement, + layerFeatureManagerDictionary: Map< + VectorLayer, + FeatureManager + > + ) { + olMap.on('singleclick', (event) => { + if (!this.popupsEnabled) { + return; + } + const hasBeenHandled = olMap.forEachFeatureAtPixel( + event.pixel, + (feature, layer) => { + // Skip layer when unset + if (layer === null) { + return false; + } + layerFeatureManagerDictionary + .get(layer as VectorLayer)! + .onFeatureClicked(event, feature as Feature); + // we only want the top one -> a truthy return breaks this loop + return true; + }, + { hitTolerance: 10 } + ); + if (!hasBeenHandled) { + this.changePopup$.next(undefined); + } + }); + + openLayersContainer.addEventListener('keydown', (event) => { + if ((event as KeyboardEvent).key === 'Escape') { + this.changePopup$.next(undefined); + } + }); + } /** * Toggles the popup with the given options. diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/resize-rectangle-interaction.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/resize-rectangle-interaction.ts new file mode 100644 index 000000000..38865567d --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/resize-rectangle-interaction.ts @@ -0,0 +1,156 @@ +import type { Feature, MapBrowserEvent } from 'ol'; +import type { Coordinate } from 'ol/coordinate'; +import { distance } from 'ol/coordinate'; +import BaseEvent from 'ol/events/Event'; +import type { Polygon } from 'ol/geom'; +import PointerInteraction from 'ol/interaction/Pointer'; +import type VectorSource from 'ol/source/Vector'; + +/** + * Provides the ability to resize a rectangle by dragging any of its corners. + */ +export class ResizeRectangleInteraction extends PointerInteraction { + /** + * The tolerance in coordinates for hitting a corner. + */ + private readonly hitTolerance = 3; + + /** + * Temporary values for the current resize operation. + * If undefined no resize operation is currently in progress. + */ + private currentResizeValues?: CurrentResizeValues; + + constructor(private readonly source: VectorSource) { + super({ + handleDownEvent: (event) => this._handleDownEvent(event), + handleDragEvent: (event) => this._handleDragEvent(event), + handleUpEvent: (event) => this._handleUpEvent(event), + }); + } + + private _handleDownEvent(event: MapBrowserEvent): boolean { + const mouseCoordinate = event.coordinate; + const feature = + this.source.getClosestFeatureToCoordinate(mouseCoordinate); + if (!feature) { + return false; + } + const geometry = feature.getGeometry()!; + const corners = geometry.getCoordinates()![0]!; + const distances = corners.map((corner) => + distance(corner, mouseCoordinate) + ); + const minDistance = Math.min(...distances); + if (minDistance > this.hitTolerance) { + // Only corners are relevant for us + return false; + } + const nearestCorner = corners[distances.indexOf(minDistance)]; + const maxDistance = Math.max(...distances); + const furthestCorner = corners[distances.indexOf(maxDistance)]; + if (nearestCorner === undefined || furthestCorner === undefined) { + return false; + } + this.currentResizeValues = { + draggedCorner: nearestCorner, + originCorner: furthestCorner, + feature, + currentScale: { x: 1, y: 1 }, + }; + return true; + } + + private _handleDragEvent(event: MapBrowserEvent): boolean { + if (this.currentResizeValues === undefined) { + return false; + } + const mouseCoordinate = event.coordinate; + const newXScale = + (mouseCoordinate[0]! - this.currentResizeValues.originCorner[0]!) / + (this.currentResizeValues.draggedCorner[0]! - + this.currentResizeValues.originCorner[0]!); + const newYScale = + (this.currentResizeValues.originCorner[1]! - mouseCoordinate[1]!) / + (this.currentResizeValues.originCorner[1]! - + this.currentResizeValues.draggedCorner[1]!); + this.currentResizeValues.feature + .getGeometry()! + .scale( + newXScale / this.currentResizeValues.currentScale!.x, + newYScale / this.currentResizeValues.currentScale!.y, + this.currentResizeValues.originCorner + ); + this.currentResizeValues.currentScale = { x: newXScale, y: newYScale }; + return true; + } + + private _handleUpEvent(event: MapBrowserEvent): boolean { + if (this.currentResizeValues === undefined) { + return true; + } + + const coordinates = this.currentResizeValues.feature + .getGeometry()! + .getCoordinates()![0]!; + const topLeftCoordinate = coordinates.reduce( + (smallestCoordinate, coordinate) => + coordinate[0]! <= smallestCoordinate[0]! || + coordinate[1]! >= smallestCoordinate[1]! + ? coordinate + : smallestCoordinate, + [Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY] + ); + this.currentResizeValues.feature.dispatchEvent( + new ResizeEvent( + this.currentResizeValues.currentScale, + this.currentResizeValues.originCorner, + topLeftCoordinate + ) + ); + this.currentResizeValues = undefined; + return false; + } + + static onResize( + feature: Feature, + callback: (event: ResizeEvent) => void + ) { + feature.addEventListener( + resizeRectangleEventType, + callback as (event: BaseEvent | Event) => void + ); + } +} + +interface CurrentResizeValues { + draggedCorner: Coordinate; + /** + * The corner that doesn't move during the resize. + */ + originCorner: Coordinate; + /** + * The feature that is currently being resized. + */ + feature: Feature; + currentScale: { x: number; y: number }; +} + +// TODO: This doesn't work as a static member of ResizeEvent, because it is undefined at runtime. Why? +const resizeRectangleEventType = 'resizerectangle'; + +class ResizeEvent extends BaseEvent { + constructor( + public readonly scale: { x: number; y: number }, + /** + * The coordinate of the corner that didn't move during the resize. + */ + public readonly origin: Coordinate, + /** + * The new top left coordinate of the rectangle. + */ + public readonly topLeftCoordinate: Coordinate + ) { + super(resizeRectangleEventType); + } +} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/satellite-layer-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/satellite-layer-manager.ts new file mode 100644 index 000000000..8ae8a9f3e --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/satellite-layer-manager.ts @@ -0,0 +1,36 @@ +import type { Store } from '@ngrx/store'; +import TileLayer from 'ol/layer/Tile'; +import XYZ from 'ol/source/XYZ'; +import { takeUntil } from 'rxjs'; +import type { AppState } from 'src/app/state/app.state'; +import { selectTileMapProperties } from 'src/app/state/application/selectors/exercise.selectors'; + +export class SatelliteLayerManager { + private readonly _satelliteLayer: TileLayer; + + public get satelliteLayer(): TileLayer { + return this._satelliteLayer; + } + + constructor( + private readonly store: Store, + private readonly destroy$: any + ) { + this._satelliteLayer = new TileLayer({ + preload: Number.POSITIVE_INFINITY, + }); + this.store + .select(selectTileMapProperties) + .pipe(takeUntil(this.destroy$)) + .subscribe((tileMapProperties) => { + this._satelliteLayer.setSource( + new XYZ({ + url: tileMapProperties.tileUrl, + maxZoom: tileMapProperties.maxZoom, + // We want to keep the tiles cached if we are zooming in and out fast + cacheSize: 1000, + }) + ); + }); + } +} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/translate-interaction.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/translate-interaction.ts index b78f05b38..0b949eed7 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/translate-interaction.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/translate-interaction.ts @@ -1,9 +1,8 @@ -import { Position } from 'digital-fuesim-manv-shared'; import { isEqual } from 'lodash-es'; import type { Feature, MapBrowserEvent } from 'ol'; -import type { LineString, Point } from 'ol/geom'; +import type { Point } from 'ol/geom'; import { Translate } from 'ol/interaction'; -import { isCoordinateArray } from '../feature-managers/element-feature-manager'; +import type { GeometryWithCoordinates, Positions } from './geometry-helper'; /** * Translates (moves) a feature to a new position. @@ -47,29 +46,14 @@ export class TranslateInteraction extends Translate { * * You can only call this function if the layer of the feature has this Interaction. */ - public static onTranslateEnd( + public static onTranslateEnd( feature: Feature, - callback: ( - newCoordinates: T extends Point ? Position : Position[] - ) => void + callback: (newCoordinates: Positions) => void, + getPosition: (feature: Feature) => Positions ) { feature.addEventListener('translateend', (event) => { // The end coordinates in the event are the mouse coordinates and not the feature coordinates. - const coordinates = feature.getGeometry()!.getCoordinates(); - if (isCoordinateArray(coordinates)) { - callback( - coordinates.map((coordinate) => - Position.create(coordinate[0]!, coordinate[1]!) - ) as T extends Point ? never : Position[] - ); - return; - } - callback( - Position.create( - coordinates[0]!, - coordinates[1]! - ) as T extends Point ? Position : never - ); + callback(getPosition(feature)); }); } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/viewport-modify.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/viewport-modify.ts deleted file mode 100644 index 487b31638..000000000 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/viewport-modify.ts +++ /dev/null @@ -1,67 +0,0 @@ -import type { Feature } from 'ol'; -import { primaryAction, shiftKeyOnly } from 'ol/events/condition'; -import type { LineString, Point } from 'ol/geom'; -import { Modify } from 'ol/interaction'; -import type VectorLayer from 'ol/layer/Vector'; -import type VectorSource from 'ol/source/Vector'; -import type { CornerName, ModifyGeometry } from './modify-helper'; - -const originCornerDict: { - [key in CornerName]: { originIndex: number; cornerIndex: number }; -} = { - bottomRight: { originIndex: 0, cornerIndex: 2 }, - bottomLeft: { originIndex: 1, cornerIndex: 3 }, - topLeft: { originIndex: 2, cornerIndex: 0 }, - topRight: { originIndex: 3, cornerIndex: 1 }, -}; - -export function createViewportModify( - viewportLayer: VectorLayer> -): Modify { - const defaultStyle = new Modify({ source: viewportLayer.getSource()! }) - .getOverlay() - .getStyleFunction(); - return new Modify({ - source: viewportLayer.getSource()!, - condition: (event) => primaryAction(event) && shiftKeyOnly(event), - deleteCondition: () => false, - insertVertexCondition: () => false, - style: (feature) => { - (feature.get('features') as Feature[]).forEach((modifyFeature) => { - const modifyGeometry = modifyFeature.get( - 'modifyGeometry' - ) as ModifyGeometry; - if (!modifyGeometry) { - return; - } - const mouseCoordinate = ( - feature.getGeometry() as Point - ).getCoordinates(); - - const corners = modifyGeometry.geometry.getCoordinates(); - const { originIndex, cornerIndex } = - originCornerDict[modifyGeometry.modifyCorner]; - // The corners array must be big enough. - if ( - corners.length <= originIndex || - corners.length <= cornerIndex - ) { - throw new Error( - `corners must be at least as big to satisfy originIndex (${originIndex}) and cornerIndex (${cornerIndex}): ${corners}` - ); - } - const origin = corners[originIndex]!; - const corner = corners[cornerIndex]!; - modifyGeometry.geometry.scale( - (mouseCoordinate[0]! - origin[0]!) / - (corner[0]! - origin[0]!), - (origin[1]! - mouseCoordinate[1]!) / - (origin[1]! - corner[1]!), - origin - ); - }); - // This renders the default LineString style. The function ignores all arguments. - return defaultStyle!(feature, 123); - }, - }); -} diff --git a/frontend/src/app/pages/exercises/exercise/shared/trainer-map-editor/trainer-map-editor.component.html b/frontend/src/app/pages/exercises/exercise/shared/trainer-map-editor/trainer-map-editor.component.html index 4b89864a6..4d3699728 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/trainer-map-editor/trainer-map-editor.component.html +++ b/frontend/src/app/pages/exercises/exercise/shared/trainer-map-editor/trainer-map-editor.component.html @@ -87,6 +87,39 @@
Ansicht/Transferpunkt

+
  • +
    Simulierte Bereiche
    +
    +
    +
    + +
    +
    +
    + Simulierter Bereich +
    +
    +
    +
    +
  • Patienten diff --git a/frontend/src/app/pages/exercises/exercise/shared/trainer-map-editor/trainer-map-editor.component.ts b/frontend/src/app/pages/exercises/exercise/shared/trainer-map-editor/trainer-map-editor.component.ts index e1258306f..6a74a0a67 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/trainer-map-editor/trainer-map-editor.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/trainer-map-editor/trainer-map-editor.component.ts @@ -6,6 +6,7 @@ import { colorCodeMap, TransferPoint, Viewport, + SimulatedRegion, } from 'digital-fuesim-manv-shared'; import type { AppState } from 'src/app/state/app.state'; import { @@ -54,6 +55,10 @@ export class TrainerMapEditorComponent { private readonly ngbModalService: NgbModal ) {} + public readonly simulatedRegionTemplate = { + image: SimulatedRegion.image, + }; + public readonly viewportTemplate = { image: Viewport.image, }; diff --git a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/start-point-name/start-point-name.component.html b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/start-point-name/start-point-name.component.html index ce930f714..fee500aee 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/start-point-name/start-point-name.component.html +++ b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/start-point-name/start-point-name.component.html @@ -1,7 +1,7 @@ - + {{ startPoint.alarmGroupName }} diff --git a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/start-point-name/start-point-name.component.ts b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/start-point-name/start-point-name.component.ts index ab0ec5e45..e68432c17 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/start-point-name/start-point-name.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/start-point-name/start-point-name.component.ts @@ -1,8 +1,5 @@ import { Component, Input } from '@angular/core'; -import type { - AlarmGroupStartPoint, - TransferStartPoint, -} from 'digital-fuesim-manv-shared'; +import { StartPoint } from 'digital-fuesim-manv-shared'; @Component({ selector: 'app-start-point-name', @@ -10,5 +7,5 @@ import type { styleUrls: ['./start-point-name.component.scss'], }) export class StartPointNameComponent { - @Input() startPoint!: AlarmGroupStartPoint | TransferStartPoint; + @Input() startPoint!: StartPoint; } diff --git a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.html b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.html index b17308b0d..0138c6716 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.html +++ b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.html @@ -1,3 +1,4 @@ + @@ -37,21 +38,21 @@ @@ -71,21 +72,21 @@ diff --git a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.ts b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.ts index 35fdd6a1a..da2e76397 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.ts @@ -1,5 +1,6 @@ import { Component } from '@angular/core'; import { Store } from '@ngrx/store'; +import { currentTransferOf } from 'digital-fuesim-manv-shared'; import type { AppState } from 'src/app/state/app.state'; import { selectExerciseStatus, @@ -20,6 +21,8 @@ export class TransferOverviewTableComponent { selectPersonnelInTransfer ); + public currentTransferOf = currentTransferOf; + public readonly exerciseStatus$ = this.store.select(selectExerciseStatus); constructor(private readonly store: Store) {} diff --git a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-target-input/transfer-target-input.component.ts b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-target-input/transfer-target-input.component.ts index 2bd0ab98f..dd84fa34e 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-target-input/transfer-target-input.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-target-input/transfer-target-input.component.ts @@ -11,7 +11,7 @@ import { selectTransferPoints } from 'src/app/state/application/selectors/exerci styleUrls: ['./transfer-target-input.component.scss'], }) export class TransferTargetInputComponent { - @Input() elementType!: 'personnel' | 'vehicles'; + @Input() elementType!: 'personnel' | 'vehicle'; @Input() elementId!: UUID; @Input() transfer!: Transfer; diff --git a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-time-input/transfer-time-input.component.ts b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-time-input/transfer-time-input.component.ts index 011a25963..f01016989 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-time-input/transfer-time-input.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-time-input/transfer-time-input.component.ts @@ -11,7 +11,7 @@ import { selectCurrentTime } from 'src/app/state/application/selectors/exercise. styleUrls: ['./transfer-time-input.component.scss'], }) export class TransferTimeInputComponent { - @Input() elementType!: 'personnel' | 'vehicles'; + @Input() elementType!: 'personnel' | 'vehicle'; @Input() elementId!: UUID; diff --git a/frontend/src/app/pages/exercises/exercise/shared/utility/types/with-position.ts b/frontend/src/app/pages/exercises/exercise/shared/utility/types/with-position.ts deleted file mode 100644 index 64c7c42dd..000000000 --- a/frontend/src/app/pages/exercises/exercise/shared/utility/types/with-position.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { Position } from 'digital-fuesim-manv-shared'; - -export type WithPosition = T & { - position: Position; -}; diff --git a/frontend/src/app/pages/landing-page/landing-page/landing-page.component.html b/frontend/src/app/pages/landing-page/landing-page/landing-page.component.html index 66e862e4d..186981c59 100644 --- a/frontend/src/app/pages/landing-page/landing-page/landing-page.component.html +++ b/frontend/src/app/pages/landing-page/landing-page/landing-page.component.html @@ -91,7 +91,7 @@

    Über dieses Projekt

    Diese Webseite entstand im Rahmen eines sogenannten Bachelorprojekts am Hasso-Plattner-Institut Potsdam in den Jahren - 2021 und 2022. Sie stellt eine digitale Umsetzung der + 2021, 2022 und 2023. Sie stellt eine digitale Umsetzung der Führungssimulation MANV (FüSim MANV) dar, einer von der Projektbeteiligte /> Malteser Berlin + + Johanniter Akademie NRW, Campus Münster
    - Projektteam: - Julian Schmidt, Clemens Schielicke, - Florian Krummrey, Marvin Müller-Mettnau, + Projektteam 2022/23: + Lukas Hagen, + Nils Hanff, + Benildur Nickel und + Lukas Radermacher +
    + + Projektteam 2021/22: + Julian Schmidt, + Clemens Schielicke, Florian + Krummrey und Marvin Müller-Mettnau +
    + + Betreuende: Matthias Barkowsky @@ -157,4 +175,8 @@

    Projektbeteiligte

    >
    + +
    + +
    diff --git a/frontend/src/app/shared/components/footer/footer.component.html b/frontend/src/app/shared/components/footer/footer.component.html new file mode 100644 index 000000000..dc6bc542a --- /dev/null +++ b/frontend/src/app/shared/components/footer/footer.component.html @@ -0,0 +1,17 @@ +
    +
    + Digitale FüSim MANV, Version {{ version }} – + Feedback geben +
    + + +
    diff --git a/frontend/src/app/shared/components/footer/footer.component.scss b/frontend/src/app/shared/components/footer/footer.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/shared/components/footer/footer.component.ts b/frontend/src/app/shared/components/footer/footer.component.ts new file mode 100644 index 000000000..eedc3f56c --- /dev/null +++ b/frontend/src/app/shared/components/footer/footer.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; +import Package from 'package.json'; + +@Component({ + selector: 'app-footer', + templateUrl: './footer.component.html', + styleUrls: ['./footer.component.scss'], +}) +export class FooterComponent { + version = Package.version; +} diff --git a/frontend/src/app/shared/directives/app-save-on-typing.directive.ts b/frontend/src/app/shared/directives/app-save-on-typing.directive.ts index f6345c1e6..ad8111d8b 100644 --- a/frontend/src/app/shared/directives/app-save-on-typing.directive.ts +++ b/frontend/src/app/shared/directives/app-save-on-typing.directive.ts @@ -2,7 +2,7 @@ import type { OnDestroy } from '@angular/core'; import { Directive, EventEmitter, Output } from '@angular/core'; import { NgModel } from '@angular/forms'; import { Subject } from 'rxjs'; -import { debounceTime, filter, takeUntil } from 'rxjs/operators'; +import { debounceTime, filter, takeUntil, tap } from 'rxjs/operators'; /** * This directive should be used when values should be autosaved while the user types into the input. @@ -29,19 +29,43 @@ export class AppSaveOnTypingDirective implements OnDestroy { destroy$ = new Subject(); @Output() readonly appSaveOnTyping: EventEmitter = new EventEmitter(); + private lastInputValue?: any; + private lastInputValueWasValid = false; + private lastSubmittedValue?: any; + constructor(ngModel: NgModel) { ngModel.update .pipe( + tap((value) => { + this.lastInputValue = value; + this.lastInputValueWasValid = ngModel.valid === true; + }), // Keeping a key (like backspace) pressed for a more than a certain threshold will result in many key presses // The debounceTime should be above that threshold to not register the initial keypress as the first update debounceTime(600), filter(() => ngModel.valid === true), takeUntil(this.destroy$) ) - .subscribe(this.appSaveOnTyping); + .subscribe((value) => { + if (this.lastSubmittedValue === value) { + // We don't want to emit the same value twice in a row + return; + } + this.lastSubmittedValue = value; + this.appSaveOnTyping.next(value); + }); } ngOnDestroy() { + if ( + this.lastInputValueWasValid && + this.lastInputValue !== this.lastSubmittedValue + ) { + // The last input value was not submitted yet + // We want to emit this last value before the appSaveOnTyping gets + // unsubscribed from during the destruction of the parent component + this.appSaveOnTyping.next(this.lastInputValue); + } this.destroy$.next(); } } diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index 2e9c57f21..d6f58dd38 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -1,5 +1,6 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; import { HospitalNameComponent } from './components/hospital-name/hospital-name.component'; import { PatientStatusDataFieldComponent } from './components/patient-status-displayl/patient-status-data-field/patient-status-data-field.component'; import { PatientStatusDisplayComponent } from './components/patient-status-displayl/patient-status-display/patient-status-display.component'; @@ -24,6 +25,7 @@ import { FileInputDirective } from './directives/file-input.directive'; import { JoinIdDirective } from './validation/join-id-validator.directive'; import { PersonnelNamePipe } from './pipes/personnel-name.pipe'; import { CaterCapacityCountPipe } from './pipes/cater-capacity-count.pipe'; +import { FooterComponent } from './components/footer/footer.component'; @NgModule({ declarations: [ @@ -51,8 +53,9 @@ import { CaterCapacityCountPipe } from './pipes/cater-capacity-count.pipe'; PersonnelNamePipe, CaterCapacityCountPipe, FileInputDirective, + FooterComponent, ], - imports: [CommonModule], + imports: [CommonModule, RouterModule], exports: [ AutofocusDirective, AppSaveOnTypingDirective, @@ -77,6 +80,7 @@ import { CaterCapacityCountPipe } from './pipes/cater-capacity-count.pipe'; IntegerValidatorDirective, PatientStatusBadgeComponent, FileInputDirective, + FooterComponent, ], }) export class SharedModule {} diff --git a/frontend/src/app/shared/types/catering-line.ts b/frontend/src/app/shared/types/catering-line.ts index 673762727..8326a5261 100644 --- a/frontend/src/app/shared/types/catering-line.ts +++ b/frontend/src/app/shared/types/catering-line.ts @@ -1,8 +1,8 @@ -import type { UUID, Position } from 'digital-fuesim-manv-shared'; +import type { UUID, MapCoordinates } from 'digital-fuesim-manv-shared'; export interface CateringLine { readonly id: `${UUID}:${UUID}`; - readonly catererPosition: Position; - readonly patientPosition: Position; + readonly catererPosition: MapCoordinates; + readonly patientPosition: MapCoordinates; } diff --git a/frontend/src/app/shared/types/transfer-line.ts b/frontend/src/app/shared/types/transfer-line.ts index 3c615d376..2769f4d7e 100644 --- a/frontend/src/app/shared/types/transfer-line.ts +++ b/frontend/src/app/shared/types/transfer-line.ts @@ -1,9 +1,9 @@ -import type { Position, UUID } from 'digital-fuesim-manv-shared'; +import type { MapCoordinates, UUID } from 'digital-fuesim-manv-shared'; export interface TransferLine { readonly id: `${UUID}:${UUID}`; - readonly startPosition: Position; - readonly endPosition: Position; + readonly startPosition: MapCoordinates; + readonly endPosition: MapCoordinates; readonly duration: number; } diff --git a/frontend/src/app/shared/validation/custom-validation-errors.ts b/frontend/src/app/shared/validation/custom-validation-errors.ts index 623631b5f..91a7d0762 100644 --- a/frontend/src/app/shared/validation/custom-validation-errors.ts +++ b/frontend/src/app/shared/validation/custom-validation-errors.ts @@ -15,7 +15,7 @@ export type CustomValidationErrors = Partial< > >; -type CustomValidator = typeof CustomValidators[keyof typeof CustomValidators]; +type CustomValidator = (typeof CustomValidators)[keyof typeof CustomValidators]; type CustomValidatorFn = ReturnType; type CustomValidationError = ReturnType extends Promise ? Awaited> diff --git a/frontend/src/app/shared/validation/display-validation/display-validation.component.ts b/frontend/src/app/shared/validation/display-validation/display-validation.component.ts index 20d6cba45..8be5ac406 100644 --- a/frontend/src/app/shared/validation/display-validation/display-validation.component.ts +++ b/frontend/src/app/shared/validation/display-validation/display-validation.component.ts @@ -11,6 +11,6 @@ export class DisplayValidationComponent { @Input() ngModelInput!: NgModel; get errors(): CustomValidationErrors | null { - return this.ngModelInput?.errors as CustomValidationErrors | null; + return this.ngModelInput.errors as CustomValidationErrors | null; } } diff --git a/frontend/src/app/state/application/selectors/exercise.selectors.ts b/frontend/src/app/state/application/selectors/exercise.selectors.ts index 9b51fcfbf..42e6ab4a8 100644 --- a/frontend/src/app/state/application/selectors/exercise.selectors.ts +++ b/frontend/src/app/state/application/selectors/exercise.selectors.ts @@ -2,10 +2,10 @@ import { createSelector } from '@ngrx/store'; import type { ExerciseState, Personnel, - Transfer, UUID, Vehicle, } from 'digital-fuesim-manv-shared'; +import { isInTransfer, currentCoordinatesOf } from 'digital-fuesim-manv-shared'; import type { TransferLine } from 'src/app/shared/types/transfer-line'; import type { AppState } from '../../app.state'; @@ -24,6 +24,7 @@ function selectPropertyFactory(key: Key) { // UUIDMap properties export const selectViewports = selectPropertyFactory('viewports'); +export const selectSimulatedRegion = selectPropertyFactory('simulatedRegions'); export const selectMapImages = selectPropertyFactory('mapImages'); export const selectPatients = selectPropertyFactory('patients'); export const selectVehicles = selectPropertyFactory('vehicles'); @@ -79,6 +80,9 @@ export const createSelectHospital = createSelectElementFromMapFactory(selectHospitals); export const createSelectViewport = createSelectElementFromMapFactory(selectViewports); +export const createSelectSimulatedRegion = createSelectElementFromMapFactory( + selectSimulatedRegion +); export const createSelectClient = createSelectElementFromMapFactory(selectClients); @@ -115,8 +119,10 @@ export const selectTransferLines = createSelector( Object.entries(transferPoint.reachableTransferPoints).map( ([connectedId, { duration }]) => ({ id: `${transferPoint.id}:${connectedId}` as const, - startPosition: transferPoint.position, - endPosition: transferPoints[connectedId]!.position, + startPosition: currentCoordinatesOf(transferPoint), + endPosition: currentCoordinatesOf( + transferPoints[connectedId]! + ), duration, }) ) @@ -155,15 +161,15 @@ export function createSelectReachableHospitals(transferPointId: UUID) { export const selectVehiclesInTransfer = createSelector( selectVehicles, (vehicles) => - Object.values(vehicles).filter( - (vehicle) => vehicle.transfer !== undefined - ) as (Vehicle & { transfer: Transfer })[] + Object.values(vehicles).filter((vehicle) => + isInTransfer(vehicle) + ) as Vehicle[] ); export const selectPersonnelInTransfer = createSelector( selectPersonnel, (personnel) => - Object.values(personnel).filter( - (_personnel) => _personnel.transfer !== undefined - ) as (Personnel & { transfer: Transfer })[] + Object.values(personnel).filter((_personnel) => + isInTransfer(_personnel) + ) as Personnel[] ); diff --git a/frontend/src/app/state/application/selectors/shared.selectors.ts b/frontend/src/app/state/application/selectors/shared.selectors.ts index f1afef26f..fbd0c8421 100644 --- a/frontend/src/app/state/application/selectors/shared.selectors.ts +++ b/frontend/src/app/state/application/selectors/shared.selectors.ts @@ -4,14 +4,18 @@ import type { Material, Patient, Personnel, - Position, + SimulatedRegion, TransferPoint, UUID, Vehicle, + WithPosition, +} from 'digital-fuesim-manv-shared'; +import { + currentCoordinatesOf, + isOnMap, + Viewport, } from 'digital-fuesim-manv-shared'; -import { Viewport } from 'digital-fuesim-manv-shared'; import { pickBy } from 'lodash-es'; -import type { WithPosition } from 'src/app/pages/exercises/exercise/shared/utility/types/with-position'; import type { CateringLine } from 'src/app/shared/types/catering-line'; import type { AppState } from '../../app.state'; import { @@ -24,6 +28,7 @@ import { selectMaterials, selectPatients, selectPersonnel, + selectSimulatedRegion, selectTransferPoints, selectVehicles, selectViewports, @@ -61,20 +66,16 @@ export const selectRestrictedViewport = createSelector( * @returns a selector that returns a UUIDMap of all elements that have a position and are in the viewport restriction */ function selectVisibleElementsFactory< - Element extends { readonly position?: Position }, + Element extends WithPosition, Elements extends { readonly [key: UUID]: Element } = { readonly [key: UUID]: Element; - }, - ElementsWithPosition extends { - [Id in keyof Elements]: WithPosition; - } = { [Id in keyof Elements]: WithPosition } + } >( selectElements: (state: AppState) => Elements, - isInViewport: ( - element: WithPosition, - viewport: Viewport - ) => boolean = (element, viewport) => - Viewport.isInViewport(viewport, element.position) + isInViewport: (element: Element, viewport: Viewport) => boolean = ( + element, + viewport + ) => Viewport.isInViewport(viewport, currentCoordinatesOf(element)) ) { return createSelector( selectRestrictedViewport, @@ -84,14 +85,11 @@ function selectVisibleElementsFactory< elements, (element) => // Is placed on the map - element.position && + isOnMap(element) && // No viewport restriction (!restrictedViewport || - isInViewport( - element as WithPosition, - restrictedViewport - )) - ) as ElementsWithPosition + isInViewport(element, restrictedViewport)) + ) ); } @@ -116,6 +114,8 @@ export const selectVisibleMapImages = selectVisibleElementsFactory( ); export const selectVisibleTransferPoints = selectVisibleElementsFactory(selectTransferPoints); +export const selectVisibleSimulatedRegions = + selectVisibleElementsFactory(selectSimulatedRegion); export const selectVisibleCateringLines = createSelector( selectRestrictedViewport, @@ -125,7 +125,7 @@ export const selectVisibleCateringLines = createSelector( (viewport, materials, personnel, patients) => // Mostly, there are fewer untreated patients than materials and personnel that are not treating Object.values(patients) - .filter((patient) => patient.position !== undefined) + .filter((patient) => isOnMap(patient)) .flatMap((patient) => [ ...Object.keys(patient.assignedPersonnelIds).map( @@ -136,9 +136,9 @@ export const selectVisibleCateringLines = createSelector( ), ].map((caterer) => ({ id: `${caterer.id}:${patient.id}` as const, - patientPosition: patient.position!, + patientPosition: currentCoordinatesOf(patient), // If the catering element is treating a patient, it must have a position - catererPosition: caterer.position!, + catererPosition: currentCoordinatesOf(caterer), })) ) // To improve performance, all Lines where both ends are not in the viewport diff --git a/frontend/src/assets/big-material.svg b/frontend/src/assets/big-material.svg new file mode 100644 index 000000000..17f963fb4 --- /dev/null +++ b/frontend/src/assets/big-material.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/image-sources.md b/frontend/src/assets/image-sources.md index 169259d6c..0271c66fd 100644 --- a/frontend/src/assets/image-sources.md +++ b/frontend/src/assets/image-sources.md @@ -35,7 +35,10 @@ Florian Greiz 23 (edited) [material.svg](material.svg): - (edited) +Benildur Nickel + +[big-material.svg](big-material.svg): +Benildur Nickel [patient.svg](patient.svg): (edited) diff --git a/frontend/src/assets/material.svg b/frontend/src/assets/material.svg index 2f96c425d..c64f1e00c 100644 --- a/frontend/src/assets/material.svg +++ b/frontend/src/assets/material.svg @@ -1 +1,108 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/simulated-region.svg b/frontend/src/assets/simulated-region.svg new file mode 100644 index 000000000..dc30aa683 --- /dev/null +++ b/frontend/src/assets/simulated-region.svg @@ -0,0 +1,62 @@ + + + + + + + + + + image/svg+xml + + + + + + + diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 5bf4417c6..852510e1d 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -24,7 +24,8 @@ "lib": ["ES2022", "dom"], // needed for https://github.com/typescript-eslint/typescript-eslint/issues/2559#issuecomment-692882427 "emitDecoratorMetadata": true, - "useDefineForClassFields": false + "useDefineForClassFields": false, + "resolveJsonModule": true }, // this fixes jest globals in .spec.ts being overwritten by cypress globals "include": ["src"], diff --git a/package-lock.json b/package-lock.json index 73fd4db64..a69fef46d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,16 @@ { "name": "digital-fuesim-manv", - "version": "0.0.0", + "version": "1.2.3-test14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv", - "version": "0.0.0", + "version": "1.2.3-test14", "devDependencies": { "concurrently": "^7.6.0", "nyc": "^15.1.0", - "prettier": "^2.8.1" + "prettier": "^2.8.3" }, "engines": { "node": ">=16", @@ -1221,9 +1221,9 @@ } }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -1532,9 +1532,9 @@ } }, "node_modules/prettier": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", - "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz", + "integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==", "dev": true, "bin": { "prettier": "bin-prettier.js" diff --git a/package.json b/package.json index 3639769b0..c6671fc3f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv", - "version": "0.0.0", + "version": "1.2.3-test14", "type": "module", "scripts": { "build": "cd shared && npm run build && cd .. && concurrently \"cd frontend && npm run build\" \"cd backend && npm run build\"", @@ -8,8 +8,10 @@ "start:all": "(cd frontend && npm run start) & (cd backend && npm run start)", "cy:ci": "cd frontend && npm run cy:run", "cy:install": "cd frontend && npm run cy:install", - "install:all": "npm i --install-links=false && concurrently \"cd shared && npm i --install-links=false\" \"cd frontend && npm i --install-links=false\" \"cd backend && npm i --install-links=false\"", - "setup": "npm i --install-links=false && cd shared && npm i --install-links=false && npm run build && cd .. && concurrently \"cd frontend && npm i --install-links=false\" \"cd backend && npm i --install-links=false\"", + "benchmark": "cd benchmark && npm run benchmark", + "install:all": "npm i && concurrently \"cd shared && npm i \" \"cd frontend && npm i \" \"cd backend && npm i \" \"cd benchmark && npm i \"", + "setup": "npm i && cd shared && npm i && npm run build && cd .. && concurrently \"cd frontend && npm i \" \"cd backend && npm i \" \"cd benchmark && npm i \"", + "setup:package-lock-only": "npm i --package-lock-only && cd shared && npm i --package-lock-only && cd ../frontend && npm i --package-lock-only && cd ../backend && npm i --package-lock-only && cd ../benchmark && npm i --package-lock-only", "prune": "npm prune && cd shared && npm prune && cd ../frontend && npm prune && cd ../backend && npm prune", "prune:deployment": "npm prune --production && cd shared && npm prune --production && cd ../backend && npm prune --production", "deployment": "npm run setup:ci && npm run build:deployment && npm run prune:deployment", @@ -32,6 +34,6 @@ "devDependencies": { "concurrently": "^7.6.0", "nyc": "^15.1.0", - "prettier": "^2.8.1" + "prettier": "^2.8.3" } } diff --git a/shared/.npmrc b/shared/.npmrc new file mode 100644 index 000000000..a6ee44b04 --- /dev/null +++ b/shared/.npmrc @@ -0,0 +1 @@ +install-links=false diff --git a/shared/README.md b/shared/README.md index c4cb15433..558167bc8 100644 --- a/shared/README.md +++ b/shared/README.md @@ -12,13 +12,17 @@ Keep in mind to add new exports to the `index.ts` file in the folder. - Note that in all cases (other than validation) plain objects of these classes have to be used (instead of instance objects). You can use the `create` methods of all models for this. - [src/socket-api/](./src/socket-api) the types for [socket.io](https://socket.io/docs/v4/typescript/) - [src/state-helpers/](./src/state-helpers) utilities for working with the state. +- [src/state-migrations/](./src/state-migrations) migrations to update old states and actions to the newest version. - [src/store/](./src/store) reducers, actions and utilities that are used with the state - [src/utils/](./src/utils) general utilities -## Updates to state types +## Updates to state types and migrations Note that whenever the state types get updated you have to increase `ExerciseState.currentStateVersion` in [`state.ts`](./src/state.ts). +In addition, you have to add a migration in [`state-migrations`](./src/state-migrations). Look at [`./src/state-migrations/migration-functions.ts`](./src/state-migrations/migration-functions.ts) for more information. +To test the migrations, you can use the benchmarks in [`../benchmark`](../benchmark) and look for errors. + ## Adding new `Action`s When writing new `Action`s, note the comments in [src/store/action-reducer.ts](./src/store/action-reducer.ts) and [src/store/action-reducers/action-reducers.ts](./src/store/action-reducers/action-reducers.ts). diff --git a/shared/package-lock.json b/shared/package-lock.json index 1383970c7..59a9e52e2 100644 --- a/shared/package-lock.json +++ b/shared/package-lock.json @@ -1,16 +1,17 @@ { "name": "digital-fuesim-manv-shared", - "version": "0.0.0", + "version": "1.2.3-test14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-shared", - "version": "0.0.0", + "version": "1.2.3-test14", "dependencies": { + "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", - "immer": "^9.0.16", + "immer": "^9.0.17", "lodash-es": "^4.17.21", "rbush": "^3.0.1", "rbush-knn": "github:mourner/rbush-knn", @@ -18,22 +19,22 @@ "uuid": "^9.0.0" }, "devDependencies": { - "@types/jest": "^29.2.4", + "@types/jest": "^29.2.5", "@types/lodash-es": "^4.17.6", "@types/rbush": "^3.0.0", "@types/uuid": "^9.0.0", "@types/validator": "^13.7.10", - "@typescript-eslint/eslint-plugin": "5.47.0", - "@typescript-eslint/parser": "5.47.0", - "eslint": "^8.30.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-total-functions": "6.0.0", "eslint-plugin-unicorn": "^45.0.2", "jest": "^29.3.1", - "ts-jest": "^29.0.3", + "ts-jest": "^29.0.5", "ts-node": "^10.9.1", - "typescript": "~4.8.2" + "typescript": "~4.9.4" }, "engines": { "node": ">=16", @@ -701,9 +702,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz", - "integrity": "sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -1189,6 +1190,17 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1347,9 +1359,9 @@ } }, "node_modules/@types/jest": { - "version": "29.2.4", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.4.tgz", - "integrity": "sha512-PipFB04k2qTRPePduVLTRiPzQfvMeLwUN3Z21hsAKaB/W9IIzgB2pizCL466ftJlcyZqnHoC9ZHpxLGl3fS86A==", + "version": "29.2.5", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz", + "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -1446,14 +1458,14 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.0.tgz", - "integrity": "sha512-AHZtlXAMGkDmyLuLZsRpH3p4G/1iARIwc/T0vIem2YB+xW6pZaXYXzCBnZSF/5fdM97R9QqZWZ+h3iW10XgevQ==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", + "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/type-utils": "5.47.0", - "@typescript-eslint/utils": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/type-utils": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", @@ -1479,13 +1491,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.0.tgz", - "integrity": "sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0" + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1496,9 +1508,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.0.tgz", - "integrity": "sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1509,13 +1521,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.0.tgz", - "integrity": "sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1536,16 +1548,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.47.0.tgz", - "integrity": "sha512-U9xcc0N7xINrCdGVPwABjbAKqx4GK67xuMV87toI+HUqgXj26m6RBp9UshEXcTrgCkdGYFzgKLt8kxu49RilDw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", + "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/typescript-estree": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -1562,12 +1574,12 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.0.tgz", - "integrity": "sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/types": "5.48.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -1598,14 +1610,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.47.0.tgz", - "integrity": "sha512-udPU4ckK+R1JWCGdQC4Qa27NtBg7w020ffHqGyAK8pAgOVuNw7YaKXGChk+udh+iiGIJf6/E/0xhVXyPAbsczw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz", + "integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/typescript-estree": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", "debug": "^4.3.4" }, "engines": { @@ -1625,13 +1637,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.0.tgz", - "integrity": "sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0" + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1642,9 +1654,9 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.0.tgz", - "integrity": "sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1655,13 +1667,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.0.tgz", - "integrity": "sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1682,12 +1694,12 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.0.tgz", - "integrity": "sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/types": "5.48.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -1716,13 +1728,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.47.0.tgz", - "integrity": "sha512-1J+DFFrYoDUXQE1b7QjrNGARZE6uVhBqIvdaXTe5IN+NmEyD68qXR1qX1g2u4voA+nCaelQyG8w30SAOihhEYg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", + "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.47.0", - "@typescript-eslint/utils": "5.47.0", + "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -1743,13 +1755,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.0.tgz", - "integrity": "sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0" + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1760,9 +1772,9 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.0.tgz", - "integrity": "sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1773,13 +1785,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.0.tgz", - "integrity": "sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1800,16 +1812,16 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.47.0.tgz", - "integrity": "sha512-U9xcc0N7xINrCdGVPwABjbAKqx4GK67xuMV87toI+HUqgXj26m6RBp9UshEXcTrgCkdGYFzgKLt8kxu49RilDw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", + "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/typescript-estree": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -1826,12 +1838,12 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.0.tgz", - "integrity": "sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/types": "5.48.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -2093,6 +2105,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/babel-jest": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz", @@ -2707,12 +2737,12 @@ } }, "node_modules/eslint": { - "version": "8.30.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.30.0.tgz", - "integrity": "sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ==", + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", + "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.4.0", + "@eslint/eslintrc": "^1.4.1", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -2763,9 +2793,9 @@ } }, "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==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", + "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -2775,13 +2805,14 @@ } }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, "dependencies": { "debug": "^3.2.7", - "resolve": "^1.20.0" + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { @@ -2820,23 +2851,25 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "version": "2.27.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.4.tgz", + "integrity": "sha512-Z1jVt1EGKia1X9CnBCkpAOhWy8FgQ7OmJ/IblEkT82yrFU/xJaxwujaTzLWqigewwynRQ9mmHfX9MtAfhxm0sA==", "dev": true, "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.0", + "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", "has": "^1.0.3", - "is-core-module": "^2.8.1", + "is-core-module": "^2.11.0", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", "tsconfig-paths": "^3.14.1" }, "engines": { @@ -2847,12 +2880,12 @@ } }, "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "node_modules/eslint-plugin-import/node_modules/doctrine": { @@ -2867,11 +2900,14 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } }, "node_modules/eslint-plugin-total-functions": { "version": "6.0.0", @@ -3567,9 +3603,9 @@ } }, "node_modules/immer": { - "version": "9.0.16", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz", - "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==", + "version": "9.0.17", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.17.tgz", + "integrity": "sha512-+hBruaLSQvkPfxRiTLK/mi4vLH+/VQS6z2KJahdoxlleFOI8ARqzOF17uy12eFDlqWmPoygwc5evgwcp+dlHhg==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -4610,9 +4646,9 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -5245,9 +5281,9 @@ } }, "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==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz", + "integrity": "sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==", "dev": true, "engines": { "node": ">=6" @@ -5937,15 +5973,15 @@ } }, "node_modules/ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", + "version": "29.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz", + "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==", "dev": true, "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^29.0.0", - "json5": "^2.2.1", + "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", @@ -6035,9 +6071,9 @@ } }, "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "dependencies": { "minimist": "^1.2.0" @@ -6110,9 +6146,9 @@ } }, "node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/shared/package.json b/shared/package.json index d8a9eb57d..7b74d8cf8 100644 --- a/shared/package.json +++ b/shared/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-shared", - "version": "0.0.0", + "version": "1.2.3-test14", "type": "module", "main": "./dist/index.js", "esnext": "./dist/index.js", @@ -25,9 +25,10 @@ "npm": ">=8" }, "dependencies": { + "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", - "immer": "^9.0.16", + "immer": "^9.0.17", "lodash-es": "^4.17.21", "rbush": "^3.0.1", "rbush-knn": "github:mourner/rbush-knn", @@ -35,22 +36,22 @@ "uuid": "^9.0.0" }, "devDependencies": { - "@types/jest": "^29.2.4", + "@types/jest": "^29.2.5", "@types/lodash-es": "^4.17.6", "@types/rbush": "^3.0.0", "@types/uuid": "^9.0.0", "@types/validator": "^13.7.10", - "@typescript-eslint/eslint-plugin": "5.47.0", - "@typescript-eslint/parser": "5.47.0", - "eslint": "^8.30.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-total-functions": "6.0.0", "eslint-plugin-unicorn": "^45.0.2", "jest": "^29.3.1", - "ts-jest": "^29.0.3", + "ts-jest": "^29.0.5", "ts-node": "^10.9.1", - "typescript": "~4.8.2" + "typescript": "~4.9.4" }, "exports": { ".": { diff --git a/shared/src/data/default-state/material-templates.ts b/shared/src/data/default-state/material-templates.ts index 3c1470928..c9d3327fa 100644 --- a/shared/src/data/default-state/material-templates.ts +++ b/shared/src/data/default-state/material-templates.ts @@ -10,7 +10,7 @@ const standardMaterialTemplate = MaterialTemplate.create( 'standard', { url: '/assets/material.svg', - height: 40, + height: 35, aspectRatio: 1, }, CanCaterFor.create(2, 0, 0, 'and'), @@ -21,9 +21,8 @@ const standardMaterialTemplate = MaterialTemplate.create( const bigMaterialTemplate = MaterialTemplate.create( 'big', { - url: '/assets/material.svg', - // Roughly double the area of the standard material - height: 56, + url: '/assets/big-material.svg', + height: 35, aspectRatio: 1, }, CanCaterFor.create(2, 2, 0, 'and'), diff --git a/shared/src/data/default-state/patient-templates.ts b/shared/src/data/default-state/patient-templates.ts index a936d471a..15536ae8d 100644 --- a/shared/src/data/default-state/patient-templates.ts +++ b/shared/src/data/default-state/patient-templates.ts @@ -1,9 +1,9 @@ import { FunctionParameters, + PatientCategory, PatientHealthState, PatientTemplate, } from '../../models'; -import { PatientCategory } from '../../models/patient-category'; import type { ImageProperties } from '../../models/utils'; import { healthPointsDefaults } from '../../models/utils'; diff --git a/shared/src/data/dummy-objects/patient.ts b/shared/src/data/dummy-objects/patient.ts index 809f13991..dfeb9b58b 100644 --- a/shared/src/data/dummy-objects/patient.ts +++ b/shared/src/data/dummy-objects/patient.ts @@ -1,4 +1,6 @@ import { FunctionParameters, Patient, PatientHealthState } from '../../models'; +import { MapCoordinates } from '../../models/utils/position/map-coordinates'; +import { MapPosition } from '../../models/utils/position/map-position'; import { PatientStatusCode } from '../../models/utils/patient-status-code'; import { defaultPatientCategories } from '../default-state/patient-templates'; @@ -23,6 +25,7 @@ export function generateDummyPatient(): Patient { healthState.id, template.image, template.health, - '' + '', + MapPosition.create(MapCoordinates.create(0, 0)) ); } diff --git a/shared/src/export-import/file-format/base-file.ts b/shared/src/export-import/file-format/base-file.ts index cde1aa076..34a78a0b2 100644 --- a/shared/src/export-import/file-format/base-file.ts +++ b/shared/src/export-import/file-format/base-file.ts @@ -1,5 +1,6 @@ -import { IsIn, IsInt, IsString, Min } from 'class-validator'; +import { IsInt, Min } from 'class-validator'; import { ExerciseState } from '../../state'; +import { IsLiteralUnion } from '../../utils/validators'; export abstract class BaseExportImportFile { public static readonly currentFileVersion = 1; @@ -13,7 +14,9 @@ export abstract class BaseExportImportFile { @Min(0) public readonly dataVersion: number = ExerciseState.currentStateVersion; - @IsIn(['complete', 'partial']) - @IsString() + @IsLiteralUnion({ + complete: true, + partial: true, + }) public abstract readonly type: 'complete' | 'partial'; } diff --git a/shared/src/export-import/file-format/partial-export.ts b/shared/src/export-import/file-format/partial-export.ts index a819a58ae..94a810171 100644 --- a/shared/src/export-import/file-format/partial-export.ts +++ b/shared/src/export-import/file-format/partial-export.ts @@ -1,21 +1,15 @@ import { Type } from 'class-transformer'; -import { - IsArray, - IsIn, - IsOptional, - IsString, - ValidateNested, -} from 'class-validator'; +import { IsArray, IsOptional, ValidateNested } from 'class-validator'; import { MapImageTemplate, PatientTemplate, VehicleTemplate, } from '../../models'; +import { IsValue } from '../../utils/validators'; import { BaseExportImportFile } from './base-file'; export class PartialExport extends BaseExportImportFile { - @IsIn(['partial']) - @IsString() + @IsValue('partial' as const) public readonly type: 'partial' = 'partial'; @IsOptional() diff --git a/shared/src/export-import/file-format/state-export.ts b/shared/src/export-import/file-format/state-export.ts index 8d39d6f91..eddc3f1a8 100644 --- a/shared/src/export-import/file-format/state-export.ts +++ b/shared/src/export-import/file-format/state-export.ts @@ -1,32 +1,21 @@ import { Type } from 'class-transformer'; -import type { ValidationError } from 'class-validator'; -import { - IsArray, - IsIn, - IsOptional, - IsString, - ValidateNested, -} from 'class-validator'; +import { IsArray, IsOptional, ValidateNested } from 'class-validator'; import { ExerciseState } from '../../state'; import type { ExerciseAction } from '../../store'; -import { validateExerciseAction } from '../../store'; +import { IsExerciseAction } from '../../store'; import { Mutable } from '../../utils'; +import { IsValue } from '../../utils/validators'; import { BaseExportImportFile } from './base-file'; export class StateHistoryCompound { @IsArray() + @IsExerciseAction({ each: true }) public actionHistory: ExerciseAction[]; @ValidateNested() @Type(() => ExerciseState) public initialState: Mutable; - public validateActions(): (ValidationError | string)[][] { - return this.actionHistory.map((action) => - validateExerciseAction(action) - ); - } - public constructor( actionHistory: ExerciseAction[], initialState: Mutable @@ -37,8 +26,7 @@ export class StateHistoryCompound { } export class StateExport extends BaseExportImportFile { - @IsIn(['complete']) - @IsString() + @IsValue('complete' as const) public readonly type: 'complete' = 'complete'; @ValidateNested() diff --git a/shared/src/index.ts b/shared/src/index.ts index 74eff16c7..dadb0e5f2 100644 --- a/shared/src/index.ts +++ b/shared/src/index.ts @@ -19,6 +19,7 @@ export * from './export-import/file-format'; export * from './models'; export * from './models/utils'; export * from './utils'; +export * from './simulation'; export * from './state'; export * from './store'; export * from './socket-api'; @@ -26,3 +27,4 @@ export * from './http-interfaces'; export * from './state-helpers'; export * from './data'; export * from './store/action-reducers/utils'; +export * from './state-migrations'; diff --git a/shared/src/models/alarm-group.ts b/shared/src/models/alarm-group.ts index 91f2843e5..2d6ed8dc1 100644 --- a/shared/src/models/alarm-group.ts +++ b/shared/src/models/alarm-group.ts @@ -1,16 +1,21 @@ -import { IsObject, IsString, IsUUID } from 'class-validator'; +import { IsString, IsUUID } from 'class-validator'; import { UUID, uuid, uuidValidationOptions } from '../utils'; +import { IsValue } from '../utils/validators'; +import { IsIdMap } from '../utils/validators/is-id-map'; import { getCreate } from './utils'; -import type { AlarmGroupVehicle } from './utils/alarm-group-vehicle'; +import { AlarmGroupVehicle } from './utils/alarm-group-vehicle'; export class AlarmGroup { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('alarmGroup' as const) + public readonly type = 'alarmGroup'; + @IsString() public readonly name: string; - @IsObject() + @IsIdMap(AlarmGroupVehicle) public alarmGroupVehicles: { readonly [key: UUID]: AlarmGroupVehicle } = {}; /** diff --git a/shared/src/models/client.ts b/shared/src/models/client.ts index 18fa28792..ae42a3546 100644 --- a/shared/src/models/client.ts +++ b/shared/src/models/client.ts @@ -6,19 +6,23 @@ import { MaxLength, } from 'class-validator'; import { UUID, uuid, uuidValidationOptions } from '../utils'; +import { IsLiteralUnion, IsValue } from '../utils/validators'; import { getCreate, Role } from './utils'; +import { roleAllowedValues } from './utils/role'; export class Client { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('client' as const) + public readonly type = 'client'; + @IsString() // Required by database @MaxLength(255) public readonly name: string; - // TODO - @IsString() + @IsLiteralUnion(roleAllowedValues) public readonly role: Role; @IsUUID(4, uuidValidationOptions) diff --git a/shared/src/models/element.ts b/shared/src/models/element.ts new file mode 100644 index 000000000..9aa445366 --- /dev/null +++ b/shared/src/models/element.ts @@ -0,0 +1,26 @@ +import type { + AlarmGroup, + Client, + Hospital, + MapImage, + Material, + Patient, + Personnel, + SimulatedRegion, + TransferPoint, + Vehicle, + Viewport, +} from '.'; + +export type Element = + | AlarmGroup + | Client + | Hospital + | MapImage + | Material + | Patient + | Personnel + | SimulatedRegion + | TransferPoint + | Vehicle + | Viewport; diff --git a/shared/src/models/eoc-log-entry.ts b/shared/src/models/eoc-log-entry.ts index f6b7c0113..ed83508e9 100644 --- a/shared/src/models/eoc-log-entry.ts +++ b/shared/src/models/eoc-log-entry.ts @@ -1,11 +1,15 @@ import { IsInt, IsString, IsUUID, MaxLength } from 'class-validator'; import { UUID, uuid, uuidValidationOptions } from '../utils'; +import { IsValue } from '../utils/validators'; import { getCreate } from './utils'; export class EocLogEntry { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('eocLogEntry' as const) + public readonly type = 'eocLogEntry'; + /** * The time in the exercise */ diff --git a/shared/src/models/exercise-configuration.ts b/shared/src/models/exercise-configuration.ts index 9899cdc3d..dce59e0a9 100644 --- a/shared/src/models/exercise-configuration.ts +++ b/shared/src/models/exercise-configuration.ts @@ -1,9 +1,13 @@ import { Type } from 'class-transformer'; import { IsBoolean, ValidateNested } from 'class-validator'; import { defaultTileMapProperties } from '../data'; +import { IsValue } from '../utils/validators'; import { getCreate, TileMapProperties } from './utils'; export class ExerciseConfiguration { + @IsValue('exerciseConfiguration' as const) + public readonly type = 'exerciseConfiguration'; + @IsBoolean() public readonly pretriageEnabled: boolean = true; @IsBoolean() diff --git a/shared/src/models/hospital-patient.ts b/shared/src/models/hospital-patient.ts index 643d2fa63..17a2588ac 100644 --- a/shared/src/models/hospital-patient.ts +++ b/shared/src/models/hospital-patient.ts @@ -1,25 +1,26 @@ import { Type } from 'class-transformer'; import { - IsDefined, IsNumber, IsString, IsUUID, - Max, Min, ValidateNested, } from 'class-validator'; import type { Mutable } from '../utils'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../utils'; +import { IsIdMap, IsLiteralUnion, IsValue } from '../utils/validators'; import { getCreate, HealthPoints, - healthPointsDefaults, ImageProperties, + IsValidHealthPoint, PatientStatus, + patientStatusAllowedValues, } from './utils'; import { BiometricInformation } from './utils/biometric-information'; import { PersonalInformation } from './utils/personal-information'; -import type { Patient, PatientHealthState } from '.'; +import { PatientHealthState } from './patient-health-state'; +import type { Patient } from '.'; export class HospitalPatient { /** @@ -28,6 +29,9 @@ export class HospitalPatient { @IsUUID(4, uuidValidationOptions) public readonly patientId: UUID; + @IsValue('hospitalPatient' as const) + public readonly type = 'hospitalPatient'; + /** * the vehicle that a patient was transported with */ @@ -54,19 +58,17 @@ export class HospitalPatient { @Type(() => BiometricInformation) public readonly biometricInformation: BiometricInformation; - // TODO - @IsString() + @IsLiteralUnion(patientStatusAllowedValues) public readonly pretriageStatus: PatientStatus; - // TODO - @IsString() + @IsLiteralUnion(patientStatusAllowedValues) public readonly realStatus: PatientStatus; @ValidateNested() @Type(() => ImageProperties) public readonly image: ImageProperties; - @IsDefined() + @IsIdMap(PatientHealthState) public readonly healthStates: { readonly [stateId: UUID]: PatientHealthState; } = {}; @@ -80,9 +82,7 @@ export class HospitalPatient { /** * See {@link HealthPoints} for context of this property. */ - @IsNumber() - @Max(healthPointsDefaults.max) - @Min(healthPointsDefaults.min) + @IsValidHealthPoint() public readonly health: HealthPoints; @IsNumber() diff --git a/shared/src/models/hospital.ts b/shared/src/models/hospital.ts index d1b07bcc9..528e35c83 100644 --- a/shared/src/models/hospital.ts +++ b/shared/src/models/hospital.ts @@ -1,11 +1,15 @@ -import { IsDefined, IsNumber, IsString, IsUUID, Min } from 'class-validator'; +import { IsNumber, IsString, IsUUID, Min } from 'class-validator'; import { uuid, uuidValidationOptions, UUID, UUIDSet } from '../utils'; +import { IsUUIDSet, IsValue } from '../utils/validators'; import { getCreate } from './utils'; export class Hospital { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('hospital' as const) + public readonly type = 'hospital'; + @IsString() public readonly name: string; @@ -19,8 +23,7 @@ export class Hospital { /** * These Ids reference a hospitalPatients patientId */ - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly patientIds: UUIDSet = {}; /** diff --git a/shared/src/models/index.ts b/shared/src/models/index.ts index 1c81ba726..555a44389 100644 --- a/shared/src/models/index.ts +++ b/shared/src/models/index.ts @@ -14,3 +14,6 @@ export { TransferPoint } from './transfer-point'; export { Vehicle } from './vehicle'; export { VehicleTemplate } from './vehicle-template'; export { Viewport } from './viewport'; +export { PatientCategory } from './patient-category'; +export { SimulatedRegion } from './simulated-region'; +export { Element } from './element'; diff --git a/shared/src/models/map-image-template.ts b/shared/src/models/map-image-template.ts index c701df501..9a2f4ab90 100644 --- a/shared/src/models/map-image-template.ts +++ b/shared/src/models/map-image-template.ts @@ -1,12 +1,16 @@ import { Type } from 'class-transformer'; import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { UUID, uuid, uuidValidationOptions } from '../utils'; +import { IsValue } from '../utils/validators'; import { getCreate, ImageProperties } from './utils'; export class MapImageTemplate { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('mapImageTemplate' as const) + public readonly type = 'mapImageTemplate'; + @IsString() public readonly name: string; diff --git a/shared/src/models/map-image.ts b/shared/src/models/map-image.ts index 6dc0c3e46..9d8f158a5 100644 --- a/shared/src/models/map-image.ts +++ b/shared/src/models/map-image.ts @@ -1,14 +1,23 @@ import { Type } from 'class-transformer'; import { IsBoolean, IsInt, IsUUID, ValidateNested } from 'class-validator'; import { uuid, UUID, uuidValidationOptions } from '../utils'; -import { Position, getCreate, ImageProperties } from './utils'; +import { IsValue } from '../utils/validators'; +import { IsPosition } from '../utils/validators/is-position'; +import type { MapCoordinates } from './utils'; +import { MapPosition, getCreate, ImageProperties, Position } from './utils'; export class MapImage { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('mapImage' as const) + public readonly type = 'mapImage'; + + /** + * @deprecated Do not access directly, use helper methods from models/utils/position/position-helpers(-mutable) instead. + */ @ValidateNested() - @Type(() => Position) + @IsPosition() public readonly position: Position; @ValidateNested() @@ -34,12 +43,12 @@ export class MapImage { * @deprecated Use {@link create} instead */ constructor( - topLeft: Position, + topLeft: MapCoordinates, image: ImageProperties, isLocked: boolean, zIndex: number ) { - this.position = topLeft; + this.position = MapPosition.create(topLeft); this.image = image; this.isLocked = isLocked; this.zIndex = zIndex; diff --git a/shared/src/models/material-template.ts b/shared/src/models/material-template.ts index 34b869b39..39b45da3e 100644 --- a/shared/src/models/material-template.ts +++ b/shared/src/models/material-template.ts @@ -1,11 +1,15 @@ import { Type } from 'class-transformer'; -import { IsNumber, IsString, Max, Min, ValidateNested } from 'class-validator'; +import { IsNumber, Max, Min, ValidateNested } from 'class-validator'; import { maxTreatmentRange } from '../state-helpers/max-treatment-range'; +import { IsLiteralUnion, IsValue } from '../utils/validators'; import { CanCaterFor, getCreate, ImageProperties } from './utils'; -import { MaterialType } from './utils/material-type'; +import { MaterialType, materialTypeAllowedValues } from './utils/material-type'; export class MaterialTemplate { - @IsString() + @IsValue('materialTemplate' as const) + public readonly type = 'materialTemplate'; + + @IsLiteralUnion(materialTypeAllowedValues) public readonly materialType: MaterialType; @ValidateNested() diff --git a/shared/src/models/material.ts b/shared/src/models/material.ts index 49f3aef4d..0df36780c 100644 --- a/shared/src/models/material.ts +++ b/shared/src/models/material.ts @@ -1,31 +1,34 @@ import { Type } from 'class-transformer'; import { - IsDefined, - IsNumber, - IsOptional, - IsString, IsUUID, - Max, - Min, + IsString, ValidateNested, + IsNumber, + Min, + Max, } from 'class-validator'; import { maxTreatmentRange } from '../state-helpers/max-treatment-range'; -import { uuid, UUID, UUIDSet, uuidValidationOptions } from '../utils'; +import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils'; +import { IsUUIDSet, IsValue } from '../utils/validators'; +import { IsPosition } from '../utils/validators/is-position'; import type { MaterialTemplate } from './material-template'; -import { CanCaterFor, getCreate, ImageProperties, Position } from './utils'; +import { CanCaterFor, ImageProperties, getCreate } from './utils'; +import { Position } from './utils/position/position'; export class Material { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('material' as const) + public readonly type = 'material'; + @IsUUID(4, uuidValidationOptions) public readonly vehicleId: UUID; @IsString() public readonly vehicleName: string; - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly assignedPatientIds: UUIDSet; @ValidateNested() @@ -53,12 +56,11 @@ export class Material { public readonly treatmentRange: number; /** - * if undefined, is in vehicle with {@link this.vehicleId} + * @deprecated Do not access directly, use helper methods from models/utils/position/position-helpers(-mutable) instead. */ + @IsPosition() @ValidateNested() - @Type(() => Position) - @IsOptional() - public readonly position?: Position; + public readonly position: Position; @ValidateNested() @Type(() => ImageProperties) @@ -75,16 +77,16 @@ export class Material { canCaterFor: CanCaterFor, treatmentRange: number, overrideTreatmentRange: number, - position?: Position + position: Position ) { this.vehicleId = vehicleId; this.vehicleName = vehicleName; this.assignedPatientIds = assignedPatientIds; - this.position = position; this.image = image; this.canCaterFor = canCaterFor; this.treatmentRange = treatmentRange; this.overrideTreatmentRange = overrideTreatmentRange; + this.position = position; } static readonly create = getCreate(this); @@ -92,7 +94,8 @@ export class Material { static generateMaterial( materialTemplate: MaterialTemplate, vehicleId: UUID, - vehicleName: string + vehicleName: string, + position: Position ): Material { return this.create( vehicleId, @@ -102,11 +105,7 @@ export class Material { materialTemplate.canCaterFor, materialTemplate.treatmentRange, materialTemplate.overrideTreatmentRange, - undefined + position ); } - - static isInVehicle(material: Material): boolean { - return material.position === undefined; - } } diff --git a/shared/src/models/patient-category.ts b/shared/src/models/patient-category.ts index 6b9d8b683..d6161453c 100644 --- a/shared/src/models/patient-category.ts +++ b/shared/src/models/patient-category.ts @@ -1,10 +1,14 @@ import { Type } from 'class-transformer'; import { ArrayNotEmpty, IsArray, ValidateNested } from 'class-validator'; +import { IsValue } from '../utils/validators'; import { PatientTemplate } from './patient-template'; import { getCreate, ImageProperties } from './utils'; import { PatientStatusCode } from './utils/patient-status-code'; export class PatientCategory { + @IsValue('patientCategory' as const) + public readonly type = 'patientCategory'; + @ValidateNested() @Type(() => PatientStatusCode) public readonly name: PatientStatusCode; diff --git a/shared/src/models/patient-health-state.ts b/shared/src/models/patient-health-state.ts index 60810920e..9e04c85ea 100644 --- a/shared/src/models/patient-health-state.ts +++ b/shared/src/models/patient-health-state.ts @@ -7,6 +7,7 @@ import { ValidateNested, } from 'class-validator'; import { uuid, UUID, uuidValidationOptions } from '../utils'; +import { IsValue } from '../utils/validators'; import { getCreate, HealthPoints, IsValidHealthPoint } from './utils'; /** @@ -109,6 +110,9 @@ export class PatientHealthState { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('patientHealthState' as const) + public readonly type = 'patientHealthState'; + @Type(() => FunctionParameters) @ValidateNested() public readonly functionParameters: FunctionParameters; diff --git a/shared/src/models/patient-template.ts b/shared/src/models/patient-template.ts index 753d09f83..0c3140dbd 100644 --- a/shared/src/models/patient-template.ts +++ b/shared/src/models/patient-template.ts @@ -1,6 +1,7 @@ import { Type } from 'class-transformer'; -import { IsDefined, IsUUID, ValidateNested } from 'class-validator'; +import { IsUUID, ValidateNested } from 'class-validator'; import { cloneDeepMutable, UUID, uuid, uuidValidationOptions } from '../utils'; +import { IsIdMap, IsValue } from '../utils/validators'; import type { PatientStatusCode } from './utils'; import { BiometricInformation, @@ -14,12 +15,16 @@ import { PersonalInformation } from './utils/personal-information'; import { Patient } from './patient'; import type { FunctionParameters } from './patient-health-state'; import { PretriageInformation } from './utils/pretriage-information'; -import type { PatientHealthState } from '.'; +import { PatientHealthState } from './patient-health-state'; +import type { Position } from './utils/position/position'; export class PatientTemplate { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('patientTemplate' as const) + public readonly type = 'patientTemplate'; + @ValidateNested() @Type(() => BiometricInformation) public readonly biometricInformation: BiometricInformation; @@ -32,7 +37,7 @@ export class PatientTemplate { @Type(() => ImageProperties) public readonly image: ImageProperties; - @IsDefined() + @IsIdMap(PatientHealthState) public readonly healthStates: { readonly [stateId: UUID]: PatientHealthState; }; @@ -66,7 +71,8 @@ export class PatientTemplate { public static generatePatient( template: PatientTemplate, - patientStatusCode: PatientStatusCode + patientStatusCode: PatientStatusCode, + position: Position ): Patient { // Randomize function parameters const healthStates = Object.fromEntries( @@ -106,7 +112,8 @@ export class PatientTemplate { template.startingHealthStateId, template.image, template.health, - '' + '', + position ); } } diff --git a/shared/src/models/patient.ts b/shared/src/models/patient.ts index a249d7310..168f9b77f 100644 --- a/shared/src/models/patient.ts +++ b/shared/src/models/patient.ts @@ -1,36 +1,48 @@ import { Type } from 'class-transformer'; import { - IsBoolean, - IsDefined, - IsNumber, - IsOptional, - IsString, IsUUID, + ValidateNested, + IsNumber, Max, - MaxLength, Min, - ValidateNested, + IsBoolean, + IsString, + MaxLength, } from 'class-validator'; import { isEmpty } from 'lodash-es'; -import { UUID, uuid, UUIDSet, uuidValidationOptions } from '../utils'; +import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils'; import { - getCreate, - HealthPoints, - healthPointsDefaults, - ImageProperties, + IsLiteralUnion, + IsIdMap, + IsUUIDSet, + IsValue, +} from '../utils/validators'; +import { IsPosition } from '../utils/validators/is-position'; +import { PatientHealthState } from './patient-health-state'; +import { + BiometricInformation, + PatientStatusCode, PatientStatus, - Position, + patientStatusAllowedValues, + ImageProperties, + healthPointsDefaults, + HealthPoints, + getCreate, + isAlive, + isOnMap, + isInSimulatedRegion, } from './utils'; -import { BiometricInformation } from './utils/biometric-information'; -import { PatientStatusCode } from './utils/patient-status-code'; -import { PretriageInformation } from './utils/pretriage-information'; +import { Position } from './utils/position/position'; import { PersonalInformation } from './utils/personal-information'; -import type { PatientHealthState } from '.'; +import { PretriageInformation } from './utils/pretriage-information'; export class Patient { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('patient') + public readonly type = 'patient'; + @ValidateNested() @Type(() => PersonalInformation) public readonly personalInformation: PersonalInformation; @@ -51,12 +63,10 @@ export class Patient { @Type(() => PatientStatusCode) public readonly patientStatusCode: PatientStatusCode; - // TODO - @IsString() + @IsLiteralUnion(patientStatusAllowedValues) public readonly pretriageStatus: PatientStatus; - // TODO - @IsString() + @IsLiteralUnion(patientStatusAllowedValues) public readonly realStatus: PatientStatus; @ValidateNested() @@ -64,19 +74,11 @@ export class Patient { public readonly image: ImageProperties; /** - * Exclusive-or to {@link vehicleId} + * @deprecated Do not access directly, use helper methods from models/utils/position/position-helpers(-mutable) instead. */ + @IsPosition() @ValidateNested() - @Type(() => Position) - @IsOptional() - public readonly position?: Position; - - /** - * Exclusive-or to {@link position} - */ - @IsUUID(4, uuidValidationOptions) - @IsOptional() - public readonly vehicleId?: UUID; + public readonly position: Position; /** * The time the patient already is in the current state @@ -84,7 +86,7 @@ export class Patient { @IsNumber() public readonly stateTime: number = 0; - @IsDefined() + @IsIdMap(PatientHealthState) public readonly healthStates: { readonly [stateId: UUID]: PatientHealthState; } = {}; @@ -103,12 +105,10 @@ export class Patient { @Min(healthPointsDefaults.min) public readonly health: HealthPoints; - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly assignedPersonnelIds: UUIDSet = {}; - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly assignedMaterialIds: UUIDSet = {}; /** * The speed with which the patients healthStatus changes @@ -158,7 +158,8 @@ export class Patient { currentHealthStateId: UUID, image: ImageProperties, health: HealthPoints, - remarks: string + remarks: string, + position: Position ) { this.personalInformation = personalInformation; this.biometricInformation = biometricInformation; @@ -171,6 +172,7 @@ export class Patient { this.image = image; this.health = health; this.remarks = remarks; + this.position = position; } static readonly create = getCreate(this); @@ -192,11 +194,14 @@ export class Patient { return patient.treatmentTime >= this.pretriageTimeThreshold; } - static isInVehicle(patient: Patient): boolean { - return patient.position === undefined; - } - static isTreatedByPersonnel(patient: Patient) { return !isEmpty(patient.assignedPersonnelIds); } + + static canBeTreated(patient: Patient) { + return ( + isAlive(patient.health) && + (isOnMap(patient) || isInSimulatedRegion(patient)) + ); + } } diff --git a/shared/src/models/personnel-template.ts b/shared/src/models/personnel-template.ts index 505cf4903..fc3e3c101 100644 --- a/shared/src/models/personnel-template.ts +++ b/shared/src/models/personnel-template.ts @@ -1,16 +1,21 @@ import { Type } from 'class-transformer'; -import { IsNumber, IsString, Max, Min, ValidateNested } from 'class-validator'; +import { IsNumber, Max, Min, ValidateNested } from 'class-validator'; import { maxTreatmentRange } from '../state-helpers/max-treatment-range'; +import { IsLiteralUnion, IsValue } from '../utils/validators'; import { + PersonnelType, CanCaterFor, - getCreate, ImageProperties, - PersonnelType, + getCreate, } from './utils'; +import { personnelTypeAllowedValues } from './utils/personnel-type'; // TODO: These are not (yet) saved in the state -> Decide whether they should and if not move this file from the models folder away export class PersonnelTemplate { - @IsString() + @IsValue('personnelTemplate' as const) + public readonly type = 'personnelTemplate'; + + @IsLiteralUnion(personnelTypeAllowedValues) public readonly personnelType: PersonnelType; @ValidateNested() diff --git a/shared/src/models/personnel.ts b/shared/src/models/personnel.ts index 20cd9aa8b..7e5d55bd7 100644 --- a/shared/src/models/personnel.ts +++ b/shared/src/models/personnel.ts @@ -1,42 +1,43 @@ import { Type } from 'class-transformer'; import { - IsDefined, - IsNumber, - IsOptional, - IsString, IsUUID, - Max, - Min, + IsString, ValidateNested, + IsNumber, + Min, + Max, } from 'class-validator'; import { maxTreatmentRange } from '../state-helpers/max-treatment-range'; -import { UUID, UUIDSet, uuid, uuidValidationOptions } from '../utils'; +import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils'; +import { IsLiteralUnion, IsUUIDSet, IsValue } from '../utils/validators'; +import { IsPosition } from '../utils/validators/is-position'; import type { PersonnelTemplate } from './personnel-template'; import { + PersonnelType, CanCaterFor, - Position, ImageProperties, - PersonnelType, getCreate, - Transfer, } from './utils'; +import { Position } from './utils/position/position'; +import { personnelTypeAllowedValues } from './utils/personnel-type'; export class Personnel { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('personnel' as const) + public readonly type = 'personnel'; + @IsUUID(4, uuidValidationOptions) public readonly vehicleId: UUID; - // TODO - @IsString() + @IsLiteralUnion(personnelTypeAllowedValues) public readonly personnelType: PersonnelType; @IsString() public readonly vehicleName: string; - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly assignedPatientIds: UUIDSet; @ValidateNested() @@ -68,20 +69,11 @@ export class Personnel { public readonly image: ImageProperties; /** - * If undefined, the personnel is either in the vehicle with {@link this.vehicleId} or in transfer. - */ - @ValidateNested() - @Type(() => Position) - @IsOptional() - public readonly position?: Position; - - /** - * If undefined, the personnel is either in the vehicle with {@link this.vehicleId} or has a {@link position}. + * @deprecated Do not access directly, use helper methods from models/utils/position/position-helpers(-mutable) instead. */ + @IsPosition() @ValidateNested() - @Type(() => Transfer) - @IsOptional() - public readonly transfer?: Transfer; + public readonly position: Position; /** * @deprecated Use {@link create} instead @@ -95,17 +87,17 @@ export class Personnel { canCaterFor: CanCaterFor, treatmentRange: number, overrideTreatmentRange: number, - position?: Position + position: Position ) { this.vehicleId = vehicleId; this.vehicleName = vehicleName; this.personnelType = personnelType; this.assignedPatientIds = assignedPatientIds; - this.position = position; this.image = image; this.canCaterFor = canCaterFor; this.treatmentRange = treatmentRange; this.overrideTreatmentRange = overrideTreatmentRange; + this.position = position; } static readonly create = getCreate(this); @@ -113,7 +105,8 @@ export class Personnel { static generatePersonnel( personnelTemplate: PersonnelTemplate, vehicleId: UUID, - vehicleName: string + vehicleName: string, + position: Position ): Personnel { return this.create( vehicleId, @@ -124,13 +117,7 @@ export class Personnel { personnelTemplate.canCaterFor, personnelTemplate.treatmentRange, personnelTemplate.overrideTreatmentRange, - undefined - ); - } - - static isInVehicle(personnel: Personnel): boolean { - return ( - personnel.position === undefined && personnel.transfer === undefined + position ); } } diff --git a/shared/src/models/simulated-region.ts b/shared/src/models/simulated-region.ts new file mode 100644 index 000000000..8dba7803d --- /dev/null +++ b/shared/src/models/simulated-region.ts @@ -0,0 +1,87 @@ +import { Type } from 'class-transformer'; +import { IsString, IsUUID, ValidateNested } from 'class-validator'; +import { UUID, uuid, uuidValidationOptions } from '../utils'; +import { IsPosition } from '../utils/validators/is-position'; +import { IsMultiTypedIdMap, IsValue } from '../utils/validators'; +import type { ExerciseSimulationEvent } from '../simulation'; +import { simulationEventTypeOptions } from '../simulation'; +import type { ExerciseSimulationActivityState } from '../simulation/activities'; +import { getSimulationActivityConstructor } from '../simulation/activities'; +import type { ExerciseSimulationBehaviorState } from '../simulation/behaviors'; +import { simulationBehaviorTypeOptions } from '../simulation/behaviors'; +import { + getCreate, + isInSimulatedRegion, + MapPosition, + Position, + currentSimulatedRegionIdOf, + Size, +} from './utils'; +import type { ImageProperties, MapCoordinates } from './utils'; +import type { WithPosition } from './utils/position/with-position'; + +export class SimulatedRegion { + @IsUUID(4, uuidValidationOptions) + public readonly id: UUID = uuid(); + + @IsValue('simulatedRegion' as const) + public readonly type = 'simulatedRegion'; + + /** + * top-left position + * + * @deprecated Do not access directly, use helper methods from models/utils/position/position-helpers(-mutable) instead. + */ + @ValidateNested() + @IsPosition() + public readonly position: Position; + + @ValidateNested() + @Type(() => Size) + public readonly size: Size; + + @IsString() + public readonly name: string; + + /** + * @param position top-left position + * @deprecated Use {@link create} instead + */ + constructor(position: MapCoordinates, size: Size, name: string) { + this.position = MapPosition.create(position); + this.size = size; + this.name = name; + } + + @Type(...simulationEventTypeOptions) + @ValidateNested() + public readonly inEvents: readonly ExerciseSimulationEvent[] = []; + + @Type(...simulationBehaviorTypeOptions) + @ValidateNested() + public readonly behaviors: readonly ExerciseSimulationBehaviorState[] = []; + + @IsMultiTypedIdMap(getSimulationActivityConstructor) + @ValidateNested() + public readonly activities: { + readonly [stateId: UUID]: ExerciseSimulationActivityState; + } = {}; + + static readonly create = getCreate(this); + + static image: ImageProperties = { + url: 'assets/simulated-region.svg', + height: 1800, + aspectRatio: 1600 / 900, + }; + + static isInSimulatedRegion( + region: SimulatedRegion, + withPosition: WithPosition + ): boolean { + return ( + isInSimulatedRegion(withPosition) && + currentSimulatedRegionIdOf(withPosition) === region.id + ); + } +} diff --git a/shared/src/models/transfer-point.ts b/shared/src/models/transfer-point.ts index 46242c969..3691a5cac 100644 --- a/shared/src/models/transfer-point.ts +++ b/shared/src/models/transfer-point.ts @@ -1,23 +1,32 @@ -import { Type } from 'class-transformer'; -import { IsDefined, IsString, IsUUID, ValidateNested } from 'class-validator'; +import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { UUID, uuid, UUIDSet, uuidValidationOptions } from '../utils'; -import type { ImageProperties } from './utils'; -import { getCreate, Position } from './utils'; +import { + IsReachableTransferPoints, + IsUUIDSet, + IsValue, +} from '../utils/validators'; +import { IsPosition } from '../utils/validators/is-position'; +import type { ImageProperties, MapCoordinates } from './utils'; +import { MapPosition, Position, getCreate } from './utils'; export class TransferPoint { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('transferPoint' as const) + public readonly type = 'transferPoint'; + + /** + * @deprecated Do not access directly, use helper methods from models/utils/position/position-helpers(-mutable) instead. + */ @ValidateNested() - @Type(() => Position) + @IsPosition() public readonly position: Position; - // TODO - @IsDefined() + @IsReachableTransferPoints() public readonly reachableTransferPoints: ReachableTransferPoints; - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly reachableHospitals: UUIDSet = {}; @IsString() @@ -30,13 +39,13 @@ export class TransferPoint { * @deprecated Use {@link create} instead */ constructor( - position: Position, + position: MapCoordinates, reachableTransferPoints: ReachableTransferPoints, reachableHospitals: UUIDSet, internalName: string, externalName: string ) { - this.position = position; + this.position = MapPosition.create(position); this.reachableTransferPoints = reachableTransferPoints; this.reachableHospitals = reachableHospitals; this.internalName = internalName; @@ -56,8 +65,7 @@ export class TransferPoint { } } -// TODO: Add validation -interface ReachableTransferPoints { +export interface ReachableTransferPoints { readonly [connectTransferPointId: UUID]: { /** * The time in ms it takes to get from this transfer point to the other one. diff --git a/shared/src/models/utils/biometric-information.ts b/shared/src/models/utils/biometric-information.ts index 3ecef84c4..9e7734d8b 100644 --- a/shared/src/models/utils/biometric-information.ts +++ b/shared/src/models/utils/biometric-information.ts @@ -1,13 +1,14 @@ import { IsInt, IsString, Min } from 'class-validator'; +import { IsLiteralUnion } from '../../utils/validators'; import { getCreate } from './get-create'; -import { Sex } from './sex'; +import { Sex, sexAllowedValues } from './sex'; export class BiometricInformation { @IsInt() @Min(0) public readonly age: number; - @IsString() + @IsLiteralUnion(sexAllowedValues) public readonly sex: Sex; /** diff --git a/shared/src/models/utils/cater-for.ts b/shared/src/models/utils/cater-for.ts index 1ec5b0892..42d26c639 100644 --- a/shared/src/models/utils/cater-for.ts +++ b/shared/src/models/utils/cater-for.ts @@ -1,6 +1,14 @@ -import { IsNumber, IsString, Min } from 'class-validator'; +import { IsNumber, Min } from 'class-validator'; +import type { AllowedValues } from '../../utils/validators'; +import { IsLiteralUnion } from '../../utils/validators'; import { getCreate } from './get-create'; +type LogicalOperator = 'and' | 'or'; +const logicalOperatorAllowedValues: AllowedValues = { + and: true, + or: true, +}; + export class CanCaterFor { /** * if {@link logicalOperator} `=== 'and'` it is cumulative, @@ -30,9 +38,8 @@ export class CanCaterFor { @Min(0) public readonly green: number; - // TODO: Use a better validator - @IsString() - public readonly logicalOperator: 'and' | 'or'; + @IsLiteralUnion(logicalOperatorAllowedValues) + public readonly logicalOperator: LogicalOperator; /** * @deprecated Use {@link create} instead @@ -41,7 +48,7 @@ export class CanCaterFor { red: number, yellow: number, green: number, - logicalOperator: 'and' | 'or' + logicalOperator: LogicalOperator ) { this.red = red; this.yellow = yellow; diff --git a/shared/src/models/utils/exercise-status.ts b/shared/src/models/utils/exercise-status.ts index 8c00def2d..ce94ea98e 100644 --- a/shared/src/models/utils/exercise-status.ts +++ b/shared/src/models/utils/exercise-status.ts @@ -1 +1,9 @@ +import type { AllowedValues } from '../../utils/validators'; + export type ExerciseStatus = 'notStarted' | 'paused' | 'running'; + +export const exerciseStatusAllowedValues: AllowedValues = { + notStarted: true, + paused: true, + running: true, +}; diff --git a/shared/src/models/utils/get-create.ts b/shared/src/models/utils/get-create.ts index 5cccc3042..4dab6f921 100644 --- a/shared/src/models/utils/get-create.ts +++ b/shared/src/models/utils/get-create.ts @@ -9,7 +9,7 @@ import type { Constructor } from '../../utils'; * * @example * ```typescript - * export class Position { + * export class Coordinates { * @IsNumber() * public a: number; * /** diff --git a/shared/src/models/utils/index.ts b/shared/src/models/utils/index.ts index d4b477f34..7199bde54 100644 --- a/shared/src/models/utils/index.ts +++ b/shared/src/models/utils/index.ts @@ -1,4 +1,11 @@ -export { Position } from './position'; +export { Position } from './position/position'; +export { WithPosition } from './position/with-position'; +export { MapPosition } from './position/map-position'; +export { VehiclePosition } from './position/vehicle-position'; +export { TransferPosition } from './position/transfer-position'; +export { SimulatedRegionPosition } from './position/simulated-region-position'; +export { MapCoordinates } from './position/map-coordinates'; +export * from './position/position-helpers'; export * from './patient-status'; export { Size } from './size'; export { Role } from './role'; diff --git a/shared/src/models/utils/material-type.ts b/shared/src/models/utils/material-type.ts index e88b92a4c..dbfbdacfe 100644 --- a/shared/src/models/utils/material-type.ts +++ b/shared/src/models/utils/material-type.ts @@ -1 +1,8 @@ +import type { AllowedValues } from '../../utils/validators'; + export type MaterialType = 'big' | 'standard'; + +export const materialTypeAllowedValues: AllowedValues = { + big: true, + standard: true, +}; diff --git a/shared/src/models/utils/patient-status-code.ts b/shared/src/models/utils/patient-status-code.ts index 5539f72a6..618d609e0 100644 --- a/shared/src/models/utils/patient-status-code.ts +++ b/shared/src/models/utils/patient-status-code.ts @@ -1,9 +1,25 @@ import { Type } from 'class-transformer'; -import { IsString, ValidateNested } from 'class-validator'; +import { ValidateNested } from 'class-validator'; +import type { AllowedValues } from '../../utils/validators'; +import { IsLiteralUnion } from '../../utils/validators'; import { getCreate } from './get-create'; type ColorCode = 'V' | 'W' | 'X' | 'Y' | 'Z'; +const colorCodeAllowedValues: AllowedValues = { + V: true, + W: true, + X: true, + Y: true, + Z: true, +}; type BehaviourCode = 'A' | 'B' | 'C' | 'D' | 'E'; +const behaviourCodeAllowedValues: AllowedValues = { + A: true, + B: true, + C: true, + D: true, + E: true, +}; export const colorCodeMap = { V: 'black', @@ -11,13 +27,9 @@ export const colorCodeMap = { X: 'green', Y: 'yellow', Z: 'red', -} as const; - -// This is only for typesafety -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const _colorCodeMap: { readonly [key in ColorCode]: string } = colorCodeMap; +} as const satisfies { readonly [Key in ColorCode]: string }; -export const behaviourCodeMap: { [key in BehaviourCode]: string } = { +export const behaviourCodeMap: { [Key in BehaviourCode]: string } = { A: 'bi-arrow-right-square-fill', B: 'bi-heartbreak-fill', C: 'bi-exclamation-circle-fill', @@ -26,10 +38,10 @@ export const behaviourCodeMap: { [key in BehaviourCode]: string } = { }; export class PatientStatusDataField { - @IsString() + @IsLiteralUnion(colorCodeAllowedValues) public readonly colorCode: ColorCode; - @IsString() + @IsLiteralUnion(behaviourCodeAllowedValues) public readonly behaviourCode: BehaviourCode; /** diff --git a/shared/src/models/utils/patient-status.ts b/shared/src/models/utils/patient-status.ts index e4e2888eb..26524d0ac 100644 --- a/shared/src/models/utils/patient-status.ts +++ b/shared/src/models/utils/patient-status.ts @@ -1,3 +1,5 @@ +import type { AllowedValues } from '../../utils/validators'; + export type PatientStatus = | 'black' | 'blue' @@ -16,3 +18,12 @@ export const statusNames: { white: 'Ungesichtet', yellow: 'SK II', }; + +export const patientStatusAllowedValues: AllowedValues = { + black: true, + blue: true, + green: true, + red: true, + white: true, + yellow: true, +}; diff --git a/shared/src/models/utils/personnel-type.ts b/shared/src/models/utils/personnel-type.ts index 7f5c1628b..0ef52f35f 100644 --- a/shared/src/models/utils/personnel-type.ts +++ b/shared/src/models/utils/personnel-type.ts @@ -1,4 +1,15 @@ +import type { AllowedValues } from '../../utils/validators'; + export type PersonnelType = 'gf' | 'notarzt' | 'notSan' | 'rettSan' | 'san'; + +export const personnelTypeAllowedValues: AllowedValues = { + gf: true, + notarzt: true, + notSan: true, + rettSan: true, + san: true, +}; + export const personnelTypeNames: { [key in PersonnelType]: string; } = { diff --git a/shared/src/models/utils/position.ts b/shared/src/models/utils/position/map-coordinates.ts similarity index 82% rename from shared/src/models/utils/position.ts rename to shared/src/models/utils/position/map-coordinates.ts index f61d5a5f9..75963fef0 100644 --- a/shared/src/models/utils/position.ts +++ b/shared/src/models/utils/position/map-coordinates.ts @@ -1,7 +1,7 @@ import { IsNumber } from 'class-validator'; -import { getCreate } from './get-create'; +import { getCreate } from '../get-create'; -export class Position { +export class MapCoordinates { @IsNumber() public readonly x: number; diff --git a/shared/src/models/utils/position/map-position.ts b/shared/src/models/utils/position/map-position.ts new file mode 100644 index 000000000..9dd5a121f --- /dev/null +++ b/shared/src/models/utils/position/map-position.ts @@ -0,0 +1,32 @@ +import { Type } from 'class-transformer'; +import { ValidateNested } from 'class-validator'; +import { IsValue } from '../../../utils/validators'; +import { getCreate } from '../get-create'; +import { MapCoordinates } from './map-coordinates'; +// import needed to display @link Links in Comments +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { isOnMap, isNotOnMap, currentCoordinatesOf } from './position-helpers'; + +export class MapPosition { + /** + * @deprecated Use {@link isOnMap } or {@link isNotOnMap} instead + */ + @IsValue('coordinates') + public readonly type = 'coordinates'; + + /** + * @deprecated Use {@link currentCoordinatesOf} instead + */ + @Type(() => MapCoordinates) + @ValidateNested() + public readonly coordinates: MapCoordinates; + + /** + * @deprecated Use {@link create} instead + */ + constructor(position: MapCoordinates) { + this.coordinates = position; + } + + static readonly create = getCreate(this); +} diff --git a/shared/src/models/utils/position/position-helpers-mutable.ts b/shared/src/models/utils/position/position-helpers-mutable.ts new file mode 100644 index 000000000..d13030065 --- /dev/null +++ b/shared/src/models/utils/position/position-helpers-mutable.ts @@ -0,0 +1,103 @@ +import type { ExerciseState } from '../../../state'; +import { getElement } from '../../../store/action-reducers/utils'; +import { + removeTreatmentsOfElement, + updateTreatments, +} from '../../../store/action-reducers/utils/calculate-treatments'; +import type { SpatialElementType } from '../../../store/action-reducers/utils/spatial-elements'; +import { + removeElementPosition, + updateElementPosition, +} from '../../../store/action-reducers/utils/spatial-elements'; +import type { Mutable, UUID } from '../../../utils'; +import { cloneDeepMutable } from '../../../utils'; +import type { Position } from './position'; +import { + coordinatesOfPosition, + isPositionNotOnMap, + isPositionOnMap, + isNotOnMap, + isOnMap, +} from './position-helpers'; + +type MutablePosition = Mutable; + +interface WithMutablePosition { + position: MutablePosition; + type: MovableType; +} +interface WithMutablePositionAndId extends WithMutablePosition { + id: UUID; +} +type MovableType = + | 'alarmGroup' + | 'client' + | 'hospital' + | 'mapImage' + | 'material' + | 'patient' + | 'personnel' + | 'simulatedRegion' + | 'transferPoint' + | 'vehicle' + | 'viewport'; + +export function changePositionWithId( + of: UUID, + to: Position, + type: MovableType, + inState: Mutable +) { + changePosition(getElement(inState, type, of) as any, to, inState); +} + +export function changePosition( + element: WithMutablePosition, + to: Position, + state: Mutable +) { + if ( + element.type === 'patient' || + element.type === 'personnel' || + element.type === 'material' + ) { + updateSpatialElementTree( + element as WithMutablePositionAndId, + to, + element.type, + state + ); + if (element.position.type !== to.type) { + removeTreatmentsOfElement(state, element as any); + } + element.position = cloneDeepMutable(to); + updateTreatments(state, element as any); + return; + } + element.position = cloneDeepMutable(to); +} + +function updateSpatialElementTree( + element: WithMutablePositionAndId, + to: Position, + type: SpatialElementType, + state: Mutable +) { + if (isOnMap(element) && isPositionOnMap(to)) { + updateElementPosition( + state, + type, + element.id, + coordinatesOfPosition(to) + ); + } else if (isOnMap(element) && isPositionNotOnMap(to)) { + removeElementPosition(state, type, element.id); + } else if (isNotOnMap(element) && isPositionOnMap(to)) { + updateElementPosition( + state, + type, + element.id, + coordinatesOfPosition(to) + ); + } +} diff --git a/shared/src/models/utils/position/position-helpers.ts b/shared/src/models/utils/position/position-helpers.ts new file mode 100644 index 000000000..819a1b9e5 --- /dev/null +++ b/shared/src/models/utils/position/position-helpers.ts @@ -0,0 +1,162 @@ +import type { UUID } from '../../../utils'; +import type { Transfer } from '../transfer'; +import { MapCoordinates } from './map-coordinates'; +import type { MapPosition } from './map-position'; +import type { Position } from './position'; +import type { SimulatedRegionPosition } from './simulated-region-position'; +import type { TransferPosition } from './transfer-position'; +import type { VehiclePosition } from './vehicle-position'; +import type { WithExtent } from './with-extent'; +import type { WithPosition } from './with-position'; + +export function isOnMap(withPosition: WithPosition): boolean { + return isPositionOnMap(withPosition.position); +} +export function isInVehicle(withPosition: WithPosition): boolean { + return isPositionInVehicle(withPosition.position); +} +export function isInTransfer(withPosition: WithPosition): boolean { + return isPositionInTransfer(withPosition.position); +} +export function isInSimulatedRegion(withPosition: WithPosition): boolean { + return isPositionInSimulatedRegion(withPosition.position); +} +export function isNotOnMap(withPosition: WithPosition): boolean { + return !isOnMap(withPosition); +} +export function isNotInVehicle(withPosition: WithPosition): boolean { + return !isInVehicle(withPosition); +} +export function isNotInTransfer(withPosition: WithPosition): boolean { + return !isInTransfer(withPosition); +} +export function isNotInSimulatedRegion(withPosition: WithPosition): boolean { + return !isInSimulatedRegion(withPosition); +} + +export function currentCoordinatesOf( + withPosition: WithPosition +): MapCoordinates { + if (isOnMap(withPosition)) { + return coordinatesOfPosition(withPosition.position); + } + throw new TypeError( + `Expected position of object to be on Map. Was of type ${withPosition.position.type}.` + ); +} + +export function currentVehicleIdOf(withPosition: WithPosition): UUID { + if (isInVehicle(withPosition)) { + return vehicleIdOfPosition(withPosition.position); + } + throw new TypeError( + `Expected position of object to be in vehicle. Was of type ${withPosition.position.type}.` + ); +} + +export function currentTransferOf(withPosition: WithPosition): Transfer { + if (isInTransfer(withPosition)) { + return transferOfPosition(withPosition.position); + } + throw new TypeError( + `Expected position of object to be in transfer. Was of type ${withPosition.position.type}.` + ); +} + +export function currentSimulatedRegionIdOf(withPosition: WithPosition): UUID { + if (isInSimulatedRegion(withPosition)) { + return simulatedRegionIdOfPosition(withPosition.position); + } + throw new TypeError( + `Expected position of object to be in simulatedRegion. Was of type ${withPosition.position.type}.` + ); +} + +export function isPositionOnMap(position: Position): boolean { + return position.type === 'coordinates'; +} +export function isPositionInVehicle(position: Position): boolean { + return position.type === 'vehicle'; +} +export function isPositionInTransfer(position: Position): boolean { + return position.type === 'transfer'; +} +export function isPositionInSimulatedRegion(position: Position): boolean { + return position.type === 'simulatedRegion'; +} +export function isPositionNotOnMap(position: Position): boolean { + return !isPositionOnMap(position); +} +export function isPositionNotInVehicle(position: Position): boolean { + return !isPositionInVehicle(position); +} +export function isPositionNotInTransfer(position: Position): boolean { + return !isPositionInTransfer(position); +} +export function isPositionNotInSimulatedRegion(position: Position): boolean { + return !isPositionInSimulatedRegion(position); +} + +export function coordinatesOfPosition(position: Position): MapCoordinates { + if (isPositionOnMap(position)) { + return (position as MapPosition).coordinates; + } + throw new TypeError( + `Expected position to be on Map. Was of type ${position.type}.` + ); +} + +export function vehicleIdOfPosition(position: Position): UUID { + if (isPositionInVehicle(position)) { + return (position as VehiclePosition).vehicleId; + } + throw new TypeError( + `Expected position to be in vehicle. Was of type ${position.type}.` + ); +} + +export function transferOfPosition(position: Position): Transfer { + if (isPositionInTransfer(position)) { + return (position as TransferPosition).transfer; + } + throw new TypeError( + `Expected position to be in transfer. Was of type ${position.type}.` + ); +} + +export function simulatedRegionIdOfPosition(position: Position): UUID { + if (isPositionInSimulatedRegion(position)) { + return (position as SimulatedRegionPosition).simulatedRegionId; + } + throw new TypeError( + `Expected position to be in simulatedRegion. Was of type ${position.type}.` + ); +} + +export function upperLeftCornerOf(element: WithExtent): MapCoordinates { + const corner = { ...currentCoordinatesOf(element) }; + + if (element.size.width < 0) { + corner.x += element.size.width; + } + + if (element.size.height < 0) { + corner.y -= element.size.height; + } + + return MapCoordinates.create(corner.x, corner.y); +} + +export function lowerRightCornerOf(element: WithExtent): MapCoordinates { + const corner = { ...currentCoordinatesOf(element) }; + + if (element.size.width > 0) { + corner.x += element.size.width; + } + + if (element.size.height > 0) { + corner.y -= element.size.height; + } + + return MapCoordinates.create(corner.x, corner.y); +} diff --git a/shared/src/models/utils/position/position.ts b/shared/src/models/utils/position/position.ts new file mode 100644 index 000000000..055c0f545 --- /dev/null +++ b/shared/src/models/utils/position/position.ts @@ -0,0 +1,10 @@ +import type { MapPosition } from './map-position'; +import type { SimulatedRegionPosition } from './simulated-region-position'; +import type { TransferPosition } from './transfer-position'; +import type { VehiclePosition } from './vehicle-position'; + +export type Position = + | MapPosition + | SimulatedRegionPosition + | TransferPosition + | VehiclePosition; diff --git a/shared/src/models/utils/position/simulated-region-position.ts b/shared/src/models/utils/position/simulated-region-position.ts new file mode 100644 index 000000000..fc1dc9fc6 --- /dev/null +++ b/shared/src/models/utils/position/simulated-region-position.ts @@ -0,0 +1,38 @@ +import { IsUUID } from 'class-validator'; +import { UUID } from '../../../utils'; +import { IsValue } from '../../../utils/validators'; +import { getCreate } from '../get-create'; +import { + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + isInSimulatedRegion, + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + isNotInSimulatedRegion, + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + currentSimulatedRegionIdOf, +} from './position-helpers'; + +export class SimulatedRegionPosition { + /** + * @deprecated Use {@link isInSimulatedRegion } or {@link isNotInSimulatedRegion} instead + */ + @IsValue('simulatedRegion') + public readonly type = 'simulatedRegion'; + + /** + * @deprecated Use {@link currentSimulatedRegionIdOf } instead + */ + @IsUUID() + public readonly simulatedRegionId: UUID; + + /** + * @deprecated Use {@link create} instead + */ + constructor(simulatedRegionId: UUID) { + this.simulatedRegionId = simulatedRegionId; + } + + static readonly create = getCreate(this); +} diff --git a/shared/src/models/utils/position/transfer-position.ts b/shared/src/models/utils/position/transfer-position.ts new file mode 100644 index 000000000..f2f8b9672 --- /dev/null +++ b/shared/src/models/utils/position/transfer-position.ts @@ -0,0 +1,40 @@ +import { Type } from 'class-transformer'; +import { ValidateNested } from 'class-validator'; +import { IsValue } from '../../../utils/validators'; +import { getCreate } from '../get-create'; +import { Transfer } from '../transfer'; +import { + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + isInTransfer, + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + isNotInTransfer, + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + currentTransferOf, +} from './position-helpers'; + +export class TransferPosition { + /** + * @deprecated Use {@link isInTransfer } or {@link isNotInTransfer} instead + */ + @IsValue('transfer') + public readonly type = 'transfer'; + + /** + * @deprecated Use {@link currentTransferOf } instead + */ + @Type(() => Transfer) + @ValidateNested() + public readonly transfer: Transfer; + + /** + * @deprecated Use {@link create} instead + */ + constructor(transfer: Transfer) { + this.transfer = transfer; + } + + static readonly create = getCreate(this); +} diff --git a/shared/src/models/utils/position/vehicle-position.ts b/shared/src/models/utils/position/vehicle-position.ts new file mode 100644 index 000000000..4f91a3e0b --- /dev/null +++ b/shared/src/models/utils/position/vehicle-position.ts @@ -0,0 +1,38 @@ +import { IsUUID } from 'class-validator'; +import { UUID } from '../../../utils'; +import { IsValue } from '../../../utils/validators'; +import { getCreate } from '../get-create'; +import { + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + isInVehicle, + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + isNotInVehicle, + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + currentVehicleIdOf, +} from './position-helpers'; + +export class VehiclePosition { + /** + * @deprecated Use {@link isInVehicle } or {@link isNotInVehicle} instead + */ + @IsValue('vehicle') + public readonly type = 'vehicle'; + + /** + * @deprecated Use {@link currentVehicleIdOf } instead + */ + @IsUUID() + public readonly vehicleId: UUID; + + /** + * @deprecated Use {@link create} instead + */ + constructor(vehicleId: UUID) { + this.vehicleId = vehicleId; + } + + static readonly create = getCreate(this); +} diff --git a/shared/src/models/utils/position/with-extent.ts b/shared/src/models/utils/position/with-extent.ts new file mode 100644 index 000000000..a85914f2d --- /dev/null +++ b/shared/src/models/utils/position/with-extent.ts @@ -0,0 +1,6 @@ +import type { Size } from '../size'; +import type { WithPosition } from './with-position'; + +export interface WithExtent extends WithPosition { + readonly size: Size; +} diff --git a/shared/src/models/utils/position/with-position.ts b/shared/src/models/utils/position/with-position.ts new file mode 100644 index 000000000..9fca34434 --- /dev/null +++ b/shared/src/models/utils/position/with-position.ts @@ -0,0 +1,5 @@ +import type { Position } from './position'; + +export interface WithPosition { + readonly position: Position; +} diff --git a/shared/src/models/utils/role.ts b/shared/src/models/utils/role.ts index 88151fac8..7f184dd6b 100644 --- a/shared/src/models/utils/role.ts +++ b/shared/src/models/utils/role.ts @@ -1 +1,7 @@ +import type { AllowedValues } from '../../utils/validators'; + export type Role = 'participant' | 'trainer'; +export const roleAllowedValues: AllowedValues = { + participant: true, + trainer: true, +}; diff --git a/shared/src/models/utils/sex.ts b/shared/src/models/utils/sex.ts index e1c6ea13b..57f988dd0 100644 --- a/shared/src/models/utils/sex.ts +++ b/shared/src/models/utils/sex.ts @@ -1 +1,9 @@ +import type { AllowedValues } from '../../utils/validators'; + export type Sex = 'diverse' | 'female' | 'male'; + +export const sexAllowedValues: AllowedValues = { + diverse: true, + female: true, + male: true, +}; diff --git a/shared/src/models/utils/spatial-tree.ts b/shared/src/models/utils/spatial-tree.ts index b617941aa..33ea781dc 100644 --- a/shared/src/models/utils/spatial-tree.ts +++ b/shared/src/models/utils/spatial-tree.ts @@ -9,7 +9,7 @@ import RBush from 'rbush'; import knn from 'rbush-knn'; import type { Mutable, UUID } from '../../utils'; import { ImmutableJsonObject } from '../../utils'; -import type { Position, Size } from '.'; +import type { MapCoordinates, Size } from '.'; import { getCreate } from '.'; /** @@ -64,7 +64,7 @@ export class SpatialTree { public static addElement( spatialTree: Mutable, elementId: UUID, - position: Position + position: MapCoordinates ) { const pointRBush = this.getPointRBush(spatialTree); pointRBush.insert({ @@ -77,7 +77,7 @@ export class SpatialTree { public static removeElement( spatialTree: Mutable, elementId: UUID, - position: Mutable | Position + position: MapCoordinates | Mutable ) { const pointRBush = this.getPointRBush(spatialTree); pointRBush.remove( @@ -93,8 +93,8 @@ export class SpatialTree { public static moveElement( spatialTree: Mutable, elementId: UUID, - startPosition: Mutable | Position, - targetPosition: Position + startPosition: MapCoordinates | Mutable, + targetPosition: MapCoordinates ) { // TODO: use the move function from RBush, when available: https://github.com/mourner/rbush/issues/28 this.removeElement(spatialTree, elementId, startPosition); @@ -109,7 +109,7 @@ export class SpatialTree { */ public static findAllElementsInCircle( spatialTree: Mutable, - circlePosition: Position, + circlePosition: MapCoordinates, radius: number ): UUID[] { // knn does not work great with `0`|`undefined` as it interprets either as `infinity` @@ -136,7 +136,7 @@ export class SpatialTree { */ public static findAllElementsInRectangle( spatialTree: Mutable, - topLeftPosition: Position, + topLeftPosition: MapCoordinates, size: Size ) { return this.getPointRBush(spatialTree).search({ @@ -154,12 +154,12 @@ export class SpatialTree { * @param id of the element */ interface PointRBushElement { - position: Position; + position: MapCoordinates; id: UUID; } /** - * An RBush that works with our {@link Position} format (elements being points) + * An RBush that works with our {@link MapCoordinates} format (elements being points) * @see https://github.com/mourner/rbush#data-format */ class PointRBush extends RBush { diff --git a/shared/src/models/utils/start-points.ts b/shared/src/models/utils/start-points.ts index 3b9ffaf93..d976dcd1e 100644 --- a/shared/src/models/utils/start-points.ts +++ b/shared/src/models/utils/start-points.ts @@ -1,12 +1,14 @@ -import { IsIn, IsNumber, IsString, IsUUID, Min } from 'class-validator'; +import type { TypeOptions } from 'class-transformer'; +import { IsNumber, IsString, IsUUID, Min } from 'class-validator'; import { UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import { getCreate } from './get-create'; export type StartPoint = AlarmGroupStartPoint | TransferStartPoint; export class TransferStartPoint { - @IsIn(['transferPoint']) - public readonly type = 'transferPoint'; + @IsValue('transferStartPoint' as const) + public readonly type = 'transferStartPoint'; @IsUUID(4, uuidValidationOptions) public readonly transferPointId: UUID; @@ -22,8 +24,8 @@ export class TransferStartPoint { } export class AlarmGroupStartPoint { - @IsIn(['alarmGroup']) - public readonly type = 'alarmGroup'; + @IsValue('alarmGroupStartPoint' as const) + public readonly type = 'alarmGroupStartPoint'; @IsString() public readonly alarmGroupName: string; @@ -42,3 +44,20 @@ export class AlarmGroupStartPoint { static readonly create = getCreate(this); } + +export const startPointTypeOptions: TypeOptions = { + keepDiscriminatorProperty: true, + discriminator: { + property: 'type', + subTypes: [ + { + name: 'alarmGroupStartPoint', + value: AlarmGroupStartPoint, + }, + { + name: 'transferStartPoint', + value: TransferStartPoint, + }, + ], + }, +}; diff --git a/shared/src/models/utils/transfer.ts b/shared/src/models/utils/transfer.ts index 65ba7340b..a5a33d610 100644 --- a/shared/src/models/utils/transfer.ts +++ b/shared/src/models/utils/transfer.ts @@ -1,7 +1,8 @@ -import { IsBoolean, IsNumber, IsObject, IsUUID } from 'class-validator'; +import { Type } from 'class-transformer'; +import { IsBoolean, IsNumber, IsUUID, ValidateNested } from 'class-validator'; import { UUID, uuidValidationOptions } from '../../utils'; import { getCreate } from './get-create'; -import { StartPoint } from './start-points'; +import { StartPoint, startPointTypeOptions } from './start-points'; export class Transfer { /** @@ -10,7 +11,8 @@ export class Transfer { @IsNumber() public readonly endTimeStamp: number; - @IsObject() + @ValidateNested() + @Type(() => Object, startPointTypeOptions) public readonly startPoint: StartPoint; @IsUUID(4, uuidValidationOptions) diff --git a/shared/src/models/vehicle-template.ts b/shared/src/models/vehicle-template.ts index b4ceb0900..c2956dd40 100644 --- a/shared/src/models/vehicle-template.ts +++ b/shared/src/models/vehicle-template.ts @@ -7,14 +7,23 @@ import { IsArray, } from 'class-validator'; import { uuidValidationOptions, UUID, uuid } from '../utils'; +import { IsLiteralUnion, IsValue } from '../utils/validators'; import type { PersonnelType } from './utils'; -import { ImageProperties, getCreate } from './utils'; +import { + ImageProperties, + personnelTypeAllowedValues, + getCreate, +} from './utils'; import type { MaterialType } from './utils/material-type'; +import { materialTypeAllowedValues } from './utils/material-type'; export class VehicleTemplate { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('vehicleTemplate' as const) + public readonly type = 'vehicleTemplate'; + @IsString() public readonly vehicleType: string; @@ -29,11 +38,15 @@ export class VehicleTemplate { public readonly patientCapacity: number; @IsArray() - @IsString({ each: true }) + @IsLiteralUnion(personnelTypeAllowedValues, { + each: true, + }) public readonly personnel: readonly PersonnelType[]; @IsArray() - @IsString({ each: true }) + @IsLiteralUnion(materialTypeAllowedValues, { + each: true, + }) public readonly materials: readonly MaterialType[]; /** diff --git a/shared/src/models/vehicle.ts b/shared/src/models/vehicle.ts index 87073bf5c..3e0b4c330 100644 --- a/shared/src/models/vehicle.ts +++ b/shared/src/models/vehicle.ts @@ -1,59 +1,47 @@ import { Type } from 'class-transformer'; -import { - IsDefined, - IsNumber, - IsOptional, - IsString, - IsUUID, - ValidateNested, -} from 'class-validator'; +import { IsNumber, IsString, IsUUID, ValidateNested } from 'class-validator'; import { uuid, uuidValidationOptions, UUID, UUIDSet } from '../utils'; -import { getCreate, Position, Transfer } from './utils'; +import { IsUUIDSet, IsValue } from '../utils/validators'; +import { IsPosition } from '../utils/validators/is-position'; +import type { WithPosition } from './utils'; +import { currentVehicleIdOf, getCreate, isInVehicle } from './utils'; import { ImageProperties } from './utils/image-properties'; +import { Position } from './utils/position/position'; export class Vehicle { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('vehicle' as const) + public readonly type = 'vehicle'; + @IsString() public readonly vehicleType: string; @IsString() public readonly name: string; - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly materialIds: UUIDSet = {}; @IsNumber() public readonly patientCapacity: number; /** - * Exclusive-or to {@link transfer} + * @deprecated Do not access directly, use helper methods from models/utils/position/position-helpers(-mutable) instead. */ + @IsPosition() @ValidateNested() - @Type(() => Position) - @IsOptional() - public readonly position?: Position; + public readonly position: Position; @ValidateNested() @Type(() => ImageProperties) public readonly image: ImageProperties; - /** - * Exclusive-or to {@link position} - */ - @ValidateNested() - @Type(() => Transfer) - @IsOptional() - public readonly transfer?: Transfer; - - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly personnelIds: UUIDSet = {}; - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly patientIds: UUIDSet = {}; /** @@ -64,14 +52,23 @@ export class Vehicle { name: string, materialIds: UUIDSet, patientCapacity: number, - image: ImageProperties + image: ImageProperties, + position: Position ) { this.vehicleType = vehicleType; this.name = name; this.materialIds = materialIds; this.patientCapacity = patientCapacity; this.image = image; + this.position = position; } static readonly create = getCreate(this); + + static isInVehicle(vehicle: Vehicle, withPosition: WithPosition): boolean { + return ( + isInVehicle(withPosition) && + currentVehicleIdOf(withPosition) === vehicle.id + ); + } } diff --git a/shared/src/models/viewport.ts b/shared/src/models/viewport.ts index fc31482b7..400cebdbd 100644 --- a/shared/src/models/viewport.ts +++ b/shared/src/models/viewport.ts @@ -1,18 +1,32 @@ import { Type } from 'class-transformer'; import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { UUID, uuid, uuidValidationOptions } from '../utils'; -import { getCreate, Position, Size } from './utils'; -import type { ImageProperties } from './utils'; +import { IsPosition } from '../utils/validators/is-position'; +import { IsValue } from '../utils/validators'; +import { + getCreate, + lowerRightCornerOf, + MapPosition, + Position, + Size, + upperLeftCornerOf, +} from './utils'; +import type { ImageProperties, MapCoordinates } from './utils'; export class Viewport { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('viewport' as const) + public readonly type = 'viewport'; + /** * top-left position + * + * @deprecated Do not access directly, use helper methods from models/utils/position/position-helpers(-mutable) instead. */ @ValidateNested() - @Type(() => Position) + @IsPosition() public readonly position: Position; @ValidateNested() @@ -26,8 +40,8 @@ export class Viewport { * @param position top-left position * @deprecated Use {@link create} instead */ - constructor(position: Position, size: Size, name: string) { - this.position = position; + constructor(position: MapCoordinates, size: Size, name: string) { + this.position = MapPosition.create(position); this.size = size; this.name = name; } @@ -40,12 +54,14 @@ export class Viewport { aspectRatio: 1600 / 900, }; - static isInViewport(viewport: Viewport, position: Position): boolean { + static isInViewport(viewport: Viewport, position: MapCoordinates): boolean { + const upperLeftCorner = upperLeftCornerOf(viewport); + const lowerRightCorner = lowerRightCornerOf(viewport); return ( - viewport.position.x <= position.x && - position.x <= viewport.position.x + viewport.size.width && - viewport.position.y - viewport.size.height <= position.y && - position.y <= viewport.position.y + upperLeftCorner.x <= position.x && + position.x <= lowerRightCorner.x && + lowerRightCorner.y <= position.y && + position.y <= upperLeftCorner.y ); } } diff --git a/shared/src/simulation/activities/delay-event.ts b/shared/src/simulation/activities/delay-event.ts new file mode 100644 index 000000000..32914a992 --- /dev/null +++ b/shared/src/simulation/activities/delay-event.ts @@ -0,0 +1,48 @@ +import { Type } from 'class-transformer'; +import { IsInt, IsUUID, Min, ValidateNested } from 'class-validator'; +import { getCreate } from '../../models/utils'; +import { UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; +import { ExerciseSimulationEvent, simulationEventTypeOptions } from '../events'; +import { sendSimulationEvent } from '../utils/simulated-region'; +import type { + SimulationActivity, + SimulationActivityState, +} from './simulation-activity'; + +export class DelayEventActivityState implements SimulationActivityState { + @IsValue('delayEventActivity' as const) + public readonly type = 'delayEventActivity'; + + @IsUUID(4, uuidValidationOptions) + public readonly id!: UUID; + + @Type(...simulationEventTypeOptions) + @ValidateNested() + public readonly event!: ExerciseSimulationEvent; + + @IsInt() + @Min(0) + public readonly endTime!: number; + + /** + * @deprecated Use {@link create} instead + */ + constructor(id: UUID, event: ExerciseSimulationEvent, endTime: number) { + this.id = id; + this.event = event; + this.endTime = endTime; + } + + static readonly create = getCreate(this); +} + +export const delayEventActivity: SimulationActivity = { + activityState: DelayEventActivityState, + tick(draftState, simulatedRegion, activityState, _tickInterval, terminate) { + if (draftState.currentTime >= activityState.endTime) { + sendSimulationEvent(simulatedRegion, activityState.event); + terminate(); + } + }, +}; diff --git a/shared/src/simulation/activities/exercise-simulation-activity.ts b/shared/src/simulation/activities/exercise-simulation-activity.ts new file mode 100644 index 000000000..1f713cca5 --- /dev/null +++ b/shared/src/simulation/activities/exercise-simulation-activity.ts @@ -0,0 +1,48 @@ +import type { Type } from 'class-transformer'; +import { delayEventActivity } from './delay-event'; +import { SimulationActivityState } from './simulation-activity'; +import { unloadVehicleActivity } from './unload-vehicle'; + +export const simulationActivities = { + unloadVehicleActivity, + delayEventActivity, +}; + +export type ExerciseSimulationActivity = + (typeof simulationActivities)[keyof typeof simulationActivities]; + +export type ExerciseSimulationActivityState = InstanceType< + ExerciseSimulationActivity['activityState'] +>; + +type ExerciseSimulationActivityDictionary = { + [Activity in ExerciseSimulationActivity as InstanceType< + Activity['activityState'] + >['type']]: Activity; +}; + +export const simulationActivityDictionary = Object.fromEntries( + Object.values(simulationActivities).map((activity) => [ + new activity.activityState().type, + activity, + ]) +) as ExerciseSimulationActivityDictionary; + +export function getSimulationActivityConstructor( + state: ExerciseSimulationActivityState +) { + return simulationActivityDictionary[state.type]?.activityState; +} + +export const simulationActivityTypeOptions: Parameters = [ + () => SimulationActivityState, + { + keepDiscriminatorProperty: true, + discriminator: { + property: 'type', + subTypes: Object.entries(simulationActivityDictionary).map( + ([name, value]) => ({ name, value: value.activityState }) + ), + }, + }, +]; diff --git a/shared/src/simulation/activities/index.ts b/shared/src/simulation/activities/index.ts new file mode 100644 index 000000000..7a9ff4061 --- /dev/null +++ b/shared/src/simulation/activities/index.ts @@ -0,0 +1,2 @@ +export * from './exercise-simulation-activity'; +export * from './unload-vehicle'; diff --git a/shared/src/simulation/activities/simulation-activity.ts b/shared/src/simulation/activities/simulation-activity.ts new file mode 100644 index 000000000..928c2103c --- /dev/null +++ b/shared/src/simulation/activities/simulation-activity.ts @@ -0,0 +1,24 @@ +import type { SimulatedRegion } from '../../models'; +import type { ExerciseState } from '../../state'; +import type { Constructor, Mutable, UUID } from '../../utils'; + +export class SimulationActivityState { + readonly type!: `${string}Activity`; + readonly id!: UUID; +} + +export interface SimulationActivity { + readonly activityState: Constructor; + readonly tick: ( + draftState: Mutable, + simulatedRegion: Mutable, + activityState: Mutable, + tickInterval: number, + terminate: () => void + ) => void; + readonly onTerminate?: ( + draftState: Mutable, + simulatedRegion: Mutable, + activityId: UUID + ) => void; +} diff --git a/shared/src/simulation/activities/unload-vehicle.ts b/shared/src/simulation/activities/unload-vehicle.ts new file mode 100644 index 000000000..7af6ee032 --- /dev/null +++ b/shared/src/simulation/activities/unload-vehicle.ts @@ -0,0 +1,74 @@ +import { IsInt, IsUUID, Min } from 'class-validator'; +import { SimulatedRegion } from '../../models'; +import { getCreate } from '../../models/utils'; +import { UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; +import { unloadVehicle } from '../utils/vehicle'; +import type { + SimulationActivity, + SimulationActivityState, +} from './simulation-activity'; + +export class UnloadVehicleActivityState implements SimulationActivityState { + @IsValue('unloadVehicleActivity' as const) + public readonly type = 'unloadVehicleActivity'; + + @IsUUID(4, uuidValidationOptions) + public readonly id!: UUID; + + @IsUUID(4, uuidValidationOptions) + public readonly vehicleId!: UUID; + + @IsInt() + @Min(0) + public readonly startTime!: number; + + @IsInt() + @Min(0) + public readonly duration!: number; + + /** + * @deprecated Use {@link create} instead + */ + constructor( + id: UUID, + vehicleId: UUID, + startTime: number, + duration: number + ) { + this.vehicleId = vehicleId; + this.startTime = startTime; + this.duration = duration; + this.id = id; + } + + static readonly create = getCreate(this); +} + +// Because this activity relies on a cancel condition, we cannot model it as a DelayEventActivity +export const unloadVehicleActivity: SimulationActivity = + { + activityState: UnloadVehicleActivityState, + tick( + draftState, + simulatedRegion, + activityState, + _tickInterval, + terminate + ) { + const vehicle = draftState.vehicles[activityState.vehicleId]; + if ( + !vehicle || + !SimulatedRegion.isInSimulatedRegion(simulatedRegion, vehicle) + ) { + // The vehicle has left the region or was deleted for some reason. Cancel unloading. + terminate(); + } else if ( + draftState.currentTime >= + activityState.startTime + activityState.duration + ) { + unloadVehicle(draftState, simulatedRegion, vehicle); + terminate(); + } + }, + }; diff --git a/shared/src/simulation/behaviors/exercise-simulation-behavior.ts b/shared/src/simulation/behaviors/exercise-simulation-behavior.ts new file mode 100644 index 000000000..8e53b31b1 --- /dev/null +++ b/shared/src/simulation/behaviors/exercise-simulation-behavior.ts @@ -0,0 +1,40 @@ +import type { Type } from 'class-transformer'; +import { SimulationBehaviorState } from './simulation-behavior'; +import { unloadArrivingVehiclesBehavior } from './unload-arrived-vehicles'; + +export const simulationBehaviors = { + unloadArrivingVehiclesBehavior, +}; + +export type ExerciseSimulationBehavior = + (typeof simulationBehaviors)[keyof typeof simulationBehaviors]; + +export type ExerciseSimulationBehaviorState = InstanceType< + ExerciseSimulationBehavior['behaviorState'] +>; + +type ExerciseSimulationBehaviorDictionary = { + [Behavior in ExerciseSimulationBehavior as InstanceType< + Behavior['behaviorState'] + >['type']]: Behavior; +}; + +export const simulationBehaviorDictionary = Object.fromEntries( + Object.values(simulationBehaviors).map((behavior) => [ + new behavior.behaviorState().type, + behavior, + ]) +) as ExerciseSimulationBehaviorDictionary; + +export const simulationBehaviorTypeOptions: Parameters = [ + () => SimulationBehaviorState, + { + keepDiscriminatorProperty: true, + discriminator: { + property: 'type', + subTypes: Object.entries(simulationBehaviorDictionary).map( + ([name, value]) => ({ name, value: value.behaviorState }) + ), + }, + }, +]; diff --git a/shared/src/simulation/behaviors/index.ts b/shared/src/simulation/behaviors/index.ts new file mode 100644 index 000000000..19dff8af3 --- /dev/null +++ b/shared/src/simulation/behaviors/index.ts @@ -0,0 +1,2 @@ +export * from './exercise-simulation-behavior'; +export * from './unload-arrived-vehicles'; diff --git a/shared/src/simulation/behaviors/simulation-behavior.ts b/shared/src/simulation/behaviors/simulation-behavior.ts new file mode 100644 index 000000000..5b436008d --- /dev/null +++ b/shared/src/simulation/behaviors/simulation-behavior.ts @@ -0,0 +1,19 @@ +import type { SimulatedRegion } from '../../models'; +import type { ExerciseState } from '../../state'; +import type { Constructor, Mutable, UUID } from '../../utils'; +import type { ExerciseSimulationEvent } from '../events'; + +export class SimulationBehaviorState { + readonly type!: `${string}Behavior`; + readonly id!: UUID; +} + +export interface SimulationBehavior { + readonly behaviorState: Constructor; + readonly handleEvent: ( + draftState: Mutable, + simulatedRegion: Mutable, + behaviorState: Mutable, + event: Mutable + ) => void; +} diff --git a/shared/src/simulation/behaviors/unload-arrived-vehicles.ts b/shared/src/simulation/behaviors/unload-arrived-vehicles.ts new file mode 100644 index 000000000..8644ed585 --- /dev/null +++ b/shared/src/simulation/behaviors/unload-arrived-vehicles.ts @@ -0,0 +1,52 @@ +import { IsInt, IsUUID, Min } from 'class-validator'; +import { getCreate } from '../../models/utils'; +import { UUID, uuid, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; +import { UnloadVehicleActivityState } from '../activities/unload-vehicle'; +import { nextUUID } from '../utils/randomness'; +import { addActivity } from '../utils/simulated-region'; +import type { + SimulationBehavior, + SimulationBehaviorState, +} from './simulation-behavior'; + +export class UnloadArrivingVehiclesBehaviorState + implements SimulationBehaviorState +{ + @IsValue('unloadArrivingVehiclesBehavior' as const) + readonly type = 'unloadArrivingVehiclesBehavior'; + + @IsUUID(4, uuidValidationOptions) + public readonly id: UUID = uuid(); + + @IsInt() + @Min(0) + public readonly unloadDelay!: number; + + /** + * @deprecated Use {@link create} instead + */ + constructor(unloadDelay: number) { + this.unloadDelay = unloadDelay; + } + + static readonly create = getCreate(this); +} + +export const unloadArrivingVehiclesBehavior: SimulationBehavior = + { + behaviorState: UnloadArrivingVehiclesBehaviorState, + handleEvent(draftState, simulatedRegion, behaviorState, event) { + if (event.type === 'vehicleArrivedEvent') { + addActivity( + simulatedRegion, + UnloadVehicleActivityState.create( + nextUUID(draftState), + event.vehicleId, + event.arrivalTime, + behaviorState.unloadDelay + ) + ); + } + }, + }; diff --git a/shared/src/simulation/events/exercise-simulation-event.ts b/shared/src/simulation/events/exercise-simulation-event.ts new file mode 100644 index 000000000..85781c6e9 --- /dev/null +++ b/shared/src/simulation/events/exercise-simulation-event.ts @@ -0,0 +1,37 @@ +import type { Type } from 'class-transformer'; +import type { Constructor } from '../../utils'; +import { SimulationEvent } from './simulation-event'; +import { TickEvent } from './tick'; +import { VehicleArrivedEvent } from './vehicle-arrived'; + +export const simulationEvents = { + TickEvent, + VehicleArrivedEvent, +}; + +export type ExerciseSimulationEvent = InstanceType< + (typeof simulationEvents)[keyof typeof simulationEvents] +>; + +type ExerciseSimulationEventDictionary = { + [EventType in ExerciseSimulationEvent as EventType['type']]: Constructor; +}; + +// TODO: compute dynamically +export const simulationEventDictionary: ExerciseSimulationEventDictionary = { + tickEvent: TickEvent, + vehicleArrivedEvent: VehicleArrivedEvent, +}; + +export const simulationEventTypeOptions: Parameters = [ + () => SimulationEvent, + { + keepDiscriminatorProperty: true, + discriminator: { + property: 'type', + subTypes: Object.entries(simulationEventDictionary).map( + ([name, value]) => ({ name, value }) + ), + }, + }, +]; diff --git a/shared/src/simulation/events/index.ts b/shared/src/simulation/events/index.ts new file mode 100644 index 000000000..7b3bea99f --- /dev/null +++ b/shared/src/simulation/events/index.ts @@ -0,0 +1,3 @@ +export * from './exercise-simulation-event'; +export * from './vehicle-arrived'; +export * from './tick'; diff --git a/shared/src/simulation/events/simulation-event.ts b/shared/src/simulation/events/simulation-event.ts new file mode 100644 index 000000000..744952f52 --- /dev/null +++ b/shared/src/simulation/events/simulation-event.ts @@ -0,0 +1,3 @@ +export class SimulationEvent { + readonly type!: `${string}Event`; +} diff --git a/shared/src/simulation/events/tick.ts b/shared/src/simulation/events/tick.ts new file mode 100644 index 000000000..f0ee03304 --- /dev/null +++ b/shared/src/simulation/events/tick.ts @@ -0,0 +1,22 @@ +import { IsInt, IsPositive } from 'class-validator'; +import { getCreate } from '../../models/utils'; +import { IsValue } from '../../utils/validators'; +import type { SimulationEvent } from './simulation-event'; + +export class TickEvent implements SimulationEvent { + @IsValue('tickEvent') + readonly type = 'tickEvent'; + + @IsInt() + @IsPositive() + public readonly tickInterval!: number; + + /** + * @deprecated Use {@link create} instead + */ + constructor(tickInterval: number) { + this.tickInterval = tickInterval; + } + + static readonly create = getCreate(this); +} diff --git a/shared/src/simulation/events/vehicle-arrived.ts b/shared/src/simulation/events/vehicle-arrived.ts new file mode 100644 index 000000000..bff048dbc --- /dev/null +++ b/shared/src/simulation/events/vehicle-arrived.ts @@ -0,0 +1,27 @@ +import { IsInt, IsUUID, Min } from 'class-validator'; +import { getCreate } from '../../models/utils'; +import { UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; +import type { SimulationEvent } from './simulation-event'; + +export class VehicleArrivedEvent implements SimulationEvent { + @IsValue('vehicleArrivedEvent') + readonly type = 'vehicleArrivedEvent'; + + @IsUUID(4, uuidValidationOptions) + readonly vehicleId!: UUID; + + @IsInt() + @Min(0) + readonly arrivalTime!: number; + + /** + * @deprecated Use {@link create} instead + */ + constructor(vehicleId: UUID, arrivalTime: number) { + this.vehicleId = vehicleId; + this.arrivalTime = arrivalTime; + } + + static readonly create = getCreate(this); +} diff --git a/shared/src/simulation/index.ts b/shared/src/simulation/index.ts new file mode 100644 index 000000000..4090dc283 --- /dev/null +++ b/shared/src/simulation/index.ts @@ -0,0 +1,4 @@ +export * from './activities'; +export * from './behaviors'; +export * from './events'; +export * from './utils'; diff --git a/shared/src/simulation/utils/index.ts b/shared/src/simulation/utils/index.ts new file mode 100644 index 000000000..f67c90177 --- /dev/null +++ b/shared/src/simulation/utils/index.ts @@ -0,0 +1,3 @@ +export * from './simulated-region'; +export * from './vehicle'; +export * from './randomness'; diff --git a/shared/src/simulation/utils/randomness.ts b/shared/src/simulation/utils/randomness.ts new file mode 100644 index 000000000..3fd7a431d --- /dev/null +++ b/shared/src/simulation/utils/randomness.ts @@ -0,0 +1,70 @@ +/* eslint-disable no-bitwise */ +import { IsInt, Min, ValidateIf } from 'class-validator'; +import { sha256 } from '@noble/hashes/sha256'; +import { v4 } from 'uuid'; +import { getCreate } from '../../models/utils'; +import type { ExerciseState } from '../../state'; +import type { Mutable, UUID } from '../../utils'; +import { IsLiteralUnion, IsValue } from '../../utils/validators'; + +export class RandomState { + @IsValue('randomState' as const) + readonly type = 'randomState'; + + @IsLiteralUnion({ 'sha256-id-ctr': true }) + readonly algo = 'sha256-id-ctr'; + + @ValidateIf((o) => o.algo === 'sha256-id-ctr') + @IsInt() + @Min(0) + readonly counter: number = 0; + + static readonly create = getCreate(this); +} + +export function seededRandomState() { + return RandomState.create(); +} + +export function nextBool( + draftState: Mutable, + probability: number = 0.5 +): boolean { + return nextInt(draftState, 4294967296) / 4294967296 < probability; +} + +export function nextUUID(draftState: Mutable): UUID { + return v4({ + random: advance(draftState), + }); +} + +/** + * Draws the next integer from a pseudo random number generator persisted in `draftState`. + * @param draftState The exercise state where the pseudo random number generator state is stored + * @param upperBound The exclusive upper bound of the return value + * Must be a positive integer not greater than `4294967296`, or `2**32` + * @returns An integer from `0` (inclusive) to `upperBound` (exclusive) + */ +export function nextInt( + draftState: Mutable, + upperBound: number +): number { + const state = advance(draftState) + .slice(0, 4) + .map((b, i) => Math.trunc(b * 256 ** i)) + .reduce((a, b) => a | b); + return Math.trunc(state % upperBound); +} + +/** + * Draws the next bytes from a pseudo random number generator persisted in `draftState`. + * @param draftState The exercise state where the pseudo random number generator state is stored + * @returns An array of length 32 (specific to sha256) of numbers from 0-255 + */ +function advance(draftState: Mutable): Uint8Array { + const state = draftState.randomState; + const result = sha256(`${draftState.id}${state.counter.toString()}`); + state.counter++; + return result; +} diff --git a/shared/src/simulation/utils/simulated-region.ts b/shared/src/simulation/utils/simulated-region.ts new file mode 100644 index 000000000..4b429a20a --- /dev/null +++ b/shared/src/simulation/utils/simulated-region.ts @@ -0,0 +1,97 @@ +import type { SimulatedRegion } from '../../models'; +import type { ExerciseState } from '../../state'; +import type { Mutable, UUID } from '../../utils'; +import { cloneDeepMutable } from '../../utils'; +import type { ExerciseSimulationActivityState } from '../activities'; +import { simulationActivityDictionary } from '../activities'; +import { simulationBehaviorDictionary } from '../behaviors'; +import type { ExerciseSimulationEvent } from '../events'; +import { TickEvent } from '../events/tick'; + +export function simulateAllRegions( + draftState: Mutable, + tickInterval: number +) { + Object.values(draftState.simulatedRegions).forEach((simulatedRegion) => { + simulateSingleRegion(draftState, simulatedRegion, tickInterval); + }); +} + +function simulateSingleRegion( + draftState: Mutable, + simulatedRegion: Mutable, + tickInterval: number +) { + sendSimulationEvent(simulatedRegion, TickEvent.create(tickInterval)); + handleSimulationEvents(draftState, simulatedRegion); + tickActivities(draftState, simulatedRegion, tickInterval); +} + +function tickActivities( + draftState: Mutable, + simulatedRegion: Mutable, + tickInterval: number +) { + Object.values(simulatedRegion.activities).forEach((activityState) => { + simulationActivityDictionary[activityState.type].tick( + draftState, + simulatedRegion, + activityState as any, + tickInterval, + () => { + terminateActivity( + draftState, + simulatedRegion, + activityState.id + ); + } + ); + }); +} + +function handleSimulationEvents( + draftState: Mutable, + simulatedRegion: Mutable +) { + simulatedRegion.behaviors.forEach((behaviorState) => { + simulatedRegion.inEvents.forEach((event) => { + simulationBehaviorDictionary[behaviorState.type].handleEvent( + draftState, + simulatedRegion, + behaviorState as any, + event + ); + }); + }); + simulatedRegion.inEvents = []; +} + +export function sendSimulationEvent( + simulatedRegion: Mutable, + event: ExerciseSimulationEvent +) { + simulatedRegion.inEvents.push(cloneDeepMutable(event)); +} + +export function addActivity( + simulatedRegion: Mutable, + activityState: ExerciseSimulationActivityState +) { + simulatedRegion.activities[activityState.id] = + cloneDeepMutable(activityState); +} + +export function terminateActivity( + draftState: Mutable, + simulatedRegion: Mutable, + activityId: UUID +) { + const activityType = simulatedRegion.activities[activityId]?.type; + if (activityType) { + const activity = simulationActivityDictionary[activityType]; + if (activity.onTerminate) { + activity.onTerminate(draftState, simulatedRegion, activityId); + } + delete simulatedRegion.activities[activityId]; + } +} diff --git a/shared/src/simulation/utils/vehicle.ts b/shared/src/simulation/utils/vehicle.ts new file mode 100644 index 000000000..c4f794fb0 --- /dev/null +++ b/shared/src/simulation/utils/vehicle.ts @@ -0,0 +1,40 @@ +import { SimulatedRegion, Vehicle } from '../../models'; +import { SimulatedRegionPosition } from '../../models/utils'; +import { changePositionWithId } from '../../models/utils/position/position-helpers-mutable'; +import type { ExerciseState } from '../../state'; +import { getElement } from '../../store/action-reducers/utils'; +import type { Mutable } from '../../utils'; + +export function unloadVehicle( + draftState: Mutable, + simulatedRegion: Mutable, + vehicle: Mutable +) { + if (!SimulatedRegion.isInSimulatedRegion(simulatedRegion, vehicle)) { + console.error( + `Trying to unload a vehicle with id ${vehicle.id} into simulated region with id ${simulatedRegion.id} but the vehicle is not in that region.` + ); + return; + } + + const loadedElements = [ + { uuidSet: vehicle.materialIds, elementType: 'material' }, + { uuidSet: vehicle.personnelIds, elementType: 'personnel' }, + { uuidSet: vehicle.patientIds, elementType: 'patient' }, + ] as const; + + for (const { uuidSet, elementType } of loadedElements) { + for (const elementId of Object.keys(uuidSet)) { + const element = getElement(draftState, elementType, elementId); + if (Vehicle.isInVehicle(vehicle, element)) { + changePositionWithId( + elementId, + SimulatedRegionPosition.create(simulatedRegion.id), + elementType, + draftState + ); + } + } + } + vehicle.patientIds = {}; +} diff --git a/shared/src/state-helpers/create-vehicle-parameters.ts b/shared/src/state-helpers/create-vehicle-parameters.ts index d4d9951ad..661973a9a 100644 --- a/shared/src/state-helpers/create-vehicle-parameters.ts +++ b/shared/src/state-helpers/create-vehicle-parameters.ts @@ -2,8 +2,10 @@ import type { Vehicle, VehicleTemplate } from '../models'; import { Material, Personnel } from '../models'; import type { MaterialTemplate } from '../models/material-template'; import type { PersonnelTemplate } from '../models/personnel-template'; -import type { PersonnelType, Position } from '../models/utils'; +import type { PersonnelType, MapCoordinates } from '../models/utils'; +import { MapPosition } from '../models/utils/position/map-position'; import type { MaterialType } from '../models/utils/material-type'; +import { VehiclePosition } from '../models/utils/position/vehicle-position'; import { uuid } from '../utils'; import { arrayToUUIDSet } from '../utils/array-to-uuid-set'; @@ -20,7 +22,7 @@ export function createVehicleParameters( personnelTemplates: { [Key in PersonnelType]: PersonnelTemplate; }, - vehiclePosition?: Position + vehiclePosition: MapCoordinates ): { materials: Material[]; personnel: Personnel[]; @@ -31,19 +33,22 @@ export function createVehicleParameters( Material.generateMaterial( materialTemplates[currentMaterial], vehicleId, - vehicleTemplate.name + vehicleTemplate.name, + VehiclePosition.create(vehicleId) ) ); const personnel = vehicleTemplate.personnel.map((currentPersonnel) => Personnel.generatePersonnel( personnelTemplates[currentPersonnel], vehicleId, - vehicleTemplate.name + vehicleTemplate.name, + VehiclePosition.create(vehicleId) ) ); const vehicle: Vehicle = { id: vehicleId, + type: 'vehicle', materialIds: arrayToUUIDSet(materials.map((m) => m.id)), vehicleType: vehicleTemplate.vehicleType, name: vehicleTemplate.name, @@ -51,7 +56,7 @@ export function createVehicleParameters( image: vehicleTemplate.image, patientIds: {}, personnelIds: arrayToUUIDSet(personnel.map((p) => p.id)), - position: vehiclePosition, + position: MapPosition.create(vehiclePosition), }; return { materials, diff --git a/backend/src/database/state-migrations/10-rename-delete-transfer-action.ts b/shared/src/state-migrations/10-rename-delete-transfer-action.ts similarity index 71% rename from backend/src/database/state-migrations/10-rename-delete-transfer-action.ts rename to shared/src/state-migrations/10-rename-delete-transfer-action.ts index 24c60b961..078956f63 100644 --- a/backend/src/database/state-migrations/10-rename-delete-transfer-action.ts +++ b/shared/src/state-migrations/10-rename-delete-transfer-action.ts @@ -1,5 +1,6 @@ -import type { Action, Mutable } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import type { Action } from '../store'; +import type { Mutable } from '../utils'; +import type { Migration } from './migration-functions'; export const renameDeleteTransferAction10: Migration = { actions: (_initialState, actions) => { diff --git a/backend/src/database/state-migrations/11-add-map-image-is-locked.ts b/shared/src/state-migrations/11-add-map-image-is-locked.ts similarity index 82% rename from backend/src/database/state-migrations/11-add-map-image-is-locked.ts rename to shared/src/state-migrations/11-add-map-image-is-locked.ts index a5f3e4efb..92a16243c 100644 --- a/backend/src/database/state-migrations/11-add-map-image-is-locked.ts +++ b/shared/src/state-migrations/11-add-map-image-is-locked.ts @@ -1,5 +1,6 @@ -import type { Action, UUID } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import type { Action } from '../store'; +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; export const addMapImageIsLocked11: Migration = { actions: (_initialState, actions) => { diff --git a/backend/src/database/state-migrations/12-rename-incorrect-patient-images.ts b/shared/src/state-migrations/12-rename-incorrect-patient-images.ts similarity index 92% rename from backend/src/database/state-migrations/12-rename-incorrect-patient-images.ts rename to shared/src/state-migrations/12-rename-incorrect-patient-images.ts index 42f3bd391..df1d7b7ad 100644 --- a/backend/src/database/state-migrations/12-rename-incorrect-patient-images.ts +++ b/shared/src/state-migrations/12-rename-incorrect-patient-images.ts @@ -1,5 +1,5 @@ -import { StrictObject } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import { StrictObject } from '../utils'; +import type { Migration } from './migration-functions'; export const renameIncorrectPatientImages12: Migration = { actions: (_initialState, actions) => { diff --git a/backend/src/database/state-migrations/13-add-map-image-zindex.ts b/shared/src/state-migrations/13-add-map-image-zindex.ts similarity index 82% rename from backend/src/database/state-migrations/13-add-map-image-zindex.ts rename to shared/src/state-migrations/13-add-map-image-zindex.ts index 6324d80da..8f3d80a4e 100644 --- a/backend/src/database/state-migrations/13-add-map-image-zindex.ts +++ b/shared/src/state-migrations/13-add-map-image-zindex.ts @@ -1,5 +1,6 @@ -import type { Action, UUID } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import type { Action } from '../store'; +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; export const addMapImageZIndex13: Migration = { actions: (_initialState, actions) => { diff --git a/backend/src/database/state-migrations/14-add-personnel-and-material-templates-to-state.ts b/shared/src/state-migrations/14-add-personnel-and-material-templates-to-state.ts similarity index 96% rename from backend/src/database/state-migrations/14-add-personnel-and-material-templates-to-state.ts rename to shared/src/state-migrations/14-add-personnel-and-material-templates-to-state.ts index 795f14ee2..f65f020f6 100644 --- a/backend/src/database/state-migrations/14-add-personnel-and-material-templates-to-state.ts +++ b/shared/src/state-migrations/14-add-personnel-and-material-templates-to-state.ts @@ -1,5 +1,5 @@ -import { cloneDeepMutable } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import { cloneDeepMutable } from '../utils'; +import type { Migration } from './migration-functions'; export const addPersonnelAndMaterialToState14: Migration = { actions: null, diff --git a/shared/src/state-migrations/15-add-simulated-regions.ts b/shared/src/state-migrations/15-add-simulated-regions.ts new file mode 100644 index 000000000..76a2e863b --- /dev/null +++ b/shared/src/state-migrations/15-add-simulated-regions.ts @@ -0,0 +1,8 @@ +import type { Migration } from './migration-functions'; + +export const addSimulatedRegions15: Migration = { + actions: null, + state: (state: any) => { + state.simulatedRegions = {}; + }, +}; diff --git a/shared/src/state-migrations/16-add-meta-position.ts b/shared/src/state-migrations/16-add-meta-position.ts new file mode 100644 index 000000000..344228c2d --- /dev/null +++ b/shared/src/state-migrations/16-add-meta-position.ts @@ -0,0 +1,218 @@ +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; + +export const addMetaPosition16: Migration = { + actions: (_initialState, actions) => { + actions.forEach((action) => { + if ( + (action as { type: string } | null)?.type === + '[Patient] Add patient' + ) { + const typedAction = action as { + patient: { + position?: { x: number; y: number }; + vehicleId?: UUID; + metaPosition?: any; + }; + }; + if (typedAction.patient.position) { + typedAction.patient.metaPosition = { + type: 'coordinates', + position: { + x: typedAction.patient.position.x, + y: typedAction.patient.position.y, + }, + }; + } else if (typedAction.patient.vehicleId) { + typedAction.patient.metaPosition = { + type: 'vehicle', + vehicleId: typedAction.patient.vehicleId, + }; + } + } + if ( + (action as { type: string } | null)?.type === + '[Vehicle] Add vehicle' + ) { + const typedAction = action as { + vehicle: { + position?: { x: number; y: number }; + transfer?: any; + metaPosition?: any; + }; + materials: { + position?: { x: number; y: number }; + vehicleId?: UUID; + metaPosition?: any; + }[]; + personnel: { + position?: { x: number; y: number }; + transfer?: any; + vehicleId?: UUID; + metaPosition?: any; + }[]; + }; + if (typedAction.vehicle.position) { + typedAction.vehicle.metaPosition = { + type: 'coordinates', + position: { + x: typedAction.vehicle.position.x, + y: typedAction.vehicle.position.y, + }, + }; + } else if (typedAction.vehicle.transfer) { + typedAction.vehicle.metaPosition = { + type: 'transfer', + transfer: typedAction.vehicle.transfer, + }; + } else { + typedAction.vehicle.metaPosition = { + type: 'coordinates', + position: { + x: 0, + y: 0, + }, + }; + } + for (const personnel of typedAction.personnel) { + if (personnel.position) { + personnel.metaPosition = { + type: 'coordinates', + position: { + x: personnel.position.x, + y: personnel.position.y, + }, + }; + } else if (personnel.transfer) { + personnel.metaPosition = { + type: 'transfer', + transfer: personnel.transfer, + }; + } else if (personnel.vehicleId) { + personnel.metaPosition = { + type: 'vehicle', + vehicleId: personnel.vehicleId, + }; + } + } + + for (const material of typedAction.materials) { + if (material.position) { + material.metaPosition = { + type: 'coordinates', + position: { + x: material.position.x, + y: material.position.y, + }, + }; + } else if (material.vehicleId) { + material.metaPosition = { + type: 'vehicle', + vehicleId: material.vehicleId, + }; + } + } + } + }); + }, + state: (state) => { + const typedState = state as { + patients: { + [patientId: UUID]: { + position?: { x: number; y: number }; + vehicleId?: UUID; + metaPosition?: any; + }; + }; + materials: { + [materialId: UUID]: { + position?: { x: number; y: number }; + vehicleId?: UUID; + metaPosition?: any; + }; + }; + vehicles: { + [vehicleId: UUID]: { + position?: { x: number; y: number }; + transfer?: any; + metaPosition?: any; + }; + }; + personnel: { + [personnelId: UUID]: { + position?: { x: number; y: number }; + transfer?: any; + vehicleId?: UUID; + metaPosition?: any; + }; + }; + }; + + Object.values(typedState.patients).forEach((patient) => { + if (patient.position) { + patient.metaPosition = { + type: 'coordinates', + position: { x: patient.position.x, y: patient.position.y }, + }; + } else if (patient.vehicleId) { + patient.metaPosition = { + type: 'vehicle', + vehicleId: patient.vehicleId, + }; + } + }); + + Object.values(typedState.materials).forEach((material) => { + if (material.position) { + material.metaPosition = { + type: 'coordinates', + position: { + x: material.position.x, + y: material.position.y, + }, + }; + } else if (material.vehicleId) { + material.metaPosition = { + type: 'vehicle', + vehicleId: material.vehicleId, + }; + } + }); + + Object.values(typedState.vehicles).forEach((vehicle) => { + if (vehicle.position) { + vehicle.metaPosition = { + type: 'coordinates', + position: { x: vehicle.position.x, y: vehicle.position.y }, + }; + } else if (vehicle.transfer) { + vehicle.metaPosition = { + type: 'transfer', + transfer: vehicle.transfer, + }; + } + }); + + Object.values(typedState.personnel).forEach((personnel) => { + if (personnel.position) { + personnel.metaPosition = { + type: 'coordinates', + position: { + x: personnel.position.x, + y: personnel.position.y, + }, + }; + } else if (personnel.transfer) { + personnel.metaPosition = { + type: 'transfer', + transfer: personnel.transfer, + }; + } else if (personnel.vehicleId) { + personnel.metaPosition = { + type: 'vehicle', + vehicleId: personnel.vehicleId, + }; + } + }); + }, +}; diff --git a/shared/src/state-migrations/17-add-type-property.ts b/shared/src/state-migrations/17-add-type-property.ts new file mode 100644 index 000000000..afd36843f --- /dev/null +++ b/shared/src/state-migrations/17-add-type-property.ts @@ -0,0 +1,329 @@ +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; + +export const addTypeProperty17: Migration = { + actions: (_initialState, actions) => { + actions.forEach((action) => { + const actionType = (action as { type: string } | null)?.type; + + if (actionType === '[AlarmGroup] Add AlarmGroup') { + const typedAction = action as { + alarmGroup: { + type: 'alarmGroup'; + }; + }; + + typedAction.alarmGroup.type = 'alarmGroup'; + } + + if (actionType === '[Client] Add client') { + const typedAction = action as { + client: { + type: 'client'; + }; + }; + + typedAction.client.type = 'client'; + } + + if (actionType === '[Hospital] Add hospital') { + const typedAction = action as { + hospital: { + type: 'hospital'; + }; + }; + + typedAction.hospital.type = 'hospital'; + } + + if (actionType === '[MapImageTemplate] Add mapImageTemplate') { + const typedAction = action as { + mapImageTemplate: { + type: 'mapImageTemplate'; + }; + }; + + typedAction.mapImageTemplate.type = 'mapImageTemplate'; + } + + if (actionType === '[MapImage] Add MapImage') { + const typedAction = action as { + mapImage: { + type: 'mapImage'; + }; + }; + + typedAction.mapImage.type = 'mapImage'; + } + + if (actionType === '[Patient] Add patient') { + const typedAction = action as { + patient: { + type: 'patient'; + healthStates: { + [key: UUID]: { type: 'patientHealthState' }; + }; + }; + }; + + typedAction.patient.type = 'patient'; + Object.values(typedAction.patient.healthStates).forEach( + (healthState) => { + healthState.type = 'patientHealthState'; + } + ); + } + + if (actionType === '[SimulatedRegion] Add simulated region') { + const typedAction = action as { + simulatedRegion: { + type: 'simulatedRegion'; + }; + }; + + typedAction.simulatedRegion.type = 'simulatedRegion'; + } + + if ( + actionType === '[Transfer] Add to transfer' || + actionType === '[Transfer] Edit transfer' || + actionType === '[Transfer] Finish transfer' || + actionType === '[Transfer] Toggle pause transfer' + ) { + const typedAction = action as { + elementType: 'personnel' | 'vehicle' | 'vehicles'; + }; + + if (typedAction.elementType === 'vehicles') { + typedAction.elementType = 'vehicle'; + } + } + + if (actionType === '[TransferPoint] Add TransferPoint') { + const typedAction = action as { + transferPoint: { + type: 'transferPoint'; + }; + }; + + typedAction.transferPoint.type = 'transferPoint'; + } + + if (actionType === '[Vehicle] Add vehicle') { + const typedAction = action as { + vehicle: { + type: 'vehicle'; + }; + materials: { type: 'material' }[]; + personnel: { type: 'personnel' }[]; + }; + + typedAction.vehicle.type = 'vehicle'; + typedAction.materials.forEach((material) => { + material.type = 'material'; + }); + typedAction.personnel.forEach((personnel) => { + personnel.type = 'personnel'; + }); + } + + if (actionType === '[Vehicle] Load vehicle') { + const typedAction = action as { + elementToBeLoadedType: + | 'material' + | 'materials' + | 'patient' + | 'patients' + | 'personnel'; + }; + + if (typedAction.elementToBeLoadedType === 'materials') { + typedAction.elementToBeLoadedType = 'material'; + } else if (typedAction.elementToBeLoadedType === 'patients') { + typedAction.elementToBeLoadedType = 'patient'; + } + } + + if (actionType === '[Viewport] Add viewport') { + const typedAction = action as { + viewport: { + type: 'viewport'; + }; + }; + + typedAction.viewport.type = 'viewport'; + } + }); + }, + state: (state) => { + const typedState = state as { + alarmGroups: { + [key: UUID]: { + type: 'alarmGroup'; + }; + }; + clients: { + [key: UUID]: { + type: 'client'; + }; + }; + eocLog: { type: 'eocLogEntry' }[]; + configuration: { type: 'exerciseConfiguration' }; + hospitalPatients: { + [key: UUID]: { + type: 'hospitalPatient'; + }; + }; + hospitals: { + [key: UUID]: { + type: 'hospital'; + }; + }; + mapImageTemplates: { type: 'mapImageTemplate' }[]; + mapImages: { + [key: UUID]: { + type: 'mapImage'; + }; + }; + materialTemplates: { type: 'materialTemplate' }[]; + materials: { + [key: UUID]: { + type: 'material'; + }; + }; + patientCategories: { + type: 'patientCategory'; + patientTemplates: { type: 'patientTemplate' }[]; + }[]; + patients: { + [key: UUID]: { + type: 'patient'; + healthStates: { + [key: UUID]: { type: 'patientHealthState' }; + }; + }; + }; + personnelTemplates: { type: 'personnelTemplate' }[]; + personnel: { + [key: UUID]: { + type: 'personnel'; + }; + }; + simulatedRegions: { + [key: UUID]: { + type: 'simulatedRegion'; + }; + }; + transferPoints: { + [key: UUID]: { + type: 'transferPoint'; + }; + }; + vehicleTemplates: { type: 'vehicleTemplate' }[]; + vehicles: { + [key: UUID]: { + type: 'vehicle'; + }; + }; + viewports: { + [key: UUID]: { + type: 'viewport'; + }; + }; + }; + + Object.values(typedState.alarmGroups).forEach((alarmGroup) => { + alarmGroup.type = 'alarmGroup'; + }); + + Object.values(typedState.clients).forEach((client) => { + client.type = 'client'; + }); + + Object.values(typedState.eocLog).forEach((logEntry) => { + logEntry.type = 'eocLogEntry'; + }); + + typedState.configuration.type = 'exerciseConfiguration'; + + Object.values(typedState.hospitalPatients).forEach( + (hospitalPatient) => { + hospitalPatient.type = 'hospitalPatient'; + } + ); + + Object.values(typedState.hospitals).forEach((hospital) => { + hospital.type = 'hospital'; + }); + + Object.values(typedState.mapImageTemplates).forEach( + (mapImageTemplate) => { + mapImageTemplate.type = 'mapImageTemplate'; + } + ); + + Object.values(typedState.mapImages).forEach((mapImage) => { + mapImage.type = 'mapImage'; + }); + + Object.values(typedState.materialTemplates).forEach( + (materialTemplate) => { + materialTemplate.type = 'materialTemplate'; + } + ); + + Object.values(typedState.materials).forEach((material) => { + material.type = 'material'; + }); + + Object.values(typedState.patientCategories).forEach( + (patientCategory) => { + patientCategory.type = 'patientCategory'; + patientCategory.patientTemplates.forEach((patientTemplate) => { + patientTemplate.type = 'patientTemplate'; + }); + } + ); + + Object.values(typedState.patients).forEach((patient) => { + patient.type = 'patient'; + Object.values(patient.healthStates).forEach((healthState) => { + healthState.type = 'patientHealthState'; + }); + }); + + Object.values(typedState.personnelTemplates).forEach( + (personnelTemplates) => { + personnelTemplates.type = 'personnelTemplate'; + } + ); + + Object.values(typedState.personnel).forEach((personnel) => { + personnel.type = 'personnel'; + }); + + Object.values(typedState.simulatedRegions).forEach( + (simulatedRegion) => { + simulatedRegion.type = 'simulatedRegion'; + } + ); + + Object.values(typedState.transferPoints).forEach((transferPoint) => { + transferPoint.type = 'transferPoint'; + }); + + Object.values(typedState.vehicleTemplates).forEach( + (vehicleTemplate) => { + vehicleTemplate.type = 'vehicleTemplate'; + } + ); + + Object.values(typedState.vehicles).forEach((vehicle) => { + vehicle.type = 'vehicle'; + }); + + Object.values(typedState.viewports).forEach((viewport) => { + viewport.type = 'viewport'; + }); + }, +}; diff --git a/shared/src/state-migrations/18-replace-position-with-meta-position.ts b/shared/src/state-migrations/18-replace-position-with-meta-position.ts new file mode 100644 index 000000000..df30f0ea4 --- /dev/null +++ b/shared/src/state-migrations/18-replace-position-with-meta-position.ts @@ -0,0 +1,386 @@ +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; + +export const replacePositionWithMetaPosition18: Migration = { + actions: (_initialState, actions) => { + actions.forEach((action) => { + if ( + (action as { type: string } | null)?.type === + '[Patient] Add patient' + ) { + const typedAction = action as { + patient: { + metaPosition?: + | any + | { type: 'coordinates'; position: any } + | { type: any }; + position: any; + }; + }; + if (typedAction.patient.metaPosition?.type === 'coordinates') { + typedAction.patient.metaPosition.coordinates = + typedAction.patient.metaPosition.position; + delete typedAction.patient.metaPosition.position; + } + typedAction.patient.position = typedAction.patient.metaPosition; + delete typedAction.patient.metaPosition; + } + if ( + (action as { type: string } | null)?.type === + '[Vehicle] Add vehicle' + ) { + const typedAction = action as { + vehicle: { + metaPosition?: + | any + | { type: 'coordinates'; position: any } + | { type: any }; + position: any; + }; + materials: { + metaPosition?: + | any + | { type: 'coordinates'; position: any } + | { type: any }; + position: any; + }[]; + personnel: { + transfer?: any; + metaPosition?: + | any + | { type: 'coordinates'; position: any } + | { type: any }; + position: any; + }[]; + }; + for (const material of typedAction.materials) { + if (material.metaPosition?.type === 'coordinates') { + material.metaPosition.coordinates = + material.metaPosition.position; + delete material.metaPosition.position; + } + material.position = material.metaPosition; + delete material.metaPosition; + } + + for (const personnel of typedAction.personnel) { + delete personnel.transfer; + if (personnel.metaPosition?.type === 'coordinates') { + personnel.metaPosition.coordinates = + personnel.metaPosition.position; + delete personnel.metaPosition.position; + } + personnel.position = personnel.metaPosition; + delete personnel.metaPosition; + } + + if (typedAction.vehicle.metaPosition?.type === 'coordinates') { + typedAction.vehicle.metaPosition.coordinates = + typedAction.vehicle.metaPosition.position; + delete typedAction.vehicle.metaPosition.position; + } + typedAction.vehicle.position = typedAction.vehicle.metaPosition; + delete typedAction.vehicle.metaPosition; + } + if ( + (action as { type: string } | null)?.type === + '[Viewport] Add viewport' + ) { + const typedAction = action as { + viewport: { + position: + | { + type: 'coordinates'; + coordinates: { x: number; y: number }; + } + | { x: number; y: number }; + }; + }; + typedAction.viewport.position = { + type: 'coordinates', + coordinates: { + x: ( + typedAction.viewport.position as { + x: number; + y: number; + } + ).x, + y: ( + typedAction.viewport.position as { + x: number; + y: number; + } + ).y, + }, + }; + } + if ( + (action as { type: string } | null)?.type === + '[SimulatedRegion] Add simulated region' + ) { + const typedAction = action as { + simulatedRegion: { + position: + | { + type: 'coordinates'; + coordinates: { x: number; y: number }; + } + | { x: number; y: number }; + }; + }; + typedAction.simulatedRegion.position = { + type: 'coordinates', + coordinates: { + x: ( + typedAction.simulatedRegion.position as { + x: number; + y: number; + } + ).x, + y: ( + typedAction.simulatedRegion.position as { + x: number; + y: number; + } + ).y, + }, + }; + } + if ( + (action as { type: string } | null)?.type === + '[MapImage] Add MapImage' + ) { + const typedAction = action as { + mapImage: { + position: + | { + type: 'coordinates'; + coordinates: { x: number; y: number }; + } + | { x: number; y: number }; + }; + }; + typedAction.mapImage.position = { + type: 'coordinates', + coordinates: { + x: ( + typedAction.mapImage.position as { + x: number; + y: number; + } + ).x, + y: ( + typedAction.mapImage.position as { + x: number; + y: number; + } + ).y, + }, + }; + } + if ( + (action as { type: string } | null)?.type === + '[TransferPoint] Add TransferPoint' + ) { + const typedAction = action as { + transferPoint: { + position: + | { + type: 'coordinates'; + coordinates: { x: number; y: number }; + } + | { x: number; y: number }; + }; + }; + typedAction.transferPoint.position = { + type: 'coordinates', + coordinates: { + x: ( + typedAction.transferPoint.position as { + x: number; + y: number; + } + ).x, + y: ( + typedAction.transferPoint.position as { + x: number; + y: number; + } + ).y, + }, + }; + } + }); + }, + state: (state) => { + const typedState = state as { + patients: { + [patientId: UUID]: { + vehicleId?: any; + transfer?: any; + metaPosition?: + | any + | { type: 'coordinates'; position: any } + | { type: any }; + position: any; + }; + }; + materials: { + [materialId: UUID]: { + metaPosition?: + | any + | { type: 'coordinates'; position: any } + | { type: any }; + position: any; + }; + }; + vehicles: { + [vehicleId: UUID]: { + transfer?: any; + metaPosition?: + | any + | { type: 'coordinates'; position: any } + | { type: any }; + position: any; + }; + }; + personnel: { + [personnelId: UUID]: { + transfer?: any; + metaPosition?: + | any + | { type: 'coordinates'; position: any } + | { type: any }; + position: any; + }; + }; + viewports: { + [viewportId: UUID]: { + position: + | { + type: 'coordinates'; + coordinates: { x: number; y: number }; + } + | { x: number; y: number }; + }; + }; + simulatedRegions: { + [simulatedRegionId: UUID]: { + position: + | { + type: 'coordinates'; + coordinates: { x: number; y: number }; + } + | { x: number; y: number }; + }; + }; + mapImages: { + [simulatedRegionId: UUID]: { + position: + | { + type: 'coordinates'; + coordinates: { x: number; y: number }; + } + | { x: number; y: number }; + }; + }; + transferPoints: { + [simulatedRegionId: UUID]: { + position: + | { + type: 'coordinates'; + coordinates: { x: number; y: number }; + } + | { x: number; y: number }; + }; + }; + }; + + Object.values(typedState.patients).forEach((patient) => { + delete patient.transfer; + delete patient.vehicleId; + if (patient.metaPosition?.type === 'coordinates') { + patient.metaPosition.coordinates = + patient.metaPosition.position; + delete patient.metaPosition.position; + } + patient.position = patient.metaPosition; + delete patient.metaPosition; + }); + + Object.values(typedState.materials).forEach((material) => { + if (material.metaPosition?.type === 'coordinates') { + material.metaPosition.coordinates = + material.metaPosition.position; + delete material.metaPosition.position; + } + material.position = material.metaPosition; + delete material.metaPosition; + }); + + Object.values(typedState.vehicles).forEach((vehicle) => { + delete vehicle.transfer; + + if (vehicle.metaPosition?.type === 'coordinates') { + vehicle.metaPosition.coordinates = + vehicle.metaPosition.position; + delete vehicle.metaPosition.position; + } + vehicle.position = vehicle.metaPosition; + delete vehicle.metaPosition; + }); + + Object.values(typedState.personnel).forEach((personnel) => { + delete personnel.transfer; + if (personnel.metaPosition?.type === 'coordinates') { + personnel.metaPosition.coordinates = + personnel.metaPosition.position; + delete personnel.metaPosition.position; + } + personnel.position = personnel.metaPosition; + delete personnel.metaPosition; + }); + Object.values(typedState.viewports).forEach((viewport) => { + viewport.position = { + type: 'coordinates', + coordinates: { + x: (viewport.position as { x: number; y: number }).x, + y: (viewport.position as { x: number; y: number }).y, + }, + }; + }); + Object.values(typedState.simulatedRegions).forEach( + (simulatedRegion) => { + simulatedRegion.position = { + type: 'coordinates', + coordinates: { + x: ( + simulatedRegion.position as { x: number; y: number } + ).x, + y: ( + simulatedRegion.position as { x: number; y: number } + ).y, + }, + }; + } + ); + Object.values(typedState.mapImages).forEach((mapImage) => { + mapImage.position = { + type: 'coordinates', + coordinates: { + x: (mapImage.position as { x: number; y: number }).x, + y: (mapImage.position as { x: number; y: number }).y, + }, + }; + }); + Object.values(typedState.transferPoints).forEach((transferPoint) => { + transferPoint.position = { + type: 'coordinates', + coordinates: { + x: (transferPoint.position as { x: number; y: number }).x, + y: (transferPoint.position as { x: number; y: number }).y, + }, + }; + }); + }, +}; diff --git a/shared/src/state-migrations/19-rename-start-point-types.ts b/shared/src/state-migrations/19-rename-start-point-types.ts new file mode 100644 index 000000000..fdd5179b1 --- /dev/null +++ b/shared/src/state-migrations/19-rename-start-point-types.ts @@ -0,0 +1,131 @@ +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; + +export const renameStartPointTypes19: Migration = { + actions: (_initialState, actions) => { + actions.forEach((action) => { + if ( + (action as { type: string } | null)?.type === + '[Transfer] Add to transfer' + ) { + const typedAction = action as { + startPoint: { + type: + | 'alarmGroup' + | 'alarmGroupStartPoint' + | 'transferPoint' + | 'transferStartPoint'; + }; + }; + if (typedAction.startPoint.type === 'alarmGroup') { + typedAction.startPoint.type = 'alarmGroupStartPoint'; + } else if (typedAction.startPoint.type === 'transferPoint') { + typedAction.startPoint.type = 'transferStartPoint'; + } + } + }); + }, + state: (state) => { + const typedState = state as { + materials: { + [materialId: UUID]: { + position: { + type: 'transfer'; + transfer: { + startPoint: { + type: + | 'alarmGroup' + | 'alarmGroupStartPoint' + | 'transferPoint' + | 'transferStartPoint'; + }; + }; + }; + }; + }; + vehicles: { + [vehicleId: UUID]: { + position: { + type: 'transfer'; + transfer: { + startPoint: { + type: + | 'alarmGroup' + | 'alarmGroupStartPoint' + | 'transferPoint' + | 'transferStartPoint'; + }; + }; + }; + }; + }; + personnel: { + [personnelId: UUID]: { + position: { + type: 'transfer'; + transfer: { + startPoint: { + type: + | 'alarmGroup' + | 'alarmGroupStartPoint' + | 'transferPoint' + | 'transferStartPoint'; + }; + }; + }; + }; + }; + }; + + Object.values(typedState.materials).forEach((material) => { + if (material.position.type === 'transfer') { + if ( + material.position.transfer.startPoint.type === 'alarmGroup' + ) { + material.position.transfer.startPoint.type = + 'alarmGroupStartPoint'; + } else if ( + material.position.transfer.startPoint.type === + 'transferPoint' + ) { + material.position.transfer.startPoint.type = + 'transferStartPoint'; + } + } + }); + + Object.values(typedState.vehicles).forEach((vehicle) => { + if (vehicle.position.type === 'transfer') { + if ( + vehicle.position.transfer.startPoint.type === 'alarmGroup' + ) { + vehicle.position.transfer.startPoint.type = + 'alarmGroupStartPoint'; + } else if ( + vehicle.position.transfer.startPoint.type === + 'transferPoint' + ) { + vehicle.position.transfer.startPoint.type = + 'transferStartPoint'; + } + } + }); + + Object.values(typedState.personnel).forEach((personnel) => { + if (personnel.position.type === 'transfer') { + if ( + personnel.position.transfer.startPoint.type === 'alarmGroup' + ) { + personnel.position.transfer.startPoint.type = + 'alarmGroupStartPoint'; + } else if ( + personnel.position.transfer.startPoint.type === + 'transferPoint' + ) { + personnel.position.transfer.startPoint.type = + 'transferStartPoint'; + } + } + }); + }, +}; diff --git a/shared/src/state-migrations/20-add-simulation-properties.ts b/shared/src/state-migrations/20-add-simulation-properties.ts new file mode 100644 index 000000000..34b6be3b0 --- /dev/null +++ b/shared/src/state-migrations/20-add-simulation-properties.ts @@ -0,0 +1,46 @@ +import { seededRandomState } from '../simulation'; +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; + +export const addSimulationProperties20: Migration = { + actions: (_initialState, actions) => { + actions.forEach((action) => { + if ( + (action as { type: string } | null)?.type === + '[SimulatedRegion] Add simulated region' + ) { + const typedAction = action as { + simulatedRegion: { + inEvents: any[]; + behaviors: any[]; + activities: object; + }; + }; + typedAction.simulatedRegion.inEvents = []; + typedAction.simulatedRegion.behaviors = []; + typedAction.simulatedRegion.activities = {}; + } + }); + }, + state: (state: any) => { + state.randomState = seededRandomState(); + + const typedState = state as { + simulatedRegions: { + [simulatedRegionId: UUID]: { + inEvents: any[]; + behaviors: any[]; + activities: object; + }; + }; + }; + + Object.values(typedState.simulatedRegions).forEach( + (simulatedRegion) => { + simulatedRegion.inEvents = []; + simulatedRegion.behaviors = []; + simulatedRegion.activities = {}; + } + ); + }, +}; diff --git a/backend/src/database/state-migrations/3-update-eoc-log.ts b/shared/src/state-migrations/3-update-eoc-log.ts similarity index 90% rename from backend/src/database/state-migrations/3-update-eoc-log.ts rename to shared/src/state-migrations/3-update-eoc-log.ts index dd50b49ab..e6d52b124 100644 --- a/backend/src/database/state-migrations/3-update-eoc-log.ts +++ b/shared/src/state-migrations/3-update-eoc-log.ts @@ -1,5 +1,6 @@ -import type { Client, EocLogEntry, UUID } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import type { Client, EocLogEntry } from '../models'; +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; export const updateEocLog3: Migration = { actions: null, diff --git a/backend/src/database/state-migrations/4-remove-set-participant-id-action.ts b/shared/src/state-migrations/4-remove-set-participant-id-action.ts similarity index 78% rename from backend/src/database/state-migrations/4-remove-set-participant-id-action.ts rename to shared/src/state-migrations/4-remove-set-participant-id-action.ts index ab8a4d88d..7b3eef26d 100644 --- a/backend/src/database/state-migrations/4-remove-set-participant-id-action.ts +++ b/shared/src/state-migrations/4-remove-set-participant-id-action.ts @@ -1,5 +1,5 @@ -import type { Action } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import type { Action } from '../store'; +import type { Migration } from './migration-functions'; export const removeSetParticipantIdAction4: Migration = { actions: (_initialState, actions) => { diff --git a/backend/src/database/state-migrations/5-remove-statistics.ts b/shared/src/state-migrations/5-remove-statistics.ts similarity index 74% rename from backend/src/database/state-migrations/5-remove-statistics.ts rename to shared/src/state-migrations/5-remove-statistics.ts index 435c349b2..a13666b0a 100644 --- a/backend/src/database/state-migrations/5-remove-statistics.ts +++ b/shared/src/state-migrations/5-remove-statistics.ts @@ -1,4 +1,4 @@ -import type { Migration } from './migrations'; +import type { Migration } from './migration-functions'; export const removeStatistics5: Migration = { actions: null, diff --git a/backend/src/database/state-migrations/6-remove-state-history.ts b/shared/src/state-migrations/6-remove-state-history.ts similarity index 89% rename from backend/src/database/state-migrations/6-remove-state-history.ts rename to shared/src/state-migrations/6-remove-state-history.ts index 4df5cd0bb..3517ab53b 100644 --- a/backend/src/database/state-migrations/6-remove-state-history.ts +++ b/shared/src/state-migrations/6-remove-state-history.ts @@ -1,5 +1,5 @@ -import type { Action } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import type { Action } from '../store'; +import type { Migration } from './migration-functions'; export const removeStateHistory6: Migration = { actions: (_initialState, actions) => { diff --git a/backend/src/database/state-migrations/7-add-patient-remarks.ts b/shared/src/state-migrations/7-add-patient-remarks.ts similarity index 81% rename from backend/src/database/state-migrations/7-add-patient-remarks.ts rename to shared/src/state-migrations/7-add-patient-remarks.ts index a09d2fcb8..9d22efc86 100644 --- a/backend/src/database/state-migrations/7-add-patient-remarks.ts +++ b/shared/src/state-migrations/7-add-patient-remarks.ts @@ -1,5 +1,6 @@ -import type { Action, UUID } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import type { Action } from '../store'; +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; export const addPatientRemarks7: Migration = { actions: (_initialState, actions) => { diff --git a/backend/src/database/state-migrations/8-treatment-system-improvements.ts b/shared/src/state-migrations/8-treatment-system-improvements.ts similarity index 95% rename from backend/src/database/state-migrations/8-treatment-system-improvements.ts rename to shared/src/state-migrations/8-treatment-system-improvements.ts index 8223a3c69..d1ead0fc4 100644 --- a/backend/src/database/state-migrations/8-treatment-system-improvements.ts +++ b/shared/src/state-migrations/8-treatment-system-improvements.ts @@ -1,9 +1,6 @@ -import { - cloneDeepMutable, - SpatialTree, - StrictObject, -} from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import { SpatialTree } from '../models/utils'; +import { cloneDeepMutable, StrictObject } from '../utils'; +import type { Migration } from './migration-functions'; export const treatmentSystemImprovements8: Migration = { actions: (_initialState, actions: any[]) => { diff --git a/backend/src/database/state-migrations/9-remove-is-being-treated.ts b/shared/src/state-migrations/9-remove-is-being-treated.ts similarity index 82% rename from backend/src/database/state-migrations/9-remove-is-being-treated.ts rename to shared/src/state-migrations/9-remove-is-being-treated.ts index d29574f1d..d3ef10ac5 100644 --- a/backend/src/database/state-migrations/9-remove-is-being-treated.ts +++ b/shared/src/state-migrations/9-remove-is-being-treated.ts @@ -1,5 +1,6 @@ -import type { Action, UUID } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import type { Action } from '../store'; +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; export const removeIsBeingTreated9: Migration = { actions: (_initialState, actions) => { diff --git a/shared/src/state-migrations/impossible-migration.ts b/shared/src/state-migrations/impossible-migration.ts new file mode 100644 index 000000000..a684fdd68 --- /dev/null +++ b/shared/src/state-migrations/impossible-migration.ts @@ -0,0 +1,29 @@ +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; + +export const impossibleMigration: Migration = { + actions: (initialState, actions) => { + throw new RestoreError( + 'The migration is not possible', + (initialState as { id?: UUID }).id ?? 'unknown' + ); + }, + state: (state) => { + throw new RestoreError( + 'The migration is not possible', + (state as { id?: UUID }).id ?? 'unknown' + ); + }, +}; + +// TODO: Rename into `MigrationError` (upstream changes in the backend) +class RestoreError extends Error { + public constructor( + message: string, + public readonly exerciseId: UUID, + innerError?: Error + ) { + super(`Failed to restore exercise \`${exerciseId}\`: ${message}`); + this.cause = innerError; + } +} diff --git a/shared/src/state-migrations/index.ts b/shared/src/state-migrations/index.ts new file mode 100644 index 000000000..59cb930e6 --- /dev/null +++ b/shared/src/state-migrations/index.ts @@ -0,0 +1 @@ +export * from './migrations'; diff --git a/shared/src/state-migrations/migration-functions.ts b/shared/src/state-migrations/migration-functions.ts new file mode 100644 index 000000000..63a9e586c --- /dev/null +++ b/shared/src/state-migrations/migration-functions.ts @@ -0,0 +1,66 @@ +import { renameDeleteTransferAction10 } from './10-rename-delete-transfer-action'; +import { addMapImageIsLocked11 } from './11-add-map-image-is-locked'; +import { renameIncorrectPatientImages12 } from './12-rename-incorrect-patient-images'; +import { addMapImageZIndex13 } from './13-add-map-image-zindex'; +import { addPersonnelAndMaterialToState14 } from './14-add-personnel-and-material-templates-to-state'; +import { addSimulatedRegions15 } from './15-add-simulated-regions'; +import { addMetaPosition16 } from './16-add-meta-position'; +import { addTypeProperty17 } from './17-add-type-property'; +import { replacePositionWithMetaPosition18 } from './18-replace-position-with-meta-position'; +import { renameStartPointTypes19 } from './19-rename-start-point-types'; +import { addSimulationProperties20 } from './20-add-simulation-properties'; +import { updateEocLog3 } from './3-update-eoc-log'; +import { removeSetParticipantIdAction4 } from './4-remove-set-participant-id-action'; +import { removeStatistics5 } from './5-remove-statistics'; +import { removeStateHistory6 } from './6-remove-state-history'; +import { addPatientRemarks7 } from './7-add-patient-remarks'; +import { treatmentSystemImprovements8 } from './8-treatment-system-improvements'; +import { removeIsBeingTreated9 } from './9-remove-is-being-treated'; +import { impossibleMigration } from './impossible-migration'; + +/** + * Such a function gets the already migrated initial state of the exercise and an array of all actions (not yet migrated). + * It is expected that afterwards the actions in the provided array are migrated. + * It is not allowed to modify the order of the actions, to add an action or to remove an action. + * To indicate that an action should be removed it can be replaced by `null`. + * It may throw a {@link RestoreError} when a migration is not possible. + */ +type MigrateActionsFunction = ( + initialState: object, + actions: (object | null)[] +) => void; + +/** + * Such a function gets the not yet migrated state and is expected to mutate it to a migrated version. + * It may throw a {@link RestoreError} when a migration is not possible. + */ +type MigrateStateFunction = (state: object) => void; + +export interface Migration { + actions: MigrateActionsFunction | null; + state: MigrateStateFunction | null; +} + +export const migrations: { + [TargetStateVersion: number]: Migration; +} = { + 2: impossibleMigration, + 3: updateEocLog3, + 4: removeSetParticipantIdAction4, + 5: removeStatistics5, + 6: removeStateHistory6, + 7: addPatientRemarks7, + 8: treatmentSystemImprovements8, + 9: removeIsBeingTreated9, + 10: renameDeleteTransferAction10, + 11: addMapImageIsLocked11, + 12: renameIncorrectPatientImages12, + 13: addMapImageZIndex13, + 14: addPersonnelAndMaterialToState14, + 15: addSimulatedRegions15, + 16: addMetaPosition16, + 17: addTypeProperty17, + 18: replacePositionWithMetaPosition18, + 19: renameStartPointTypes19, + 20: addSimulationProperties20, +}; diff --git a/backend/src/database/state-migrations/migrations.spec.ts b/shared/src/state-migrations/migrations.spec.ts similarity index 76% rename from backend/src/database/state-migrations/migrations.spec.ts rename to shared/src/state-migrations/migrations.spec.ts index 69f430da3..daa9ac5ad 100644 --- a/backend/src/database/state-migrations/migrations.spec.ts +++ b/shared/src/state-migrations/migrations.spec.ts @@ -1,6 +1,6 @@ -import { ExerciseState } from 'digital-fuesim-manv-shared'; import { range } from 'lodash-es'; -import { migrations } from './migrations'; +import { ExerciseState } from '../state'; +import { migrations } from './migration-functions'; describe('migrations definition', () => { it('has the correct versions', () => { diff --git a/shared/src/state-migrations/migrations.ts b/shared/src/state-migrations/migrations.ts new file mode 100644 index 000000000..f23b01d8d --- /dev/null +++ b/shared/src/state-migrations/migrations.ts @@ -0,0 +1,76 @@ +import type { StateExport } from '../export-import/file-format'; +import { ExerciseState } from '../state'; +import type { ExerciseAction } from '../store'; +import { applyAllActions } from '../store'; +import type { Mutable } from '../utils'; +import { cloneDeepMutable } from '../utils'; +import { migrations } from './migration-functions'; + +export function migrateStateExport( + stateExportToMigrate: StateExport +): Mutable { + const stateExport = cloneDeepMutable(stateExportToMigrate); + const propertiesToMigrate = { + currentState: stateExport.currentState, + history: stateExport.history + ? { + initialState: stateExport.history.initialState, + actions: stateExport.history.actionHistory, + } + : undefined, + }; + const newVersion = applyMigrations( + stateExport.dataVersion, + propertiesToMigrate + ); + stateExport.dataVersion = newVersion; + stateExport.currentState = propertiesToMigrate.currentState; + if (stateExport.history) { + stateExport.history.actionHistory = + // Remove actions that are marked to be removed by the migrations + propertiesToMigrate.history!.actions.filter( + (action) => action !== null + ); + } + return stateExport; +} + +/** + * Migrates {@link propertiesToMigrate} to the newest version ({@link ExerciseState.currentStateVersion}) + * by mutating them. + * + * @returns The new state version + */ +export function applyMigrations( + currentStateVersion: number, + propertiesToMigrate: { + currentState: object; + history?: { initialState: object; actions: (object | null)[] }; + } +): number { + const targetVersion = ExerciseState.currentStateVersion; + for (let i = currentStateVersion + 1; i <= targetVersion; i++) { + const stateMigration = migrations[i]!.state; + if (stateMigration !== null) { + if (propertiesToMigrate.history) + stateMigration(propertiesToMigrate.history.initialState); + else stateMigration(propertiesToMigrate.currentState); + } + if (!propertiesToMigrate.history) continue; + const actionMigration = migrations[i]!.actions; + if (actionMigration !== null) { + actionMigration( + propertiesToMigrate.history.initialState, + propertiesToMigrate.history.actions + ); + } + } + if (propertiesToMigrate.history) + propertiesToMigrate.currentState = applyAllActions( + propertiesToMigrate.history.initialState as ExerciseState, + propertiesToMigrate.history.actions.filter( + (action) => action !== null + ) as ExerciseAction[] + ); + return targetVersion; +} diff --git a/shared/src/state.ts b/shared/src/state.ts index 866711741..b54476fe7 100644 --- a/shared/src/state.ts +++ b/shared/src/state.ts @@ -8,36 +8,47 @@ import { Min, ValidateNested, } from 'class-validator'; -import { defaultMapImagesTemplates } from './data/default-state/map-images-templates'; +import { + defaultMapImagesTemplates, + defaultPatientCategories, + defaultVehicleTemplates, +} from './data'; import { defaultMaterialTemplates } from './data/default-state/material-templates'; -import { defaultPatientCategories } from './data/default-state/patient-templates'; import { defaultPersonnelTemplates } from './data/default-state/personnel-templates'; -import { defaultVehicleTemplates } from './data/default-state/vehicle-templates'; -import type { +import { AlarmGroup, Client, + EocLogEntry, Hospital, HospitalPatient, MapImage, + MapImageTemplate, Material, Patient, + PatientCategory, Personnel, + SimulatedRegion, TransferPoint, Vehicle, + VehicleTemplate, Viewport, } from './models'; -import { EocLogEntry, MapImageTemplate, VehicleTemplate } from './models'; import { ExerciseConfiguration } from './models/exercise-configuration'; import type { MaterialTemplate } from './models/material-template'; -import { PatientCategory } from './models/patient-category'; import type { PersonnelTemplate } from './models/personnel-template'; import type { PersonnelType } from './models/utils'; -import { getCreate, SpatialTree } from './models/utils'; -import { ExerciseStatus } from './models/utils/exercise-status'; +import { + ExerciseStatus, + exerciseStatusAllowedValues, + getCreate, + SpatialTree, +} from './models/utils'; import type { MaterialType } from './models/utils/material-type'; -import type { SpatialElementType } from './store/action-reducers/utils/spatial-elements'; +import { seededRandomState, RandomState } from './simulation/utils'; +import type { SpatialElementPlural } from './store/action-reducers/utils/spatial-elements'; import type { UUID } from './utils'; import { uuid, uuidValidationOptions } from './utils'; +import { IsIdMap, IsLiteralUnion } from './utils/validators'; export class ExerciseState { @IsUUID(4, uuidValidationOptions) @@ -52,32 +63,41 @@ export class ExerciseState { @IsInt() @Min(0) public readonly currentTime = 0; - @IsString() + @IsLiteralUnion(exerciseStatusAllowedValues) public readonly currentStatus: ExerciseStatus = 'notStarted'; - @IsObject() + + @Type(() => RandomState) + @ValidateNested() + public readonly randomState: RandomState = seededRandomState(); + + @IsIdMap(Viewport) public readonly viewports: { readonly [key: UUID]: Viewport } = {}; - @IsObject() + @IsIdMap(SimulatedRegion) + public readonly simulatedRegions: { + readonly [key: UUID]: SimulatedRegion; + } = {}; + @IsIdMap(Vehicle) public readonly vehicles: { readonly [key: UUID]: Vehicle } = {}; - @IsObject() + @IsIdMap(Personnel) public readonly personnel: { readonly [key: UUID]: Personnel } = {}; - @IsObject() + @IsIdMap(Patient) public readonly patients: { readonly [key: UUID]: Patient } = {}; - @IsObject() + @IsIdMap(Material) public readonly materials: { readonly [key: UUID]: Material } = {}; - @IsObject() + @IsIdMap(MapImage) public readonly mapImages: { readonly [key: UUID]: MapImage } = {}; - @IsObject() + @IsIdMap(TransferPoint) public readonly transferPoints: { readonly [key: UUID]: TransferPoint } = {}; - @IsObject() + @IsIdMap(Hospital) public readonly hospitals: { readonly [key: UUID]: Hospital } = {}; - @IsObject() + @IsIdMap(HospitalPatient, (hospitalPatient) => hospitalPatient.patientId) public readonly hospitalPatients: { readonly [key: UUID]: HospitalPatient; } = {}; - @IsObject() + @IsIdMap(AlarmGroup) public readonly alarmGroups: { readonly [key: UUID]: AlarmGroup } = {}; - @IsObject() + @IsIdMap(Client) public readonly clients: { readonly [key: UUID]: Client } = {}; @IsArray() @ValidateNested() @@ -104,12 +124,12 @@ export class ExerciseState { @Type(() => EocLogEntry) public readonly eocLog: readonly EocLogEntry[] = []; @IsString() - public readonly participantId: string = ''; + public readonly participantId: string; // Mutable` could still have immutable objects in spatialTree @IsObject() public readonly spatialTrees: { - [type in SpatialElementType]: SpatialTree; + [type in SpatialElementPlural]: SpatialTree; } = { materials: SpatialTree.create(), patients: SpatialTree.create(), @@ -134,5 +154,5 @@ export class ExerciseState { * * This number MUST be increased every time a change to any object (that is part of the state or the state itself) is made in a way that there may be states valid before that are no longer valid. */ - static readonly currentStateVersion = 14; + static readonly currentStateVersion = 20; } diff --git a/shared/src/store/action-reducers/action-reducers.ts b/shared/src/store/action-reducers/action-reducers.ts index 9ba15932c..47d8c0739 100644 --- a/shared/src/store/action-reducers/action-reducers.ts +++ b/shared/src/store/action-reducers/action-reducers.ts @@ -13,6 +13,7 @@ import { TransferPointActionReducers } from './transfer-point'; import { VehicleActionReducers } from './vehicle'; import { ViewportActionReducers } from './viewport'; import { EmergencyOperationCenterActionReducers } from './emergency-operation-center'; +import { SimulatedRegionActionReducers } from './simulated-region'; /** * All action reducers of the exercise must be registered here @@ -33,9 +34,11 @@ const actionReducers = { ...TransferActionReducers, ...HospitalActionReducers, ...EmergencyOperationCenterActionReducers, + ...SimulatedRegionActionReducers, }; -type ExerciseActionReducer = typeof actionReducers[keyof typeof actionReducers]; +type ExerciseActionReducer = + (typeof actionReducers)[keyof typeof actionReducers]; type ExerciseActionTypeDictionary = { [_ActionReducer in ExerciseActionReducer as InstanceType< diff --git a/shared/src/store/action-reducers/alarm-group.ts b/shared/src/store/action-reducers/alarm-group.ts index 909b3c49a..cf4d3cead 100644 --- a/shared/src/store/action-reducers/alarm-group.ts +++ b/shared/src/store/action-reducers/alarm-group.ts @@ -10,12 +10,13 @@ import { AlarmGroup } from '../../models/alarm-group'; import { AlarmGroupVehicle } from '../../models/utils/alarm-group-vehicle'; import type { Mutable } from '../../utils'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; import { getElement } from './utils/get-element'; export class AddAlarmGroupAction implements Action { - @IsString() + @IsValue('[AlarmGroup] Add AlarmGroup' as const) public readonly type = '[AlarmGroup] Add AlarmGroup'; @ValidateNested() @@ -24,7 +25,7 @@ export class AddAlarmGroupAction implements Action { } export class RenameAlarmGroupAction implements Action { - @IsString() + @IsValue('[AlarmGroup] Rename AlarmGroup' as const) public readonly type = '[AlarmGroup] Rename AlarmGroup'; @IsUUID(4, uuidValidationOptions) @@ -34,14 +35,14 @@ export class RenameAlarmGroupAction implements Action { public readonly name!: string; } export class RemoveAlarmGroupAction implements Action { - @IsString() + @IsValue('[AlarmGroup] Remove AlarmGroup' as const) public readonly type = '[AlarmGroup] Remove AlarmGroup'; @IsUUID(4, uuidValidationOptions) public readonly alarmGroupId!: UUID; } export class AddAlarmGroupVehicleAction implements Action { - @IsString() + @IsValue('[AlarmGroup] Add AlarmGroupVehicle' as const) public readonly type = '[AlarmGroup] Add AlarmGroupVehicle'; @IsUUID(4, uuidValidationOptions) @@ -52,7 +53,7 @@ export class AddAlarmGroupVehicleAction implements Action { public readonly alarmGroupVehicle!: AlarmGroupVehicle; } export class EditAlarmGroupVehicleAction implements Action { - @IsString() + @IsValue('[AlarmGroup] Edit AlarmGroupVehicle' as const) public readonly type = '[AlarmGroup] Edit AlarmGroupVehicle'; @IsUUID(4, uuidValidationOptions) @@ -69,7 +70,7 @@ export class EditAlarmGroupVehicleAction implements Action { public readonly name!: string; } export class RemoveAlarmGroupVehicleAction implements Action { - @IsString() + @IsValue('[AlarmGroup] Remove AlarmGroupVehicle' as const) public readonly type = '[AlarmGroup] Remove AlarmGroupVehicle'; @IsUUID(4, uuidValidationOptions) @@ -95,7 +96,7 @@ export namespace AlarmGroupActionReducers { reducer: (draftState, { alarmGroupId, name }) => { const alarmGroup = getElement( draftState, - 'alarmGroups', + 'alarmGroup', alarmGroupId ); alarmGroup.name = name; @@ -107,7 +108,7 @@ export namespace AlarmGroupActionReducers { export const removeAlarmGroup: ActionReducer = { action: RemoveAlarmGroupAction, reducer: (draftState, { alarmGroupId }) => { - getElement(draftState, 'alarmGroups', alarmGroupId); + getElement(draftState, 'alarmGroup', alarmGroupId); delete draftState.alarmGroups[alarmGroupId]; return draftState; }, @@ -120,7 +121,7 @@ export namespace AlarmGroupActionReducers { reducer: (draftState, { alarmGroupId, alarmGroupVehicle }) => { const alarmGroup = getElement( draftState, - 'alarmGroups', + 'alarmGroup', alarmGroupId ); alarmGroup.alarmGroupVehicles[alarmGroupVehicle.id] = @@ -139,7 +140,7 @@ export namespace AlarmGroupActionReducers { ) => { const alarmGroup = getElement( draftState, - 'alarmGroups', + 'alarmGroup', alarmGroupId ); const alarmGroupVehicle = getAlarmGroupVehicle( @@ -159,7 +160,7 @@ export namespace AlarmGroupActionReducers { reducer: (draftState, { alarmGroupId, alarmGroupVehicleId }) => { const alarmGroup = getElement( draftState, - 'alarmGroups', + 'alarmGroup', alarmGroupId ); getAlarmGroupVehicle(alarmGroup, alarmGroupVehicleId); diff --git a/shared/src/store/action-reducers/client.ts b/shared/src/store/action-reducers/client.ts index 37ae01b13..55208470e 100644 --- a/shared/src/store/action-reducers/client.ts +++ b/shared/src/store/action-reducers/client.ts @@ -1,18 +1,13 @@ import { Type } from 'class-transformer'; -import { - IsString, - ValidateNested, - IsUUID, - IsOptional, - IsBoolean, -} from 'class-validator'; +import { IsBoolean, IsOptional, IsUUID, ValidateNested } from 'class-validator'; import { Client } from '../../models'; -import { uuidValidationOptions, UUID, cloneDeepMutable } from '../../utils'; +import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { getElement } from './utils/get-element'; export class AddClientAction implements Action { - @IsString() + @IsValue('[Client] Add client' as const) public readonly type = '[Client] Add client'; @ValidateNested() @Type(() => Client) @@ -20,14 +15,14 @@ export class AddClientAction implements Action { } export class RemoveClientAction implements Action { - @IsString() + @IsValue('[Client] Remove client' as const) public readonly type = '[Client] Remove client'; @IsUUID(4, uuidValidationOptions) public readonly clientId!: UUID; } export class RestrictViewToViewportAction implements Action { - @IsString() + @IsValue('[Client] Restrict to viewport' as const) public readonly type = '[Client] Restrict to viewport'; @IsUUID(4, uuidValidationOptions) public readonly clientId!: UUID; @@ -37,7 +32,7 @@ export class RestrictViewToViewportAction implements Action { } export class SetWaitingRoomAction implements Action { - @IsString() + @IsValue('[Client] Set waitingroom' as const) public readonly type = '[Client] Set waitingroom'; @IsUUID(4, uuidValidationOptions) public readonly clientId!: UUID; @@ -58,7 +53,7 @@ export namespace ClientActionReducers { export const removeClient: ActionReducer = { action: RemoveClientAction, reducer: (draftState, { clientId }) => { - getElement(draftState, 'clients', clientId); + getElement(draftState, 'client', clientId); delete draftState.clients[clientId]; return draftState; }, @@ -69,12 +64,12 @@ export namespace ClientActionReducers { { action: RestrictViewToViewportAction, reducer: (draftState, { clientId, viewportId }) => { - const client = getElement(draftState, 'clients', clientId); + const client = getElement(draftState, 'client', clientId); if (viewportId === undefined) { client.viewRestrictedToViewportId = viewportId; return draftState; } - getElement(draftState, 'viewports', viewportId); + getElement(draftState, 'viewport', viewportId); client.viewRestrictedToViewportId = viewportId; return draftState; }, @@ -84,7 +79,7 @@ export namespace ClientActionReducers { export const setWaitingRoom: ActionReducer = { action: SetWaitingRoomAction, reducer: (draftState, { clientId, shouldBeInWaitingRoom }) => { - const client = getElement(draftState, 'clients', clientId); + const client = getElement(draftState, 'client', clientId); client.isInWaitingRoom = shouldBeInWaitingRoom; return draftState; }, diff --git a/shared/src/store/action-reducers/configuration.ts b/shared/src/store/action-reducers/configuration.ts index 6d9f906ec..d850e5635 100644 --- a/shared/src/store/action-reducers/configuration.ts +++ b/shared/src/store/action-reducers/configuration.ts @@ -1,11 +1,12 @@ import { Type } from 'class-transformer'; -import { IsBoolean, IsString, ValidateNested } from 'class-validator'; +import { IsBoolean, ValidateNested } from 'class-validator'; import { TileMapProperties } from '../../models/utils'; import { cloneDeepMutable } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; export class SetTileMapPropertiesAction implements Action { - @IsString() + @IsValue('[Configuration] Set tileMapProperties' as const) public readonly type = '[Configuration] Set tileMapProperties'; @ValidateNested() @@ -14,7 +15,7 @@ export class SetTileMapPropertiesAction implements Action { } export class SetPretriageEnabledAction implements Action { - @IsString() + @IsValue('[Configuration] Set pretriageEnabled' as const) public readonly type = '[Configuration] Set pretriageEnabled'; @IsBoolean() @@ -22,7 +23,7 @@ export class SetPretriageEnabledAction implements Action { } export class SetBluePatientsEnabledFlagAction implements Action { - @IsString() + @IsValue('[Configuration] Set bluePatientsEnabled' as const) public readonly type = '[Configuration] Set bluePatientsEnabled'; @IsBoolean() diff --git a/shared/src/store/action-reducers/emergency-operation-center.ts b/shared/src/store/action-reducers/emergency-operation-center.ts index d2ddcc094..71a0a7531 100644 --- a/shared/src/store/action-reducers/emergency-operation-center.ts +++ b/shared/src/store/action-reducers/emergency-operation-center.ts @@ -1,10 +1,11 @@ import { IsString, MaxLength } from 'class-validator'; import { EocLogEntry } from '../../models'; -import type { Action, ActionReducer } from '../action-reducer'; import { cloneDeepMutable } from '../../utils'; +import { IsValue } from '../../utils/validators'; +import type { Action, ActionReducer } from '../action-reducer'; export class AddLogEntryAction implements Action { - @IsString() + @IsValue('[Emergency Operation Center] Add Log Entry' as const) public readonly type = '[Emergency Operation Center] Add Log Entry'; @IsString() @MaxLength(255) diff --git a/shared/src/store/action-reducers/exercise.ts b/shared/src/store/action-reducers/exercise.ts index 35535ee9e..ea4d45ece 100644 --- a/shared/src/store/action-reducers/exercise.ts +++ b/shared/src/store/action-reducers/exercise.ts @@ -4,32 +4,43 @@ import { IsBoolean, IsInt, IsPositive, - IsString, ValidateNested, } from 'class-validator'; import type { Personnel, Vehicle } from '../../models'; import { Patient } from '../../models'; -import { getStatus } from '../../models/utils'; +import { + getStatus, + isNotInTransfer, + currentTransferOf, + TransferPosition, +} from '../../models/utils'; +import { changePosition } from '../../models/utils/position/position-helpers-mutable'; +import { simulateAllRegions } from '../../simulation/utils/simulated-region'; import type { ExerciseState } from '../../state'; import type { Mutable } from '../../utils'; +import { cloneDeepMutable } from '../../utils'; +import type { ElementTypePluralMap } from '../../utils/element-type-plural-map'; +import { elementTypePluralMap } from '../../utils/element-type-plural-map'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; +import type { TransferableElementType } from './transfer'; import { letElementArrive } from './transfer'; import { updateTreatments } from './utils/calculate-treatments'; import { PatientUpdate } from './utils/patient-updates'; export class PauseExerciseAction implements Action { - @IsString() + @IsValue('[Exercise] Pause' as const) public readonly type = '[Exercise] Pause'; } export class StartExerciseAction implements Action { - @IsString() + @IsValue('[Exercise] Start' as const) public readonly type = '[Exercise] Start'; } export class ExerciseTickAction implements Action { - @IsString() + @IsValue('[Exercise] Tick' as const) public readonly type = '[Exercise] Tick'; @IsArray() @@ -122,32 +133,45 @@ export namespace ExerciseActionReducers { }); // Refresh transfers - refreshTransfer(draftState, 'vehicles', tickInterval); + refreshTransfer(draftState, 'vehicle', tickInterval); refreshTransfer(draftState, 'personnel', tickInterval); + + simulateAllRegions(draftState, tickInterval); return draftState; }, rights: 'server', }; } +type TransferTypePluralMap = Pick< + ElementTypePluralMap, + TransferableElementType +>; + function refreshTransfer( draftState: Mutable, - key: 'personnel' | 'vehicles', + type: keyof TransferTypePluralMap, tickInterval: number ): void { - const elements = draftState[key]; + const elements = draftState[elementTypePluralMap[type]]; Object.values(elements).forEach((element: Mutable) => { - if (!element.transfer) { + if (isNotInTransfer(element)) { return; } - if (element.transfer.isPaused) { - element.transfer.endTimeStamp += tickInterval; + if (currentTransferOf(element).isPaused) { + const newTransfer = cloneDeepMutable(currentTransferOf(element)); + newTransfer.endTimeStamp += tickInterval; + changePosition( + element, + TransferPosition.create(newTransfer), + draftState + ); return; } // Not transferred yet - if (element.transfer.endTimeStamp > draftState.currentTime) { + if (currentTransferOf(element).endTimeStamp > draftState.currentTime) { return; } - letElementArrive(draftState, key, element.id); + letElementArrive(draftState, type, element.id); }); } diff --git a/shared/src/store/action-reducers/hospital.ts b/shared/src/store/action-reducers/hospital.ts index 6e98dc9ed..b5bb8e559 100644 --- a/shared/src/store/action-reducers/hospital.ts +++ b/shared/src/store/action-reducers/hospital.ts @@ -9,12 +9,13 @@ import { import { Hospital } from '../../models'; import { HospitalPatient } from '../../models/hospital-patient'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { getElement } from './utils/get-element'; import { deleteVehicle } from './vehicle'; export class AddHospitalAction implements Action { - @IsString() + @IsValue('[Hospital] Add hospital' as const) public readonly type = '[Hospital] Add hospital'; @ValidateNested() @Type(() => Hospital) @@ -22,7 +23,7 @@ export class AddHospitalAction implements Action { } export class EditTransportDurationToHospitalAction implements Action { - @IsString() + @IsValue('[Hospital] Edit transportDuration to hospital' as const) public readonly type = '[Hospital] Edit transportDuration to hospital'; @IsUUID(4, uuidValidationOptions) public readonly hospitalId!: UUID; @@ -33,7 +34,7 @@ export class EditTransportDurationToHospitalAction implements Action { } export class RenameHospitalAction implements Action { - @IsString() + @IsValue('[Hospital] Rename hospital' as const) public readonly type = '[Hospital] Rename hospital'; @IsUUID(4, uuidValidationOptions) public readonly hospitalId!: UUID; @@ -43,14 +44,14 @@ export class RenameHospitalAction implements Action { } export class RemoveHospitalAction implements Action { - @IsString() + @IsValue('[Hospital] Remove hospital' as const) public readonly type = '[Hospital] Remove hospital'; @IsUUID(4, uuidValidationOptions) public readonly hospitalId!: UUID; } export class TransportPatientToHospitalAction implements Action { - @IsString() + @IsValue('[Hospital] Transport patient to hospital' as const) public readonly type = '[Hospital] Transport patient to hospital'; @IsUUID(4, uuidValidationOptions) public readonly hospitalId!: UUID; @@ -73,11 +74,7 @@ export namespace HospitalActionReducers { { action: EditTransportDurationToHospitalAction, reducer: (draftState, { hospitalId, transportDuration }) => { - const hospital = getElement( - draftState, - 'hospitals', - hospitalId - ); + const hospital = getElement(draftState, 'hospital', hospitalId); hospital.transportDuration = transportDuration; return draftState; }, @@ -87,7 +84,7 @@ export namespace HospitalActionReducers { export const renameHospital: ActionReducer = { action: RenameHospitalAction, reducer: (draftState, { hospitalId, name }) => { - const hospital = getElement(draftState, 'hospitals', hospitalId); + const hospital = getElement(draftState, 'hospital', hospitalId); hospital.name = name; return draftState; }, @@ -97,7 +94,7 @@ export namespace HospitalActionReducers { export const removeHospital: ActionReducer = { action: RemoveHospitalAction, reducer: (draftState, { hospitalId }) => { - const hospital = getElement(draftState, 'hospitals', hospitalId); + const hospital = getElement(draftState, 'hospital', hospitalId); // TODO: maybe make a hospital undeletable (if at least one patient is in it) for (const patientId of Object.keys(hospital.patientIds)) { delete draftState.hospitalPatients[patientId]; @@ -117,17 +114,13 @@ export namespace HospitalActionReducers { { action: TransportPatientToHospitalAction, reducer: (draftState, { hospitalId, vehicleId }) => { - const hospital = getElement( - draftState, - 'hospitals', - hospitalId - ); - const vehicle = getElement(draftState, 'vehicles', vehicleId); + const hospital = getElement(draftState, 'hospital', hospitalId); + const vehicle = getElement(draftState, 'vehicle', vehicleId); // TODO: Block vehicles whose material and personnel are unloaded for (const patientId of Object.keys(vehicle.patientIds)) { const patient = getElement( draftState, - 'patients', + 'patient', patientId ); draftState.hospitalPatients[patientId] = diff --git a/shared/src/store/action-reducers/index.ts b/shared/src/store/action-reducers/index.ts index 1d868cd03..229134134 100644 --- a/shared/src/store/action-reducers/index.ts +++ b/shared/src/store/action-reducers/index.ts @@ -5,6 +5,7 @@ export * from './patient'; export * from './personnel'; export * from './vehicle'; export * from './viewport'; +export * from './map-images'; export * from './action-reducers'; // Don't forget to register the actionReducer in `action-reducers.ts` diff --git a/shared/src/store/action-reducers/map-image-templates.ts b/shared/src/store/action-reducers/map-image-templates.ts index 537172d72..d771cac2e 100644 --- a/shared/src/store/action-reducers/map-image-templates.ts +++ b/shared/src/store/action-reducers/map-image-templates.ts @@ -5,11 +5,12 @@ import { ImageProperties } from '../../models/utils'; import type { ExerciseState } from '../../state'; import type { Mutable } from '../../utils'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; export class AddMapImageTemplateAction implements Action { - @IsString() + @IsValue('[MapImageTemplate] Add mapImageTemplate' as const) public readonly type = '[MapImageTemplate] Add mapImageTemplate'; @ValidateNested() @@ -18,7 +19,7 @@ export class AddMapImageTemplateAction implements Action { } export class EditMapImageTemplateAction implements Action { - @IsString() + @IsValue('[MapImageTemplate] Edit mapImageTemplate' as const) public readonly type = '[MapImageTemplate] Edit mapImageTemplate'; @IsUUID(4, uuidValidationOptions) @@ -33,7 +34,7 @@ export class EditMapImageTemplateAction implements Action { } export class DeleteMapImageTemplateAction implements Action { - @IsString() + @IsValue('[MapImageTemplate] Delete mapImageTemplate' as const) public readonly type = '[MapImageTemplate] Delete mapImageTemplate'; @IsUUID(4, uuidValidationOptions) diff --git a/shared/src/store/action-reducers/map-images.ts b/shared/src/store/action-reducers/map-images.ts index f18af2372..d564fbaad 100644 --- a/shared/src/store/action-reducers/map-images.ts +++ b/shared/src/store/action-reducers/map-images.ts @@ -9,7 +9,8 @@ import { ValidateNested, } from 'class-validator'; import { MapImage } from '../../models'; -import { Position } from '../../models/utils'; +import { MapPosition, MapCoordinates } from '../../models/utils'; +import { changePosition } from '../../models/utils/position/position-helpers-mutable'; import type { ExerciseState } from '../../state'; import type { Mutable } from '../../utils'; import { @@ -18,11 +19,12 @@ import { UUID, uuidValidationOptions, } from '../../utils'; +import { IsLiteralUnion, IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { getElement } from './utils/get-element'; export class AddMapImageAction implements Action { - @IsString() + @IsValue('[MapImage] Add MapImage' as const) public readonly type = '[MapImage] Add MapImage'; @ValidateNested() @@ -31,19 +33,19 @@ export class AddMapImageAction implements Action { } export class MoveMapImageAction implements Action { - @IsString() + @IsValue('[MapImage] Move MapImage' as const) public readonly type = '[MapImage] Move MapImage'; @IsUUID(4, uuidValidationOptions) public readonly mapImageId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; } export class ScaleMapImageAction implements Action { - @IsString() + @IsValue('[MapImage] Scale MapImage' as const) public readonly type = '[MapImage] Scale MapImage'; @IsUUID(4, uuidValidationOptions) @@ -61,7 +63,7 @@ export class ScaleMapImageAction implements Action { } export class RemoveMapImageAction implements Action { - @IsString() + @IsValue('[MapImage] Remove MapImage' as const) public readonly type = '[MapImage] Remove MapImage'; @IsUUID(4, uuidValidationOptions) @@ -69,7 +71,7 @@ export class RemoveMapImageAction implements Action { } export class SetIsLockedMapImageAction implements Action { - @IsString() + @IsValue('[MapImage] Set isLocked' as const) public readonly type = '[MapImage] Set isLocked'; @IsUUID(4, uuidValidationOptions) @@ -80,32 +82,39 @@ export class SetIsLockedMapImageAction implements Action { } export class ReconfigureMapImageUrlAction implements Action { - @IsString() + @IsValue('[MapImage] Reconfigure Url' as const) public readonly type = '[MapImage] Reconfigure Url'; @IsUUID(4, uuidValidationOptions) public readonly mapImageId!: UUID; /** - * data URI or URL of new image + * Data URI or URL of new image */ @IsString() public readonly newUrl!: string; } +type ChangeZIndexActionMode = + | 'bringToBack' + | 'bringToFront' + | 'oneLayerBack' + | 'oneLayerForward'; + export class ChangeZIndexMapImageAction implements Action { - @IsString() + @IsValue('[MapImage] Change zIndex' as const) public readonly type = '[MapImage] Change zIndex'; @IsUUID(4, uuidValidationOptions) public readonly mapImageId!: UUID; - @IsString() - public readonly mode!: - | 'bringToBack' - | 'bringToFront' - | 'oneLayerBack' - | 'oneLayerForward'; + @IsLiteralUnion({ + bringToBack: true, + bringToFront: true, + oneLayerBack: true, + oneLayerForward: true, + }) + public readonly mode!: ChangeZIndexActionMode; } export namespace MapImagesActionReducers { @@ -125,8 +134,12 @@ export namespace MapImagesActionReducers { export const moveMapImage: ActionReducer = { action: MoveMapImageAction, reducer: (draftState, { mapImageId, targetPosition }) => { - const mapImage = getElement(draftState, 'mapImages', mapImageId); - mapImage.position = cloneDeepMutable(targetPosition); + const mapImage = getElement(draftState, 'mapImage', mapImageId); + changePosition( + mapImage, + MapPosition.create(targetPosition), + draftState + ); return draftState; }, rights: 'trainer', @@ -135,7 +148,7 @@ export namespace MapImagesActionReducers { export const scaleMapImage: ActionReducer = { action: ScaleMapImageAction, reducer: (draftState, { mapImageId, newHeight, newAspectRatio }) => { - const mapImage = getElement(draftState, 'mapImages', mapImageId); + const mapImage = getElement(draftState, 'mapImage', mapImageId); if (newHeight) { mapImage.image.height = newHeight; } @@ -150,7 +163,7 @@ export namespace MapImagesActionReducers { export const removeMapImage: ActionReducer = { action: RemoveMapImageAction, reducer: (draftState, { mapImageId }) => { - getElement(draftState, 'mapImages', mapImageId); + getElement(draftState, 'mapImage', mapImageId); delete draftState.mapImages[mapImageId]; return draftState; }, @@ -161,11 +174,7 @@ export namespace MapImagesActionReducers { { action: ReconfigureMapImageUrlAction, reducer: (draftState, { mapImageId, newUrl }) => { - const mapImage = getElement( - draftState, - 'mapImages', - mapImageId - ); + const mapImage = getElement(draftState, 'mapImage', mapImageId); mapImage.image.url = newUrl; return draftState; }, @@ -175,7 +184,7 @@ export namespace MapImagesActionReducers { export const setLockedMapImage: ActionReducer = { action: SetIsLockedMapImageAction, reducer: (draftState, { mapImageId, newLocked }) => { - const mapImage = getElement(draftState, 'mapImages', mapImageId); + const mapImage = getElement(draftState, 'mapImage', mapImageId); mapImage.isLocked = newLocked; return draftState; }, @@ -185,7 +194,7 @@ export namespace MapImagesActionReducers { export const changeZIndex: ActionReducer = { action: ChangeZIndexMapImageAction, reducer: (draftState, { mapImageId, mode }) => { - const mapImage = getElement(draftState, 'mapImages', mapImageId); + const mapImage = getElement(draftState, 'mapImage', mapImageId); switch (mode) { case 'bringToFront': case 'bringToBack': { diff --git a/shared/src/store/action-reducers/material.ts b/shared/src/store/action-reducers/material.ts index de5192175..681107209 100644 --- a/shared/src/store/action-reducers/material.ts +++ b/shared/src/store/action-reducers/material.ts @@ -1,31 +1,32 @@ import { Type } from 'class-transformer'; -import { IsString, IsUUID, ValidateNested } from 'class-validator'; -import { Position } from '../../models/utils'; +import { IsUUID, ValidateNested } from 'class-validator'; +import { MapPosition, MapCoordinates } from '../../models/utils'; +import { changePositionWithId } from '../../models/utils/position/position-helpers-mutable'; import { UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; -import { updateElementPosition } from './utils/spatial-elements'; export class MoveMaterialAction implements Action { - @IsString() + @IsValue('[Material] Move material' as const) public readonly type = '[Material] Move material'; @IsUUID(4, uuidValidationOptions) public readonly materialId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; } export namespace MaterialActionReducers { export const moveMaterial: ActionReducer = { action: MoveMaterialAction, reducer: (draftState, { materialId, targetPosition }) => { - updateElementPosition( - draftState, - 'materials', + changePositionWithId( materialId, - targetPosition + MapPosition.create(targetPosition), + 'material', + draftState ); return draftState; }, diff --git a/shared/src/store/action-reducers/patient.ts b/shared/src/store/action-reducers/patient.ts index f2e63736a..e8df777d5 100644 --- a/shared/src/store/action-reducers/patient.ts +++ b/shared/src/store/action-reducers/patient.ts @@ -1,7 +1,17 @@ import { Type } from 'class-transformer'; import { IsString, IsUUID, MaxLength, ValidateNested } from 'class-validator'; import { Patient } from '../../models'; -import { PatientStatus, Position } from '../../models/utils'; +import { + isOnMap, + MapPosition, + PatientStatus, + patientStatusAllowedValues, + MapCoordinates, +} from '../../models/utils'; +import { + changePosition, + changePositionWithId, +} from '../../models/utils/position/position-helpers-mutable'; import type { ExerciseState } from '../../state'; import type { Mutable } from '../../utils'; import { @@ -10,26 +20,23 @@ import { UUID, uuidValidationOptions, } from '../../utils'; +import { IsLiteralUnion, IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; import { updateTreatments } from './utils/calculate-treatments'; import { getElement } from './utils/get-element'; -import { - addElementPosition, - removeElementPosition, - updateElementPosition, -} from './utils/spatial-elements'; +import { removeElementPosition } from './utils/spatial-elements'; export function deletePatient( draftState: Mutable, patientId: UUID ) { - removeElementPosition(draftState, 'patients', patientId); + removeElementPosition(draftState, 'patient', patientId); delete draftState.patients[patientId]; } export class AddPatientAction implements Action { - @IsString() + @IsValue('[Patient] Add patient' as const) public readonly type = '[Patient] Add patient'; @ValidateNested() @Type(() => Patient) @@ -37,37 +44,37 @@ export class AddPatientAction implements Action { } export class MovePatientAction implements Action { - @IsString() + @IsValue('[Patient] Move patient' as const) public readonly type = '[Patient] Move patient'; @IsUUID(4, uuidValidationOptions) public readonly patientId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; } export class RemovePatientAction implements Action { - @IsString() + @IsValue('[Patient] Remove patient' as const) public readonly type = '[Patient] Remove patient'; @IsUUID(4, uuidValidationOptions) public readonly patientId!: UUID; } export class SetVisibleStatusAction implements Action { - @IsString() + @IsValue('[Patient] Set Visible Status' as const) public readonly type = '[Patient] Set Visible Status'; @IsUUID(4, uuidValidationOptions) public readonly patientId!: UUID; - @IsString() + @IsLiteralUnion(patientStatusAllowedValues) public readonly patientStatus!: PatientStatus; } export class SetUserTextAction implements Action { - @IsString() + @IsValue('[Patient] Set Remarks' as const) public readonly type = '[Patient] Set Remarks'; @IsUUID(4, uuidValidationOptions) @@ -115,7 +122,7 @@ export namespace PatientActionReducers { } const mutablePatient = cloneDeepMutable(patient); draftState.patients[mutablePatient.id] = mutablePatient; - addElementPosition(draftState, 'patients', mutablePatient.id); + changePosition(mutablePatient, patient.position, draftState); return draftState; }, rights: 'trainer', @@ -124,11 +131,11 @@ export namespace PatientActionReducers { export const movePatient: ActionReducer = { action: MovePatientAction, reducer: (draftState, { patientId, targetPosition }) => { - updateElementPosition( - draftState, - 'patients', + changePositionWithId( patientId, - targetPosition + MapPosition.create(targetPosition), + 'patient', + draftState ); return draftState; }, @@ -147,10 +154,10 @@ export namespace PatientActionReducers { export const setVisibleStatus: ActionReducer = { action: SetVisibleStatusAction, reducer: (draftState, { patientId, patientStatus }) => { - const patient = getElement(draftState, 'patients', patientId); + const patient = getElement(draftState, 'patient', patientId); patient.pretriageStatus = patientStatus; - if (patient.position !== undefined) { + if (isOnMap(patient)) { updateTreatments(draftState, patient); } @@ -162,7 +169,7 @@ export namespace PatientActionReducers { export const setUserTextAction: ActionReducer = { action: SetUserTextAction, reducer: (draftState, { patientId, remarks }) => { - const patient = getElement(draftState, 'patients', patientId); + const patient = getElement(draftState, 'patient', patientId); patient.remarks = remarks; return draftState; }, diff --git a/shared/src/store/action-reducers/personnel.ts b/shared/src/store/action-reducers/personnel.ts index 89cdeaae9..0078da337 100644 --- a/shared/src/store/action-reducers/personnel.ts +++ b/shared/src/store/action-reducers/personnel.ts @@ -1,31 +1,32 @@ import { Type } from 'class-transformer'; -import { IsString, IsUUID, ValidateNested } from 'class-validator'; -import { Position } from '../../models/utils'; +import { IsUUID, ValidateNested } from 'class-validator'; +import { MapPosition, MapCoordinates } from '../../models/utils'; +import { changePositionWithId } from '../../models/utils/position/position-helpers-mutable'; import { UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; -import { updateElementPosition } from './utils/spatial-elements'; export class MovePersonnelAction implements Action { - @IsString() + @IsValue('[Personnel] Move personnel' as const) public readonly type = '[Personnel] Move personnel'; @IsUUID(4, uuidValidationOptions) public readonly personnelId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; } export namespace PersonnelActionReducers { export const movePersonnel: ActionReducer = { action: MovePersonnelAction, reducer: (draftState, { personnelId, targetPosition }) => { - updateElementPosition( - draftState, - 'personnel', + changePositionWithId( personnelId, - targetPosition + MapPosition.create(targetPosition), + 'personnel', + draftState ); return draftState; }, diff --git a/shared/src/store/action-reducers/simulated-region.ts b/shared/src/store/action-reducers/simulated-region.ts new file mode 100644 index 000000000..4199e4ade --- /dev/null +++ b/shared/src/store/action-reducers/simulated-region.ts @@ -0,0 +1,237 @@ +import { Type } from 'class-transformer'; +import { IsString, IsUUID, ValidateNested } from 'class-validator'; +import { SimulatedRegion } from '../../models'; +import { + MapCoordinates, + MapPosition, + SimulatedRegionPosition, + Size, +} from '../../models/utils'; +import { + changePosition, + changePositionWithId, +} from '../../models/utils/position/position-helpers-mutable'; +import { + ExerciseSimulationBehaviorState, + sendSimulationEvent, + simulationBehaviorTypeOptions, + VehicleArrivedEvent, +} from '../../simulation'; +import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; +import { IsLiteralUnion, IsValue } from '../../utils/validators'; +import type { Action, ActionReducer } from '../action-reducer'; +import { getElement } from './utils/get-element'; + +export class AddSimulatedRegionAction implements Action { + @IsValue('[SimulatedRegion] Add simulated region' as const) + readonly type = '[SimulatedRegion] Add simulated region'; + @ValidateNested() + @Type(() => SimulatedRegion) + public simulatedRegion!: SimulatedRegion; +} + +export class RemoveSimulatedRegionAction implements Action { + @IsValue('[SimulatedRegion] Remove simulated region' as const) + public readonly type = '[SimulatedRegion] Remove simulated region'; + @IsUUID(4, uuidValidationOptions) + public readonly simulatedRegionId!: UUID; +} + +export class MoveSimulatedRegionAction implements Action { + @IsValue('[SimulatedRegion] Move simulated region' as const) + public readonly type = '[SimulatedRegion] Move simulated region'; + @IsUUID(4, uuidValidationOptions) + public readonly simulatedRegionId!: UUID; + @ValidateNested() + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; +} + +export class ResizeSimulatedRegionAction implements Action { + @IsValue('[SimulatedRegion] Resize simulated region' as const) + public readonly type = '[SimulatedRegion] Resize simulated region'; + @IsUUID(4, uuidValidationOptions) + public readonly simulatedRegionId!: UUID; + @ValidateNested() + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; + @ValidateNested() + @Type(() => Size) + public readonly newSize!: Size; +} + +export class RenameSimulatedRegionAction implements Action { + @IsValue('[SimulatedRegion] Rename simulatedRegion' as const) + public readonly type = '[SimulatedRegion] Rename simulatedRegion'; + + @IsUUID(4, uuidValidationOptions) + public readonly simulatedRegionId!: UUID; + + @IsString() + public readonly newName!: string; +} + +export class AddElementToSimulatedRegionAction implements Action { + @IsValue('[SimulatedRegion] Add Element' as const) + public readonly type = '[SimulatedRegion] Add Element'; + + @IsUUID(4, uuidValidationOptions) + public readonly simulatedRegionId!: UUID; + + @IsLiteralUnion({ + material: true, + patient: true, + personnel: true, + vehicle: true, + }) + public readonly elementToBeAddedType!: + | 'material' + | 'patient' + | 'personnel' + | 'vehicle'; + + @IsUUID(4, uuidValidationOptions) + public readonly elementToBeAddedId!: UUID; +} + +export class AddBehaviorToSimulatedRegionAction implements Action { + @IsValue('[SimulatedRegion] Add Behavior' as const) + public readonly type = '[SimulatedRegion] Add Behavior'; + + @IsUUID(4, uuidValidationOptions) + public readonly simulatedRegionId!: UUID; + + @Type(...simulationBehaviorTypeOptions) + @ValidateNested() + public readonly behaviorState!: ExerciseSimulationBehaviorState; +} + +export namespace SimulatedRegionActionReducers { + export const addSimulatedRegion: ActionReducer = { + action: AddSimulatedRegionAction, + reducer: (draftState, { simulatedRegion }) => { + draftState.simulatedRegions[simulatedRegion.id] = + cloneDeepMutable(simulatedRegion); + return draftState; + }, + rights: 'trainer', + }; + + export const removeSimulatedRegion: ActionReducer = + { + action: RemoveSimulatedRegionAction, + reducer: (draftState, { simulatedRegionId }) => { + getElement(draftState, 'simulatedRegion', simulatedRegionId); + delete draftState.simulatedRegions[simulatedRegionId]; + return draftState; + }, + rights: 'trainer', + }; + + export const moveSimulatedRegion: ActionReducer = + { + action: MoveSimulatedRegionAction, + reducer: (draftState, { simulatedRegionId, targetPosition }) => { + changePositionWithId( + simulatedRegionId, + MapPosition.create(targetPosition), + 'simulatedRegion', + draftState + ); + return draftState; + }, + rights: 'trainer', + }; + + export const resizeSimulatedRegion: ActionReducer = + { + action: ResizeSimulatedRegionAction, + reducer: ( + draftState, + { simulatedRegionId, targetPosition, newSize } + ) => { + const simulatedRegion = getElement( + draftState, + 'simulatedRegion', + simulatedRegionId + ); + changePosition( + simulatedRegion, + MapPosition.create(targetPosition), + draftState + ); + simulatedRegion.size = cloneDeepMutable(newSize); + return draftState; + }, + rights: 'trainer', + }; + + export const renameSimulatedRegion: ActionReducer = + { + action: RenameSimulatedRegionAction, + reducer: (draftState, { simulatedRegionId, newName }) => { + const simulatedRegion = getElement( + draftState, + 'simulatedRegion', + simulatedRegionId + ); + simulatedRegion.name = newName; + return draftState; + }, + rights: 'trainer', + }; + + export const addElementToSimulatedRegion: ActionReducer = + { + action: AddElementToSimulatedRegionAction, + reducer: ( + draftState, + { simulatedRegionId, elementToBeAddedId, elementToBeAddedType } + ) => { + const simulatedRegion = getElement( + draftState, + 'simulatedRegion', + simulatedRegionId + ); + const element = getElement( + draftState, + elementToBeAddedType, + elementToBeAddedId + ); + + changePosition( + element, + SimulatedRegionPosition.create(simulatedRegionId), + draftState + ); + + if (element.type === 'vehicle') { + sendSimulationEvent( + simulatedRegion, + VehicleArrivedEvent.create( + element.id, + draftState.currentTime + ) + ); + } + + return draftState; + }, + rights: 'participant', + }; + + export const addBehaviorToSimulatedRegion: ActionReducer = + { + action: AddBehaviorToSimulatedRegionAction, + reducer: (draftState, { simulatedRegionId, behaviorState }) => { + const simulatedRegion = getElement( + draftState, + 'simulatedRegion', + simulatedRegionId + ); + simulatedRegion.behaviors.push(cloneDeepMutable(behaviorState)); + return draftState; + }, + rights: 'participant', + }; +} diff --git a/shared/src/store/action-reducers/transfer-point.ts b/shared/src/store/action-reducers/transfer-point.ts index 51fe81602..2e2abf06d 100644 --- a/shared/src/store/action-reducers/transfer-point.ts +++ b/shared/src/store/action-reducers/transfer-point.ts @@ -7,8 +7,16 @@ import { ValidateNested, } from 'class-validator'; import { TransferPoint } from '../../models'; -import { Position } from '../../models/utils'; -import { uuidValidationOptions, UUID, cloneDeepMutable } from '../../utils'; +import { + currentCoordinatesOf, + isInTransfer, + MapCoordinates, + MapPosition, + currentTransferOf, +} from '../../models/utils'; +import { changePositionWithId } from '../../models/utils/position/position-helpers-mutable'; +import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; import { letElementArrive } from './transfer'; @@ -18,7 +26,7 @@ import { getElement } from './utils/get-element'; // TODO check: type "TransferPoint" the T is big, in other files, the second word starts with a small letter export class AddTransferPointAction implements Action { - @IsString() + @IsValue('[TransferPoint] Add TransferPoint' as const) public readonly type = `[TransferPoint] Add TransferPoint`; @ValidateNested() @Type(() => TransferPoint) @@ -26,19 +34,19 @@ export class AddTransferPointAction implements Action { } export class MoveTransferPointAction implements Action { - @IsString() + @IsValue('[TransferPoint] Move TransferPoint' as const) public readonly type = '[TransferPoint] Move TransferPoint'; @IsUUID(4, uuidValidationOptions) public readonly transferPointId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; } export class RenameTransferPointAction implements Action { - @IsString() + @IsValue('[TransferPoint] Rename TransferPoint' as const) public readonly type = '[TransferPoint] Rename TransferPoint'; @IsUUID(4, uuidValidationOptions) @@ -54,7 +62,7 @@ export class RenameTransferPointAction implements Action { } export class RemoveTransferPointAction implements Action { - @IsString() + @IsValue('[TransferPoint] Remove TransferPoint' as const) public readonly type = '[TransferPoint] Remove TransferPoint'; @IsUUID(4, uuidValidationOptions) @@ -62,7 +70,7 @@ export class RemoveTransferPointAction implements Action { } export class ConnectTransferPointsAction implements Action { - @IsString() + @IsValue('[TransferPoint] Connect TransferPoints' as const) public readonly type = '[TransferPoint] Connect TransferPoints'; @IsUUID(4, uuidValidationOptions) @@ -77,7 +85,7 @@ export class ConnectTransferPointsAction implements Action { } export class DisconnectTransferPointsAction implements Action { - @IsString() + @IsValue('[TransferPoint] Disconnect TransferPoints' as const) public readonly type = '[TransferPoint] Disconnect TransferPoints'; @IsUUID(4, uuidValidationOptions) @@ -88,7 +96,7 @@ export class DisconnectTransferPointsAction implements Action { } export class ConnectHospitalAction implements Action { - @IsString() + @IsValue('[TransferPoint] Connect hospital' as const) public readonly type = '[TransferPoint] Connect hospital'; @IsUUID(4, uuidValidationOptions) public readonly hospitalId!: UUID; @@ -98,7 +106,7 @@ export class ConnectHospitalAction implements Action { } export class DisconnectHospitalAction implements Action { - @IsString() + @IsValue('[TransferPoint] Disconnect hospital' as const) public readonly type = '[TransferPoint] Disconnect hospital'; @IsUUID(4, uuidValidationOptions) public readonly hospitalId!: UUID; @@ -121,12 +129,12 @@ export namespace TransferPointActionReducers { export const moveTransferPoint: ActionReducer = { action: MoveTransferPointAction, reducer: (draftState, { transferPointId, targetPosition }) => { - const transferPoint = getElement( - draftState, - 'transferPoints', - transferPointId + changePositionWithId( + transferPointId, + MapPosition.create(targetPosition), + 'transferPoint', + draftState ); - transferPoint.position = cloneDeepMutable(targetPosition); return draftState; }, rights: 'trainer', @@ -141,7 +149,7 @@ export namespace TransferPointActionReducers { ) => { const transferPoint = getElement( draftState, - 'transferPoints', + 'transferPoint', transferPointId ); // Empty strings are ignored @@ -172,19 +180,19 @@ export namespace TransferPointActionReducers { } const transferPoint1 = getElement( draftState, - 'transferPoints', + 'transferPoint', transferPointId1 ); const transferPoint2 = getElement( draftState, - 'transferPoints', + 'transferPoint', transferPointId2 ); const _duration = duration ?? estimateDuration( - transferPoint1.position, - transferPoint2.position + currentCoordinatesOf(transferPoint1), + currentCoordinatesOf(transferPoint2) ); transferPoint1.reachableTransferPoints[transferPointId2] = { duration: _duration, @@ -209,12 +217,12 @@ export namespace TransferPointActionReducers { } const transferPoint1 = getElement( draftState, - 'transferPoints', + 'transferPoint', transferPointId1 ); const transferPoint2 = getElement( draftState, - 'transferPoints', + 'transferPoint', transferPointId2 ); delete transferPoint1.reachableTransferPoints[transferPointId2]; @@ -229,20 +237,21 @@ export namespace TransferPointActionReducers { action: RemoveTransferPointAction, reducer: (draftState, { transferPointId }) => { // check if transferPoint exists - getElement(draftState, 'transferPoints', transferPointId); + getElement(draftState, 'transferPoint', transferPointId); // TODO: make it dynamic (if at any time something else is able to transfer this part needs to be changed accordingly) // Let all vehicles and personnel arrive that are on transfer to this transferPoint before deleting it for (const vehicleId of Object.keys(draftState.vehicles)) { const vehicle = getElement( draftState, - 'vehicles', + 'vehicle', vehicleId ); if ( - vehicle.transfer?.targetTransferPointId === - transferPointId + isInTransfer(vehicle) && + currentTransferOf(vehicle).targetTransferPointId === + transferPointId ) { - letElementArrive(draftState, 'vehicles', vehicleId); + letElementArrive(draftState, vehicle.type, vehicleId); } } for (const personnelId of Object.keys(draftState.personnel)) { @@ -252,10 +261,15 @@ export namespace TransferPointActionReducers { personnelId ); if ( - personnel.transfer?.targetTransferPointId === - transferPointId + isInTransfer(personnel) && + currentTransferOf(personnel).targetTransferPointId === + transferPointId ) { - letElementArrive(draftState, 'personnel', personnelId); + letElementArrive( + draftState, + personnel.type, + personnelId + ); } } // TODO: If we can assume that the transfer points are always connected to each other, @@ -285,10 +299,10 @@ export namespace TransferPointActionReducers { action: ConnectHospitalAction, reducer: (draftState, { transferPointId, hospitalId }) => { // Check if hospital with this Id exists - getElement(draftState, 'hospitals', hospitalId); + getElement(draftState, 'hospital', hospitalId); const transferPoint = getElement( draftState, - 'transferPoints', + 'transferPoint', transferPointId ); transferPoint.reachableHospitals[hospitalId] = true; @@ -301,10 +315,10 @@ export namespace TransferPointActionReducers { action: DisconnectHospitalAction, reducer: (draftState, { hospitalId, transferPointId }) => { // Check if hospital with this Id exists - getElement(draftState, 'hospitals', hospitalId); + getElement(draftState, 'hospital', hospitalId); const transferPoint = getElement( draftState, - 'transferPoints', + 'transferPoint', transferPointId ); delete transferPoint.reachableHospitals[hospitalId]; @@ -321,7 +335,10 @@ export namespace TransferPointActionReducers { * @returns an estimated duration in ms to drive between the the two given positions * The resulting value is a multiple of 0.1 minutes. */ -function estimateDuration(startPosition: Position, targetPosition: Position) { +function estimateDuration( + startPosition: MapCoordinates, + targetPosition: MapCoordinates +) { // TODO: tweak these values more // How long in ms it takes to start + stop moving const overheadSummand = 10 * 1000; diff --git a/shared/src/store/action-reducers/transfer.ts b/shared/src/store/action-reducers/transfer.ts index ad5362962..c124beabd 100644 --- a/shared/src/store/action-reducers/transfer.ts +++ b/shared/src/store/action-reducers/transfer.ts @@ -1,16 +1,31 @@ -import { IsInt, IsObject, IsOptional, IsString, IsUUID } from 'class-validator'; -import type { ExerciseState, Position } from '../..'; -import { imageSizeToPosition, TransferPoint } from '../..'; -import { StartPoint } from '../../models/utils/start-points'; +import { Type } from 'class-transformer'; +import { IsInt, IsOptional, IsUUID, ValidateNested } from 'class-validator'; +import { TransferPoint } from '../../models'; +import type { MapCoordinates } from '../../models/utils'; +import { + isInTransfer, + isNotInTransfer, + currentTransferOf, + TransferPosition, + currentCoordinatesOf, + MapPosition, + StartPoint, + startPointTypeOptions, +} from '../../models/utils'; +import { changePosition } from '../../models/utils/position/position-helpers-mutable'; +import type { ExerciseState } from '../../state'; +import { imageSizeToPosition } from '../../state-helpers'; import type { Mutable } from '../../utils'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; +import type { AllowedValues } from '../../utils/validators'; +import { IsLiteralUnion, IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; -import { getElement } from './utils/get-element'; -import { - removeElementPosition, - updateElementPosition, -} from './utils/spatial-elements'; +import { getElement } from './utils'; + +export type TransferableElementType = 'personnel' | 'vehicle'; +const transferableElementTypeAllowedValues: AllowedValues = + { personnel: true, vehicle: true }; /** * Personnel/Vehicle in transfer will arrive immediately at new targetTransferPoint @@ -19,45 +34,41 @@ import { */ export function letElementArrive( draftState: Mutable, - elementType: 'personnel' | 'vehicles', + elementType: TransferableElementType, elementId: UUID ) { const element = getElement(draftState, elementType, elementId); // check that element is in transfer, this should be always the case where this function is used - if (!element.transfer) { + if (isNotInTransfer(element)) { throw getNotInTransferError(element.id); } const targetTransferPoint = getElement( draftState, - 'transferPoints', - element.transfer.targetTransferPointId + 'transferPoint', + currentTransferOf(element).targetTransferPointId ); - const newPosition: Mutable = { - x: targetTransferPoint.position.x, + const newPosition: Mutable = { + x: currentCoordinatesOf(targetTransferPoint).x, y: - targetTransferPoint.position.y + + currentCoordinatesOf(targetTransferPoint).y + // Position it in the upper half of the transferPoint imageSizeToPosition(TransferPoint.image.height / 3), }; - if (elementType === 'personnel') { - updateElementPosition(draftState, 'personnel', element.id, newPosition); - } else { - element.position = newPosition; - } - delete element.transfer; + changePosition(element, MapPosition.create(newPosition), draftState); } export class AddToTransferAction implements Action { - @IsString() + @IsValue('[Transfer] Add to transfer' as const) public readonly type = '[Transfer] Add to transfer'; - @IsString() - elementType!: 'personnel' | 'vehicles'; + @IsLiteralUnion(transferableElementTypeAllowedValues) + elementType!: TransferableElementType; @IsUUID(4, uuidValidationOptions) public readonly elementId!: UUID; - @IsObject() + @ValidateNested() + @Type(() => Object, startPointTypeOptions) public readonly startPoint!: StartPoint; @IsUUID(4, uuidValidationOptions) @@ -65,11 +76,11 @@ export class AddToTransferAction implements Action { } export class EditTransferAction implements Action { - @IsString() + @IsValue('[Transfer] Edit transfer' as const) public readonly type = '[Transfer] Edit transfer'; - @IsString() - elementType!: 'personnel' | 'vehicles'; + @IsLiteralUnion(transferableElementTypeAllowedValues) + elementType!: TransferableElementType; @IsUUID(4, uuidValidationOptions) public readonly elementId!: UUID; @@ -89,11 +100,11 @@ export class EditTransferAction implements Action { } export class FinishTransferAction implements Action { - @IsString() + @IsValue('[Transfer] Finish transfer' as const) public readonly type = '[Transfer] Finish transfer'; - @IsString() - elementType!: 'personnel' | 'vehicles'; + @IsLiteralUnion(transferableElementTypeAllowedValues) + elementType!: TransferableElementType; @IsUUID(4, uuidValidationOptions) public readonly elementId!: UUID; @@ -103,11 +114,11 @@ export class FinishTransferAction implements Action { } export class TogglePauseTransferAction implements Action { - @IsString() + @IsValue('[Transfer] Toggle pause transfer' as const) public readonly type = '[Transfer] Toggle pause transfer'; - @IsString() - elementType!: 'personnel' | 'vehicles'; + @IsLiteralUnion(transferableElementTypeAllowedValues) + elementType!: TransferableElementType; @IsUUID(4, uuidValidationOptions) public readonly elementId!: UUID; @@ -121,9 +132,10 @@ export namespace TransferActionReducers { { elementType, elementId, startPoint, targetTransferPointId } ) => { // check if transferPoint exists - getElement(draftState, 'transferPoints', targetTransferPointId); + getElement(draftState, 'transferPoint', targetTransferPointId); const element = getElement(draftState, elementType, elementId); - if (element.transfer) { + + if (isInTransfer(element)) { throw new ReducerError( `Element with id ${element.id} is already in transfer` ); @@ -131,10 +143,10 @@ export namespace TransferActionReducers { // Get the duration let duration: number; - if (startPoint.type === 'transferPoint') { + if (startPoint.type === 'transferStartPoint') { const transferStartPoint = getElement( draftState, - 'transferPoints', + 'transferPoint', startPoint.transferPointId ); const connection = @@ -151,20 +163,17 @@ export namespace TransferActionReducers { duration = startPoint.duration; } - // Remove the position of the element - if (elementType === 'personnel') { - removeElementPosition(draftState, 'personnel', element.id); - } else { - element.position = undefined; - } - // Set the element to transfer - element.transfer = { - startPoint: cloneDeepMutable(startPoint), - targetTransferPointId, - endTimeStamp: draftState.currentTime + duration, - isPaused: false, - }; + changePosition( + element, + TransferPosition.create({ + startPoint: cloneDeepMutable(startPoint), + targetTransferPointId, + endTimeStamp: draftState.currentTime + duration, + isPaused: false, + }), + draftState + ); return draftState; }, @@ -178,21 +187,28 @@ export namespace TransferActionReducers { { elementType, elementId, targetTransferPointId, timeToAdd } ) => { const element = getElement(draftState, elementType, elementId); - if (!element.transfer) { + if (isNotInTransfer(element)) { throw getNotInTransferError(element.id); } + const newTransfer = cloneDeepMutable(currentTransferOf(element)); if (targetTransferPointId) { // check if transferPoint exists - getElement(draftState, 'transferPoints', targetTransferPointId); - element.transfer.targetTransferPointId = targetTransferPointId; + + getElement(draftState, 'transferPoint', targetTransferPointId); + newTransfer.targetTransferPointId = targetTransferPointId; } if (timeToAdd) { // The endTimeStamp shouldn't be less then the current time - element.transfer.endTimeStamp = Math.max( + newTransfer.endTimeStamp = Math.max( draftState.currentTime, - element.transfer.endTimeStamp + timeToAdd + newTransfer.endTimeStamp + timeToAdd ); } + changePosition( + element, + TransferPosition.create(newTransfer), + draftState + ); return draftState; }, rights: 'trainer', @@ -205,9 +221,9 @@ export namespace TransferActionReducers { { elementType, elementId, targetTransferPointId } ) => { // check if transferPoint exists - getElement(draftState, 'transferPoints', targetTransferPointId); + getElement(draftState, 'transferPoint', targetTransferPointId); const element = getElement(draftState, elementType, elementId); - if (!element.transfer) { + if (isNotInTransfer(element)) { throw getNotInTransferError(element.id); } letElementArrive(draftState, elementType, elementId); @@ -221,10 +237,18 @@ export namespace TransferActionReducers { action: TogglePauseTransferAction, reducer: (draftState, { elementType, elementId }) => { const element = getElement(draftState, elementType, elementId); - if (!element.transfer) { + if (isNotInTransfer(element)) { throw getNotInTransferError(element.id); } - element.transfer.isPaused = !element.transfer.isPaused; + const newTransfer = cloneDeepMutable( + currentTransferOf(element) + ); + newTransfer.isPaused = !newTransfer.isPaused; + changePosition( + element, + TransferPosition.create(newTransfer), + draftState + ); return draftState; }, rights: 'trainer', diff --git a/shared/src/store/action-reducers/utils/calculate-distance.ts b/shared/src/store/action-reducers/utils/calculate-distance.ts index 66fd06b9b..986f53d8a 100644 --- a/shared/src/store/action-reducers/utils/calculate-distance.ts +++ b/shared/src/store/action-reducers/utils/calculate-distance.ts @@ -1,8 +1,8 @@ -import type { Position } from '../../../models/utils'; +import type { MapCoordinates } from '../../../models/utils'; /** * @returns the distance between the two positions in meters. */ -export function calculateDistance(a: Position, b: Position) { +export function calculateDistance(a: MapCoordinates, b: MapCoordinates) { return Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2); } diff --git a/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts b/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts index 450294a7e..d48852cd7 100644 --- a/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts +++ b/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts @@ -4,9 +4,16 @@ import { defaultMaterialTemplates } from '../../../data/default-state/material-t import { defaultPersonnelTemplates } from '../../../data/default-state/personnel-templates'; import type { Patient } from '../../../models'; import { Material, Personnel } from '../../../models'; -import type { PatientStatus } from '../../../models/utils'; -import { CanCaterFor, Position } from '../../../models/utils'; +import type { Position, PatientStatus } from '../../../models/utils'; +import { + currentCoordinatesOf, + isPositionOnMap, + CanCaterFor, + MapCoordinates, +} from '../../../models/utils'; +import { MapPosition } from '../../../models/utils/position/map-position'; import { SpatialTree } from '../../../models/utils/spatial-tree'; +import { VehiclePosition } from '../../../models/utils/position/vehicle-position'; import { ExerciseState } from '../../../state'; import type { Mutable, UUID } from '../../../utils'; import { cloneDeepMutable, uuid } from '../../../utils'; @@ -20,7 +27,7 @@ interface Catering { * The id of the material or personnel catering */ catererId: UUID; - catererType: 'materials' | 'personnel'; + catererType: 'material' | 'personnel'; /** * All patients treated by {@link catererId} */ @@ -41,11 +48,11 @@ function assertCatering( for (const catering of caterings) { // Update all the patients const patients = catering.patientIds.map((patientId) => - getElement(draftState, 'patients', patientId) + getElement(draftState, 'patient', patientId) ); for (const patient of patients) { patient[ - catering.catererType === 'materials' + catering.catererType === 'material' ? 'assignedMaterialIds' : 'assignedPersonnelIds' ][catering.catererId] = true; @@ -69,29 +76,33 @@ function addPatient( state: Mutable, pretriageStatus: PatientStatus, realStatus: PatientStatus, - position?: Position + position?: MapCoordinates ): Mutable { const patient = cloneDeepMutable(generateDummyPatient()); patient.pretriageStatus = pretriageStatus; patient.realStatus = realStatus; if (position) { - patient.position = cloneDeepMutable(position); + patient.position = { + type: 'coordinates', + coordinates: cloneDeepMutable(position), + }; SpatialTree.addElement( state.spatialTrees.patients, patient.id, - patient.position + position ); } state.patients[patient.id] = patient; return patient; } -function addPersonnel(state: Mutable, position?: Position) { +function addPersonnel(state: Mutable, position: Position) { const personnel = cloneDeepMutable( Personnel.generatePersonnel( defaultPersonnelTemplates.notSan, uuid(), - 'RTW 3/83/1' + 'RTW 3/83/1', + position ) ); personnel.canCaterFor = { @@ -100,24 +111,24 @@ function addPersonnel(state: Mutable, position?: Position) { green: 0, logicalOperator: 'and', }; - if (position) { - personnel.position = cloneDeepMutable(position); + if (isPositionOnMap(position)) { SpatialTree.addElement( state.spatialTrees.personnel, personnel.id, - personnel.position + currentCoordinatesOf(personnel) ); } state.personnel[personnel.id] = personnel; return personnel; } -function addMaterial(state: Mutable, position?: Position) { +function addMaterial(state: Mutable, position: Position) { const material = cloneDeepMutable( Material.generateMaterial( defaultMaterialTemplates.standard, uuid(), - 'RTW 3/83/1' + 'RTW 3/83/1', + position ) ); material.canCaterFor = { @@ -126,12 +137,11 @@ function addMaterial(state: Mutable, position?: Position) { green: 0, logicalOperator: 'and', }; - if (position) { - material.position = cloneDeepMutable(position); + if (isPositionOnMap(position)) { SpatialTree.addElement( state.spatialTrees.materials, material.id, - material.position + currentCoordinatesOf(material) ); } state.materials[material.id] = material; @@ -170,7 +180,7 @@ describe('calculate treatment', () => { it('does nothing when there is only personnel in vehicle', () => { const { beforeState, newState } = setupStateAndApplyTreatments( (state) => { - addPersonnel(state); + addPersonnel(state, VehiclePosition.create('')); } ); expect(newState).toStrictEqual(beforeState); @@ -179,7 +189,7 @@ describe('calculate treatment', () => { it('does nothing when there is only personnel outside vehicle', () => { const { beforeState, newState } = setupStateAndApplyTreatments( (state) => { - addPersonnel(state, Position.create(0, 0)); + addPersonnel(state, VehiclePosition.create('')); } ); expect(newState).toStrictEqual(beforeState); @@ -188,7 +198,7 @@ describe('calculate treatment', () => { it('does nothing when there is only material in vehicle', () => { const { beforeState, newState } = setupStateAndApplyTreatments( (state) => { - addMaterial(state); + addMaterial(state, MapPosition.create({ x: 0, y: 0 })); } ); expect(newState).toStrictEqual(beforeState); @@ -197,7 +207,7 @@ describe('calculate treatment', () => { it('does nothing when there is only material outside vehicle', () => { const { beforeState, newState } = setupStateAndApplyTreatments( (state) => { - addMaterial(state, Position.create(0, 0)); + addMaterial(state, MapPosition.create({ x: 0, y: 0 })); } ); expect(newState).toStrictEqual(beforeState); @@ -208,7 +218,12 @@ describe('calculate treatment', () => { (state) => { (['green', 'yellow', 'red'] as PatientStatus[]).forEach( (color) => { - addPatient(state, color, color, Position.create(0, 0)); + addPatient( + state, + color, + color, + MapCoordinates.create(0, 0) + ); } ); } @@ -219,7 +234,12 @@ describe('calculate treatment', () => { it('does nothing when there are only dead patients', () => { const { beforeState, newState } = setupStateAndApplyTreatments( (state) => { - addPatient(state, 'black', 'black', Position.create(0, 0)); + addPatient( + state, + 'black', + 'black', + MapCoordinates.create(0, 0) + ); } ); expect(newState).toStrictEqual(beforeState); @@ -228,8 +248,13 @@ describe('calculate treatment', () => { it('does nothing when all personnel is in a vehicle', () => { const { beforeState, newState } = setupStateAndApplyTreatments( (state) => { - addPatient(state, 'green', 'green', Position.create(0, 0)); - addPersonnel(state); + addPatient( + state, + 'green', + 'green', + MapCoordinates.create(0, 0) + ); + addPersonnel(state, VehiclePosition.create('')); } ); expect(newState).toStrictEqual(beforeState); @@ -238,8 +263,13 @@ describe('calculate treatment', () => { it('does nothing when all material is in a vehicle', () => { const { beforeState, newState } = setupStateAndApplyTreatments( (state) => { - addPatient(state, 'green', 'green', Position.create(0, 0)); - addMaterial(state); + addPatient( + state, + 'green', + 'green', + MapCoordinates.create(0, 0) + ); + addMaterial(state, VehiclePosition.create('')); } ); expect(newState).toStrictEqual(beforeState); @@ -257,21 +287,24 @@ describe('calculate treatment', () => { state, 'green', 'green', - Position.create(0, 0) + MapCoordinates.create(0, 0) ).id; ids.redPatient = addPatient( state, 'red', 'red', - Position.create(2, 2) + MapCoordinates.create(2, 2) + ).id; + ids.material = addMaterial( + state, + MapPosition.create({ x: 0, y: 0 }) ).id; - ids.material = addMaterial(state, Position.create(0, 0)).id; } ); assertCatering(beforeState, newState, [ { catererId: ids.material, - catererType: 'materials', + catererType: 'material', patientIds: [ids.greenPatient], }, ]); @@ -289,22 +322,24 @@ describe('calculate treatment', () => { state, 'green', 'green', - Position.create(-3, -3) + MapCoordinates.create(-3, -3) ).id; ids.redPatient = addPatient( state, 'red', 'red', - Position.create(3, 3) + MapCoordinates.create(3, 3) + ).id; + ids.material = addMaterial( + state, + MapPosition.create({ x: 0, y: 0 }) ).id; - ids.material = addMaterial(state, Position.create(0, 0)).id; } ); - console.log(ids); assertCatering(beforeState, newState, [ { catererId: ids.material, - catererType: 'materials', + catererType: 'material', patientIds: [ids.redPatient], }, ]); @@ -322,15 +357,18 @@ describe('calculate treatment', () => { state, 'green', 'green', - Position.create(-10, -10) + MapCoordinates.create(-10, -10) ).id; ids.redPatient = addPatient( state, 'red', 'red', - Position.create(20, 20) + MapCoordinates.create(20, 20) + ).id; + ids.material = addMaterial( + state, + MapPosition.create({ x: 0, y: 0 }) ).id; - ids.material = addMaterial(state, Position.create(0, 0)).id; } ); assertCatering(beforeState, newState, []); @@ -348,15 +386,18 @@ describe('calculate treatment', () => { state, 'green', 'green', - Position.create(-1, -1) + MapCoordinates.create(-1, -1) ).id; ids.redPatient = addPatient( state, 'red', 'red', - Position.create(2, 2) + MapCoordinates.create(2, 2) ).id; - const material = addMaterial(state, Position.create(0, 0)); + const material = addMaterial( + state, + MapPosition.create({ x: 0, y: 0 }) + ); material.canCaterFor = cloneDeepMutable( CanCaterFor.create(1, 0, 1, 'and') ); @@ -366,7 +407,7 @@ describe('calculate treatment', () => { assertCatering(beforeState, newState, [ { catererId: ids.material, - catererType: 'materials', + catererType: 'material', patientIds: [ids.redPatient, ids.greenPatient], }, ]); diff --git a/shared/src/store/action-reducers/utils/calculate-treatments.ts b/shared/src/store/action-reducers/utils/calculate-treatments.ts index fbc9fd9d7..a1d9fa16a 100644 --- a/shared/src/store/action-reducers/utils/calculate-treatments.ts +++ b/shared/src/store/action-reducers/utils/calculate-treatments.ts @@ -1,11 +1,17 @@ import { groupBy } from 'lodash-es'; import type { Material, Personnel } from '../../../models'; import { Patient } from '../../../models'; -import type { PatientStatus, Position } from '../../../models/utils'; +import type { MapCoordinates, PatientStatus } from '../../../models/utils'; +import { + currentCoordinatesOf, + isNotOnMap, + isInSimulatedRegion, +} from '../../../models/utils'; import { SpatialTree } from '../../../models/utils/spatial-tree'; import type { ExerciseState } from '../../../state'; import { maxTreatmentRange } from '../../../state-helpers/max-treatment-range'; import type { Mutable, UUID } from '../../../utils'; +import { elementTypePluralMap } from '../../../utils/element-type-plural-map'; import { getElement } from './get-element'; // TODO: `caterFor` and `treat` are currently used as synonyms without a clear distinction. @@ -82,7 +88,7 @@ function tryToCaterFor( cateringElement.assignedPatientIds[patient.id] = true; - if (isPersonnel(cateringElement)) { + if (cateringElement.type === 'personnel') { patient.assignedPersonnelIds[cateringElement.id] = true; } else { patient.assignedMaterialIds[cateringElement.id] = true; @@ -92,38 +98,18 @@ function tryToCaterFor( return true; } -// TODO: Instead, give each Element a "type" property -> discriminated union -function isPatient( - element: Mutable -): element is Mutable { - return (element as Patient).personalInformation !== undefined; -} - -function isPersonnel( - element: Mutable -): element is Mutable { - return (element as Personnel).personnelType !== undefined; -} - -function isMaterial( - element: Mutable -): element is Mutable { - // as Material does not include any distinguishable properties, we will check if it is not of type Personnel or Patient - return !isPersonnel(element) && !isPatient(element); -} - /** * @param position of the patient where all elements of {@link elementType} should be recalculated * @param elementIdsToBeSkipped the elements whose treatment should not be updated */ function updateCateringAroundPatient( state: Mutable, - position: Position, - elementType: 'materials' | 'personnel', + position: MapCoordinates, + elementType: 'material' | 'personnel', elementIdsToBeSkipped: Set ) { const elementsInTreatmentRange = SpatialTree.findAllElementsInCircle( - state.spatialTrees[elementType], + state.spatialTrees[elementTypePluralMap[elementType]], position, maxTreatmentRange ).filter((elementId) => !elementIdsToBeSkipped.has(elementId)); @@ -133,14 +119,11 @@ function updateCateringAroundPatient( } } -function removeTreatmentsOfElement( +export function removeTreatmentsOfElement( state: Mutable, element: Mutable ) { - // TODO: when elements have their own type saved don't use const patient = getElement(state, 'patients', element.id); - // instead use const patient = element; - // same for personnel and material in the other if statements - if (isPatient(element)) { + if (element.type === 'patient') { const patient = element; // Make all personnel stop treating this patient for (const personnelId of Object.keys(patient.assignedPersonnelIds)) { @@ -150,23 +133,23 @@ function removeTreatmentsOfElement( patient.assignedPersonnelIds = {}; // Make all material stop treating this patient for (const materialId of Object.keys(patient.assignedMaterialIds)) { - const material = getElement(state, 'materials', materialId); + const material = getElement(state, 'material', materialId); delete material.assignedPatientIds[patient.id]; } patient.assignedMaterialIds = {}; - } else if (isPersonnel(element)) { + } else if (element.type === 'personnel') { const personnel = element; // This personnel doesn't treat any patients anymore for (const patientId of Object.keys(personnel.assignedPatientIds)) { - const patient = getElement(state, 'patients', patientId); + const patient = getElement(state, 'patient', patientId); delete patient.assignedPersonnelIds[personnel.id]; } personnel.assignedPatientIds = {}; - } else if (isMaterial(element)) { + } else if (element.type === 'material') { const material = element; // This material doesn't treat any patients anymore for (const patientId of Object.keys(material.assignedPatientIds)) { - const patient = getElement(state, 'patients', patientId); + const patient = getElement(state, 'patient', patientId); delete patient.assignedMaterialIds[material.id]; } material.assignedPatientIds = {}; @@ -188,13 +171,16 @@ export function updateTreatments( // Currently, the treatment pattern algorithm is stable. This means that completely done from scratch, // the result would semantically be the same. This could be changed later. - if (element.position === undefined) { - // The element is no longer in a position (get it?!) to be treated or treat a patient + if (isInSimulatedRegion(element)) { + return; + } + + if (isNotOnMap(element)) { removeTreatmentsOfElement(state, element); return; } - if (isPersonnel(element) || isMaterial(element)) { + if (element.type === 'personnel' || element.type === 'material') { updateCatering(state, element); return; } @@ -208,21 +194,21 @@ export function updateTreatments( alreadyUpdatedElementIds.add(personnelId); } for (const materialId of Object.keys(element.assignedMaterialIds)) { - updateCatering(state, getElement(state, 'materials', materialId)); + updateCatering(state, getElement(state, 'material', materialId)); // Saving materialIds of material that already got calculated - makes small movements of patients more efficient alreadyUpdatedElementIds.add(materialId); } updateCateringAroundPatient( state, - element.position, + currentCoordinatesOf(element), 'personnel', alreadyUpdatedElementIds ); updateCateringAroundPatient( state, - element.position, - 'materials', + currentCoordinatesOf(element), + 'material', alreadyUpdatedElementIds ); // The treatment of the patient has just been updated -> hence the visible status hasn't been changed since the last update @@ -243,8 +229,8 @@ function updateCatering( (cateringElement.canCaterFor.red === 0 && cateringElement.canCaterFor.yellow === 0 && cateringElement.canCaterFor.green === 0) || - // The element is no longer in a position to treat a patient - cateringElement.position === undefined + // The element is no longer in a position to treat a patient on the map + isNotOnMap(cateringElement) ) { return; } @@ -262,7 +248,7 @@ function updateCatering( if (cateringElement.overrideTreatmentRange > 0) { const patientIdsInOverrideRange = SpatialTree.findAllElementsInCircle( state.spatialTrees.patients, - cateringElement.position, + currentCoordinatesOf(cateringElement), cateringElement.overrideTreatmentRange ); // In the overrideTreatmentRange (the override circle) only the distance to the patient is important - his/her injuries are ignored @@ -270,7 +256,7 @@ function updateCatering( tryToCaterFor( cateringElement, catersFor, - getElement(state, 'patients', patientId), + getElement(state, 'patient', patientId), state.configuration.pretriageEnabled, state.configuration.bluePatientsEnabled ); @@ -291,12 +277,12 @@ function updateCatering( const patientsInTreatmentRange: Mutable[] = SpatialTree.findAllElementsInCircle( state.spatialTrees.patients, - cateringElement.position, + currentCoordinatesOf(cateringElement), cateringElement.treatmentRange ) // Filter out every patient in the overrideTreatmentRange .filter((patientId) => !cateredForPatients.has(patientId)) - .map((patientId) => getElement(state, 'patients', patientId)); + .map((patientId) => getElement(state, 'patient', patientId)); const patientsPerStatus = groupBy(patientsInTreatmentRange, (patient) => getCateringStatus( diff --git a/shared/src/store/action-reducers/utils/get-element.ts b/shared/src/store/action-reducers/utils/get-element.ts index bda9e3776..653f6087c 100644 --- a/shared/src/store/action-reducers/utils/get-element.ts +++ b/shared/src/store/action-reducers/utils/get-element.ts @@ -1,5 +1,7 @@ import type { ExerciseState } from '../../../state'; import type { Mutable, UUID } from '../../../utils'; +import type { ElementTypePluralMap } from '../../../utils/element-type-plural-map'; +import { elementTypePluralMap } from '../../../utils/element-type-plural-map'; import { ReducerError } from '../../reducer-error'; /** @@ -7,24 +9,16 @@ import { ReducerError } from '../../reducer-error'; * @throws ReducerError if the element does not exist */ export function getElement< - ElementType extends - | 'alarmGroups' - | 'clients' - | 'hospitals' - | 'mapImages' - | 'materials' - | 'patients' - | 'personnel' - | 'transferPoints' - | 'vehicles' - | 'viewports', + ElementType extends keyof ElementTypePluralMap, State extends ExerciseState | Mutable >( state: State, elementType: ElementType, elementId: UUID -): State[ElementType][UUID] { - const element = state[elementType][elementId] as State[ElementType][UUID]; +): State[ElementTypePluralMap[ElementType]][UUID] { + const element = state[elementTypePluralMap[elementType]][ + elementId + ] as State[ElementTypePluralMap[ElementType]][UUID]; if (!element) { throw new ReducerError( `Element of type ${elementType} with id ${elementId} does not exist` diff --git a/shared/src/store/action-reducers/utils/spatial-elements.ts b/shared/src/store/action-reducers/utils/spatial-elements.ts index 49e84c6da..1a1e897f9 100644 --- a/shared/src/store/action-reducers/utils/spatial-elements.ts +++ b/shared/src/store/action-reducers/utils/spatial-elements.ts @@ -1,9 +1,16 @@ -import type { Position } from '../../../models/utils'; +import type { MapCoordinates } from '../../../models/utils'; +import { + isOnMap, + isNotOnMap, + currentCoordinatesOf, +} from '../../../models/utils'; import { SpatialTree } from '../../../models/utils/spatial-tree'; import type { ExerciseState } from '../../../state'; import type { Mutable, UUID } from '../../../utils'; import { cloneDeepMutable } from '../../../utils'; -import { updateTreatments } from './calculate-treatments'; +import type { ElementTypePluralMap } from '../../../utils/element-type-plural-map'; +import { elementTypePluralMap } from '../../../utils/element-type-plural-map'; +import { removeTreatmentsOfElement } from './calculate-treatments'; import { getElement } from './get-element'; /** @@ -11,7 +18,9 @@ import { getElement } from './get-element'; * The position of the element must be changed via one of the function in this file. * In addition, the respective functions must be called when an element gets added or removed. */ -export type SpatialElementType = 'materials' | 'patients' | 'personnel'; +export type SpatialElementType = 'material' | 'patient' | 'personnel'; +type SpatialTypePluralMap = Pick; +export type SpatialElementPlural = SpatialTypePluralMap[SpatialElementType]; /** * Adds an element with a position and executes side effects to guarantee the consistency of the state. @@ -23,15 +32,14 @@ export function addElementPosition( elementId: UUID ) { const element = getElement(state, elementType, elementId); - if (element.position === undefined) { + if (isNotOnMap(element)) { return; } SpatialTree.addElement( - state.spatialTrees[elementType], + state.spatialTrees[elementTypePluralMap[elementType]], element.id, - element.position + currentCoordinatesOf(element) ); - updateTreatments(state, element); } /** @@ -41,26 +49,24 @@ export function updateElementPosition( state: Mutable, elementType: SpatialElementType, elementId: UUID, - targetPosition: Position + targetPosition: MapCoordinates ) { const element = getElement(state, elementType, elementId); - const startPosition = element.position; - if (startPosition !== undefined) { + if (isOnMap(element)) { + const startPosition = cloneDeepMutable(currentCoordinatesOf(element)); SpatialTree.moveElement( - state.spatialTrees[elementType], + state.spatialTrees[elementTypePluralMap[elementType]], element.id, startPosition, targetPosition ); } else { SpatialTree.addElement( - state.spatialTrees[elementType], + state.spatialTrees[elementTypePluralMap[elementType]], element.id, targetPosition ); } - element.position = cloneDeepMutable(targetPosition); - updateTreatments(state, element); } /** @@ -73,14 +79,13 @@ export function removeElementPosition( elementId: UUID ) { const element = getElement(state, elementType, elementId); - if (element.position === undefined) { + removeTreatmentsOfElement(state, element); + if (isNotOnMap(element)) { return; } SpatialTree.removeElement( - state.spatialTrees[elementType], + state.spatialTrees[elementTypePluralMap[elementType]], element.id, - element.position + cloneDeepMutable(currentCoordinatesOf(element)) ); - element.position = undefined; - updateTreatments(state, element); } diff --git a/shared/src/store/action-reducers/vehicle.ts b/shared/src/store/action-reducers/vehicle.ts index 6f4d2a433..6716c9326 100644 --- a/shared/src/store/action-reducers/vehicle.ts +++ b/shared/src/store/action-reducers/vehicle.ts @@ -1,7 +1,20 @@ import { Type } from 'class-transformer'; import { IsArray, IsString, IsUUID, ValidateNested } from 'class-validator'; import { Material, Personnel, Vehicle } from '../../models'; -import { Position } from '../../models/utils'; +import { + currentCoordinatesOf, + isInTransfer, + isInVehicle, + isNotInTransfer, + isNotOnMap, + MapCoordinates, + MapPosition, + VehiclePosition, +} from '../../models/utils'; +import { + changePosition, + changePositionWithId, +} from '../../models/utils/position/position-helpers-mutable'; import type { ExerciseState } from '../../state'; import { imageSizeToPosition } from '../../state-helpers'; import type { Mutable } from '../../utils'; @@ -11,24 +24,21 @@ import { UUID, uuidValidationOptions, } from '../../utils'; +import { IsLiteralUnion, IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; import { deletePatient } from './patient'; import { getElement } from './utils/get-element'; -import { - addElementPosition, - removeElementPosition, - updateElementPosition, -} from './utils/spatial-elements'; +import { removeElementPosition } from './utils/spatial-elements'; export function deleteVehicle( draftState: Mutable, vehicleId: UUID ) { - const vehicle = getElement(draftState, 'vehicles', vehicleId); + const vehicle = getElement(draftState, 'vehicle', vehicleId); // Delete related material and personnel Object.keys(vehicle.materialIds).forEach((materialId) => { - removeElementPosition(draftState, 'materials', materialId); + removeElementPosition(draftState, 'material', materialId); delete draftState.materials[materialId]; }); Object.keys(vehicle.personnelIds).forEach((personnelId) => { @@ -43,7 +53,7 @@ export function deleteVehicle( } export class AddVehicleAction implements Action { - @IsString() + @IsValue('[Vehicle] Add vehicle' as const) public readonly type = '[Vehicle] Add vehicle'; @ValidateNested() @Type(() => Vehicle) @@ -61,7 +71,7 @@ export class AddVehicleAction implements Action { } export class RenameVehicleAction implements Action { - @IsString() + @IsValue('[Vehicle] Rename vehicle' as const) public readonly type = '[Vehicle] Rename vehicle'; @IsUUID(4, uuidValidationOptions) public readonly vehicleId!: UUID; @@ -71,42 +81,46 @@ export class RenameVehicleAction implements Action { } export class MoveVehicleAction implements Action { - @IsString() + @IsValue('[Vehicle] Move vehicle' as const) public readonly type = '[Vehicle] Move vehicle'; @IsUUID(4, uuidValidationOptions) public readonly vehicleId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; } export class RemoveVehicleAction implements Action { - @IsString() + @IsValue('[Vehicle] Remove vehicle' as const) public readonly type = '[Vehicle] Remove vehicle'; @IsUUID(4, uuidValidationOptions) public readonly vehicleId!: UUID; } export class UnloadVehicleAction implements Action { - @IsString() + @IsValue('[Vehicle] Unload vehicle' as const) public readonly type = '[Vehicle] Unload vehicle'; @IsUUID(4, uuidValidationOptions) public readonly vehicleId!: UUID; } export class LoadVehicleAction implements Action { - @IsString() + @IsValue('[Vehicle] Load vehicle' as const) public readonly type = '[Vehicle] Load vehicle'; @IsUUID(4, uuidValidationOptions) public readonly vehicleId!: UUID; - @IsString() + @IsLiteralUnion({ + material: true, + patient: true, + personnel: true, + }) public readonly elementToBeLoadedType!: - | 'materials' - | 'patients' + | 'material' + | 'patient' | 'personnel'; @IsUUID(4, uuidValidationOptions) @@ -145,12 +159,20 @@ export namespace VehicleActionReducers { } draftState.vehicles[vehicle.id] = cloneDeepMutable(vehicle); for (const material of cloneDeepMutable(materials)) { + changePosition( + material, + VehiclePosition.create(vehicle.id), + draftState + ); draftState.materials[material.id] = material; - addElementPosition(draftState, 'materials', material.id); } for (const person of cloneDeepMutable(personnel)) { + changePosition( + person, + VehiclePosition.create(vehicle.id), + draftState + ); draftState.personnel[person.id] = person; - addElementPosition(draftState, 'personnel', person.id); } return draftState; }, @@ -160,8 +182,12 @@ export namespace VehicleActionReducers { export const moveVehicle: ActionReducer = { action: MoveVehicleAction, reducer: (draftState, { vehicleId, targetPosition }) => { - const vehicle = getElement(draftState, 'vehicles', vehicleId); - vehicle.position = cloneDeepMutable(targetPosition); + changePositionWithId( + vehicleId, + MapPosition.create(targetPosition), + 'vehicle', + draftState + ); return draftState; }, rights: 'participant', @@ -170,7 +196,7 @@ export namespace VehicleActionReducers { export const renameVehicle: ActionReducer = { action: RenameVehicleAction, reducer: (draftState, { vehicleId, name }) => { - const vehicle = getElement(draftState, 'vehicles', vehicleId); + const vehicle = getElement(draftState, 'vehicle', vehicleId); vehicle.name = name; for (const personnelId of Object.keys(vehicle.personnelIds)) { draftState.personnel[personnelId]!.vehicleName = name; @@ -195,13 +221,13 @@ export namespace VehicleActionReducers { export const unloadVehicle: ActionReducer = { action: UnloadVehicleAction, reducer: (draftState, { vehicleId }) => { - const vehicle = getElement(draftState, 'vehicles', vehicleId); - const unloadPosition = vehicle.position; - if (!unloadPosition) { + const vehicle = getElement(draftState, 'vehicle', vehicleId); + if (isNotOnMap(vehicle)) { throw new ReducerError( - `Vehicle with id ${vehicleId} is currently in transfer` + `Vehicle with id ${vehicleId} is currently not on the map` ); } + const unloadPosition = currentCoordinatesOf(vehicle); const materialIds = Object.keys(vehicle.materialIds); const personnelIds = Object.keys(vehicle.personnelIds); const patientIds = Object.keys(vehicle.patientIds); @@ -221,10 +247,14 @@ export namespace VehicleActionReducers { for (const patientId of patientIds) { x += space; - updateElementPosition(draftState, 'patients', patientId, { - x, - y: unloadPosition.y, - }); + changePositionWithId( + patientId, + MapPosition.create( + MapCoordinates.create(x, unloadPosition.y) + ), + 'patient', + draftState + ); delete vehicle.patientIds[patientId]; } @@ -235,31 +265,29 @@ export namespace VehicleActionReducers { 'personnel', personnelId ); - if (Personnel.isInVehicle(personnel)) { - updateElementPosition( - draftState, - 'personnel', + if (isInVehicle(personnel)) { + changePositionWithId( personnelId, - { - x, - y: unloadPosition.y, - } + MapPosition.create( + MapCoordinates.create(x, unloadPosition.y) + ), + 'personnel', + draftState ); } } for (const materialId of materialIds) { x += space; - const material = getElement( - draftState, - 'materials', - materialId - ); - if (Material.isInVehicle(material)) { - updateElementPosition(draftState, 'materials', materialId, { - x, - y: unloadPosition.y, - }); + const material = getElement(draftState, 'material', materialId); + if (isInVehicle(material)) { + changePosition( + material, + MapPosition.create( + MapCoordinates.create(x, unloadPosition.y) + ), + draftState + ); } } @@ -274,12 +302,12 @@ export namespace VehicleActionReducers { draftState, { vehicleId, elementToBeLoadedId, elementToBeLoadedType } ) => { - const vehicle = getElement(draftState, 'vehicles', vehicleId); + const vehicle = getElement(draftState, 'vehicle', vehicleId); switch (elementToBeLoadedType) { - case 'materials': { + case 'material': { const material = getElement( draftState, - 'materials', + 'material', elementToBeLoadedId ); if (!vehicle.materialIds[elementToBeLoadedId]) { @@ -287,7 +315,11 @@ export namespace VehicleActionReducers { `Material with id ${material.id} is not assignable to the vehicle with id ${vehicle.id}` ); } - removeElementPosition(draftState, 'materials', material.id); + changePosition( + material, + VehiclePosition.create(vehicleId), + draftState + ); break; } case 'personnel': { @@ -296,7 +328,7 @@ export namespace VehicleActionReducers { 'personnel', elementToBeLoadedId ); - if (personnel.transfer !== undefined) { + if (isInTransfer(personnel)) { throw new ReducerError( `Personnel with id ${elementToBeLoadedId} is currently in transfer` ); @@ -306,17 +338,17 @@ export namespace VehicleActionReducers { `Personnel with id ${personnel.id} is not assignable to the vehicle with id ${vehicle.id}` ); } - removeElementPosition( - draftState, - 'personnel', - personnel.id + changePosition( + personnel, + VehiclePosition.create(vehicleId), + draftState ); break; } - case 'patients': { + case 'patient': { const patient = getElement( draftState, - 'patients', + 'patient', elementToBeLoadedId ); if ( @@ -328,15 +360,17 @@ export namespace VehicleActionReducers { ); } vehicle.patientIds[elementToBeLoadedId] = true; - - removeElementPosition(draftState, 'patients', patient.id); - + changePosition( + patient, + VehiclePosition.create(vehicleId), + draftState + ); // Load in all materials Object.keys(vehicle.materialIds).forEach((materialId) => { - removeElementPosition( - draftState, - 'materials', - materialId + changePosition( + getElement(draftState, 'material', materialId), + VehiclePosition.create(vehicleId), + draftState ); }); @@ -345,14 +379,23 @@ export namespace VehicleActionReducers { .filter( // Skip personnel currently in transfer (personnelId) => - getElement(draftState, 'personnel', personnelId) - .transfer === undefined + isNotInTransfer( + getElement( + draftState, + 'personnel', + personnelId + ) + ) ) .forEach((personnelId) => { - removeElementPosition( - draftState, - 'personnel', - personnelId + changePosition( + getElement( + draftState, + 'personnel', + personnelId + ), + VehiclePosition.create(vehicleId), + draftState ); }); } diff --git a/shared/src/store/action-reducers/viewport.ts b/shared/src/store/action-reducers/viewport.ts index 98a5e07a2..3719ab8a1 100644 --- a/shared/src/store/action-reducers/viewport.ts +++ b/shared/src/store/action-reducers/viewport.ts @@ -1,13 +1,18 @@ import { Type } from 'class-transformer'; import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { Viewport } from '../../models'; -import { Position, Size } from '../../models/utils'; -import { uuidValidationOptions, UUID, cloneDeepMutable } from '../../utils'; +import { MapCoordinates, MapPosition, Size } from '../../models/utils'; +import { + changePosition, + changePositionWithId, +} from '../../models/utils/position/position-helpers-mutable'; +import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { getElement } from './utils/get-element'; export class AddViewportAction implements Action { - @IsString() + @IsValue('[Viewport] Add viewport' as const) readonly type = '[Viewport] Add viewport'; @ValidateNested() @Type(() => Viewport) @@ -15,37 +20,37 @@ export class AddViewportAction implements Action { } export class RemoveViewportAction implements Action { - @IsString() + @IsValue('[Viewport] Remove viewport' as const) public readonly type = '[Viewport] Remove viewport'; @IsUUID(4, uuidValidationOptions) public readonly viewportId!: UUID; } export class MoveViewportAction implements Action { - @IsString() + @IsValue('[Viewport] Move viewport' as const) public readonly type = '[Viewport] Move viewport'; @IsUUID(4, uuidValidationOptions) public readonly viewportId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; } export class ResizeViewportAction implements Action { - @IsString() + @IsValue('[Viewport] Resize viewport' as const) public readonly type = '[Viewport] Resize viewport'; @IsUUID(4, uuidValidationOptions) public readonly viewportId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; @ValidateNested() @Type(() => Size) public readonly newSize!: Size; } export class RenameViewportAction implements Action { - @IsString() + @IsValue('[Viewport] Rename viewport' as const) public readonly type = '[Viewport] Rename viewport'; @IsUUID(4, uuidValidationOptions) @@ -68,7 +73,7 @@ export namespace ViewportActionReducers { export const removeViewport: ActionReducer = { action: RemoveViewportAction, reducer: (draftState, { viewportId }) => { - getElement(draftState, 'viewports', viewportId); + getElement(draftState, 'viewport', viewportId); delete draftState.viewports[viewportId]; return draftState; }, @@ -78,8 +83,12 @@ export namespace ViewportActionReducers { export const moveViewport: ActionReducer = { action: MoveViewportAction, reducer: (draftState, { viewportId, targetPosition }) => { - const viewport = getElement(draftState, 'viewports', viewportId); - viewport.position = cloneDeepMutable(targetPosition); + changePositionWithId( + viewportId, + MapPosition.create(targetPosition), + 'viewport', + draftState + ); return draftState; }, rights: 'trainer', @@ -88,8 +97,12 @@ export namespace ViewportActionReducers { export const resizeViewport: ActionReducer = { action: ResizeViewportAction, reducer: (draftState, { viewportId, targetPosition, newSize }) => { - const viewport = getElement(draftState, 'viewports', viewportId); - viewport.position = cloneDeepMutable(targetPosition); + const viewport = getElement(draftState, 'viewport', viewportId); + changePosition( + viewport, + MapPosition.create(targetPosition), + draftState + ); viewport.size = cloneDeepMutable(newSize); return draftState; }, @@ -99,7 +112,7 @@ export namespace ViewportActionReducers { export const renameViewport: ActionReducer = { action: RenameViewportAction, reducer: (draftState, { viewportId, newName }) => { - const viewport = getElement(draftState, 'viewports', viewportId); + const viewport = getElement(draftState, 'viewport', viewportId); viewport.name = newName; return draftState; }, diff --git a/shared/src/store/reduce-exercise-state.spec.ts b/shared/src/store/reduce-exercise-state.spec.ts index 49afadc2d..317638bcc 100644 --- a/shared/src/store/reduce-exercise-state.spec.ts +++ b/shared/src/store/reduce-exercise-state.spec.ts @@ -1,5 +1,6 @@ import type { Viewport } from '../models'; import type { ExerciseStatus } from '../models/utils'; +import { MapCoordinates, MapPosition } from '../models/utils'; import { ExerciseState } from '../state'; import type { UUID } from '../utils'; import { uuid } from '../utils'; @@ -12,9 +13,10 @@ describe('exerciseReducer', () => { function generateViewport(): Viewport { return { id: uuid(), + type: 'viewport', name: 'Test', size: { width: 100, height: 100 }, - position: { x: 0, y: 0 }, + position: MapPosition.create(MapCoordinates.create(0, 0)), } as const; } diff --git a/shared/src/store/validate-exercise-action.spec.ts b/shared/src/store/validate-exercise-action.spec.ts index 9bc74a97d..f5486b287 100644 --- a/shared/src/store/validate-exercise-action.spec.ts +++ b/shared/src/store/validate-exercise-action.spec.ts @@ -1,5 +1,5 @@ -import type { Position } from '../models/utils'; import { Viewport } from '../models'; +import type { MapCoordinates } from '../models/utils'; import type { ExerciseAction } from './action-reducers'; import { validateExerciseAction } from '.'; @@ -71,15 +71,19 @@ describe('validateExerciseAction', () => { type: '[Viewport] Add viewport', viewport: { id: 'b02c7756-ea52-427f-9fc3-0e163799544d', + type: 'viewport', name: '', size: { height: 1, width: 1, }, position: { - // this is of type string instead of number - x: '0' as unknown as number, - y: 0, + type: 'coordinates', + coordinates: { + // this is of type string instead of number + x: '0' as unknown as number, + y: 0, + }, }, }, }) @@ -112,16 +116,20 @@ describe('validateExerciseAction', () => { type: '[Viewport] Add viewport', viewport: { id: 'b02c7756-ea52-427f-9fc3-0e163799544d', + type: 'viewport', name: '', size: { height: 1, width: 1, }, position: { - x: 0, - y: 0, - z: 0, - } as unknown as Position, + type: 'coordinates', + coordinates: { + x: 0, + y: 0, + z: 0, + } as unknown as MapCoordinates, + }, }, }) ).not.toEqual([]); diff --git a/shared/src/store/validate-exercise-action.ts b/shared/src/store/validate-exercise-action.ts index 1c95dfba4..3c25697ea 100644 --- a/shared/src/store/validate-exercise-action.ts +++ b/shared/src/store/validate-exercise-action.ts @@ -1,7 +1,13 @@ import { plainToInstance } from 'class-transformer'; -import type { ValidationError } from 'class-validator'; +import type { + ValidationArguments, + ValidationError, + ValidationOptions, +} from 'class-validator'; import { validateSync } from 'class-validator'; import type { Constructor } from '../utils'; +import type { GenericPropertyDecorator } from '../utils/validators/generic-property-decorator'; +import { makeValidator } from '../utils/validators/make-validator'; import type { ExerciseAction } from './action-reducers'; import { getExerciseActionTypeDictionary } from './action-reducers'; import { defaultValidateOptions } from './validation-options'; @@ -30,3 +36,21 @@ export function validateExerciseAction( defaultValidateOptions ); } + +// Decorators for validation +// Placed here instead of in utils/validators to prevent circular imports + +export function isExerciseAction(value: unknown): value is ExerciseAction { + return validateExerciseAction(value as ExerciseAction).length === 0; +} + +// eslint-disable-next-line @typescript-eslint/naming-convention +export function IsExerciseAction( + validationOptions?: ValidationOptions & { each?: Each } +): GenericPropertyDecorator { + return makeValidator( + 'isExerciseAction', + (value: unknown, args?: ValidationArguments) => isExerciseAction(value), + validationOptions + ); +} diff --git a/shared/src/store/validate-exercise-export.ts b/shared/src/store/validate-exercise-export.ts index 276d3cc78..747047fa3 100644 --- a/shared/src/store/validate-exercise-export.ts +++ b/shared/src/store/validate-exercise-export.ts @@ -4,7 +4,6 @@ import { validateSync } from 'class-validator'; import type { ExportImportFile } from '../export-import/file-format'; import { PartialExport, StateExport } from '../export-import/file-format'; import type { Constructor } from '../utils'; -import { validateExerciseAction } from './validate-exercise-action'; import { defaultValidateOptions } from './validation-options'; /** @@ -35,12 +34,5 @@ export function validateExerciseExport( ), defaultValidateOptions ); - if (exportImportFile.type === 'complete' && exportImportFile.history) { - validationErrors.push( - ...exportImportFile.history.actionHistory.flatMap((action) => - validateExerciseAction(action) - ) - ); - } return validationErrors; } diff --git a/shared/src/utils/element-type-plural-map.ts b/shared/src/utils/element-type-plural-map.ts new file mode 100644 index 000000000..630dcd7ef --- /dev/null +++ b/shared/src/utils/element-type-plural-map.ts @@ -0,0 +1,21 @@ +// eslint-disable-next-line @typescript-eslint/no-shadow +import type { Element } from '../models/element'; +import type { ExerciseState } from '../state'; + +type ElementType = Element['type']; + +export const elementTypePluralMap = { + alarmGroup: 'alarmGroups', + client: 'clients', + hospital: 'hospitals', + mapImage: 'mapImages', + material: 'materials', + patient: 'patients', + personnel: 'personnel', + simulatedRegion: 'simulatedRegions', + transferPoint: 'transferPoints', + vehicle: 'vehicles', + viewport: 'viewports', +} as const satisfies { [Key in ElementType]: keyof ExerciseState }; + +export type ElementTypePluralMap = typeof elementTypePluralMap; diff --git a/shared/src/utils/index.ts b/shared/src/utils/index.ts index 9a8518c80..6d4505f4e 100644 --- a/shared/src/utils/index.ts +++ b/shared/src/utils/index.ts @@ -9,3 +9,4 @@ export * from './clone-deep'; export * from './strict-object'; export * from './sleep'; export * from './assert-exhaustiveness'; +export * from './sort-object'; diff --git a/shared/src/utils/sort-object.spec.ts b/shared/src/utils/sort-object.spec.ts new file mode 100644 index 000000000..8a00cf8c2 --- /dev/null +++ b/shared/src/utils/sort-object.spec.ts @@ -0,0 +1,55 @@ +import { cloneDeep } from 'lodash-es'; +import { sortObject } from './sort-object'; + +const tests: SortObjectTest[] = [ + { + object: { c: 3, b: 2, a: 1 }, + compareFn: ([keyA, valueA], [keyB, valueB]) => valueA - valueB, + expectedObject: { a: 1, b: 2, c: 3 }, + }, + { + object: { a: 1, b: 2, c: 3 }, + compareFn: ([keyA, valueA], [keyB, valueB]) => valueA - valueB, + expectedObject: { a: 1, b: 2, c: 3 }, + }, + { + object: { c: 3, b: 2, a: 1 }, + compareFn: ([keyA, valueA], [keyB, valueB]) => valueB - valueA, + expectedObject: { c: 3, b: 2, a: 1 }, + }, + { + object: { c: 3, b: 2, a: 1 }, + compareFn: ([keyA, valueA], [keyB, valueB]) => + (keyA as string).localeCompare(keyB as string), + expectedObject: { a: 1, b: 2, c: 3 }, + }, +]; + +describe('sortObject', () => { + it.each(tests)('$# sorts %j', ({ object, compareFn, expectedObject }) => { + const objectToBeSorted = cloneDeep(object); + const sortedObj = sortObject(objectToBeSorted, compareFn); + // The sorted object should be equal to the expected object + expect(JSON.stringify(sortedObj)).toBe(JSON.stringify(expectedObject)); + expect(Object.keys(sortedObj)).toStrictEqual( + Object.keys(expectedObject) + ); + expect(Object.values(sortedObj)).toStrictEqual( + Object.values(expectedObject) + ); + // The original object should not be mutated + expect(JSON.stringify(objectToBeSorted)).toBe(JSON.stringify(object)); + expect(Object.keys(objectToBeSorted)).toStrictEqual( + Object.keys(object) + ); + expect(Object.values(objectToBeSorted)).toStrictEqual( + Object.values(object) + ); + }); +}); + +interface SortObjectTest { + object: T; + compareFn: (a: [keyof T, T[keyof T]], b: [keyof T, T[keyof T]]) => number; + expectedObject: T; +} diff --git a/shared/src/utils/sort-object.ts b/shared/src/utils/sort-object.ts new file mode 100644 index 000000000..cfbce54b9 --- /dev/null +++ b/shared/src/utils/sort-object.ts @@ -0,0 +1,24 @@ +import { StrictObject } from './strict-object'; + +/** + * + * @param obj The object to sort. It will not be mutated. + * @param compareFn Function used to determine the order of the elements. + * It gets the key and value of the elements to compare as arguments. + * It is expected to return a negative value if the first argument is less than the second argument, + * zero if they're equal, and a positive value otherwise. + * @returns A new object with the same keys as obj and the keys and values sorted according to the compareFn. + * + * @example + * ````ts + * const obj = { c: 3, b: 2, a: 1 }; + * const sortedObj = sortObject(obj, ([keyA, valueA], [keyB, valueB]) => valueA - valueB); + * // sortedObj = { a: 1, b: 2, c: 3 } + * ```` + */ +export function sortObject( + obj: T, + compareFn: (a: [keyof T, T[keyof T]], b: [keyof T, T[keyof T]]) => number +): T { + return Object.fromEntries(StrictObject.entries(obj).sort(compareFn)) as T; +} diff --git a/shared/src/utils/validators/combine-decorators.ts b/shared/src/utils/validators/combine-decorators.ts new file mode 100644 index 000000000..d48c1fef8 --- /dev/null +++ b/shared/src/utils/validators/combine-decorators.ts @@ -0,0 +1,37 @@ +import type { GenericPropertyDecorator } from './generic-property-decorator'; + +// Source: https://github.com/nestjs/nest/blob/a448f53b7746d35bf25a18f1759c971e5b7fea1c/packages/common/decorators/core/apply-decorators.ts + +/** + * @param decorators one or more decorators (e.g., `IsString(...)`) + * @returns a new decorator that applies all the provided decorators + * + * Useful to build new decorators (or a decorator factory) encapsulating multiple decorators + */ +export function combineDecorators( + ...decorators: Array< + | ClassDecorator + | GenericPropertyDecorator + | MethodDecorator + | PropertyDecorator + > +) { + // eslint-disable-next-line @typescript-eslint/ban-types + return ( + target: TFunction | object, + propertyKey?: string | symbol, + descriptor?: TypedPropertyDescriptor + ) => { + for (const decorator of decorators) { + if (target instanceof Function && !descriptor) { + (decorator as ClassDecorator)(target); + continue; + } + (decorator as MethodDecorator | PropertyDecorator)( + target, + propertyKey!, + descriptor! + ); + } + }; +} diff --git a/shared/src/utils/validators/create-map-validator.ts b/shared/src/utils/validators/create-map-validator.ts new file mode 100644 index 000000000..7d8716bc6 --- /dev/null +++ b/shared/src/utils/validators/create-map-validator.ts @@ -0,0 +1,38 @@ +export interface MapValidationFunctions { + keyValidator: (key: number | string | symbol) => key is K; + valueValidator: (value: unknown) => value is V; + consistencyValidator?: (key: string, value: unknown) => boolean; +} + +/** + * The provided flow is as follows: + * + * 1. It's checked whether `valueToBeValidated` is of type `object` + * 2. It's checked whether `valueToBeValidated` is not `null` + * 3. For every key-value pair of the object, the following are verified: + * 1. It's checked whether the key fulfills {@link keyValidator} + * 2. It's checked whether the transformed value is valid using {@link valueValidator} + * 3. When {@link consistencyValidator} is provided, it's applied to the key and value + * + * This process is guaranteed to be short-circuiting, so later steps can rely on a successful earlier step. + */ +export function createMapValidator({ + keyValidator, + valueValidator, + consistencyValidator, +}: MapValidationFunctions): ( + valueToBeValidated: unknown +) => valueToBeValidated is { [key in K]: V } { + return ( + valueToBeValidated: unknown + ): valueToBeValidated is { [key in K]: V } => + typeof valueToBeValidated === 'object' && + valueToBeValidated !== null && + Object.entries(valueToBeValidated).every( + ([key, value]: [string, unknown]) => + keyValidator(key) && + valueValidator(value) && + (consistencyValidator === undefined || + consistencyValidator(key, value as V)) + ); +} diff --git a/shared/src/utils/validators/generic-property-decorator.ts b/shared/src/utils/validators/generic-property-decorator.ts new file mode 100644 index 000000000..8ea7ab03f --- /dev/null +++ b/shared/src/utils/validators/generic-property-decorator.ts @@ -0,0 +1,13 @@ +/** + * T The type the decorated property in the class must be. This only works for public properties. + * Each Whether the Decorator is used to validate an array (https://github.com/typestack/class-validator#validating-arrays) + */ +export type GenericPropertyDecorator = < + Target extends { + readonly [key in Key]: Each extends true ? readonly T[] : T; + }, + Key extends string +>( + target: Target, + propertyKey: Key +) => void; diff --git a/shared/src/utils/validators/index.ts b/shared/src/utils/validators/index.ts new file mode 100644 index 000000000..04aec4b96 --- /dev/null +++ b/shared/src/utils/validators/index.ts @@ -0,0 +1,7 @@ +// TODO: Propagate the errors from subobjects + +export * from './is-id-map'; +export * from './is-reachable-transfer-points-object'; +export * from './is-literal-union'; +export * from './is-uuid-set'; +export * from './is-value'; diff --git a/shared/src/utils/validators/is-id-map.ts b/shared/src/utils/validators/is-id-map.ts new file mode 100644 index 000000000..e4fbd5e2c --- /dev/null +++ b/shared/src/utils/validators/is-id-map.ts @@ -0,0 +1,70 @@ +import { plainToInstance, Transform } from 'class-transformer'; +import type { ValidationOptions } from 'class-validator'; +import { isUUID, ValidateNested } from 'class-validator'; +import type { Constructor } from '../constructor'; +import type { UUID } from '../uuid'; +import { combineDecorators } from './combine-decorators'; +import type { GenericPropertyDecorator } from './generic-property-decorator'; + +// An `isIdMap` function is omitted. +// It's currently not used and it's not trivial to migrate the decorator approach below +// to a standalone function. +// For reference, such an implementation once existed as part of https://github.com/hpi-sam/digital-fuesim-manv/pull/125. + +/** + * An `IdMap` is of type `{ readonly [key: UUID]: T }` + * + * @property getId A function to get the id that is used as the key in the object. Defaults to `.id`, this might be wrong for some types, though. + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export function IsIdMap( + type: Constructor, + getId: (value: T) => UUID = (value) => (value as { id: UUID }).id, + validationOptions?: ValidationOptions & { each?: Each } +): GenericPropertyDecorator<{ readonly [key: UUID]: T }, Each> { + return IsMultiTypedIdMap(() => type, getId, validationOptions); +} + +/** + * An `IdMap` is of type `{ readonly [key: UUID]: T }` + * This validates IdMaps that can contain multiple types. + * + * @property getConstructor A function to get the constructor for a given plain object. Return a falsy value if the constructor cannot be determined which is invalid. Usually dispatches on the `.type` property. + * @property getId A function to get the id that is used as the key in the object. Defaults to `.id`, this might be wrong for some types, though. + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export function IsMultiTypedIdMap< + T extends Constructor, + Each extends boolean = false +>( + getConstructor: (value: InstanceType) => T | undefined, + getId: (value: InstanceType) => UUID = (value) => + (value as { id: UUID }).id, + validationOptions?: ValidationOptions & { each?: Each } +): GenericPropertyDecorator<{ readonly [key: UUID]: InstanceType }, Each> { + const transform = Transform( + ({ value }) => { + const plainMap = value as { [key: UUID]: InstanceType }; + if ( + Object.entries(plainMap).some( + ([key, plain]) => !isUUID(key, 4) || key !== getId(plain) + ) + ) { + return 'invalid'; + } + const plainWithConstructor = Object.values(plainMap).map( + (entry) => [entry, getConstructor(entry)] as const + ); + if (plainWithConstructor.some(([_, constr]) => !constr)) { + return 'invalid'; + } + const instances = plainWithConstructor.map(([entry, constr]) => + plainToInstance(constr!, entry) + ); + return instances; + }, + { toClassOnly: true } + ); + const validateNested = ValidateNested({ ...validationOptions, each: true }); + return combineDecorators(transform, validateNested); +} diff --git a/shared/src/utils/validators/is-literal-union.ts b/shared/src/utils/validators/is-literal-union.ts new file mode 100644 index 000000000..5b4455f37 --- /dev/null +++ b/shared/src/utils/validators/is-literal-union.ts @@ -0,0 +1,58 @@ +import type { ValidationOptions, ValidationArguments } from 'class-validator'; +import { isIn } from 'class-validator'; +import type { GenericPropertyDecorator } from './generic-property-decorator'; +import { makeValidator } from './make-validator'; + +/** + * A type for validating unions of string literals. + * + * @example + * ````ts + * type StringLiteralUnion = 'a' | 'b'; + * + * const stringLiteralUnionAllowedValues: AllowedValues = { + * a: true, + * b: true, + * }; + * + * class MyClassToValidate { + * @IsLiteralUnion(stringLiteralUnionAllowedValues) + * public readonly myString: StringLiteralUnion; + * } + * + * ```` + */ +export type AllowedValues = { + [key in T]: true; +}; + +export function isLiteralUnion( + allowedValues: AllowedValues, + valueToBeValidated: unknown +): boolean { + return isIn(valueToBeValidated, Object.keys(allowedValues)); +} + +/** + * A validator to check whether a property is part of a literal union type. + * + * Only literal types that may be keys of objects, i.e. `number`, `string`, and `symbol`, are allowed. + * @param allowedValues {@link AllowedValues} that specify which values may be present. + * @param validationOptions {@link ValidationOptions} passed on to `class-validator`. + * @returns A `class-validator` validator that verifies that the value is in the keys of {@link allowedValues}. + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export function IsLiteralUnion< + T extends number | string | symbol, + Each extends boolean = false +>( + allowedValues: AllowedValues, + validationOptions?: ValidationOptions & { each?: Each } +): GenericPropertyDecorator { + return makeValidator( + 'isLiteralUnion', + (value: unknown, args?: ValidationArguments) => + isLiteralUnion(allowedValues, value), + validationOptions + ); +} diff --git a/shared/src/utils/validators/is-position.ts b/shared/src/utils/validators/is-position.ts new file mode 100644 index 000000000..cf72d7f66 --- /dev/null +++ b/shared/src/utils/validators/is-position.ts @@ -0,0 +1,36 @@ +import { Type } from 'class-transformer'; +import { MapPosition } from '../../models/utils/position/map-position'; +import type { Position } from '../../models/utils/position/position'; +import { SimulatedRegionPosition } from '../../models/utils/position/simulated-region-position'; +import { TransferPosition } from '../../models/utils/position/transfer-position'; +import { VehiclePosition } from '../../models/utils/position/vehicle-position'; +import { IsLiteralUnion } from './is-literal-union'; + +class PositionBase { + @IsLiteralUnion({ + coordinates: true, + simulatedRegion: true, + transfer: true, + vehicle: true, + }) + public type: Position['type']; + + constructor(type: Position['type']) { + this.type = type; + } +} + +// eslint-disable-next-line @typescript-eslint/naming-convention +export const IsPosition = () => + Type(() => PositionBase, { + keepDiscriminatorProperty: true, + discriminator: { + property: 'type', + subTypes: [ + { name: 'coordinates', value: MapPosition }, + { name: 'simulatedRegion', value: SimulatedRegionPosition }, + { name: 'transfer', value: TransferPosition }, + { name: 'vehicle', value: VehiclePosition }, + ], + }, + }); diff --git a/shared/src/utils/validators/is-reachable-transfer-points-object.ts b/shared/src/utils/validators/is-reachable-transfer-points-object.ts new file mode 100644 index 000000000..362390edb --- /dev/null +++ b/shared/src/utils/validators/is-reachable-transfer-points-object.ts @@ -0,0 +1,33 @@ +import type { ValidationOptions, ValidationArguments } from 'class-validator'; +import { isUUID, isNumber, min } from 'class-validator'; +import type { ReachableTransferPoints } from '../../models/transfer-point'; +import type { UUID } from '../uuid'; +import { createMapValidator } from './create-map-validator'; +import type { GenericPropertyDecorator } from './generic-property-decorator'; +import { makeValidator } from './make-validator'; + +export const isReachableTransferPoints = createMapValidator< + UUID, + ReachableTransferPoints +>({ + keyValidator: ((key) => isUUID(key, 4)) as (key: unknown) => key is UUID, + valueValidator: ((value) => + typeof value === 'object' && + value !== null && + isNumber((value as { duration: number }).duration) && + min((value as { duration: number }).duration, 0)) as ( + value: unknown + ) => value is ReachableTransferPoints, +}); + +// eslint-disable-next-line @typescript-eslint/naming-convention +export function IsReachableTransferPoints( + validationOptions?: ValidationOptions & { each?: Each } +): GenericPropertyDecorator { + return makeValidator( + 'isReachableTransferPoints', + (value: unknown, args?: ValidationArguments) => + isReachableTransferPoints(value), + validationOptions + ); +} diff --git a/shared/src/utils/validators/is-uuid-set.ts b/shared/src/utils/validators/is-uuid-set.ts new file mode 100644 index 000000000..8e586a497 --- /dev/null +++ b/shared/src/utils/validators/is-uuid-set.ts @@ -0,0 +1,27 @@ +import type { ValidationOptions, ValidationArguments } from 'class-validator'; +import { isUUID } from 'class-validator'; +import type { UUID } from '../uuid'; +import type { UUIDSet } from '../uuid-set'; +import { createMapValidator } from './create-map-validator'; +import type { GenericPropertyDecorator } from './generic-property-decorator'; +import { makeValidator } from './make-validator'; + +export const isUUIDSet = createMapValidator({ + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + keyValidator: <(key: unknown) => key is UUID>((key) => isUUID(key, 4)), + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + valueValidator: <(value: unknown) => value is true>( + ((value) => value === true) + ), +}); + +// eslint-disable-next-line @typescript-eslint/naming-convention +export function IsUUIDSet( + validationOptions?: ValidationOptions & { each?: Each } +): GenericPropertyDecorator { + return makeValidator( + 'isUUIDSet', + (value: unknown, args?: ValidationArguments) => isUUIDSet(value), + validationOptions + ); +} diff --git a/shared/src/utils/validators/is-value.ts b/shared/src/utils/validators/is-value.ts new file mode 100644 index 000000000..0f6ee8e59 --- /dev/null +++ b/shared/src/utils/validators/is-value.ts @@ -0,0 +1,45 @@ +import type { ValidationOptions, ValidationArguments } from 'class-validator'; +import { isIn } from 'class-validator'; +import type { GenericPropertyDecorator } from './generic-property-decorator'; +import { makeValidator } from './make-validator'; + +/** + * Check whether two values are identical, using {@link isIn} from `class-validator`. + * + * As of `class-validator` version `0.14.0`, this means that the equality check is doen with `===`. + * @param expectedValue The single value that is allowed. + * @param valueToBeValidated The actual value. + * @returns Whether the values are identical. + */ +export function isValue< + T extends bigint | boolean | number | string | symbol | null | undefined +>(expectedValue: T, valueToBeValidated: unknown): boolean { + return isIn(valueToBeValidated, [expectedValue]); +} + +/** + * A validator for a constant value. Uses {@link isIn} for validation, all limitations of this validator apply. + * + * This means that, as of `class-validator` version `0.14.0`, `===` is used for equality checks. + * + * It is highly recommended to use `as const` with this decorator to enable better type checking. + * @param expectedValue The single value that is allowed for this property. + * @param validationOptions {@link ValidationOptions} passed on to `class-validator`. + * @returns A `class-validator` validator that verifies that the value is exactly {@link expectedValue}. + */ +// TODO [typescript@>=5.0]: Use `const T` (https://github.com/microsoft/TypeScript/pull/51865) (and remove doc comment about `as const`) +// eslint-disable-next-line @typescript-eslint/naming-convention +export function IsValue< + T extends bigint | boolean | number | string | symbol | null | undefined, + Each extends boolean = false +>( + expectedValue: T, + validationOptions?: ValidationOptions & { each?: Each } +): GenericPropertyDecorator { + return makeValidator( + 'isValue', + (value: unknown, args?: ValidationArguments) => + isValue(expectedValue, value), + validationOptions + ); +} diff --git a/shared/src/utils/validators/make-validator.ts b/shared/src/utils/validators/make-validator.ts new file mode 100644 index 000000000..2a37f2920 --- /dev/null +++ b/shared/src/utils/validators/make-validator.ts @@ -0,0 +1,31 @@ +import type { ValidationArguments, ValidationOptions } from 'class-validator'; +import { registerDecorator } from 'class-validator'; +import type { GenericPropertyDecorator } from './generic-property-decorator'; + +export function makeValidator( + name: `is${string}`, + validationFunction: ( + value: unknown, + validationArguments?: ValidationArguments + ) => boolean, + validationOptions?: ValidationOptions & { each?: Each } +): GenericPropertyDecorator { + // Disabled as this is the suggested way for [class-validator](https://github.com/typestack/class-validator#custom-validation-decorators) + // eslint-disable-next-line @typescript-eslint/ban-types + return function (object: Object, propertyName: string) { + registerDecorator({ + name, + target: object.constructor, + propertyName, + options: { + message: + validationOptions?.message ?? + `Value must be a correct ${name.slice(2)}`, + ...validationOptions, + }, + validator: { + validate: validationFunction, + }, + }); + }; +}