diff --git a/.circleci/config.yml b/.circleci/config.yml index 0381bff26e3d..5ab0af8fb0cc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,21 +6,24 @@ executors: - image: cimg/node:20.11-browsers resource_class: small environment: - FONTCONFIG_PATH: /etc/fonts NODE_OPTIONS: --max_old_space_size=2048 node-browsers-medium: docker: - image: cimg/node:20.11-browsers resource_class: medium environment: - FONTCONFIG_PATH: /etc/fonts NODE_OPTIONS: --max_old_space_size=3072 + node-linux-medium: + machine: + image: ubuntu-2404:2024.05.1 + resource_class: medium #// linux medium: 2 CPUs, 7.5 GB RAM, 10 credits/min + environment: + NODE_OPTIONS: --max_old_space_size=6144 node-browsers-medium-plus: docker: - image: cimg/node:20.11-browsers resource_class: medium+ environment: - FONTCONFIG_PATH: /etc/fonts NODE_OPTIONS: --max_old_space_size=4096 shellcheck: docker: @@ -28,7 +31,7 @@ executors: resource_class: small playwright: docker: - - image: mcr.microsoft.com/playwright:v1.42.1-focal + - image: mcr.microsoft.com/playwright:v1.44.1-focal resource_class: medium orbs: @@ -42,6 +45,14 @@ rc_branch_only: &rc_branch_only only: - /^Version-v(\d+)[.](\d+)[.](\d+)/ +develop_master_rc_only: &develop_master_rc_only + filters: + branches: + only: + - develop + - master + - /^Version-v(\d+)[.](\d+)[.](\d+)/ + aliases: # Shallow Git Clone - &shallow-git-clone @@ -70,6 +81,18 @@ aliases: git checkout -B "$CIRCLE_BRANCH" "$CIRCLE_SHA1" fi + # Check if MMI Optional tests should run + - &check-mmi-optional + name: Check if MMI Optional tests should run + command: | + RUN_MMI_OPTIONAL=$(cat ./RUN_MMI_OPTIONAL) + if [[ "${RUN_MMI_OPTIONAL}" == "true" ]]; then + echo "Running MMI Optional tests" + else + echo "Skipping MMI Optional tests" + circleci step halt + fi + workflows: test_and_release: jobs: @@ -80,6 +103,7 @@ workflows: - trigger-beta-build: requires: - prep-deps + - check-pr-tag - prep-deps - test-deps-audit: requires: @@ -99,7 +123,7 @@ workflows: - validate-lavamoat-policy-webapp: matrix: parameters: - build-type: [main, beta, flask, mmi, desktop] + build-type: [main, beta, flask, mmi] requires: - prep-deps - prep-build-mmi: @@ -108,33 +132,42 @@ workflows: - prep-build: requires: - prep-deps - - prep-build-desktop: - filters: - branches: - only: develop + - prep-build-mv2: requires: - prep-deps - prep-build-flask: requires: - prep-deps + - prep-build-flask-mv2: + requires: + - prep-deps - prep-build-test: requires: - prep-deps - - prep-build-multichain-test: + - prep-build-test-mv2: + requires: + - prep-deps + - prep-build-confirmation-redesign-test: requires: - prep-deps - - prep-build-test-mv3: + - prep-build-confirmation-redesign-test-mv2: + <<: *develop_master_rc_only requires: - prep-deps - prep-build-test-flask: requires: - prep-deps + - prep-build-test-flask-mv2: + <<: *develop_master_rc_only + requires: + - prep-deps - prep-build-test-mmi: requires: - prep-deps - prep-build-test-mmi-playwright: requires: - prep-deps + - check-pr-tag - prep-build-storybook: requires: - prep-deps @@ -154,15 +187,22 @@ workflows: - test-e2e-chrome: requires: - prep-build-test - - test-e2e-chrome-multichain: + - test-e2e-chrome-confirmation-redesign: requires: - - prep-build-multichain-test + - prep-build-confirmation-redesign-test - test-e2e-firefox: requires: - - prep-build-test + - prep-build-test-mv2 + - test-e2e-firefox-confirmation-redesign: + <<: *develop_master_rc_only + requires: + - prep-build-confirmation-redesign-test-mv2 - test-e2e-chrome-rpc: requires: - prep-build-test + - test-api-specs: + requires: + - prep-build-test - test-e2e-chrome-multiple-providers: requires: - prep-build-test @@ -170,8 +210,9 @@ workflows: requires: - prep-build-test-flask - test-e2e-firefox-flask: + <<: *develop_master_rc_only requires: - - prep-build-test-flask + - prep-build-test-flask-mv2 - test-e2e-chrome-mmi: requires: - prep-build-test-mmi @@ -181,9 +222,6 @@ workflows: - test-e2e-chrome-rpc-mmi: requires: - prep-build-test-mmi - - test-e2e-chrome-mv3: - requires: - - prep-build-test-mv3 - test-e2e-chrome-vault-decryption: filters: branches: @@ -192,20 +230,16 @@ workflows: - /^Version-v(\d+)[.](\d+)[.](\d+)/ requires: - prep-build - - test-unit-mocha: - requires: - - prep-deps - test-unit-jest-main: requires: - prep-deps - test-unit-jest-development: requires: - prep-deps - - upload-and-validate-coverage: + - upload-coverage: requires: - test-unit-jest-main - test-unit-jest-development - - test-unit-mocha - test-unit-global: requires: - prep-deps @@ -216,36 +250,29 @@ workflows: - validate-source-maps: requires: - prep-build + - validate-source-maps-mv2: + requires: + - prep-build-mv2 - validate-source-maps-beta: requires: - trigger-beta-build - - validate-source-maps-desktop: - filters: - branches: - only: develop - requires: - - prep-build-desktop - validate-source-maps-mmi: requires: - prep-build-mmi - validate-source-maps-flask: requires: - prep-build-flask - - test-mozilla-lint: + - validate-source-maps-flask-mv2: requires: - - prep-deps - - prep-build - - test-mozilla-lint-desktop: - filters: - branches: - only: develop + - prep-build-flask-mv2 + - test-mozilla-lint-mv2: requires: - prep-deps - - prep-build-desktop - - test-mozilla-lint-flask: + - prep-build-mv2 + - test-mozilla-lint-flask-mv2: requires: - prep-deps - - prep-build-flask + - prep-build-flask-mv2 - all-tests-pass: requires: - test-deps-depcheck @@ -259,19 +286,17 @@ workflows: - test-unit-jest-main - test-unit-jest-development - test-unit-global - - test-unit-mocha - - upload-and-validate-coverage + - upload-coverage - validate-source-maps - validate-source-maps-beta - - validate-source-maps-desktop - validate-source-maps-flask - validate-source-maps-mmi - - test-mozilla-lint - - test-mozilla-lint-desktop - - test-mozilla-lint-flask + - test-mozilla-lint-mv2 + - test-mozilla-lint-flask-mv2 - test-e2e-chrome - - test-e2e-chrome-multichain - test-e2e-chrome-multiple-providers + - test-e2e-chrome-confirmation-redesign + - test-e2e-firefox-confirmation-redesign - test-e2e-firefox - test-e2e-chrome-flask - test-e2e-firefox-flask @@ -287,18 +312,18 @@ workflows: - prep-build-test - stats-module-load-init: requires: - - prep-build-test-mv3 + - prep-build-test - job-publish-prerelease: requires: - prep-deps - prep-build + - prep-build-mv2 - trigger-beta-build - - prep-build-desktop - prep-build-mmi - prep-build-flask + - prep-build-flask-mv2 - prep-build-storybook - prep-build-ts-migration-dashboard - - prep-build-test-mv3 - benchmark - user-actions-benchmark - stats-module-load-init @@ -310,9 +335,10 @@ workflows: requires: - prep-deps - prep-build - - prep-build-desktop + - prep-build-mv2 - prep-build-mmi - prep-build-flask + - prep-build-flask-mv2 - all-tests-pass - job-publish-storybook: filters: @@ -332,6 +358,7 @@ jobs: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - when: @@ -361,6 +388,7 @@ jobs: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -376,10 +404,44 @@ jobs: name: Create GitHub Pull Request for version command: .circleci/scripts/release-create-release-pr.sh + check-pr-tag: + docker: + - image: cimg/base:stable + steps: + - run: + name: Check for MMI Team Tag + command: | + #!/bin/bash + + GH_LABEL=team-mmi + if [ -z "$CIRCLE_PULL_REQUESTS" ]; then + echo "Skipping tag check; this is not a PR." + echo "false" > ./RUN_MMI_OPTIONAL + exit 0 + fi + + echo $CIRCLE_PULL_REQUESTS | sed 's/,/\n/g' + + # See if any associated PRs have matching label + HAS_MATCHING_PR=$(echo $CIRCLE_PULL_REQUESTS \ + | sed -e 's#,#\n#g' -e 's#/github.com/#/api.github.com/repos/#g' -e 's#/pull/#/pulls/#g' \ + | xargs -n1 curl -s \ + | jq -s "map((.labels|map(select(.name==\"${GH_LABEL}\"))))|flatten|length > 0") + + echo "${GH_LABEL} tag presence: ${HAS_MATCHING_PR}" + + # assign the RUN_MMI_OPTIONAL variable + echo "${HAS_MATCHING_PR}" > ./RUN_MMI_OPTIONAL + - persist_to_workspace: + root: . + paths: + - RUN_MMI_OPTIONAL + prep-deps: executor: node-browsers-medium steps: - run: *shallow-git-clone + - run: sudo corepack enable - run: name: Save Yarn version command: | @@ -414,6 +476,7 @@ jobs: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -427,6 +490,7 @@ jobs: executor: node-browsers-medium steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -443,6 +507,7 @@ jobs: type: string steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -453,9 +518,10 @@ jobs: command: .circleci/scripts/check-working-tree.sh prep-build: - executor: node-browsers-medium-plus + executor: node-linux-medium steps: - run: *shallow-git-clone + - run: corepack enable - attach_workspace: at: . - when: @@ -488,34 +554,54 @@ jobs: - dist - builds - prep-build-desktop: - executor: node-browsers-medium-plus + prep-build-mv2: + executor: node-linux-medium steps: - run: *shallow-git-clone + - run: corepack enable - attach_workspace: at: . - - run: - name: build:dist - command: yarn build --build-type desktop dist + - when: + condition: + not: + matches: + pattern: /^master$/ + value: << pipeline.git.branch >> + steps: + - run: + name: build:dist + command: ENABLE_MV3=false yarn build dist + - when: + condition: + matches: + pattern: /^master$/ + value: << pipeline.git.branch >> + steps: + - run: + name: build:prod + command: ENABLE_MV3=false yarn build prod - run: name: build:debug command: find dist/ -type f -exec md5sum {} \; | sort -k 2 - run: - name: Move desktop build to 'dist-desktop' to avoid conflict with production build - command: mv ./dist ./dist-desktop + name: Move mm build to 'dist-mv2' to avoid conflict with production build + command: mv ./dist ./dist-mv2 - run: - name: Move desktop zips to 'builds-desktop' to avoid conflict with production build - command: mv ./builds ./builds-desktop + name: Move mm zips to 'builds-mv2' to avoid conflict with production build + command: mv ./builds ./builds-mv2 + - store_artifacts: + path: builds-mv2 - persist_to_workspace: root: . paths: - - dist-desktop - - builds-desktop + - dist-mv2 + - builds-mv2 prep-build-mmi: - executor: node-browsers-medium-plus + executor: node-linux-medium steps: - run: *shallow-git-clone + - run: corepack enable - attach_workspace: at: . - when: @@ -556,9 +642,10 @@ jobs: destination: builds-mmi prep-build-flask: - executor: node-browsers-medium-plus + executor: node-linux-medium steps: - run: *shallow-git-clone + - run: corepack enable - attach_workspace: at: . - when: @@ -595,10 +682,52 @@ jobs: - dist-flask - builds-flask + prep-build-flask-mv2: + executor: node-linux-medium + steps: + - run: *shallow-git-clone + - run: corepack enable + - attach_workspace: + at: . + - when: + condition: + not: + matches: + pattern: /^master$/ + value: << pipeline.git.branch >> + steps: + - run: + name: build:dist + command: ENABLE_MV3=false yarn build --build-type flask dist + - when: + condition: + matches: + pattern: /^master$/ + value: << pipeline.git.branch >> + steps: + - run: + name: build:prod + command: ENABLE_MV3=false yarn build --build-type flask prod + - run: + name: build:debug + command: find dist/ -type f -exec md5sum {} \; | sort -k 2 + - run: + name: Move flask build to 'dist-flask' to avoid conflict with production build + command: mv ./dist ./dist-flask-mv2 + - run: + name: Move flask zips to 'builds-flask' to avoid conflict with production build + command: mv ./builds ./builds-flask-mv2 + - persist_to_workspace: + root: . + paths: + - dist-flask-mv2 + - builds-flask-mv2 + prep-build-test-flask: - executor: node-browsers-medium-plus + executor: node-linux-medium steps: - run: *shallow-git-clone + - run: corepack enable - attach_workspace: at: . - run: @@ -616,10 +745,33 @@ jobs: - dist-test-flask - builds-test-flask + prep-build-test-flask-mv2: + executor: node-linux-medium + steps: + - run: *shallow-git-clone + - run: corepack enable + - attach_workspace: + at: . + - run: + name: Build extension for testing + command: yarn build:test:flask:mv2 + - run: + name: Move test build to 'dist-test-flask' to avoid conflict with production build + command: mv ./dist ./dist-test-flask-mv2 + - run: + name: Move test zips to 'builds-test-flask' to avoid conflict with production build + command: mv ./builds ./builds-test-flask-mv2 + - persist_to_workspace: + root: . + paths: + - dist-test-flask-mv2 + - builds-test-flask-mv2 + prep-build-test-mmi: - executor: node-browsers-medium-plus + executor: node-linux-medium steps: - run: *shallow-git-clone + - run: corepack enable - attach_workspace: at: . - run: @@ -638,11 +790,13 @@ jobs: - builds-test-mmi prep-build-test-mmi-playwright: - executor: node-browsers-medium-plus + executor: node-linux-medium steps: - run: *shallow-git-clone + - run: corepack enable - attach_workspace: at: . + - run: *check-mmi-optional - run: name: Build MMI extension for Playwright e2e command: | @@ -657,81 +811,110 @@ jobs: - persist_to_workspace: root: . paths: + - RUN_MMI_OPTIONAL - dist-test-mmi-playwright - builds-test-mmi-playwright - store_artifacts: path: builds-test-mmi-playwright destination: builds-test-mmi-playwright - prep-build-test-mv3: - executor: node-browsers-medium-plus + prep-build-test: + executor: node-linux-medium steps: - run: *shallow-git-clone + - run: corepack enable - attach_workspace: at: . - run: - name: Build extension in mv3 for testing - command: yarn build:test:mv3 + name: Build extension for testing + command: yarn build:test - run: name: Move test build to 'dist-test' to avoid conflict with production build - command: mv ./dist ./dist-test-mv3 + command: mv ./dist ./dist-test - run: - name: Move test zips to 'builds-test-mv3' to avoid conflict with production build - command: mv ./builds ./builds-test-mv3 + name: Move test zips to 'builds-test' to avoid conflict with production build + command: mv ./builds ./builds-test + - store_artifacts: + path: builds-test - persist_to_workspace: root: . paths: - - dist-test-mv3 - - builds-test-mv3 + - dist-test + - builds-test - prep-build-test: - executor: node-browsers-medium-plus + prep-build-test-mv2: + executor: node-linux-medium steps: - run: *shallow-git-clone + - run: corepack enable - attach_workspace: at: . - run: name: Build extension for testing - command: yarn build:test + command: yarn build:test:mv2 - run: - name: Move test build to 'dist-test' to avoid conflict with production build - command: mv ./dist ./dist-test + name: Move test build to 'dist-test-mv2' to avoid conflict with production build + command: mv ./dist ./dist-test-mv2 - run: - name: Move test zips to 'builds-test' to avoid conflict with production build - command: mv ./builds ./builds-test + name: Move test zips to 'builds-test-mv2' to avoid conflict with production build + command: mv ./builds ./builds-test-mv2 - store_artifacts: - path: builds-test + path: builds-test-mv2 - persist_to_workspace: root: . paths: - - dist-test - - builds-test + - dist-test-mv2 + - builds-test-mv2 - prep-build-multichain-test: - executor: node-browsers-medium-plus + prep-build-confirmation-redesign-test: + executor: node-linux-medium steps: - run: *shallow-git-clone + - run: corepack enable - attach_workspace: at: . - run: name: Build extension for testing - command: MULTICHAIN=1 yarn build:test + command: ENABLE_CONFIRMATION_REDESIGN="true" yarn build:test - run: name: Move test build to 'dist-test' to avoid conflict with production build - command: mv ./dist ./dist-test-multichain + command: mv ./dist ./dist-test-confirmations - run: name: Move test zips to 'builds-test' to avoid conflict with production build - command: mv ./builds ./builds-test-multichain + command: mv ./builds ./builds-test-confirmations + - persist_to_workspace: + root: . + paths: + - dist-test-confirmations + - builds-test-confirmations + + prep-build-confirmation-redesign-test-mv2: + executor: node-linux-medium + steps: + - run: *shallow-git-clone + - run: corepack enable + - attach_workspace: + at: . + - run: + name: Build extension for testing + command: ENABLE_CONFIRMATION_REDESIGN="true" yarn build:test:mv2 + - run: + name: Move test build to 'dist-test-confirmations-mv2' to avoid conflict with production build + command: mv ./dist ./dist-test-confirmations-mv2 + - run: + name: Move test zips to 'builds-test-confirmations-mv2' to avoid conflict with production build + command: mv ./builds ./builds-test-confirmations-mv2 - persist_to_workspace: root: . paths: - - dist-test-multichain - - builds-test-multichain + - dist-test-confirmations-mv2 + - builds-test-confirmations-mv2 prep-build-storybook: - executor: node-browsers-medium-plus + executor: node-linux-medium steps: - run: *shallow-git-clone + - run: corepack enable - attach_workspace: at: . - run: @@ -746,6 +929,7 @@ jobs: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -760,6 +944,7 @@ jobs: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -770,6 +955,7 @@ jobs: executor: node-browsers-medium steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -783,6 +969,7 @@ jobs: executor: node-browsers-medium-plus steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -802,9 +989,10 @@ jobs: command: ./development/shellcheck.sh test-lint-lockfile: - executor: node-browsers-small + executor: node-browsers-medium steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -818,6 +1006,7 @@ jobs: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - when: @@ -844,6 +1033,7 @@ jobs: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -854,17 +1044,18 @@ jobs: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: name: depcheck command: yarn depcheck - test-e2e-chrome: + test-api-specs: executor: node-browsers-medium-plus - parallelism: 20 steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -873,79 +1064,89 @@ jobs: - run: name: Move test zips to builds command: mv ./builds-test ./builds + - gh/install - run: - name: test:e2e:chrome + name: test:api-specs command: | - if .circleci/scripts/test-run-e2e.sh - then - timeout 20m yarn test:e2e:chrome --retries 2 --debug - fi + timeout 20m yarn test:api-specs --retries 2 no_output_timeout: 5m + - run: + name: Comment on PR + command: | + if [ -f html-report/index.html ]; then + gh pr comment "${CIRCLE_PR_NUMBER}" --body ":x: API Spec Test Failed. View the report [here](https://output.circle-artifacts.com/output/job/${CIRCLE_WORKFLOW_JOB_ID}/artifacts/${CIRCLE_NODE_INDEX}/html-report/index.html)." + else + echo "API Spec Report not found!" + fi + when: on_fail - store_artifacts: - path: test-artifacts - destination: test-artifacts - - store_test_results: - path: test/test-results/e2e + path: html-report + destination: html-report - test-e2e-chrome-multichain: + test-e2e-chrome: executor: node-browsers-medium-plus parallelism: 20 steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: name: Move test build to dist - command: mv ./dist-test-multichain ./dist + command: mv ./dist-test ./dist - run: name: Move test zips to builds - command: mv ./builds-test-multichain ./builds + command: mv ./builds-test ./builds - run: - name: test:e2e:chrome-multichain + name: test:e2e:chrome command: | if .circleci/scripts/test-run-e2e.sh then - timeout 20m yarn test:e2e:chrome --retries 2 --debug + timeout 20m yarn test:e2e:chrome --retries 1 fi no_output_timeout: 5m - environment: - MULTICHAIN: 1 - store_artifacts: path: test-artifacts destination: test-artifacts - store_test_results: path: test/test-results/e2e - test-e2e-chrome-mv3: + test-e2e-chrome-confirmation-redesign: executor: node-browsers-medium-plus - parallelism: 16 + parallelism: 20 steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: name: Move test build to dist - command: mv ./dist-test-mv3 ./dist + command: mv ./dist-test-confirmations ./dist - run: name: Move test zips to builds - command: mv ./builds-test-mv3 ./builds + command: mv ./builds-test-confirmations ./builds - run: - name: test:e2e:chrome + name: test:e2e:chrome-confirmation-redesign command: | if .circleci/scripts/test-run-e2e.sh then - timeout 20m yarn test:e2e:chrome --retries 2 --debug || echo "Temporarily suppressing MV3 e2e test failures" + timeout 20m yarn test:e2e:chrome:confirmation-redesign --retries 1 fi no_output_timeout: 5m + environment: + ENABLE_CONFIRMATION_REDESIGN: "true" - store_artifacts: path: test-artifacts destination: test-artifacts + - store_test_results: + path: test/test-results/e2e test-e2e-chrome-rpc: executor: node-browsers-medium parallelism: 1 steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -959,7 +1160,7 @@ jobs: command: | if .circleci/scripts/test-run-e2e.sh then - timeout 20m yarn test:e2e:chrome:rpc --retries 2 + timeout 20m yarn test:e2e:chrome:rpc --retries 1 fi no_output_timeout: 5m - store_artifacts: @@ -973,6 +1174,7 @@ jobs: parallelism: 1 steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -986,7 +1188,7 @@ jobs: command: | if .circleci/scripts/test-run-e2e.sh then - yarn test:e2e:chrome:multi-provider --retries 2 + yarn test:e2e:chrome:multi-provider --retries 1 fi no_output_timeout: 5m - store_artifacts: @@ -999,6 +1201,7 @@ jobs: executor: node-browsers-medium steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -1012,7 +1215,7 @@ jobs: command: | if .circleci/scripts/test-run-e2e.sh then - timeout 20m yarn test:e2e:chrome:rpc --retries 2 --debug --build-type=mmi + timeout 20m yarn test:e2e:chrome:rpc --retries 1 --build-type=mmi fi no_output_timeout: 5m - store_artifacts: @@ -1025,6 +1228,7 @@ jobs: executor: node-browsers-medium-plus steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -1032,29 +1236,36 @@ jobs: command: | if .circleci/scripts/test-run-e2e.sh then - yarn test:e2e:single test/e2e/vault-decryption-chrome.spec.js --browser chrome --retries 2 --debug + yarn test:e2e:single test/e2e/vault-decryption-chrome.spec.js --browser chrome --retries 1 fi no_output_timeout: 5m + - store_artifacts: + path: test-artifacts + destination: test-artifacts + - store_test_results: + path: test/test-results/e2e test-e2e-firefox-flask: executor: node-browsers-medium-plus parallelism: 10 steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: name: Move test build to dist - command: mv ./dist-test-flask ./dist + command: mv ./dist-test-flask-mv2 ./dist - run: name: Move test zips to builds - command: mv ./builds-test-flask ./builds + command: mv ./builds-test-flask-mv2 ./builds - run: name: test:e2e:firefox:flask command: | + export ENABLE_MV3=false if .circleci/scripts/test-run-e2e.sh then - timeout 20m yarn test:e2e:firefox:flask --retries 2 --debug + timeout 20m yarn test:e2e:firefox:flask --retries 1 fi no_output_timeout: 5m - store_artifacts: @@ -1068,6 +1279,7 @@ jobs: parallelism: 8 steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -1081,7 +1293,7 @@ jobs: command: | if .circleci/scripts/test-run-e2e.sh then - timeout 20m yarn test:e2e:chrome:flask --retries 2 --debug + timeout 20m yarn test:e2e:chrome:flask --retries 1 fi no_output_timeout: 5m - store_artifacts: @@ -1095,6 +1307,7 @@ jobs: parallelism: 12 steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -1108,7 +1321,7 @@ jobs: command: | if .circleci/scripts/test-run-e2e.sh then - timeout 20m yarn test:e2e:chrome:mmi --retries 2 --debug --build-type=mmi + timeout 20m yarn test:e2e:chrome:mmi --retries 1 --build-type=mmi fi no_output_timeout: 5m - store_artifacts: @@ -1122,8 +1335,10 @@ jobs: parallelism: 2 steps: - run: *shallow-git-clone + - run: corepack enable - attach_workspace: at: . + - run: *check-mmi-optional - run: name: Move test build to dist command: mv ./dist-test-mmi-playwright ./dist @@ -1162,22 +1377,55 @@ jobs: parallelism: 24 steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: name: Move test build to dist - command: mv ./dist-test ./dist + command: mv ./dist-test-mv2 ./dist - run: name: Move test zips to builds - command: mv ./builds-test ./builds + command: mv ./builds-test-mv2 ./builds - run: name: test:e2e:firefox command: | + export ENABLE_MV3=false + if .circleci/scripts/test-run-e2e.sh + then + timeout 20m yarn test:e2e:firefox --retries 1 + fi + no_output_timeout: 5m + - store_artifacts: + path: test-artifacts + destination: test-artifacts + - store_test_results: + path: test/test-results/e2e + + test-e2e-firefox-confirmation-redesign: + executor: node-browsers-medium-plus + parallelism: 20 + steps: + - run: *shallow-git-clone + - run: sudo corepack enable + - attach_workspace: + at: . + - run: + name: Move test build to dist + command: mv ./dist-test-confirmations-mv2 ./dist + - run: + name: Move test zips to builds + command: mv ./builds-test-confirmations-mv2 ./builds + - run: + name: test:e2e:firefox-confirmation-redesign + command: | + export ENABLE_MV3=false if .circleci/scripts/test-run-e2e.sh then - timeout 20m yarn test:e2e:firefox --retries 2 --debug + timeout 20m yarn test:e2e:firefox --retries 1 fi no_output_timeout: 5m + environment: + ENABLE_CONFIRMATION_REDESIGN: "true" - store_artifacts: path: test-artifacts destination: test-artifacts @@ -1188,6 +1436,7 @@ jobs: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -1211,6 +1460,7 @@ jobs: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -1234,25 +1484,26 @@ jobs: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: name: Move test build to dist - command: mv ./dist-test-mv3 ./dist + command: mv ./dist-test ./dist - run: name: Move test zips to builds - command: mv ./builds-test-mv3 ./builds + command: mv ./builds-test ./builds - run: name: Run page load benchmark command: | - mkdir -p test-artifacts/chrome/mv3 - cp -R development/charts/flamegraph test-artifacts/chrome/mv3/initialisation - cp -R development/charts/flamegraph/chart test-artifacts/chrome/mv3/initialisation/background - cp -R development/charts/flamegraph/chart test-artifacts/chrome/mv3/initialisation/ui - cp -R development/charts/table test-artifacts/chrome/mv3/load_time + mkdir -p test-artifacts/chrome/ + cp -R development/charts/flamegraph test-artifacts/chrome/initialisation + cp -R development/charts/flamegraph/chart test-artifacts/chrome/initialisation/background + cp -R development/charts/flamegraph/chart test-artifacts/chrome/initialisation/ui + cp -R development/charts/table test-artifacts/chrome/load_time - run: name: Run page load benchmark - command: yarn mv3:stats:chrome --out test-artifacts/chrome/mv3 + command: yarn mv3:stats:chrome --out test-artifacts/chrome - run: name: Install jq command: sudo apt install jq -y @@ -1268,9 +1519,10 @@ jobs: - test-artifacts job-publish-prerelease: - executor: node-browsers-small + executor: node-browsers-medium steps: - checkout + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -1294,9 +1546,15 @@ jobs: - store_artifacts: path: builds-flask destination: builds-flask + - store_artifacts: + path: builds-flask-mv2 + destination: builds-flask-mv2 - store_artifacts: path: builds-mmi destination: builds-mmi + - store_artifacts: + path: builds-mv2 + destination: builds-mv2 - store_artifacts: path: builds-test - store_artifacts: @@ -1308,8 +1566,6 @@ jobs: path: test-artifacts destination: test-artifacts # important: generate lavamoat viz AFTER uploading builds as artifacts - # Temporarily disabled until we can update to a version of `sesify` with - # this fix included: https://github.com/LavaMoat/LavaMoat/pull/121 - run: name: build:lavamoat-viz command: ./.circleci/scripts/create-lavamoat-viz.sh @@ -1335,6 +1591,7 @@ jobs: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -1358,6 +1615,7 @@ jobs: fingerprints: - '3d:49:29:f4:b2:e8:ea:af:d1:32:eb:2a:fc:15:85:d8' - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -1373,6 +1631,7 @@ jobs: fingerprints: - '8b:21:e3:20:7c:c9:db:82:74:2d:86:d6:11:a7:2f:49' - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -1383,25 +1642,11 @@ jobs: git config user.email metamaskbot@users.noreply.github.com yarn ts-migration:dashboard:deploy - test-unit-mocha: - executor: node-browsers-small - steps: - - run: *shallow-git-clone - - attach_workspace: - at: . - - run: - name: test:coverage:mocha - command: yarn test:coverage:mocha - - persist_to_workspace: - root: . - paths: - - .nyc_output - - coverage - test-unit-jest-development: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -1419,6 +1664,7 @@ jobs: parallelism: 8 steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -1431,16 +1677,14 @@ jobs: - store_test_results: path: test/test-results/junit.xml - upload-and-validate-coverage: + upload-coverage: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - codecov/upload - - run: - name: test:coverage:validate - command: yarn test:coverage:validate - persist_to_workspace: root: . paths: @@ -1450,6 +1694,7 @@ jobs: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -1460,6 +1705,7 @@ jobs: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -1470,6 +1716,7 @@ jobs: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: @@ -1477,92 +1724,104 @@ jobs: command: | .circleci/scripts/validate-source-maps-beta.sh - validate-source-maps-desktop: + validate-source-maps-mmi: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: - name: Move desktop build to dist - command: mv ./dist-desktop ./dist + name: Move mmi build to dist + command: mv ./dist-mmi ./dist - run: - name: Move desktop zips to builds - command: mv ./builds-desktop ./builds + name: Move mmi zips to builds + command: mv ./builds-mmi ./builds - run: name: Validate source maps command: yarn validate-source-maps - validate-source-maps-mmi: + validate-source-maps-flask: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: - name: Move mmi build to dist - command: mv ./dist-mmi ./dist + name: Move flask build to dist + command: mv ./dist-flask ./dist - run: - name: Move mmi zips to builds - command: mv ./builds-mmi ./builds + name: Move flask zips to builds + command: mv ./builds-flask ./builds - run: name: Validate source maps command: yarn validate-source-maps - validate-source-maps-flask: + validate-source-maps-flask-mv2: executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: name: Move flask build to dist - command: mv ./dist-flask ./dist + command: mv ./dist-flask-mv2 ./dist - run: name: Move flask zips to builds - command: mv ./builds-flask ./builds + command: mv ./builds-flask-mv2 ./builds - run: name: Validate source maps command: yarn validate-source-maps - test-mozilla-lint: - executor: node-browsers-medium + validate-source-maps-mv2: + executor: node-browsers-small steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: - name: test:mozilla-lint - command: yarn mozilla-lint + name: Move flask build to dist + command: mv ./dist-mv2 ./dist + - run: + name: Move flask zips to builds + command: mv ./builds-mv2 ./builds + - run: + name: Validate source maps + command: yarn validate-source-maps - test-mozilla-lint-desktop: + test-mozilla-lint-mv2: executor: node-browsers-medium steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: - name: Move desktop build to dist - command: mv ./dist-desktop ./dist + name: Move flask build to dist + command: mv ./dist-mv2 ./dist - run: - name: Move desktop zips to builds - command: mv ./builds-desktop ./builds + name: Move flask zips to builds + command: mv ./builds-mv2 ./builds - run: name: test:mozilla-lint command: yarn mozilla-lint - test-mozilla-lint-flask: + test-mozilla-lint-flask-mv2: executor: node-browsers-medium steps: - run: *shallow-git-clone + - run: sudo corepack enable - attach_workspace: at: . - run: name: Move flask build to dist - command: mv ./dist-flask ./dist + command: mv ./dist-flask-mv2 ./dist - run: name: Move flask zips to builds - command: mv ./builds-flask ./builds + command: mv ./builds-flask-mv2 ./builds - run: name: test:mozilla-lint command: yarn mozilla-lint @@ -1572,4 +1831,4 @@ jobs: steps: - run: name: All Tests Passed - command: echo 'weew - everything passed!' + command: echo 'whew - everything passed!' diff --git a/.circleci/scripts/bundle-stats-commit.sh b/.circleci/scripts/bundle-stats-commit.sh index b7cb44ac756a..14b3604d82ec 100755 --- a/.circleci/scripts/bundle-stats-commit.sh +++ b/.circleci/scripts/bundle-stats-commit.sh @@ -42,7 +42,7 @@ git clone git@github.com:MetaMask/extension_bundlesize_stats.git temp { echo " '${CIRCLE_SHA1}': "; - cat test-artifacts/chrome/mv3/bundle_size_stats.json; + cat test-artifacts/chrome/bundle_size_stats.json; echo ", "; } >> temp/stats/bundle_size_data.temp.js @@ -57,14 +57,14 @@ if [ -f temp/stats/bundle_size_data.json ]; then { echo "},"; echo "\"$CIRCLE_SHA1\":"; - cat test-artifacts/chrome/mv3/bundle_size_stats.json; + cat test-artifacts/chrome/bundle_size_stats.json; echo "}"; } >> bundle_size_stats.temp.json else { echo "{"; echo "\"$CIRCLE_SHA1\":"; - cat test-artifacts/chrome/mv3/bundle_size_stats.json; + cat test-artifacts/chrome/bundle_size_stats.json; echo "}"; } > bundle_size_stats.temp.json fi diff --git a/.circleci/scripts/create-cherry-pick-pr.sh b/.circleci/scripts/create-cherry-pick-pr.sh new file mode 100644 index 000000000000..da401345ac79 --- /dev/null +++ b/.circleci/scripts/create-cherry-pick-pr.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +# Takes in 3 args +# - 1 - Base PR Branch Name +# - 2 - Commit Hash +# - 3 - PR Number + +BASE_PR_BRANCH_NAME="${1}" +COMMIT_HASH_TO_CHERRY_PICK="${2}" +PR_BRANCH_NAME="chore/cherry-pick-${3}" +PR_TITLE="chore: cherry-pick #${3}" +PR_BODY="This PR cherry-picks #${3}" + +git config user.name "MetaMask Bot" +git config user.email "metamaskbot@users.noreply.github.com" + +git checkout "${BASE_PR_BRANCH_NAME}" +git pull +git checkout -b "${PR_BRANCH_NAME}" +git cherry-pick "${COMMIT_HASH_TO_CHERRY_PICK}" + +git push --set-upstream origin "${PR_BRANCH_NAME}" + +gh pr create \ + --draft \ + --title "${PR_TITLE}" \ + --body "${PR_BODY}" \ + --head "${BASE_PR_BRANCH_NAME}" \ No newline at end of file diff --git a/.circleci/scripts/create-lavamoat-viz.sh b/.circleci/scripts/create-lavamoat-viz.sh index 4f2df2cdb1ce..135f8a461263 100755 --- a/.circleci/scripts/create-lavamoat-viz.sh +++ b/.circleci/scripts/create-lavamoat-viz.sh @@ -10,8 +10,33 @@ BUILD_DEST="./build-artifacts/build-viz/" # prepare artifacts dir mkdir -p "${BUILD_DEST}" -# generate lavamoat debug config +# generate lavamoat debug configs yarn lavamoat:debug:build +yarn lavamoat:debug:webapp --parallel=false +# generate entries for all present policy dirs under lavamoat/browserify +# static entry for build-system +POLICY_DIR_NAMES=$(find lavamoat/browserify -maxdepth 1 -mindepth 1 -type d -printf '%f ') + +POLICY_FILE_PATHS_JSON=$(echo -n "${POLICY_DIR_NAMES}" \ + | jq --raw-input --slurp --indent 0 ' + rtrimstr(" ") + | split(" ") + | map({ + "key": ., + "value": { + "debug": ("lavamoat/browserify/"+.+"/policy-debug.json"), + "override":"lavamoat/browserify/policy-override.json", + "primary":("lavamoat/browserify/"+.+"/policy.json") + } + }) + | from_entries + |."build-system"= { + "debug": "lavamoat/build-system/policy-debug.json", + "override":"lavamoat/build-system/policy-override.json", + "primary": "lavamoat/build-system/policy.json" + }' +) # generate viz -npx lavamoat-viz --dest "${BUILD_DEST}" +# shellcheck disable=SC2086 +yarn lavamoat-viz --dest "${BUILD_DEST}" --policyNames build-system ${POLICY_DIR_NAMES} --policyFilePathsJson "${POLICY_FILE_PATHS_JSON}" diff --git a/.circleci/scripts/release-create-gh-release.sh b/.circleci/scripts/release-create-gh-release.sh index e138e20c5b59..37a654798b9f 100755 --- a/.circleci/scripts/release-create-gh-release.sh +++ b/.circleci/scripts/release-create-gh-release.sh @@ -69,9 +69,9 @@ then release_body="$(awk -v version="${tag##v}" -f .circleci/scripts/show-changelog.awk CHANGELOG.md)" hub release create \ --attach builds/metamask-chrome-*.zip \ - --attach builds/metamask-firefox-*.zip \ + --attach builds-mv2/metamask-firefox-*.zip \ --attach builds-flask/metamask-flask-chrome-*.zip \ - --attach builds-flask/metamask-flask-firefox-*.zip \ + --attach builds-flask-mv2/metamask-flask-firefox-*.zip \ --attach builds-mmi/metamask-mmi-chrome-*.zip \ --attach builds-mmi/metamask-mmi-firefox-*.zip \ --message "Version ${tag##v}" \ diff --git a/.depcheckrc.yml b/.depcheckrc.yml index b4d28d081ec0..e4169c5436f0 100644 --- a/.depcheckrc.yml +++ b/.depcheckrc.yml @@ -39,8 +39,6 @@ ignores: - 'wait-on' - 'tsx' # used in .devcontainer - 'prettier-eslint' # used by the Prettier ESLint VSCode extension - # development tool - - 'nyc' # storybook - '@storybook/cli' - '@storybook/core' @@ -62,6 +60,8 @@ ignores: - 'jest-environment-jsdom' # babel - '@babel/plugin-transform-logical-assignment-operators' + # trezor + - 'ts-mixer' # files depcheck should not parse ignorePatterns: diff --git a/.devcontainer/download-builds.ts b/.devcontainer/download-builds.ts index a4bc33e89ab9..1253c8a81599 100644 --- a/.devcontainer/download-builds.ts +++ b/.devcontainer/download-builds.ts @@ -45,11 +45,12 @@ async function getBuilds(branch: string, jobNames: string[]) { console.log(`jobName: ${jobName}, jobId: ${jobId}`); + // Using the CircleCI API version 1.1 here, because this endpoint recently started requiring Authorization in v2 const response = await fetch( - `https://circleci.com/api/v2/project/gh/MetaMask/metamask-extension/${jobId}/artifacts`, + `https://circleci.com/api/v1.1/project/gh/MetaMask/metamask-extension/${jobId}/artifacts`, ); - const artifacts = (await response.json()).items; + const artifacts = await response.json(); if (!artifacts || artifacts.length === 0) { return []; diff --git a/.eslintrc.js b/.eslintrc.js index d57cc7bf7aef..9f7fed5928ed 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -18,6 +18,10 @@ module.exports = { ignorePatterns: readFileSync('.prettierignore', 'utf8').trim().split('\n'), // eslint's parser, esprima, is not compatible with ESM, so use the babel parser instead parser: '@babel/eslint-parser', + plugins: ['@metamask/design-tokens'], + rules: { + '@metamask/design-tokens/color-no-hex': 'warn', + }, overrides: [ /** * == Modules == @@ -42,9 +46,7 @@ module.exports = { 'development/**/*.js', 'test/e2e/**/*.js', 'test/helpers/*.js', - 'test/lib/wait-until-called.js', 'test/run-unit-tests.js', - 'test/merge-coverage.js', ], extends: [ path.resolve(__dirname, '.eslintrc.base.js'), @@ -90,8 +92,6 @@ module.exports = { 'test/stub/**/*.js', 'test/unit-global/**/*.js', ], - // TODO: Convert these files to modern JS - excludedFiles: ['test/lib/wait-until-called.js'], extends: [ path.resolve(__dirname, '.eslintrc.base.js'), path.resolve(__dirname, '.eslintrc.node.js'), @@ -135,6 +135,7 @@ module.exports = { path.resolve(__dirname, '.eslintrc.typescript-compat.js'), ], rules: { + '@typescript-eslint/no-explicit-any': 'error', // this rule is new, but we didn't use it before, so it's off now '@typescript-eslint/no-duplicate-enum-values': 'off', '@typescript-eslint/no-shadow': [ @@ -256,26 +257,7 @@ module.exports = { * Mocha library. */ { - files: [ - '**/*.test.js', - 'test/lib/wait-until-called.js', - 'test/e2e/**/*.spec.js', - ], - excludedFiles: [ - 'app/scripts/controllers/app-state.test.js', - 'app/scripts/controllers/mmi-controller.test.js', - 'app/scripts/controllers/permissions/**/*.test.js', - 'app/scripts/controllers/preferences.test.js', - 'app/scripts/lib/**/*.test.js', - 'app/scripts/metamask-controller.test.js', - 'app/scripts/migrations/*.test.js', - 'app/scripts/platforms/*.test.js', - 'development/**/*.test.js', - 'shared/**/*.test.js', - 'ui/**/*.test.js', - 'ui/__mocks__/*.js', - 'test/e2e/helpers.test.js', - ], + files: ['test/e2e/**/*.spec.js', 'test/unit-global/*.test.js'], extends: ['@metamask/eslint-config-mocha'], rules: { // In Mocha tests, it is common to use `this` to store values or do @@ -288,13 +270,19 @@ module.exports = { * Jest tests * * These are files that make use of globals and syntax introduced by the - * Jest library. The files in this section should match the Mocha excludedFiles section. + * Jest library. + * TODO: This list of files is incomplete, and should be replaced with globs that match the + * Jest config. */ { files: [ '**/__snapshots__/*.snap', 'app/scripts/controllers/app-state.test.js', 'app/scripts/controllers/mmi-controller.test.ts', + 'app/scripts/metamask-controller.actions.test.js', + 'app/scripts/detect-multiple-instances.test.js', + 'app/scripts/controllers/swaps.test.js', + 'app/scripts/controllers/metametrics.test.js', 'app/scripts/controllers/permissions/**/*.test.js', 'app/scripts/controllers/preferences.test.js', 'app/scripts/lib/**/*.test.js', @@ -378,7 +366,6 @@ module.exports = { 'test/e2e/benchmark.js', 'test/helpers/setup-helper.js', 'test/run-unit-tests.js', - 'test/merge-coverage.js', ], rules: { 'node/no-process-exit': 'off', @@ -438,5 +425,18 @@ module.exports = { ], }, }, + /** + * Don't check for static hex values in .test, .spec or .stories files + */ + { + files: [ + '**/*.test.{js,ts,tsx}', + '**/*.spec.{js,ts,tsx}', + '**/*.stories.{js,ts,tsx}', + ], + rules: { + '@metamask/design-tokens/color-no-hex': 'off', + }, + }, ], }; diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 00c3678ffb6b..8bf55d58dbd4 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -29,7 +29,7 @@ offscreen/scripts/offscreen.ts @MetaMask/snaps-devs # empower our CI steps. ANY addition of orbs to our CircleCI config # should be brought to the attention of engineering leadership for # discussion -.circleci/ @MetaMask/library-admins @kumavis @brad-decker +.circleci/ @MetaMask/library-admins @kumavis # The privacy-snapshot.json file includes a list of all hosts that the # extension communicates with during the E2E test suite runs. It is not a @@ -50,4 +50,37 @@ privacy-snapshot.json @MetaMask/extension-privacy-reviewers # For now, restricting approvals inside the .devcontainer folder to devs # who were involved with the Codespaces project. -.devcontainer/ @MetaMask/library-admins @HowardBraham @plasmacorral @brad-decker +.devcontainer/ @MetaMask/library-admins @HowardBraham @plasmacorral + +# Confirmations team to own code for confirmations on UI. +ui/pages/confirmations @MetaMask/confirmations + +# MMI team is responsible for code related with Institutioanl version of MetaMask +ui/pages/institutional @MetaMask/mmi +ui/components/institutional @MetaMask/mmi +ui/ducks/institutional @MetaMask/mmi +ui/selectors/institutional @MetaMask/mmi + +# Design System to own code for the component-library folder +# Slack handle: @metamask-design-system-team | Slack channel: #metamask-design-system +ui/components/component-library @MetaMask/design-system-engineers + +# The Notifications team is responsible for code related to notifications, +# authentication, and profile syncing inside the Extension. + +# Controllers +**/controllers/authentication/** @MetaMask/notifications +**/controllers/metamask-notifications/** @MetaMask/notifications +**/controllers/push-platform-notifications/** @MetaMask/notifications +**/controllers/user-storage/** @MetaMask/notifications + +# UI +**/metamask-notifications/** @MetaMask/notifications +**/multichain/notification*/** @MetaMask/notifications +**/pages/notification*/** @MetaMask/notifications +**/utils/notification.util.ts @MetaMask/notifications + +# Accounts team is responsible for code related with snap management accounts +# Slack handle: @accounts-team-devs | Slack channel: #metamask-accounts-team + +app/scripts/lib/snap-keyring @MetaMask/accounts-engineers diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 819be0fac1ec..cec32fc26969 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -29,7 +29,7 @@ body: id: screenshot-recording attributes: label: Screenshots/Recordings - description: Please include screenshots/recordings if applicable! (https://recordit.co/ is recommended) + description: Please include screenshots/recordings if applicable! - type: textarea id: reproduce attributes: @@ -105,6 +105,7 @@ body: - GridPlus Lattice1 - AirGap Vault - imToken + - OneKey - Other (please elaborate in the "Additional Context" section) - type: textarea id: additional diff --git a/.github/guidelines/LABELING_GUIDELINES.md b/.github/guidelines/LABELING_GUIDELINES.md index 054cec4aff24..02081367bb5e 100644 --- a/.github/guidelines/LABELING_GUIDELINES.md +++ b/.github/guidelines/LABELING_GUIDELINES.md @@ -11,8 +11,10 @@ It's essential to ensure that PRs have the appropriate labels before they are co ### Mandatory release version labels: - **release-x.y.z**: This label is automatically added to a PR and its linked issues upon the PR's merge. The `x.y.z` in the label represents the version in which the changes from the PR will be included. This label is auto-generated by a [GitHub action](../workflows/add-release-label.yml), which determines the version by incrementing the minor version number from the most recent release. Manual intervention is only required in specific cases. For instance, if a merged PR is cherry-picked into a release branch, typically done to address Release Candidate (RC) bugs, the label would need to be manually updated to reflect the correct version. - **regression-prod-x.y.z**: This label is automatically added to a bug report issue at the time of its creation. The `x.y.z` in the label represents the version in which the bug first appeared. This label is auto-generated by a [GitHub action](../workflows/check-template-and-add-labels.yml), which determines the `x.y.z` value based on the version information provided in the bug report issue form. Manual intervention is only necessary under certain circumstances. For example, if a user submits a bug report and specifies the version they are currently using, but the bug was actually introduced in a prior version, the label would need to be manually updated to accurately reflect the version where the bug originated. +- **regression-RC-x.y.z**: This label is manually added to a bug report issue by release engineers when a bug is found during release regerssion testing phase. The `x.y.z` in the label represents the release candidate (RC) version in which the bug's been discovered. -### Optional QA labels: +### Optional labels: +- **regression-develop**: This label can manually be added to a bug report issue at the time of its creation if the bug is present on the development branch, i.e., `develop`, but is not yet released in production. - **needs-qa**: If the PR includes a new features, complex testing steps, or large refactors, this label must be added to indicated PR requires a full manual QA prior being merged and added to a release. ### Labels prohibited when PR needs to be merged: diff --git a/.github/pull-request-template.md b/.github/pull-request-template.md index 0c046fb560d8..59232248ef51 100644 --- a/.github/pull-request-template.md +++ b/.github/pull-request-template.md @@ -1,3 +1,9 @@ + + + ## **Description** /2"?(X=ae(new x.type.Rule(z.value.args[0],z.value.args[1]),w),X.body=Pe(X.body),Z={value:X,len:y,type:x.type.is_rule(X)?p:A}):(X=new x.type.Rule(z.value,null),Z={value:X,len:y,type:p}),X){var ie=X.singleton_variables();ie.length>0&&w.throw_warning(x.warning.singleton(ie,X.head.indicator,F))}return Z}else return{type:A,value:x.error.syntax(S[y],"callable expected")};else return{type:A,value:x.error.syntax(S[y]?S[y]:S[y-1],". or operator expected")};return z}function Ae(w,S,y){y=y||{},y.from=y.from?y.from:"$tau-js",y.reconsult=y.reconsult!==void 0?y.reconsult:!0;var F=new U(w),z={},X;F.new_text(S);var Z=0,ie=F.get_tokens(Z);do{if(ie===null||!ie[Z])break;var Se=pe(w,ie,Z);if(Se.type===A)return new H("throw",[Se.value]);if(Se.value.body===null&&Se.value.head.indicator==="?-/1"){var Ne=new Je(w.session);Ne.add_goal(Se.value.head.args[0]),Ne.answer(function(dt){x.type.is_error(dt)?w.throw_warning(dt.args[0]):(dt===!1||dt===null)&&w.throw_warning(x.warning.failed_goal(Se.value.head.args[0],Se.len))}),Z=Se.len;var ot=!0}else if(Se.value.body===null&&Se.value.head.indicator===":-/1"){var ot=w.run_directive(Se.value.head.args[0]);Z=Se.len,Se.value.head.args[0].indicator==="char_conversion/2"&&(ie=F.get_tokens(Z),Z=0)}else{X=Se.value.head.indicator,y.reconsult!==!1&&z[X]!==!0&&!w.is_multifile_predicate(X)&&(w.session.rules[X]=a(w.session.rules[X]||[],function(jt){return jt.dynamic}),z[X]=!0);var ot=w.add_rule(Se.value,y);Z=Se.len}if(!ot)return ot}while(!0);return!0}function ye(w,S){var y=new U(w);y.new_text(S);var F=0;do{var z=y.get_tokens(F);if(z===null)break;var X=J(w,z,0,w.__get_max_priority(),!1);if(X.type!==A){var Z=X.len,ie=Z;if(z[Z]&&z[Z].name==="atom"&&z[Z].raw===".")w.add_goal(Pe(X.value));else{var Se=z[Z];return new H("throw",[x.error.syntax(Se||z[Z-1],". or operator expected",!Se)])}F=X.len+1}else return new H("throw",[X.value])}while(!0);return!0}function ae(w,S){w=w.rename(S);var y=S.next_free_variable(),F=we(w.body,y,S);return F.error?F.value:(w.body=F.value,w.head.args=w.head.args.concat([y,F.variable]),w.head=new H(w.head.id,w.head.args),w)}function we(w,S,y){var F;if(x.type.is_term(w)&&w.indicator==="!/0")return{value:w,variable:S,error:!1};if(x.type.is_term(w)&&w.indicator===",/2"){var z=we(w.args[0],S,y);if(z.error)return z;var X=we(w.args[1],z.variable,y);return X.error?X:{value:new H(",",[z.value,X.value]),variable:X.variable,error:!1}}else{if(x.type.is_term(w)&&w.indicator==="{}/1")return{value:w.args[0],variable:S,error:!1};if(x.type.is_empty_list(w))return{value:new H("true",[]),variable:S,error:!1};if(x.type.is_list(w)){F=y.next_free_variable();for(var Z=w,ie;Z.indicator==="./2";)ie=Z,Z=Z.args[1];return x.type.is_variable(Z)?{value:x.error.instantiation("DCG"),variable:S,error:!0}:x.type.is_empty_list(Z)?(ie.args[1]=F,{value:new H("=",[S,w]),variable:F,error:!1}):{value:x.error.type("list",w,"DCG"),variable:S,error:!0}}else return x.type.is_callable(w)?(F=y.next_free_variable(),w.args=w.args.concat([S,F]),w=new H(w.id,w.args),{value:w,variable:F,error:!1}):{value:x.error.type("callable",w,"DCG"),variable:S,error:!0}}}function Pe(w){return x.type.is_variable(w)?new H("call",[w]):x.type.is_term(w)&&[",/2",";/2","->/2"].indexOf(w.indicator)!==-1?new H(w.id,[Pe(w.args[0]),Pe(w.args[1])]):w}function g(w,S){for(var y=S||new x.type.Term("[]",[]),F=w.length-1;F>=0;F--)y=new x.type.Term(".",[w[F],y]);return y}function Ee(w,S){for(var y=w.length-1;y>=0;y--)w[y]===S&&w.splice(y,1)}function De(w){for(var S={},y=[],F=0;F=0;S--)if(w.charAt(S)==="/")return new H("/",[new H(w.substring(0,S)),new ke(parseInt(w.substring(S+1)),!1)])}function Ie(w){this.id=w}function ke(w,S){this.is_float=S!==void 0?S:parseInt(w)!==w,this.value=this.is_float?w:parseInt(w)}var ht=0;function H(w,S,y){this.ref=y||++ht,this.id=w,this.args=S||[],this.indicator=w+"/"+this.args.length}var lt=0;function Re(w,S,y,F,z,X){this.id=lt++,this.stream=w,this.mode=S,this.alias=y,this.type=F!==void 0?F:"text",this.reposition=z!==void 0?z:!0,this.eof_action=X!==void 0?X:"eof_code",this.position=this.mode==="append"?"end_of_stream":0,this.output=this.mode==="write"||this.mode==="append",this.input=this.mode==="read"}function Qe(w){w=w||{},this.links=w}function be(w,S,y){S=S||new Qe,y=y||null,this.goal=w,this.substitution=S,this.parent=y}function _e(w,S,y){this.head=w,this.body=S,this.dynamic=y||!1}function Te(w){w=w===void 0||w<=0?1e3:w,this.rules={},this.src_predicates={},this.rename=0,this.modules=[],this.thread=new Je(this),this.total_threads=1,this.renamed_variables={},this.public_predicates={},this.multifile_predicates={},this.limit=w,this.streams={user_input:new Re(typeof hl<"u"&&hl.exports?nodejs_user_input:tau_user_input,"read","user_input","text",!1,"reset"),user_output:new Re(typeof hl<"u"&&hl.exports?nodejs_user_output:tau_user_output,"write","user_output","text",!1,"eof_code")},this.file_system=typeof hl<"u"&&hl.exports?nodejs_file_system:tau_file_system,this.standard_input=this.streams.user_input,this.standard_output=this.streams.user_output,this.current_input=this.streams.user_input,this.current_output=this.streams.user_output,this.format_success=function(S){return S.substitution},this.format_error=function(S){return S.goal},this.flag={bounded:x.flag.bounded.value,max_integer:x.flag.max_integer.value,min_integer:x.flag.min_integer.value,integer_rounding_function:x.flag.integer_rounding_function.value,char_conversion:x.flag.char_conversion.value,debug:x.flag.debug.value,max_arity:x.flag.max_arity.value,unknown:x.flag.unknown.value,double_quotes:x.flag.double_quotes.value,occurs_check:x.flag.occurs_check.value,dialect:x.flag.dialect.value,version_data:x.flag.version_data.value,nodejs:x.flag.nodejs.value},this.__loaded_modules=[],this.__char_conversion={},this.__operators={1200:{":-":["fx","xfx"],"-->":["xfx"],"?-":["fx"]},1100:{";":["xfy"]},1050:{"->":["xfy"]},1e3:{",":["xfy"]},900:{"\\+":["fy"]},700:{"=":["xfx"],"\\=":["xfx"],"==":["xfx"],"\\==":["xfx"],"@<":["xfx"],"@=<":["xfx"],"@>":["xfx"],"@>=":["xfx"],"=..":["xfx"],is:["xfx"],"=:=":["xfx"],"=\\=":["xfx"],"<":["xfx"],"=<":["xfx"],">":["xfx"],">=":["xfx"]},600:{":":["xfy"]},500:{"+":["yfx"],"-":["yfx"],"/\\":["yfx"],"\\/":["yfx"]},400:{"*":["yfx"],"/":["yfx"],"//":["yfx"],rem:["yfx"],mod:["yfx"],"<<":["yfx"],">>":["yfx"]},200:{"**":["xfx"],"^":["xfy"],"-":["fy"],"+":["fy"],"\\":["fy"]}}}function Je(w){this.epoch=Date.now(),this.session=w,this.session.total_threads++,this.total_steps=0,this.cpu_time=0,this.cpu_time_last=0,this.points=[],this.debugger=!1,this.debugger_states=[],this.level="top_level/0",this.__calls=[],this.current_limit=this.session.limit,this.warnings=[]}function He(w,S,y){this.id=w,this.rules=S,this.exports=y,x.module[w]=this}He.prototype.exports_predicate=function(w){return this.exports.indexOf(w)!==-1},Ie.prototype.unify=function(w,S){if(S&&e(w.variables(),this.id)!==-1&&!x.type.is_variable(w))return null;var y={};return y[this.id]=w,new Qe(y)},ke.prototype.unify=function(w,S){return x.type.is_number(w)&&this.value===w.value&&this.is_float===w.is_float?new Qe:null},H.prototype.unify=function(w,S){if(x.type.is_term(w)&&this.indicator===w.indicator){for(var y=new Qe,F=0;F=0){var F=this.args[0].value,z=Math.floor(F/26),X=F%26;return"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[X]+(z!==0?z:"")}switch(this.indicator){case"[]/0":case"{}/0":case"!/0":return this.id;case"{}/1":return"{"+this.args[0].toString(w)+"}";case"./2":for(var Z="["+this.args[0].toString(w),ie=this.args[1];ie.indicator==="./2";)Z+=", "+ie.args[0].toString(w),ie=ie.args[1];return ie.indicator!=="[]/0"&&(Z+="|"+ie.toString(w)),Z+="]",Z;case",/2":return"("+this.args[0].toString(w)+", "+this.args[1].toString(w)+")";default:var Se=this.id,Ne=w.session?w.session.lookup_operator(this.id,this.args.length):null;if(w.session===void 0||w.ignore_ops||Ne===null)return w.quoted&&!/^(!|,|;|[a-z][0-9a-zA-Z_]*)$/.test(Se)&&Se!=="{}"&&Se!=="[]"&&(Se="'"+b(Se)+"'"),Se+(this.args.length?"("+o(this.args,function($t){return $t.toString(w)}).join(", ")+")":"");var ot=Ne.priority>S.priority||Ne.priority===S.priority&&(Ne.class==="xfy"&&this.indicator!==S.indicator||Ne.class==="yfx"&&this.indicator!==S.indicator||this.indicator===S.indicator&&Ne.class==="yfx"&&y==="right"||this.indicator===S.indicator&&Ne.class==="xfy"&&y==="left");Ne.indicator=this.indicator;var dt=ot?"(":"",jt=ot?")":"";return this.args.length===0?"("+this.id+")":["fy","fx"].indexOf(Ne.class)!==-1?dt+Se+" "+this.args[0].toString(w,Ne)+jt:["yf","xf"].indexOf(Ne.class)!==-1?dt+this.args[0].toString(w,Ne)+" "+Se+jt:dt+this.args[0].toString(w,Ne,"left")+" "+this.id+" "+this.args[1].toString(w,Ne,"right")+jt}},Re.prototype.toString=function(w){return"("+this.id+")"},Qe.prototype.toString=function(w){var S="{";for(var y in this.links)!this.links.hasOwnProperty(y)||(S!=="{"&&(S+=", "),S+=y+"/"+this.links[y].toString(w));return S+="}",S},be.prototype.toString=function(w){return this.goal===null?"<"+this.substitution.toString(w)+">":"<"+this.goal.toString(w)+", "+this.substitution.toString(w)+">"},_e.prototype.toString=function(w){return this.body?this.head.toString(w)+" :- "+this.body.toString(w)+".":this.head.toString(w)+"."},Te.prototype.toString=function(w){for(var S="",y=0;y=0;z--)F=new H(".",[S[z],F]);return F}return new H(this.id,o(this.args,function(X){return X.apply(w)}),this.ref)},Re.prototype.apply=function(w){return this},_e.prototype.apply=function(w){return new _e(this.head.apply(w),this.body!==null?this.body.apply(w):null)},Qe.prototype.apply=function(w){var S,y={};for(S in this.links)!this.links.hasOwnProperty(S)||(y[S]=this.links[S].apply(w));return new Qe(y)},H.prototype.select=function(){for(var w=this;w.indicator===",/2";)w=w.args[0];return w},H.prototype.replace=function(w){return this.indicator===",/2"?this.args[0].indicator===",/2"?new H(",",[this.args[0].replace(w),this.args[1]]):w===null?this.args[1]:new H(",",[w,this.args[1]]):w},H.prototype.search=function(w){if(x.type.is_term(w)&&w.ref!==void 0&&this.ref===w.ref)return!0;for(var S=0;SS&&F0&&(S=this.head_point().substitution.domain());e(S,x.format_variable(this.session.rename))!==-1;)this.session.rename++;if(w.id==="_")return new Ie(x.format_variable(this.session.rename));this.session.renamed_variables[w.id]=x.format_variable(this.session.rename)}return new Ie(this.session.renamed_variables[w.id])},Te.prototype.next_free_variable=function(){return this.thread.next_free_variable()},Je.prototype.next_free_variable=function(){this.session.rename++;var w=[];for(this.points.length>0&&(w=this.head_point().substitution.domain());e(w,x.format_variable(this.session.rename))!==-1;)this.session.rename++;return new Ie(x.format_variable(this.session.rename))},Te.prototype.is_public_predicate=function(w){return!this.public_predicates.hasOwnProperty(w)||this.public_predicates[w]===!0},Je.prototype.is_public_predicate=function(w){return this.session.is_public_predicate(w)},Te.prototype.is_multifile_predicate=function(w){return this.multifile_predicates.hasOwnProperty(w)&&this.multifile_predicates[w]===!0},Je.prototype.is_multifile_predicate=function(w){return this.session.is_multifile_predicate(w)},Te.prototype.prepend=function(w){return this.thread.prepend(w)},Je.prototype.prepend=function(w){for(var S=w.length-1;S>=0;S--)this.points.push(w[S])},Te.prototype.success=function(w,S){return this.thread.success(w,S)},Je.prototype.success=function(w,y){var y=typeof y>"u"?w:y;this.prepend([new be(w.goal.replace(null),w.substitution,y)])},Te.prototype.throw_error=function(w){return this.thread.throw_error(w)},Je.prototype.throw_error=function(w){this.prepend([new be(new H("throw",[w]),new Qe,null,null)])},Te.prototype.step_rule=function(w,S){return this.thread.step_rule(w,S)},Je.prototype.step_rule=function(w,S){var y=S.indicator;if(w==="user"&&(w=null),w===null&&this.session.rules.hasOwnProperty(y))return this.session.rules[y];for(var F=w===null?this.session.modules:e(this.session.modules,w)===-1?[]:[w],z=0;z1)&&this.again()},Te.prototype.answers=function(w,S,y){return this.thread.answers(w,S,y)},Je.prototype.answers=function(w,S,y){var F=S||1e3,z=this;if(S<=0){y&&y();return}this.answer(function(X){w(X),X!==!1?setTimeout(function(){z.answers(w,S-1,y)},1):y&&y()})},Te.prototype.again=function(w){return this.thread.again(w)},Je.prototype.again=function(w){for(var S,y=Date.now();this.__calls.length>0;){for(this.warnings=[],w!==!1&&(this.current_limit=this.session.limit);this.current_limit>0&&this.points.length>0&&this.head_point().goal!==null&&!x.type.is_error(this.head_point().goal);)if(this.current_limit--,this.step()===!0)return;var F=Date.now();this.cpu_time_last=F-y,this.cpu_time+=this.cpu_time_last;var z=this.__calls.shift();this.current_limit<=0?z(null):this.points.length===0?z(!1):x.type.is_error(this.head_point().goal)?(S=this.session.format_error(this.points.pop()),this.points=[],z(S)):(this.debugger&&this.debugger_states.push(this.head_point()),S=this.session.format_success(this.points.pop()),z(S))}},Te.prototype.unfold=function(w){if(w.body===null)return!1;var S=w.head,y=w.body,F=y.select(),z=new Je(this),X=[];z.add_goal(F),z.step();for(var Z=z.points.length-1;Z>=0;Z--){var ie=z.points[Z],Se=S.apply(ie.substitution),Ne=y.replace(ie.goal);Ne!==null&&(Ne=Ne.apply(ie.substitution)),X.push(new _e(Se,Ne))}var ot=this.rules[S.indicator],dt=e(ot,w);return X.length>0&&dt!==-1?(ot.splice.apply(ot,[dt,1].concat(X)),!0):!1},Je.prototype.unfold=function(w){return this.session.unfold(w)},Ie.prototype.interpret=function(w){return x.error.instantiation(w.level)},ke.prototype.interpret=function(w){return this},H.prototype.interpret=function(w){return x.type.is_unitary_list(this)?this.args[0].interpret(w):x.operate(w,this)},Ie.prototype.compare=function(w){return this.idw.id?1:0},ke.prototype.compare=function(w){if(this.value===w.value&&this.is_float===w.is_float)return 0;if(this.valuew.value)return 1},H.prototype.compare=function(w){if(this.args.lengthw.args.length||this.args.length===w.args.length&&this.id>w.id)return 1;for(var S=0;SF)return 1;if(w.constructor===ke){if(w.is_float&&S.is_float)return 0;if(w.is_float)return-1;if(S.is_float)return 1}return 0},is_substitution:function(w){return w instanceof Qe},is_state:function(w){return w instanceof be},is_rule:function(w){return w instanceof _e},is_variable:function(w){return w instanceof Ie},is_stream:function(w){return w instanceof Re},is_anonymous_var:function(w){return w instanceof Ie&&w.id==="_"},is_callable:function(w){return w instanceof H},is_number:function(w){return w instanceof ke},is_integer:function(w){return w instanceof ke&&!w.is_float},is_float:function(w){return w instanceof ke&&w.is_float},is_term:function(w){return w instanceof H},is_atom:function(w){return w instanceof H&&w.args.length===0},is_ground:function(w){if(w instanceof Ie)return!1;if(w instanceof H){for(var S=0;S0},is_list:function(w){return w instanceof H&&(w.indicator==="[]/0"||w.indicator==="./2")},is_empty_list:function(w){return w instanceof H&&w.indicator==="[]/0"},is_non_empty_list:function(w){return w instanceof H&&w.indicator==="./2"},is_fully_list:function(w){for(;w instanceof H&&w.indicator==="./2";)w=w.args[1];return w instanceof Ie||w instanceof H&&w.indicator==="[]/0"},is_instantiated_list:function(w){for(;w instanceof H&&w.indicator==="./2";)w=w.args[1];return w instanceof H&&w.indicator==="[]/0"},is_unitary_list:function(w){return w instanceof H&&w.indicator==="./2"&&w.args[1]instanceof H&&w.args[1].indicator==="[]/0"},is_character:function(w){return w instanceof H&&(w.id.length===1||w.id.length>0&&w.id.length<=2&&n(w.id,0)>=65536)},is_character_code:function(w){return w instanceof ke&&!w.is_float&&w.value>=0&&w.value<=1114111},is_byte:function(w){return w instanceof ke&&!w.is_float&&w.value>=0&&w.value<=255},is_operator:function(w){return w instanceof H&&x.arithmetic.evaluation[w.indicator]},is_directive:function(w){return w instanceof H&&x.directive[w.indicator]!==void 0},is_builtin:function(w){return w instanceof H&&x.predicate[w.indicator]!==void 0},is_error:function(w){return w instanceof H&&w.indicator==="throw/1"},is_predicate_indicator:function(w){return w instanceof H&&w.indicator==="//2"&&w.args[0]instanceof H&&w.args[0].args.length===0&&w.args[1]instanceof ke&&w.args[1].is_float===!1},is_flag:function(w){return w instanceof H&&w.args.length===0&&x.flag[w.id]!==void 0},is_value_flag:function(w,S){if(!x.type.is_flag(w))return!1;for(var y in x.flag[w.id].allowed)if(!!x.flag[w.id].allowed.hasOwnProperty(y)&&x.flag[w.id].allowed[y].equals(S))return!0;return!1},is_io_mode:function(w){return x.type.is_atom(w)&&["read","write","append"].indexOf(w.id)!==-1},is_stream_option:function(w){return x.type.is_term(w)&&(w.indicator==="alias/1"&&x.type.is_atom(w.args[0])||w.indicator==="reposition/1"&&x.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false")||w.indicator==="type/1"&&x.type.is_atom(w.args[0])&&(w.args[0].id==="text"||w.args[0].id==="binary")||w.indicator==="eof_action/1"&&x.type.is_atom(w.args[0])&&(w.args[0].id==="error"||w.args[0].id==="eof_code"||w.args[0].id==="reset"))},is_stream_position:function(w){return x.type.is_integer(w)&&w.value>=0||x.type.is_atom(w)&&(w.id==="end_of_stream"||w.id==="past_end_of_stream")},is_stream_property:function(w){return x.type.is_term(w)&&(w.indicator==="input/0"||w.indicator==="output/0"||w.indicator==="alias/1"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0]))||w.indicator==="file_name/1"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0]))||w.indicator==="position/1"&&(x.type.is_variable(w.args[0])||x.type.is_stream_position(w.args[0]))||w.indicator==="reposition/1"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false"))||w.indicator==="type/1"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0])&&(w.args[0].id==="text"||w.args[0].id==="binary"))||w.indicator==="mode/1"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0])&&(w.args[0].id==="read"||w.args[0].id==="write"||w.args[0].id==="append"))||w.indicator==="eof_action/1"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0])&&(w.args[0].id==="error"||w.args[0].id==="eof_code"||w.args[0].id==="reset"))||w.indicator==="end_of_stream/1"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0])&&(w.args[0].id==="at"||w.args[0].id==="past"||w.args[0].id==="not")))},is_streamable:function(w){return w.__proto__.stream!==void 0},is_read_option:function(w){return x.type.is_term(w)&&["variables/1","variable_names/1","singletons/1"].indexOf(w.indicator)!==-1},is_write_option:function(w){return x.type.is_term(w)&&(w.indicator==="quoted/1"&&x.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false")||w.indicator==="ignore_ops/1"&&x.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false")||w.indicator==="numbervars/1"&&x.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false"))},is_close_option:function(w){return x.type.is_term(w)&&w.indicator==="force/1"&&x.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false")},is_modifiable_flag:function(w){return x.type.is_flag(w)&&x.flag[w.id].changeable},is_module:function(w){return w instanceof H&&w.indicator==="library/1"&&w.args[0]instanceof H&&w.args[0].args.length===0&&x.module[w.args[0].id]!==void 0}},arithmetic:{evaluation:{"e/0":{type_args:null,type_result:!0,fn:function(w){return Math.E}},"pi/0":{type_args:null,type_result:!0,fn:function(w){return Math.PI}},"tau/0":{type_args:null,type_result:!0,fn:function(w){return 2*Math.PI}},"epsilon/0":{type_args:null,type_result:!0,fn:function(w){return Number.EPSILON}},"+/1":{type_args:null,type_result:null,fn:function(w,S){return w}},"-/1":{type_args:null,type_result:null,fn:function(w,S){return-w}},"\\/1":{type_args:!1,type_result:!1,fn:function(w,S){return~w}},"abs/1":{type_args:null,type_result:null,fn:function(w,S){return Math.abs(w)}},"sign/1":{type_args:null,type_result:null,fn:function(w,S){return Math.sign(w)}},"float_integer_part/1":{type_args:!0,type_result:!1,fn:function(w,S){return parseInt(w)}},"float_fractional_part/1":{type_args:!0,type_result:!0,fn:function(w,S){return w-parseInt(w)}},"float/1":{type_args:null,type_result:!0,fn:function(w,S){return parseFloat(w)}},"floor/1":{type_args:!0,type_result:!1,fn:function(w,S){return Math.floor(w)}},"truncate/1":{type_args:!0,type_result:!1,fn:function(w,S){return parseInt(w)}},"round/1":{type_args:!0,type_result:!1,fn:function(w,S){return Math.round(w)}},"ceiling/1":{type_args:!0,type_result:!1,fn:function(w,S){return Math.ceil(w)}},"sin/1":{type_args:null,type_result:!0,fn:function(w,S){return Math.sin(w)}},"cos/1":{type_args:null,type_result:!0,fn:function(w,S){return Math.cos(w)}},"tan/1":{type_args:null,type_result:!0,fn:function(w,S){return Math.tan(w)}},"asin/1":{type_args:null,type_result:!0,fn:function(w,S){return Math.asin(w)}},"acos/1":{type_args:null,type_result:!0,fn:function(w,S){return Math.acos(w)}},"atan/1":{type_args:null,type_result:!0,fn:function(w,S){return Math.atan(w)}},"atan2/2":{type_args:null,type_result:!0,fn:function(w,S,y){return Math.atan2(w,S)}},"exp/1":{type_args:null,type_result:!0,fn:function(w,S){return Math.exp(w)}},"sqrt/1":{type_args:null,type_result:!0,fn:function(w,S){return Math.sqrt(w)}},"log/1":{type_args:null,type_result:!0,fn:function(w,S){return w>0?Math.log(w):x.error.evaluation("undefined",S.__call_indicator)}},"+/2":{type_args:null,type_result:null,fn:function(w,S,y){return w+S}},"-/2":{type_args:null,type_result:null,fn:function(w,S,y){return w-S}},"*/2":{type_args:null,type_result:null,fn:function(w,S,y){return w*S}},"//2":{type_args:null,type_result:!0,fn:function(w,S,y){return S?w/S:x.error.evaluation("zero_division",y.__call_indicator)}},"///2":{type_args:!1,type_result:!1,fn:function(w,S,y){return S?parseInt(w/S):x.error.evaluation("zero_division",y.__call_indicator)}},"**/2":{type_args:null,type_result:!0,fn:function(w,S,y){return Math.pow(w,S)}},"^/2":{type_args:null,type_result:null,fn:function(w,S,y){return Math.pow(w,S)}},"<>/2":{type_args:!1,type_result:!1,fn:function(w,S,y){return w>>S}},"/\\/2":{type_args:!1,type_result:!1,fn:function(w,S,y){return w&S}},"\\//2":{type_args:!1,type_result:!1,fn:function(w,S,y){return w|S}},"xor/2":{type_args:!1,type_result:!1,fn:function(w,S,y){return w^S}},"rem/2":{type_args:!1,type_result:!1,fn:function(w,S,y){return S?w%S:x.error.evaluation("zero_division",y.__call_indicator)}},"mod/2":{type_args:!1,type_result:!1,fn:function(w,S,y){return S?w-parseInt(w/S)*S:x.error.evaluation("zero_division",y.__call_indicator)}},"max/2":{type_args:null,type_result:null,fn:function(w,S,y){return Math.max(w,S)}},"min/2":{type_args:null,type_result:null,fn:function(w,S,y){return Math.min(w,S)}}}},directive:{"dynamic/1":function(w,S){var y=S.args[0];if(x.type.is_variable(y))w.throw_error(x.error.instantiation(S.indicator));else if(!x.type.is_compound(y)||y.indicator!=="//2")w.throw_error(x.error.type("predicate_indicator",y,S.indicator));else if(x.type.is_variable(y.args[0])||x.type.is_variable(y.args[1]))w.throw_error(x.error.instantiation(S.indicator));else if(!x.type.is_atom(y.args[0]))w.throw_error(x.error.type("atom",y.args[0],S.indicator));else if(!x.type.is_integer(y.args[1]))w.throw_error(x.error.type("integer",y.args[1],S.indicator));else{var F=S.args[0].args[0].id+"/"+S.args[0].args[1].value;w.session.public_predicates[F]=!0,w.session.rules[F]||(w.session.rules[F]=[])}},"multifile/1":function(w,S){var y=S.args[0];x.type.is_variable(y)?w.throw_error(x.error.instantiation(S.indicator)):!x.type.is_compound(y)||y.indicator!=="//2"?w.throw_error(x.error.type("predicate_indicator",y,S.indicator)):x.type.is_variable(y.args[0])||x.type.is_variable(y.args[1])?w.throw_error(x.error.instantiation(S.indicator)):x.type.is_atom(y.args[0])?x.type.is_integer(y.args[1])?w.session.multifile_predicates[S.args[0].args[0].id+"/"+S.args[0].args[1].value]=!0:w.throw_error(x.error.type("integer",y.args[1],S.indicator)):w.throw_error(x.error.type("atom",y.args[0],S.indicator))},"set_prolog_flag/2":function(w,S){var y=S.args[0],F=S.args[1];x.type.is_variable(y)||x.type.is_variable(F)?w.throw_error(x.error.instantiation(S.indicator)):x.type.is_atom(y)?x.type.is_flag(y)?x.type.is_value_flag(y,F)?x.type.is_modifiable_flag(y)?w.session.flag[y.id]=F:w.throw_error(x.error.permission("modify","flag",y)):w.throw_error(x.error.domain("flag_value",new H("+",[y,F]),S.indicator)):w.throw_error(x.error.domain("prolog_flag",y,S.indicator)):w.throw_error(x.error.type("atom",y,S.indicator))},"use_module/1":function(w,S){var y=S.args[0];if(x.type.is_variable(y))w.throw_error(x.error.instantiation(S.indicator));else if(!x.type.is_term(y))w.throw_error(x.error.type("term",y,S.indicator));else if(x.type.is_module(y)){var F=y.args[0].id;e(w.session.modules,F)===-1&&w.session.modules.push(F)}},"char_conversion/2":function(w,S){var y=S.args[0],F=S.args[1];x.type.is_variable(y)||x.type.is_variable(F)?w.throw_error(x.error.instantiation(S.indicator)):x.type.is_character(y)?x.type.is_character(F)?y.id===F.id?delete w.session.__char_conversion[y.id]:w.session.__char_conversion[y.id]=F.id:w.throw_error(x.error.type("character",F,S.indicator)):w.throw_error(x.error.type("character",y,S.indicator))},"op/3":function(w,S){var y=S.args[0],F=S.args[1],z=S.args[2];if(x.type.is_variable(y)||x.type.is_variable(F)||x.type.is_variable(z))w.throw_error(x.error.instantiation(S.indicator));else if(!x.type.is_integer(y))w.throw_error(x.error.type("integer",y,S.indicator));else if(!x.type.is_atom(F))w.throw_error(x.error.type("atom",F,S.indicator));else if(!x.type.is_atom(z))w.throw_error(x.error.type("atom",z,S.indicator));else if(y.value<0||y.value>1200)w.throw_error(x.error.domain("operator_priority",y,S.indicator));else if(z.id===",")w.throw_error(x.error.permission("modify","operator",z,S.indicator));else if(z.id==="|"&&(y.value<1001||F.id.length!==3))w.throw_error(x.error.permission("modify","operator",z,S.indicator));else if(["fy","fx","yf","xf","xfx","yfx","xfy"].indexOf(F.id)===-1)w.throw_error(x.error.domain("operator_specifier",F,S.indicator));else{var X={prefix:null,infix:null,postfix:null};for(var Z in w.session.__operators)if(!!w.session.__operators.hasOwnProperty(Z)){var ie=w.session.__operators[Z][z.id];ie&&(e(ie,"fx")!==-1&&(X.prefix={priority:Z,type:"fx"}),e(ie,"fy")!==-1&&(X.prefix={priority:Z,type:"fy"}),e(ie,"xf")!==-1&&(X.postfix={priority:Z,type:"xf"}),e(ie,"yf")!==-1&&(X.postfix={priority:Z,type:"yf"}),e(ie,"xfx")!==-1&&(X.infix={priority:Z,type:"xfx"}),e(ie,"xfy")!==-1&&(X.infix={priority:Z,type:"xfy"}),e(ie,"yfx")!==-1&&(X.infix={priority:Z,type:"yfx"}))}var Se;switch(F.id){case"fy":case"fx":Se="prefix";break;case"yf":case"xf":Se="postfix";break;default:Se="infix";break}if(((X.prefix&&Se==="prefix"||X.postfix&&Se==="postfix"||X.infix&&Se==="infix")&&X[Se].type!==F.id||X.infix&&Se==="postfix"||X.postfix&&Se==="infix")&&y.value!==0)w.throw_error(x.error.permission("create","operator",z,S.indicator));else return X[Se]&&(Ee(w.session.__operators[X[Se].priority][z.id],F.id),w.session.__operators[X[Se].priority][z.id].length===0&&delete w.session.__operators[X[Se].priority][z.id]),y.value>0&&(w.session.__operators[y.value]||(w.session.__operators[y.value.toString()]={}),w.session.__operators[y.value][z.id]||(w.session.__operators[y.value][z.id]=[]),w.session.__operators[y.value][z.id].push(F.id)),!0}}},predicate:{"op/3":function(w,S,y){x.directive["op/3"](w,y)&&w.success(S)},"current_op/3":function(w,S,y){var F=y.args[0],z=y.args[1],X=y.args[2],Z=[];for(var ie in w.session.__operators)for(var Se in w.session.__operators[ie])for(var Ne=0;Ne/2"){var F=w.points,z=w.session.format_success,X=w.session.format_error;w.session.format_success=function(Ne){return Ne.substitution},w.session.format_error=function(Ne){return Ne.goal},w.points=[new be(y.args[0].args[0],S.substitution,S)];var Z=function(Ne){w.points=F,w.session.format_success=z,w.session.format_error=X,Ne===!1?w.prepend([new be(S.goal.replace(y.args[1]),S.substitution,S)]):x.type.is_error(Ne)?w.throw_error(Ne.args[0]):Ne===null?(w.prepend([S]),w.__calls.shift()(null)):w.prepend([new be(S.goal.replace(y.args[0].args[1]).apply(Ne),S.substitution.apply(Ne),S)])};w.__calls.unshift(Z)}else{var ie=new be(S.goal.replace(y.args[0]),S.substitution,S),Se=new be(S.goal.replace(y.args[1]),S.substitution,S);w.prepend([ie,Se])}},"!/0":function(w,S,y){var F,z,X=[];for(F=S,z=null;F.parent!==null&&F.parent.goal.search(y);)if(z=F,F=F.parent,F.goal!==null){var Z=F.goal.select();if(Z&&Z.id==="call"&&Z.search(y)){F=z;break}}for(var ie=w.points.length-1;ie>=0;ie--){for(var Se=w.points[ie],Ne=Se.parent;Ne!==null&&Ne!==F.parent;)Ne=Ne.parent;Ne===null&&Ne!==F.parent&&X.push(Se)}w.points=X.reverse(),w.success(S)},"\\+/1":function(w,S,y){var F=y.args[0];x.type.is_variable(F)?w.throw_error(x.error.instantiation(w.level)):x.type.is_callable(F)?w.prepend([new be(S.goal.replace(new H(",",[new H(",",[new H("call",[F]),new H("!",[])]),new H("fail",[])])),S.substitution,S),new be(S.goal.replace(null),S.substitution,S)]):w.throw_error(x.error.type("callable",F,w.level))},"->/2":function(w,S,y){var F=S.goal.replace(new H(",",[y.args[0],new H(",",[new H("!"),y.args[1]])]));w.prepend([new be(F,S.substitution,S)])},"fail/0":function(w,S,y){},"false/0":function(w,S,y){},"true/0":function(w,S,y){w.success(S)},"call/1":ne(1),"call/2":ne(2),"call/3":ne(3),"call/4":ne(4),"call/5":ne(5),"call/6":ne(6),"call/7":ne(7),"call/8":ne(8),"once/1":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(",",[new H("call",[F]),new H("!",[])])),S.substitution,S)])},"forall/2":function(w,S,y){var F=y.args[0],z=y.args[1];w.prepend([new be(S.goal.replace(new H("\\+",[new H(",",[new H("call",[F]),new H("\\+",[new H("call",[z])])])])),S.substitution,S)])},"repeat/0":function(w,S,y){w.prepend([new be(S.goal.replace(null),S.substitution,S),S])},"throw/1":function(w,S,y){x.type.is_variable(y.args[0])?w.throw_error(x.error.instantiation(w.level)):w.throw_error(y.args[0])},"catch/3":function(w,S,y){var F=w.points;w.points=[],w.prepend([new be(y.args[0],S.substitution,S)]);var z=w.session.format_success,X=w.session.format_error;w.session.format_success=function(ie){return ie.substitution},w.session.format_error=function(ie){return ie.goal};var Z=function(ie){var Se=w.points;if(w.points=F,w.session.format_success=z,w.session.format_error=X,x.type.is_error(ie)){for(var Ne=[],ot=w.points.length-1;ot>=0;ot--){for(var $t=w.points[ot],dt=$t.parent;dt!==null&&dt!==S.parent;)dt=dt.parent;dt===null&&dt!==S.parent&&Ne.push($t)}w.points=Ne;var jt=w.get_flag("occurs_check").indicator==="true/0",$t=new be,xt=x.unify(ie.args[0],y.args[1],jt);xt!==null?($t.substitution=S.substitution.apply(xt),$t.goal=S.goal.replace(y.args[2]).apply(xt),$t.parent=S,w.prepend([$t])):w.throw_error(ie.args[0])}else if(ie!==!1){for(var an=ie===null?[]:[new be(S.goal.apply(ie).replace(null),S.substitution.apply(ie),S)],Qr=[],ot=Se.length-1;ot>=0;ot--){Qr.push(Se[ot]);var mr=Se[ot].goal!==null?Se[ot].goal.select():null;if(x.type.is_term(mr)&&mr.indicator==="!/0")break}var xr=o(Qr,function(Wr){return Wr.goal===null&&(Wr.goal=new H("true",[])),Wr=new be(S.goal.replace(new H("catch",[Wr.goal,y.args[1],y.args[2]])),S.substitution.apply(Wr.substitution),Wr.parent),Wr.exclude=y.args[0].variables(),Wr}).reverse();w.prepend(xr),w.prepend(an),ie===null&&(this.current_limit=0,w.__calls.shift()(null))}};w.__calls.unshift(Z)},"=/2":function(w,S,y){var F=w.get_flag("occurs_check").indicator==="true/0",z=new be,X=x.unify(y.args[0],y.args[1],F);X!==null&&(z.goal=S.goal.apply(X).replace(null),z.substitution=S.substitution.apply(X),z.parent=S,w.prepend([z]))},"unify_with_occurs_check/2":function(w,S,y){var F=new be,z=x.unify(y.args[0],y.args[1],!0);z!==null&&(F.goal=S.goal.apply(z).replace(null),F.substitution=S.substitution.apply(z),F.parent=S,w.prepend([F]))},"\\=/2":function(w,S,y){var F=w.get_flag("occurs_check").indicator==="true/0",z=x.unify(y.args[0],y.args[1],F);z===null&&w.success(S)},"subsumes_term/2":function(w,S,y){var F=w.get_flag("occurs_check").indicator==="true/0",z=x.unify(y.args[1],y.args[0],F);z!==null&&y.args[1].apply(z).equals(y.args[1])&&w.success(S)},"findall/3":function(w,S,y){var F=y.args[0],z=y.args[1],X=y.args[2];if(x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(z))w.throw_error(x.error.type("callable",z,y.indicator));else if(!x.type.is_variable(X)&&!x.type.is_list(X))w.throw_error(x.error.type("list",X,y.indicator));else{var Z=w.next_free_variable(),ie=new H(",",[z,new H("=",[Z,F])]),Se=w.points,Ne=w.session.limit,ot=w.session.format_success;w.session.format_success=function($t){return $t.substitution},w.add_goal(ie,!0,S);var dt=[],jt=function($t){if($t!==!1&&$t!==null&&!x.type.is_error($t))w.__calls.unshift(jt),dt.push($t.links[Z.id]),w.session.limit=w.current_limit;else if(w.points=Se,w.session.limit=Ne,w.session.format_success=ot,x.type.is_error($t))w.throw_error($t.args[0]);else if(w.current_limit>0){for(var xt=new H("[]"),an=dt.length-1;an>=0;an--)xt=new H(".",[dt[an],xt]);w.prepend([new be(S.goal.replace(new H("=",[X,xt])),S.substitution,S)])}};w.__calls.unshift(jt)}},"bagof/3":function(w,S,y){var F,z=y.args[0],X=y.args[1],Z=y.args[2];if(x.type.is_variable(X))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(X))w.throw_error(x.error.type("callable",X,y.indicator));else if(!x.type.is_variable(Z)&&!x.type.is_list(Z))w.throw_error(x.error.type("list",Z,y.indicator));else{var ie=w.next_free_variable(),Se;X.indicator==="^/2"?(Se=X.args[0].variables(),X=X.args[1]):Se=[],Se=Se.concat(z.variables());for(var Ne=X.variables().filter(function(xr){return e(Se,xr)===-1}),ot=new H("[]"),dt=Ne.length-1;dt>=0;dt--)ot=new H(".",[new Ie(Ne[dt]),ot]);var jt=new H(",",[X,new H("=",[ie,new H(",",[ot,z])])]),$t=w.points,xt=w.session.limit,an=w.session.format_success;w.session.format_success=function(xr){return xr.substitution},w.add_goal(jt,!0,S);var Qr=[],mr=function(xr){if(xr!==!1&&xr!==null&&!x.type.is_error(xr)){w.__calls.unshift(mr);var Wr=!1,Vn=xr.links[ie.id].args[0],Ns=xr.links[ie.id].args[1];for(var Ri in Qr)if(!!Qr.hasOwnProperty(Ri)){var ps=Qr[Ri];if(ps.variables.equals(Vn)){ps.answers.push(Ns),Wr=!0;break}}Wr||Qr.push({variables:Vn,answers:[Ns]}),w.session.limit=w.current_limit}else if(w.points=$t,w.session.limit=xt,w.session.format_success=an,x.type.is_error(xr))w.throw_error(xr.args[0]);else if(w.current_limit>0){for(var io=[],Si=0;Si=0;so--)Ls=new H(".",[xr[so],Ls]);io.push(new be(S.goal.replace(new H(",",[new H("=",[ot,Qr[Si].variables]),new H("=",[Z,Ls])])),S.substitution,S))}w.prepend(io)}};w.__calls.unshift(mr)}},"setof/3":function(w,S,y){var F,z=y.args[0],X=y.args[1],Z=y.args[2];if(x.type.is_variable(X))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(X))w.throw_error(x.error.type("callable",X,y.indicator));else if(!x.type.is_variable(Z)&&!x.type.is_list(Z))w.throw_error(x.error.type("list",Z,y.indicator));else{var ie=w.next_free_variable(),Se;X.indicator==="^/2"?(Se=X.args[0].variables(),X=X.args[1]):Se=[],Se=Se.concat(z.variables());for(var Ne=X.variables().filter(function(xr){return e(Se,xr)===-1}),ot=new H("[]"),dt=Ne.length-1;dt>=0;dt--)ot=new H(".",[new Ie(Ne[dt]),ot]);var jt=new H(",",[X,new H("=",[ie,new H(",",[ot,z])])]),$t=w.points,xt=w.session.limit,an=w.session.format_success;w.session.format_success=function(xr){return xr.substitution},w.add_goal(jt,!0,S);var Qr=[],mr=function(xr){if(xr!==!1&&xr!==null&&!x.type.is_error(xr)){w.__calls.unshift(mr);var Wr=!1,Vn=xr.links[ie.id].args[0],Ns=xr.links[ie.id].args[1];for(var Ri in Qr)if(!!Qr.hasOwnProperty(Ri)){var ps=Qr[Ri];if(ps.variables.equals(Vn)){ps.answers.push(Ns),Wr=!0;break}}Wr||Qr.push({variables:Vn,answers:[Ns]}),w.session.limit=w.current_limit}else if(w.points=$t,w.session.limit=xt,w.session.format_success=an,x.type.is_error(xr))w.throw_error(xr.args[0]);else if(w.current_limit>0){for(var io=[],Si=0;Si=0;so--)Ls=new H(".",[xr[so],Ls]);io.push(new be(S.goal.replace(new H(",",[new H("=",[ot,Qr[Si].variables]),new H("=",[Z,Ls])])),S.substitution,S))}w.prepend(io)}};w.__calls.unshift(mr)}},"functor/3":function(w,S,y){var F,z=y.args[0],X=y.args[1],Z=y.args[2];if(x.type.is_variable(z)&&(x.type.is_variable(X)||x.type.is_variable(Z)))w.throw_error(x.error.instantiation("functor/3"));else if(!x.type.is_variable(Z)&&!x.type.is_integer(Z))w.throw_error(x.error.type("integer",y.args[2],"functor/3"));else if(!x.type.is_variable(X)&&!x.type.is_atomic(X))w.throw_error(x.error.type("atomic",y.args[1],"functor/3"));else if(x.type.is_integer(X)&&x.type.is_integer(Z)&&Z.value!==0)w.throw_error(x.error.type("atom",y.args[1],"functor/3"));else if(x.type.is_variable(z)){if(y.args[2].value>=0){for(var ie=[],Se=0;Se0&&F<=y.args[1].args.length){var z=new H("=",[y.args[1].args[F-1],y.args[2]]);w.prepend([new be(S.goal.replace(z),S.substitution,S)])}}},"=../2":function(w,S,y){var F;if(x.type.is_variable(y.args[0])&&(x.type.is_variable(y.args[1])||x.type.is_non_empty_list(y.args[1])&&x.type.is_variable(y.args[1].args[0])))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_fully_list(y.args[1]))w.throw_error(x.error.type("list",y.args[1],y.indicator));else if(x.type.is_variable(y.args[0])){if(!x.type.is_variable(y.args[1])){var X=[];for(F=y.args[1].args[1];F.indicator==="./2";)X.push(F.args[0]),F=F.args[1];x.type.is_variable(y.args[0])&&x.type.is_variable(F)?w.throw_error(x.error.instantiation(y.indicator)):X.length===0&&x.type.is_compound(y.args[1].args[0])?w.throw_error(x.error.type("atomic",y.args[1].args[0],y.indicator)):X.length>0&&(x.type.is_compound(y.args[1].args[0])||x.type.is_number(y.args[1].args[0]))?w.throw_error(x.error.type("atom",y.args[1].args[0],y.indicator)):X.length===0?w.prepend([new be(S.goal.replace(new H("=",[y.args[1].args[0],y.args[0]],S)),S.substitution,S)]):w.prepend([new be(S.goal.replace(new H("=",[new H(y.args[1].args[0].id,X),y.args[0]])),S.substitution,S)])}}else{if(x.type.is_atomic(y.args[0]))F=new H(".",[y.args[0],new H("[]")]);else{F=new H("[]");for(var z=y.args[0].args.length-1;z>=0;z--)F=new H(".",[y.args[0].args[z],F]);F=new H(".",[new H(y.args[0].id),F])}w.prepend([new be(S.goal.replace(new H("=",[F,y.args[1]])),S.substitution,S)])}},"copy_term/2":function(w,S,y){var F=y.args[0].rename(w);w.prepend([new be(S.goal.replace(new H("=",[F,y.args[1]])),S.substitution,S.parent)])},"term_variables/2":function(w,S,y){var F=y.args[0],z=y.args[1];if(!x.type.is_fully_list(z))w.throw_error(x.error.type("list",z,y.indicator));else{var X=g(o(De(F.variables()),function(Z){return new Ie(Z)}));w.prepend([new be(S.goal.replace(new H("=",[z,X])),S.substitution,S)])}},"clause/2":function(w,S,y){if(x.type.is_variable(y.args[0]))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(y.args[0]))w.throw_error(x.error.type("callable",y.args[0],y.indicator));else if(!x.type.is_variable(y.args[1])&&!x.type.is_callable(y.args[1]))w.throw_error(x.error.type("callable",y.args[1],y.indicator));else if(w.session.rules[y.args[0].indicator]!==void 0)if(w.is_public_predicate(y.args[0].indicator)){var F=[];for(var z in w.session.rules[y.args[0].indicator])if(!!w.session.rules[y.args[0].indicator].hasOwnProperty(z)){var X=w.session.rules[y.args[0].indicator][z];w.session.renamed_variables={},X=X.rename(w),X.body===null&&(X.body=new H("true"));var Z=new H(",",[new H("=",[X.head,y.args[0]]),new H("=",[X.body,y.args[1]])]);F.push(new be(S.goal.replace(Z),S.substitution,S))}w.prepend(F)}else w.throw_error(x.error.permission("access","private_procedure",y.args[0].indicator,y.indicator))},"current_predicate/1":function(w,S,y){var F=y.args[0];if(!x.type.is_variable(F)&&(!x.type.is_compound(F)||F.indicator!=="//2"))w.throw_error(x.error.type("predicate_indicator",F,y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_variable(F.args[0])&&!x.type.is_atom(F.args[0]))w.throw_error(x.error.type("atom",F.args[0],y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_variable(F.args[1])&&!x.type.is_integer(F.args[1]))w.throw_error(x.error.type("integer",F.args[1],y.indicator));else{var z=[];for(var X in w.session.rules)if(!!w.session.rules.hasOwnProperty(X)){var Z=X.lastIndexOf("/"),ie=X.substr(0,Z),Se=parseInt(X.substr(Z+1,X.length-(Z+1))),Ne=new H("/",[new H(ie),new ke(Se,!1)]),ot=new H("=",[Ne,F]);z.push(new be(S.goal.replace(ot),S.substitution,S))}w.prepend(z)}},"asserta/1":function(w,S,y){if(x.type.is_variable(y.args[0]))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(y.args[0]))w.throw_error(x.error.type("callable",y.args[0],y.indicator));else{var F,z;y.args[0].indicator===":-/2"?(F=y.args[0].args[0],z=Pe(y.args[0].args[1])):(F=y.args[0],z=null),x.type.is_callable(F)?z!==null&&!x.type.is_callable(z)?w.throw_error(x.error.type("callable",z,y.indicator)):w.is_public_predicate(F.indicator)?(w.session.rules[F.indicator]===void 0&&(w.session.rules[F.indicator]=[]),w.session.public_predicates[F.indicator]=!0,w.session.rules[F.indicator]=[new _e(F,z,!0)].concat(w.session.rules[F.indicator]),w.success(S)):w.throw_error(x.error.permission("modify","static_procedure",F.indicator,y.indicator)):w.throw_error(x.error.type("callable",F,y.indicator))}},"assertz/1":function(w,S,y){if(x.type.is_variable(y.args[0]))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(y.args[0]))w.throw_error(x.error.type("callable",y.args[0],y.indicator));else{var F,z;y.args[0].indicator===":-/2"?(F=y.args[0].args[0],z=Pe(y.args[0].args[1])):(F=y.args[0],z=null),x.type.is_callable(F)?z!==null&&!x.type.is_callable(z)?w.throw_error(x.error.type("callable",z,y.indicator)):w.is_public_predicate(F.indicator)?(w.session.rules[F.indicator]===void 0&&(w.session.rules[F.indicator]=[]),w.session.public_predicates[F.indicator]=!0,w.session.rules[F.indicator].push(new _e(F,z,!0)),w.success(S)):w.throw_error(x.error.permission("modify","static_procedure",F.indicator,y.indicator)):w.throw_error(x.error.type("callable",F,y.indicator))}},"retract/1":function(w,S,y){if(x.type.is_variable(y.args[0]))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(y.args[0]))w.throw_error(x.error.type("callable",y.args[0],y.indicator));else{var F,z;if(y.args[0].indicator===":-/2"?(F=y.args[0].args[0],z=y.args[0].args[1]):(F=y.args[0],z=new H("true")),typeof S.retract>"u")if(w.is_public_predicate(F.indicator)){if(w.session.rules[F.indicator]!==void 0){for(var X=[],Z=0;Zw.get_flag("max_arity").value)w.throw_error(x.error.representation("max_arity",y.indicator));else{var F=y.args[0].args[0].id+"/"+y.args[0].args[1].value;w.is_public_predicate(F)?(delete w.session.rules[F],w.success(S)):w.throw_error(x.error.permission("modify","static_procedure",F,y.indicator))}},"atom_length/2":function(w,S,y){if(x.type.is_variable(y.args[0]))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_atom(y.args[0]))w.throw_error(x.error.type("atom",y.args[0],y.indicator));else if(!x.type.is_variable(y.args[1])&&!x.type.is_integer(y.args[1]))w.throw_error(x.error.type("integer",y.args[1],y.indicator));else if(x.type.is_integer(y.args[1])&&y.args[1].value<0)w.throw_error(x.error.domain("not_less_than_zero",y.args[1],y.indicator));else{var F=new ke(y.args[0].id.length,!1);w.prepend([new be(S.goal.replace(new H("=",[F,y.args[1]])),S.substitution,S)])}},"atom_concat/3":function(w,S,y){var F,z,X=y.args[0],Z=y.args[1],ie=y.args[2];if(x.type.is_variable(ie)&&(x.type.is_variable(X)||x.type.is_variable(Z)))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(X)&&!x.type.is_atom(X))w.throw_error(x.error.type("atom",X,y.indicator));else if(!x.type.is_variable(Z)&&!x.type.is_atom(Z))w.throw_error(x.error.type("atom",Z,y.indicator));else if(!x.type.is_variable(ie)&&!x.type.is_atom(ie))w.throw_error(x.error.type("atom",ie,y.indicator));else{var Se=x.type.is_variable(X),Ne=x.type.is_variable(Z);if(!Se&&!Ne)z=new H("=",[ie,new H(X.id+Z.id)]),w.prepend([new be(S.goal.replace(z),S.substitution,S)]);else if(Se&&!Ne)F=ie.id.substr(0,ie.id.length-Z.id.length),F+Z.id===ie.id&&(z=new H("=",[X,new H(F)]),w.prepend([new be(S.goal.replace(z),S.substitution,S)]));else if(Ne&&!Se)F=ie.id.substr(X.id.length),X.id+F===ie.id&&(z=new H("=",[Z,new H(F)]),w.prepend([new be(S.goal.replace(z),S.substitution,S)]));else{for(var ot=[],dt=0;dt<=ie.id.length;dt++){var jt=new H(ie.id.substr(0,dt)),$t=new H(ie.id.substr(dt));z=new H(",",[new H("=",[jt,X]),new H("=",[$t,Z])]),ot.push(new be(S.goal.replace(z),S.substitution,S))}w.prepend(ot)}}},"sub_atom/5":function(w,S,y){var F,z=y.args[0],X=y.args[1],Z=y.args[2],ie=y.args[3],Se=y.args[4];if(x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(X)&&!x.type.is_integer(X))w.throw_error(x.error.type("integer",X,y.indicator));else if(!x.type.is_variable(Z)&&!x.type.is_integer(Z))w.throw_error(x.error.type("integer",Z,y.indicator));else if(!x.type.is_variable(ie)&&!x.type.is_integer(ie))w.throw_error(x.error.type("integer",ie,y.indicator));else if(x.type.is_integer(X)&&X.value<0)w.throw_error(x.error.domain("not_less_than_zero",X,y.indicator));else if(x.type.is_integer(Z)&&Z.value<0)w.throw_error(x.error.domain("not_less_than_zero",Z,y.indicator));else if(x.type.is_integer(ie)&&ie.value<0)w.throw_error(x.error.domain("not_less_than_zero",ie,y.indicator));else{var Ne=[],ot=[],dt=[];if(x.type.is_variable(X))for(F=0;F<=z.id.length;F++)Ne.push(F);else Ne.push(X.value);if(x.type.is_variable(Z))for(F=0;F<=z.id.length;F++)ot.push(F);else ot.push(Z.value);if(x.type.is_variable(ie))for(F=0;F<=z.id.length;F++)dt.push(F);else dt.push(ie.value);var jt=[];for(var $t in Ne)if(!!Ne.hasOwnProperty($t)){F=Ne[$t];for(var xt in ot)if(!!ot.hasOwnProperty(xt)){var an=ot[xt],Qr=z.id.length-F-an;if(e(dt,Qr)!==-1&&F+an+Qr===z.id.length){var mr=z.id.substr(F,an);if(z.id===z.id.substr(0,F)+mr+z.id.substr(F+an,Qr)){var xr=new H("=",[new H(mr),Se]),Wr=new H("=",[X,new ke(F)]),Vn=new H("=",[Z,new ke(an)]),Ns=new H("=",[ie,new ke(Qr)]),Ri=new H(",",[new H(",",[new H(",",[Wr,Vn]),Ns]),xr]);jt.push(new be(S.goal.replace(Ri),S.substitution,S))}}}}w.prepend(jt)}},"atom_chars/2":function(w,S,y){var F=y.args[0],z=y.args[1];if(x.type.is_variable(F)&&x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_atom(F))w.throw_error(x.error.type("atom",F,y.indicator));else if(x.type.is_variable(F)){for(var ie=z,Se=x.type.is_variable(F),Ne="";ie.indicator==="./2";){if(x.type.is_character(ie.args[0]))Ne+=ie.args[0].id;else if(x.type.is_variable(ie.args[0])&&Se){w.throw_error(x.error.instantiation(y.indicator));return}else if(!x.type.is_variable(ie.args[0])){w.throw_error(x.error.type("character",ie.args[0],y.indicator));return}ie=ie.args[1]}x.type.is_variable(ie)&&Se?w.throw_error(x.error.instantiation(y.indicator)):!x.type.is_empty_list(ie)&&!x.type.is_variable(ie)?w.throw_error(x.error.type("list",z,y.indicator)):w.prepend([new be(S.goal.replace(new H("=",[new H(Ne),F])),S.substitution,S)])}else{for(var X=new H("[]"),Z=F.id.length-1;Z>=0;Z--)X=new H(".",[new H(F.id.charAt(Z)),X]);w.prepend([new be(S.goal.replace(new H("=",[z,X])),S.substitution,S)])}},"atom_codes/2":function(w,S,y){var F=y.args[0],z=y.args[1];if(x.type.is_variable(F)&&x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_atom(F))w.throw_error(x.error.type("atom",F,y.indicator));else if(x.type.is_variable(F)){for(var ie=z,Se=x.type.is_variable(F),Ne="";ie.indicator==="./2";){if(x.type.is_character_code(ie.args[0]))Ne+=u(ie.args[0].value);else if(x.type.is_variable(ie.args[0])&&Se){w.throw_error(x.error.instantiation(y.indicator));return}else if(!x.type.is_variable(ie.args[0])){w.throw_error(x.error.representation("character_code",y.indicator));return}ie=ie.args[1]}x.type.is_variable(ie)&&Se?w.throw_error(x.error.instantiation(y.indicator)):!x.type.is_empty_list(ie)&&!x.type.is_variable(ie)?w.throw_error(x.error.type("list",z,y.indicator)):w.prepend([new be(S.goal.replace(new H("=",[new H(Ne),F])),S.substitution,S)])}else{for(var X=new H("[]"),Z=F.id.length-1;Z>=0;Z--)X=new H(".",[new ke(n(F.id,Z),!1),X]);w.prepend([new be(S.goal.replace(new H("=",[z,X])),S.substitution,S)])}},"char_code/2":function(w,S,y){var F=y.args[0],z=y.args[1];if(x.type.is_variable(F)&&x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_character(F))w.throw_error(x.error.type("character",F,y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_integer(z))w.throw_error(x.error.type("integer",z,y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_character_code(z))w.throw_error(x.error.representation("character_code",y.indicator));else if(x.type.is_variable(z)){var X=new ke(n(F.id,0),!1);w.prepend([new be(S.goal.replace(new H("=",[X,z])),S.substitution,S)])}else{var Z=new H(u(z.value));w.prepend([new be(S.goal.replace(new H("=",[Z,F])),S.substitution,S)])}},"number_chars/2":function(w,S,y){var F,z=y.args[0],X=y.args[1];if(x.type.is_variable(z)&&x.type.is_variable(X))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_number(z))w.throw_error(x.error.type("number",z,y.indicator));else if(!x.type.is_variable(X)&&!x.type.is_list(X))w.throw_error(x.error.type("list",X,y.indicator));else{var Z=x.type.is_variable(z);if(!x.type.is_variable(X)){var ie=X,Se=!0;for(F="";ie.indicator==="./2";){if(x.type.is_character(ie.args[0]))F+=ie.args[0].id;else if(x.type.is_variable(ie.args[0]))Se=!1;else if(!x.type.is_variable(ie.args[0])){w.throw_error(x.error.type("character",ie.args[0],y.indicator));return}ie=ie.args[1]}if(Se=Se&&x.type.is_empty_list(ie),!x.type.is_empty_list(ie)&&!x.type.is_variable(ie)){w.throw_error(x.error.type("list",X,y.indicator));return}if(!Se&&Z){w.throw_error(x.error.instantiation(y.indicator));return}else if(Se)if(x.type.is_variable(ie)&&Z){w.throw_error(x.error.instantiation(y.indicator));return}else{var Ne=w.parse(F),ot=Ne.value;!x.type.is_number(ot)||Ne.tokens[Ne.tokens.length-1].space?w.throw_error(x.error.syntax_by_predicate("parseable_number",y.indicator)):w.prepend([new be(S.goal.replace(new H("=",[z,ot])),S.substitution,S)]);return}}if(!Z){F=z.toString();for(var dt=new H("[]"),jt=F.length-1;jt>=0;jt--)dt=new H(".",[new H(F.charAt(jt)),dt]);w.prepend([new be(S.goal.replace(new H("=",[X,dt])),S.substitution,S)])}}},"number_codes/2":function(w,S,y){var F,z=y.args[0],X=y.args[1];if(x.type.is_variable(z)&&x.type.is_variable(X))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_number(z))w.throw_error(x.error.type("number",z,y.indicator));else if(!x.type.is_variable(X)&&!x.type.is_list(X))w.throw_error(x.error.type("list",X,y.indicator));else{var Z=x.type.is_variable(z);if(!x.type.is_variable(X)){var ie=X,Se=!0;for(F="";ie.indicator==="./2";){if(x.type.is_character_code(ie.args[0]))F+=u(ie.args[0].value);else if(x.type.is_variable(ie.args[0]))Se=!1;else if(!x.type.is_variable(ie.args[0])){w.throw_error(x.error.type("character_code",ie.args[0],y.indicator));return}ie=ie.args[1]}if(Se=Se&&x.type.is_empty_list(ie),!x.type.is_empty_list(ie)&&!x.type.is_variable(ie)){w.throw_error(x.error.type("list",X,y.indicator));return}if(!Se&&Z){w.throw_error(x.error.instantiation(y.indicator));return}else if(Se)if(x.type.is_variable(ie)&&Z){w.throw_error(x.error.instantiation(y.indicator));return}else{var Ne=w.parse(F),ot=Ne.value;!x.type.is_number(ot)||Ne.tokens[Ne.tokens.length-1].space?w.throw_error(x.error.syntax_by_predicate("parseable_number",y.indicator)):w.prepend([new be(S.goal.replace(new H("=",[z,ot])),S.substitution,S)]);return}}if(!Z){F=z.toString();for(var dt=new H("[]"),jt=F.length-1;jt>=0;jt--)dt=new H(".",[new ke(n(F,jt),!1),dt]);w.prepend([new be(S.goal.replace(new H("=",[X,dt])),S.substitution,S)])}}},"upcase_atom/2":function(w,S,y){var F=y.args[0],z=y.args[1];x.type.is_variable(F)?w.throw_error(x.error.instantiation(y.indicator)):x.type.is_atom(F)?!x.type.is_variable(z)&&!x.type.is_atom(z)?w.throw_error(x.error.type("atom",z,y.indicator)):w.prepend([new be(S.goal.replace(new H("=",[z,new H(F.id.toUpperCase(),[])])),S.substitution,S)]):w.throw_error(x.error.type("atom",F,y.indicator))},"downcase_atom/2":function(w,S,y){var F=y.args[0],z=y.args[1];x.type.is_variable(F)?w.throw_error(x.error.instantiation(y.indicator)):x.type.is_atom(F)?!x.type.is_variable(z)&&!x.type.is_atom(z)?w.throw_error(x.error.type("atom",z,y.indicator)):w.prepend([new be(S.goal.replace(new H("=",[z,new H(F.id.toLowerCase(),[])])),S.substitution,S)]):w.throw_error(x.error.type("atom",F,y.indicator))},"atomic_list_concat/2":function(w,S,y){var F=y.args[0],z=y.args[1];w.prepend([new be(S.goal.replace(new H("atomic_list_concat",[F,new H("",[]),z])),S.substitution,S)])},"atomic_list_concat/3":function(w,S,y){var F=y.args[0],z=y.args[1],X=y.args[2];if(x.type.is_variable(z)||x.type.is_variable(F)&&x.type.is_variable(X))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_list(F))w.throw_error(x.error.type("list",F,y.indicator));else if(!x.type.is_variable(X)&&!x.type.is_atom(X))w.throw_error(x.error.type("atom",X,y.indicator));else if(x.type.is_variable(X)){for(var ie="",Se=F;x.type.is_term(Se)&&Se.indicator==="./2";){if(!x.type.is_atom(Se.args[0])&&!x.type.is_number(Se.args[0])){w.throw_error(x.error.type("atomic",Se.args[0],y.indicator));return}ie!==""&&(ie+=z.id),x.type.is_atom(Se.args[0])?ie+=Se.args[0].id:ie+=""+Se.args[0].value,Se=Se.args[1]}ie=new H(ie,[]),x.type.is_variable(Se)?w.throw_error(x.error.instantiation(y.indicator)):!x.type.is_term(Se)||Se.indicator!=="[]/0"?w.throw_error(x.error.type("list",F,y.indicator)):w.prepend([new be(S.goal.replace(new H("=",[ie,X])),S.substitution,S)])}else{var Z=g(o(X.id.split(z.id),function(Ne){return new H(Ne,[])}));w.prepend([new be(S.goal.replace(new H("=",[Z,F])),S.substitution,S)])}},"@=/2":function(w,S,y){x.compare(y.args[0],y.args[1])>0&&w.success(S)},"@>=/2":function(w,S,y){x.compare(y.args[0],y.args[1])>=0&&w.success(S)},"compare/3":function(w,S,y){var F=y.args[0],z=y.args[1],X=y.args[2];if(!x.type.is_variable(F)&&!x.type.is_atom(F))w.throw_error(x.error.type("atom",F,y.indicator));else if(x.type.is_atom(F)&&["<",">","="].indexOf(F.id)===-1)w.throw_error(x.type.domain("order",F,y.indicator));else{var Z=x.compare(z,X);Z=Z===0?"=":Z===-1?"<":">",w.prepend([new be(S.goal.replace(new H("=",[F,new H(Z,[])])),S.substitution,S)])}},"is/2":function(w,S,y){var F=y.args[1].interpret(w);x.type.is_number(F)?w.prepend([new be(S.goal.replace(new H("=",[y.args[0],F],w.level)),S.substitution,S)]):w.throw_error(F)},"between/3":function(w,S,y){var F=y.args[0],z=y.args[1],X=y.args[2];if(x.type.is_variable(F)||x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_integer(F))w.throw_error(x.error.type("integer",F,y.indicator));else if(!x.type.is_integer(z))w.throw_error(x.error.type("integer",z,y.indicator));else if(!x.type.is_variable(X)&&!x.type.is_integer(X))w.throw_error(x.error.type("integer",X,y.indicator));else if(x.type.is_variable(X)){var Z=[new be(S.goal.replace(new H("=",[X,F])),S.substitution,S)];F.value=X.value&&w.success(S)},"succ/2":function(w,S,y){var F=y.args[0],z=y.args[1];x.type.is_variable(F)&&x.type.is_variable(z)?w.throw_error(x.error.instantiation(y.indicator)):!x.type.is_variable(F)&&!x.type.is_integer(F)?w.throw_error(x.error.type("integer",F,y.indicator)):!x.type.is_variable(z)&&!x.type.is_integer(z)?w.throw_error(x.error.type("integer",z,y.indicator)):!x.type.is_variable(F)&&F.value<0?w.throw_error(x.error.domain("not_less_than_zero",F,y.indicator)):!x.type.is_variable(z)&&z.value<0?w.throw_error(x.error.domain("not_less_than_zero",z,y.indicator)):(x.type.is_variable(z)||z.value>0)&&(x.type.is_variable(F)?w.prepend([new be(S.goal.replace(new H("=",[F,new ke(z.value-1,!1)])),S.substitution,S)]):w.prepend([new be(S.goal.replace(new H("=",[z,new ke(F.value+1,!1)])),S.substitution,S)]))},"=:=/2":function(w,S,y){var F=x.arithmetic_compare(w,y.args[0],y.args[1]);x.type.is_term(F)?w.throw_error(F):F===0&&w.success(S)},"=\\=/2":function(w,S,y){var F=x.arithmetic_compare(w,y.args[0],y.args[1]);x.type.is_term(F)?w.throw_error(F):F!==0&&w.success(S)},"/2":function(w,S,y){var F=x.arithmetic_compare(w,y.args[0],y.args[1]);x.type.is_term(F)?w.throw_error(F):F>0&&w.success(S)},">=/2":function(w,S,y){var F=x.arithmetic_compare(w,y.args[0],y.args[1]);x.type.is_term(F)?w.throw_error(F):F>=0&&w.success(S)},"var/1":function(w,S,y){x.type.is_variable(y.args[0])&&w.success(S)},"atom/1":function(w,S,y){x.type.is_atom(y.args[0])&&w.success(S)},"atomic/1":function(w,S,y){x.type.is_atomic(y.args[0])&&w.success(S)},"compound/1":function(w,S,y){x.type.is_compound(y.args[0])&&w.success(S)},"integer/1":function(w,S,y){x.type.is_integer(y.args[0])&&w.success(S)},"float/1":function(w,S,y){x.type.is_float(y.args[0])&&w.success(S)},"number/1":function(w,S,y){x.type.is_number(y.args[0])&&w.success(S)},"nonvar/1":function(w,S,y){x.type.is_variable(y.args[0])||w.success(S)},"ground/1":function(w,S,y){y.variables().length===0&&w.success(S)},"acyclic_term/1":function(w,S,y){for(var F=S.substitution.apply(S.substitution),z=y.args[0].variables(),X=0;X0?xt[xt.length-1]:null,xt!==null&&(jt=J(w,xt,0,w.__get_max_priority(),!1))}if(jt.type===p&&jt.len===xt.length-1&&an.value==="."){jt=jt.value.rename(w);var Qr=new H("=",[z,jt]);if(ie.variables){var mr=g(o(De(jt.variables()),function(xr){return new Ie(xr)}));Qr=new H(",",[Qr,new H("=",[ie.variables,mr])])}if(ie.variable_names){var mr=g(o(De(jt.variables()),function(Wr){var Vn;for(Vn in w.session.renamed_variables)if(w.session.renamed_variables.hasOwnProperty(Vn)&&w.session.renamed_variables[Vn]===Wr)break;return new H("=",[new H(Vn,[]),new Ie(Wr)])}));Qr=new H(",",[Qr,new H("=",[ie.variable_names,mr])])}if(ie.singletons){var mr=g(o(new _e(jt,null).singleton_variables(),function(Wr){var Vn;for(Vn in w.session.renamed_variables)if(w.session.renamed_variables.hasOwnProperty(Vn)&&w.session.renamed_variables[Vn]===Wr)break;return new H("=",[new H(Vn,[]),new Ie(Wr)])}));Qr=new H(",",[Qr,new H("=",[ie.singletons,mr])])}w.prepend([new be(S.goal.replace(Qr),S.substitution,S)])}else jt.type===p?w.throw_error(x.error.syntax(xt[jt.len],"unexpected token",!1)):w.throw_error(jt.value)}}},"write/1":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(",",[new H("current_output",[new Ie("S")]),new H("write",[new Ie("S"),F])])),S.substitution,S)])},"write/2":function(w,S,y){var F=y.args[0],z=y.args[1];w.prepend([new be(S.goal.replace(new H("write_term",[F,z,new H(".",[new H("quoted",[new H("false",[])]),new H(".",[new H("ignore_ops",[new H("false")]),new H(".",[new H("numbervars",[new H("true")]),new H("[]",[])])])])])),S.substitution,S)])},"writeq/1":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(",",[new H("current_output",[new Ie("S")]),new H("writeq",[new Ie("S"),F])])),S.substitution,S)])},"writeq/2":function(w,S,y){var F=y.args[0],z=y.args[1];w.prepend([new be(S.goal.replace(new H("write_term",[F,z,new H(".",[new H("quoted",[new H("true",[])]),new H(".",[new H("ignore_ops",[new H("false")]),new H(".",[new H("numbervars",[new H("true")]),new H("[]",[])])])])])),S.substitution,S)])},"write_canonical/1":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(",",[new H("current_output",[new Ie("S")]),new H("write_canonical",[new Ie("S"),F])])),S.substitution,S)])},"write_canonical/2":function(w,S,y){var F=y.args[0],z=y.args[1];w.prepend([new be(S.goal.replace(new H("write_term",[F,z,new H(".",[new H("quoted",[new H("true",[])]),new H(".",[new H("ignore_ops",[new H("true")]),new H(".",[new H("numbervars",[new H("false")]),new H("[]",[])])])])])),S.substitution,S)])},"write_term/2":function(w,S,y){var F=y.args[0],z=y.args[1];w.prepend([new be(S.goal.replace(new H(",",[new H("current_output",[new Ie("S")]),new H("write_term",[new Ie("S"),F,z])])),S.substitution,S)])},"write_term/3":function(w,S,y){var F=y.args[0],z=y.args[1],X=y.args[2],Z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(x.type.is_variable(F)||x.type.is_variable(X))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_list(X))w.throw_error(x.error.type("list",X,y.indicator));else if(!x.type.is_stream(F)&&!x.type.is_atom(F))w.throw_error(x.error.domain("stream_or_alias",F,y.indicator));else if(!x.type.is_stream(Z)||Z.stream===null)w.throw_error(x.error.existence("stream",F,y.indicator));else if(Z.input)w.throw_error(x.error.permission("output","stream",F,y.indicator));else if(Z.type==="binary")w.throw_error(x.error.permission("output","binary_stream",F,y.indicator));else if(Z.position==="past_end_of_stream"&&Z.eof_action==="error")w.throw_error(x.error.permission("output","past_end_of_stream",F,y.indicator));else{for(var ie={},Se=X,Ne;x.type.is_term(Se)&&Se.indicator==="./2";){if(Ne=Se.args[0],x.type.is_variable(Ne)){w.throw_error(x.error.instantiation(y.indicator));return}else if(!x.type.is_write_option(Ne)){w.throw_error(x.error.domain("write_option",Ne,y.indicator));return}ie[Ne.id]=Ne.args[0].id==="true",Se=Se.args[1]}if(Se.indicator!=="[]/0"){x.type.is_variable(Se)?w.throw_error(x.error.instantiation(y.indicator)):w.throw_error(x.error.type("list",X,y.indicator));return}else{ie.session=w.session;var ot=z.toString(ie);Z.stream.put(ot,Z.position),typeof Z.position=="number"&&(Z.position+=ot.length),w.success(S)}}},"halt/0":function(w,S,y){w.points=[]},"halt/1":function(w,S,y){var F=y.args[0];x.type.is_variable(F)?w.throw_error(x.error.instantiation(y.indicator)):x.type.is_integer(F)?w.points=[]:w.throw_error(x.error.type("integer",F,y.indicator))},"current_prolog_flag/2":function(w,S,y){var F=y.args[0],z=y.args[1];if(!x.type.is_variable(F)&&!x.type.is_atom(F))w.throw_error(x.error.type("atom",F,y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_flag(F))w.throw_error(x.error.domain("prolog_flag",F,y.indicator));else{var X=[];for(var Z in x.flag)if(!!x.flag.hasOwnProperty(Z)){var ie=new H(",",[new H("=",[new H(Z),F]),new H("=",[w.get_flag(Z),z])]);X.push(new be(S.goal.replace(ie),S.substitution,S))}w.prepend(X)}},"set_prolog_flag/2":function(w,S,y){var F=y.args[0],z=y.args[1];x.type.is_variable(F)||x.type.is_variable(z)?w.throw_error(x.error.instantiation(y.indicator)):x.type.is_atom(F)?x.type.is_flag(F)?x.type.is_value_flag(F,z)?x.type.is_modifiable_flag(F)?(w.session.flag[F.id]=z,w.success(S)):w.throw_error(x.error.permission("modify","flag",F)):w.throw_error(x.error.domain("flag_value",new H("+",[F,z]),y.indicator)):w.throw_error(x.error.domain("prolog_flag",F,y.indicator)):w.throw_error(x.error.type("atom",F,y.indicator))}},flag:{bounded:{allowed:[new H("true"),new H("false")],value:new H("true"),changeable:!1},max_integer:{allowed:[new ke(Number.MAX_SAFE_INTEGER)],value:new ke(Number.MAX_SAFE_INTEGER),changeable:!1},min_integer:{allowed:[new ke(Number.MIN_SAFE_INTEGER)],value:new ke(Number.MIN_SAFE_INTEGER),changeable:!1},integer_rounding_function:{allowed:[new H("down"),new H("toward_zero")],value:new H("toward_zero"),changeable:!1},char_conversion:{allowed:[new H("on"),new H("off")],value:new H("on"),changeable:!0},debug:{allowed:[new H("on"),new H("off")],value:new H("off"),changeable:!0},max_arity:{allowed:[new H("unbounded")],value:new H("unbounded"),changeable:!1},unknown:{allowed:[new H("error"),new H("fail"),new H("warning")],value:new H("error"),changeable:!0},double_quotes:{allowed:[new H("chars"),new H("codes"),new H("atom")],value:new H("codes"),changeable:!0},occurs_check:{allowed:[new H("false"),new H("true")],value:new H("false"),changeable:!0},dialect:{allowed:[new H("tau")],value:new H("tau"),changeable:!1},version_data:{allowed:[new H("tau",[new ke(t.major,!1),new ke(t.minor,!1),new ke(t.patch,!1),new H(t.status)])],value:new H("tau",[new ke(t.major,!1),new ke(t.minor,!1),new ke(t.patch,!1),new H(t.status)]),changeable:!1},nodejs:{allowed:[new H("yes"),new H("no")],value:new H(typeof hl<"u"&&hl.exports?"yes":"no"),changeable:!1}},unify:function(w,S,y){y=y===void 0?!1:y;for(var F=[{left:w,right:S}],z={};F.length!==0;){var X=F.pop();if(w=X.left,S=X.right,x.type.is_term(w)&&x.type.is_term(S)){if(w.indicator!==S.indicator)return null;for(var Z=0;Zz.value?1:0:z}else return F},operate:function(w,S){if(x.type.is_operator(S)){for(var y=x.type.is_operator(S),F=[],z,X=!1,Z=0;Zw.get_flag("max_integer").value||z0?w.start+w.matches[0].length:w.start,z=y?new H("token_not_found"):new H("found",[new H(w.value.toString())]),X=new H(".",[new H("line",[new ke(w.line+1)]),new H(".",[new H("column",[new ke(F+1)]),new H(".",[z,new H("[]",[])])])]);return new H("error",[new H("syntax_error",[new H(S)]),X])},syntax_by_predicate:function(w,S){return new H("error",[new H("syntax_error",[new H(w)]),ee(S)])}},warning:{singleton:function(w,S,y){for(var F=new H("[]"),z=w.length-1;z>=0;z--)F=new H(".",[new Ie(w[z]),F]);return new H("warning",[new H("singleton_variables",[F,ee(S)]),new H(".",[new H("line",[new ke(y,!1)]),new H("[]")])])},failed_goal:function(w,S){return new H("warning",[new H("failed_goal",[w]),new H(".",[new H("line",[new ke(S,!1)]),new H("[]")])])}},format_variable:function(w){return"_"+w},format_answer:function(w,S,F){S instanceof Te&&(S=S.thread);var F=F||{};if(F.session=S?S.session:void 0,x.type.is_error(w))return"uncaught exception: "+w.args[0].toString();if(w===!1)return"false.";if(w===null)return"limit exceeded ;";var z=0,X="";if(x.type.is_substitution(w)){var Z=w.domain(!0);w=w.filter(function(Ne,ot){return!x.type.is_variable(ot)||Z.indexOf(ot.id)!==-1&&Ne!==ot.id})}for(var ie in w.links)!w.links.hasOwnProperty(ie)||(z++,X!==""&&(X+=", "),X+=ie.toString(F)+" = "+w.links[ie].toString(F));var Se=typeof S>"u"||S.points.length>0?" ;":".";return z===0?"true"+Se:X+Se},flatten_error:function(w){if(!x.type.is_error(w))return null;w=w.args[0];var S={};return S.type=w.args[0].id,S.thrown=S.type==="syntax_error"?null:w.args[1].id,S.expected=null,S.found=null,S.representation=null,S.existence=null,S.existence_type=null,S.line=null,S.column=null,S.permission_operation=null,S.permission_type=null,S.evaluation_type=null,S.type==="type_error"||S.type==="domain_error"?(S.expected=w.args[0].args[0].id,S.found=w.args[0].args[1].toString()):S.type==="syntax_error"?w.args[1].indicator==="./2"?(S.expected=w.args[0].args[0].id,S.found=w.args[1].args[1].args[1].args[0],S.found=S.found.id==="token_not_found"?S.found.id:S.found.args[0].id,S.line=w.args[1].args[0].args[0].value,S.column=w.args[1].args[1].args[0].args[0].value):S.thrown=w.args[1].id:S.type==="permission_error"?(S.found=w.args[0].args[2].toString(),S.permission_operation=w.args[0].args[0].id,S.permission_type=w.args[0].args[1].id):S.type==="evaluation_error"?S.evaluation_type=w.args[0].args[0].id:S.type==="representation_error"?S.representation=w.args[0].args[0].id:S.type==="existence_error"&&(S.existence=w.args[0].args[1].toString(),S.existence_type=w.args[0].args[0].id),S},create:function(w){return new x.type.Session(w)}};typeof hl<"u"?hl.exports=x:window.pl=x})()});function ame(t,e,r){t.prepend(r.map(o=>new Ra.default.type.State(e.goal.replace(o),e.substitution,e)))}function CH(t){let e=cme.get(t.session);if(e==null)throw new Error("Assertion failed: A project should have been registered for the active session");return e}function ume(t,e){cme.set(t,e),t.consult(`:- use_module(library(${tdt.id})).`)}var wH,Ra,lme,c0,$gt,edt,cme,tdt,Ame=Et(()=>{Ye();wH=$e(g2()),Ra=$e(EH()),lme=$e(Be("vm")),{is_atom:c0,is_variable:$gt,is_instantiated_list:edt}=Ra.default.type;cme=new WeakMap;tdt=new Ra.default.type.Module("constraints",{["project_workspaces_by_descriptor/3"]:(t,e,r)=>{let[o,a,n]=r.args;if(!c0(o)||!c0(a)){t.throw_error(Ra.default.error.instantiation(r.indicator));return}let u=W.parseIdent(o.id),A=W.makeDescriptor(u,a.id),h=CH(t).tryWorkspaceByDescriptor(A);$gt(n)&&h!==null&&ame(t,e,[new Ra.default.type.Term("=",[n,new Ra.default.type.Term(String(h.relativeCwd))])]),c0(n)&&h!==null&&h.relativeCwd===n.id&&t.success(e)},["workspace_field/3"]:(t,e,r)=>{let[o,a,n]=r.args;if(!c0(o)||!c0(a)){t.throw_error(Ra.default.error.instantiation(r.indicator));return}let A=CH(t).tryWorkspaceByCwd(o.id);if(A==null)return;let p=(0,wH.default)(A.manifest.raw,a.id);typeof p>"u"||ame(t,e,[new Ra.default.type.Term("=",[n,new Ra.default.type.Term(typeof p=="object"?JSON.stringify(p):p)])])},["workspace_field_test/3"]:(t,e,r)=>{let[o,a,n]=r.args;t.prepend([new Ra.default.type.State(e.goal.replace(new Ra.default.type.Term("workspace_field_test",[o,a,n,new Ra.default.type.Term("[]",[])])),e.substitution,e)])},["workspace_field_test/4"]:(t,e,r)=>{let[o,a,n,u]=r.args;if(!c0(o)||!c0(a)||!c0(n)||!edt(u)){t.throw_error(Ra.default.error.instantiation(r.indicator));return}let p=CH(t).tryWorkspaceByCwd(o.id);if(p==null)return;let h=(0,wH.default)(p.manifest.raw,a.id);if(typeof h>"u")return;let E={$$:h};for(let[v,b]of u.toJavaScript().entries())E[`$${v}`]=b;lme.default.runInNewContext(n.id,E)&&t.success(e)}},["project_workspaces_by_descriptor/3","workspace_field/3","workspace_field_test/3","workspace_field_test/4"])});var S2={};Kt(S2,{Constraints:()=>P2,DependencyType:()=>gme});function to(t){if(t instanceof vC.default.type.Num)return t.value;if(t instanceof vC.default.type.Term)switch(t.indicator){case"throw/1":return to(t.args[0]);case"error/1":return to(t.args[0]);case"error/2":if(t.args[0]instanceof vC.default.type.Term&&t.args[0].indicator==="syntax_error/1")return Object.assign(to(t.args[0]),...to(t.args[1]));{let e=to(t.args[0]);return e.message+=` (in ${to(t.args[1])})`,e}case"syntax_error/1":return new zt(43,`Syntax error: ${to(t.args[0])}`);case"existence_error/2":return new zt(44,`Existence error: ${to(t.args[0])} ${to(t.args[1])} not found`);case"instantiation_error/0":return new zt(75,"Instantiation error: an argument is variable when an instantiated argument was expected");case"line/1":return{line:to(t.args[0])};case"column/1":return{column:to(t.args[0])};case"found/1":return{found:to(t.args[0])};case"./2":return[to(t.args[0])].concat(to(t.args[1]));case"//2":return`${to(t.args[0])}/${to(t.args[1])}`;default:return t.id}throw`couldn't pretty print because of unsupported node ${t}`}function pme(t){let e;try{e=to(t)}catch(r){throw typeof r=="string"?new zt(42,`Unknown error: ${t} (note: ${r})`):r}return typeof e.line<"u"&&typeof e.column<"u"&&(e.message+=` at line ${e.line}, column ${e.column}`),e}function $d(t){return t.id==="null"?null:`${t.toJavaScript()}`}function rdt(t){if(t.id==="null")return null;{let e=t.toJavaScript();if(typeof e!="string")return JSON.stringify(e);try{return JSON.stringify(JSON.parse(e))}catch{return JSON.stringify(e)}}}function u0(t){return typeof t=="string"?`'${t}'`:"[]"}var hme,vC,gme,fme,IH,P2,x2=Et(()=>{Ye();Ye();Pt();hme=$e(Yde()),vC=$e(EH());B2();Ame();(0,hme.default)(vC.default);gme=(o=>(o.Dependencies="dependencies",o.DevDependencies="devDependencies",o.PeerDependencies="peerDependencies",o))(gme||{}),fme=["dependencies","devDependencies","peerDependencies"];IH=class{constructor(e,r){let o=1e3*e.workspaces.length;this.session=vC.default.create(o),ume(this.session,e),this.session.consult(":- use_module(library(lists))."),this.session.consult(r)}fetchNextAnswer(){return new Promise(e=>{this.session.answer(r=>{e(r)})})}async*makeQuery(e){let r=this.session.query(e);if(r!==!0)throw pme(r);for(;;){let o=await this.fetchNextAnswer();if(o===null)throw new zt(79,"Resolution limit exceeded");if(!o)break;if(o.id==="throw")throw pme(o);yield o}}};P2=class{constructor(e){this.source="";this.project=e;let r=e.configuration.get("constraintsPath");oe.existsSync(r)&&(this.source=oe.readFileSync(r,"utf8"))}static async find(e){return new P2(e)}getProjectDatabase(){let e="";for(let r of fme)e+=`dependency_type(${r}). -`;for(let r of this.project.workspacesByCwd.values()){let o=r.relativeCwd;e+=`workspace(${u0(o)}). -`,e+=`workspace_ident(${u0(o)}, ${u0(W.stringifyIdent(r.anchoredLocator))}). -`,e+=`workspace_version(${u0(o)}, ${u0(r.manifest.version)}). -`;for(let a of fme)for(let n of r.manifest[a].values())e+=`workspace_has_dependency(${u0(o)}, ${u0(W.stringifyIdent(n))}, ${u0(n.range)}, ${a}). -`}return e+=`workspace(_) :- false. -`,e+=`workspace_ident(_, _) :- false. -`,e+=`workspace_version(_, _) :- false. -`,e+=`workspace_has_dependency(_, _, _, _) :- false. -`,e}getDeclarations(){let e="";return e+=`gen_enforced_dependency(_, _, _, _) :- false. -`,e+=`gen_enforced_field(_, _, _) :- false. -`,e}get fullSource(){return`${this.getProjectDatabase()} -${this.source} -${this.getDeclarations()}`}createSession(){return new IH(this.project,this.fullSource)}async processClassic(){let e=this.createSession();return{enforcedDependencies:await this.genEnforcedDependencies(e),enforcedFields:await this.genEnforcedFields(e)}}async process(){let{enforcedDependencies:e,enforcedFields:r}=await this.processClassic(),o=new Map;for(let{workspace:a,dependencyIdent:n,dependencyRange:u,dependencyType:A}of e){let p=I2([A,W.stringifyIdent(n)]),h=je.getMapWithDefault(o,a.cwd);je.getMapWithDefault(h,p).set(u??void 0,new Set)}for(let{workspace:a,fieldPath:n,fieldValue:u}of r){let A=I2(n),p=je.getMapWithDefault(o,a.cwd);je.getMapWithDefault(p,A).set(JSON.parse(u)??void 0,new Set)}return{manifestUpdates:o,reportedErrors:new Map}}async genEnforcedDependencies(e){let r=[];for await(let o of e.makeQuery("workspace(WorkspaceCwd), dependency_type(DependencyType), gen_enforced_dependency(WorkspaceCwd, DependencyIdent, DependencyRange, DependencyType).")){let a=K.resolve(this.project.cwd,$d(o.links.WorkspaceCwd)),n=$d(o.links.DependencyIdent),u=$d(o.links.DependencyRange),A=$d(o.links.DependencyType);if(a===null||n===null)throw new Error("Invalid rule");let p=this.project.getWorkspaceByCwd(a),h=W.parseIdent(n);r.push({workspace:p,dependencyIdent:h,dependencyRange:u,dependencyType:A})}return je.sortMap(r,[({dependencyRange:o})=>o!==null?"0":"1",({workspace:o})=>W.stringifyIdent(o.anchoredLocator),({dependencyIdent:o})=>W.stringifyIdent(o)])}async genEnforcedFields(e){let r=[];for await(let o of e.makeQuery("workspace(WorkspaceCwd), gen_enforced_field(WorkspaceCwd, FieldPath, FieldValue).")){let a=K.resolve(this.project.cwd,$d(o.links.WorkspaceCwd)),n=$d(o.links.FieldPath),u=rdt(o.links.FieldValue);if(a===null||n===null)throw new Error("Invalid rule");let A=this.project.getWorkspaceByCwd(a);r.push({workspace:A,fieldPath:n,fieldValue:u})}return je.sortMap(r,[({workspace:o})=>W.stringifyIdent(o.anchoredLocator),({fieldPath:o})=>o])}async*query(e){let r=this.createSession();for await(let o of r.makeQuery(e)){let a={};for(let[n,u]of Object.entries(o.links))n!=="_"&&(a[n]=$d(u));yield a}}}});var vme=_(vk=>{"use strict";Object.defineProperty(vk,"__esModule",{value:!0});function q2(t){let e=[...t.caches],r=e.shift();return r===void 0?Bme():{get(o,a,n={miss:()=>Promise.resolve()}){return r.get(o,a,n).catch(()=>q2({caches:e}).get(o,a,n))},set(o,a){return r.set(o,a).catch(()=>q2({caches:e}).set(o,a))},delete(o){return r.delete(o).catch(()=>q2({caches:e}).delete(o))},clear(){return r.clear().catch(()=>q2({caches:e}).clear())}}}function Bme(){return{get(t,e,r={miss:()=>Promise.resolve()}){return e().then(a=>Promise.all([a,r.miss(a)])).then(([a])=>a)},set(t,e){return Promise.resolve(e)},delete(t){return Promise.resolve()},clear(){return Promise.resolve()}}}vk.createFallbackableCache=q2;vk.createNullCache=Bme});var Pme=_((QWt,Dme)=>{Dme.exports=vme()});var Sme=_(LH=>{"use strict";Object.defineProperty(LH,"__esModule",{value:!0});function wdt(t={serializable:!0}){let e={};return{get(r,o,a={miss:()=>Promise.resolve()}){let n=JSON.stringify(r);if(n in e)return Promise.resolve(t.serializable?JSON.parse(e[n]):e[n]);let u=o(),A=a&&a.miss||(()=>Promise.resolve());return u.then(p=>A(p)).then(()=>u)},set(r,o){return e[JSON.stringify(r)]=t.serializable?JSON.stringify(o):o,Promise.resolve(o)},delete(r){return delete e[JSON.stringify(r)],Promise.resolve()},clear(){return e={},Promise.resolve()}}}LH.createInMemoryCache=wdt});var bme=_((TWt,xme)=>{xme.exports=Sme()});var Qme=_(Zc=>{"use strict";Object.defineProperty(Zc,"__esModule",{value:!0});function Idt(t,e,r){let o={"x-algolia-api-key":r,"x-algolia-application-id":e};return{headers(){return t===MH.WithinHeaders?o:{}},queryParameters(){return t===MH.WithinQueryParameters?o:{}}}}function Bdt(t){let e=0,r=()=>(e++,new Promise(o=>{setTimeout(()=>{o(t(r))},Math.min(100*e,1e3))}));return t(r)}function kme(t,e=(r,o)=>Promise.resolve()){return Object.assign(t,{wait(r){return kme(t.then(o=>Promise.all([e(o,r),o])).then(o=>o[1]))}})}function vdt(t){let e=t.length-1;for(e;e>0;e--){let r=Math.floor(Math.random()*(e+1)),o=t[e];t[e]=t[r],t[r]=o}return t}function Ddt(t,e){return e&&Object.keys(e).forEach(r=>{t[r]=e[r](t)}),t}function Pdt(t,...e){let r=0;return t.replace(/%s/g,()=>encodeURIComponent(e[r++]))}var Sdt="4.14.2",xdt=t=>()=>t.transporter.requester.destroy(),MH={WithinQueryParameters:0,WithinHeaders:1};Zc.AuthMode=MH;Zc.addMethods=Ddt;Zc.createAuth=Idt;Zc.createRetryablePromise=Bdt;Zc.createWaitablePromise=kme;Zc.destroy=xdt;Zc.encode=Pdt;Zc.shuffle=vdt;Zc.version=Sdt});var G2=_((NWt,Fme)=>{Fme.exports=Qme()});var Tme=_(OH=>{"use strict";Object.defineProperty(OH,"__esModule",{value:!0});var bdt={Delete:"DELETE",Get:"GET",Post:"POST",Put:"PUT"};OH.MethodEnum=bdt});var Y2=_((MWt,Rme)=>{Rme.exports=Tme()});var Jme=_(Fi=>{"use strict";Object.defineProperty(Fi,"__esModule",{value:!0});var Lme=Y2();function UH(t,e){let r=t||{},o=r.data||{};return Object.keys(r).forEach(a=>{["timeout","headers","queryParameters","data","cacheable"].indexOf(a)===-1&&(o[a]=r[a])}),{data:Object.entries(o).length>0?o:void 0,timeout:r.timeout||e,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var W2={Read:1,Write:2,Any:3},xC={Up:1,Down:2,Timeouted:3},Mme=2*60*1e3;function HH(t,e=xC.Up){return{...t,status:e,lastUpdate:Date.now()}}function Ome(t){return t.status===xC.Up||Date.now()-t.lastUpdate>Mme}function Ume(t){return t.status===xC.Timeouted&&Date.now()-t.lastUpdate<=Mme}function jH(t){return typeof t=="string"?{protocol:"https",url:t,accept:W2.Any}:{protocol:t.protocol||"https",url:t.url,accept:t.accept||W2.Any}}function kdt(t,e){return Promise.all(e.map(r=>t.get(r,()=>Promise.resolve(HH(r))))).then(r=>{let o=r.filter(A=>Ome(A)),a=r.filter(A=>Ume(A)),n=[...o,...a],u=n.length>0?n.map(A=>jH(A)):e;return{getTimeout(A,p){return(a.length===0&&A===0?1:a.length+3+A)*p},statelessHosts:u}})}var Qdt=({isTimedOut:t,status:e})=>!t&&~~e===0,Fdt=t=>{let e=t.status;return t.isTimedOut||Qdt(t)||~~(e/100)!==2&&~~(e/100)!==4},Tdt=({status:t})=>~~(t/100)===2,Rdt=(t,e)=>Fdt(t)?e.onRetry(t):Tdt(t)?e.onSuccess(t):e.onFail(t);function Nme(t,e,r,o){let a=[],n=Gme(r,o),u=Yme(t,o),A=r.method,p=r.method!==Lme.MethodEnum.Get?{}:{...r.data,...o.data},h={"x-algolia-agent":t.userAgent.value,...t.queryParameters,...p,...o.queryParameters},E=0,I=(v,b)=>{let C=v.pop();if(C===void 0)throw Kme(_H(a));let T={data:n,headers:u,method:A,url:jme(C,r.path,h),connectTimeout:b(E,t.timeouts.connect),responseTimeout:b(E,o.timeout)},L=J=>{let te={request:T,response:J,host:C,triesLeft:v.length};return a.push(te),te},U={onSuccess:J=>_me(J),onRetry(J){let te=L(J);return J.isTimedOut&&E++,Promise.all([t.logger.info("Retryable failure",qH(te)),t.hostsCache.set(C,HH(C,J.isTimedOut?xC.Timeouted:xC.Down))]).then(()=>I(v,b))},onFail(J){throw L(J),Hme(J,_H(a))}};return t.requester.send(T).then(J=>Rdt(J,U))};return kdt(t.hostsCache,e).then(v=>I([...v.statelessHosts].reverse(),v.getTimeout))}function Ndt(t){let{hostsCache:e,logger:r,requester:o,requestsCache:a,responsesCache:n,timeouts:u,userAgent:A,hosts:p,queryParameters:h,headers:E}=t,I={hostsCache:e,logger:r,requester:o,requestsCache:a,responsesCache:n,timeouts:u,userAgent:A,headers:E,queryParameters:h,hosts:p.map(v=>jH(v)),read(v,b){let C=UH(b,I.timeouts.read),T=()=>Nme(I,I.hosts.filter(J=>(J.accept&W2.Read)!==0),v,C);if((C.cacheable!==void 0?C.cacheable:v.cacheable)!==!0)return T();let U={request:v,mappedRequestOptions:C,transporter:{queryParameters:I.queryParameters,headers:I.headers}};return I.responsesCache.get(U,()=>I.requestsCache.get(U,()=>I.requestsCache.set(U,T()).then(J=>Promise.all([I.requestsCache.delete(U),J]),J=>Promise.all([I.requestsCache.delete(U),Promise.reject(J)])).then(([J,te])=>te)),{miss:J=>I.responsesCache.set(U,J)})},write(v,b){return Nme(I,I.hosts.filter(C=>(C.accept&W2.Write)!==0),v,UH(b,I.timeouts.write))}};return I}function Ldt(t){let e={value:`Algolia for JavaScript (${t})`,add(r){let o=`; ${r.segment}${r.version!==void 0?` (${r.version})`:""}`;return e.value.indexOf(o)===-1&&(e.value=`${e.value}${o}`),e}};return e}function _me(t){try{return JSON.parse(t.content)}catch(e){throw Vme(e.message,t)}}function Hme({content:t,status:e},r){let o=t;try{o=JSON.parse(t).message}catch{}return Wme(o,e,r)}function Mdt(t,...e){let r=0;return t.replace(/%s/g,()=>encodeURIComponent(e[r++]))}function jme(t,e,r){let o=qme(r),a=`${t.protocol}://${t.url}/${e.charAt(0)==="/"?e.substr(1):e}`;return o.length&&(a+=`?${o}`),a}function qme(t){let e=r=>Object.prototype.toString.call(r)==="[object Object]"||Object.prototype.toString.call(r)==="[object Array]";return Object.keys(t).map(r=>Mdt("%s=%s",r,e(t[r])?JSON.stringify(t[r]):t[r])).join("&")}function Gme(t,e){if(t.method===Lme.MethodEnum.Get||t.data===void 0&&e.data===void 0)return;let r=Array.isArray(t.data)?t.data:{...t.data,...e.data};return JSON.stringify(r)}function Yme(t,e){let r={...t.headers,...e.headers},o={};return Object.keys(r).forEach(a=>{let n=r[a];o[a.toLowerCase()]=n}),o}function _H(t){return t.map(e=>qH(e))}function qH(t){let e=t.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return{...t,request:{...t.request,headers:{...t.request.headers,...e}}}}function Wme(t,e,r){return{name:"ApiError",message:t,status:e,transporterStackTrace:r}}function Vme(t,e){return{name:"DeserializationError",message:t,response:e}}function Kme(t){return{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:t}}Fi.CallEnum=W2;Fi.HostStatusEnum=xC;Fi.createApiError=Wme;Fi.createDeserializationError=Vme;Fi.createMappedRequestOptions=UH;Fi.createRetryError=Kme;Fi.createStatefulHost=HH;Fi.createStatelessHost=jH;Fi.createTransporter=Ndt;Fi.createUserAgent=Ldt;Fi.deserializeFailure=Hme;Fi.deserializeSuccess=_me;Fi.isStatefulHostTimeouted=Ume;Fi.isStatefulHostUp=Ome;Fi.serializeData=Gme;Fi.serializeHeaders=Yme;Fi.serializeQueryParameters=qme;Fi.serializeUrl=jme;Fi.stackFrameWithoutCredentials=qH;Fi.stackTraceWithoutCredentials=_H});var V2=_((UWt,zme)=>{zme.exports=Jme()});var Xme=_(d0=>{"use strict";Object.defineProperty(d0,"__esModule",{value:!0});var bC=G2(),Odt=V2(),K2=Y2(),Udt=t=>{let e=t.region||"us",r=bC.createAuth(bC.AuthMode.WithinHeaders,t.appId,t.apiKey),o=Odt.createTransporter({hosts:[{url:`analytics.${e}.algolia.com`}],...t,headers:{...r.headers(),"content-type":"application/json",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}}),a=t.appId;return bC.addMethods({appId:a,transporter:o},t.methods)},_dt=t=>(e,r)=>t.transporter.write({method:K2.MethodEnum.Post,path:"2/abtests",data:e},r),Hdt=t=>(e,r)=>t.transporter.write({method:K2.MethodEnum.Delete,path:bC.encode("2/abtests/%s",e)},r),jdt=t=>(e,r)=>t.transporter.read({method:K2.MethodEnum.Get,path:bC.encode("2/abtests/%s",e)},r),qdt=t=>e=>t.transporter.read({method:K2.MethodEnum.Get,path:"2/abtests"},e),Gdt=t=>(e,r)=>t.transporter.write({method:K2.MethodEnum.Post,path:bC.encode("2/abtests/%s/stop",e)},r);d0.addABTest=_dt;d0.createAnalyticsClient=Udt;d0.deleteABTest=Hdt;d0.getABTest=jdt;d0.getABTests=qdt;d0.stopABTest=Gdt});var $me=_((HWt,Zme)=>{Zme.exports=Xme()});var tye=_(J2=>{"use strict";Object.defineProperty(J2,"__esModule",{value:!0});var GH=G2(),Ydt=V2(),eye=Y2(),Wdt=t=>{let e=t.region||"us",r=GH.createAuth(GH.AuthMode.WithinHeaders,t.appId,t.apiKey),o=Ydt.createTransporter({hosts:[{url:`personalization.${e}.algolia.com`}],...t,headers:{...r.headers(),"content-type":"application/json",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}});return GH.addMethods({appId:t.appId,transporter:o},t.methods)},Vdt=t=>e=>t.transporter.read({method:eye.MethodEnum.Get,path:"1/strategies/personalization"},e),Kdt=t=>(e,r)=>t.transporter.write({method:eye.MethodEnum.Post,path:"1/strategies/personalization",data:e},r);J2.createPersonalizationClient=Wdt;J2.getPersonalizationStrategy=Vdt;J2.setPersonalizationStrategy=Kdt});var nye=_((qWt,rye)=>{rye.exports=tye()});var mye=_(Ft=>{"use strict";Object.defineProperty(Ft,"__esModule",{value:!0});var Gt=G2(),Na=V2(),Ir=Y2(),Jdt=Be("crypto");function Dk(t){let e=r=>t.request(r).then(o=>{if(t.batch!==void 0&&t.batch(o.hits),!t.shouldStop(o))return o.cursor?e({cursor:o.cursor}):e({page:(r.page||0)+1})});return e({})}var zdt=t=>{let e=t.appId,r=Gt.createAuth(t.authMode!==void 0?t.authMode:Gt.AuthMode.WithinHeaders,e,t.apiKey),o=Na.createTransporter({hosts:[{url:`${e}-dsn.algolia.net`,accept:Na.CallEnum.Read},{url:`${e}.algolia.net`,accept:Na.CallEnum.Write}].concat(Gt.shuffle([{url:`${e}-1.algolianet.com`},{url:`${e}-2.algolianet.com`},{url:`${e}-3.algolianet.com`}])),...t,headers:{...r.headers(),"content-type":"application/x-www-form-urlencoded",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}}),a={transporter:o,appId:e,addAlgoliaAgent(n,u){o.userAgent.add({segment:n,version:u})},clearCache(){return Promise.all([o.requestsCache.clear(),o.responsesCache.clear()]).then(()=>{})}};return Gt.addMethods(a,t.methods)};function iye(){return{name:"MissingObjectIDError",message:"All objects must have an unique objectID (like a primary key) to be valid. Algolia is also able to generate objectIDs automatically but *it's not recommended*. To do it, use the `{'autoGenerateObjectIDIfNotExist': true}` option."}}function sye(){return{name:"ObjectNotFoundError",message:"Object not found."}}function oye(){return{name:"ValidUntilNotFoundError",message:"ValidUntil not found in given secured api key."}}var Xdt=t=>(e,r)=>{let{queryParameters:o,...a}=r||{},n={acl:e,...o!==void 0?{queryParameters:o}:{}},u=(A,p)=>Gt.createRetryablePromise(h=>z2(t)(A.key,p).catch(E=>{if(E.status!==404)throw E;return h()}));return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:"1/keys",data:n},a),u)},Zdt=t=>(e,r,o)=>{let a=Na.createMappedRequestOptions(o);return a.queryParameters["X-Algolia-User-ID"]=e,t.transporter.write({method:Ir.MethodEnum.Post,path:"1/clusters/mapping",data:{cluster:r}},a)},$dt=t=>(e,r,o)=>t.transporter.write({method:Ir.MethodEnum.Post,path:"1/clusters/mapping/batch",data:{users:e,cluster:r}},o),emt=t=>(e,r)=>Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode("/1/dictionaries/%s/batch",e),data:{clearExistingDictionaryEntries:!0,requests:{action:"addEntry",body:[]}}},r),(o,a)=>kC(t)(o.taskID,a)),Pk=t=>(e,r,o)=>{let a=(n,u)=>X2(t)(e,{methods:{waitTask:Zi}}).waitTask(n.taskID,u);return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode("1/indexes/%s/operation",e),data:{operation:"copy",destination:r}},o),a)},tmt=t=>(e,r,o)=>Pk(t)(e,r,{...o,scope:[xk.Rules]}),rmt=t=>(e,r,o)=>Pk(t)(e,r,{...o,scope:[xk.Settings]}),nmt=t=>(e,r,o)=>Pk(t)(e,r,{...o,scope:[xk.Synonyms]}),imt=t=>(e,r)=>e.method===Ir.MethodEnum.Get?t.transporter.read(e,r):t.transporter.write(e,r),smt=t=>(e,r)=>{let o=(a,n)=>Gt.createRetryablePromise(u=>z2(t)(e,n).then(u).catch(A=>{if(A.status!==404)throw A}));return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Delete,path:Gt.encode("1/keys/%s",e)},r),o)},omt=t=>(e,r,o)=>{let a=r.map(n=>({action:"deleteEntry",body:{objectID:n}}));return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode("/1/dictionaries/%s/batch",e),data:{clearExistingDictionaryEntries:!1,requests:a}},o),(n,u)=>kC(t)(n.taskID,u))},amt=()=>(t,e)=>{let r=Na.serializeQueryParameters(e),o=Jdt.createHmac("sha256",t).update(r).digest("hex");return Buffer.from(o+r).toString("base64")},z2=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:Gt.encode("1/keys/%s",e)},r),aye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:Gt.encode("1/task/%s",e.toString())},r),lmt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:"/1/dictionaries/*/settings"},e),cmt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:"1/logs"},e),umt=()=>t=>{let e=Buffer.from(t,"base64").toString("ascii"),r=/validUntil=(\d+)/,o=e.match(r);if(o===null)throw oye();return parseInt(o[1],10)-Math.round(new Date().getTime()/1e3)},Amt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:"1/clusters/mapping/top"},e),fmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:Gt.encode("1/clusters/mapping/%s",e)},r),pmt=t=>e=>{let{retrieveMappings:r,...o}=e||{};return r===!0&&(o.getClusters=!0),t.transporter.read({method:Ir.MethodEnum.Get,path:"1/clusters/mapping/pending"},o)},X2=t=>(e,r={})=>{let o={transporter:t.transporter,appId:t.appId,indexName:e};return Gt.addMethods(o,r.methods)},hmt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:"1/keys"},e),gmt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:"1/clusters"},e),dmt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:"1/indexes"},e),mmt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:"1/clusters/mapping"},e),ymt=t=>(e,r,o)=>{let a=(n,u)=>X2(t)(e,{methods:{waitTask:Zi}}).waitTask(n.taskID,u);return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode("1/indexes/%s/operation",e),data:{operation:"move",destination:r}},o),a)},Emt=t=>(e,r)=>{let o=(a,n)=>Promise.all(Object.keys(a.taskID).map(u=>X2(t)(u,{methods:{waitTask:Zi}}).waitTask(a.taskID[u],n)));return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:"1/indexes/*/batch",data:{requests:e}},r),o)},Cmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:"1/indexes/*/objects",data:{requests:e}},r),wmt=t=>(e,r)=>{let o=e.map(a=>({...a,params:Na.serializeQueryParameters(a.params||{})}));return t.transporter.read({method:Ir.MethodEnum.Post,path:"1/indexes/*/queries",data:{requests:o},cacheable:!0},r)},Imt=t=>(e,r)=>Promise.all(e.map(o=>{let{facetName:a,facetQuery:n,...u}=o.params;return X2(t)(o.indexName,{methods:{searchForFacetValues:hye}}).searchForFacetValues(a,n,{...r,...u})})),Bmt=t=>(e,r)=>{let o=Na.createMappedRequestOptions(r);return o.queryParameters["X-Algolia-User-ID"]=e,t.transporter.write({method:Ir.MethodEnum.Delete,path:"1/clusters/mapping"},o)},vmt=t=>(e,r,o)=>{let a=r.map(n=>({action:"addEntry",body:n}));return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode("/1/dictionaries/%s/batch",e),data:{clearExistingDictionaryEntries:!0,requests:a}},o),(n,u)=>kC(t)(n.taskID,u))},Dmt=t=>(e,r)=>{let o=(a,n)=>Gt.createRetryablePromise(u=>z2(t)(e,n).catch(A=>{if(A.status!==404)throw A;return u()}));return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode("1/keys/%s/restore",e)},r),o)},Pmt=t=>(e,r,o)=>{let a=r.map(n=>({action:"addEntry",body:n}));return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode("/1/dictionaries/%s/batch",e),data:{clearExistingDictionaryEntries:!1,requests:a}},o),(n,u)=>kC(t)(n.taskID,u))},Smt=t=>(e,r,o)=>t.transporter.read({method:Ir.MethodEnum.Post,path:Gt.encode("/1/dictionaries/%s/search",e),data:{query:r},cacheable:!0},o),xmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:"1/clusters/mapping/search",data:{query:e}},r),bmt=t=>(e,r)=>Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Put,path:"/1/dictionaries/*/settings",data:e},r),(o,a)=>kC(t)(o.taskID,a)),kmt=t=>(e,r)=>{let o=Object.assign({},r),{queryParameters:a,...n}=r||{},u=a?{queryParameters:a}:{},A=["acl","indexes","referers","restrictSources","queryParameters","description","maxQueriesPerIPPerHour","maxHitsPerQuery"],p=E=>Object.keys(o).filter(I=>A.indexOf(I)!==-1).every(I=>E[I]===o[I]),h=(E,I)=>Gt.createRetryablePromise(v=>z2(t)(e,I).then(b=>p(b)?Promise.resolve():v()));return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Put,path:Gt.encode("1/keys/%s",e),data:u},n),h)},kC=t=>(e,r)=>Gt.createRetryablePromise(o=>aye(t)(e,r).then(a=>a.status!=="published"?o():void 0)),lye=t=>(e,r)=>{let o=(a,n)=>Zi(t)(a.taskID,n);return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode("1/indexes/%s/batch",t.indexName),data:{requests:e}},r),o)},Qmt=t=>e=>Dk({shouldStop:r=>r.cursor===void 0,...e,request:r=>t.transporter.read({method:Ir.MethodEnum.Post,path:Gt.encode("1/indexes/%s/browse",t.indexName),data:r},e)}),Fmt=t=>e=>{let r={hitsPerPage:1e3,...e};return Dk({shouldStop:o=>o.hits.length({...a,hits:a.hits.map(n=>(delete n._highlightResult,n))}))}})},Tmt=t=>e=>{let r={hitsPerPage:1e3,...e};return Dk({shouldStop:o=>o.hits.length({...a,hits:a.hits.map(n=>(delete n._highlightResult,n))}))}})},Sk=t=>(e,r,o)=>{let{batchSize:a,...n}=o||{},u={taskIDs:[],objectIDs:[]},A=(p=0)=>{let h=[],E;for(E=p;E({action:r,body:I})),n).then(I=>(u.objectIDs=u.objectIDs.concat(I.objectIDs),u.taskIDs.push(I.taskID),E++,A(E)))};return Gt.createWaitablePromise(A(),(p,h)=>Promise.all(p.taskIDs.map(E=>Zi(t)(E,h))))},Rmt=t=>e=>Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode("1/indexes/%s/clear",t.indexName)},e),(r,o)=>Zi(t)(r.taskID,o)),Nmt=t=>e=>{let{forwardToReplicas:r,...o}=e||{},a=Na.createMappedRequestOptions(o);return r&&(a.queryParameters.forwardToReplicas=1),Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode("1/indexes/%s/rules/clear",t.indexName)},a),(n,u)=>Zi(t)(n.taskID,u))},Lmt=t=>e=>{let{forwardToReplicas:r,...o}=e||{},a=Na.createMappedRequestOptions(o);return r&&(a.queryParameters.forwardToReplicas=1),Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode("1/indexes/%s/synonyms/clear",t.indexName)},a),(n,u)=>Zi(t)(n.taskID,u))},Mmt=t=>(e,r)=>Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode("1/indexes/%s/deleteByQuery",t.indexName),data:e},r),(o,a)=>Zi(t)(o.taskID,a)),Omt=t=>e=>Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Delete,path:Gt.encode("1/indexes/%s",t.indexName)},e),(r,o)=>Zi(t)(r.taskID,o)),Umt=t=>(e,r)=>Gt.createWaitablePromise(cye(t)([e],r).then(o=>({taskID:o.taskIDs[0]})),(o,a)=>Zi(t)(o.taskID,a)),cye=t=>(e,r)=>{let o=e.map(a=>({objectID:a}));return Sk(t)(o,rm.DeleteObject,r)},_mt=t=>(e,r)=>{let{forwardToReplicas:o,...a}=r||{},n=Na.createMappedRequestOptions(a);return o&&(n.queryParameters.forwardToReplicas=1),Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Delete,path:Gt.encode("1/indexes/%s/rules/%s",t.indexName,e)},n),(u,A)=>Zi(t)(u.taskID,A))},Hmt=t=>(e,r)=>{let{forwardToReplicas:o,...a}=r||{},n=Na.createMappedRequestOptions(a);return o&&(n.queryParameters.forwardToReplicas=1),Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Delete,path:Gt.encode("1/indexes/%s/synonyms/%s",t.indexName,e)},n),(u,A)=>Zi(t)(u.taskID,A))},jmt=t=>e=>uye(t)(e).then(()=>!0).catch(r=>{if(r.status!==404)throw r;return!1}),qmt=t=>(e,r,o)=>t.transporter.read({method:Ir.MethodEnum.Post,path:Gt.encode("1/answers/%s/prediction",t.indexName),data:{query:e,queryLanguages:r},cacheable:!0},o),Gmt=t=>(e,r)=>{let{query:o,paginate:a,...n}=r||{},u=0,A=()=>pye(t)(o||"",{...n,page:u}).then(p=>{for(let[h,E]of Object.entries(p.hits))if(e(E))return{object:E,position:parseInt(h,10),page:u};if(u++,a===!1||u>=p.nbPages)throw sye();return A()});return A()},Ymt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:Gt.encode("1/indexes/%s/%s",t.indexName,e)},r),Wmt=()=>(t,e)=>{for(let[r,o]of Object.entries(t.hits))if(o.objectID===e)return parseInt(r,10);return-1},Vmt=t=>(e,r)=>{let{attributesToRetrieve:o,...a}=r||{},n=e.map(u=>({indexName:t.indexName,objectID:u,...o?{attributesToRetrieve:o}:{}}));return t.transporter.read({method:Ir.MethodEnum.Post,path:"1/indexes/*/objects",data:{requests:n}},a)},Kmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:Gt.encode("1/indexes/%s/rules/%s",t.indexName,e)},r),uye=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:Gt.encode("1/indexes/%s/settings",t.indexName),data:{getVersion:2}},e),Jmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:Gt.encode("1/indexes/%s/synonyms/%s",t.indexName,e)},r),Aye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:Gt.encode("1/indexes/%s/task/%s",t.indexName,e.toString())},r),zmt=t=>(e,r)=>Gt.createWaitablePromise(fye(t)([e],r).then(o=>({objectID:o.objectIDs[0],taskID:o.taskIDs[0]})),(o,a)=>Zi(t)(o.taskID,a)),fye=t=>(e,r)=>{let{createIfNotExists:o,...a}=r||{},n=o?rm.PartialUpdateObject:rm.PartialUpdateObjectNoCreate;return Sk(t)(e,n,a)},Xmt=t=>(e,r)=>{let{safe:o,autoGenerateObjectIDIfNotExist:a,batchSize:n,...u}=r||{},A=(C,T,L,U)=>Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode("1/indexes/%s/operation",C),data:{operation:L,destination:T}},U),(J,te)=>Zi(t)(J.taskID,te)),p=Math.random().toString(36).substring(7),h=`${t.indexName}_tmp_${p}`,E=YH({appId:t.appId,transporter:t.transporter,indexName:h}),I=[],v=A(t.indexName,h,"copy",{...u,scope:["settings","synonyms","rules"]});I.push(v);let b=(o?v.wait(u):v).then(()=>{let C=E(e,{...u,autoGenerateObjectIDIfNotExist:a,batchSize:n});return I.push(C),o?C.wait(u):C}).then(()=>{let C=A(h,t.indexName,"move",u);return I.push(C),o?C.wait(u):C}).then(()=>Promise.all(I)).then(([C,T,L])=>({objectIDs:T.objectIDs,taskIDs:[C.taskID,...T.taskIDs,L.taskID]}));return Gt.createWaitablePromise(b,(C,T)=>Promise.all(I.map(L=>L.wait(T))))},Zmt=t=>(e,r)=>WH(t)(e,{...r,clearExistingRules:!0}),$mt=t=>(e,r)=>VH(t)(e,{...r,clearExistingSynonyms:!0}),eyt=t=>(e,r)=>Gt.createWaitablePromise(YH(t)([e],r).then(o=>({objectID:o.objectIDs[0],taskID:o.taskIDs[0]})),(o,a)=>Zi(t)(o.taskID,a)),YH=t=>(e,r)=>{let{autoGenerateObjectIDIfNotExist:o,...a}=r||{},n=o?rm.AddObject:rm.UpdateObject;if(n===rm.UpdateObject){for(let u of e)if(u.objectID===void 0)return Gt.createWaitablePromise(Promise.reject(iye()))}return Sk(t)(e,n,a)},tyt=t=>(e,r)=>WH(t)([e],r),WH=t=>(e,r)=>{let{forwardToReplicas:o,clearExistingRules:a,...n}=r||{},u=Na.createMappedRequestOptions(n);return o&&(u.queryParameters.forwardToReplicas=1),a&&(u.queryParameters.clearExistingRules=1),Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode("1/indexes/%s/rules/batch",t.indexName),data:e},u),(A,p)=>Zi(t)(A.taskID,p))},ryt=t=>(e,r)=>VH(t)([e],r),VH=t=>(e,r)=>{let{forwardToReplicas:o,clearExistingSynonyms:a,replaceExistingSynonyms:n,...u}=r||{},A=Na.createMappedRequestOptions(u);return o&&(A.queryParameters.forwardToReplicas=1),(n||a)&&(A.queryParameters.replaceExistingSynonyms=1),Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode("1/indexes/%s/synonyms/batch",t.indexName),data:e},A),(p,h)=>Zi(t)(p.taskID,h))},pye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:Gt.encode("1/indexes/%s/query",t.indexName),data:{query:e},cacheable:!0},r),hye=t=>(e,r,o)=>t.transporter.read({method:Ir.MethodEnum.Post,path:Gt.encode("1/indexes/%s/facets/%s/query",t.indexName,e),data:{facetQuery:r},cacheable:!0},o),gye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:Gt.encode("1/indexes/%s/rules/search",t.indexName),data:{query:e}},r),dye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:Gt.encode("1/indexes/%s/synonyms/search",t.indexName),data:{query:e}},r),nyt=t=>(e,r)=>{let{forwardToReplicas:o,...a}=r||{},n=Na.createMappedRequestOptions(a);return o&&(n.queryParameters.forwardToReplicas=1),Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Put,path:Gt.encode("1/indexes/%s/settings",t.indexName),data:e},n),(u,A)=>Zi(t)(u.taskID,A))},Zi=t=>(e,r)=>Gt.createRetryablePromise(o=>Aye(t)(e,r).then(a=>a.status!=="published"?o():void 0)),iyt={AddObject:"addObject",Analytics:"analytics",Browser:"browse",DeleteIndex:"deleteIndex",DeleteObject:"deleteObject",EditSettings:"editSettings",ListIndexes:"listIndexes",Logs:"logs",Personalization:"personalization",Recommendation:"recommendation",Search:"search",SeeUnretrievableAttributes:"seeUnretrievableAttributes",Settings:"settings",Usage:"usage"},rm={AddObject:"addObject",UpdateObject:"updateObject",PartialUpdateObject:"partialUpdateObject",PartialUpdateObjectNoCreate:"partialUpdateObjectNoCreate",DeleteObject:"deleteObject",DeleteIndex:"delete",ClearIndex:"clear"},xk={Settings:"settings",Synonyms:"synonyms",Rules:"rules"},syt={None:"none",StopIfEnoughMatches:"stopIfEnoughMatches"},oyt={Synonym:"synonym",OneWaySynonym:"oneWaySynonym",AltCorrection1:"altCorrection1",AltCorrection2:"altCorrection2",Placeholder:"placeholder"};Ft.ApiKeyACLEnum=iyt;Ft.BatchActionEnum=rm;Ft.ScopeEnum=xk;Ft.StrategyEnum=syt;Ft.SynonymEnum=oyt;Ft.addApiKey=Xdt;Ft.assignUserID=Zdt;Ft.assignUserIDs=$dt;Ft.batch=lye;Ft.browseObjects=Qmt;Ft.browseRules=Fmt;Ft.browseSynonyms=Tmt;Ft.chunkedBatch=Sk;Ft.clearDictionaryEntries=emt;Ft.clearObjects=Rmt;Ft.clearRules=Nmt;Ft.clearSynonyms=Lmt;Ft.copyIndex=Pk;Ft.copyRules=tmt;Ft.copySettings=rmt;Ft.copySynonyms=nmt;Ft.createBrowsablePromise=Dk;Ft.createMissingObjectIDError=iye;Ft.createObjectNotFoundError=sye;Ft.createSearchClient=zdt;Ft.createValidUntilNotFoundError=oye;Ft.customRequest=imt;Ft.deleteApiKey=smt;Ft.deleteBy=Mmt;Ft.deleteDictionaryEntries=omt;Ft.deleteIndex=Omt;Ft.deleteObject=Umt;Ft.deleteObjects=cye;Ft.deleteRule=_mt;Ft.deleteSynonym=Hmt;Ft.exists=jmt;Ft.findAnswers=qmt;Ft.findObject=Gmt;Ft.generateSecuredApiKey=amt;Ft.getApiKey=z2;Ft.getAppTask=aye;Ft.getDictionarySettings=lmt;Ft.getLogs=cmt;Ft.getObject=Ymt;Ft.getObjectPosition=Wmt;Ft.getObjects=Vmt;Ft.getRule=Kmt;Ft.getSecuredApiKeyRemainingValidity=umt;Ft.getSettings=uye;Ft.getSynonym=Jmt;Ft.getTask=Aye;Ft.getTopUserIDs=Amt;Ft.getUserID=fmt;Ft.hasPendingMappings=pmt;Ft.initIndex=X2;Ft.listApiKeys=hmt;Ft.listClusters=gmt;Ft.listIndices=dmt;Ft.listUserIDs=mmt;Ft.moveIndex=ymt;Ft.multipleBatch=Emt;Ft.multipleGetObjects=Cmt;Ft.multipleQueries=wmt;Ft.multipleSearchForFacetValues=Imt;Ft.partialUpdateObject=zmt;Ft.partialUpdateObjects=fye;Ft.removeUserID=Bmt;Ft.replaceAllObjects=Xmt;Ft.replaceAllRules=Zmt;Ft.replaceAllSynonyms=$mt;Ft.replaceDictionaryEntries=vmt;Ft.restoreApiKey=Dmt;Ft.saveDictionaryEntries=Pmt;Ft.saveObject=eyt;Ft.saveObjects=YH;Ft.saveRule=tyt;Ft.saveRules=WH;Ft.saveSynonym=ryt;Ft.saveSynonyms=VH;Ft.search=pye;Ft.searchDictionaryEntries=Smt;Ft.searchForFacetValues=hye;Ft.searchRules=gye;Ft.searchSynonyms=dye;Ft.searchUserIDs=xmt;Ft.setDictionarySettings=bmt;Ft.setSettings=nyt;Ft.updateApiKey=kmt;Ft.waitAppTask=kC;Ft.waitTask=Zi});var Eye=_((YWt,yye)=>{yye.exports=mye()});var Cye=_(bk=>{"use strict";Object.defineProperty(bk,"__esModule",{value:!0});function ayt(){return{debug(t,e){return Promise.resolve()},info(t,e){return Promise.resolve()},error(t,e){return Promise.resolve()}}}var lyt={Debug:1,Info:2,Error:3};bk.LogLevelEnum=lyt;bk.createNullLogger=ayt});var Iye=_((VWt,wye)=>{wye.exports=Cye()});var Pye=_(KH=>{"use strict";Object.defineProperty(KH,"__esModule",{value:!0});var Bye=Be("http"),vye=Be("https"),cyt=Be("url"),Dye={keepAlive:!0},uyt=new Bye.Agent(Dye),Ayt=new vye.Agent(Dye);function fyt({agent:t,httpAgent:e,httpsAgent:r,requesterOptions:o={}}={}){let a=e||t||uyt,n=r||t||Ayt;return{send(u){return new Promise(A=>{let p=cyt.parse(u.url),h=p.query===null?p.pathname:`${p.pathname}?${p.query}`,E={...o,agent:p.protocol==="https:"?n:a,hostname:p.hostname,path:h,method:u.method,headers:{...o&&o.headers?o.headers:{},...u.headers},...p.port!==void 0?{port:p.port||""}:{}},I=(p.protocol==="https:"?vye:Bye).request(E,T=>{let L=[];T.on("data",U=>{L=L.concat(U)}),T.on("end",()=>{clearTimeout(b),clearTimeout(C),A({status:T.statusCode||0,content:Buffer.concat(L).toString(),isTimedOut:!1})})}),v=(T,L)=>setTimeout(()=>{I.abort(),A({status:0,content:L,isTimedOut:!0})},T*1e3),b=v(u.connectTimeout,"Connection timeout"),C;I.on("error",T=>{clearTimeout(b),clearTimeout(C),A({status:0,content:T.message,isTimedOut:!1})}),I.once("response",()=>{clearTimeout(b),C=v(u.responseTimeout,"Socket timeout")}),u.data!==void 0&&I.write(u.data),I.end()})},destroy(){return a.destroy(),n.destroy(),Promise.resolve()}}}KH.createNodeHttpRequester=fyt});var xye=_((JWt,Sye)=>{Sye.exports=Pye()});var Fye=_((zWt,Qye)=>{"use strict";var bye=Pme(),pyt=bme(),QC=$me(),zH=G2(),JH=nye(),Ut=Eye(),hyt=Iye(),gyt=xye(),dyt=V2();function kye(t,e,r){let o={appId:t,apiKey:e,timeouts:{connect:2,read:5,write:30},requester:gyt.createNodeHttpRequester(),logger:hyt.createNullLogger(),responsesCache:bye.createNullCache(),requestsCache:bye.createNullCache(),hostsCache:pyt.createInMemoryCache(),userAgent:dyt.createUserAgent(zH.version).add({segment:"Node.js",version:process.versions.node})},a={...o,...r},n=()=>u=>JH.createPersonalizationClient({...o,...u,methods:{getPersonalizationStrategy:JH.getPersonalizationStrategy,setPersonalizationStrategy:JH.setPersonalizationStrategy}});return Ut.createSearchClient({...a,methods:{search:Ut.multipleQueries,searchForFacetValues:Ut.multipleSearchForFacetValues,multipleBatch:Ut.multipleBatch,multipleGetObjects:Ut.multipleGetObjects,multipleQueries:Ut.multipleQueries,copyIndex:Ut.copyIndex,copySettings:Ut.copySettings,copyRules:Ut.copyRules,copySynonyms:Ut.copySynonyms,moveIndex:Ut.moveIndex,listIndices:Ut.listIndices,getLogs:Ut.getLogs,listClusters:Ut.listClusters,multipleSearchForFacetValues:Ut.multipleSearchForFacetValues,getApiKey:Ut.getApiKey,addApiKey:Ut.addApiKey,listApiKeys:Ut.listApiKeys,updateApiKey:Ut.updateApiKey,deleteApiKey:Ut.deleteApiKey,restoreApiKey:Ut.restoreApiKey,assignUserID:Ut.assignUserID,assignUserIDs:Ut.assignUserIDs,getUserID:Ut.getUserID,searchUserIDs:Ut.searchUserIDs,listUserIDs:Ut.listUserIDs,getTopUserIDs:Ut.getTopUserIDs,removeUserID:Ut.removeUserID,hasPendingMappings:Ut.hasPendingMappings,generateSecuredApiKey:Ut.generateSecuredApiKey,getSecuredApiKeyRemainingValidity:Ut.getSecuredApiKeyRemainingValidity,destroy:zH.destroy,clearDictionaryEntries:Ut.clearDictionaryEntries,deleteDictionaryEntries:Ut.deleteDictionaryEntries,getDictionarySettings:Ut.getDictionarySettings,getAppTask:Ut.getAppTask,replaceDictionaryEntries:Ut.replaceDictionaryEntries,saveDictionaryEntries:Ut.saveDictionaryEntries,searchDictionaryEntries:Ut.searchDictionaryEntries,setDictionarySettings:Ut.setDictionarySettings,waitAppTask:Ut.waitAppTask,customRequest:Ut.customRequest,initIndex:u=>A=>Ut.initIndex(u)(A,{methods:{batch:Ut.batch,delete:Ut.deleteIndex,findAnswers:Ut.findAnswers,getObject:Ut.getObject,getObjects:Ut.getObjects,saveObject:Ut.saveObject,saveObjects:Ut.saveObjects,search:Ut.search,searchForFacetValues:Ut.searchForFacetValues,waitTask:Ut.waitTask,setSettings:Ut.setSettings,getSettings:Ut.getSettings,partialUpdateObject:Ut.partialUpdateObject,partialUpdateObjects:Ut.partialUpdateObjects,deleteObject:Ut.deleteObject,deleteObjects:Ut.deleteObjects,deleteBy:Ut.deleteBy,clearObjects:Ut.clearObjects,browseObjects:Ut.browseObjects,getObjectPosition:Ut.getObjectPosition,findObject:Ut.findObject,exists:Ut.exists,saveSynonym:Ut.saveSynonym,saveSynonyms:Ut.saveSynonyms,getSynonym:Ut.getSynonym,searchSynonyms:Ut.searchSynonyms,browseSynonyms:Ut.browseSynonyms,deleteSynonym:Ut.deleteSynonym,clearSynonyms:Ut.clearSynonyms,replaceAllObjects:Ut.replaceAllObjects,replaceAllSynonyms:Ut.replaceAllSynonyms,searchRules:Ut.searchRules,getRule:Ut.getRule,deleteRule:Ut.deleteRule,saveRule:Ut.saveRule,saveRules:Ut.saveRules,replaceAllRules:Ut.replaceAllRules,browseRules:Ut.browseRules,clearRules:Ut.clearRules}}),initAnalytics:()=>u=>QC.createAnalyticsClient({...o,...u,methods:{addABTest:QC.addABTest,getABTest:QC.getABTest,getABTests:QC.getABTests,stopABTest:QC.stopABTest,deleteABTest:QC.deleteABTest}}),initPersonalization:n,initRecommendation:()=>u=>(a.logger.info("The `initRecommendation` method is deprecated. Use `initPersonalization` instead."),n()(u))}})}kye.version=zH.version;Qye.exports=kye});var ZH=_((XWt,XH)=>{var Tye=Fye();XH.exports=Tye;XH.exports.default=Tye});var t6=_(($Wt,Lye)=>{"use strict";var Nye=Object.getOwnPropertySymbols,yyt=Object.prototype.hasOwnProperty,Eyt=Object.prototype.propertyIsEnumerable;function Cyt(t){if(t==null)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(t)}function wyt(){try{if(!Object.assign)return!1;var t=new String("abc");if(t[5]="de",Object.getOwnPropertyNames(t)[0]==="5")return!1;for(var e={},r=0;r<10;r++)e["_"+String.fromCharCode(r)]=r;var o=Object.getOwnPropertyNames(e).map(function(n){return e[n]});if(o.join("")!=="0123456789")return!1;var a={};return"abcdefghijklmnopqrst".split("").forEach(function(n){a[n]=n}),Object.keys(Object.assign({},a)).join("")==="abcdefghijklmnopqrst"}catch{return!1}}Lye.exports=wyt()?Object.assign:function(t,e){for(var r,o=Cyt(t),a,n=1;n{"use strict";var o6=t6(),$c=typeof Symbol=="function"&&Symbol.for,Z2=$c?Symbol.for("react.element"):60103,Iyt=$c?Symbol.for("react.portal"):60106,Byt=$c?Symbol.for("react.fragment"):60107,vyt=$c?Symbol.for("react.strict_mode"):60108,Dyt=$c?Symbol.for("react.profiler"):60114,Pyt=$c?Symbol.for("react.provider"):60109,Syt=$c?Symbol.for("react.context"):60110,xyt=$c?Symbol.for("react.forward_ref"):60112,byt=$c?Symbol.for("react.suspense"):60113,kyt=$c?Symbol.for("react.memo"):60115,Qyt=$c?Symbol.for("react.lazy"):60116,Mye=typeof Symbol=="function"&&Symbol.iterator;function $2(t){for(var e="https://reactjs.org/docs/error-decoder.html?invariant="+t,r=1;rkk.length&&kk.push(t)}function n6(t,e,r,o){var a=typeof t;(a==="undefined"||a==="boolean")&&(t=null);var n=!1;if(t===null)n=!0;else switch(a){case"string":case"number":n=!0;break;case"object":switch(t.$$typeof){case Z2:case Iyt:n=!0}}if(n)return r(o,t,e===""?"."+r6(t,0):e),1;if(n=0,e=e===""?".":e+":",Array.isArray(t))for(var u=0;u{"use strict";Jye.exports=Kye()});var f6=_((rVt,A6)=>{"use strict";var An=A6.exports;A6.exports.default=An;var Ln="\x1B[",eB="\x1B]",TC="\x07",Qk=";",zye=process.env.TERM_PROGRAM==="Apple_Terminal";An.cursorTo=(t,e)=>{if(typeof t!="number")throw new TypeError("The `x` argument is required");return typeof e!="number"?Ln+(t+1)+"G":Ln+(e+1)+";"+(t+1)+"H"};An.cursorMove=(t,e)=>{if(typeof t!="number")throw new TypeError("The `x` argument is required");let r="";return t<0?r+=Ln+-t+"D":t>0&&(r+=Ln+t+"C"),e<0?r+=Ln+-e+"A":e>0&&(r+=Ln+e+"B"),r};An.cursorUp=(t=1)=>Ln+t+"A";An.cursorDown=(t=1)=>Ln+t+"B";An.cursorForward=(t=1)=>Ln+t+"C";An.cursorBackward=(t=1)=>Ln+t+"D";An.cursorLeft=Ln+"G";An.cursorSavePosition=zye?"\x1B7":Ln+"s";An.cursorRestorePosition=zye?"\x1B8":Ln+"u";An.cursorGetPosition=Ln+"6n";An.cursorNextLine=Ln+"E";An.cursorPrevLine=Ln+"F";An.cursorHide=Ln+"?25l";An.cursorShow=Ln+"?25h";An.eraseLines=t=>{let e="";for(let r=0;r[eB,"8",Qk,Qk,e,TC,t,eB,"8",Qk,Qk,TC].join("");An.image=(t,e={})=>{let r=`${eB}1337;File=inline=1`;return e.width&&(r+=`;width=${e.width}`),e.height&&(r+=`;height=${e.height}`),e.preserveAspectRatio===!1&&(r+=";preserveAspectRatio=0"),r+":"+t.toString("base64")+TC};An.iTerm={setCwd:(t=process.cwd())=>`${eB}50;CurrentDir=${t}${TC}`,annotation:(t,e={})=>{let r=`${eB}1337;`,o=typeof e.x<"u",a=typeof e.y<"u";if((o||a)&&!(o&&a&&typeof e.length<"u"))throw new Error("`x`, `y` and `length` must be defined when `x` or `y` is defined");return t=t.replace(/\|/g,""),r+=e.isHidden?"AddHiddenAnnotation=":"AddAnnotation=",e.length>0?r+=(o?[t,e.length,e.x,e.y]:[e.length,t]).join("|"):r+=t,r+TC}}});var Zye=_((nVt,p6)=>{"use strict";var Xye=(t,e)=>{for(let r of Reflect.ownKeys(e))Object.defineProperty(t,r,Object.getOwnPropertyDescriptor(e,r));return t};p6.exports=Xye;p6.exports.default=Xye});var eEe=_((iVt,Tk)=>{"use strict";var Myt=Zye(),Fk=new WeakMap,$ye=(t,e={})=>{if(typeof t!="function")throw new TypeError("Expected a function");let r,o=0,a=t.displayName||t.name||"",n=function(...u){if(Fk.set(n,++o),o===1)r=t.apply(this,u),t=null;else if(e.throw===!0)throw new Error(`Function \`${a}\` can only be called once`);return r};return Myt(n,t),Fk.set(n,o),n};Tk.exports=$ye;Tk.exports.default=$ye;Tk.exports.callCount=t=>{if(!Fk.has(t))throw new Error(`The given function \`${t.name}\` is not wrapped by the \`onetime\` package`);return Fk.get(t)}});var tEe=_((sVt,Rk)=>{Rk.exports=["SIGABRT","SIGALRM","SIGHUP","SIGINT","SIGTERM"];process.platform!=="win32"&&Rk.exports.push("SIGVTALRM","SIGXCPU","SIGXFSZ","SIGUSR2","SIGTRAP","SIGSYS","SIGQUIT","SIGIOT");process.platform==="linux"&&Rk.exports.push("SIGIO","SIGPOLL","SIGPWR","SIGSTKFLT","SIGUNUSED")});var d6=_((oVt,LC)=>{var Ei=global.process,nm=function(t){return t&&typeof t=="object"&&typeof t.removeListener=="function"&&typeof t.emit=="function"&&typeof t.reallyExit=="function"&&typeof t.listeners=="function"&&typeof t.kill=="function"&&typeof t.pid=="number"&&typeof t.on=="function"};nm(Ei)?(rEe=Be("assert"),RC=tEe(),nEe=/^win/i.test(Ei.platform),tB=Be("events"),typeof tB!="function"&&(tB=tB.EventEmitter),Ei.__signal_exit_emitter__?Rs=Ei.__signal_exit_emitter__:(Rs=Ei.__signal_exit_emitter__=new tB,Rs.count=0,Rs.emitted={}),Rs.infinite||(Rs.setMaxListeners(1/0),Rs.infinite=!0),LC.exports=function(t,e){if(!nm(global.process))return function(){};rEe.equal(typeof t,"function","a callback must be provided for exit handler"),NC===!1&&h6();var r="exit";e&&e.alwaysLast&&(r="afterexit");var o=function(){Rs.removeListener(r,t),Rs.listeners("exit").length===0&&Rs.listeners("afterexit").length===0&&Nk()};return Rs.on(r,t),o},Nk=function(){!NC||!nm(global.process)||(NC=!1,RC.forEach(function(e){try{Ei.removeListener(e,Lk[e])}catch{}}),Ei.emit=Mk,Ei.reallyExit=g6,Rs.count-=1)},LC.exports.unload=Nk,im=function(e,r,o){Rs.emitted[e]||(Rs.emitted[e]=!0,Rs.emit(e,r,o))},Lk={},RC.forEach(function(t){Lk[t]=function(){if(!!nm(global.process)){var r=Ei.listeners(t);r.length===Rs.count&&(Nk(),im("exit",null,t),im("afterexit",null,t),nEe&&t==="SIGHUP"&&(t="SIGINT"),Ei.kill(Ei.pid,t))}}}),LC.exports.signals=function(){return RC},NC=!1,h6=function(){NC||!nm(global.process)||(NC=!0,Rs.count+=1,RC=RC.filter(function(e){try{return Ei.on(e,Lk[e]),!0}catch{return!1}}),Ei.emit=sEe,Ei.reallyExit=iEe)},LC.exports.load=h6,g6=Ei.reallyExit,iEe=function(e){!nm(global.process)||(Ei.exitCode=e||0,im("exit",Ei.exitCode,null),im("afterexit",Ei.exitCode,null),g6.call(Ei,Ei.exitCode))},Mk=Ei.emit,sEe=function(e,r){if(e==="exit"&&nm(global.process)){r!==void 0&&(Ei.exitCode=r);var o=Mk.apply(this,arguments);return im("exit",Ei.exitCode,null),im("afterexit",Ei.exitCode,null),o}else return Mk.apply(this,arguments)}):LC.exports=function(){return function(){}};var rEe,RC,nEe,tB,Rs,Nk,im,Lk,NC,h6,g6,iEe,Mk,sEe});var aEe=_((aVt,oEe)=>{"use strict";var Oyt=eEe(),Uyt=d6();oEe.exports=Oyt(()=>{Uyt(()=>{process.stderr.write("\x1B[?25h")},{alwaysLast:!0})})});var m6=_(MC=>{"use strict";var _yt=aEe(),Ok=!1;MC.show=(t=process.stderr)=>{!t.isTTY||(Ok=!1,t.write("\x1B[?25h"))};MC.hide=(t=process.stderr)=>{!t.isTTY||(_yt(),Ok=!0,t.write("\x1B[?25l"))};MC.toggle=(t,e)=>{t!==void 0&&(Ok=t),Ok?MC.show(e):MC.hide(e)}});var AEe=_(rB=>{"use strict";var uEe=rB&&rB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(rB,"__esModule",{value:!0});var lEe=uEe(f6()),cEe=uEe(m6()),Hyt=(t,{showCursor:e=!1}={})=>{let r=0,o="",a=!1,n=u=>{!e&&!a&&(cEe.default.hide(),a=!0);let A=u+` -`;A!==o&&(o=A,t.write(lEe.default.eraseLines(r)+A),r=A.split(` -`).length)};return n.clear=()=>{t.write(lEe.default.eraseLines(r)),o="",r=0},n.done=()=>{o="",r=0,e||(cEe.default.show(),a=!1)},n};rB.default={create:Hyt}});var fEe=_((uVt,jyt)=>{jyt.exports=[{name:"AppVeyor",constant:"APPVEYOR",env:"APPVEYOR",pr:"APPVEYOR_PULL_REQUEST_NUMBER"},{name:"Azure Pipelines",constant:"AZURE_PIPELINES",env:"SYSTEM_TEAMFOUNDATIONCOLLECTIONURI",pr:"SYSTEM_PULLREQUEST_PULLREQUESTID"},{name:"Bamboo",constant:"BAMBOO",env:"bamboo_planKey"},{name:"Bitbucket Pipelines",constant:"BITBUCKET",env:"BITBUCKET_COMMIT",pr:"BITBUCKET_PR_ID"},{name:"Bitrise",constant:"BITRISE",env:"BITRISE_IO",pr:"BITRISE_PULL_REQUEST"},{name:"Buddy",constant:"BUDDY",env:"BUDDY_WORKSPACE_ID",pr:"BUDDY_EXECUTION_PULL_REQUEST_ID"},{name:"Buildkite",constant:"BUILDKITE",env:"BUILDKITE",pr:{env:"BUILDKITE_PULL_REQUEST",ne:"false"}},{name:"CircleCI",constant:"CIRCLE",env:"CIRCLECI",pr:"CIRCLE_PULL_REQUEST"},{name:"Cirrus CI",constant:"CIRRUS",env:"CIRRUS_CI",pr:"CIRRUS_PR"},{name:"AWS CodeBuild",constant:"CODEBUILD",env:"CODEBUILD_BUILD_ARN"},{name:"Codeship",constant:"CODESHIP",env:{CI_NAME:"codeship"}},{name:"Drone",constant:"DRONE",env:"DRONE",pr:{DRONE_BUILD_EVENT:"pull_request"}},{name:"dsari",constant:"DSARI",env:"DSARI"},{name:"GitLab CI",constant:"GITLAB",env:"GITLAB_CI"},{name:"GoCD",constant:"GOCD",env:"GO_PIPELINE_LABEL"},{name:"Hudson",constant:"HUDSON",env:"HUDSON_URL"},{name:"Jenkins",constant:"JENKINS",env:["JENKINS_URL","BUILD_ID"],pr:{any:["ghprbPullId","CHANGE_ID"]}},{name:"Magnum CI",constant:"MAGNUM",env:"MAGNUM"},{name:"Netlify CI",constant:"NETLIFY",env:"NETLIFY_BUILD_BASE",pr:{env:"PULL_REQUEST",ne:"false"}},{name:"Sail CI",constant:"SAIL",env:"SAILCI",pr:"SAIL_PULL_REQUEST_NUMBER"},{name:"Semaphore",constant:"SEMAPHORE",env:"SEMAPHORE",pr:"PULL_REQUEST_NUMBER"},{name:"Shippable",constant:"SHIPPABLE",env:"SHIPPABLE",pr:{IS_PULL_REQUEST:"true"}},{name:"Solano CI",constant:"SOLANO",env:"TDDIUM",pr:"TDDIUM_PR_ID"},{name:"Strider CD",constant:"STRIDER",env:"STRIDER"},{name:"TaskCluster",constant:"TASKCLUSTER",env:["TASK_ID","RUN_ID"]},{name:"TeamCity",constant:"TEAMCITY",env:"TEAMCITY_VERSION"},{name:"Travis CI",constant:"TRAVIS",env:"TRAVIS",pr:{env:"TRAVIS_PULL_REQUEST",ne:"false"}}]});var gEe=_(gl=>{"use strict";var hEe=fEe(),pA=process.env;Object.defineProperty(gl,"_vendors",{value:hEe.map(function(t){return t.constant})});gl.name=null;gl.isPR=null;hEe.forEach(function(t){var e=Array.isArray(t.env)?t.env:[t.env],r=e.every(function(o){return pEe(o)});if(gl[t.constant]=r,r)switch(gl.name=t.name,typeof t.pr){case"string":gl.isPR=!!pA[t.pr];break;case"object":"env"in t.pr?gl.isPR=t.pr.env in pA&&pA[t.pr.env]!==t.pr.ne:"any"in t.pr?gl.isPR=t.pr.any.some(function(o){return!!pA[o]}):gl.isPR=pEe(t.pr);break;default:gl.isPR=null}});gl.isCI=!!(pA.CI||pA.CONTINUOUS_INTEGRATION||pA.BUILD_NUMBER||pA.RUN_ID||gl.name);function pEe(t){return typeof t=="string"?!!pA[t]:Object.keys(t).every(function(e){return pA[e]===t[e]})}});var mEe=_((fVt,dEe)=>{"use strict";dEe.exports=gEe().isCI});var EEe=_((pVt,yEe)=>{"use strict";var qyt=t=>{let e=new Set;do for(let r of Reflect.ownKeys(t))e.add([t,r]);while((t=Reflect.getPrototypeOf(t))&&t!==Object.prototype);return e};yEe.exports=(t,{include:e,exclude:r}={})=>{let o=a=>{let n=u=>typeof u=="string"?a===u:u.test(a);return e?e.some(n):r?!r.some(n):!0};for(let[a,n]of qyt(t.constructor.prototype)){if(n==="constructor"||!o(n))continue;let u=Reflect.getOwnPropertyDescriptor(a,n);u&&typeof u.value=="function"&&(t[n]=t[n].bind(t))}return t}});var PEe=_(kn=>{"use strict";Object.defineProperty(kn,"__esModule",{value:!0});var UC,sB,qk,Gk,v6;typeof window>"u"||typeof MessageChannel!="function"?(OC=null,y6=null,E6=function(){if(OC!==null)try{var t=kn.unstable_now();OC(!0,t),OC=null}catch(e){throw setTimeout(E6,0),e}},CEe=Date.now(),kn.unstable_now=function(){return Date.now()-CEe},UC=function(t){OC!==null?setTimeout(UC,0,t):(OC=t,setTimeout(E6,0))},sB=function(t,e){y6=setTimeout(t,e)},qk=function(){clearTimeout(y6)},Gk=function(){return!1},v6=kn.unstable_forceFrameRate=function(){}):(Uk=window.performance,C6=window.Date,wEe=window.setTimeout,IEe=window.clearTimeout,typeof console<"u"&&(BEe=window.cancelAnimationFrame,typeof window.requestAnimationFrame!="function"&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"),typeof BEe!="function"&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills")),typeof Uk=="object"&&typeof Uk.now=="function"?kn.unstable_now=function(){return Uk.now()}:(vEe=C6.now(),kn.unstable_now=function(){return C6.now()-vEe}),nB=!1,iB=null,_k=-1,w6=5,I6=0,Gk=function(){return kn.unstable_now()>=I6},v6=function(){},kn.unstable_forceFrameRate=function(t){0>t||125jk(u,r))p!==void 0&&0>jk(p,u)?(t[o]=p,t[A]=r,o=A):(t[o]=u,t[n]=r,o=n);else if(p!==void 0&&0>jk(p,r))t[o]=p,t[A]=r,o=A;else break e}}return e}return null}function jk(t,e){var r=t.sortIndex-e.sortIndex;return r!==0?r:t.id-e.id}var eu=[],m0=[],Gyt=1,na=null,Lo=3,Wk=!1,sm=!1,oB=!1;function Vk(t){for(var e=nc(m0);e!==null;){if(e.callback===null)Yk(m0);else if(e.startTime<=t)Yk(m0),e.sortIndex=e.expirationTime,D6(eu,e);else break;e=nc(m0)}}function P6(t){if(oB=!1,Vk(t),!sm)if(nc(eu)!==null)sm=!0,UC(S6);else{var e=nc(m0);e!==null&&sB(P6,e.startTime-t)}}function S6(t,e){sm=!1,oB&&(oB=!1,qk()),Wk=!0;var r=Lo;try{for(Vk(e),na=nc(eu);na!==null&&(!(na.expirationTime>e)||t&&!Gk());){var o=na.callback;if(o!==null){na.callback=null,Lo=na.priorityLevel;var a=o(na.expirationTime<=e);e=kn.unstable_now(),typeof a=="function"?na.callback=a:na===nc(eu)&&Yk(eu),Vk(e)}else Yk(eu);na=nc(eu)}if(na!==null)var n=!0;else{var u=nc(m0);u!==null&&sB(P6,u.startTime-e),n=!1}return n}finally{na=null,Lo=r,Wk=!1}}function DEe(t){switch(t){case 1:return-1;case 2:return 250;case 5:return 1073741823;case 4:return 1e4;default:return 5e3}}var Yyt=v6;kn.unstable_ImmediatePriority=1;kn.unstable_UserBlockingPriority=2;kn.unstable_NormalPriority=3;kn.unstable_IdlePriority=5;kn.unstable_LowPriority=4;kn.unstable_runWithPriority=function(t,e){switch(t){case 1:case 2:case 3:case 4:case 5:break;default:t=3}var r=Lo;Lo=t;try{return e()}finally{Lo=r}};kn.unstable_next=function(t){switch(Lo){case 1:case 2:case 3:var e=3;break;default:e=Lo}var r=Lo;Lo=e;try{return t()}finally{Lo=r}};kn.unstable_scheduleCallback=function(t,e,r){var o=kn.unstable_now();if(typeof r=="object"&&r!==null){var a=r.delay;a=typeof a=="number"&&0o?(t.sortIndex=a,D6(m0,t),nc(eu)===null&&t===nc(m0)&&(oB?qk():oB=!0,sB(P6,a-o))):(t.sortIndex=r,D6(eu,t),sm||Wk||(sm=!0,UC(S6))),t};kn.unstable_cancelCallback=function(t){t.callback=null};kn.unstable_wrapCallback=function(t){var e=Lo;return function(){var r=Lo;Lo=e;try{return t.apply(this,arguments)}finally{Lo=r}}};kn.unstable_getCurrentPriorityLevel=function(){return Lo};kn.unstable_shouldYield=function(){var t=kn.unstable_now();Vk(t);var e=nc(eu);return e!==na&&na!==null&&e!==null&&e.callback!==null&&e.startTime<=t&&e.expirationTime{"use strict";SEe.exports=PEe()});var xEe=_((dVt,aB)=>{aB.exports=function t(e){"use strict";var r=t6(),o=sn(),a=x6();function n(P){for(var D="https://reactjs.org/docs/error-decoder.html?invariant="+P,R=1;Rao||(P.current=yl[ao],yl[ao]=null,ao--)}function Mn(P,D){ao++,yl[ao]=P.current,P.current=D}var Ni={},On={current:Ni},_i={current:!1},tr=Ni;function Me(P,D){var R=P.type.contextTypes;if(!R)return Ni;var j=P.stateNode;if(j&&j.__reactInternalMemoizedUnmaskedChildContext===D)return j.__reactInternalMemoizedMaskedChildContext;var Y={},fe;for(fe in R)Y[fe]=D[fe];return j&&(P=P.stateNode,P.__reactInternalMemoizedUnmaskedChildContext=D,P.__reactInternalMemoizedMaskedChildContext=Y),Y}function ii(P){return P=P.childContextTypes,P!=null}function Oa(P){Kn(_i,P),Kn(On,P)}function hr(P){Kn(_i,P),Kn(On,P)}function uc(P,D,R){if(On.current!==Ni)throw Error(n(168));Mn(On,D,P),Mn(_i,R,P)}function uu(P,D,R){var j=P.stateNode;if(P=D.childContextTypes,typeof j.getChildContext!="function")return R;j=j.getChildContext();for(var Y in j)if(!(Y in P))throw Error(n(108,ae(D)||"Unknown",Y));return r({},R,{},j)}function Ac(P){var D=P.stateNode;return D=D&&D.__reactInternalMemoizedMergedChildContext||Ni,tr=On.current,Mn(On,D,P),Mn(_i,_i.current,P),!0}function El(P,D,R){var j=P.stateNode;if(!j)throw Error(n(169));R?(D=uu(P,D,tr),j.__reactInternalMemoizedMergedChildContext=D,Kn(_i,P),Kn(On,P),Mn(On,D,P)):Kn(_i,P),Mn(_i,R,P)}var vA=a.unstable_runWithPriority,Au=a.unstable_scheduleCallback,Ce=a.unstable_cancelCallback,Tt=a.unstable_shouldYield,fc=a.unstable_requestPaint,Hi=a.unstable_now,fu=a.unstable_getCurrentPriorityLevel,Yt=a.unstable_ImmediatePriority,Cl=a.unstable_UserBlockingPriority,DA=a.unstable_NormalPriority,cp=a.unstable_LowPriority,pc=a.unstable_IdlePriority,PA={},Qn=fc!==void 0?fc:function(){},hi=null,hc=null,SA=!1,sa=Hi(),Li=1e4>sa?Hi:function(){return Hi()-sa};function _o(){switch(fu()){case Yt:return 99;case Cl:return 98;case DA:return 97;case cp:return 96;case pc:return 95;default:throw Error(n(332))}}function Ze(P){switch(P){case 99:return Yt;case 98:return Cl;case 97:return DA;case 96:return cp;case 95:return pc;default:throw Error(n(332))}}function lo(P,D){return P=Ze(P),vA(P,D)}function gc(P,D,R){return P=Ze(P),Au(P,D,R)}function pu(P){return hi===null?(hi=[P],hc=Au(Yt,hu)):hi.push(P),PA}function ji(){if(hc!==null){var P=hc;hc=null,Ce(P)}hu()}function hu(){if(!SA&&hi!==null){SA=!0;var P=0;try{var D=hi;lo(99,function(){for(;P=D&&(qo=!0),P.firstContext=null)}function ms(P,D){if(aa!==P&&D!==!1&&D!==0)if((typeof D!="number"||D===1073741823)&&(aa=P,D=1073741823),D={context:P,observedBits:D,next:null},Us===null){if(co===null)throw Error(n(308));Us=D,co.dependencies={expirationTime:0,firstContext:D,responders:null}}else Us=Us.next=D;return x?P._currentValue:P._currentValue2}var _s=!1;function Un(P){return{baseState:P,firstUpdate:null,lastUpdate:null,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function Pn(P){return{baseState:P.baseState,firstUpdate:P.firstUpdate,lastUpdate:P.lastUpdate,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function ys(P,D){return{expirationTime:P,suspenseConfig:D,tag:0,payload:null,callback:null,next:null,nextEffect:null}}function We(P,D){P.lastUpdate===null?P.firstUpdate=P.lastUpdate=D:(P.lastUpdate.next=D,P.lastUpdate=D)}function tt(P,D){var R=P.alternate;if(R===null){var j=P.updateQueue,Y=null;j===null&&(j=P.updateQueue=Un(P.memoizedState))}else j=P.updateQueue,Y=R.updateQueue,j===null?Y===null?(j=P.updateQueue=Un(P.memoizedState),Y=R.updateQueue=Un(R.memoizedState)):j=P.updateQueue=Pn(Y):Y===null&&(Y=R.updateQueue=Pn(j));Y===null||j===Y?We(j,D):j.lastUpdate===null||Y.lastUpdate===null?(We(j,D),We(Y,D)):(We(j,D),Y.lastUpdate=D)}function It(P,D){var R=P.updateQueue;R=R===null?P.updateQueue=Un(P.memoizedState):nr(P,R),R.lastCapturedUpdate===null?R.firstCapturedUpdate=R.lastCapturedUpdate=D:(R.lastCapturedUpdate.next=D,R.lastCapturedUpdate=D)}function nr(P,D){var R=P.alternate;return R!==null&&D===R.updateQueue&&(D=P.updateQueue=Pn(D)),D}function $(P,D,R,j,Y,fe){switch(R.tag){case 1:return P=R.payload,typeof P=="function"?P.call(fe,j,Y):P;case 3:P.effectTag=P.effectTag&-4097|64;case 0:if(P=R.payload,Y=typeof P=="function"?P.call(fe,j,Y):P,Y==null)break;return r({},j,Y);case 2:_s=!0}return j}function me(P,D,R,j,Y){_s=!1,D=nr(P,D);for(var fe=D.baseState,ve=null,vt=0,wt=D.firstUpdate,bt=fe;wt!==null;){var _r=wt.expirationTime;_rxn?(ai=Fr,Fr=null):ai=Fr.sibling;var en=di(rt,Fr,At[xn],Wt);if(en===null){Fr===null&&(Fr=ai);break}P&&Fr&&en.alternate===null&&D(rt,Fr),Ke=fe(en,Ke,xn),Sn===null?vr=en:Sn.sibling=en,Sn=en,Fr=ai}if(xn===At.length)return R(rt,Fr),vr;if(Fr===null){for(;xnxn?(ai=Fr,Fr=null):ai=Fr.sibling;var ho=di(rt,Fr,en.value,Wt);if(ho===null){Fr===null&&(Fr=ai);break}P&&Fr&&ho.alternate===null&&D(rt,Fr),Ke=fe(ho,Ke,xn),Sn===null?vr=ho:Sn.sibling=ho,Sn=ho,Fr=ai}if(en.done)return R(rt,Fr),vr;if(Fr===null){for(;!en.done;xn++,en=At.next())en=is(rt,en.value,Wt),en!==null&&(Ke=fe(en,Ke,xn),Sn===null?vr=en:Sn.sibling=en,Sn=en);return vr}for(Fr=j(rt,Fr);!en.done;xn++,en=At.next())en=po(Fr,rt,xn,en.value,Wt),en!==null&&(P&&en.alternate!==null&&Fr.delete(en.key===null?xn:en.key),Ke=fe(en,Ke,xn),Sn===null?vr=en:Sn.sibling=en,Sn=en);return P&&Fr.forEach(function(PF){return D(rt,PF)}),vr}return function(rt,Ke,At,Wt){var vr=typeof At=="object"&&At!==null&&At.type===E&&At.key===null;vr&&(At=At.props.children);var Sn=typeof At=="object"&&At!==null;if(Sn)switch(At.$$typeof){case p:e:{for(Sn=At.key,vr=Ke;vr!==null;){if(vr.key===Sn)if(vr.tag===7?At.type===E:vr.elementType===At.type){R(rt,vr.sibling),Ke=Y(vr,At.type===E?At.props.children:At.props,Wt),Ke.ref=kA(rt,vr,At),Ke.return=rt,rt=Ke;break e}else{R(rt,vr);break}else D(rt,vr);vr=vr.sibling}At.type===E?(Ke=xu(At.props.children,rt.mode,Wt,At.key),Ke.return=rt,rt=Ke):(Wt=Hm(At.type,At.key,At.props,null,rt.mode,Wt),Wt.ref=kA(rt,Ke,At),Wt.return=rt,rt=Wt)}return ve(rt);case h:e:{for(vr=At.key;Ke!==null;){if(Ke.key===vr)if(Ke.tag===4&&Ke.stateNode.containerInfo===At.containerInfo&&Ke.stateNode.implementation===At.implementation){R(rt,Ke.sibling),Ke=Y(Ke,At.children||[],Wt),Ke.return=rt,rt=Ke;break e}else{R(rt,Ke);break}else D(rt,Ke);Ke=Ke.sibling}Ke=Fw(At,rt.mode,Wt),Ke.return=rt,rt=Ke}return ve(rt)}if(typeof At=="string"||typeof At=="number")return At=""+At,Ke!==null&&Ke.tag===6?(R(rt,Ke.sibling),Ke=Y(Ke,At,Wt),Ke.return=rt,rt=Ke):(R(rt,Ke),Ke=Qw(At,rt.mode,Wt),Ke.return=rt,rt=Ke),ve(rt);if(bA(At))return VA(rt,Ke,At,Wt);if(Ae(At))return Yo(rt,Ke,At,Wt);if(Sn&&up(rt,At),typeof At>"u"&&!vr)switch(rt.tag){case 1:case 0:throw rt=rt.type,Error(n(152,rt.displayName||rt.name||"Component"))}return R(rt,Ke)}}var gu=ng(!0),ig=ng(!1),du={},uo={current:du},QA={current:du},mc={current:du};function ca(P){if(P===du)throw Error(n(174));return P}function sg(P,D){Mn(mc,D,P),Mn(QA,P,P),Mn(uo,du,P),D=ne(D),Kn(uo,P),Mn(uo,D,P)}function yc(P){Kn(uo,P),Kn(QA,P),Kn(mc,P)}function Pm(P){var D=ca(mc.current),R=ca(uo.current);D=ee(R,P.type,D),R!==D&&(Mn(QA,P,P),Mn(uo,D,P))}function og(P){QA.current===P&&(Kn(uo,P),Kn(QA,P))}var $n={current:0};function Ap(P){for(var D=P;D!==null;){if(D.tag===13){var R=D.memoizedState;if(R!==null&&(R=R.dehydrated,R===null||Ls(R)||so(R)))return D}else if(D.tag===19&&D.memoizedProps.revealOrder!==void 0){if((D.effectTag&64)!==0)return D}else if(D.child!==null){D.child.return=D,D=D.child;continue}if(D===P)break;for(;D.sibling===null;){if(D.return===null||D.return===P)return null;D=D.return}D.sibling.return=D.return,D=D.sibling}return null}function ag(P,D){return{responder:P,props:D}}var FA=u.ReactCurrentDispatcher,Hs=u.ReactCurrentBatchConfig,mu=0,Ha=null,Gi=null,ua=null,yu=null,Es=null,Ec=null,Cc=0,G=null,Dt=0,wl=!1,bi=null,wc=0;function ct(){throw Error(n(321))}function Eu(P,D){if(D===null)return!1;for(var R=0;RCc&&(Cc=_r,_m(Cc))):(Pw(_r,wt.suspenseConfig),fe=wt.eagerReducer===P?wt.eagerState:P(fe,wt.action)),ve=wt,wt=wt.next}while(wt!==null&&wt!==j);bt||(vt=ve,Y=fe),hs(fe,D.memoizedState)||(qo=!0),D.memoizedState=fe,D.baseUpdate=vt,D.baseState=Y,R.lastRenderedState=fe}return[D.memoizedState,R.dispatch]}function cg(P){var D=TA();return typeof P=="function"&&(P=P()),D.memoizedState=D.baseState=P,P=D.queue={last:null,dispatch:null,lastRenderedReducer:Br,lastRenderedState:P},P=P.dispatch=hg.bind(null,Ha,P),[D.memoizedState,P]}function ug(P){return Cs(Br,P)}function Ag(P,D,R,j){return P={tag:P,create:D,destroy:R,deps:j,next:null},G===null?(G={lastEffect:null},G.lastEffect=P.next=P):(D=G.lastEffect,D===null?G.lastEffect=P.next=P:(R=D.next,D.next=P,P.next=R,G.lastEffect=P)),P}function pp(P,D,R,j){var Y=TA();Dt|=P,Y.memoizedState=Ag(D,R,void 0,j===void 0?null:j)}function Ic(P,D,R,j){var Y=fp();j=j===void 0?null:j;var fe=void 0;if(Gi!==null){var ve=Gi.memoizedState;if(fe=ve.destroy,j!==null&&Eu(j,ve.deps)){Ag(0,R,fe,j);return}}Dt|=P,Y.memoizedState=Ag(D,R,fe,j)}function Ct(P,D){return pp(516,192,P,D)}function Sm(P,D){return Ic(516,192,P,D)}function fg(P,D){if(typeof D=="function")return P=P(),D(P),function(){D(null)};if(D!=null)return P=P(),D.current=P,function(){D.current=null}}function pg(){}function Cu(P,D){return TA().memoizedState=[P,D===void 0?null:D],P}function xm(P,D){var R=fp();D=D===void 0?null:D;var j=R.memoizedState;return j!==null&&D!==null&&Eu(D,j[1])?j[0]:(R.memoizedState=[P,D],P)}function hg(P,D,R){if(!(25>wc))throw Error(n(301));var j=P.alternate;if(P===Ha||j!==null&&j===Ha)if(wl=!0,P={expirationTime:mu,suspenseConfig:null,action:R,eagerReducer:null,eagerState:null,next:null},bi===null&&(bi=new Map),R=bi.get(D),R===void 0)bi.set(D,P);else{for(D=R;D.next!==null;)D=D.next;D.next=P}else{var Y=ga(),fe=pt.suspense;Y=HA(Y,P,fe),fe={expirationTime:Y,suspenseConfig:fe,action:R,eagerReducer:null,eagerState:null,next:null};var ve=D.last;if(ve===null)fe.next=fe;else{var vt=ve.next;vt!==null&&(fe.next=vt),ve.next=fe}if(D.last=fe,P.expirationTime===0&&(j===null||j.expirationTime===0)&&(j=D.lastRenderedReducer,j!==null))try{var wt=D.lastRenderedState,bt=j(wt,R);if(fe.eagerReducer=j,fe.eagerState=bt,hs(bt,wt))return}catch{}finally{}Sc(P,Y)}}var wu={readContext:ms,useCallback:ct,useContext:ct,useEffect:ct,useImperativeHandle:ct,useLayoutEffect:ct,useMemo:ct,useReducer:ct,useRef:ct,useState:ct,useDebugValue:ct,useResponder:ct,useDeferredValue:ct,useTransition:ct},yw={readContext:ms,useCallback:Cu,useContext:ms,useEffect:Ct,useImperativeHandle:function(P,D,R){return R=R!=null?R.concat([P]):null,pp(4,36,fg.bind(null,D,P),R)},useLayoutEffect:function(P,D){return pp(4,36,P,D)},useMemo:function(P,D){var R=TA();return D=D===void 0?null:D,P=P(),R.memoizedState=[P,D],P},useReducer:function(P,D,R){var j=TA();return D=R!==void 0?R(D):D,j.memoizedState=j.baseState=D,P=j.queue={last:null,dispatch:null,lastRenderedReducer:P,lastRenderedState:D},P=P.dispatch=hg.bind(null,Ha,P),[j.memoizedState,P]},useRef:function(P){var D=TA();return P={current:P},D.memoizedState=P},useState:cg,useDebugValue:pg,useResponder:ag,useDeferredValue:function(P,D){var R=cg(P),j=R[0],Y=R[1];return Ct(function(){a.unstable_next(function(){var fe=Hs.suspense;Hs.suspense=D===void 0?null:D;try{Y(P)}finally{Hs.suspense=fe}})},[P,D]),j},useTransition:function(P){var D=cg(!1),R=D[0],j=D[1];return[Cu(function(Y){j(!0),a.unstable_next(function(){var fe=Hs.suspense;Hs.suspense=P===void 0?null:P;try{j(!1),Y()}finally{Hs.suspense=fe}})},[P,R]),R]}},bm={readContext:ms,useCallback:xm,useContext:ms,useEffect:Sm,useImperativeHandle:function(P,D,R){return R=R!=null?R.concat([P]):null,Ic(4,36,fg.bind(null,D,P),R)},useLayoutEffect:function(P,D){return Ic(4,36,P,D)},useMemo:function(P,D){var R=fp();D=D===void 0?null:D;var j=R.memoizedState;return j!==null&&D!==null&&Eu(D,j[1])?j[0]:(P=P(),R.memoizedState=[P,D],P)},useReducer:Cs,useRef:function(){return fp().memoizedState},useState:ug,useDebugValue:pg,useResponder:ag,useDeferredValue:function(P,D){var R=ug(P),j=R[0],Y=R[1];return Sm(function(){a.unstable_next(function(){var fe=Hs.suspense;Hs.suspense=D===void 0?null:D;try{Y(P)}finally{Hs.suspense=fe}})},[P,D]),j},useTransition:function(P){var D=ug(!1),R=D[0],j=D[1];return[xm(function(Y){j(!0),a.unstable_next(function(){var fe=Hs.suspense;Hs.suspense=P===void 0?null:P;try{j(!1),Y()}finally{Hs.suspense=fe}})},[P,R]),R]}},Aa=null,Bc=null,Il=!1;function Iu(P,D){var R=Dl(5,null,null,0);R.elementType="DELETED",R.type="DELETED",R.stateNode=D,R.return=P,R.effectTag=8,P.lastEffect!==null?(P.lastEffect.nextEffect=R,P.lastEffect=R):P.firstEffect=P.lastEffect=R}function gg(P,D){switch(P.tag){case 5:return D=io(D,P.type,P.pendingProps),D!==null?(P.stateNode=D,!0):!1;case 6:return D=Si(D,P.pendingProps),D!==null?(P.stateNode=D,!0):!1;case 13:return!1;default:return!1}}function RA(P){if(Il){var D=Bc;if(D){var R=D;if(!gg(P,D)){if(D=cc(R),!D||!gg(P,D)){P.effectTag=P.effectTag&-1025|2,Il=!1,Aa=P;return}Iu(Aa,R)}Aa=P,Bc=cu(D)}else P.effectTag=P.effectTag&-1025|2,Il=!1,Aa=P}}function hp(P){for(P=P.return;P!==null&&P.tag!==5&&P.tag!==3&&P.tag!==13;)P=P.return;Aa=P}function ja(P){if(!y||P!==Aa)return!1;if(!Il)return hp(P),Il=!0,!1;var D=P.type;if(P.tag!==5||D!=="head"&&D!=="body"&&!Qe(D,P.memoizedProps))for(D=Bc;D;)Iu(P,D),D=cc(D);if(hp(P),P.tag===13){if(!y)throw Error(n(316));if(P=P.memoizedState,P=P!==null?P.dehydrated:null,!P)throw Error(n(317));Bc=Ms(P)}else Bc=Aa?cc(P.stateNode):null;return!0}function dg(){y&&(Bc=Aa=null,Il=!1)}var gp=u.ReactCurrentOwner,qo=!1;function ws(P,D,R,j){D.child=P===null?ig(D,null,R,j):gu(D,P.child,R,j)}function Ii(P,D,R,j,Y){R=R.render;var fe=D.ref;return ds(D,Y),j=lg(P,D,R,j,fe,Y),P!==null&&!qo?(D.updateQueue=P.updateQueue,D.effectTag&=-517,P.expirationTime<=Y&&(P.expirationTime=0),si(P,D,Y)):(D.effectTag|=1,ws(P,D,j,Y),D.child)}function km(P,D,R,j,Y,fe){if(P===null){var ve=R.type;return typeof ve=="function"&&!kw(ve)&&ve.defaultProps===void 0&&R.compare===null&&R.defaultProps===void 0?(D.tag=15,D.type=ve,Qm(P,D,ve,j,Y,fe)):(P=Hm(R.type,null,j,null,D.mode,fe),P.ref=D.ref,P.return=D,D.child=P)}return ve=P.child,YD)&&_A.set(P,D)))}}function vg(P,D){P.expirationTimeP?D:P)}function fo(P){if(P.lastExpiredTime!==0)P.callbackExpirationTime=1073741823,P.callbackPriority=99,P.callbackNode=pu(Dw.bind(null,P));else{var D=Um(P),R=P.callbackNode;if(D===0)R!==null&&(P.callbackNode=null,P.callbackExpirationTime=0,P.callbackPriority=90);else{var j=ga();if(D===1073741823?j=99:D===1||D===2?j=95:(j=10*(1073741821-D)-10*(1073741821-j),j=0>=j?99:250>=j?98:5250>=j?97:95),R!==null){var Y=P.callbackPriority;if(P.callbackExpirationTime===D&&Y>=j)return;R!==PA&&Ce(R)}P.callbackExpirationTime=D,P.callbackPriority=j,D=D===1073741823?pu(Dw.bind(null,P)):gc(j,Wv.bind(null,P),{timeout:10*(1073741821-D)-Li()}),P.callbackNode=D}}}function Wv(P,D){if(Om=0,D)return D=ga(),jm(P,D),fo(P),null;var R=Um(P);if(R!==0){if(D=P.callbackNode,(yr&(rs|js))!==En)throw Error(n(327));if(Ip(),P===gi&&R===ns||Pu(P,R),Mr!==null){var j=yr;yr|=rs;var Y=qA(P);do try{gF();break}catch(vt){jA(P,vt)}while(1);if(la(),yr=j,Ep.current=Y,Yi===Rm)throw D=Nm,Pu(P,R),WA(P,R),fo(P),D;if(Mr===null)switch(Y=P.finishedWork=P.current.alternate,P.finishedExpirationTime=R,j=Yi,gi=null,j){case Bu:case Rm:throw Error(n(345));case Bi:jm(P,2=R){P.lastPingedTime=R,Pu(P,R);break}}if(fe=Um(P),fe!==0&&fe!==R)break;if(j!==0&&j!==R){P.lastPingedTime=j;break}P.timeoutHandle=Te(Su.bind(null,P),Y);break}Su(P);break;case vl:if(WA(P,R),j=P.lastSuspendedTime,R===j&&(P.nextKnownPendingLevel=Sw(Y)),OA&&(Y=P.lastPingedTime,Y===0||Y>=R)){P.lastPingedTime=R,Pu(P,R);break}if(Y=Um(P),Y!==0&&Y!==R)break;if(j!==0&&j!==R){P.lastPingedTime=j;break}if(MA!==1073741823?j=10*(1073741821-MA)-Li():Ya===1073741823?j=0:(j=10*(1073741821-Ya)-5e3,Y=Li(),R=10*(1073741821-R)-Y,j=Y-j,0>j&&(j=0),j=(120>j?120:480>j?480:1080>j?1080:1920>j?1920:3e3>j?3e3:4320>j?4320:1960*Cw(j/1960))-j,R=j?j=0:(Y=ve.busyDelayMs|0,fe=Li()-(10*(1073741821-fe)-(ve.timeoutMs|0||5e3)),j=fe<=Y?0:Y+j-fe),10 component higher in the tree to provide a loading indicator or placeholder to display.`+ml(Y))}Yi!==Pc&&(Yi=Bi),fe=yg(fe,Y),wt=j;do{switch(wt.tag){case 3:ve=fe,wt.effectTag|=4096,wt.expirationTime=D;var Ke=Gv(wt,ve,D);It(wt,Ke);break e;case 1:ve=fe;var At=wt.type,Wt=wt.stateNode;if((wt.effectTag&64)===0&&(typeof At.getDerivedStateFromError=="function"||Wt!==null&&typeof Wt.componentDidCatch=="function"&&(Du===null||!Du.has(Wt)))){wt.effectTag|=4096,wt.expirationTime=D;var vr=Yv(wt,ve,D);It(wt,vr);break e}}wt=wt.return}while(wt!==null)}Mr=zv(Mr)}catch(Sn){D=Sn;continue}break}while(1)}function qA(){var P=Ep.current;return Ep.current=wu,P===null?wu:P}function Pw(P,D){PCp&&(Cp=P)}function hF(){for(;Mr!==null;)Mr=Jv(Mr)}function gF(){for(;Mr!==null&&!Tt();)Mr=Jv(Mr)}function Jv(P){var D=Zv(P.alternate,P,ns);return P.memoizedProps=P.pendingProps,D===null&&(D=zv(P)),ww.current=null,D}function zv(P){Mr=P;do{var D=Mr.alternate;if(P=Mr.return,(Mr.effectTag&2048)===0){e:{var R=D;D=Mr;var j=ns,Y=D.pendingProps;switch(D.tag){case 2:break;case 16:break;case 15:case 0:break;case 1:ii(D.type)&&Oa(D);break;case 3:yc(D),hr(D),Y=D.stateNode,Y.pendingContext&&(Y.context=Y.pendingContext,Y.pendingContext=null),(R===null||R.child===null)&&ja(D)&&pa(D),Bl(D);break;case 5:og(D);var fe=ca(mc.current);if(j=D.type,R!==null&&D.stateNode!=null)ts(R,D,j,Y,fe),R.ref!==D.ref&&(D.effectTag|=128);else if(Y){if(R=ca(uo.current),ja(D)){if(Y=D,!y)throw Error(n(175));R=ap(Y.stateNode,Y.type,Y.memoizedProps,fe,R,Y),Y.updateQueue=R,R=R!==null,R&&pa(D)}else{var ve=ht(j,Y,fe,R,D);vc(ve,D,!1,!1),D.stateNode=ve,lt(ve,j,Y,fe,R)&&pa(D)}D.ref!==null&&(D.effectTag|=128)}else if(D.stateNode===null)throw Error(n(166));break;case 6:if(R&&D.stateNode!=null)Gr(R,D,R.memoizedProps,Y);else{if(typeof Y!="string"&&D.stateNode===null)throw Error(n(166));if(R=ca(mc.current),fe=ca(uo.current),ja(D)){if(R=D,!y)throw Error(n(176));(R=lp(R.stateNode,R.memoizedProps,R))&&pa(D)}else D.stateNode=_e(Y,R,fe,D)}break;case 11:break;case 13:if(Kn($n,D),Y=D.memoizedState,(D.effectTag&64)!==0){D.expirationTime=j;break e}Y=Y!==null,fe=!1,R===null?D.memoizedProps.fallback!==void 0&&ja(D):(j=R.memoizedState,fe=j!==null,Y||j===null||(j=R.child.sibling,j!==null&&(ve=D.firstEffect,ve!==null?(D.firstEffect=j,j.nextEffect=ve):(D.firstEffect=D.lastEffect=j,j.nextEffect=null),j.effectTag=8))),Y&&!fe&&(D.mode&2)!==0&&(R===null&&D.memoizedProps.unstable_avoidThisFallback!==!0||($n.current&1)!==0?Yi===Bu&&(Yi=ha):((Yi===Bu||Yi===ha)&&(Yi=vl),Cp!==0&&gi!==null&&(WA(gi,ns),eD(gi,Cp)))),S&&Y&&(D.effectTag|=4),w&&(Y||fe)&&(D.effectTag|=4);break;case 7:break;case 8:break;case 12:break;case 4:yc(D),Bl(D);break;case 10:wi(D);break;case 9:break;case 14:break;case 17:ii(D.type)&&Oa(D);break;case 19:if(Kn($n,D),Y=D.memoizedState,Y===null)break;if(fe=(D.effectTag&64)!==0,ve=Y.rendering,ve===null){if(fe)Dc(Y,!1);else if(Yi!==Bu||R!==null&&(R.effectTag&64)!==0)for(R=D.child;R!==null;){if(ve=Ap(R),ve!==null){for(D.effectTag|=64,Dc(Y,!1),R=ve.updateQueue,R!==null&&(D.updateQueue=R,D.effectTag|=4),Y.lastEffect===null&&(D.firstEffect=null),D.lastEffect=Y.lastEffect,R=j,Y=D.child;Y!==null;)fe=Y,j=R,fe.effectTag&=2,fe.nextEffect=null,fe.firstEffect=null,fe.lastEffect=null,ve=fe.alternate,ve===null?(fe.childExpirationTime=0,fe.expirationTime=j,fe.child=null,fe.memoizedProps=null,fe.memoizedState=null,fe.updateQueue=null,fe.dependencies=null):(fe.childExpirationTime=ve.childExpirationTime,fe.expirationTime=ve.expirationTime,fe.child=ve.child,fe.memoizedProps=ve.memoizedProps,fe.memoizedState=ve.memoizedState,fe.updateQueue=ve.updateQueue,j=ve.dependencies,fe.dependencies=j===null?null:{expirationTime:j.expirationTime,firstContext:j.firstContext,responders:j.responders}),Y=Y.sibling;Mn($n,$n.current&1|2,D),D=D.child;break e}R=R.sibling}}else{if(!fe)if(R=Ap(ve),R!==null){if(D.effectTag|=64,fe=!0,R=R.updateQueue,R!==null&&(D.updateQueue=R,D.effectTag|=4),Dc(Y,!0),Y.tail===null&&Y.tailMode==="hidden"&&!ve.alternate){D=D.lastEffect=Y.lastEffect,D!==null&&(D.nextEffect=null);break}}else Li()>Y.tailExpiration&&1Y&&(Y=j),ve>Y&&(Y=ve),fe=fe.sibling;R.childExpirationTime=Y}if(D!==null)return D;P!==null&&(P.effectTag&2048)===0&&(P.firstEffect===null&&(P.firstEffect=Mr.firstEffect),Mr.lastEffect!==null&&(P.lastEffect!==null&&(P.lastEffect.nextEffect=Mr.firstEffect),P.lastEffect=Mr.lastEffect),1P?D:P}function Su(P){var D=_o();return lo(99,dF.bind(null,P,D)),null}function dF(P,D){do Ip();while(Ig!==null);if((yr&(rs|js))!==En)throw Error(n(327));var R=P.finishedWork,j=P.finishedExpirationTime;if(R===null)return null;if(P.finishedWork=null,P.finishedExpirationTime=0,R===P.current)throw Error(n(177));P.callbackNode=null,P.callbackExpirationTime=0,P.callbackPriority=90,P.nextKnownPendingLevel=0;var Y=Sw(R);if(P.firstPendingTime=Y,j<=P.lastSuspendedTime?P.firstSuspendedTime=P.lastSuspendedTime=P.nextKnownPendingLevel=0:j<=P.firstSuspendedTime&&(P.firstSuspendedTime=j-1),j<=P.lastPingedTime&&(P.lastPingedTime=0),j<=P.lastExpiredTime&&(P.lastExpiredTime=0),P===gi&&(Mr=gi=null,ns=0),1=R?ln(P,D,R):(Mn($n,$n.current&1,D),D=si(P,D,R),D!==null?D.sibling:null);Mn($n,$n.current&1,D);break;case 19:if(j=D.childExpirationTime>=R,(P.effectTag&64)!==0){if(j)return qa(P,D,R);D.effectTag|=64}if(Y=D.memoizedState,Y!==null&&(Y.rendering=null,Y.tail=null),Mn($n,$n.current,D),!j)return null}return si(P,D,R)}qo=!1}}else qo=!1;switch(D.expirationTime=0,D.tag){case 2:if(j=D.type,P!==null&&(P.alternate=null,D.alternate=null,D.effectTag|=2),P=D.pendingProps,Y=Me(D,On.current),ds(D,R),Y=lg(null,D,j,P,Y,R),D.effectTag|=1,typeof Y=="object"&&Y!==null&&typeof Y.render=="function"&&Y.$$typeof===void 0){if(D.tag=1,mw(),ii(j)){var fe=!0;Ac(D)}else fe=!1;D.memoizedState=Y.state!==null&&Y.state!==void 0?Y.state:null;var ve=j.getDerivedStateFromProps;typeof ve=="function"&&er(D,j,ve,P),Y.updater=Zr,D.stateNode=Y,Y._reactInternalFiber=D,jo(D,j,P,R),D=mp(null,D,j,!0,fe,R)}else D.tag=0,ws(null,D,Y,R),D=D.child;return D;case 16:if(Y=D.elementType,P!==null&&(P.alternate=null,D.alternate=null,D.effectTag|=2),P=D.pendingProps,ye(Y),Y._status!==1)throw Y._result;switch(Y=Y._result,D.type=Y,fe=D.tag=BF(Y),P=Ci(Y,P),fe){case 0:D=NA(null,D,Y,P,R);break;case 1:D=dp(null,D,Y,P,R);break;case 11:D=Ii(null,D,Y,P,R);break;case 14:D=km(null,D,Y,Ci(Y.type,P),j,R);break;default:throw Error(n(306,Y,""))}return D;case 0:return j=D.type,Y=D.pendingProps,Y=D.elementType===j?Y:Ci(j,Y),NA(P,D,j,Y,R);case 1:return j=D.type,Y=D.pendingProps,Y=D.elementType===j?Y:Ci(j,Y),dp(P,D,j,Y,R);case 3:if(mg(D),j=D.updateQueue,j===null)throw Error(n(282));if(Y=D.memoizedState,Y=Y!==null?Y.element:null,me(D,j,D.pendingProps,null,R),j=D.memoizedState.element,j===Y)dg(),D=si(P,D,R);else{if((Y=D.stateNode.hydrate)&&(y?(Bc=cu(D.stateNode.containerInfo),Aa=D,Y=Il=!0):Y=!1),Y)for(R=ig(D,null,j,R),D.child=R;R;)R.effectTag=R.effectTag&-3|1024,R=R.sibling;else ws(P,D,j,R),dg();D=D.child}return D;case 5:return Pm(D),P===null&&RA(D),j=D.type,Y=D.pendingProps,fe=P!==null?P.memoizedProps:null,ve=Y.children,Qe(j,Y)?ve=null:fe!==null&&Qe(j,fe)&&(D.effectTag|=16),Go(P,D),D.mode&4&&R!==1&&be(j,Y)?(D.expirationTime=D.childExpirationTime=1,D=null):(ws(P,D,ve,R),D=D.child),D;case 6:return P===null&&RA(D),null;case 13:return ln(P,D,R);case 4:return sg(D,D.stateNode.containerInfo),j=D.pendingProps,P===null?D.child=gu(D,null,j,R):ws(P,D,j,R),D.child;case 11:return j=D.type,Y=D.pendingProps,Y=D.elementType===j?Y:Ci(j,Y),Ii(P,D,j,Y,R);case 7:return ws(P,D,D.pendingProps,R),D.child;case 8:return ws(P,D,D.pendingProps.children,R),D.child;case 12:return ws(P,D,D.pendingProps.children,R),D.child;case 10:e:{if(j=D.type._context,Y=D.pendingProps,ve=D.memoizedProps,fe=Y.value,Ho(D,fe),ve!==null){var vt=ve.value;if(fe=hs(vt,fe)?0:(typeof j._calculateChangedBits=="function"?j._calculateChangedBits(vt,fe):1073741823)|0,fe===0){if(ve.children===Y.children&&!_i.current){D=si(P,D,R);break e}}else for(vt=D.child,vt!==null&&(vt.return=D);vt!==null;){var wt=vt.dependencies;if(wt!==null){ve=vt.child;for(var bt=wt.firstContext;bt!==null;){if(bt.context===j&&(bt.observedBits&fe)!==0){vt.tag===1&&(bt=ys(R,null),bt.tag=2,tt(vt,bt)),vt.expirationTime"u")return!1;var D=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(D.isDisabled||!D.supportsFiber)return!0;try{var R=D.inject(P);xw=function(j){try{D.onCommitFiberRoot(R,j,void 0,(j.current.effectTag&64)===64)}catch{}},bw=function(j){try{D.onCommitFiberUnmount(R,j)}catch{}}}catch{}return!0}function IF(P,D,R,j){this.tag=P,this.key=R,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=D,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=j,this.effectTag=0,this.lastEffect=this.firstEffect=this.nextEffect=null,this.childExpirationTime=this.expirationTime=0,this.alternate=null}function Dl(P,D,R,j){return new IF(P,D,R,j)}function kw(P){return P=P.prototype,!(!P||!P.isReactComponent)}function BF(P){if(typeof P=="function")return kw(P)?1:0;if(P!=null){if(P=P.$$typeof,P===L)return 11;if(P===te)return 14}return 2}function YA(P,D){var R=P.alternate;return R===null?(R=Dl(P.tag,D,P.key,P.mode),R.elementType=P.elementType,R.type=P.type,R.stateNode=P.stateNode,R.alternate=P,P.alternate=R):(R.pendingProps=D,R.effectTag=0,R.nextEffect=null,R.firstEffect=null,R.lastEffect=null),R.childExpirationTime=P.childExpirationTime,R.expirationTime=P.expirationTime,R.child=P.child,R.memoizedProps=P.memoizedProps,R.memoizedState=P.memoizedState,R.updateQueue=P.updateQueue,D=P.dependencies,R.dependencies=D===null?null:{expirationTime:D.expirationTime,firstContext:D.firstContext,responders:D.responders},R.sibling=P.sibling,R.index=P.index,R.ref=P.ref,R}function Hm(P,D,R,j,Y,fe){var ve=2;if(j=P,typeof P=="function")kw(P)&&(ve=1);else if(typeof P=="string")ve=5;else e:switch(P){case E:return xu(R.children,Y,fe,D);case T:ve=8,Y|=7;break;case I:ve=8,Y|=1;break;case v:return P=Dl(12,R,D,Y|8),P.elementType=v,P.type=v,P.expirationTime=fe,P;case U:return P=Dl(13,R,D,Y),P.type=U,P.elementType=U,P.expirationTime=fe,P;case J:return P=Dl(19,R,D,Y),P.elementType=J,P.expirationTime=fe,P;default:if(typeof P=="object"&&P!==null)switch(P.$$typeof){case b:ve=10;break e;case C:ve=9;break e;case L:ve=11;break e;case te:ve=14;break e;case le:ve=16,j=null;break e}throw Error(n(130,P==null?P:typeof P,""))}return D=Dl(ve,R,D,Y),D.elementType=P,D.type=j,D.expirationTime=fe,D}function xu(P,D,R,j){return P=Dl(7,P,j,D),P.expirationTime=R,P}function Qw(P,D,R){return P=Dl(6,P,null,D),P.expirationTime=R,P}function Fw(P,D,R){return D=Dl(4,P.children!==null?P.children:[],P.key,D),D.expirationTime=R,D.stateNode={containerInfo:P.containerInfo,pendingChildren:null,implementation:P.implementation},D}function vF(P,D,R){this.tag=D,this.current=null,this.containerInfo=P,this.pingCache=this.pendingChildren=null,this.finishedExpirationTime=0,this.finishedWork=null,this.timeoutHandle=He,this.pendingContext=this.context=null,this.hydrate=R,this.callbackNode=null,this.callbackPriority=90,this.lastExpiredTime=this.lastPingedTime=this.nextKnownPendingLevel=this.lastSuspendedTime=this.firstSuspendedTime=this.firstPendingTime=0}function $v(P,D){var R=P.firstSuspendedTime;return P=P.lastSuspendedTime,R!==0&&R>=D&&P<=D}function WA(P,D){var R=P.firstSuspendedTime,j=P.lastSuspendedTime;RD||R===0)&&(P.lastSuspendedTime=D),D<=P.lastPingedTime&&(P.lastPingedTime=0),D<=P.lastExpiredTime&&(P.lastExpiredTime=0)}function eD(P,D){D>P.firstPendingTime&&(P.firstPendingTime=D);var R=P.firstSuspendedTime;R!==0&&(D>=R?P.firstSuspendedTime=P.lastSuspendedTime=P.nextKnownPendingLevel=0:D>=P.lastSuspendedTime&&(P.lastSuspendedTime=D+1),D>P.nextKnownPendingLevel&&(P.nextKnownPendingLevel=D))}function jm(P,D){var R=P.lastExpiredTime;(R===0||R>D)&&(P.lastExpiredTime=D)}function tD(P){var D=P._reactInternalFiber;if(D===void 0)throw typeof P.render=="function"?Error(n(188)):Error(n(268,Object.keys(P)));return P=Ee(D),P===null?null:P.stateNode}function rD(P,D){P=P.memoizedState,P!==null&&P.dehydrated!==null&&P.retryTime{"use strict";bEe.exports=xEe()});var FEe=_((yVt,QEe)=>{"use strict";var Wyt={ALIGN_COUNT:8,ALIGN_AUTO:0,ALIGN_FLEX_START:1,ALIGN_CENTER:2,ALIGN_FLEX_END:3,ALIGN_STRETCH:4,ALIGN_BASELINE:5,ALIGN_SPACE_BETWEEN:6,ALIGN_SPACE_AROUND:7,DIMENSION_COUNT:2,DIMENSION_WIDTH:0,DIMENSION_HEIGHT:1,DIRECTION_COUNT:3,DIRECTION_INHERIT:0,DIRECTION_LTR:1,DIRECTION_RTL:2,DISPLAY_COUNT:2,DISPLAY_FLEX:0,DISPLAY_NONE:1,EDGE_COUNT:9,EDGE_LEFT:0,EDGE_TOP:1,EDGE_RIGHT:2,EDGE_BOTTOM:3,EDGE_START:4,EDGE_END:5,EDGE_HORIZONTAL:6,EDGE_VERTICAL:7,EDGE_ALL:8,EXPERIMENTAL_FEATURE_COUNT:1,EXPERIMENTAL_FEATURE_WEB_FLEX_BASIS:0,FLEX_DIRECTION_COUNT:4,FLEX_DIRECTION_COLUMN:0,FLEX_DIRECTION_COLUMN_REVERSE:1,FLEX_DIRECTION_ROW:2,FLEX_DIRECTION_ROW_REVERSE:3,JUSTIFY_COUNT:6,JUSTIFY_FLEX_START:0,JUSTIFY_CENTER:1,JUSTIFY_FLEX_END:2,JUSTIFY_SPACE_BETWEEN:3,JUSTIFY_SPACE_AROUND:4,JUSTIFY_SPACE_EVENLY:5,LOG_LEVEL_COUNT:6,LOG_LEVEL_ERROR:0,LOG_LEVEL_WARN:1,LOG_LEVEL_INFO:2,LOG_LEVEL_DEBUG:3,LOG_LEVEL_VERBOSE:4,LOG_LEVEL_FATAL:5,MEASURE_MODE_COUNT:3,MEASURE_MODE_UNDEFINED:0,MEASURE_MODE_EXACTLY:1,MEASURE_MODE_AT_MOST:2,NODE_TYPE_COUNT:2,NODE_TYPE_DEFAULT:0,NODE_TYPE_TEXT:1,OVERFLOW_COUNT:3,OVERFLOW_VISIBLE:0,OVERFLOW_HIDDEN:1,OVERFLOW_SCROLL:2,POSITION_TYPE_COUNT:2,POSITION_TYPE_RELATIVE:0,POSITION_TYPE_ABSOLUTE:1,PRINT_OPTIONS_COUNT:3,PRINT_OPTIONS_LAYOUT:1,PRINT_OPTIONS_STYLE:2,PRINT_OPTIONS_CHILDREN:4,UNIT_COUNT:4,UNIT_UNDEFINED:0,UNIT_POINT:1,UNIT_PERCENT:2,UNIT_AUTO:3,WRAP_COUNT:3,WRAP_NO_WRAP:0,WRAP_WRAP:1,WRAP_WRAP_REVERSE:2};QEe.exports=Wyt});var LEe=_((EVt,NEe)=>{"use strict";var Vyt=Object.assign||function(t){for(var e=1;e"}}]),t}(),TEe=function(){Kk(t,null,[{key:"fromJS",value:function(r){var o=r.width,a=r.height;return new t(o,a)}}]);function t(e,r){k6(this,t),this.width=e,this.height=r}return Kk(t,[{key:"fromJS",value:function(r){r(this.width,this.height)}},{key:"toString",value:function(){return""}}]),t}(),REe=function(){function t(e,r){k6(this,t),this.unit=e,this.value=r}return Kk(t,[{key:"fromJS",value:function(r){r(this.unit,this.value)}},{key:"toString",value:function(){switch(this.unit){case tu.UNIT_POINT:return String(this.value);case tu.UNIT_PERCENT:return this.value+"%";case tu.UNIT_AUTO:return"auto";default:return this.value+"?"}}},{key:"valueOf",value:function(){return this.value}}]),t}();NEe.exports=function(t,e){function r(u,A,p){var h=u[A];u[A]=function(){for(var E=arguments.length,I=Array(E),v=0;v1?I-1:0),b=1;b1&&arguments[1]!==void 0?arguments[1]:NaN,p=arguments.length>2&&arguments[2]!==void 0?arguments[2]:NaN,h=arguments.length>3&&arguments[3]!==void 0?arguments[3]:tu.DIRECTION_LTR;return u.call(this,A,p,h)}),Vyt({Config:e.Config,Node:e.Node,Layout:t("Layout",Kyt),Size:t("Size",TEe),Value:t("Value",REe),getInstanceCount:function(){return e.getInstanceCount.apply(e,arguments)}},tu)}});var MEe=_((exports,module)=>{(function(t,e){typeof define=="function"&&define.amd?define([],function(){return e}):typeof module=="object"&&module.exports?module.exports=e:(t.nbind=t.nbind||{}).init=e})(exports,function(Module,cb){typeof Module=="function"&&(cb=Module,Module={}),Module.onRuntimeInitialized=function(t,e){return function(){t&&t.apply(this,arguments);try{Module.ccall("nbind_init")}catch(r){e(r);return}e(null,{bind:Module._nbind_value,reflect:Module.NBind.reflect,queryType:Module.NBind.queryType,toggleLightGC:Module.toggleLightGC,lib:Module})}}(Module.onRuntimeInitialized,cb);var Module;Module||(Module=(typeof Module<"u"?Module:null)||{});var moduleOverrides={};for(var key in Module)Module.hasOwnProperty(key)&&(moduleOverrides[key]=Module[key]);var ENVIRONMENT_IS_WEB=!1,ENVIRONMENT_IS_WORKER=!1,ENVIRONMENT_IS_NODE=!1,ENVIRONMENT_IS_SHELL=!1;if(Module.ENVIRONMENT)if(Module.ENVIRONMENT==="WEB")ENVIRONMENT_IS_WEB=!0;else if(Module.ENVIRONMENT==="WORKER")ENVIRONMENT_IS_WORKER=!0;else if(Module.ENVIRONMENT==="NODE")ENVIRONMENT_IS_NODE=!0;else if(Module.ENVIRONMENT==="SHELL")ENVIRONMENT_IS_SHELL=!0;else throw new Error("The provided Module['ENVIRONMENT'] value is not valid. It must be one of: WEB|WORKER|NODE|SHELL.");else ENVIRONMENT_IS_WEB=typeof window=="object",ENVIRONMENT_IS_WORKER=typeof importScripts=="function",ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof Be=="function"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER,ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(ENVIRONMENT_IS_NODE){Module.print||(Module.print=console.log),Module.printErr||(Module.printErr=console.warn);var nodeFS,nodePath;Module.read=function(e,r){nodeFS||(nodeFS={}("")),nodePath||(nodePath={}("")),e=nodePath.normalize(e);var o=nodeFS.readFileSync(e);return r?o:o.toString()},Module.readBinary=function(e){var r=Module.read(e,!0);return r.buffer||(r=new Uint8Array(r)),assert(r.buffer),r},Module.load=function(e){globalEval(read(e))},Module.thisProgram||(process.argv.length>1?Module.thisProgram=process.argv[1].replace(/\\/g,"/"):Module.thisProgram="unknown-program"),Module.arguments=process.argv.slice(2),typeof module<"u"&&(module.exports=Module),Module.inspect=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL)Module.print||(Module.print=print),typeof printErr<"u"&&(Module.printErr=printErr),typeof read<"u"?Module.read=read:Module.read=function(){throw"no read() available"},Module.readBinary=function(e){if(typeof readbuffer=="function")return new Uint8Array(readbuffer(e));var r=read(e,"binary");return assert(typeof r=="object"),r},typeof scriptArgs<"u"?Module.arguments=scriptArgs:typeof arguments<"u"&&(Module.arguments=arguments),typeof quit=="function"&&(Module.quit=function(t,e){quit(t)});else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(Module.read=function(e){var r=new XMLHttpRequest;return r.open("GET",e,!1),r.send(null),r.responseText},ENVIRONMENT_IS_WORKER&&(Module.readBinary=function(e){var r=new XMLHttpRequest;return r.open("GET",e,!1),r.responseType="arraybuffer",r.send(null),new Uint8Array(r.response)}),Module.readAsync=function(e,r,o){var a=new XMLHttpRequest;a.open("GET",e,!0),a.responseType="arraybuffer",a.onload=function(){a.status==200||a.status==0&&a.response?r(a.response):o()},a.onerror=o,a.send(null)},typeof arguments<"u"&&(Module.arguments=arguments),typeof console<"u")Module.print||(Module.print=function(e){console.log(e)}),Module.printErr||(Module.printErr=function(e){console.warn(e)});else{var TRY_USE_DUMP=!1;Module.print||(Module.print=TRY_USE_DUMP&&typeof dump<"u"?function(t){dump(t)}:function(t){})}ENVIRONMENT_IS_WORKER&&(Module.load=importScripts),typeof Module.setWindowTitle>"u"&&(Module.setWindowTitle=function(t){document.title=t})}else throw"Unknown runtime environment. Where are we?";function globalEval(t){eval.call(null,t)}!Module.load&&Module.read&&(Module.load=function(e){globalEval(Module.read(e))}),Module.print||(Module.print=function(){}),Module.printErr||(Module.printErr=Module.print),Module.arguments||(Module.arguments=[]),Module.thisProgram||(Module.thisProgram="./this.program"),Module.quit||(Module.quit=function(t,e){throw e}),Module.print=Module.print,Module.printErr=Module.printErr,Module.preRun=[],Module.postRun=[];for(var key in moduleOverrides)moduleOverrides.hasOwnProperty(key)&&(Module[key]=moduleOverrides[key]);moduleOverrides=void 0;var Runtime={setTempRet0:function(t){return tempRet0=t,t},getTempRet0:function(){return tempRet0},stackSave:function(){return STACKTOP},stackRestore:function(t){STACKTOP=t},getNativeTypeSize:function(t){switch(t){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(t[t.length-1]==="*")return Runtime.QUANTUM_SIZE;if(t[0]==="i"){var e=parseInt(t.substr(1));return assert(e%8===0),e/8}else return 0}}},getNativeFieldSize:function(t){return Math.max(Runtime.getNativeTypeSize(t),Runtime.QUANTUM_SIZE)},STACK_ALIGN:16,prepVararg:function(t,e){return e==="double"||e==="i64"?t&7&&(assert((t&7)===4),t+=4):assert((t&3)===0),t},getAlignSize:function(t,e,r){return!r&&(t=="i64"||t=="double")?8:t?Math.min(e||(t?Runtime.getNativeFieldSize(t):0),Runtime.QUANTUM_SIZE):Math.min(e,8)},dynCall:function(t,e,r){return r&&r.length?Module["dynCall_"+t].apply(null,[e].concat(r)):Module["dynCall_"+t].call(null,e)},functionPointers:[],addFunction:function(t){for(var e=0;e>2],r=(e+t+15|0)&-16;if(HEAP32[DYNAMICTOP_PTR>>2]=r,r>=TOTAL_MEMORY){var o=enlargeMemory();if(!o)return HEAP32[DYNAMICTOP_PTR>>2]=e,0}return e},alignMemory:function(t,e){var r=t=Math.ceil(t/(e||16))*(e||16);return r},makeBigInt:function(t,e,r){var o=r?+(t>>>0)+ +(e>>>0)*4294967296:+(t>>>0)+ +(e|0)*4294967296;return o},GLOBAL_BASE:8,QUANTUM_SIZE:4,__dummy__:0};Module.Runtime=Runtime;var ABORT=0,EXITSTATUS=0;function assert(t,e){t||abort("Assertion failed: "+e)}function getCFunc(ident){var func=Module["_"+ident];if(!func)try{func=eval("_"+ident)}catch(t){}return assert(func,"Cannot call unknown function "+ident+" (perhaps LLVM optimizations or closure removed it?)"),func}var cwrap,ccall;(function(){var JSfuncs={stackSave:function(){Runtime.stackSave()},stackRestore:function(){Runtime.stackRestore()},arrayToC:function(t){var e=Runtime.stackAlloc(t.length);return writeArrayToMemory(t,e),e},stringToC:function(t){var e=0;if(t!=null&&t!==0){var r=(t.length<<2)+1;e=Runtime.stackAlloc(r),stringToUTF8(t,e,r)}return e}},toC={string:JSfuncs.stringToC,array:JSfuncs.arrayToC};ccall=function(e,r,o,a,n){var u=getCFunc(e),A=[],p=0;if(a)for(var h=0;h>0]=e;break;case"i8":HEAP8[t>>0]=e;break;case"i16":HEAP16[t>>1]=e;break;case"i32":HEAP32[t>>2]=e;break;case"i64":tempI64=[e>>>0,(tempDouble=e,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[t>>2]=tempI64[0],HEAP32[t+4>>2]=tempI64[1];break;case"float":HEAPF32[t>>2]=e;break;case"double":HEAPF64[t>>3]=e;break;default:abort("invalid type for setValue: "+r)}}Module.setValue=setValue;function getValue(t,e,r){switch(e=e||"i8",e.charAt(e.length-1)==="*"&&(e="i32"),e){case"i1":return HEAP8[t>>0];case"i8":return HEAP8[t>>0];case"i16":return HEAP16[t>>1];case"i32":return HEAP32[t>>2];case"i64":return HEAP32[t>>2];case"float":return HEAPF32[t>>2];case"double":return HEAPF64[t>>3];default:abort("invalid type for setValue: "+e)}return null}Module.getValue=getValue;var ALLOC_NORMAL=0,ALLOC_STACK=1,ALLOC_STATIC=2,ALLOC_DYNAMIC=3,ALLOC_NONE=4;Module.ALLOC_NORMAL=ALLOC_NORMAL,Module.ALLOC_STACK=ALLOC_STACK,Module.ALLOC_STATIC=ALLOC_STATIC,Module.ALLOC_DYNAMIC=ALLOC_DYNAMIC,Module.ALLOC_NONE=ALLOC_NONE;function allocate(t,e,r,o){var a,n;typeof t=="number"?(a=!0,n=t):(a=!1,n=t.length);var u=typeof e=="string"?e:null,A;if(r==ALLOC_NONE?A=o:A=[typeof _malloc=="function"?_malloc:Runtime.staticAlloc,Runtime.stackAlloc,Runtime.staticAlloc,Runtime.dynamicAlloc][r===void 0?ALLOC_STATIC:r](Math.max(n,u?1:e.length)),a){var o=A,p;for(assert((A&3)==0),p=A+(n&-4);o>2]=0;for(p=A+n;o>0]=0;return A}if(u==="i8")return t.subarray||t.slice?HEAPU8.set(t,A):HEAPU8.set(new Uint8Array(t),A),A;for(var h=0,E,I,v;h>0],r|=o,!(o==0&&!e||(a++,e&&a==e)););e||(e=a);var n="";if(r<128){for(var u=1024,A;e>0;)A=String.fromCharCode.apply(String,HEAPU8.subarray(t,t+Math.min(e,u))),n=n?n+A:A,t+=u,e-=u;return n}return Module.UTF8ToString(t)}Module.Pointer_stringify=Pointer_stringify;function AsciiToString(t){for(var e="";;){var r=HEAP8[t++>>0];if(!r)return e;e+=String.fromCharCode(r)}}Module.AsciiToString=AsciiToString;function stringToAscii(t,e){return writeAsciiToMemory(t,e,!1)}Module.stringToAscii=stringToAscii;var UTF8Decoder=typeof TextDecoder<"u"?new TextDecoder("utf8"):void 0;function UTF8ArrayToString(t,e){for(var r=e;t[r];)++r;if(r-e>16&&t.subarray&&UTF8Decoder)return UTF8Decoder.decode(t.subarray(e,r));for(var o,a,n,u,A,p,h="";;){if(o=t[e++],!o)return h;if(!(o&128)){h+=String.fromCharCode(o);continue}if(a=t[e++]&63,(o&224)==192){h+=String.fromCharCode((o&31)<<6|a);continue}if(n=t[e++]&63,(o&240)==224?o=(o&15)<<12|a<<6|n:(u=t[e++]&63,(o&248)==240?o=(o&7)<<18|a<<12|n<<6|u:(A=t[e++]&63,(o&252)==248?o=(o&3)<<24|a<<18|n<<12|u<<6|A:(p=t[e++]&63,o=(o&1)<<30|a<<24|n<<18|u<<12|A<<6|p))),o<65536)h+=String.fromCharCode(o);else{var E=o-65536;h+=String.fromCharCode(55296|E>>10,56320|E&1023)}}}Module.UTF8ArrayToString=UTF8ArrayToString;function UTF8ToString(t){return UTF8ArrayToString(HEAPU8,t)}Module.UTF8ToString=UTF8ToString;function stringToUTF8Array(t,e,r,o){if(!(o>0))return 0;for(var a=r,n=r+o-1,u=0;u=55296&&A<=57343&&(A=65536+((A&1023)<<10)|t.charCodeAt(++u)&1023),A<=127){if(r>=n)break;e[r++]=A}else if(A<=2047){if(r+1>=n)break;e[r++]=192|A>>6,e[r++]=128|A&63}else if(A<=65535){if(r+2>=n)break;e[r++]=224|A>>12,e[r++]=128|A>>6&63,e[r++]=128|A&63}else if(A<=2097151){if(r+3>=n)break;e[r++]=240|A>>18,e[r++]=128|A>>12&63,e[r++]=128|A>>6&63,e[r++]=128|A&63}else if(A<=67108863){if(r+4>=n)break;e[r++]=248|A>>24,e[r++]=128|A>>18&63,e[r++]=128|A>>12&63,e[r++]=128|A>>6&63,e[r++]=128|A&63}else{if(r+5>=n)break;e[r++]=252|A>>30,e[r++]=128|A>>24&63,e[r++]=128|A>>18&63,e[r++]=128|A>>12&63,e[r++]=128|A>>6&63,e[r++]=128|A&63}}return e[r]=0,r-a}Module.stringToUTF8Array=stringToUTF8Array;function stringToUTF8(t,e,r){return stringToUTF8Array(t,HEAPU8,e,r)}Module.stringToUTF8=stringToUTF8;function lengthBytesUTF8(t){for(var e=0,r=0;r=55296&&o<=57343&&(o=65536+((o&1023)<<10)|t.charCodeAt(++r)&1023),o<=127?++e:o<=2047?e+=2:o<=65535?e+=3:o<=2097151?e+=4:o<=67108863?e+=5:e+=6}return e}Module.lengthBytesUTF8=lengthBytesUTF8;var UTF16Decoder=typeof TextDecoder<"u"?new TextDecoder("utf-16le"):void 0;function demangle(t){var e=Module.___cxa_demangle||Module.__cxa_demangle;if(e){try{var r=t.substr(1),o=lengthBytesUTF8(r)+1,a=_malloc(o);stringToUTF8(r,a,o);var n=_malloc(4),u=e(a,0,0,n);if(getValue(n,"i32")===0&&u)return Pointer_stringify(u)}catch{}finally{a&&_free(a),n&&_free(n),u&&_free(u)}return t}return Runtime.warnOnce("warning: build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling"),t}function demangleAll(t){var e=/__Z[\w\d_]+/g;return t.replace(e,function(r){var o=demangle(r);return r===o?r:r+" ["+o+"]"})}function jsStackTrace(){var t=new Error;if(!t.stack){try{throw new Error(0)}catch(e){t=e}if(!t.stack)return"(no stack trace available)"}return t.stack.toString()}function stackTrace(){var t=jsStackTrace();return Module.extraStackTrace&&(t+=` -`+Module.extraStackTrace()),demangleAll(t)}Module.stackTrace=stackTrace;var HEAP,buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferViews(){Module.HEAP8=HEAP8=new Int8Array(buffer),Module.HEAP16=HEAP16=new Int16Array(buffer),Module.HEAP32=HEAP32=new Int32Array(buffer),Module.HEAPU8=HEAPU8=new Uint8Array(buffer),Module.HEAPU16=HEAPU16=new Uint16Array(buffer),Module.HEAPU32=HEAPU32=new Uint32Array(buffer),Module.HEAPF32=HEAPF32=new Float32Array(buffer),Module.HEAPF64=HEAPF64=new Float64Array(buffer)}var STATIC_BASE,STATICTOP,staticSealed,STACK_BASE,STACKTOP,STACK_MAX,DYNAMIC_BASE,DYNAMICTOP_PTR;STATIC_BASE=STATICTOP=STACK_BASE=STACKTOP=STACK_MAX=DYNAMIC_BASE=DYNAMICTOP_PTR=0,staticSealed=!1;function abortOnCannotGrowMemory(){abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime but prevents some optimizations, (3) set Module.TOTAL_MEMORY to a higher value before the program runs, or (4) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}function enlargeMemory(){abortOnCannotGrowMemory()}var TOTAL_STACK=Module.TOTAL_STACK||5242880,TOTAL_MEMORY=Module.TOTAL_MEMORY||134217728;TOTAL_MEMORY0;){var e=t.shift();if(typeof e=="function"){e();continue}var r=e.func;typeof r=="number"?e.arg===void 0?Module.dynCall_v(r):Module.dynCall_vi(r,e.arg):r(e.arg===void 0?null:e.arg)}}var __ATPRERUN__=[],__ATINIT__=[],__ATMAIN__=[],__ATEXIT__=[],__ATPOSTRUN__=[],runtimeInitialized=!1,runtimeExited=!1;function preRun(){if(Module.preRun)for(typeof Module.preRun=="function"&&(Module.preRun=[Module.preRun]);Module.preRun.length;)addOnPreRun(Module.preRun.shift());callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){runtimeInitialized||(runtimeInitialized=!0,callRuntimeCallbacks(__ATINIT__))}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__),runtimeExited=!0}function postRun(){if(Module.postRun)for(typeof Module.postRun=="function"&&(Module.postRun=[Module.postRun]);Module.postRun.length;)addOnPostRun(Module.postRun.shift());callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(t){__ATPRERUN__.unshift(t)}Module.addOnPreRun=addOnPreRun;function addOnInit(t){__ATINIT__.unshift(t)}Module.addOnInit=addOnInit;function addOnPreMain(t){__ATMAIN__.unshift(t)}Module.addOnPreMain=addOnPreMain;function addOnExit(t){__ATEXIT__.unshift(t)}Module.addOnExit=addOnExit;function addOnPostRun(t){__ATPOSTRUN__.unshift(t)}Module.addOnPostRun=addOnPostRun;function intArrayFromString(t,e,r){var o=r>0?r:lengthBytesUTF8(t)+1,a=new Array(o),n=stringToUTF8Array(t,a,0,a.length);return e&&(a.length=n),a}Module.intArrayFromString=intArrayFromString;function intArrayToString(t){for(var e=[],r=0;r255&&(o&=255),e.push(String.fromCharCode(o))}return e.join("")}Module.intArrayToString=intArrayToString;function writeStringToMemory(t,e,r){Runtime.warnOnce("writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!");var o,a;r&&(a=e+lengthBytesUTF8(t),o=HEAP8[a]),stringToUTF8(t,e,1/0),r&&(HEAP8[a]=o)}Module.writeStringToMemory=writeStringToMemory;function writeArrayToMemory(t,e){HEAP8.set(t,e)}Module.writeArrayToMemory=writeArrayToMemory;function writeAsciiToMemory(t,e,r){for(var o=0;o>0]=t.charCodeAt(o);r||(HEAP8[e>>0]=0)}if(Module.writeAsciiToMemory=writeAsciiToMemory,(!Math.imul||Math.imul(4294967295,5)!==-5)&&(Math.imul=function t(e,r){var o=e>>>16,a=e&65535,n=r>>>16,u=r&65535;return a*u+(o*u+a*n<<16)|0}),Math.imul=Math.imul,!Math.fround){var froundBuffer=new Float32Array(1);Math.fround=function(t){return froundBuffer[0]=t,froundBuffer[0]}}Math.fround=Math.fround,Math.clz32||(Math.clz32=function(t){t=t>>>0;for(var e=0;e<32;e++)if(t&1<<31-e)return e;return 32}),Math.clz32=Math.clz32,Math.trunc||(Math.trunc=function(t){return t<0?Math.ceil(t):Math.floor(t)}),Math.trunc=Math.trunc;var Math_abs=Math.abs,Math_cos=Math.cos,Math_sin=Math.sin,Math_tan=Math.tan,Math_acos=Math.acos,Math_asin=Math.asin,Math_atan=Math.atan,Math_atan2=Math.atan2,Math_exp=Math.exp,Math_log=Math.log,Math_sqrt=Math.sqrt,Math_ceil=Math.ceil,Math_floor=Math.floor,Math_pow=Math.pow,Math_imul=Math.imul,Math_fround=Math.fround,Math_round=Math.round,Math_min=Math.min,Math_clz32=Math.clz32,Math_trunc=Math.trunc,runDependencies=0,runDependencyWatcher=null,dependenciesFulfilled=null;function getUniqueRunDependency(t){return t}function addRunDependency(t){runDependencies++,Module.monitorRunDependencies&&Module.monitorRunDependencies(runDependencies)}Module.addRunDependency=addRunDependency;function removeRunDependency(t){if(runDependencies--,Module.monitorRunDependencies&&Module.monitorRunDependencies(runDependencies),runDependencies==0&&(runDependencyWatcher!==null&&(clearInterval(runDependencyWatcher),runDependencyWatcher=null),dependenciesFulfilled)){var e=dependenciesFulfilled;dependenciesFulfilled=null,e()}}Module.removeRunDependency=removeRunDependency,Module.preloadedImages={},Module.preloadedAudios={};var ASM_CONSTS=[function(t,e,r,o,a,n,u,A){return _nbind.callbackSignatureList[t].apply(this,arguments)}];function _emscripten_asm_const_iiiiiiii(t,e,r,o,a,n,u,A){return ASM_CONSTS[t](e,r,o,a,n,u,A)}function _emscripten_asm_const_iiiii(t,e,r,o,a){return ASM_CONSTS[t](e,r,o,a)}function _emscripten_asm_const_iiidddddd(t,e,r,o,a,n,u,A,p){return ASM_CONSTS[t](e,r,o,a,n,u,A,p)}function _emscripten_asm_const_iiididi(t,e,r,o,a,n,u){return ASM_CONSTS[t](e,r,o,a,n,u)}function _emscripten_asm_const_iiii(t,e,r,o){return ASM_CONSTS[t](e,r,o)}function _emscripten_asm_const_iiiid(t,e,r,o,a){return ASM_CONSTS[t](e,r,o,a)}function _emscripten_asm_const_iiiiii(t,e,r,o,a,n){return ASM_CONSTS[t](e,r,o,a,n)}STATIC_BASE=Runtime.GLOBAL_BASE,STATICTOP=STATIC_BASE+12800,__ATINIT__.push({func:function(){__GLOBAL__sub_I_Yoga_cpp()}},{func:function(){__GLOBAL__sub_I_nbind_cc()}},{func:function(){__GLOBAL__sub_I_common_cc()}},{func:function(){__GLOBAL__sub_I_Binding_cc()}}),allocate([0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,0,0,192,127,0,0,192,127,3,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,3,0,0,0,0,0,192,127,3,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,0,0,128,191,0,0,128,191,0,0,192,127,0,0,0,0,0,0,0,0,0,0,128,63,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,2,0,0,0,0,0,0,0,190,12,0,0,200,12,0,0,208,12,0,0,216,12,0,0,230,12,0,0,242,12,0,0,1,0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0,0,192,127,3,0,0,0,180,45,0,0,181,45,0,0,182,45,0,0,181,45,0,0,182,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,1,0,0,0,4,0,0,0,183,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,184,45,0,0,185,45,0,0,181,45,0,0,181,45,0,0,182,45,0,0,186,45,0,0,185,45,0,0,148,4,0,0,3,0,0,0,187,45,0,0,164,4,0,0,188,45,0,0,2,0,0,0,189,45,0,0,164,4,0,0,188,45,0,0,185,45,0,0,164,4,0,0,185,45,0,0,164,4,0,0,188,45,0,0,181,45,0,0,182,45,0,0,181,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,5,0,0,0,6,0,0,0,1,0,0,0,7,0,0,0,183,45,0,0,182,45,0,0,181,45,0,0,190,45,0,0,190,45,0,0,182,45,0,0,182,45,0,0,185,45,0,0,181,45,0,0,185,45,0,0,182,45,0,0,181,45,0,0,185,45,0,0,182,45,0,0,185,45,0,0,48,5,0,0,3,0,0,0,56,5,0,0,1,0,0,0,189,45,0,0,185,45,0,0,164,4,0,0,76,5,0,0,2,0,0,0,191,45,0,0,186,45,0,0,182,45,0,0,185,45,0,0,192,45,0,0,185,45,0,0,182,45,0,0,186,45,0,0,185,45,0,0,76,5,0,0,76,5,0,0,136,5,0,0,182,45,0,0,181,45,0,0,2,0,0,0,190,45,0,0,136,5,0,0,56,19,0,0,156,5,0,0,2,0,0,0,184,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,8,0,0,0,9,0,0,0,1,0,0,0,10,0,0,0,204,5,0,0,181,45,0,0,181,45,0,0,2,0,0,0,180,45,0,0,204,5,0,0,2,0,0,0,195,45,0,0,236,5,0,0,97,19,0,0,198,45,0,0,211,45,0,0,212,45,0,0,213,45,0,0,214,45,0,0,215,45,0,0,188,45,0,0,182,45,0,0,216,45,0,0,217,45,0,0,218,45,0,0,219,45,0,0,192,45,0,0,181,45,0,0,0,0,0,0,185,45,0,0,110,19,0,0,186,45,0,0,115,19,0,0,221,45,0,0,120,19,0,0,148,4,0,0,132,19,0,0,96,6,0,0,145,19,0,0,222,45,0,0,164,19,0,0,223,45,0,0,173,19,0,0,0,0,0,0,3,0,0,0,104,6,0,0,1,0,0,0,187,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,11,0,0,0,12,0,0,0,1,0,0,0,13,0,0,0,185,45,0,0,224,45,0,0,164,6,0,0,188,45,0,0,172,6,0,0,180,6,0,0,2,0,0,0,188,6,0,0,7,0,0,0,224,45,0,0,7,0,0,0,164,6,0,0,1,0,0,0,213,45,0,0,185,45,0,0,224,45,0,0,172,6,0,0,185,45,0,0,224,45,0,0,164,6,0,0,185,45,0,0,224,45,0,0,211,45,0,0,211,45,0,0,222,45,0,0,211,45,0,0,224,45,0,0,222,45,0,0,211,45,0,0,224,45,0,0,172,6,0,0,222,45,0,0,211,45,0,0,224,45,0,0,188,45,0,0,222,45,0,0,211,45,0,0,40,7,0,0,188,45,0,0,2,0,0,0,224,45,0,0,185,45,0,0,188,45,0,0,188,45,0,0,188,45,0,0,188,45,0,0,222,45,0,0,224,45,0,0,148,4,0,0,185,45,0,0,148,4,0,0,148,4,0,0,148,4,0,0,148,4,0,0,148,4,0,0,185,45,0,0,164,6,0,0,148,4,0,0,0,0,0,0,0,0,0,0,1,0,0,0,14,0,0,0,15,0,0,0,1,0,0,0,16,0,0,0,148,7,0,0,2,0,0,0,225,45,0,0,183,45,0,0,188,45,0,0,168,7,0,0,5,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,234,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,148,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,9,0,0,5,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,2,0,0,0,242,45,0,0,0,4,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67,111,117,108,100,32,110,111,116,32,97,108,108,111,99,97,116,101,32,109,101,109,111,114,121,32,102,111,114,32,110,111,100,101,0,67,97,110,110,111,116,32,114,101,115,101,116,32,97,32,110,111,100,101,32,119,104,105,99,104,32,115,116,105,108,108,32,104,97,115,32,99,104,105,108,100,114,101,110,32,97,116,116,97,99,104,101,100,0,67,97,110,110,111,116,32,114,101,115,101,116,32,97,32,110,111,100,101,32,115,116,105,108,108,32,97,116,116,97,99,104,101,100,32,116,111,32,97,32,112,97,114,101,110,116,0,67,111,117,108,100,32,110,111,116,32,97,108,108,111,99,97,116,101,32,109,101,109,111,114,121,32,102,111,114,32,99,111,110,102,105,103,0,67,97,110,110,111,116,32,115,101,116,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,58,32,78,111,100,101,115,32,119,105,116,104,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,32,99,97,110,110,111,116,32,104,97,118,101,32,99,104,105,108,100,114,101,110,46,0,67,104,105,108,100,32,97,108,114,101,97,100,121,32,104,97,115,32,97,32,112,97,114,101,110,116,44,32,105,116,32,109,117,115,116,32,98,101,32,114,101,109,111,118,101,100,32,102,105,114,115,116,46,0,67,97,110,110,111,116,32,97,100,100,32,99,104,105,108,100,58,32,78,111,100,101,115,32,119,105,116,104,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,32,99,97,110,110,111,116,32,104,97,118,101,32,99,104,105,108,100,114,101,110,46,0,79,110,108,121,32,108,101,97,102,32,110,111,100,101,115,32,119,105,116,104,32,99,117,115,116,111,109,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,115,104,111,117,108,100,32,109,97,110,117,97,108,108,121,32,109,97,114,107,32,116,104,101,109,115,101,108,118,101,115,32,97,115,32,100,105,114,116,121,0,67,97,110,110,111,116,32,103,101,116,32,108,97,121,111,117,116,32,112,114,111,112,101,114,116,105,101,115,32,111,102,32,109,117,108,116,105,45,101,100,103,101,32,115,104,111,114,116,104,97,110,100,115,0,37,115,37,100,46,123,91,115,107,105,112,112,101,100,93,32,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,97,119,58,32,37,102,32,97,104,58,32,37,102,32,61,62,32,100,58,32,40,37,102,44,32,37,102,41,32,37,115,10,0,37,115,37,100,46,123,37,115,0,42,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,97,119,58,32,37,102,32,97,104,58,32,37,102,32,37,115,10,0,37,115,37,100,46,125,37,115,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,100,58,32,40,37,102,44,32,37,102,41,32,37,115,10,0,79,117,116,32,111,102,32,99,97,99,104,101,32,101,110,116,114,105,101,115,33,10,0,83,99,97,108,101,32,102,97,99,116,111,114,32,115,104,111,117,108,100,32,110,111,116,32,98,101,32,108,101,115,115,32,116,104,97,110,32,122,101,114,111,0,105,110,105,116,105,97,108,0,37,115,10,0,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,0,85,78,68,69,70,73,78,69,68,0,69,88,65,67,84,76,89,0,65,84,95,77,79,83,84,0,76,65,89,95,85,78,68,69,70,73,78,69,68,0,76,65,89,95,69,88,65,67,84,76,89,0,76,65,89,95,65,84,95,77,79,83,84,0,97,118,97,105,108,97,98,108,101,87,105,100,116,104,32,105,115,32,105,110,100,101,102,105,110,105,116,101,32,115,111,32,119,105,100,116,104,77,101,97,115,117,114,101,77,111,100,101,32,109,117,115,116,32,98,101,32,89,71,77,101,97,115,117,114,101,77,111,100,101,85,110,100,101,102,105,110,101,100,0,97,118,97,105,108,97,98,108,101,72,101,105,103,104,116,32,105,115,32,105,110,100,101,102,105,110,105,116,101,32,115,111,32,104,101,105,103,104,116,77,101,97,115,117,114,101,77,111,100,101,32,109,117,115,116,32,98,101,32,89,71,77,101,97,115,117,114,101,77,111,100,101,85,110,100,101,102,105,110,101,100,0,102,108,101,120,0,115,116,114,101,116,99,104,0,109,117,108,116,105,108,105,110,101,45,115,116,114,101,116,99,104,0,69,120,112,101,99,116,101,100,32,110,111,100,101,32,116,111,32,104,97,118,101,32,99,117,115,116,111,109,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,0,109,101,97,115,117,114,101,0,69,120,112,101,99,116,32,99,117,115,116,111,109,32,98,97,115,101,108,105,110,101,32,102,117,110,99,116,105,111,110,32,116,111,32,110,111,116,32,114,101,116,117,114,110,32,78,97,78,0,97,98,115,45,109,101,97,115,117,114,101,0,97,98,115,45,108,97,121,111,117,116,0,78,111,100,101,0,99,114,101,97,116,101,68,101,102,97,117,108,116,0,99,114,101,97,116,101,87,105,116,104,67,111,110,102,105,103,0,100,101,115,116,114,111,121,0,114,101,115,101,116,0,99,111,112,121,83,116,121,108,101,0,115,101,116,80,111,115,105,116,105,111,110,84,121,112,101,0,115,101,116,80,111,115,105,116,105,111,110,0,115,101,116,80,111,115,105,116,105,111,110,80,101,114,99,101,110,116,0,115,101,116,65,108,105,103,110,67,111,110,116,101,110,116,0,115,101,116,65,108,105,103,110,73,116,101,109,115,0,115,101,116,65,108,105,103,110,83,101,108,102,0,115,101,116,70,108,101,120,68,105,114,101,99,116,105,111,110,0,115,101,116,70,108,101,120,87,114,97,112,0,115,101,116,74,117,115,116,105,102,121,67,111,110,116,101,110,116,0,115,101,116,77,97,114,103,105,110,0,115,101,116,77,97,114,103,105,110,80,101,114,99,101,110,116,0,115,101,116,77,97,114,103,105,110,65,117,116,111,0,115,101,116,79,118,101,114,102,108,111,119,0,115,101,116,68,105,115,112,108,97,121,0,115,101,116,70,108,101,120,0,115,101,116,70,108,101,120,66,97,115,105,115,0,115,101,116,70,108,101,120,66,97,115,105,115,80,101,114,99,101,110,116,0,115,101,116,70,108,101,120,71,114,111,119,0,115,101,116,70,108,101,120,83,104,114,105,110,107,0,115,101,116,87,105,100,116,104,0,115,101,116,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,87,105,100,116,104,65,117,116,111,0,115,101,116,72,101,105,103,104,116,0,115,101,116,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,72,101,105,103,104,116,65,117,116,111,0,115,101,116,77,105,110,87,105,100,116,104,0,115,101,116,77,105,110,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,77,105,110,72,101,105,103,104,116,0,115,101,116,77,105,110,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,77,97,120,87,105,100,116,104,0,115,101,116,77,97,120,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,77,97,120,72,101,105,103,104,116,0,115,101,116,77,97,120,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,65,115,112,101,99,116,82,97,116,105,111,0,115,101,116,66,111,114,100,101,114,0,115,101,116,80,97,100,100,105,110,103,0,115,101,116,80,97,100,100,105,110,103,80,101,114,99,101,110,116,0,103,101,116,80,111,115,105,116,105,111,110,84,121,112,101,0,103,101,116,80,111,115,105,116,105,111,110,0,103,101,116,65,108,105,103,110,67,111,110,116,101,110,116,0,103,101,116,65,108,105,103,110,73,116,101,109,115,0,103,101,116,65,108,105,103,110,83,101,108,102,0,103,101,116,70,108,101,120,68,105,114,101,99,116,105,111,110,0,103,101,116,70,108,101,120,87,114,97,112,0,103,101,116,74,117,115,116,105,102,121,67,111,110,116,101,110,116,0,103,101,116,77,97,114,103,105,110,0,103,101,116,70,108,101,120,66,97,115,105,115,0,103,101,116,70,108,101,120,71,114,111,119,0,103,101,116,70,108,101,120,83,104,114,105,110,107,0,103,101,116,87,105,100,116,104,0,103,101,116,72,101,105,103,104,116,0,103,101,116,77,105,110,87,105,100,116,104,0,103,101,116,77,105,110,72,101,105,103,104,116,0,103,101,116,77,97,120,87,105,100,116,104,0,103,101,116,77,97,120,72,101,105,103,104,116,0,103,101,116,65,115,112,101,99,116,82,97,116,105,111,0,103,101,116,66,111,114,100,101,114,0,103,101,116,79,118,101,114,102,108,111,119,0,103,101,116,68,105,115,112,108,97,121,0,103,101,116,80,97,100,100,105,110,103,0,105,110,115,101,114,116,67,104,105,108,100,0,114,101,109,111,118,101,67,104,105,108,100,0,103,101,116,67,104,105,108,100,67,111,117,110,116,0,103,101,116,80,97,114,101,110,116,0,103,101,116,67,104,105,108,100,0,115,101,116,77,101,97,115,117,114,101,70,117,110,99,0,117,110,115,101,116,77,101,97,115,117,114,101,70,117,110,99,0,109,97,114,107,68,105,114,116,121,0,105,115,68,105,114,116,121,0,99,97,108,99,117,108,97,116,101,76,97,121,111,117,116,0,103,101,116,67,111,109,112,117,116,101,100,76,101,102,116,0,103,101,116,67,111,109,112,117,116,101,100,82,105,103,104,116,0,103,101,116,67,111,109,112,117,116,101,100,84,111,112,0,103,101,116,67,111,109,112,117,116,101,100,66,111,116,116,111,109,0,103,101,116,67,111,109,112,117,116,101,100,87,105,100,116,104,0,103,101,116,67,111,109,112,117,116,101,100,72,101,105,103,104,116,0,103,101,116,67,111,109,112,117,116,101,100,76,97,121,111,117,116,0,103,101,116,67,111,109,112,117,116,101,100,77,97,114,103,105,110,0,103,101,116,67,111,109,112,117,116,101,100,66,111,114,100,101,114,0,103,101,116,67,111,109,112,117,116,101,100,80,97,100,100,105,110,103,0,67,111,110,102,105,103,0,99,114,101,97,116,101,0,115,101,116,69,120,112,101,114,105,109,101,110,116,97,108,70,101,97,116,117,114,101,69,110,97,98,108,101,100,0,115,101,116,80,111,105,110,116,83,99,97,108,101,70,97,99,116,111,114,0,105,115,69,120,112,101,114,105,109,101,110,116,97,108,70,101,97,116,117,114,101,69,110,97,98,108,101,100,0,86,97,108,117,101,0,76,97,121,111,117,116,0,83,105,122,101,0,103,101,116,73,110,115,116,97,110,99,101,67,111,117,110,116,0,73,110,116,54,52,0,1,1,1,2,2,4,4,4,4,8,8,4,8,118,111,105,100,0,98,111,111,108,0,115,116,100,58,58,115,116,114,105,110,103,0,99,98,70,117,110,99,116,105,111,110,32,38,0,99,111,110,115,116,32,99,98,70,117,110,99,116,105,111,110,32,38,0,69,120,116,101,114,110,97,108,0,66,117,102,102,101,114,0,78,66,105,110,100,73,68,0,78,66,105,110,100,0,98,105,110,100,95,118,97,108,117,101,0,114,101,102,108,101,99,116,0,113,117,101,114,121,84,121,112,101,0,108,97,108,108,111,99,0,108,114,101,115,101,116,0,123,114,101,116,117,114,110,40,95,110,98,105,110,100,46,99,97,108,108,98,97,99,107,83,105,103,110,97,116,117,114,101,76,105,115,116,91,36,48,93,46,97,112,112,108,121,40,116,104,105,115,44,97,114,103,117,109,101,110,116,115,41,41,59,125,0,95,110,98,105,110,100,95,110,101,119,0,17,0,10,0,17,17,17,0,0,0,0,5,0,0,0,0,0,0,9,0,0,0,0,11,0,0,0,0,0,0,0,0,17,0,15,10,17,17,17,3,10,7,0,1,19,9,11,11,0,0,9,6,11,0,0,11,0,6,17,0,0,0,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,17,0,10,10,17,17,17,0,10,0,0,2,0,9,11,0,0,0,9,0,11,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,9,12,0,0,0,0,0,12,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,13,0,0,0,4,13,0,0,0,0,9,14,0,0,0,0,0,14,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,15,0,0,0,0,9,16,0,0,0,0,0,16,0,0,16,0,0,18,0,0,0,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,0,18,18,18,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,10,0,0,0,0,9,11,0,0,0,0,0,11,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,9,12,0,0,0,0,0,12,0,0,12,0,0,45,43,32,32,32,48,88,48,120,0,40,110,117,108,108,41,0,45,48,88,43,48,88,32,48,88,45,48,120,43,48,120,32,48,120,0,105,110,102,0,73,78,70,0,110,97,110,0,78,65,78,0,48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,46,0,84,33,34,25,13,1,2,3,17,75,28,12,16,4,11,29,18,30,39,104,110,111,112,113,98,32,5,6,15,19,20,21,26,8,22,7,40,36,23,24,9,10,14,27,31,37,35,131,130,125,38,42,43,60,61,62,63,67,71,74,77,88,89,90,91,92,93,94,95,96,97,99,100,101,102,103,105,106,107,108,114,115,116,121,122,123,124,0,73,108,108,101,103,97,108,32,98,121,116,101,32,115,101,113,117,101,110,99,101,0,68,111,109,97,105,110,32,101,114,114,111,114,0,82,101,115,117,108,116,32,110,111,116,32,114,101,112,114,101,115,101,110,116,97,98,108,101,0,78,111,116,32,97,32,116,116,121,0,80,101,114,109,105,115,115,105,111,110,32,100,101,110,105,101,100,0,79,112,101,114,97,116,105,111,110,32,110,111,116,32,112,101,114,109,105,116,116,101,100,0,78,111,32,115,117,99,104,32,102,105,108,101,32,111,114,32,100,105,114,101,99,116,111,114,121,0,78,111,32,115,117,99,104,32,112,114,111,99,101,115,115,0,70,105,108,101,32,101,120,105,115,116,115,0,86,97,108,117,101,32,116,111,111,32,108,97,114,103,101,32,102,111,114,32,100,97,116,97,32,116,121,112,101,0,78,111,32,115,112,97,99,101,32,108,101,102,116,32,111,110,32,100,101,118,105,99,101,0,79,117,116,32,111,102,32,109,101,109,111,114,121,0,82,101,115,111,117,114,99,101,32,98,117,115,121,0,73,110,116,101,114,114,117,112,116,101,100,32,115,121,115,116,101,109,32,99,97,108,108,0,82,101,115,111,117,114,99,101,32,116,101,109,112,111,114,97,114,105,108,121,32,117,110,97,118,97,105,108,97,98,108,101,0,73,110,118,97,108,105,100,32,115,101,101,107,0,67,114,111,115,115,45,100,101,118,105,99,101,32,108,105,110,107,0,82,101,97,100,45,111,110,108,121,32,102,105,108,101,32,115,121,115,116,101,109,0,68,105,114,101,99,116,111,114,121,32,110,111,116,32,101,109,112,116,121,0,67,111,110,110,101,99,116,105,111,110,32,114,101,115,101,116,32,98,121,32,112,101,101,114,0,79,112,101,114,97,116,105,111,110,32,116,105,109,101,100,32,111,117,116,0,67,111,110,110,101,99,116,105,111,110,32,114,101,102,117,115,101,100,0,72,111,115,116,32,105,115,32,100,111,119,110,0,72,111,115,116,32,105,115,32,117,110,114,101,97,99,104,97,98,108,101,0,65,100,100,114,101,115,115,32,105,110,32,117,115,101,0,66,114,111,107,101,110,32,112,105,112,101,0,73,47,79,32,101,114,114,111,114,0,78,111,32,115,117,99,104,32,100,101,118,105,99,101,32,111,114,32,97,100,100,114,101,115,115,0,66,108,111,99,107,32,100,101,118,105,99,101,32,114,101,113,117,105,114,101,100,0,78,111,32,115,117,99,104,32,100,101,118,105,99,101,0,78,111,116,32,97,32,100,105,114,101,99,116,111,114,121,0,73,115,32,97,32,100,105,114,101,99,116,111,114,121,0,84,101,120,116,32,102,105,108,101,32,98,117,115,121,0,69,120,101,99,32,102,111,114,109,97,116,32,101,114,114,111,114,0,73,110,118,97,108,105,100,32,97,114,103,117,109,101,110,116,0,65,114,103,117,109,101,110,116,32,108,105,115,116,32,116,111,111,32,108,111,110,103,0,83,121,109,98,111,108,105,99,32,108,105,110,107,32,108,111,111,112,0,70,105,108,101,110,97,109,101,32,116,111,111,32,108,111,110,103,0,84,111,111,32,109,97,110,121,32,111,112,101,110,32,102,105,108,101,115,32,105,110,32,115,121,115,116,101,109,0,78,111,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,115,32,97,118,97,105,108,97,98,108,101,0,66,97,100,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,0,78,111,32,99,104,105,108,100,32,112,114,111,99,101,115,115,0,66,97,100,32,97,100,100,114,101,115,115,0,70,105,108,101,32,116,111,111,32,108,97,114,103,101,0,84,111,111,32,109,97,110,121,32,108,105,110,107,115,0,78,111,32,108,111,99,107,115,32,97,118,97,105,108,97,98,108,101,0,82,101,115,111,117,114,99,101,32,100,101,97,100,108,111,99,107,32,119,111,117,108,100,32,111,99,99,117,114,0,83,116,97,116,101,32,110,111,116,32,114,101,99,111,118,101,114,97,98,108,101,0,80,114,101,118,105,111,117,115,32,111,119,110,101,114,32,100,105,101,100,0,79,112,101,114,97,116,105,111,110,32,99,97,110,99,101,108,101,100,0,70,117,110,99,116,105,111,110,32,110,111,116,32,105,109,112,108,101,109,101,110,116,101,100,0,78,111,32,109,101,115,115,97,103,101,32,111,102,32,100,101,115,105,114,101,100,32,116,121,112,101,0,73,100,101,110,116,105,102,105,101,114,32,114,101,109,111,118,101,100,0,68,101,118,105,99,101,32,110,111,116,32,97,32,115,116,114,101,97,109,0,78,111,32,100,97,116,97,32,97,118,97,105,108,97,98,108,101,0,68,101,118,105,99,101,32,116,105,109,101,111,117,116,0,79,117,116,32,111,102,32,115,116,114,101,97,109,115,32,114,101,115,111,117,114,99,101,115,0,76,105,110,107,32,104,97,115,32,98,101,101,110,32,115,101,118,101,114,101,100,0,80,114,111,116,111,99,111,108,32,101,114,114,111,114,0,66,97,100,32,109,101,115,115,97,103,101,0,70,105,108,101,32,100,101,115,99,114,105,112,116,111,114,32,105,110,32,98,97,100,32,115,116,97,116,101,0,78,111,116,32,97,32,115,111,99,107,101,116,0,68,101,115,116,105,110,97,116,105,111,110,32,97,100,100,114,101,115,115,32,114,101,113,117,105,114,101,100,0,77,101,115,115,97,103,101,32,116,111,111,32,108,97,114,103,101,0,80,114,111,116,111,99,111,108,32,119,114,111,110,103,32,116,121,112,101,32,102,111,114,32,115,111,99,107,101,116,0,80,114,111,116,111,99,111,108,32,110,111,116,32,97,118,97,105,108,97,98,108,101,0,80,114,111,116,111,99,111,108,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,83,111,99,107,101,116,32,116,121,112,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,78,111,116,32,115,117,112,112,111,114,116,101,100,0,80,114,111,116,111,99,111,108,32,102,97,109,105,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,65,100,100,114,101,115,115,32,102,97,109,105,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,98,121,32,112,114,111,116,111,99,111,108,0,65,100,100,114,101,115,115,32,110,111,116,32,97,118,97,105,108,97,98,108,101,0,78,101,116,119,111,114,107,32,105,115,32,100,111,119,110,0,78,101,116,119,111,114,107,32,117,110,114,101,97,99,104,97,98,108,101,0,67,111,110,110,101,99,116,105,111,110,32,114,101,115,101,116,32,98,121,32,110,101,116,119,111,114,107,0,67,111,110,110,101,99,116,105,111,110,32,97,98,111,114,116,101,100,0,78,111,32,98,117,102,102,101,114,32,115,112,97,99,101,32,97,118,97,105,108,97,98,108,101,0,83,111,99,107,101,116,32,105,115,32,99,111,110,110,101,99,116,101,100,0,83,111,99,107,101,116,32,110,111,116,32,99,111,110,110,101,99,116,101,100,0,67,97,110,110,111,116,32,115,101,110,100,32,97,102,116,101,114,32,115,111,99,107,101,116,32,115,104,117,116,100,111,119,110,0,79,112,101,114,97,116,105,111,110,32,97,108,114,101,97,100,121,32,105,110,32,112,114,111,103,114,101,115,115,0,79,112,101,114,97,116,105,111,110,32,105,110,32,112,114,111,103,114,101,115,115,0,83,116,97,108,101,32,102,105,108,101,32,104,97,110,100,108,101,0,82,101,109,111,116,101,32,73,47,79,32,101,114,114,111,114,0,81,117,111,116,97,32,101,120,99,101,101,100,101,100,0,78,111,32,109,101,100,105,117,109,32,102,111,117,110,100,0,87,114,111,110,103,32,109,101,100,105,117,109,32,116,121,112,101,0,78,111,32,101,114,114,111,114,32,105,110,102,111,114,109,97,116,105,111,110,0,0],"i8",ALLOC_NONE,Runtime.GLOBAL_BASE);var tempDoublePtr=STATICTOP;STATICTOP+=16;function _atexit(t,e){__ATEXIT__.unshift({func:t,arg:e})}function ___cxa_atexit(){return _atexit.apply(null,arguments)}function _abort(){Module.abort()}function __ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj(){Module.printErr("missing function: _ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj"),abort(-1)}function __decorate(t,e,r,o){var a=arguments.length,n=a<3?e:o===null?o=Object.getOwnPropertyDescriptor(e,r):o,u;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")n=Reflect.decorate(t,e,r,o);else for(var A=t.length-1;A>=0;A--)(u=t[A])&&(n=(a<3?u(n):a>3?u(e,r,n):u(e,r))||n);return a>3&&n&&Object.defineProperty(e,r,n),n}function _defineHidden(t){return function(e,r){Object.defineProperty(e,r,{configurable:!1,enumerable:!1,value:t,writable:!0})}}var _nbind={};function __nbind_free_external(t){_nbind.externalList[t].dereference(t)}function __nbind_reference_external(t){_nbind.externalList[t].reference()}function _llvm_stackrestore(t){var e=_llvm_stacksave,r=e.LLVM_SAVEDSTACKS[t];e.LLVM_SAVEDSTACKS.splice(t,1),Runtime.stackRestore(r)}function __nbind_register_pool(t,e,r,o){_nbind.Pool.pageSize=t,_nbind.Pool.usedPtr=e/4,_nbind.Pool.rootPtr=r,_nbind.Pool.pagePtr=o/4,HEAP32[e/4]=16909060,HEAP8[e]==1&&(_nbind.bigEndian=!0),HEAP32[e/4]=0,_nbind.makeTypeKindTbl=(n={},n[1024]=_nbind.PrimitiveType,n[64]=_nbind.Int64Type,n[2048]=_nbind.BindClass,n[3072]=_nbind.BindClassPtr,n[4096]=_nbind.SharedClassPtr,n[5120]=_nbind.ArrayType,n[6144]=_nbind.ArrayType,n[7168]=_nbind.CStringType,n[9216]=_nbind.CallbackType,n[10240]=_nbind.BindType,n),_nbind.makeTypeNameTbl={Buffer:_nbind.BufferType,External:_nbind.ExternalType,Int64:_nbind.Int64Type,_nbind_new:_nbind.CreateValueType,bool:_nbind.BooleanType,"cbFunction &":_nbind.CallbackType,"const cbFunction &":_nbind.CallbackType,"const std::string &":_nbind.StringType,"std::string":_nbind.StringType},Module.toggleLightGC=_nbind.toggleLightGC,_nbind.callUpcast=Module.dynCall_ii;var a=_nbind.makeType(_nbind.constructType,{flags:2048,id:0,name:""});a.proto=Module,_nbind.BindClass.list.push(a);var n}function _emscripten_set_main_loop_timing(t,e){if(Browser.mainLoop.timingMode=t,Browser.mainLoop.timingValue=e,!Browser.mainLoop.func)return 1;if(t==0)Browser.mainLoop.scheduler=function(){var u=Math.max(0,Browser.mainLoop.tickStartTime+e-_emscripten_get_now())|0;setTimeout(Browser.mainLoop.runner,u)},Browser.mainLoop.method="timeout";else if(t==1)Browser.mainLoop.scheduler=function(){Browser.requestAnimationFrame(Browser.mainLoop.runner)},Browser.mainLoop.method="rAF";else if(t==2){if(!window.setImmediate){let n=function(u){u.source===window&&u.data===o&&(u.stopPropagation(),r.shift()())};var a=n,r=[],o="setimmediate";window.addEventListener("message",n,!0),window.setImmediate=function(A){r.push(A),ENVIRONMENT_IS_WORKER?(Module.setImmediates===void 0&&(Module.setImmediates=[]),Module.setImmediates.push(A),window.postMessage({target:o})):window.postMessage(o,"*")}}Browser.mainLoop.scheduler=function(){window.setImmediate(Browser.mainLoop.runner)},Browser.mainLoop.method="immediate"}return 0}function _emscripten_get_now(){abort()}function _emscripten_set_main_loop(t,e,r,o,a){Module.noExitRuntime=!0,assert(!Browser.mainLoop.func,"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters."),Browser.mainLoop.func=t,Browser.mainLoop.arg=o;var n;typeof o<"u"?n=function(){Module.dynCall_vi(t,o)}:n=function(){Module.dynCall_v(t)};var u=Browser.mainLoop.currentlyRunningMainloop;if(Browser.mainLoop.runner=function(){if(!ABORT){if(Browser.mainLoop.queue.length>0){var p=Date.now(),h=Browser.mainLoop.queue.shift();if(h.func(h.arg),Browser.mainLoop.remainingBlockers){var E=Browser.mainLoop.remainingBlockers,I=E%1==0?E-1:Math.floor(E);h.counted?Browser.mainLoop.remainingBlockers=I:(I=I+.5,Browser.mainLoop.remainingBlockers=(8*E+I)/9)}if(console.log('main loop blocker "'+h.name+'" took '+(Date.now()-p)+" ms"),Browser.mainLoop.updateStatus(),u1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else Browser.mainLoop.timingMode==0&&(Browser.mainLoop.tickStartTime=_emscripten_get_now());Browser.mainLoop.method==="timeout"&&Module.ctx&&(Module.printErr("Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!"),Browser.mainLoop.method=""),Browser.mainLoop.runIter(n),!(u0?_emscripten_set_main_loop_timing(0,1e3/e):_emscripten_set_main_loop_timing(1,1),Browser.mainLoop.scheduler()),r)throw"SimulateInfiniteLoop"}var Browser={mainLoop:{scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause:function(){Browser.mainLoop.scheduler=null,Browser.mainLoop.currentlyRunningMainloop++},resume:function(){Browser.mainLoop.currentlyRunningMainloop++;var t=Browser.mainLoop.timingMode,e=Browser.mainLoop.timingValue,r=Browser.mainLoop.func;Browser.mainLoop.func=null,_emscripten_set_main_loop(r,0,!1,Browser.mainLoop.arg,!0),_emscripten_set_main_loop_timing(t,e),Browser.mainLoop.scheduler()},updateStatus:function(){if(Module.setStatus){var t=Module.statusMessage||"Please wait...",e=Browser.mainLoop.remainingBlockers,r=Browser.mainLoop.expectedBlockers;e?e"u"&&(console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available."),Module.noImageDecoding=!0);var t={};t.canHandle=function(n){return!Module.noImageDecoding&&/\.(jpg|jpeg|png|bmp)$/i.test(n)},t.handle=function(n,u,A,p){var h=null;if(Browser.hasBlobConstructor)try{h=new Blob([n],{type:Browser.getMimetype(u)}),h.size!==n.length&&(h=new Blob([new Uint8Array(n).buffer],{type:Browser.getMimetype(u)}))}catch(b){Runtime.warnOnce("Blob constructor present but fails: "+b+"; falling back to blob builder")}if(!h){var E=new Browser.BlobBuilder;E.append(new Uint8Array(n).buffer),h=E.getBlob()}var I=Browser.URLObject.createObjectURL(h),v=new Image;v.onload=function(){assert(v.complete,"Image "+u+" could not be decoded");var C=document.createElement("canvas");C.width=v.width,C.height=v.height;var T=C.getContext("2d");T.drawImage(v,0,0),Module.preloadedImages[u]=C,Browser.URLObject.revokeObjectURL(I),A&&A(n)},v.onerror=function(C){console.log("Image "+I+" could not be decoded"),p&&p()},v.src=I},Module.preloadPlugins.push(t);var e={};e.canHandle=function(n){return!Module.noAudioDecoding&&n.substr(-4)in{".ogg":1,".wav":1,".mp3":1}},e.handle=function(n,u,A,p){var h=!1;function E(T){h||(h=!0,Module.preloadedAudios[u]=T,A&&A(n))}function I(){h||(h=!0,Module.preloadedAudios[u]=new Audio,p&&p())}if(Browser.hasBlobConstructor){try{var v=new Blob([n],{type:Browser.getMimetype(u)})}catch{return I()}var b=Browser.URLObject.createObjectURL(v),C=new Audio;C.addEventListener("canplaythrough",function(){E(C)},!1),C.onerror=function(L){if(h)return;console.log("warning: browser could not fully decode audio "+u+", trying slower base64 approach");function U(J){for(var te="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",le="=",pe="",Ae=0,ye=0,ae=0;ae=6;){var we=Ae>>ye-6&63;ye-=6,pe+=te[we]}return ye==2?(pe+=te[(Ae&3)<<4],pe+=le+le):ye==4&&(pe+=te[(Ae&15)<<2],pe+=le),pe}C.src="data:audio/x-"+u.substr(-3)+";base64,"+U(n),E(C)},C.src=b,Browser.safeSetTimeout(function(){E(C)},1e4)}else return I()},Module.preloadPlugins.push(e);function r(){Browser.pointerLock=document.pointerLockElement===Module.canvas||document.mozPointerLockElement===Module.canvas||document.webkitPointerLockElement===Module.canvas||document.msPointerLockElement===Module.canvas}var o=Module.canvas;o&&(o.requestPointerLock=o.requestPointerLock||o.mozRequestPointerLock||o.webkitRequestPointerLock||o.msRequestPointerLock||function(){},o.exitPointerLock=document.exitPointerLock||document.mozExitPointerLock||document.webkitExitPointerLock||document.msExitPointerLock||function(){},o.exitPointerLock=o.exitPointerLock.bind(document),document.addEventListener("pointerlockchange",r,!1),document.addEventListener("mozpointerlockchange",r,!1),document.addEventListener("webkitpointerlockchange",r,!1),document.addEventListener("mspointerlockchange",r,!1),Module.elementPointerLock&&o.addEventListener("click",function(a){!Browser.pointerLock&&Module.canvas.requestPointerLock&&(Module.canvas.requestPointerLock(),a.preventDefault())},!1))},createContext:function(t,e,r,o){if(e&&Module.ctx&&t==Module.canvas)return Module.ctx;var a,n;if(e){var u={antialias:!1,alpha:!1};if(o)for(var A in o)u[A]=o[A];n=GL.createContext(t,u),n&&(a=GL.getContext(n).GLctx)}else a=t.getContext("2d");return a?(r&&(e||assert(typeof GLctx>"u","cannot set in module if GLctx is used, but we are a non-GL context that would replace it"),Module.ctx=a,e&&GL.makeContextCurrent(n),Module.useWebGL=e,Browser.moduleContextCreatedCallbacks.forEach(function(p){p()}),Browser.init()),a):null},destroyContext:function(t,e,r){},fullscreenHandlersInstalled:!1,lockPointer:void 0,resizeCanvas:void 0,requestFullscreen:function(t,e,r){Browser.lockPointer=t,Browser.resizeCanvas=e,Browser.vrDevice=r,typeof Browser.lockPointer>"u"&&(Browser.lockPointer=!0),typeof Browser.resizeCanvas>"u"&&(Browser.resizeCanvas=!1),typeof Browser.vrDevice>"u"&&(Browser.vrDevice=null);var o=Module.canvas;function a(){Browser.isFullscreen=!1;var u=o.parentNode;(document.fullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||document.webkitFullscreenElement||document.webkitCurrentFullScreenElement)===u?(o.exitFullscreen=document.exitFullscreen||document.cancelFullScreen||document.mozCancelFullScreen||document.msExitFullscreen||document.webkitCancelFullScreen||function(){},o.exitFullscreen=o.exitFullscreen.bind(document),Browser.lockPointer&&o.requestPointerLock(),Browser.isFullscreen=!0,Browser.resizeCanvas&&Browser.setFullscreenCanvasSize()):(u.parentNode.insertBefore(o,u),u.parentNode.removeChild(u),Browser.resizeCanvas&&Browser.setWindowedCanvasSize()),Module.onFullScreen&&Module.onFullScreen(Browser.isFullscreen),Module.onFullscreen&&Module.onFullscreen(Browser.isFullscreen),Browser.updateCanvasDimensions(o)}Browser.fullscreenHandlersInstalled||(Browser.fullscreenHandlersInstalled=!0,document.addEventListener("fullscreenchange",a,!1),document.addEventListener("mozfullscreenchange",a,!1),document.addEventListener("webkitfullscreenchange",a,!1),document.addEventListener("MSFullscreenChange",a,!1));var n=document.createElement("div");o.parentNode.insertBefore(n,o),n.appendChild(o),n.requestFullscreen=n.requestFullscreen||n.mozRequestFullScreen||n.msRequestFullscreen||(n.webkitRequestFullscreen?function(){n.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)}:null)||(n.webkitRequestFullScreen?function(){n.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT)}:null),r?n.requestFullscreen({vrDisplay:r}):n.requestFullscreen()},requestFullScreen:function(t,e,r){return Module.printErr("Browser.requestFullScreen() is deprecated. Please call Browser.requestFullscreen instead."),Browser.requestFullScreen=function(o,a,n){return Browser.requestFullscreen(o,a,n)},Browser.requestFullscreen(t,e,r)},nextRAF:0,fakeRequestAnimationFrame:function(t){var e=Date.now();if(Browser.nextRAF===0)Browser.nextRAF=e+1e3/60;else for(;e+2>=Browser.nextRAF;)Browser.nextRAF+=1e3/60;var r=Math.max(Browser.nextRAF-e,0);setTimeout(t,r)},requestAnimationFrame:function t(e){typeof window>"u"?Browser.fakeRequestAnimationFrame(e):(window.requestAnimationFrame||(window.requestAnimationFrame=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||window.oRequestAnimationFrame||Browser.fakeRequestAnimationFrame),window.requestAnimationFrame(e))},safeCallback:function(t){return function(){if(!ABORT)return t.apply(null,arguments)}},allowAsyncCallbacks:!0,queuedAsyncCallbacks:[],pauseAsyncCallbacks:function(){Browser.allowAsyncCallbacks=!1},resumeAsyncCallbacks:function(){if(Browser.allowAsyncCallbacks=!0,Browser.queuedAsyncCallbacks.length>0){var t=Browser.queuedAsyncCallbacks;Browser.queuedAsyncCallbacks=[],t.forEach(function(e){e()})}},safeRequestAnimationFrame:function(t){return Browser.requestAnimationFrame(function(){ABORT||(Browser.allowAsyncCallbacks?t():Browser.queuedAsyncCallbacks.push(t))})},safeSetTimeout:function(t,e){return Module.noExitRuntime=!0,setTimeout(function(){ABORT||(Browser.allowAsyncCallbacks?t():Browser.queuedAsyncCallbacks.push(t))},e)},safeSetInterval:function(t,e){return Module.noExitRuntime=!0,setInterval(function(){ABORT||Browser.allowAsyncCallbacks&&t()},e)},getMimetype:function(t){return{jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",bmp:"image/bmp",ogg:"audio/ogg",wav:"audio/wav",mp3:"audio/mpeg"}[t.substr(t.lastIndexOf(".")+1)]},getUserMedia:function(t){window.getUserMedia||(window.getUserMedia=navigator.getUserMedia||navigator.mozGetUserMedia),window.getUserMedia(t)},getMovementX:function(t){return t.movementX||t.mozMovementX||t.webkitMovementX||0},getMovementY:function(t){return t.movementY||t.mozMovementY||t.webkitMovementY||0},getMouseWheelDelta:function(t){var e=0;switch(t.type){case"DOMMouseScroll":e=t.detail;break;case"mousewheel":e=t.wheelDelta;break;case"wheel":e=t.deltaY;break;default:throw"unrecognized mouse wheel event: "+t.type}return e},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseEvent:function(t){if(Browser.pointerLock)t.type!="mousemove"&&"mozMovementX"in t?Browser.mouseMovementX=Browser.mouseMovementY=0:(Browser.mouseMovementX=Browser.getMovementX(t),Browser.mouseMovementY=Browser.getMovementY(t)),typeof SDL<"u"?(Browser.mouseX=SDL.mouseX+Browser.mouseMovementX,Browser.mouseY=SDL.mouseY+Browser.mouseMovementY):(Browser.mouseX+=Browser.mouseMovementX,Browser.mouseY+=Browser.mouseMovementY);else{var e=Module.canvas.getBoundingClientRect(),r=Module.canvas.width,o=Module.canvas.height,a=typeof window.scrollX<"u"?window.scrollX:window.pageXOffset,n=typeof window.scrollY<"u"?window.scrollY:window.pageYOffset;if(t.type==="touchstart"||t.type==="touchend"||t.type==="touchmove"){var u=t.touch;if(u===void 0)return;var A=u.pageX-(a+e.left),p=u.pageY-(n+e.top);A=A*(r/e.width),p=p*(o/e.height);var h={x:A,y:p};if(t.type==="touchstart")Browser.lastTouches[u.identifier]=h,Browser.touches[u.identifier]=h;else if(t.type==="touchend"||t.type==="touchmove"){var E=Browser.touches[u.identifier];E||(E=h),Browser.lastTouches[u.identifier]=E,Browser.touches[u.identifier]=h}return}var I=t.pageX-(a+e.left),v=t.pageY-(n+e.top);I=I*(r/e.width),v=v*(o/e.height),Browser.mouseMovementX=I-Browser.mouseX,Browser.mouseMovementY=v-Browser.mouseY,Browser.mouseX=I,Browser.mouseY=v}},asyncLoad:function(t,e,r,o){var a=o?"":"al "+t;Module.readAsync(t,function(n){assert(n,'Loading data file "'+t+'" failed (no arrayBuffer).'),e(new Uint8Array(n)),a&&removeRunDependency(a)},function(n){if(r)r();else throw'Loading data file "'+t+'" failed.'}),a&&addRunDependency(a)},resizeListeners:[],updateResizeListeners:function(){var t=Module.canvas;Browser.resizeListeners.forEach(function(e){e(t.width,t.height)})},setCanvasSize:function(t,e,r){var o=Module.canvas;Browser.updateCanvasDimensions(o,t,e),r||Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize:function(){if(typeof SDL<"u"){var t=HEAPU32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2];t=t|8388608,HEAP32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2]=t}Browser.updateResizeListeners()},setWindowedCanvasSize:function(){if(typeof SDL<"u"){var t=HEAPU32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2];t=t&-8388609,HEAP32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2]=t}Browser.updateResizeListeners()},updateCanvasDimensions:function(t,e,r){e&&r?(t.widthNative=e,t.heightNative=r):(e=t.widthNative,r=t.heightNative);var o=e,a=r;if(Module.forcedAspectRatio&&Module.forcedAspectRatio>0&&(o/a>2];return e},getStr:function(){var t=Pointer_stringify(SYSCALLS.get());return t},get64:function(){var t=SYSCALLS.get(),e=SYSCALLS.get();return t>=0?assert(e===0):assert(e===-1),t},getZero:function(){assert(SYSCALLS.get()===0)}};function ___syscall6(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.getStreamFromFD();return FS.close(r),0}catch(o){return(typeof FS>"u"||!(o instanceof FS.ErrnoError))&&abort(o),-o.errno}}function ___syscall54(t,e){SYSCALLS.varargs=e;try{return 0}catch(r){return(typeof FS>"u"||!(r instanceof FS.ErrnoError))&&abort(r),-r.errno}}function _typeModule(t){var e=[[0,1,"X"],[1,1,"const X"],[128,1,"X *"],[256,1,"X &"],[384,1,"X &&"],[512,1,"std::shared_ptr"],[640,1,"std::unique_ptr"],[5120,1,"std::vector"],[6144,2,"std::array"],[9216,-1,"std::function"]];function r(p,h,E,I,v,b){if(h==1){var C=I&896;(C==128||C==256||C==384)&&(p="X const")}var T;return b?T=E.replace("X",p).replace("Y",v):T=p.replace("X",E).replace("Y",v),T.replace(/([*&]) (?=[*&])/g,"$1")}function o(p,h,E,I,v){throw new Error(p+" type "+E.replace("X",h+"?")+(I?" with flag "+I:"")+" in "+v)}function a(p,h,E,I,v,b,C,T){b===void 0&&(b="X"),T===void 0&&(T=1);var L=E(p);if(L)return L;var U=I(p),J=U.placeholderFlag,te=e[J];C&&te&&(b=r(C[2],C[0],b,te[0],"?",!0));var le;J==0&&(le="Unbound"),J>=10&&(le="Corrupt"),T>20&&(le="Deeply nested"),le&&o(le,p,b,J,v||"?");var pe=U.paramList[0],Ae=a(pe,h,E,I,v,b,te,T+1),ye,ae={flags:te[0],id:p,name:"",paramList:[Ae]},we=[],Pe="?";switch(U.placeholderFlag){case 1:ye=Ae.spec;break;case 2:if((Ae.flags&15360)==1024&&Ae.spec.ptrSize==1){ae.flags=7168;break}case 3:case 6:case 5:ye=Ae.spec,Ae.flags&15360;break;case 8:Pe=""+U.paramList[1],ae.paramList.push(U.paramList[1]);break;case 9:for(var g=0,Ee=U.paramList[1];g>2]=t),t}function _llvm_stacksave(){var t=_llvm_stacksave;return t.LLVM_SAVEDSTACKS||(t.LLVM_SAVEDSTACKS=[]),t.LLVM_SAVEDSTACKS.push(Runtime.stackSave()),t.LLVM_SAVEDSTACKS.length-1}function ___syscall140(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.getStreamFromFD(),o=SYSCALLS.get(),a=SYSCALLS.get(),n=SYSCALLS.get(),u=SYSCALLS.get(),A=a;return FS.llseek(r,A,u),HEAP32[n>>2]=r.position,r.getdents&&A===0&&u===0&&(r.getdents=null),0}catch(p){return(typeof FS>"u"||!(p instanceof FS.ErrnoError))&&abort(p),-p.errno}}function ___syscall146(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.get(),o=SYSCALLS.get(),a=SYSCALLS.get(),n=0;___syscall146.buffer||(___syscall146.buffers=[null,[],[]],___syscall146.printChar=function(E,I){var v=___syscall146.buffers[E];assert(v),I===0||I===10?((E===1?Module.print:Module.printErr)(UTF8ArrayToString(v,0)),v.length=0):v.push(I)});for(var u=0;u>2],p=HEAP32[o+(u*8+4)>>2],h=0;h"u"||!(E instanceof FS.ErrnoError))&&abort(E),-E.errno}}function __nbind_finish(){for(var t=0,e=_nbind.BindClass.list;tt.pageSize/2||e>t.pageSize-r){var o=_nbind.typeNameTbl.NBind.proto;return o.lalloc(e)}else return HEAPU32[t.usedPtr]=r+e,t.rootPtr+r},t.lreset=function(e,r){var o=HEAPU32[t.pagePtr];if(o){var a=_nbind.typeNameTbl.NBind.proto;a.lreset(e,r)}else HEAPU32[t.usedPtr]=e},t}();_nbind.Pool=Pool;function constructType(t,e){var r=t==10240?_nbind.makeTypeNameTbl[e.name]||_nbind.BindType:_nbind.makeTypeKindTbl[t],o=new r(e);return typeIdTbl[e.id]=o,_nbind.typeNameTbl[e.name]=o,o}_nbind.constructType=constructType;function getType(t){return typeIdTbl[t]}_nbind.getType=getType;function queryType(t){var e=HEAPU8[t],r=_nbind.structureList[e][1];t/=4,r<0&&(++t,r=HEAPU32[t]+1);var o=Array.prototype.slice.call(HEAPU32.subarray(t+1,t+1+r));return e==9&&(o=[o[0],o.slice(1)]),{paramList:o,placeholderFlag:e}}_nbind.queryType=queryType;function getTypes(t,e){return t.map(function(r){return typeof r=="number"?_nbind.getComplexType(r,constructType,getType,queryType,e):_nbind.typeNameTbl[r]})}_nbind.getTypes=getTypes;function readTypeIdList(t,e){return Array.prototype.slice.call(HEAPU32,t/4,t/4+e)}_nbind.readTypeIdList=readTypeIdList;function readAsciiString(t){for(var e=t;HEAPU8[e++];);return String.fromCharCode.apply("",HEAPU8.subarray(t,e-1))}_nbind.readAsciiString=readAsciiString;function readPolicyList(t){var e={};if(t)for(;;){var r=HEAPU32[t/4];if(!r)break;e[readAsciiString(r)]=!0,t+=4}return e}_nbind.readPolicyList=readPolicyList;function getDynCall(t,e){var r={float32_t:"d",float64_t:"d",int64_t:"d",uint64_t:"d",void:"v"},o=t.map(function(n){return r[n.name]||"i"}).join(""),a=Module["dynCall_"+o];if(!a)throw new Error("dynCall_"+o+" not found for "+e+"("+t.map(function(n){return n.name}).join(", ")+")");return a}_nbind.getDynCall=getDynCall;function addMethod(t,e,r,o){var a=t[e];t.hasOwnProperty(e)&&a?((a.arity||a.arity===0)&&(a=_nbind.makeOverloader(a,a.arity),t[e]=a),a.addMethod(r,o)):(r.arity=o,t[e]=r)}_nbind.addMethod=addMethod;function throwError(t){throw new Error(t)}_nbind.throwError=throwError,_nbind.bigEndian=!1,_a=_typeModule(_typeModule),_nbind.Type=_a.Type,_nbind.makeType=_a.makeType,_nbind.getComplexType=_a.getComplexType,_nbind.structureList=_a.structureList;var BindType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.heap=HEAPU32,r.ptrSize=4,r}return e.prototype.needsWireRead=function(r){return!!this.wireRead||!!this.makeWireRead},e.prototype.needsWireWrite=function(r){return!!this.wireWrite||!!this.makeWireWrite},e}(_nbind.Type);_nbind.BindType=BindType;var PrimitiveType=function(t){__extends(e,t);function e(r){var o=t.call(this,r)||this,a=r.flags&32?{32:HEAPF32,64:HEAPF64}:r.flags&8?{8:HEAPU8,16:HEAPU16,32:HEAPU32}:{8:HEAP8,16:HEAP16,32:HEAP32};return o.heap=a[r.ptrSize*8],o.ptrSize=r.ptrSize,o}return e.prototype.needsWireWrite=function(r){return!!r&&!!r.Strict},e.prototype.makeWireWrite=function(r,o){return o&&o.Strict&&function(a){if(typeof a=="number")return a;throw new Error("Type mismatch")}},e}(BindType);_nbind.PrimitiveType=PrimitiveType;function pushCString(t,e){if(t==null){if(e&&e.Nullable)return 0;throw new Error("Type mismatch")}if(e&&e.Strict){if(typeof t!="string")throw new Error("Type mismatch")}else t=t.toString();var r=Module.lengthBytesUTF8(t)+1,o=_nbind.Pool.lalloc(r);return Module.stringToUTF8Array(t,HEAPU8,o,r),o}_nbind.pushCString=pushCString;function popCString(t){return t===0?null:Module.Pointer_stringify(t)}_nbind.popCString=popCString;var CStringType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=popCString,r.wireWrite=pushCString,r.readResources=[_nbind.resources.pool],r.writeResources=[_nbind.resources.pool],r}return e.prototype.makeWireWrite=function(r,o){return function(a){return pushCString(a,o)}},e}(BindType);_nbind.CStringType=CStringType;var BooleanType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=function(o){return!!o},r}return e.prototype.needsWireWrite=function(r){return!!r&&!!r.Strict},e.prototype.makeWireRead=function(r){return"!!("+r+")"},e.prototype.makeWireWrite=function(r,o){return o&&o.Strict&&function(a){if(typeof a=="boolean")return a;throw new Error("Type mismatch")}||r},e}(BindType);_nbind.BooleanType=BooleanType;var Wrapper=function(){function t(){}return t.prototype.persist=function(){this.__nbindState|=1},t}();_nbind.Wrapper=Wrapper;function makeBound(t,e){var r=function(o){__extends(a,o);function a(n,u,A,p){var h=o.call(this)||this;if(!(h instanceof a))return new(Function.prototype.bind.apply(a,Array.prototype.concat.apply([null],arguments)));var E=u,I=A,v=p;if(n!==_nbind.ptrMarker){var b=h.__nbindConstructor.apply(h,arguments);E=4608,v=HEAPU32[b/4],I=HEAPU32[b/4+1]}var C={configurable:!0,enumerable:!1,value:null,writable:!1},T={__nbindFlags:E,__nbindPtr:I};v&&(T.__nbindShared=v,_nbind.mark(h));for(var L=0,U=Object.keys(T);L>=1;var r=_nbind.valueList[t];return _nbind.valueList[t]=firstFreeValue,firstFreeValue=t,r}else{if(e)return _nbind.popShared(t,e);throw new Error("Invalid value slot "+t)}}_nbind.popValue=popValue;var valueBase=18446744073709552e3;function push64(t){return typeof t=="number"?t:pushValue(t)*4096+valueBase}function pop64(t){return t=3?u=Buffer.from(n):u=new Buffer(n),u.copy(o)}else getBuffer(o).set(n)}}_nbind.commitBuffer=commitBuffer;var dirtyList=[],gcTimer=0;function sweep(){for(var t=0,e=dirtyList;t>2]=DYNAMIC_BASE,staticSealed=!0;function invoke_viiiii(t,e,r,o,a,n){try{Module.dynCall_viiiii(t,e,r,o,a,n)}catch(u){if(typeof u!="number"&&u!=="longjmp")throw u;Module.setThrew(1,0)}}function invoke_vif(t,e,r){try{Module.dynCall_vif(t,e,r)}catch(o){if(typeof o!="number"&&o!=="longjmp")throw o;Module.setThrew(1,0)}}function invoke_vid(t,e,r){try{Module.dynCall_vid(t,e,r)}catch(o){if(typeof o!="number"&&o!=="longjmp")throw o;Module.setThrew(1,0)}}function invoke_fiff(t,e,r,o){try{return Module.dynCall_fiff(t,e,r,o)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_vi(t,e){try{Module.dynCall_vi(t,e)}catch(r){if(typeof r!="number"&&r!=="longjmp")throw r;Module.setThrew(1,0)}}function invoke_vii(t,e,r){try{Module.dynCall_vii(t,e,r)}catch(o){if(typeof o!="number"&&o!=="longjmp")throw o;Module.setThrew(1,0)}}function invoke_ii(t,e){try{return Module.dynCall_ii(t,e)}catch(r){if(typeof r!="number"&&r!=="longjmp")throw r;Module.setThrew(1,0)}}function invoke_viddi(t,e,r,o,a){try{Module.dynCall_viddi(t,e,r,o,a)}catch(n){if(typeof n!="number"&&n!=="longjmp")throw n;Module.setThrew(1,0)}}function invoke_vidd(t,e,r,o){try{Module.dynCall_vidd(t,e,r,o)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_iiii(t,e,r,o){try{return Module.dynCall_iiii(t,e,r,o)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_diii(t,e,r,o){try{return Module.dynCall_diii(t,e,r,o)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_di(t,e){try{return Module.dynCall_di(t,e)}catch(r){if(typeof r!="number"&&r!=="longjmp")throw r;Module.setThrew(1,0)}}function invoke_iid(t,e,r){try{return Module.dynCall_iid(t,e,r)}catch(o){if(typeof o!="number"&&o!=="longjmp")throw o;Module.setThrew(1,0)}}function invoke_iii(t,e,r){try{return Module.dynCall_iii(t,e,r)}catch(o){if(typeof o!="number"&&o!=="longjmp")throw o;Module.setThrew(1,0)}}function invoke_viiddi(t,e,r,o,a,n){try{Module.dynCall_viiddi(t,e,r,o,a,n)}catch(u){if(typeof u!="number"&&u!=="longjmp")throw u;Module.setThrew(1,0)}}function invoke_viiiiii(t,e,r,o,a,n,u){try{Module.dynCall_viiiiii(t,e,r,o,a,n,u)}catch(A){if(typeof A!="number"&&A!=="longjmp")throw A;Module.setThrew(1,0)}}function invoke_dii(t,e,r){try{return Module.dynCall_dii(t,e,r)}catch(o){if(typeof o!="number"&&o!=="longjmp")throw o;Module.setThrew(1,0)}}function invoke_i(t){try{return Module.dynCall_i(t)}catch(e){if(typeof e!="number"&&e!=="longjmp")throw e;Module.setThrew(1,0)}}function invoke_iiiiii(t,e,r,o,a,n){try{return Module.dynCall_iiiiii(t,e,r,o,a,n)}catch(u){if(typeof u!="number"&&u!=="longjmp")throw u;Module.setThrew(1,0)}}function invoke_viiid(t,e,r,o,a){try{Module.dynCall_viiid(t,e,r,o,a)}catch(n){if(typeof n!="number"&&n!=="longjmp")throw n;Module.setThrew(1,0)}}function invoke_viififi(t,e,r,o,a,n,u){try{Module.dynCall_viififi(t,e,r,o,a,n,u)}catch(A){if(typeof A!="number"&&A!=="longjmp")throw A;Module.setThrew(1,0)}}function invoke_viii(t,e,r,o){try{Module.dynCall_viii(t,e,r,o)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_v(t){try{Module.dynCall_v(t)}catch(e){if(typeof e!="number"&&e!=="longjmp")throw e;Module.setThrew(1,0)}}function invoke_viid(t,e,r,o){try{Module.dynCall_viid(t,e,r,o)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_idd(t,e,r){try{return Module.dynCall_idd(t,e,r)}catch(o){if(typeof o!="number"&&o!=="longjmp")throw o;Module.setThrew(1,0)}}function invoke_viiii(t,e,r,o,a){try{Module.dynCall_viiii(t,e,r,o,a)}catch(n){if(typeof n!="number"&&n!=="longjmp")throw n;Module.setThrew(1,0)}}Module.asmGlobalArg={Math,Int8Array,Int16Array,Int32Array,Uint8Array,Uint16Array,Uint32Array,Float32Array,Float64Array,NaN:NaN,Infinity:1/0},Module.asmLibraryArg={abort,assert,enlargeMemory,getTotalMemory,abortOnCannotGrowMemory,invoke_viiiii,invoke_vif,invoke_vid,invoke_fiff,invoke_vi,invoke_vii,invoke_ii,invoke_viddi,invoke_vidd,invoke_iiii,invoke_diii,invoke_di,invoke_iid,invoke_iii,invoke_viiddi,invoke_viiiiii,invoke_dii,invoke_i,invoke_iiiiii,invoke_viiid,invoke_viififi,invoke_viii,invoke_v,invoke_viid,invoke_idd,invoke_viiii,_emscripten_asm_const_iiiii,_emscripten_asm_const_iiidddddd,_emscripten_asm_const_iiiid,__nbind_reference_external,_emscripten_asm_const_iiiiiiii,_removeAccessorPrefix,_typeModule,__nbind_register_pool,__decorate,_llvm_stackrestore,___cxa_atexit,__extends,__nbind_get_value_object,__ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj,_emscripten_set_main_loop_timing,__nbind_register_primitive,__nbind_register_type,_emscripten_memcpy_big,__nbind_register_function,___setErrNo,__nbind_register_class,__nbind_finish,_abort,_nbind_value,_llvm_stacksave,___syscall54,_defineHidden,_emscripten_set_main_loop,_emscripten_get_now,__nbind_register_callback_signature,_emscripten_asm_const_iiiiii,__nbind_free_external,_emscripten_asm_const_iiii,_emscripten_asm_const_iiididi,___syscall6,_atexit,___syscall140,___syscall146,DYNAMICTOP_PTR,tempDoublePtr,ABORT,STACKTOP,STACK_MAX,cttz_i8,___dso_handle};var asm=function(t,e,r){var o=new t.Int8Array(r),a=new t.Int16Array(r),n=new t.Int32Array(r),u=new t.Uint8Array(r),A=new t.Uint16Array(r),p=new t.Uint32Array(r),h=new t.Float32Array(r),E=new t.Float64Array(r),I=e.DYNAMICTOP_PTR|0,v=e.tempDoublePtr|0,b=e.ABORT|0,C=e.STACKTOP|0,T=e.STACK_MAX|0,L=e.cttz_i8|0,U=e.___dso_handle|0,J=0,te=0,le=0,pe=0,Ae=t.NaN,ye=t.Infinity,ae=0,we=0,Pe=0,g=0,Ee=0,De=0,ce=t.Math.floor,ne=t.Math.abs,ee=t.Math.sqrt,Ie=t.Math.pow,ke=t.Math.cos,ht=t.Math.sin,H=t.Math.tan,lt=t.Math.acos,Re=t.Math.asin,Qe=t.Math.atan,be=t.Math.atan2,_e=t.Math.exp,Te=t.Math.log,Je=t.Math.ceil,He=t.Math.imul,x=t.Math.min,w=t.Math.max,S=t.Math.clz32,y=t.Math.fround,F=e.abort,z=e.assert,X=e.enlargeMemory,Z=e.getTotalMemory,ie=e.abortOnCannotGrowMemory,Se=e.invoke_viiiii,Ne=e.invoke_vif,ot=e.invoke_vid,dt=e.invoke_fiff,jt=e.invoke_vi,$t=e.invoke_vii,xt=e.invoke_ii,an=e.invoke_viddi,Qr=e.invoke_vidd,mr=e.invoke_iiii,xr=e.invoke_diii,Wr=e.invoke_di,Vn=e.invoke_iid,Ns=e.invoke_iii,Ri=e.invoke_viiddi,ps=e.invoke_viiiiii,io=e.invoke_dii,Si=e.invoke_i,Ls=e.invoke_iiiiii,so=e.invoke_viiid,cc=e.invoke_viififi,cu=e.invoke_viii,ap=e.invoke_v,lp=e.invoke_viid,Ms=e.invoke_idd,Dn=e.invoke_viiii,oo=e._emscripten_asm_const_iiiii,Os=e._emscripten_asm_const_iiidddddd,ml=e._emscripten_asm_const_iiiid,yl=e.__nbind_reference_external,ao=e._emscripten_asm_const_iiiiiiii,Kn=e._removeAccessorPrefix,Mn=e._typeModule,Ni=e.__nbind_register_pool,On=e.__decorate,_i=e._llvm_stackrestore,tr=e.___cxa_atexit,Me=e.__extends,ii=e.__nbind_get_value_object,Oa=e.__ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj,hr=e._emscripten_set_main_loop_timing,uc=e.__nbind_register_primitive,uu=e.__nbind_register_type,Ac=e._emscripten_memcpy_big,El=e.__nbind_register_function,vA=e.___setErrNo,Au=e.__nbind_register_class,Ce=e.__nbind_finish,Tt=e._abort,fc=e._nbind_value,Hi=e._llvm_stacksave,fu=e.___syscall54,Yt=e._defineHidden,Cl=e._emscripten_set_main_loop,DA=e._emscripten_get_now,cp=e.__nbind_register_callback_signature,pc=e._emscripten_asm_const_iiiiii,PA=e.__nbind_free_external,Qn=e._emscripten_asm_const_iiii,hi=e._emscripten_asm_const_iiididi,hc=e.___syscall6,SA=e._atexit,sa=e.___syscall140,Li=e.___syscall146,_o=y(0);let Ze=y(0);function lo(s){s=s|0;var l=0;return l=C,C=C+s|0,C=C+15&-16,l|0}function gc(){return C|0}function pu(s){s=s|0,C=s}function ji(s,l){s=s|0,l=l|0,C=s,T=l}function hu(s,l){s=s|0,l=l|0,J||(J=s,te=l)}function xA(s){s=s|0,De=s}function Ua(){return De|0}function dc(){var s=0,l=0;Dr(8104,8,400)|0,Dr(8504,408,540)|0,s=9044,l=s+44|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));o[9088]=0,o[9089]=1,n[2273]=0,n[2274]=948,n[2275]=948,tr(17,8104,U|0)|0}function hs(s){s=s|0,ft(s+948|0)}function _t(s){return s=y(s),((Du(s)|0)&2147483647)>>>0>2139095040|0}function Fn(s,l,c){s=s|0,l=l|0,c=c|0;e:do if(n[s+(l<<3)+4>>2]|0)s=s+(l<<3)|0;else{if((l|2|0)==3&&n[s+60>>2]|0){s=s+56|0;break}switch(l|0){case 0:case 2:case 4:case 5:{if(n[s+52>>2]|0){s=s+48|0;break e}break}default:}if(n[s+68>>2]|0){s=s+64|0;break}else{s=(l|1|0)==5?948:c;break}}while(0);return s|0}function Ci(s){s=s|0;var l=0;return l=pD(1e3)|0,oa(s,(l|0)!=0,2456),n[2276]=(n[2276]|0)+1,Dr(l|0,8104,1e3)|0,o[s+2>>0]|0&&(n[l+4>>2]=2,n[l+12>>2]=4),n[l+976>>2]=s,l|0}function oa(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;d=C,C=C+16|0,f=d,l||(n[f>>2]=c,yg(s,5,3197,f)),C=d}function co(){return Ci(956)|0}function Us(s){s=s|0;var l=0;return l=Vt(1e3)|0,aa(l,s),oa(n[s+976>>2]|0,1,2456),n[2276]=(n[2276]|0)+1,n[l+944>>2]=0,l|0}function aa(s,l){s=s|0,l=l|0;var c=0;Dr(s|0,l|0,948)|0,Fm(s+948|0,l+948|0),c=s+960|0,s=l+960|0,l=c+40|0;do n[c>>2]=n[s>>2],c=c+4|0,s=s+4|0;while((c|0)<(l|0))}function la(s){s=s|0;var l=0,c=0,f=0,d=0;if(l=s+944|0,c=n[l>>2]|0,c|0&&(Ho(c+948|0,s)|0,n[l>>2]=0),c=wi(s)|0,c|0){l=0;do n[(gs(s,l)|0)+944>>2]=0,l=l+1|0;while((l|0)!=(c|0))}c=s+948|0,f=n[c>>2]|0,d=s+952|0,l=n[d>>2]|0,(l|0)!=(f|0)&&(n[d>>2]=l+(~((l+-4-f|0)>>>2)<<2)),ds(c),hD(s),n[2276]=(n[2276]|0)+-1}function Ho(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0;f=n[s>>2]|0,k=s+4|0,c=n[k>>2]|0,m=c;e:do if((f|0)==(c|0))d=f,B=4;else for(s=f;;){if((n[s>>2]|0)==(l|0)){d=s,B=4;break e}if(s=s+4|0,(s|0)==(c|0)){s=0;break}}while(0);return(B|0)==4&&((d|0)!=(c|0)?(f=d+4|0,s=m-f|0,l=s>>2,l&&(Mw(d|0,f|0,s|0)|0,c=n[k>>2]|0),s=d+(l<<2)|0,(c|0)==(s|0)||(n[k>>2]=c+(~((c+-4-s|0)>>>2)<<2)),s=1):s=0),s|0}function wi(s){return s=s|0,(n[s+952>>2]|0)-(n[s+948>>2]|0)>>2|0}function gs(s,l){s=s|0,l=l|0;var c=0;return c=n[s+948>>2]|0,(n[s+952>>2]|0)-c>>2>>>0>l>>>0?s=n[c+(l<<2)>>2]|0:s=0,s|0}function ds(s){s=s|0;var l=0,c=0,f=0,d=0;f=C,C=C+32|0,l=f,d=n[s>>2]|0,c=(n[s+4>>2]|0)-d|0,((n[s+8>>2]|0)-d|0)>>>0>c>>>0&&(d=c>>2,wp(l,d,d,s+8|0),Ig(s,l),UA(l)),C=f}function ms(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0;O=wi(s)|0;do if(O|0){if((n[(gs(s,0)|0)+944>>2]|0)==(s|0)){if(!(Ho(s+948|0,l)|0))break;Dr(l+400|0,8504,540)|0,n[l+944>>2]=0,Le(s);break}B=n[(n[s+976>>2]|0)+12>>2]|0,k=s+948|0,Q=(B|0)==0,c=0,m=0;do f=n[(n[k>>2]|0)+(m<<2)>>2]|0,(f|0)==(l|0)?Le(s):(d=Us(f)|0,n[(n[k>>2]|0)+(c<<2)>>2]=d,n[d+944>>2]=s,Q||LT[B&15](f,d,s,c),c=c+1|0),m=m+1|0;while((m|0)!=(O|0));if(c>>>0>>0){Q=s+948|0,k=s+952|0,B=c,c=n[k>>2]|0;do m=(n[Q>>2]|0)+(B<<2)|0,f=m+4|0,d=c-f|0,l=d>>2,l&&(Mw(m|0,f|0,d|0)|0,c=n[k>>2]|0),d=c,f=m+(l<<2)|0,(d|0)!=(f|0)&&(c=d+(~((d+-4-f|0)>>>2)<<2)|0,n[k>>2]=c),B=B+1|0;while((B|0)!=(O|0))}}while(0)}function _s(s){s=s|0;var l=0,c=0,f=0,d=0;Un(s,(wi(s)|0)==0,2491),Un(s,(n[s+944>>2]|0)==0,2545),l=s+948|0,c=n[l>>2]|0,f=s+952|0,d=n[f>>2]|0,(d|0)!=(c|0)&&(n[f>>2]=d+(~((d+-4-c|0)>>>2)<<2)),ds(l),l=s+976|0,c=n[l>>2]|0,Dr(s|0,8104,1e3)|0,o[c+2>>0]|0&&(n[s+4>>2]=2,n[s+12>>2]=4),n[l>>2]=c}function Un(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;d=C,C=C+16|0,f=d,l||(n[f>>2]=c,Ao(s,5,3197,f)),C=d}function Pn(){return n[2276]|0}function ys(){var s=0;return s=pD(20)|0,We((s|0)!=0,2592),n[2277]=(n[2277]|0)+1,n[s>>2]=n[239],n[s+4>>2]=n[240],n[s+8>>2]=n[241],n[s+12>>2]=n[242],n[s+16>>2]=n[243],s|0}function We(s,l){s=s|0,l=l|0;var c=0,f=0;f=C,C=C+16|0,c=f,s||(n[c>>2]=l,Ao(0,5,3197,c)),C=f}function tt(s){s=s|0,hD(s),n[2277]=(n[2277]|0)+-1}function It(s,l){s=s|0,l=l|0;var c=0;l?(Un(s,(wi(s)|0)==0,2629),c=1):(c=0,l=0),n[s+964>>2]=l,n[s+988>>2]=c}function nr(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,m=f+8|0,d=f+4|0,B=f,n[d>>2]=l,Un(s,(n[l+944>>2]|0)==0,2709),Un(s,(n[s+964>>2]|0)==0,2763),$(s),l=s+948|0,n[B>>2]=(n[l>>2]|0)+(c<<2),n[m>>2]=n[B>>2],me(l,m,d)|0,n[(n[d>>2]|0)+944>>2]=s,Le(s),C=f}function $(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0;if(c=wi(s)|0,c|0&&(n[(gs(s,0)|0)+944>>2]|0)!=(s|0)){f=n[(n[s+976>>2]|0)+12>>2]|0,d=s+948|0,m=(f|0)==0,l=0;do B=n[(n[d>>2]|0)+(l<<2)>>2]|0,k=Us(B)|0,n[(n[d>>2]|0)+(l<<2)>>2]=k,n[k+944>>2]=s,m||LT[f&15](B,k,s,l),l=l+1|0;while((l|0)!=(c|0))}}function me(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0,Ge=0,Oe=0,Fe=0,et=0,Xe=0;et=C,C=C+64|0,q=et+52|0,k=et+48|0,se=et+28|0,Ge=et+24|0,Oe=et+20|0,Fe=et,f=n[s>>2]|0,m=f,l=f+((n[l>>2]|0)-m>>2<<2)|0,f=s+4|0,d=n[f>>2]|0,B=s+8|0;do if(d>>>0<(n[B>>2]|0)>>>0){if((l|0)==(d|0)){n[l>>2]=n[c>>2],n[f>>2]=(n[f>>2]|0)+4;break}_A(s,l,d,l+4|0),l>>>0<=c>>>0&&(c=(n[f>>2]|0)>>>0>c>>>0?c+4|0:c),n[l>>2]=n[c>>2]}else{f=(d-m>>2)+1|0,d=N(s)|0,d>>>0>>0&&zr(s),M=n[s>>2]|0,O=(n[B>>2]|0)-M|0,m=O>>1,wp(Fe,O>>2>>>0>>1>>>0?m>>>0>>0?f:m:d,l-M>>2,s+8|0),M=Fe+8|0,f=n[M>>2]|0,m=Fe+12|0,O=n[m>>2]|0,B=O,Q=f;do if((f|0)==(O|0)){if(O=Fe+4|0,f=n[O>>2]|0,Xe=n[Fe>>2]|0,d=Xe,f>>>0<=Xe>>>0){f=B-d>>1,f=(f|0)==0?1:f,wp(se,f,f>>>2,n[Fe+16>>2]|0),n[Ge>>2]=n[O>>2],n[Oe>>2]=n[M>>2],n[k>>2]=n[Ge>>2],n[q>>2]=n[Oe>>2],vw(se,k,q),f=n[Fe>>2]|0,n[Fe>>2]=n[se>>2],n[se>>2]=f,f=se+4|0,Xe=n[O>>2]|0,n[O>>2]=n[f>>2],n[f>>2]=Xe,f=se+8|0,Xe=n[M>>2]|0,n[M>>2]=n[f>>2],n[f>>2]=Xe,f=se+12|0,Xe=n[m>>2]|0,n[m>>2]=n[f>>2],n[f>>2]=Xe,UA(se),f=n[M>>2]|0;break}m=f,B=((m-d>>2)+1|0)/-2|0,k=f+(B<<2)|0,d=Q-m|0,m=d>>2,m&&(Mw(k|0,f|0,d|0)|0,f=n[O>>2]|0),Xe=k+(m<<2)|0,n[M>>2]=Xe,n[O>>2]=f+(B<<2),f=Xe}while(0);n[f>>2]=n[c>>2],n[M>>2]=(n[M>>2]|0)+4,l=Bg(s,Fe,l)|0,UA(Fe)}while(0);return C=et,l|0}function Le(s){s=s|0;var l=0;do{if(l=s+984|0,o[l>>0]|0)break;o[l>>0]=1,h[s+504>>2]=y(Ae),s=n[s+944>>2]|0}while((s|0)!=0)}function ft(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-4-f|0)>>>2)<<2)),gt(c))}function pt(s){return s=s|0,n[s+944>>2]|0}function Rt(s){s=s|0,Un(s,(n[s+964>>2]|0)!=0,2832),Le(s)}function er(s){return s=s|0,(o[s+984>>0]|0)!=0|0}function Zr(s,l){s=s|0,l=l|0,LUe(s,l,400)|0&&(Dr(s|0,l|0,400)|0,Le(s))}function qi(s){s=s|0;var l=Ze;return l=y(h[s+44>>2]),s=_t(l)|0,y(s?y(0):l)}function es(s){s=s|0;var l=Ze;return l=y(h[s+48>>2]),_t(l)|0&&(l=o[(n[s+976>>2]|0)+2>>0]|0?y(1):y(0)),y(l)}function xi(s,l){s=s|0,l=l|0,n[s+980>>2]=l}function jo(s){return s=s|0,n[s+980>>2]|0}function bA(s,l){s=s|0,l=l|0;var c=0;c=s+4|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function kA(s){return s=s|0,n[s+4>>2]|0}function up(s,l){s=s|0,l=l|0;var c=0;c=s+8|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function ng(s){return s=s|0,n[s+8>>2]|0}function gu(s,l){s=s|0,l=l|0;var c=0;c=s+12|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function ig(s){return s=s|0,n[s+12>>2]|0}function du(s,l){s=s|0,l=l|0;var c=0;c=s+16|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function uo(s){return s=s|0,n[s+16>>2]|0}function QA(s,l){s=s|0,l=l|0;var c=0;c=s+20|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function mc(s){return s=s|0,n[s+20>>2]|0}function ca(s,l){s=s|0,l=l|0;var c=0;c=s+24|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function sg(s){return s=s|0,n[s+24>>2]|0}function yc(s,l){s=s|0,l=l|0;var c=0;c=s+28|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function Pm(s){return s=s|0,n[s+28>>2]|0}function og(s,l){s=s|0,l=l|0;var c=0;c=s+32|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function $n(s){return s=s|0,n[s+32>>2]|0}function Ap(s,l){s=s|0,l=l|0;var c=0;c=s+36|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function ag(s){return s=s|0,n[s+36>>2]|0}function FA(s,l){s=s|0,l=y(l);var c=0;c=s+40|0,y(h[c>>2])!=l&&(h[c>>2]=l,Le(s))}function Hs(s,l){s=s|0,l=y(l);var c=0;c=s+44|0,y(h[c>>2])!=l&&(h[c>>2]=l,Le(s))}function mu(s,l){s=s|0,l=y(l);var c=0;c=s+48|0,y(h[c>>2])!=l&&(h[c>>2]=l,Le(s))}function Ha(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=(m^1)&1,f=s+52|0,d=s+56|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function Gi(s,l){s=s|0,l=y(l);var c=0,f=0;f=s+52|0,c=s+56|0,y(h[f>>2])==l&&(n[c>>2]|0)==2||(h[f>>2]=l,f=_t(l)|0,n[c>>2]=f?3:2,Le(s))}function ua(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+52|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function yu(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=_t(c)|0,f=(m^1)&1,d=s+132+(l<<3)|0,l=s+132+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Le(s))}function Es(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=_t(c)|0,f=m?0:2,d=s+132+(l<<3)|0,l=s+132+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Le(s))}function Ec(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=l+132+(c<<3)|0,l=n[f+4>>2]|0,c=s,n[c>>2]=n[f>>2],n[c+4>>2]=l}function Cc(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=_t(c)|0,f=(m^1)&1,d=s+60+(l<<3)|0,l=s+60+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Le(s))}function G(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=_t(c)|0,f=m?0:2,d=s+60+(l<<3)|0,l=s+60+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Le(s))}function Dt(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=l+60+(c<<3)|0,l=n[f+4>>2]|0,c=s,n[c>>2]=n[f>>2],n[c+4>>2]=l}function wl(s,l){s=s|0,l=l|0;var c=0;c=s+60+(l<<3)+4|0,(n[c>>2]|0)!=3&&(h[s+60+(l<<3)>>2]=y(Ae),n[c>>2]=3,Le(s))}function bi(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=_t(c)|0,f=(m^1)&1,d=s+204+(l<<3)|0,l=s+204+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Le(s))}function wc(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=_t(c)|0,f=m?0:2,d=s+204+(l<<3)|0,l=s+204+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Le(s))}function ct(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=l+204+(c<<3)|0,l=n[f+4>>2]|0,c=s,n[c>>2]=n[f>>2],n[c+4>>2]=l}function Eu(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=_t(c)|0,f=(m^1)&1,d=s+276+(l<<3)|0,l=s+276+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Le(s))}function lg(s,l){return s=s|0,l=l|0,y(h[s+276+(l<<3)>>2])}function mw(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=(m^1)&1,f=s+348|0,d=s+352|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function TA(s,l){s=s|0,l=y(l);var c=0,f=0;f=s+348|0,c=s+352|0,y(h[f>>2])==l&&(n[c>>2]|0)==2||(h[f>>2]=l,f=_t(l)|0,n[c>>2]=f?3:2,Le(s))}function fp(s){s=s|0;var l=0;l=s+352|0,(n[l>>2]|0)!=3&&(h[s+348>>2]=y(Ae),n[l>>2]=3,Le(s))}function Br(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+348|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function Cs(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=(m^1)&1,f=s+356|0,d=s+360|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function cg(s,l){s=s|0,l=y(l);var c=0,f=0;f=s+356|0,c=s+360|0,y(h[f>>2])==l&&(n[c>>2]|0)==2||(h[f>>2]=l,f=_t(l)|0,n[c>>2]=f?3:2,Le(s))}function ug(s){s=s|0;var l=0;l=s+360|0,(n[l>>2]|0)!=3&&(h[s+356>>2]=y(Ae),n[l>>2]=3,Le(s))}function Ag(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+356|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function pp(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=(m^1)&1,f=s+364|0,d=s+368|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function Ic(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=m?0:2,f=s+364|0,d=s+368|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function Ct(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+364|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function Sm(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=(m^1)&1,f=s+372|0,d=s+376|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function fg(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=m?0:2,f=s+372|0,d=s+376|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function pg(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+372|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function Cu(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=(m^1)&1,f=s+380|0,d=s+384|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function xm(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=m?0:2,f=s+380|0,d=s+384|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function hg(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+380|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function wu(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=(m^1)&1,f=s+388|0,d=s+392|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function yw(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=m?0:2,f=s+388|0,d=s+392|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function bm(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+388|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function Aa(s,l){s=s|0,l=y(l);var c=0;c=s+396|0,y(h[c>>2])!=l&&(h[c>>2]=l,Le(s))}function Bc(s){return s=s|0,y(h[s+396>>2])}function Il(s){return s=s|0,y(h[s+400>>2])}function Iu(s){return s=s|0,y(h[s+404>>2])}function gg(s){return s=s|0,y(h[s+408>>2])}function RA(s){return s=s|0,y(h[s+412>>2])}function hp(s){return s=s|0,y(h[s+416>>2])}function ja(s){return s=s|0,y(h[s+420>>2])}function dg(s,l){switch(s=s|0,l=l|0,Un(s,(l|0)<6,2918),l|0){case 0:{l=(n[s+496>>2]|0)==2?5:4;break}case 2:{l=(n[s+496>>2]|0)==2?4:5;break}default:}return y(h[s+424+(l<<2)>>2])}function gp(s,l){switch(s=s|0,l=l|0,Un(s,(l|0)<6,2918),l|0){case 0:{l=(n[s+496>>2]|0)==2?5:4;break}case 2:{l=(n[s+496>>2]|0)==2?4:5;break}default:}return y(h[s+448+(l<<2)>>2])}function qo(s,l){switch(s=s|0,l=l|0,Un(s,(l|0)<6,2918),l|0){case 0:{l=(n[s+496>>2]|0)==2?5:4;break}case 2:{l=(n[s+496>>2]|0)==2?4:5;break}default:}return y(h[s+472+(l<<2)>>2])}function ws(s,l){s=s|0,l=l|0;var c=0,f=Ze;return c=n[s+4>>2]|0,(c|0)==(n[l+4>>2]|0)?c?(f=y(h[s>>2]),s=y(ne(y(f-y(h[l>>2]))))>2]=0,n[f+4>>2]=0,n[f+8>>2]=0,Oa(f|0,s|0,l|0,0),Ao(s,3,(o[f+11>>0]|0)<0?n[f>>2]|0:f,c),s3e(f),C=c}function Go(s,l,c,f){s=y(s),l=y(l),c=c|0,f=f|0;var d=Ze;s=y(s*l),d=y(kT(s,y(1)));do if(Ii(d,y(0))|0)s=y(s-d);else{if(s=y(s-d),Ii(d,y(1))|0){s=y(s+y(1));break}if(c){s=y(s+y(1));break}f||(d>y(.5)?d=y(1):(f=Ii(d,y(.5))|0,d=y(f?1:0)),s=y(s+d))}while(0);return y(s/l)}function NA(s,l,c,f,d,m,B,k,Q,O,M,q,se){s=s|0,l=y(l),c=c|0,f=y(f),d=d|0,m=y(m),B=B|0,k=y(k),Q=y(Q),O=y(O),M=y(M),q=y(q),se=se|0;var Ge=0,Oe=Ze,Fe=Ze,et=Ze,Xe=Ze,at=Ze,Ue=Ze;return Q>2]),Oe!=y(0))?(et=y(Go(l,Oe,0,0)),Xe=y(Go(f,Oe,0,0)),Fe=y(Go(m,Oe,0,0)),Oe=y(Go(k,Oe,0,0))):(Fe=m,et=l,Oe=k,Xe=f),(d|0)==(s|0)?Ge=Ii(Fe,et)|0:Ge=0,(B|0)==(c|0)?se=Ii(Oe,Xe)|0:se=0,!Ge&&(at=y(l-M),!(dp(s,at,Q)|0))&&!(mp(s,at,d,Q)|0)?Ge=mg(s,at,d,m,Q)|0:Ge=1,!se&&(Ue=y(f-q),!(dp(c,Ue,O)|0))&&!(mp(c,Ue,B,O)|0)?se=mg(c,Ue,B,k,O)|0:se=1,se=Ge&se),se|0}function dp(s,l,c){return s=s|0,l=y(l),c=y(c),(s|0)==1?s=Ii(l,c)|0:s=0,s|0}function mp(s,l,c,f){return s=s|0,l=y(l),c=c|0,f=y(f),(s|0)==2&(c|0)==0?l>=f?s=1:s=Ii(l,f)|0:s=0,s|0}function mg(s,l,c,f,d){return s=s|0,l=y(l),c=c|0,f=y(f),d=y(d),(s|0)==2&(c|0)==2&f>l?d<=l?s=1:s=Ii(l,d)|0:s=0,s|0}function fa(s,l,c,f,d,m,B,k,Q,O,M){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=m|0,B=y(B),k=y(k),Q=Q|0,O=O|0,M=M|0;var q=0,se=0,Ge=0,Oe=0,Fe=Ze,et=Ze,Xe=0,at=0,Ue=0,qe=0,Lt=0,Or=0,or=0,Xt=0,Pr=0,Nr=0,ir=0,bn=Ze,go=Ze,mo=Ze,yo=0,ya=0;ir=C,C=C+160|0,Xt=ir+152|0,or=ir+120|0,Or=ir+104|0,Ue=ir+72|0,Oe=ir+56|0,Lt=ir+8|0,at=ir,qe=(n[2279]|0)+1|0,n[2279]=qe,Pr=s+984|0,(o[Pr>>0]|0)!=0&&(n[s+512>>2]|0)!=(n[2278]|0)?Xe=4:(n[s+516>>2]|0)==(f|0)?Nr=0:Xe=4,(Xe|0)==4&&(n[s+520>>2]=0,n[s+924>>2]=-1,n[s+928>>2]=-1,h[s+932>>2]=y(-1),h[s+936>>2]=y(-1),Nr=1);e:do if(n[s+964>>2]|0)if(Fe=y(ln(s,2,B)),et=y(ln(s,0,B)),q=s+916|0,mo=y(h[q>>2]),go=y(h[s+920>>2]),bn=y(h[s+932>>2]),NA(d,l,m,c,n[s+924>>2]|0,mo,n[s+928>>2]|0,go,bn,y(h[s+936>>2]),Fe,et,M)|0)Xe=22;else if(Ge=n[s+520>>2]|0,!Ge)Xe=21;else for(se=0;;){if(q=s+524+(se*24|0)|0,bn=y(h[q>>2]),go=y(h[s+524+(se*24|0)+4>>2]),mo=y(h[s+524+(se*24|0)+16>>2]),NA(d,l,m,c,n[s+524+(se*24|0)+8>>2]|0,bn,n[s+524+(se*24|0)+12>>2]|0,go,mo,y(h[s+524+(se*24|0)+20>>2]),Fe,et,M)|0){Xe=22;break e}if(se=se+1|0,se>>>0>=Ge>>>0){Xe=21;break}}else{if(Q){if(q=s+916|0,!(Ii(y(h[q>>2]),l)|0)){Xe=21;break}if(!(Ii(y(h[s+920>>2]),c)|0)){Xe=21;break}if((n[s+924>>2]|0)!=(d|0)){Xe=21;break}q=(n[s+928>>2]|0)==(m|0)?q:0,Xe=22;break}if(Ge=n[s+520>>2]|0,!Ge)Xe=21;else for(se=0;;){if(q=s+524+(se*24|0)|0,Ii(y(h[q>>2]),l)|0&&Ii(y(h[s+524+(se*24|0)+4>>2]),c)|0&&(n[s+524+(se*24|0)+8>>2]|0)==(d|0)&&(n[s+524+(se*24|0)+12>>2]|0)==(m|0)){Xe=22;break e}if(se=se+1|0,se>>>0>=Ge>>>0){Xe=21;break}}}while(0);do if((Xe|0)==21)o[11697]|0?(q=0,Xe=28):(q=0,Xe=31);else if((Xe|0)==22){if(se=(o[11697]|0)!=0,!((q|0)!=0&(Nr^1)))if(se){Xe=28;break}else{Xe=31;break}Oe=q+16|0,n[s+908>>2]=n[Oe>>2],Ge=q+20|0,n[s+912>>2]=n[Ge>>2],(o[11698]|0)==0|se^1||(n[at>>2]=LA(qe)|0,n[at+4>>2]=qe,Ao(s,4,2972,at),se=n[s+972>>2]|0,se|0&&ef[se&127](s),d=qa(d,Q)|0,m=qa(m,Q)|0,ya=+y(h[Oe>>2]),yo=+y(h[Ge>>2]),n[Lt>>2]=d,n[Lt+4>>2]=m,E[Lt+8>>3]=+l,E[Lt+16>>3]=+c,E[Lt+24>>3]=ya,E[Lt+32>>3]=yo,n[Lt+40>>2]=O,Ao(s,4,2989,Lt))}while(0);return(Xe|0)==28&&(se=LA(qe)|0,n[Oe>>2]=se,n[Oe+4>>2]=qe,n[Oe+8>>2]=Nr?3047:11699,Ao(s,4,3038,Oe),se=n[s+972>>2]|0,se|0&&ef[se&127](s),Lt=qa(d,Q)|0,Xe=qa(m,Q)|0,n[Ue>>2]=Lt,n[Ue+4>>2]=Xe,E[Ue+8>>3]=+l,E[Ue+16>>3]=+c,n[Ue+24>>2]=O,Ao(s,4,3049,Ue),Xe=31),(Xe|0)==31&&(si(s,l,c,f,d,m,B,k,Q,M),o[11697]|0&&(se=n[2279]|0,Lt=LA(se)|0,n[Or>>2]=Lt,n[Or+4>>2]=se,n[Or+8>>2]=Nr?3047:11699,Ao(s,4,3083,Or),se=n[s+972>>2]|0,se|0&&ef[se&127](s),Lt=qa(d,Q)|0,Or=qa(m,Q)|0,yo=+y(h[s+908>>2]),ya=+y(h[s+912>>2]),n[or>>2]=Lt,n[or+4>>2]=Or,E[or+8>>3]=yo,E[or+16>>3]=ya,n[or+24>>2]=O,Ao(s,4,3092,or)),n[s+516>>2]=f,q||(se=s+520|0,q=n[se>>2]|0,(q|0)==16&&(o[11697]|0&&Ao(s,4,3124,Xt),n[se>>2]=0,q=0),Q?q=s+916|0:(n[se>>2]=q+1,q=s+524+(q*24|0)|0),h[q>>2]=l,h[q+4>>2]=c,n[q+8>>2]=d,n[q+12>>2]=m,n[q+16>>2]=n[s+908>>2],n[q+20>>2]=n[s+912>>2],q=0)),Q&&(n[s+416>>2]=n[s+908>>2],n[s+420>>2]=n[s+912>>2],o[s+985>>0]=1,o[Pr>>0]=0),n[2279]=(n[2279]|0)+-1,n[s+512>>2]=n[2278],C=ir,Nr|(q|0)==0|0}function ln(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return f=y(V(s,l,c)),y(f+y(re(s,l,c)))}function Ao(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=C,C=C+16|0,d=m,n[d>>2]=f,s?f=n[s+976>>2]|0:f=0,Eg(f,s,l,c,d),C=m}function LA(s){return s=s|0,(s>>>0>60?3201:3201+(60-s)|0)|0}function qa(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;return d=C,C=C+32|0,c=d+12|0,f=d,n[c>>2]=n[254],n[c+4>>2]=n[255],n[c+8>>2]=n[256],n[f>>2]=n[257],n[f+4>>2]=n[258],n[f+8>>2]=n[259],(s|0)>2?s=11699:s=n[(l?f:c)+(s<<2)>>2]|0,C=d,s|0}function si(s,l,c,f,d,m,B,k,Q,O){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=m|0,B=y(B),k=y(k),Q=Q|0,O=O|0;var M=0,q=0,se=0,Ge=0,Oe=Ze,Fe=Ze,et=Ze,Xe=Ze,at=Ze,Ue=Ze,qe=Ze,Lt=0,Or=0,or=0,Xt=Ze,Pr=Ze,Nr=0,ir=Ze,bn=0,go=0,mo=0,yo=0,ya=0,Qp=0,Fp=0,xl=0,Tp=0,Fu=0,Tu=0,Rp=0,Np=0,Lp=0,Xr=0,bl=0,Mp=0,bc=0,Op=Ze,Up=Ze,Ru=Ze,Nu=Ze,kc=Ze,qs=0,za=0,Wo=0,kl=0,rf=0,nf=Ze,Lu=Ze,sf=Ze,of=Ze,Gs=Ze,vs=Ze,Ql=0,Tn=Ze,af=Ze,Eo=Ze,Qc=Ze,Co=Ze,Fc=Ze,lf=0,cf=0,Tc=Ze,Ys=Ze,Fl=0,uf=0,Af=0,ff=0,br=Ze,Jn=0,Ds=0,wo=0,Ws=0,Tr=0,ur=0,Tl=0,Jt=Ze,pf=0,li=0;Tl=C,C=C+16|0,qs=Tl+12|0,za=Tl+8|0,Wo=Tl+4|0,kl=Tl,Un(s,(d|0)==0|(_t(l)|0)^1,3326),Un(s,(m|0)==0|(_t(c)|0)^1,3406),Ds=mt(s,f)|0,n[s+496>>2]=Ds,Tr=fr(2,Ds)|0,ur=fr(0,Ds)|0,h[s+440>>2]=y(V(s,Tr,B)),h[s+444>>2]=y(re(s,Tr,B)),h[s+428>>2]=y(V(s,ur,B)),h[s+436>>2]=y(re(s,ur,B)),h[s+464>>2]=y(Cr(s,Tr)),h[s+468>>2]=y(yn(s,Tr)),h[s+452>>2]=y(Cr(s,ur)),h[s+460>>2]=y(yn(s,ur)),h[s+488>>2]=y(oi(s,Tr,B)),h[s+492>>2]=y(Mi(s,Tr,B)),h[s+476>>2]=y(oi(s,ur,B)),h[s+484>>2]=y(Mi(s,ur,B));do if(n[s+964>>2]|0)wg(s,l,c,d,m,B,k);else{if(wo=s+948|0,Ws=(n[s+952>>2]|0)-(n[wo>>2]|0)>>2,!Ws){Gv(s,l,c,d,m,B,k);break}if(!Q&&Yv(s,l,c,d,m,B,k)|0)break;$(s),bl=s+508|0,o[bl>>0]=0,Tr=fr(n[s+4>>2]|0,Ds)|0,ur=Cw(Tr,Ds)|0,Jn=he(Tr)|0,Mp=n[s+8>>2]|0,uf=s+28|0,bc=(n[uf>>2]|0)!=0,Co=Jn?B:k,Tc=Jn?k:B,Op=y(Ep(s,Tr,B)),Up=y(ww(s,Tr,B)),Oe=y(Ep(s,ur,B)),Fc=y(En(s,Tr,B)),Ys=y(En(s,ur,B)),or=Jn?d:m,Fl=Jn?m:d,br=Jn?Fc:Ys,at=Jn?Ys:Fc,Qc=y(ln(s,2,B)),Xe=y(ln(s,0,B)),Fe=y(y(Gr(s+364|0,B))-br),et=y(y(Gr(s+380|0,B))-br),Ue=y(y(Gr(s+372|0,k))-at),qe=y(y(Gr(s+388|0,k))-at),Ru=Jn?Fe:Ue,Nu=Jn?et:qe,Qc=y(l-Qc),l=y(Qc-br),_t(l)|0?br=l:br=y(_n(y(Tg(l,et)),Fe)),af=y(c-Xe),l=y(af-at),_t(l)|0?Eo=l:Eo=y(_n(y(Tg(l,qe)),Ue)),Fe=Jn?br:Eo,Tn=Jn?Eo:br;e:do if((or|0)==1)for(f=0,q=0;;){if(M=gs(s,q)|0,!f)y(rs(M))>y(0)&&y(js(M))>y(0)?f=M:f=0;else if(Tm(M)|0){Ge=0;break e}if(q=q+1|0,q>>>0>=Ws>>>0){Ge=f;break}}else Ge=0;while(0);Lt=Ge+500|0,Or=Ge+504|0,f=0,M=0,l=y(0),se=0;do{if(q=n[(n[wo>>2]|0)+(se<<2)>>2]|0,(n[q+36>>2]|0)==1)Bu(q),o[q+985>>0]=1,o[q+984>>0]=0;else{Bl(q),Q&&yp(q,mt(q,Ds)|0,Fe,Tn,br);do if((n[q+24>>2]|0)!=1)if((q|0)==(Ge|0)){n[Lt>>2]=n[2278],h[Or>>2]=y(0);break}else{Rm(s,q,br,d,Eo,br,Eo,m,Ds,O);break}else M|0&&(n[M+960>>2]=q),n[q+960>>2]=0,M=q,f=(f|0)==0?q:f;while(0);vs=y(h[q+504>>2]),l=y(l+y(vs+y(ln(q,Tr,br))))}se=se+1|0}while((se|0)!=(Ws|0));for(mo=l>Fe,Ql=bc&((or|0)==2&mo)?1:or,bn=(Fl|0)==1,ya=bn&(Q^1),Qp=(Ql|0)==1,Fp=(Ql|0)==2,xl=976+(Tr<<2)|0,Tp=(Fl|2|0)==2,Lp=bn&(bc^1),Fu=1040+(ur<<2)|0,Tu=1040+(Tr<<2)|0,Rp=976+(ur<<2)|0,Np=(Fl|0)!=1,mo=bc&((or|0)!=0&mo),go=s+976|0,bn=bn^1,l=Fe,Nr=0,yo=0,vs=y(0),kc=y(0);;){e:do if(Nr>>>0>>0)for(Or=n[wo>>2]|0,se=0,qe=y(0),Ue=y(0),et=y(0),Fe=y(0),q=0,M=0,Ge=Nr;;){if(Lt=n[Or+(Ge<<2)>>2]|0,(n[Lt+36>>2]|0)!=1&&(n[Lt+940>>2]=yo,(n[Lt+24>>2]|0)!=1)){if(Xe=y(ln(Lt,Tr,br)),Xr=n[xl>>2]|0,c=y(Gr(Lt+380+(Xr<<3)|0,Co)),at=y(h[Lt+504>>2]),c=y(Tg(c,at)),c=y(_n(y(Gr(Lt+364+(Xr<<3)|0,Co)),c)),bc&(se|0)!=0&y(Xe+y(Ue+c))>l){m=se,Xe=qe,or=Ge;break e}Xe=y(Xe+c),c=y(Ue+Xe),Xe=y(qe+Xe),Tm(Lt)|0&&(et=y(et+y(rs(Lt))),Fe=y(Fe-y(at*y(js(Lt))))),M|0&&(n[M+960>>2]=Lt),n[Lt+960>>2]=0,se=se+1|0,M=Lt,q=(q|0)==0?Lt:q}else Xe=qe,c=Ue;if(Ge=Ge+1|0,Ge>>>0>>0)qe=Xe,Ue=c;else{m=se,or=Ge;break}}else m=0,Xe=y(0),et=y(0),Fe=y(0),q=0,or=Nr;while(0);Xr=et>y(0)&ety(0)&FeNu&((_t(Nu)|0)^1))l=Nu,Xr=51;else if(o[(n[go>>2]|0)+3>>0]|0)Xr=51;else{if(Xt!=y(0)&&y(rs(s))!=y(0)){Xr=53;break}l=Xe,Xr=53}while(0);if((Xr|0)==51&&(Xr=0,_t(l)|0?Xr=53:(Pr=y(l-Xe),ir=l)),(Xr|0)==53&&(Xr=0,Xe>2]|0,Ge=Pry(0),Ue=y(Pr/Xt),et=y(0),Xe=y(0),l=y(0),M=q;do c=y(Gr(M+380+(se<<3)|0,Co)),Fe=y(Gr(M+364+(se<<3)|0,Co)),Fe=y(Tg(c,y(_n(Fe,y(h[M+504>>2]))))),Ge?(c=y(Fe*y(js(M))),c!=y(-0)&&(Jt=y(Fe-y(at*c)),nf=y(Bi(M,Tr,Jt,ir,br)),Jt!=nf)&&(et=y(et-y(nf-Fe)),l=y(l+c))):Lt&&(Lu=y(rs(M)),Lu!=y(0))&&(Jt=y(Fe+y(Ue*Lu)),sf=y(Bi(M,Tr,Jt,ir,br)),Jt!=sf)&&(et=y(et-y(sf-Fe)),Xe=y(Xe-Lu)),M=n[M+960>>2]|0;while((M|0)!=0);if(l=y(qe+l),Fe=y(Pr+et),rf)l=y(0);else{at=y(Xt+Xe),Ge=n[xl>>2]|0,Lt=Fey(0),at=y(Fe/at),l=y(0);do{Jt=y(Gr(q+380+(Ge<<3)|0,Co)),et=y(Gr(q+364+(Ge<<3)|0,Co)),et=y(Tg(Jt,y(_n(et,y(h[q+504>>2]))))),Lt?(Jt=y(et*y(js(q))),Fe=y(-Jt),Jt!=y(-0)?(Jt=y(Ue*Fe),Fe=y(Bi(q,Tr,y(et+(Or?Fe:Jt)),ir,br))):Fe=et):se&&(of=y(rs(q)),of!=y(0))?Fe=y(Bi(q,Tr,y(et+y(at*of)),ir,br)):Fe=et,l=y(l-y(Fe-et)),Xe=y(ln(q,Tr,br)),c=y(ln(q,ur,br)),Fe=y(Fe+Xe),h[za>>2]=Fe,n[kl>>2]=1,et=y(h[q+396>>2]);e:do if(_t(et)|0){M=_t(Tn)|0;do if(!M){if(mo|(ts(q,ur,Tn)|0|bn)||(ha(s,q)|0)!=4||(n[(vl(q,ur)|0)+4>>2]|0)==3||(n[(Pc(q,ur)|0)+4>>2]|0)==3)break;h[qs>>2]=Tn,n[Wo>>2]=1;break e}while(0);if(ts(q,ur,Tn)|0){M=n[q+992+(n[Rp>>2]<<2)>>2]|0,Jt=y(c+y(Gr(M,Tn))),h[qs>>2]=Jt,M=Np&(n[M+4>>2]|0)==2,n[Wo>>2]=((_t(Jt)|0|M)^1)&1;break}else{h[qs>>2]=Tn,n[Wo>>2]=M?0:2;break}}else Jt=y(Fe-Xe),Xt=y(Jt/et),Jt=y(et*Jt),n[Wo>>2]=1,h[qs>>2]=y(c+(Jn?Xt:Jt));while(0);yr(q,Tr,ir,br,kl,za),yr(q,ur,Tn,br,Wo,qs);do if(!(ts(q,ur,Tn)|0)&&(ha(s,q)|0)==4){if((n[(vl(q,ur)|0)+4>>2]|0)==3){M=0;break}M=(n[(Pc(q,ur)|0)+4>>2]|0)!=3}else M=0;while(0);Jt=y(h[za>>2]),Xt=y(h[qs>>2]),pf=n[kl>>2]|0,li=n[Wo>>2]|0,fa(q,Jn?Jt:Xt,Jn?Xt:Jt,Ds,Jn?pf:li,Jn?li:pf,br,Eo,Q&(M^1),3488,O)|0,o[bl>>0]=o[bl>>0]|o[q+508>>0],q=n[q+960>>2]|0}while((q|0)!=0)}}else l=y(0);if(l=y(Pr+l),li=l>0]=li|u[bl>>0],Fp&l>y(0)?(M=n[xl>>2]|0,(n[s+364+(M<<3)+4>>2]|0)!=0&&(Gs=y(Gr(s+364+(M<<3)|0,Co)),Gs>=y(0))?Fe=y(_n(y(0),y(Gs-y(ir-l)))):Fe=y(0)):Fe=l,Lt=Nr>>>0>>0,Lt){Ge=n[wo>>2]|0,se=Nr,M=0;do q=n[Ge+(se<<2)>>2]|0,n[q+24>>2]|0||(M=((n[(vl(q,Tr)|0)+4>>2]|0)==3&1)+M|0,M=M+((n[(Pc(q,Tr)|0)+4>>2]|0)==3&1)|0),se=se+1|0;while((se|0)!=(or|0));M?(Xe=y(0),c=y(0)):Xr=101}else Xr=101;e:do if((Xr|0)==101)switch(Xr=0,Mp|0){case 1:{M=0,Xe=y(Fe*y(.5)),c=y(0);break e}case 2:{M=0,Xe=Fe,c=y(0);break e}case 3:{if(m>>>0<=1){M=0,Xe=y(0),c=y(0);break e}c=y((m+-1|0)>>>0),M=0,Xe=y(0),c=y(y(_n(Fe,y(0)))/c);break e}case 5:{c=y(Fe/y((m+1|0)>>>0)),M=0,Xe=c;break e}case 4:{c=y(Fe/y(m>>>0)),M=0,Xe=y(c*y(.5));break e}default:{M=0,Xe=y(0),c=y(0);break e}}while(0);if(l=y(Op+Xe),Lt){et=y(Fe/y(M|0)),se=n[wo>>2]|0,q=Nr,Fe=y(0);do{M=n[se+(q<<2)>>2]|0;e:do if((n[M+36>>2]|0)!=1){switch(n[M+24>>2]|0){case 1:{if(gi(M,Tr)|0){if(!Q)break e;Jt=y(Mr(M,Tr,ir)),Jt=y(Jt+y(Cr(s,Tr))),Jt=y(Jt+y(V(M,Tr,br))),h[M+400+(n[Tu>>2]<<2)>>2]=Jt;break e}break}case 0:if(li=(n[(vl(M,Tr)|0)+4>>2]|0)==3,Jt=y(et+l),l=li?Jt:l,Q&&(li=M+400+(n[Tu>>2]<<2)|0,h[li>>2]=y(l+y(h[li>>2]))),li=(n[(Pc(M,Tr)|0)+4>>2]|0)==3,Jt=y(et+l),l=li?Jt:l,ya){Jt=y(c+y(ln(M,Tr,br))),Fe=Tn,l=y(l+y(Jt+y(h[M+504>>2])));break e}else{l=y(l+y(c+y(ns(M,Tr,br)))),Fe=y(_n(Fe,y(ns(M,ur,br))));break e}default:}Q&&(Jt=y(Xe+y(Cr(s,Tr))),li=M+400+(n[Tu>>2]<<2)|0,h[li>>2]=y(Jt+y(h[li>>2])))}while(0);q=q+1|0}while((q|0)!=(or|0))}else Fe=y(0);if(c=y(Up+l),Tp?Xe=y(y(Bi(s,ur,y(Ys+Fe),Tc,B))-Ys):Xe=Tn,et=y(y(Bi(s,ur,y(Ys+(Lp?Tn:Fe)),Tc,B))-Ys),Lt&Q){q=Nr;do{se=n[(n[wo>>2]|0)+(q<<2)>>2]|0;do if((n[se+36>>2]|0)!=1){if((n[se+24>>2]|0)==1){if(gi(se,ur)|0){if(Jt=y(Mr(se,ur,Tn)),Jt=y(Jt+y(Cr(s,ur))),Jt=y(Jt+y(V(se,ur,br))),M=n[Fu>>2]|0,h[se+400+(M<<2)>>2]=Jt,!(_t(Jt)|0))break}else M=n[Fu>>2]|0;Jt=y(Cr(s,ur)),h[se+400+(M<<2)>>2]=y(Jt+y(V(se,ur,br)));break}M=ha(s,se)|0;do if((M|0)==4){if((n[(vl(se,ur)|0)+4>>2]|0)==3){Xr=139;break}if((n[(Pc(se,ur)|0)+4>>2]|0)==3){Xr=139;break}if(ts(se,ur,Tn)|0){l=Oe;break}pf=n[se+908+(n[xl>>2]<<2)>>2]|0,n[qs>>2]=pf,l=y(h[se+396>>2]),li=_t(l)|0,Fe=(n[v>>2]=pf,y(h[v>>2])),li?l=et:(Pr=y(ln(se,ur,br)),Jt=y(Fe/l),l=y(l*Fe),l=y(Pr+(Jn?Jt:l))),h[za>>2]=l,h[qs>>2]=y(y(ln(se,Tr,br))+Fe),n[Wo>>2]=1,n[kl>>2]=1,yr(se,Tr,ir,br,Wo,qs),yr(se,ur,Tn,br,kl,za),l=y(h[qs>>2]),Pr=y(h[za>>2]),Jt=Jn?l:Pr,l=Jn?Pr:l,li=((_t(Jt)|0)^1)&1,fa(se,Jt,l,Ds,li,((_t(l)|0)^1)&1,br,Eo,1,3493,O)|0,l=Oe}else Xr=139;while(0);e:do if((Xr|0)==139){Xr=0,l=y(Xe-y(ns(se,ur,br)));do if((n[(vl(se,ur)|0)+4>>2]|0)==3){if((n[(Pc(se,ur)|0)+4>>2]|0)!=3)break;l=y(Oe+y(_n(y(0),y(l*y(.5)))));break e}while(0);if((n[(Pc(se,ur)|0)+4>>2]|0)==3){l=Oe;break}if((n[(vl(se,ur)|0)+4>>2]|0)==3){l=y(Oe+y(_n(y(0),l)));break}switch(M|0){case 1:{l=Oe;break e}case 2:{l=y(Oe+y(l*y(.5)));break e}default:{l=y(Oe+l);break e}}}while(0);Jt=y(vs+l),li=se+400+(n[Fu>>2]<<2)|0,h[li>>2]=y(Jt+y(h[li>>2]))}while(0);q=q+1|0}while((q|0)!=(or|0))}if(vs=y(vs+et),kc=y(_n(kc,c)),m=yo+1|0,or>>>0>=Ws>>>0)break;l=ir,Nr=or,yo=m}do if(Q){if(M=m>>>0>1,!M&&!(Yi(s)|0))break;if(!(_t(Tn)|0)){l=y(Tn-vs);e:do switch(n[s+12>>2]|0){case 3:{Oe=y(Oe+l),Ue=y(0);break}case 2:{Oe=y(Oe+y(l*y(.5))),Ue=y(0);break}case 4:{Tn>vs?Ue=y(l/y(m>>>0)):Ue=y(0);break}case 7:if(Tn>vs){Oe=y(Oe+y(l/y(m<<1>>>0))),Ue=y(l/y(m>>>0)),Ue=M?Ue:y(0);break e}else{Oe=y(Oe+y(l*y(.5))),Ue=y(0);break e}case 6:{Ue=y(l/y(yo>>>0)),Ue=Tn>vs&M?Ue:y(0);break}default:Ue=y(0)}while(0);if(m|0)for(Lt=1040+(ur<<2)|0,Or=976+(ur<<2)|0,Ge=0,q=0;;){e:do if(q>>>0>>0)for(Fe=y(0),et=y(0),l=y(0),se=q;;){M=n[(n[wo>>2]|0)+(se<<2)>>2]|0;do if((n[M+36>>2]|0)!=1&&(n[M+24>>2]|0)==0){if((n[M+940>>2]|0)!=(Ge|0))break e;if(Nm(M,ur)|0&&(Jt=y(h[M+908+(n[Or>>2]<<2)>>2]),l=y(_n(l,y(Jt+y(ln(M,ur,br)))))),(ha(s,M)|0)!=5)break;Gs=y(Ya(M)),Gs=y(Gs+y(V(M,0,br))),Jt=y(h[M+912>>2]),Jt=y(y(Jt+y(ln(M,0,br)))-Gs),Gs=y(_n(et,Gs)),Jt=y(_n(Fe,Jt)),Fe=Jt,et=Gs,l=y(_n(l,y(Gs+Jt)))}while(0);if(M=se+1|0,M>>>0>>0)se=M;else{se=M;break}}else et=y(0),l=y(0),se=q;while(0);if(at=y(Ue+l),c=Oe,Oe=y(Oe+at),q>>>0>>0){Xe=y(c+et),M=q;do{q=n[(n[wo>>2]|0)+(M<<2)>>2]|0;e:do if((n[q+36>>2]|0)!=1&&(n[q+24>>2]|0)==0)switch(ha(s,q)|0){case 1:{Jt=y(c+y(V(q,ur,br))),h[q+400+(n[Lt>>2]<<2)>>2]=Jt;break e}case 3:{Jt=y(y(Oe-y(re(q,ur,br)))-y(h[q+908+(n[Or>>2]<<2)>>2])),h[q+400+(n[Lt>>2]<<2)>>2]=Jt;break e}case 2:{Jt=y(c+y(y(at-y(h[q+908+(n[Or>>2]<<2)>>2]))*y(.5))),h[q+400+(n[Lt>>2]<<2)>>2]=Jt;break e}case 4:{if(Jt=y(c+y(V(q,ur,br))),h[q+400+(n[Lt>>2]<<2)>>2]=Jt,ts(q,ur,Tn)|0||(Jn?(Fe=y(h[q+908>>2]),l=y(Fe+y(ln(q,Tr,br))),et=at):(et=y(h[q+912>>2]),et=y(et+y(ln(q,ur,br))),l=at,Fe=y(h[q+908>>2])),Ii(l,Fe)|0&&Ii(et,y(h[q+912>>2]))|0))break e;fa(q,l,et,Ds,1,1,br,Eo,1,3501,O)|0;break e}case 5:{h[q+404>>2]=y(y(Xe-y(Ya(q)))+y(Mr(q,0,Tn)));break e}default:break e}while(0);M=M+1|0}while((M|0)!=(se|0))}if(Ge=Ge+1|0,(Ge|0)==(m|0))break;q=se}}}while(0);if(h[s+908>>2]=y(Bi(s,2,Qc,B,B)),h[s+912>>2]=y(Bi(s,0,af,k,B)),(Ql|0)!=0&&(lf=n[s+32>>2]|0,cf=(Ql|0)==2,!(cf&(lf|0)!=2))?cf&(lf|0)==2&&(l=y(Fc+ir),l=y(_n(y(Tg(l,y(MA(s,Tr,kc,Co)))),Fc)),Xr=198):(l=y(Bi(s,Tr,kc,Co,B)),Xr=198),(Xr|0)==198&&(h[s+908+(n[976+(Tr<<2)>>2]<<2)>>2]=l),(Fl|0)!=0&&(Af=n[s+32>>2]|0,ff=(Fl|0)==2,!(ff&(Af|0)!=2))?ff&(Af|0)==2&&(l=y(Ys+Tn),l=y(_n(y(Tg(l,y(MA(s,ur,y(Ys+vs),Tc)))),Ys)),Xr=204):(l=y(Bi(s,ur,y(Ys+vs),Tc,B)),Xr=204),(Xr|0)==204&&(h[s+908+(n[976+(ur<<2)>>2]<<2)>>2]=l),Q){if((n[uf>>2]|0)==2){q=976+(ur<<2)|0,se=1040+(ur<<2)|0,M=0;do Ge=gs(s,M)|0,n[Ge+24>>2]|0||(pf=n[q>>2]|0,Jt=y(h[s+908+(pf<<2)>>2]),li=Ge+400+(n[se>>2]<<2)|0,Jt=y(Jt-y(h[li>>2])),h[li>>2]=y(Jt-y(h[Ge+908+(pf<<2)>>2]))),M=M+1|0;while((M|0)!=(Ws|0))}if(f|0){M=Jn?Ql:d;do Lm(s,f,br,M,Eo,Ds,O),f=n[f+960>>2]|0;while((f|0)!=0)}if(M=(Tr|2|0)==3,q=(ur|2|0)==3,M|q){f=0;do se=n[(n[wo>>2]|0)+(f<<2)>>2]|0,(n[se+36>>2]|0)!=1&&(M&&Cp(s,se,Tr),q&&Cp(s,se,ur)),f=f+1|0;while((f|0)!=(Ws|0))}}}while(0);C=Tl}function pa(s,l){s=s|0,l=y(l);var c=0;oa(s,l>=y(0),3147),c=l==y(0),h[s+4>>2]=c?y(0):l}function vc(s,l,c,f){s=s|0,l=y(l),c=y(c),f=f|0;var d=Ze,m=Ze,B=0,k=0,Q=0;n[2278]=(n[2278]|0)+1,Bl(s),ts(s,2,l)|0?(d=y(Gr(n[s+992>>2]|0,l)),Q=1,d=y(d+y(ln(s,2,l)))):(d=y(Gr(s+380|0,l)),d>=y(0)?Q=2:(Q=((_t(l)|0)^1)&1,d=l)),ts(s,0,c)|0?(m=y(Gr(n[s+996>>2]|0,c)),k=1,m=y(m+y(ln(s,0,l)))):(m=y(Gr(s+388|0,c)),m>=y(0)?k=2:(k=((_t(c)|0)^1)&1,m=c)),B=s+976|0,fa(s,d,m,f,Q,k,l,c,1,3189,n[B>>2]|0)|0&&(yp(s,n[s+496>>2]|0,l,c,l),Dc(s,y(h[(n[B>>2]|0)+4>>2]),y(0),y(0)),o[11696]|0)&&km(s,7)}function Bl(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0;k=C,C=C+32|0,B=k+24|0,m=k+16|0,f=k+8|0,d=k,c=0;do l=s+380+(c<<3)|0,(n[s+380+(c<<3)+4>>2]|0)!=0&&(Q=l,O=n[Q+4>>2]|0,M=f,n[M>>2]=n[Q>>2],n[M+4>>2]=O,M=s+364+(c<<3)|0,O=n[M+4>>2]|0,Q=d,n[Q>>2]=n[M>>2],n[Q+4>>2]=O,n[m>>2]=n[f>>2],n[m+4>>2]=n[f+4>>2],n[B>>2]=n[d>>2],n[B+4>>2]=n[d+4>>2],ws(m,B)|0)||(l=s+348+(c<<3)|0),n[s+992+(c<<2)>>2]=l,c=c+1|0;while((c|0)!=2);C=k}function ts(s,l,c){s=s|0,l=l|0,c=y(c);var f=0;switch(s=n[s+992+(n[976+(l<<2)>>2]<<2)>>2]|0,n[s+4>>2]|0){case 0:case 3:{s=0;break}case 1:{y(h[s>>2])>2])>2]|0){case 2:{l=y(y(y(h[s>>2])*l)/y(100));break}case 1:{l=y(h[s>>2]);break}default:l=y(Ae)}return y(l)}function yp(s,l,c,f,d){s=s|0,l=l|0,c=y(c),f=y(f),d=y(d);var m=0,B=Ze;l=n[s+944>>2]|0?l:1,m=fr(n[s+4>>2]|0,l)|0,l=Cw(m,l)|0,c=y(Mm(s,m,c)),f=y(Mm(s,l,f)),B=y(c+y(V(s,m,d))),h[s+400+(n[1040+(m<<2)>>2]<<2)>>2]=B,c=y(c+y(re(s,m,d))),h[s+400+(n[1e3+(m<<2)>>2]<<2)>>2]=c,c=y(f+y(V(s,l,d))),h[s+400+(n[1040+(l<<2)>>2]<<2)>>2]=c,d=y(f+y(re(s,l,d))),h[s+400+(n[1e3+(l<<2)>>2]<<2)>>2]=d}function Dc(s,l,c,f){s=s|0,l=y(l),c=y(c),f=y(f);var d=0,m=0,B=Ze,k=Ze,Q=0,O=0,M=Ze,q=0,se=Ze,Ge=Ze,Oe=Ze,Fe=Ze;if(l!=y(0)&&(d=s+400|0,Fe=y(h[d>>2]),m=s+404|0,Oe=y(h[m>>2]),q=s+416|0,Ge=y(h[q>>2]),O=s+420|0,B=y(h[O>>2]),se=y(Fe+c),M=y(Oe+f),f=y(se+Ge),k=y(M+B),Q=(n[s+988>>2]|0)==1,h[d>>2]=y(Go(Fe,l,0,Q)),h[m>>2]=y(Go(Oe,l,0,Q)),c=y(kT(y(Ge*l),y(1))),Ii(c,y(0))|0?m=0:m=(Ii(c,y(1))|0)^1,c=y(kT(y(B*l),y(1))),Ii(c,y(0))|0?d=0:d=(Ii(c,y(1))|0)^1,Fe=y(Go(f,l,Q&m,Q&(m^1))),h[q>>2]=y(Fe-y(Go(se,l,0,Q))),Fe=y(Go(k,l,Q&d,Q&(d^1))),h[O>>2]=y(Fe-y(Go(M,l,0,Q))),m=(n[s+952>>2]|0)-(n[s+948>>2]|0)>>2,m|0)){d=0;do Dc(gs(s,d)|0,l,se,M),d=d+1|0;while((d|0)!=(m|0))}}function Ew(s,l,c,f,d){switch(s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,c|0){case 5:case 0:{s=a7(n[489]|0,f,d)|0;break}default:s=t3e(f,d)|0}return s|0}function yg(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;d=C,C=C+16|0,m=d,n[m>>2]=f,Eg(s,0,l,c,m),C=d}function Eg(s,l,c,f,d){if(s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,s=s|0?s:956,x7[n[s+8>>2]&1](s,l,c,f,d)|0,(c|0)==5)Tt();else return}function Ga(s,l,c){s=s|0,l=l|0,c=c|0,o[s+l>>0]=c&1}function Fm(s,l){s=s|0,l=l|0;var c=0,f=0;n[s>>2]=0,n[s+4>>2]=0,n[s+8>>2]=0,c=l+4|0,f=(n[c>>2]|0)-(n[l>>2]|0)>>2,f|0&&(Cg(s,f),Qt(s,n[l>>2]|0,n[c>>2]|0,f))}function Cg(s,l){s=s|0,l=l|0;var c=0;if((N(s)|0)>>>0>>0&&zr(s),l>>>0>1073741823)Tt();else{c=Vt(l<<2)|0,n[s+4>>2]=c,n[s>>2]=c,n[s+8>>2]=c+(l<<2);return}}function Qt(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,f=s+4|0,s=c-l|0,(s|0)>0&&(Dr(n[f>>2]|0,l|0,s|0)|0,n[f>>2]=(n[f>>2]|0)+(s>>>2<<2))}function N(s){return s=s|0,1073741823}function V(s,l,c){return s=s|0,l=l|0,c=y(c),he(l)|0&&(n[s+96>>2]|0)!=0?s=s+92|0:s=Fn(s+60|0,n[1040+(l<<2)>>2]|0,992)|0,y(ze(s,c))}function re(s,l,c){return s=s|0,l=l|0,c=y(c),he(l)|0&&(n[s+104>>2]|0)!=0?s=s+100|0:s=Fn(s+60|0,n[1e3+(l<<2)>>2]|0,992)|0,y(ze(s,c))}function he(s){return s=s|0,(s|1|0)==3|0}function ze(s,l){return s=s|0,l=y(l),(n[s+4>>2]|0)==3?l=y(0):l=y(Gr(s,l)),y(l)}function mt(s,l){return s=s|0,l=l|0,s=n[s>>2]|0,((s|0)==0?(l|0)>1?l:1:s)|0}function fr(s,l){s=s|0,l=l|0;var c=0;e:do if((l|0)==2){switch(s|0){case 2:{s=3;break e}case 3:break;default:{c=4;break e}}s=2}else c=4;while(0);return s|0}function Cr(s,l){s=s|0,l=l|0;var c=Ze;return he(l)|0&&(n[s+312>>2]|0)!=0&&(c=y(h[s+308>>2]),c>=y(0))||(c=y(_n(y(h[(Fn(s+276|0,n[1040+(l<<2)>>2]|0,992)|0)>>2]),y(0)))),y(c)}function yn(s,l){s=s|0,l=l|0;var c=Ze;return he(l)|0&&(n[s+320>>2]|0)!=0&&(c=y(h[s+316>>2]),c>=y(0))||(c=y(_n(y(h[(Fn(s+276|0,n[1e3+(l<<2)>>2]|0,992)|0)>>2]),y(0)))),y(c)}function oi(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return he(l)|0&&(n[s+240>>2]|0)!=0&&(f=y(Gr(s+236|0,c)),f>=y(0))||(f=y(_n(y(Gr(Fn(s+204|0,n[1040+(l<<2)>>2]|0,992)|0,c)),y(0)))),y(f)}function Mi(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return he(l)|0&&(n[s+248>>2]|0)!=0&&(f=y(Gr(s+244|0,c)),f>=y(0))||(f=y(_n(y(Gr(Fn(s+204|0,n[1e3+(l<<2)>>2]|0,992)|0,c)),y(0)))),y(f)}function wg(s,l,c,f,d,m,B){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=y(m),B=y(B);var k=Ze,Q=Ze,O=Ze,M=Ze,q=Ze,se=Ze,Ge=0,Oe=0,Fe=0;Fe=C,C=C+16|0,Ge=Fe,Oe=s+964|0,Un(s,(n[Oe>>2]|0)!=0,3519),k=y(En(s,2,l)),Q=y(En(s,0,l)),O=y(ln(s,2,l)),M=y(ln(s,0,l)),_t(l)|0?q=l:q=y(_n(y(0),y(y(l-O)-k))),_t(c)|0?se=c:se=y(_n(y(0),y(y(c-M)-Q))),(f|0)==1&(d|0)==1?(h[s+908>>2]=y(Bi(s,2,y(l-O),m,m)),l=y(Bi(s,0,y(c-M),B,m))):(b7[n[Oe>>2]&1](Ge,s,q,f,se,d),q=y(k+y(h[Ge>>2])),se=y(l-O),h[s+908>>2]=y(Bi(s,2,(f|2|0)==2?q:se,m,m)),se=y(Q+y(h[Ge+4>>2])),l=y(c-M),l=y(Bi(s,0,(d|2|0)==2?se:l,B,m))),h[s+912>>2]=l,C=Fe}function Gv(s,l,c,f,d,m,B){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=y(m),B=y(B);var k=Ze,Q=Ze,O=Ze,M=Ze;O=y(En(s,2,m)),k=y(En(s,0,m)),M=y(ln(s,2,m)),Q=y(ln(s,0,m)),l=y(l-M),h[s+908>>2]=y(Bi(s,2,(f|2|0)==2?O:l,m,m)),c=y(c-Q),h[s+912>>2]=y(Bi(s,0,(d|2|0)==2?k:c,B,m))}function Yv(s,l,c,f,d,m,B){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=y(m),B=y(B);var k=0,Q=Ze,O=Ze;return k=(f|0)==2,!(l<=y(0)&k)&&!(c<=y(0)&(d|0)==2)&&!((f|0)==1&(d|0)==1)?s=0:(Q=y(ln(s,0,m)),O=y(ln(s,2,m)),k=l>2]=y(Bi(s,2,k?y(0):l,m,m)),l=y(c-Q),k=c>2]=y(Bi(s,0,k?y(0):l,B,m)),s=1),s|0}function Cw(s,l){return s=s|0,l=l|0,OA(s)|0?s=fr(2,l)|0:s=0,s|0}function Ep(s,l,c){return s=s|0,l=l|0,c=y(c),c=y(oi(s,l,c)),y(c+y(Cr(s,l)))}function ww(s,l,c){return s=s|0,l=l|0,c=y(c),c=y(Mi(s,l,c)),y(c+y(yn(s,l)))}function En(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return f=y(Ep(s,l,c)),y(f+y(ww(s,l,c)))}function Tm(s){return s=s|0,n[s+24>>2]|0?s=0:y(rs(s))!=y(0)?s=1:s=y(js(s))!=y(0),s|0}function rs(s){s=s|0;var l=Ze;if(n[s+944>>2]|0){if(l=y(h[s+44>>2]),_t(l)|0)return l=y(h[s+40>>2]),s=l>y(0)&((_t(l)|0)^1),y(s?l:y(0))}else l=y(0);return y(l)}function js(s){s=s|0;var l=Ze,c=0,f=Ze;do if(n[s+944>>2]|0){if(l=y(h[s+48>>2]),_t(l)|0){if(c=o[(n[s+976>>2]|0)+2>>0]|0,c<<24>>24==0&&(f=y(h[s+40>>2]),f>24?y(1):y(0)}}else l=y(0);while(0);return y(l)}function Bu(s){s=s|0;var l=0,c=0;if(zm(s+400|0,0,540)|0,o[s+985>>0]=1,$(s),c=wi(s)|0,c|0){l=s+948|0,s=0;do Bu(n[(n[l>>2]|0)+(s<<2)>>2]|0),s=s+1|0;while((s|0)!=(c|0))}}function Rm(s,l,c,f,d,m,B,k,Q,O){s=s|0,l=l|0,c=y(c),f=f|0,d=y(d),m=y(m),B=y(B),k=k|0,Q=Q|0,O=O|0;var M=0,q=Ze,se=0,Ge=0,Oe=Ze,Fe=Ze,et=0,Xe=Ze,at=0,Ue=Ze,qe=0,Lt=0,Or=0,or=0,Xt=0,Pr=0,Nr=0,ir=0,bn=0,go=0;bn=C,C=C+16|0,Or=bn+12|0,or=bn+8|0,Xt=bn+4|0,Pr=bn,ir=fr(n[s+4>>2]|0,Q)|0,qe=he(ir)|0,q=y(Gr(Iw(l)|0,qe?m:B)),Lt=ts(l,2,m)|0,Nr=ts(l,0,B)|0;do if(!(_t(q)|0)&&!(_t(qe?c:d)|0)){if(M=l+504|0,!(_t(y(h[M>>2]))|0)&&(!(Bw(n[l+976>>2]|0,0)|0)||(n[l+500>>2]|0)==(n[2278]|0)))break;h[M>>2]=y(_n(q,y(En(l,ir,m))))}else se=7;while(0);do if((se|0)==7){if(at=qe^1,!(at|Lt^1)){B=y(Gr(n[l+992>>2]|0,m)),h[l+504>>2]=y(_n(B,y(En(l,2,m))));break}if(!(qe|Nr^1)){B=y(Gr(n[l+996>>2]|0,B)),h[l+504>>2]=y(_n(B,y(En(l,0,m))));break}h[Or>>2]=y(Ae),h[or>>2]=y(Ae),n[Xt>>2]=0,n[Pr>>2]=0,Xe=y(ln(l,2,m)),Ue=y(ln(l,0,m)),Lt?(Oe=y(Xe+y(Gr(n[l+992>>2]|0,m))),h[Or>>2]=Oe,n[Xt>>2]=1,Ge=1):(Ge=0,Oe=y(Ae)),Nr?(q=y(Ue+y(Gr(n[l+996>>2]|0,B))),h[or>>2]=q,n[Pr>>2]=1,M=1):(M=0,q=y(Ae)),se=n[s+32>>2]|0,qe&(se|0)==2?se=2:_t(Oe)|0&&!(_t(c)|0)&&(h[Or>>2]=c,n[Xt>>2]=2,Ge=2,Oe=c),!((se|0)==2&at)&&_t(q)|0&&!(_t(d)|0)&&(h[or>>2]=d,n[Pr>>2]=2,M=2,q=d),Fe=y(h[l+396>>2]),et=_t(Fe)|0;do if(et)se=Ge;else{if((Ge|0)==1&at){h[or>>2]=y(y(Oe-Xe)/Fe),n[Pr>>2]=1,M=1,se=1;break}qe&(M|0)==1?(h[Or>>2]=y(Fe*y(q-Ue)),n[Xt>>2]=1,M=1,se=1):se=Ge}while(0);go=_t(c)|0,Ge=(ha(s,l)|0)!=4,!(qe|Lt|((f|0)!=1|go)|(Ge|(se|0)==1))&&(h[Or>>2]=c,n[Xt>>2]=1,!et)&&(h[or>>2]=y(y(c-Xe)/Fe),n[Pr>>2]=1,M=1),!(Nr|at|((k|0)!=1|(_t(d)|0))|(Ge|(M|0)==1))&&(h[or>>2]=d,n[Pr>>2]=1,!et)&&(h[Or>>2]=y(Fe*y(d-Ue)),n[Xt>>2]=1),yr(l,2,m,m,Xt,Or),yr(l,0,B,m,Pr,or),c=y(h[Or>>2]),d=y(h[or>>2]),fa(l,c,d,Q,n[Xt>>2]|0,n[Pr>>2]|0,m,B,0,3565,O)|0,B=y(h[l+908+(n[976+(ir<<2)>>2]<<2)>>2]),h[l+504>>2]=y(_n(B,y(En(l,ir,m))))}while(0);n[l+500>>2]=n[2278],C=bn}function Bi(s,l,c,f,d){return s=s|0,l=l|0,c=y(c),f=y(f),d=y(d),f=y(MA(s,l,c,f)),y(_n(f,y(En(s,l,d))))}function ha(s,l){return s=s|0,l=l|0,l=l+20|0,l=n[((n[l>>2]|0)==0?s+16|0:l)>>2]|0,(l|0)==5&&OA(n[s+4>>2]|0)|0&&(l=1),l|0}function vl(s,l){return s=s|0,l=l|0,he(l)|0&&(n[s+96>>2]|0)!=0?l=4:l=n[1040+(l<<2)>>2]|0,s+60+(l<<3)|0}function Pc(s,l){return s=s|0,l=l|0,he(l)|0&&(n[s+104>>2]|0)!=0?l=5:l=n[1e3+(l<<2)>>2]|0,s+60+(l<<3)|0}function yr(s,l,c,f,d,m){switch(s=s|0,l=l|0,c=y(c),f=y(f),d=d|0,m=m|0,c=y(Gr(s+380+(n[976+(l<<2)>>2]<<3)|0,c)),c=y(c+y(ln(s,l,f))),n[d>>2]|0){case 2:case 1:{d=_t(c)|0,f=y(h[m>>2]),h[m>>2]=d|f>2]=2,h[m>>2]=c);break}default:}}function gi(s,l){return s=s|0,l=l|0,s=s+132|0,he(l)|0&&(n[(Fn(s,4,948)|0)+4>>2]|0)!=0?s=1:s=(n[(Fn(s,n[1040+(l<<2)>>2]|0,948)|0)+4>>2]|0)!=0,s|0}function Mr(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0;return s=s+132|0,he(l)|0&&(f=Fn(s,4,948)|0,(n[f+4>>2]|0)!=0)?d=4:(f=Fn(s,n[1040+(l<<2)>>2]|0,948)|0,n[f+4>>2]|0?d=4:c=y(0)),(d|0)==4&&(c=y(Gr(f,c))),y(c)}function ns(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return f=y(h[s+908+(n[976+(l<<2)>>2]<<2)>>2]),f=y(f+y(V(s,l,c))),y(f+y(re(s,l,c)))}function Yi(s){s=s|0;var l=0,c=0,f=0;e:do if(OA(n[s+4>>2]|0)|0)l=0;else if((n[s+16>>2]|0)!=5)if(c=wi(s)|0,!c)l=0;else for(l=0;;){if(f=gs(s,l)|0,(n[f+24>>2]|0)==0&&(n[f+20>>2]|0)==5){l=1;break e}if(l=l+1|0,l>>>0>=c>>>0){l=0;break}}else l=1;while(0);return l|0}function Nm(s,l){s=s|0,l=l|0;var c=Ze;return c=y(h[s+908+(n[976+(l<<2)>>2]<<2)>>2]),c>=y(0)&((_t(c)|0)^1)|0}function Ya(s){s=s|0;var l=Ze,c=0,f=0,d=0,m=0,B=0,k=0,Q=Ze;if(c=n[s+968>>2]|0,c)Q=y(h[s+908>>2]),l=y(h[s+912>>2]),l=y(v7[c&0](s,Q,l)),Un(s,(_t(l)|0)^1,3573);else{m=wi(s)|0;do if(m|0){for(c=0,d=0;;){if(f=gs(s,d)|0,n[f+940>>2]|0){B=8;break}if((n[f+24>>2]|0)!=1)if(k=(ha(s,f)|0)==5,k){c=f;break}else c=(c|0)==0?f:c;if(d=d+1|0,d>>>0>=m>>>0){B=8;break}}if((B|0)==8&&!c)break;return l=y(Ya(c)),y(l+y(h[c+404>>2]))}while(0);l=y(h[s+912>>2])}return y(l)}function MA(s,l,c,f){s=s|0,l=l|0,c=y(c),f=y(f);var d=Ze,m=0;return OA(l)|0?(l=1,m=3):he(l)|0?(l=0,m=3):(f=y(Ae),d=y(Ae)),(m|0)==3&&(d=y(Gr(s+364+(l<<3)|0,f)),f=y(Gr(s+380+(l<<3)|0,f))),m=f=y(0)&((_t(f)|0)^1)),c=m?f:c,m=d>=y(0)&((_t(d)|0)^1)&c>2]|0,m)|0,Oe=Cw(et,m)|0,Fe=he(et)|0,q=y(ln(l,2,c)),se=y(ln(l,0,c)),ts(l,2,c)|0?k=y(q+y(Gr(n[l+992>>2]|0,c))):gi(l,2)|0&&sr(l,2)|0?(k=y(h[s+908>>2]),Q=y(Cr(s,2)),Q=y(k-y(Q+y(yn(s,2)))),k=y(Mr(l,2,c)),k=y(Bi(l,2,y(Q-y(k+y(vu(l,2,c)))),c,c))):k=y(Ae),ts(l,0,d)|0?Q=y(se+y(Gr(n[l+996>>2]|0,d))):gi(l,0)|0&&sr(l,0)|0?(Q=y(h[s+912>>2]),at=y(Cr(s,0)),at=y(Q-y(at+y(yn(s,0)))),Q=y(Mr(l,0,d)),Q=y(Bi(l,0,y(at-y(Q+y(vu(l,0,d)))),d,c))):Q=y(Ae),O=_t(k)|0,M=_t(Q)|0;do if(O^M&&(Ge=y(h[l+396>>2]),!(_t(Ge)|0)))if(O){k=y(q+y(y(Q-se)*Ge));break}else{at=y(se+y(y(k-q)/Ge)),Q=M?at:Q;break}while(0);M=_t(k)|0,O=_t(Q)|0,M|O&&(Ue=(M^1)&1,f=c>y(0)&((f|0)!=0&M),k=Fe?k:f?c:k,fa(l,k,Q,m,Fe?Ue:f?2:Ue,M&(O^1)&1,k,Q,0,3623,B)|0,k=y(h[l+908>>2]),k=y(k+y(ln(l,2,c))),Q=y(h[l+912>>2]),Q=y(Q+y(ln(l,0,c)))),fa(l,k,Q,m,1,1,k,Q,1,3635,B)|0,sr(l,et)|0&&!(gi(l,et)|0)?(Ue=n[976+(et<<2)>>2]|0,at=y(h[s+908+(Ue<<2)>>2]),at=y(at-y(h[l+908+(Ue<<2)>>2])),at=y(at-y(yn(s,et))),at=y(at-y(re(l,et,c))),at=y(at-y(vu(l,et,Fe?c:d))),h[l+400+(n[1040+(et<<2)>>2]<<2)>>2]=at):Xe=21;do if((Xe|0)==21){if(!(gi(l,et)|0)&&(n[s+8>>2]|0)==1){Ue=n[976+(et<<2)>>2]|0,at=y(h[s+908+(Ue<<2)>>2]),at=y(y(at-y(h[l+908+(Ue<<2)>>2]))*y(.5)),h[l+400+(n[1040+(et<<2)>>2]<<2)>>2]=at;break}!(gi(l,et)|0)&&(n[s+8>>2]|0)==2&&(Ue=n[976+(et<<2)>>2]|0,at=y(h[s+908+(Ue<<2)>>2]),at=y(at-y(h[l+908+(Ue<<2)>>2])),h[l+400+(n[1040+(et<<2)>>2]<<2)>>2]=at)}while(0);sr(l,Oe)|0&&!(gi(l,Oe)|0)?(Ue=n[976+(Oe<<2)>>2]|0,at=y(h[s+908+(Ue<<2)>>2]),at=y(at-y(h[l+908+(Ue<<2)>>2])),at=y(at-y(yn(s,Oe))),at=y(at-y(re(l,Oe,c))),at=y(at-y(vu(l,Oe,Fe?d:c))),h[l+400+(n[1040+(Oe<<2)>>2]<<2)>>2]=at):Xe=30;do if((Xe|0)==30&&!(gi(l,Oe)|0)){if((ha(s,l)|0)==2){Ue=n[976+(Oe<<2)>>2]|0,at=y(h[s+908+(Ue<<2)>>2]),at=y(y(at-y(h[l+908+(Ue<<2)>>2]))*y(.5)),h[l+400+(n[1040+(Oe<<2)>>2]<<2)>>2]=at;break}Ue=(ha(s,l)|0)==3,Ue^(n[s+28>>2]|0)==2&&(Ue=n[976+(Oe<<2)>>2]|0,at=y(h[s+908+(Ue<<2)>>2]),at=y(at-y(h[l+908+(Ue<<2)>>2])),h[l+400+(n[1040+(Oe<<2)>>2]<<2)>>2]=at)}while(0)}function Cp(s,l,c){s=s|0,l=l|0,c=c|0;var f=Ze,d=0;d=n[976+(c<<2)>>2]|0,f=y(h[l+908+(d<<2)>>2]),f=y(y(h[s+908+(d<<2)>>2])-f),f=y(f-y(h[l+400+(n[1040+(c<<2)>>2]<<2)>>2])),h[l+400+(n[1e3+(c<<2)>>2]<<2)>>2]=f}function OA(s){return s=s|0,(s|1|0)==1|0}function Iw(s){s=s|0;var l=Ze;switch(n[s+56>>2]|0){case 0:case 3:{l=y(h[s+40>>2]),l>y(0)&((_t(l)|0)^1)?s=o[(n[s+976>>2]|0)+2>>0]|0?1056:992:s=1056;break}default:s=s+52|0}return s|0}function Bw(s,l){return s=s|0,l=l|0,(o[s+l>>0]|0)!=0|0}function sr(s,l){return s=s|0,l=l|0,s=s+132|0,he(l)|0&&(n[(Fn(s,5,948)|0)+4>>2]|0)!=0?s=1:s=(n[(Fn(s,n[1e3+(l<<2)>>2]|0,948)|0)+4>>2]|0)!=0,s|0}function vu(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0;return s=s+132|0,he(l)|0&&(f=Fn(s,5,948)|0,(n[f+4>>2]|0)!=0)?d=4:(f=Fn(s,n[1e3+(l<<2)>>2]|0,948)|0,n[f+4>>2]|0?d=4:c=y(0)),(d|0)==4&&(c=y(Gr(f,c))),y(c)}function Mm(s,l,c){return s=s|0,l=l|0,c=y(c),gi(s,l)|0?c=y(Mr(s,l,c)):c=y(-y(vu(s,l,c))),y(c)}function Du(s){return s=y(s),h[v>>2]=s,n[v>>2]|0|0}function wp(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>1073741823)Tt();else{d=Vt(l<<2)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<2)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<2)}function Ig(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function UA(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-4-l|0)>>>2)<<2)),s=n[s>>2]|0,s|0&>(s)}function _A(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;if(B=s+4|0,k=n[B>>2]|0,d=k-f|0,m=d>>2,s=l+(m<<2)|0,s>>>0>>0){f=k;do n[f>>2]=n[s>>2],s=s+4|0,f=(n[B>>2]|0)+4|0,n[B>>2]=f;while(s>>>0>>0)}m|0&&Mw(k+(0-m<<2)|0,l|0,d|0)|0}function Bg(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0;return k=l+4|0,Q=n[k>>2]|0,d=n[s>>2]|0,B=c,m=B-d|0,f=Q+(0-(m>>2)<<2)|0,n[k>>2]=f,(m|0)>0&&Dr(f|0,d|0,m|0)|0,d=s+4|0,m=l+8|0,f=(n[d>>2]|0)-B|0,(f|0)>0&&(Dr(n[m>>2]|0,c|0,f|0)|0,n[m>>2]=(n[m>>2]|0)+(f>>>2<<2)),B=n[s>>2]|0,n[s>>2]=n[k>>2],n[k>>2]=B,B=n[d>>2]|0,n[d>>2]=n[m>>2],n[m>>2]=B,B=s+8|0,c=l+12|0,s=n[B>>2]|0,n[B>>2]=n[c>>2],n[c>>2]=s,n[l>>2]=n[k>>2],Q|0}function vw(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;if(B=n[l>>2]|0,m=n[c>>2]|0,(B|0)!=(m|0)){d=s+8|0,c=((m+-4-B|0)>>>2)+1|0,s=B,f=n[d>>2]|0;do n[f>>2]=n[s>>2],f=(n[d>>2]|0)+4|0,n[d>>2]=f,s=s+4|0;while((s|0)!=(m|0));n[l>>2]=B+(c<<2)}}function Om(){dc()}function ga(){var s=0;return s=Vt(4)|0,HA(s),s|0}function HA(s){s=s|0,n[s>>2]=ys()|0}function Sc(s){s=s|0,s|0&&(vg(s),gt(s))}function vg(s){s=s|0,tt(n[s>>2]|0)}function Um(s,l,c){s=s|0,l=l|0,c=c|0,Ga(n[s>>2]|0,l,c)}function fo(s,l){s=s|0,l=y(l),pa(n[s>>2]|0,l)}function Wv(s,l){return s=s|0,l=l|0,Bw(n[s>>2]|0,l)|0}function Dw(){var s=0;return s=Vt(8)|0,Vv(s,0),s|0}function Vv(s,l){s=s|0,l=l|0,l?l=Ci(n[l>>2]|0)|0:l=co()|0,n[s>>2]=l,n[s+4>>2]=0,xi(l,s)}function pF(s){s=s|0;var l=0;return l=Vt(8)|0,Vv(l,s),l|0}function Kv(s){s=s|0,s|0&&(Pu(s),gt(s))}function Pu(s){s=s|0;var l=0;la(n[s>>2]|0),l=s+4|0,s=n[l>>2]|0,n[l>>2]=0,s|0&&(jA(s),gt(s))}function jA(s){s=s|0,qA(s)}function qA(s){s=s|0,s=n[s>>2]|0,s|0&&PA(s|0)}function Pw(s){return s=s|0,jo(s)|0}function _m(s){s=s|0;var l=0,c=0;c=s+4|0,l=n[c>>2]|0,n[c>>2]=0,l|0&&(jA(l),gt(l)),_s(n[s>>2]|0)}function hF(s,l){s=s|0,l=l|0,Zr(n[s>>2]|0,n[l>>2]|0)}function gF(s,l){s=s|0,l=l|0,ca(n[s>>2]|0,l)}function Jv(s,l,c){s=s|0,l=l|0,c=+c,yu(n[s>>2]|0,l,y(c))}function zv(s,l,c){s=s|0,l=l|0,c=+c,Es(n[s>>2]|0,l,y(c))}function Sw(s,l){s=s|0,l=l|0,gu(n[s>>2]|0,l)}function Su(s,l){s=s|0,l=l|0,du(n[s>>2]|0,l)}function dF(s,l){s=s|0,l=l|0,QA(n[s>>2]|0,l)}function mF(s,l){s=s|0,l=l|0,bA(n[s>>2]|0,l)}function Ip(s,l){s=s|0,l=l|0,yc(n[s>>2]|0,l)}function yF(s,l){s=s|0,l=l|0,up(n[s>>2]|0,l)}function Xv(s,l,c){s=s|0,l=l|0,c=+c,Cc(n[s>>2]|0,l,y(c))}function GA(s,l,c){s=s|0,l=l|0,c=+c,G(n[s>>2]|0,l,y(c))}function EF(s,l){s=s|0,l=l|0,wl(n[s>>2]|0,l)}function CF(s,l){s=s|0,l=l|0,og(n[s>>2]|0,l)}function Zv(s,l){s=s|0,l=l|0,Ap(n[s>>2]|0,l)}function xw(s,l){s=s|0,l=+l,FA(n[s>>2]|0,y(l))}function bw(s,l){s=s|0,l=+l,Ha(n[s>>2]|0,y(l))}function wF(s,l){s=s|0,l=+l,Gi(n[s>>2]|0,y(l))}function IF(s,l){s=s|0,l=+l,Hs(n[s>>2]|0,y(l))}function Dl(s,l){s=s|0,l=+l,mu(n[s>>2]|0,y(l))}function kw(s,l){s=s|0,l=+l,mw(n[s>>2]|0,y(l))}function BF(s,l){s=s|0,l=+l,TA(n[s>>2]|0,y(l))}function YA(s){s=s|0,fp(n[s>>2]|0)}function Hm(s,l){s=s|0,l=+l,Cs(n[s>>2]|0,y(l))}function xu(s,l){s=s|0,l=+l,cg(n[s>>2]|0,y(l))}function Qw(s){s=s|0,ug(n[s>>2]|0)}function Fw(s,l){s=s|0,l=+l,pp(n[s>>2]|0,y(l))}function vF(s,l){s=s|0,l=+l,Ic(n[s>>2]|0,y(l))}function $v(s,l){s=s|0,l=+l,Sm(n[s>>2]|0,y(l))}function WA(s,l){s=s|0,l=+l,fg(n[s>>2]|0,y(l))}function eD(s,l){s=s|0,l=+l,Cu(n[s>>2]|0,y(l))}function jm(s,l){s=s|0,l=+l,xm(n[s>>2]|0,y(l))}function tD(s,l){s=s|0,l=+l,wu(n[s>>2]|0,y(l))}function rD(s,l){s=s|0,l=+l,yw(n[s>>2]|0,y(l))}function qm(s,l){s=s|0,l=+l,Aa(n[s>>2]|0,y(l))}function nD(s,l,c){s=s|0,l=l|0,c=+c,Eu(n[s>>2]|0,l,y(c))}function DF(s,l,c){s=s|0,l=l|0,c=+c,bi(n[s>>2]|0,l,y(c))}function P(s,l,c){s=s|0,l=l|0,c=+c,wc(n[s>>2]|0,l,y(c))}function D(s){return s=s|0,sg(n[s>>2]|0)|0}function R(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;f=C,C=C+16|0,d=f,Ec(d,n[l>>2]|0,c),j(s,d),C=f}function j(s,l){s=s|0,l=l|0,Y(s,n[l+4>>2]|0,+y(h[l>>2]))}function Y(s,l,c){s=s|0,l=l|0,c=+c,n[s>>2]=l,E[s+8>>3]=c}function fe(s){return s=s|0,ig(n[s>>2]|0)|0}function ve(s){return s=s|0,uo(n[s>>2]|0)|0}function vt(s){return s=s|0,mc(n[s>>2]|0)|0}function wt(s){return s=s|0,kA(n[s>>2]|0)|0}function bt(s){return s=s|0,Pm(n[s>>2]|0)|0}function _r(s){return s=s|0,ng(n[s>>2]|0)|0}function is(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;f=C,C=C+16|0,d=f,Dt(d,n[l>>2]|0,c),j(s,d),C=f}function di(s){return s=s|0,$n(n[s>>2]|0)|0}function po(s){return s=s|0,ag(n[s>>2]|0)|0}function VA(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,ua(f,n[l>>2]|0),j(s,f),C=c}function Yo(s){return s=s|0,+ +y(qi(n[s>>2]|0))}function rt(s){return s=s|0,+ +y(es(n[s>>2]|0))}function Ke(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,Br(f,n[l>>2]|0),j(s,f),C=c}function At(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,Ag(f,n[l>>2]|0),j(s,f),C=c}function Wt(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,Ct(f,n[l>>2]|0),j(s,f),C=c}function vr(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,pg(f,n[l>>2]|0),j(s,f),C=c}function Sn(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,hg(f,n[l>>2]|0),j(s,f),C=c}function Fr(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,bm(f,n[l>>2]|0),j(s,f),C=c}function xn(s){return s=s|0,+ +y(Bc(n[s>>2]|0))}function ai(s,l){return s=s|0,l=l|0,+ +y(lg(n[s>>2]|0,l))}function en(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;f=C,C=C+16|0,d=f,ct(d,n[l>>2]|0,c),j(s,d),C=f}function ho(s,l,c){s=s|0,l=l|0,c=c|0,nr(n[s>>2]|0,n[l>>2]|0,c)}function PF(s,l){s=s|0,l=l|0,ms(n[s>>2]|0,n[l>>2]|0)}function sve(s){return s=s|0,wi(n[s>>2]|0)|0}function ove(s){return s=s|0,s=pt(n[s>>2]|0)|0,s?s=Pw(s)|0:s=0,s|0}function ave(s,l){return s=s|0,l=l|0,s=gs(n[s>>2]|0,l)|0,s?s=Pw(s)|0:s=0,s|0}function lve(s,l){s=s|0,l=l|0;var c=0,f=0;f=Vt(4)|0,$G(f,l),c=s+4|0,l=n[c>>2]|0,n[c>>2]=f,l|0&&(jA(l),gt(l)),It(n[s>>2]|0,1)}function $G(s,l){s=s|0,l=l|0,Cve(s,l)}function cve(s,l,c,f,d,m){s=s|0,l=l|0,c=y(c),f=f|0,d=y(d),m=m|0;var B=0,k=0;B=C,C=C+16|0,k=B,uve(k,jo(l)|0,+c,f,+d,m),h[s>>2]=y(+E[k>>3]),h[s+4>>2]=y(+E[k+8>>3]),C=B}function uve(s,l,c,f,d,m){s=s|0,l=l|0,c=+c,f=f|0,d=+d,m=m|0;var B=0,k=0,Q=0,O=0,M=0;B=C,C=C+32|0,M=B+8|0,O=B+20|0,Q=B,k=B+16|0,E[M>>3]=c,n[O>>2]=f,E[Q>>3]=d,n[k>>2]=m,Ave(s,n[l+4>>2]|0,M,O,Q,k),C=B}function Ave(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0;B=C,C=C+16|0,k=B,Va(k),l=da(l)|0,fve(s,l,+E[c>>3],n[f>>2]|0,+E[d>>3],n[m>>2]|0),Ka(k),C=B}function da(s){return s=s|0,n[s>>2]|0}function fve(s,l,c,f,d,m){s=s|0,l=l|0,c=+c,f=f|0,d=+d,m=m|0;var B=0;B=Pl(pve()|0)|0,c=+KA(c),f=SF(f)|0,d=+KA(d),hve(s,hi(0,B|0,l|0,+c,f|0,+d,SF(m)|0)|0)}function pve(){var s=0;return o[7608]|0||(yve(9120),s=7608,n[s>>2]=1,n[s+4>>2]=0),9120}function Pl(s){return s=s|0,n[s+8>>2]|0}function KA(s){return s=+s,+ +xF(s)}function SF(s){return s=s|0,t5(s)|0}function hve(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;d=C,C=C+32|0,c=d,f=l,f&1?(gve(c,0),ii(f|0,c|0)|0,dve(s,c),mve(c)):(n[s>>2]=n[l>>2],n[s+4>>2]=n[l+4>>2],n[s+8>>2]=n[l+8>>2],n[s+12>>2]=n[l+12>>2]),C=d}function gve(s,l){s=s|0,l=l|0,e5(s,l),n[s+8>>2]=0,o[s+24>>0]=0}function dve(s,l){s=s|0,l=l|0,l=l+8|0,n[s>>2]=n[l>>2],n[s+4>>2]=n[l+4>>2],n[s+8>>2]=n[l+8>>2],n[s+12>>2]=n[l+12>>2]}function mve(s){s=s|0,o[s+24>>0]=0}function e5(s,l){s=s|0,l=l|0,n[s>>2]=l}function t5(s){return s=s|0,s|0}function xF(s){return s=+s,+s}function yve(s){s=s|0,Sl(s,Eve()|0,4)}function Eve(){return 1064}function Sl(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c,n[s+8>>2]=cp(l|0,c+1|0)|0}function Cve(s,l){s=s|0,l=l|0,l=n[l>>2]|0,n[s>>2]=l,yl(l|0)}function wve(s){s=s|0;var l=0,c=0;c=s+4|0,l=n[c>>2]|0,n[c>>2]=0,l|0&&(jA(l),gt(l)),It(n[s>>2]|0,0)}function Ive(s){s=s|0,Rt(n[s>>2]|0)}function Bve(s){return s=s|0,er(n[s>>2]|0)|0}function vve(s,l,c,f){s=s|0,l=+l,c=+c,f=f|0,vc(n[s>>2]|0,y(l),y(c),f)}function Dve(s){return s=s|0,+ +y(Il(n[s>>2]|0))}function Pve(s){return s=s|0,+ +y(gg(n[s>>2]|0))}function Sve(s){return s=s|0,+ +y(Iu(n[s>>2]|0))}function xve(s){return s=s|0,+ +y(RA(n[s>>2]|0))}function bve(s){return s=s|0,+ +y(hp(n[s>>2]|0))}function kve(s){return s=s|0,+ +y(ja(n[s>>2]|0))}function Qve(s,l){s=s|0,l=l|0,E[s>>3]=+y(Il(n[l>>2]|0)),E[s+8>>3]=+y(gg(n[l>>2]|0)),E[s+16>>3]=+y(Iu(n[l>>2]|0)),E[s+24>>3]=+y(RA(n[l>>2]|0)),E[s+32>>3]=+y(hp(n[l>>2]|0)),E[s+40>>3]=+y(ja(n[l>>2]|0))}function Fve(s,l){return s=s|0,l=l|0,+ +y(dg(n[s>>2]|0,l))}function Tve(s,l){return s=s|0,l=l|0,+ +y(gp(n[s>>2]|0,l))}function Rve(s,l){return s=s|0,l=l|0,+ +y(qo(n[s>>2]|0,l))}function Nve(){return Pn()|0}function Lve(){Mve(),Ove(),Uve(),_ve(),Hve(),jve()}function Mve(){HNe(11713,4938,1)}function Ove(){oNe(10448)}function Uve(){HRe(10408)}function _ve(){uRe(10324)}function Hve(){yFe(10096)}function jve(){qve(9132)}function qve(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0,Ge=0,Oe=0,Fe=0,et=0,Xe=0,at=0,Ue=0,qe=0,Lt=0,Or=0,or=0,Xt=0,Pr=0,Nr=0,ir=0,bn=0,go=0,mo=0,yo=0,ya=0,Qp=0,Fp=0,xl=0,Tp=0,Fu=0,Tu=0,Rp=0,Np=0,Lp=0,Xr=0,bl=0,Mp=0,bc=0,Op=0,Up=0,Ru=0,Nu=0,kc=0,qs=0,za=0,Wo=0,kl=0,rf=0,nf=0,Lu=0,sf=0,of=0,Gs=0,vs=0,Ql=0,Tn=0,af=0,Eo=0,Qc=0,Co=0,Fc=0,lf=0,cf=0,Tc=0,Ys=0,Fl=0,uf=0,Af=0,ff=0,br=0,Jn=0,Ds=0,wo=0,Ws=0,Tr=0,ur=0,Tl=0;l=C,C=C+672|0,c=l+656|0,Tl=l+648|0,ur=l+640|0,Tr=l+632|0,Ws=l+624|0,wo=l+616|0,Ds=l+608|0,Jn=l+600|0,br=l+592|0,ff=l+584|0,Af=l+576|0,uf=l+568|0,Fl=l+560|0,Ys=l+552|0,Tc=l+544|0,cf=l+536|0,lf=l+528|0,Fc=l+520|0,Co=l+512|0,Qc=l+504|0,Eo=l+496|0,af=l+488|0,Tn=l+480|0,Ql=l+472|0,vs=l+464|0,Gs=l+456|0,of=l+448|0,sf=l+440|0,Lu=l+432|0,nf=l+424|0,rf=l+416|0,kl=l+408|0,Wo=l+400|0,za=l+392|0,qs=l+384|0,kc=l+376|0,Nu=l+368|0,Ru=l+360|0,Up=l+352|0,Op=l+344|0,bc=l+336|0,Mp=l+328|0,bl=l+320|0,Xr=l+312|0,Lp=l+304|0,Np=l+296|0,Rp=l+288|0,Tu=l+280|0,Fu=l+272|0,Tp=l+264|0,xl=l+256|0,Fp=l+248|0,Qp=l+240|0,ya=l+232|0,yo=l+224|0,mo=l+216|0,go=l+208|0,bn=l+200|0,ir=l+192|0,Nr=l+184|0,Pr=l+176|0,Xt=l+168|0,or=l+160|0,Or=l+152|0,Lt=l+144|0,qe=l+136|0,Ue=l+128|0,at=l+120|0,Xe=l+112|0,et=l+104|0,Fe=l+96|0,Oe=l+88|0,Ge=l+80|0,se=l+72|0,q=l+64|0,M=l+56|0,O=l+48|0,Q=l+40|0,k=l+32|0,B=l+24|0,m=l+16|0,d=l+8|0,f=l,Gve(s,3646),Yve(s,3651,2)|0,Wve(s,3665,2)|0,Vve(s,3682,18)|0,n[Tl>>2]=19,n[Tl+4>>2]=0,n[c>>2]=n[Tl>>2],n[c+4>>2]=n[Tl+4>>2],Tw(s,3690,c)|0,n[ur>>2]=1,n[ur+4>>2]=0,n[c>>2]=n[ur>>2],n[c+4>>2]=n[ur+4>>2],Kve(s,3696,c)|0,n[Tr>>2]=2,n[Tr+4>>2]=0,n[c>>2]=n[Tr>>2],n[c+4>>2]=n[Tr+4>>2],bu(s,3706,c)|0,n[Ws>>2]=1,n[Ws+4>>2]=0,n[c>>2]=n[Ws>>2],n[c+4>>2]=n[Ws+4>>2],Dg(s,3722,c)|0,n[wo>>2]=2,n[wo+4>>2]=0,n[c>>2]=n[wo>>2],n[c+4>>2]=n[wo+4>>2],Dg(s,3734,c)|0,n[Ds>>2]=3,n[Ds+4>>2]=0,n[c>>2]=n[Ds>>2],n[c+4>>2]=n[Ds+4>>2],bu(s,3753,c)|0,n[Jn>>2]=4,n[Jn+4>>2]=0,n[c>>2]=n[Jn>>2],n[c+4>>2]=n[Jn+4>>2],bu(s,3769,c)|0,n[br>>2]=5,n[br+4>>2]=0,n[c>>2]=n[br>>2],n[c+4>>2]=n[br+4>>2],bu(s,3783,c)|0,n[ff>>2]=6,n[ff+4>>2]=0,n[c>>2]=n[ff>>2],n[c+4>>2]=n[ff+4>>2],bu(s,3796,c)|0,n[Af>>2]=7,n[Af+4>>2]=0,n[c>>2]=n[Af>>2],n[c+4>>2]=n[Af+4>>2],bu(s,3813,c)|0,n[uf>>2]=8,n[uf+4>>2]=0,n[c>>2]=n[uf>>2],n[c+4>>2]=n[uf+4>>2],bu(s,3825,c)|0,n[Fl>>2]=3,n[Fl+4>>2]=0,n[c>>2]=n[Fl>>2],n[c+4>>2]=n[Fl+4>>2],Dg(s,3843,c)|0,n[Ys>>2]=4,n[Ys+4>>2]=0,n[c>>2]=n[Ys>>2],n[c+4>>2]=n[Ys+4>>2],Dg(s,3853,c)|0,n[Tc>>2]=9,n[Tc+4>>2]=0,n[c>>2]=n[Tc>>2],n[c+4>>2]=n[Tc+4>>2],bu(s,3870,c)|0,n[cf>>2]=10,n[cf+4>>2]=0,n[c>>2]=n[cf>>2],n[c+4>>2]=n[cf+4>>2],bu(s,3884,c)|0,n[lf>>2]=11,n[lf+4>>2]=0,n[c>>2]=n[lf>>2],n[c+4>>2]=n[lf+4>>2],bu(s,3896,c)|0,n[Fc>>2]=1,n[Fc+4>>2]=0,n[c>>2]=n[Fc>>2],n[c+4>>2]=n[Fc+4>>2],Is(s,3907,c)|0,n[Co>>2]=2,n[Co+4>>2]=0,n[c>>2]=n[Co>>2],n[c+4>>2]=n[Co+4>>2],Is(s,3915,c)|0,n[Qc>>2]=3,n[Qc+4>>2]=0,n[c>>2]=n[Qc>>2],n[c+4>>2]=n[Qc+4>>2],Is(s,3928,c)|0,n[Eo>>2]=4,n[Eo+4>>2]=0,n[c>>2]=n[Eo>>2],n[c+4>>2]=n[Eo+4>>2],Is(s,3948,c)|0,n[af>>2]=5,n[af+4>>2]=0,n[c>>2]=n[af>>2],n[c+4>>2]=n[af+4>>2],Is(s,3960,c)|0,n[Tn>>2]=6,n[Tn+4>>2]=0,n[c>>2]=n[Tn>>2],n[c+4>>2]=n[Tn+4>>2],Is(s,3974,c)|0,n[Ql>>2]=7,n[Ql+4>>2]=0,n[c>>2]=n[Ql>>2],n[c+4>>2]=n[Ql+4>>2],Is(s,3983,c)|0,n[vs>>2]=20,n[vs+4>>2]=0,n[c>>2]=n[vs>>2],n[c+4>>2]=n[vs+4>>2],Tw(s,3999,c)|0,n[Gs>>2]=8,n[Gs+4>>2]=0,n[c>>2]=n[Gs>>2],n[c+4>>2]=n[Gs+4>>2],Is(s,4012,c)|0,n[of>>2]=9,n[of+4>>2]=0,n[c>>2]=n[of>>2],n[c+4>>2]=n[of+4>>2],Is(s,4022,c)|0,n[sf>>2]=21,n[sf+4>>2]=0,n[c>>2]=n[sf>>2],n[c+4>>2]=n[sf+4>>2],Tw(s,4039,c)|0,n[Lu>>2]=10,n[Lu+4>>2]=0,n[c>>2]=n[Lu>>2],n[c+4>>2]=n[Lu+4>>2],Is(s,4053,c)|0,n[nf>>2]=11,n[nf+4>>2]=0,n[c>>2]=n[nf>>2],n[c+4>>2]=n[nf+4>>2],Is(s,4065,c)|0,n[rf>>2]=12,n[rf+4>>2]=0,n[c>>2]=n[rf>>2],n[c+4>>2]=n[rf+4>>2],Is(s,4084,c)|0,n[kl>>2]=13,n[kl+4>>2]=0,n[c>>2]=n[kl>>2],n[c+4>>2]=n[kl+4>>2],Is(s,4097,c)|0,n[Wo>>2]=14,n[Wo+4>>2]=0,n[c>>2]=n[Wo>>2],n[c+4>>2]=n[Wo+4>>2],Is(s,4117,c)|0,n[za>>2]=15,n[za+4>>2]=0,n[c>>2]=n[za>>2],n[c+4>>2]=n[za+4>>2],Is(s,4129,c)|0,n[qs>>2]=16,n[qs+4>>2]=0,n[c>>2]=n[qs>>2],n[c+4>>2]=n[qs+4>>2],Is(s,4148,c)|0,n[kc>>2]=17,n[kc+4>>2]=0,n[c>>2]=n[kc>>2],n[c+4>>2]=n[kc+4>>2],Is(s,4161,c)|0,n[Nu>>2]=18,n[Nu+4>>2]=0,n[c>>2]=n[Nu>>2],n[c+4>>2]=n[Nu+4>>2],Is(s,4181,c)|0,n[Ru>>2]=5,n[Ru+4>>2]=0,n[c>>2]=n[Ru>>2],n[c+4>>2]=n[Ru+4>>2],Dg(s,4196,c)|0,n[Up>>2]=6,n[Up+4>>2]=0,n[c>>2]=n[Up>>2],n[c+4>>2]=n[Up+4>>2],Dg(s,4206,c)|0,n[Op>>2]=7,n[Op+4>>2]=0,n[c>>2]=n[Op>>2],n[c+4>>2]=n[Op+4>>2],Dg(s,4217,c)|0,n[bc>>2]=3,n[bc+4>>2]=0,n[c>>2]=n[bc>>2],n[c+4>>2]=n[bc+4>>2],JA(s,4235,c)|0,n[Mp>>2]=1,n[Mp+4>>2]=0,n[c>>2]=n[Mp>>2],n[c+4>>2]=n[Mp+4>>2],bF(s,4251,c)|0,n[bl>>2]=4,n[bl+4>>2]=0,n[c>>2]=n[bl>>2],n[c+4>>2]=n[bl+4>>2],JA(s,4263,c)|0,n[Xr>>2]=5,n[Xr+4>>2]=0,n[c>>2]=n[Xr>>2],n[c+4>>2]=n[Xr+4>>2],JA(s,4279,c)|0,n[Lp>>2]=6,n[Lp+4>>2]=0,n[c>>2]=n[Lp>>2],n[c+4>>2]=n[Lp+4>>2],JA(s,4293,c)|0,n[Np>>2]=7,n[Np+4>>2]=0,n[c>>2]=n[Np>>2],n[c+4>>2]=n[Np+4>>2],JA(s,4306,c)|0,n[Rp>>2]=8,n[Rp+4>>2]=0,n[c>>2]=n[Rp>>2],n[c+4>>2]=n[Rp+4>>2],JA(s,4323,c)|0,n[Tu>>2]=9,n[Tu+4>>2]=0,n[c>>2]=n[Tu>>2],n[c+4>>2]=n[Tu+4>>2],JA(s,4335,c)|0,n[Fu>>2]=2,n[Fu+4>>2]=0,n[c>>2]=n[Fu>>2],n[c+4>>2]=n[Fu+4>>2],bF(s,4353,c)|0,n[Tp>>2]=12,n[Tp+4>>2]=0,n[c>>2]=n[Tp>>2],n[c+4>>2]=n[Tp+4>>2],Pg(s,4363,c)|0,n[xl>>2]=1,n[xl+4>>2]=0,n[c>>2]=n[xl>>2],n[c+4>>2]=n[xl+4>>2],zA(s,4376,c)|0,n[Fp>>2]=2,n[Fp+4>>2]=0,n[c>>2]=n[Fp>>2],n[c+4>>2]=n[Fp+4>>2],zA(s,4388,c)|0,n[Qp>>2]=13,n[Qp+4>>2]=0,n[c>>2]=n[Qp>>2],n[c+4>>2]=n[Qp+4>>2],Pg(s,4402,c)|0,n[ya>>2]=14,n[ya+4>>2]=0,n[c>>2]=n[ya>>2],n[c+4>>2]=n[ya+4>>2],Pg(s,4411,c)|0,n[yo>>2]=15,n[yo+4>>2]=0,n[c>>2]=n[yo>>2],n[c+4>>2]=n[yo+4>>2],Pg(s,4421,c)|0,n[mo>>2]=16,n[mo+4>>2]=0,n[c>>2]=n[mo>>2],n[c+4>>2]=n[mo+4>>2],Pg(s,4433,c)|0,n[go>>2]=17,n[go+4>>2]=0,n[c>>2]=n[go>>2],n[c+4>>2]=n[go+4>>2],Pg(s,4446,c)|0,n[bn>>2]=18,n[bn+4>>2]=0,n[c>>2]=n[bn>>2],n[c+4>>2]=n[bn+4>>2],Pg(s,4458,c)|0,n[ir>>2]=3,n[ir+4>>2]=0,n[c>>2]=n[ir>>2],n[c+4>>2]=n[ir+4>>2],zA(s,4471,c)|0,n[Nr>>2]=1,n[Nr+4>>2]=0,n[c>>2]=n[Nr>>2],n[c+4>>2]=n[Nr+4>>2],iD(s,4486,c)|0,n[Pr>>2]=10,n[Pr+4>>2]=0,n[c>>2]=n[Pr>>2],n[c+4>>2]=n[Pr+4>>2],JA(s,4496,c)|0,n[Xt>>2]=11,n[Xt+4>>2]=0,n[c>>2]=n[Xt>>2],n[c+4>>2]=n[Xt+4>>2],JA(s,4508,c)|0,n[or>>2]=3,n[or+4>>2]=0,n[c>>2]=n[or>>2],n[c+4>>2]=n[or+4>>2],bF(s,4519,c)|0,n[Or>>2]=4,n[Or+4>>2]=0,n[c>>2]=n[Or>>2],n[c+4>>2]=n[Or+4>>2],Jve(s,4530,c)|0,n[Lt>>2]=19,n[Lt+4>>2]=0,n[c>>2]=n[Lt>>2],n[c+4>>2]=n[Lt+4>>2],zve(s,4542,c)|0,n[qe>>2]=12,n[qe+4>>2]=0,n[c>>2]=n[qe>>2],n[c+4>>2]=n[qe+4>>2],Xve(s,4554,c)|0,n[Ue>>2]=13,n[Ue+4>>2]=0,n[c>>2]=n[Ue>>2],n[c+4>>2]=n[Ue+4>>2],Zve(s,4568,c)|0,n[at>>2]=2,n[at+4>>2]=0,n[c>>2]=n[at>>2],n[c+4>>2]=n[at+4>>2],$ve(s,4578,c)|0,n[Xe>>2]=20,n[Xe+4>>2]=0,n[c>>2]=n[Xe>>2],n[c+4>>2]=n[Xe+4>>2],eDe(s,4587,c)|0,n[et>>2]=22,n[et+4>>2]=0,n[c>>2]=n[et>>2],n[c+4>>2]=n[et+4>>2],Tw(s,4602,c)|0,n[Fe>>2]=23,n[Fe+4>>2]=0,n[c>>2]=n[Fe>>2],n[c+4>>2]=n[Fe+4>>2],Tw(s,4619,c)|0,n[Oe>>2]=14,n[Oe+4>>2]=0,n[c>>2]=n[Oe>>2],n[c+4>>2]=n[Oe+4>>2],tDe(s,4629,c)|0,n[Ge>>2]=1,n[Ge+4>>2]=0,n[c>>2]=n[Ge>>2],n[c+4>>2]=n[Ge+4>>2],rDe(s,4637,c)|0,n[se>>2]=4,n[se+4>>2]=0,n[c>>2]=n[se>>2],n[c+4>>2]=n[se+4>>2],zA(s,4653,c)|0,n[q>>2]=5,n[q+4>>2]=0,n[c>>2]=n[q>>2],n[c+4>>2]=n[q+4>>2],zA(s,4669,c)|0,n[M>>2]=6,n[M+4>>2]=0,n[c>>2]=n[M>>2],n[c+4>>2]=n[M+4>>2],zA(s,4686,c)|0,n[O>>2]=7,n[O+4>>2]=0,n[c>>2]=n[O>>2],n[c+4>>2]=n[O+4>>2],zA(s,4701,c)|0,n[Q>>2]=8,n[Q+4>>2]=0,n[c>>2]=n[Q>>2],n[c+4>>2]=n[Q+4>>2],zA(s,4719,c)|0,n[k>>2]=9,n[k+4>>2]=0,n[c>>2]=n[k>>2],n[c+4>>2]=n[k+4>>2],zA(s,4736,c)|0,n[B>>2]=21,n[B+4>>2]=0,n[c>>2]=n[B>>2],n[c+4>>2]=n[B+4>>2],nDe(s,4754,c)|0,n[m>>2]=2,n[m+4>>2]=0,n[c>>2]=n[m>>2],n[c+4>>2]=n[m+4>>2],iD(s,4772,c)|0,n[d>>2]=3,n[d+4>>2]=0,n[c>>2]=n[d>>2],n[c+4>>2]=n[d+4>>2],iD(s,4790,c)|0,n[f>>2]=4,n[f+4>>2]=0,n[c>>2]=n[f>>2],n[c+4>>2]=n[f+4>>2],iD(s,4808,c)|0,C=l}function Gve(s,l){s=s|0,l=l|0;var c=0;c=cFe()|0,n[s>>2]=c,uFe(c,l),xp(n[s>>2]|0)}function Yve(s,l,c){return s=s|0,l=l|0,c=c|0,JQe(s,pn(l)|0,c,0),s|0}function Wve(s,l,c){return s=s|0,l=l|0,c=c|0,TQe(s,pn(l)|0,c,0),s|0}function Vve(s,l,c){return s=s|0,l=l|0,c=c|0,EQe(s,pn(l)|0,c,0),s|0}function Tw(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],nQe(s,l,d),C=f,s|0}function Kve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Oke(s,l,d),C=f,s|0}function bu(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Ike(s,l,d),C=f,s|0}function Dg(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],oke(s,l,d),C=f,s|0}function Is(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Gbe(s,l,d),C=f,s|0}function JA(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],xbe(s,l,d),C=f,s|0}function bF(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],fbe(s,l,d),C=f,s|0}function Pg(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Oxe(s,l,d),C=f,s|0}function zA(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Ixe(s,l,d),C=f,s|0}function iD(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],oxe(s,l,d),C=f,s|0}function Jve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],GSe(s,l,d),C=f,s|0}function zve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],xSe(s,l,d),C=f,s|0}function Xve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],pSe(s,l,d),C=f,s|0}function Zve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],ZPe(s,l,d),C=f,s|0}function $ve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],NPe(s,l,d),C=f,s|0}function eDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],yPe(s,l,d),C=f,s|0}function tDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],rPe(s,l,d),C=f,s|0}function rDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],ODe(s,l,d),C=f,s|0}function nDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],iDe(s,l,d),C=f,s|0}function iDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],sDe(s,c,d,1),C=f}function pn(s){return s=s|0,s|0}function sDe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=kF()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=oDe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,aDe(m,f)|0,f),C=d}function kF(){var s=0,l=0;if(o[7616]|0||(i5(9136),tr(24,9136,U|0)|0,l=7616,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9136)|0)){s=9136,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));i5(9136)}return 9136}function oDe(s){return s=s|0,0}function aDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=kF()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],n5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(uDe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function hn(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,O=0,M=0,q=0,se=0,Ge=0;B=C,C=C+32|0,se=B+24|0,q=B+20|0,Q=B+16|0,M=B+12|0,O=B+8|0,k=B+4|0,Ge=B,n[q>>2]=l,n[Q>>2]=c,n[M>>2]=f,n[O>>2]=d,n[k>>2]=m,m=s+28|0,n[Ge>>2]=n[m>>2],n[se>>2]=n[Ge>>2],lDe(s+24|0,se,q,M,O,Q,k)|0,n[m>>2]=n[n[m>>2]>>2],C=B}function lDe(s,l,c,f,d,m,B){return s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,B=B|0,s=cDe(l)|0,l=Vt(24)|0,r5(l+4|0,n[c>>2]|0,n[f>>2]|0,n[d>>2]|0,n[m>>2]|0,n[B>>2]|0),n[l>>2]=n[s>>2],n[s>>2]=l,l|0}function cDe(s){return s=s|0,n[s>>2]|0}function r5(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,n[s>>2]=l,n[s+4>>2]=c,n[s+8>>2]=f,n[s+12>>2]=d,n[s+16>>2]=m}function gr(s,l){return s=s|0,l=l|0,l|s|0}function n5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function uDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=ADe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,fDe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],n5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,pDe(s,k),hDe(k),C=O;return}}function ADe(s){return s=s|0,357913941}function fDe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function pDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function hDe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function i5(s){s=s|0,mDe(s)}function gDe(s){s=s|0,dDe(s+24|0)}function Rr(s){return s=s|0,n[s>>2]|0}function dDe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function mDe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,3,l,yDe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Vr(){return 9228}function yDe(){return 1140}function EDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=CDe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=wDe(l,f)|0,C=c,l|0}function Kr(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,n[s>>2]=l,n[s+4>>2]=c,n[s+8>>2]=f,n[s+12>>2]=d,n[s+16>>2]=m}function CDe(s){return s=s|0,(n[(kF()|0)+24>>2]|0)+(s*12|0)|0}function wDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;return d=C,C=C+48|0,f=d,c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),tf[c&31](f,s),f=IDe(f)|0,C=d,f|0}function IDe(s){s=s|0;var l=0,c=0,f=0,d=0;return d=C,C=C+32|0,l=d+12|0,c=d,f=QF(s5()|0)|0,f?(FF(l,f),TF(c,l),BDe(s,c),s=RF(l)|0):s=vDe(s)|0,C=d,s|0}function s5(){var s=0;return o[7632]|0||(RDe(9184),tr(25,9184,U|0)|0,s=7632,n[s>>2]=1,n[s+4>>2]=0),9184}function QF(s){return s=s|0,n[s+36>>2]|0}function FF(s,l){s=s|0,l=l|0,n[s>>2]=l,n[s+4>>2]=s,n[s+8>>2]=0}function TF(s,l){s=s|0,l=l|0,n[s>>2]=n[l>>2],n[s+4>>2]=n[l+4>>2],n[s+8>>2]=0}function BDe(s,l){s=s|0,l=l|0,xDe(l,s,s+8|0,s+16|0,s+24|0,s+32|0,s+40|0)|0}function RF(s){return s=s|0,n[(n[s+4>>2]|0)+8>>2]|0}function vDe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0;Q=C,C=C+16|0,c=Q+4|0,f=Q,d=Wa(8)|0,m=d,B=Vt(48)|0,k=B,l=k+48|0;do n[k>>2]=n[s>>2],k=k+4|0,s=s+4|0;while((k|0)<(l|0));return l=m+4|0,n[l>>2]=B,k=Vt(8)|0,B=n[l>>2]|0,n[f>>2]=0,n[c>>2]=n[f>>2],o5(k,B,c),n[d>>2]=k,C=Q,m|0}function o5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Vt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1092,n[c+12>>2]=l,n[s+4>>2]=c}function DDe(s){s=s|0,Jm(s),gt(s)}function PDe(s){s=s|0,s=n[s+12>>2]|0,s|0&>(s)}function SDe(s){s=s|0,gt(s)}function xDe(s,l,c,f,d,m,B){return s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,B=B|0,m=bDe(n[s>>2]|0,l,c,f,d,m,B)|0,B=s+4|0,n[(n[B>>2]|0)+8>>2]=m,n[(n[B>>2]|0)+8>>2]|0}function bDe(s,l,c,f,d,m,B){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,B=B|0;var k=0,Q=0;return k=C,C=C+16|0,Q=k,Va(Q),s=da(s)|0,B=kDe(s,+E[l>>3],+E[c>>3],+E[f>>3],+E[d>>3],+E[m>>3],+E[B>>3])|0,Ka(Q),C=k,B|0}function kDe(s,l,c,f,d,m,B){s=s|0,l=+l,c=+c,f=+f,d=+d,m=+m,B=+B;var k=0;return k=Pl(QDe()|0)|0,l=+KA(l),c=+KA(c),f=+KA(f),d=+KA(d),m=+KA(m),Os(0,k|0,s|0,+l,+c,+f,+d,+m,+ +KA(B))|0}function QDe(){var s=0;return o[7624]|0||(FDe(9172),s=7624,n[s>>2]=1,n[s+4>>2]=0),9172}function FDe(s){s=s|0,Sl(s,TDe()|0,6)}function TDe(){return 1112}function RDe(s){s=s|0,Bp(s)}function NDe(s){s=s|0,a5(s+24|0),l5(s+16|0)}function a5(s){s=s|0,MDe(s)}function l5(s){s=s|0,LDe(s)}function LDe(s){s=s|0;var l=0,c=0;if(l=n[s>>2]|0,l|0)do c=l,l=n[l>>2]|0,gt(c);while((l|0)!=0);n[s>>2]=0}function MDe(s){s=s|0;var l=0,c=0;if(l=n[s>>2]|0,l|0)do c=l,l=n[l>>2]|0,gt(c);while((l|0)!=0);n[s>>2]=0}function Bp(s){s=s|0;var l=0;n[s+16>>2]=0,n[s+20>>2]=0,l=s+24|0,n[l>>2]=0,n[s+28>>2]=l,n[s+36>>2]=0,o[s+40>>0]=0,o[s+41>>0]=0}function ODe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],UDe(s,c,d,0),C=f}function UDe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=NF()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=_De(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,HDe(m,f)|0,f),C=d}function NF(){var s=0,l=0;if(o[7640]|0||(u5(9232),tr(26,9232,U|0)|0,l=7640,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9232)|0)){s=9232,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));u5(9232)}return 9232}function _De(s){return s=s|0,0}function HDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=NF()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],c5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(jDe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function c5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function jDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=qDe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,GDe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],c5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,YDe(s,k),WDe(k),C=O;return}}function qDe(s){return s=s|0,357913941}function GDe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function YDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function WDe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function u5(s){s=s|0,JDe(s)}function VDe(s){s=s|0,KDe(s+24|0)}function KDe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function JDe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,1,l,zDe()|0,3),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function zDe(){return 1144}function XDe(s,l,c,f,d){s=s|0,l=l|0,c=+c,f=+f,d=d|0;var m=0,B=0,k=0,Q=0;m=C,C=C+16|0,B=m+8|0,k=m,Q=ZDe(s)|0,s=n[Q+4>>2]|0,n[k>>2]=n[Q>>2],n[k+4>>2]=s,n[B>>2]=n[k>>2],n[B+4>>2]=n[k+4>>2],$De(l,B,c,f,d),C=m}function ZDe(s){return s=s|0,(n[(NF()|0)+24>>2]|0)+(s*12|0)|0}function $De(s,l,c,f,d){s=s|0,l=l|0,c=+c,f=+f,d=d|0;var m=0,B=0,k=0,Q=0,O=0;O=C,C=C+16|0,B=O+2|0,k=O+1|0,Q=O,m=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(m=n[(n[s>>2]|0)+m>>2]|0),ku(B,c),c=+Qu(B,c),ku(k,f),f=+Qu(k,f),XA(Q,d),Q=ZA(Q,d)|0,D7[m&1](s,c,f,Q),C=O}function ku(s,l){s=s|0,l=+l}function Qu(s,l){return s=s|0,l=+l,+ +tPe(l)}function XA(s,l){s=s|0,l=l|0}function ZA(s,l){return s=s|0,l=l|0,ePe(l)|0}function ePe(s){return s=s|0,s|0}function tPe(s){return s=+s,+s}function rPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],nPe(s,c,d,1),C=f}function nPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=LF()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=iPe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,sPe(m,f)|0,f),C=d}function LF(){var s=0,l=0;if(o[7648]|0||(f5(9268),tr(27,9268,U|0)|0,l=7648,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9268)|0)){s=9268,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));f5(9268)}return 9268}function iPe(s){return s=s|0,0}function sPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=LF()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],A5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(oPe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function A5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function oPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=aPe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,lPe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],A5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,cPe(s,k),uPe(k),C=O;return}}function aPe(s){return s=s|0,357913941}function lPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function cPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function uPe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function f5(s){s=s|0,pPe(s)}function APe(s){s=s|0,fPe(s+24|0)}function fPe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function pPe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,4,l,hPe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function hPe(){return 1160}function gPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=dPe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=mPe(l,f)|0,C=c,l|0}function dPe(s){return s=s|0,(n[(LF()|0)+24>>2]|0)+(s*12|0)|0}function mPe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),p5(Ng[c&31](s)|0)|0}function p5(s){return s=s|0,s&1|0}function yPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],EPe(s,c,d,0),C=f}function EPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=MF()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=CPe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,wPe(m,f)|0,f),C=d}function MF(){var s=0,l=0;if(o[7656]|0||(g5(9304),tr(28,9304,U|0)|0,l=7656,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9304)|0)){s=9304,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));g5(9304)}return 9304}function CPe(s){return s=s|0,0}function wPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=MF()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],h5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(IPe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function h5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function IPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=BPe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,vPe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],h5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,DPe(s,k),PPe(k),C=O;return}}function BPe(s){return s=s|0,357913941}function vPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function DPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function PPe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function g5(s){s=s|0,bPe(s)}function SPe(s){s=s|0,xPe(s+24|0)}function xPe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function bPe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,5,l,kPe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function kPe(){return 1164}function QPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=FPe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],TPe(l,d,c),C=f}function FPe(s){return s=s|0,(n[(MF()|0)+24>>2]|0)+(s*12|0)|0}function TPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),vp(d,c),c=Dp(d,c)|0,tf[f&31](s,c),Pp(d),C=m}function vp(s,l){s=s|0,l=l|0,RPe(s,l)}function Dp(s,l){return s=s|0,l=l|0,s|0}function Pp(s){s=s|0,jA(s)}function RPe(s,l){s=s|0,l=l|0,OF(s,l)}function OF(s,l){s=s|0,l=l|0,n[s>>2]=l}function NPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],LPe(s,c,d,0),C=f}function LPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=UF()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=MPe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,OPe(m,f)|0,f),C=d}function UF(){var s=0,l=0;if(o[7664]|0||(m5(9340),tr(29,9340,U|0)|0,l=7664,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9340)|0)){s=9340,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));m5(9340)}return 9340}function MPe(s){return s=s|0,0}function OPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=UF()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],d5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(UPe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function d5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function UPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=_Pe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,HPe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],d5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,jPe(s,k),qPe(k),C=O;return}}function _Pe(s){return s=s|0,357913941}function HPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function jPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function qPe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function m5(s){s=s|0,WPe(s)}function GPe(s){s=s|0,YPe(s+24|0)}function YPe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function WPe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,4,l,VPe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function VPe(){return 1180}function KPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=JPe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],c=zPe(l,d,c)|0,C=f,c|0}function JPe(s){return s=s|0,(n[(UF()|0)+24>>2]|0)+(s*12|0)|0}function zPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;return m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),Sg(d,c),d=xg(d,c)|0,d=sD(NT[f&15](s,d)|0)|0,C=m,d|0}function Sg(s,l){s=s|0,l=l|0}function xg(s,l){return s=s|0,l=l|0,XPe(l)|0}function sD(s){return s=s|0,s|0}function XPe(s){return s=s|0,s|0}function ZPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],$Pe(s,c,d,0),C=f}function $Pe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=_F()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=eSe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,tSe(m,f)|0,f),C=d}function _F(){var s=0,l=0;if(o[7672]|0||(E5(9376),tr(30,9376,U|0)|0,l=7672,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9376)|0)){s=9376,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));E5(9376)}return 9376}function eSe(s){return s=s|0,0}function tSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=_F()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],y5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(rSe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function y5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function rSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=nSe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,iSe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],y5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,sSe(s,k),oSe(k),C=O;return}}function nSe(s){return s=s|0,357913941}function iSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function sSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function oSe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function E5(s){s=s|0,cSe(s)}function aSe(s){s=s|0,lSe(s+24|0)}function lSe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function cSe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,5,l,C5()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function C5(){return 1196}function uSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=ASe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=fSe(l,f)|0,C=c,l|0}function ASe(s){return s=s|0,(n[(_F()|0)+24>>2]|0)+(s*12|0)|0}function fSe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),sD(Ng[c&31](s)|0)|0}function pSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],hSe(s,c,d,1),C=f}function hSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=HF()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=gSe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,dSe(m,f)|0,f),C=d}function HF(){var s=0,l=0;if(o[7680]|0||(I5(9412),tr(31,9412,U|0)|0,l=7680,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9412)|0)){s=9412,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));I5(9412)}return 9412}function gSe(s){return s=s|0,0}function dSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=HF()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],w5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(mSe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function w5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function mSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=ySe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,ESe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],w5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,CSe(s,k),wSe(k),C=O;return}}function ySe(s){return s=s|0,357913941}function ESe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function CSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function wSe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function I5(s){s=s|0,vSe(s)}function ISe(s){s=s|0,BSe(s+24|0)}function BSe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function vSe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,6,l,B5()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function B5(){return 1200}function DSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=PSe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=SSe(l,f)|0,C=c,l|0}function PSe(s){return s=s|0,(n[(HF()|0)+24>>2]|0)+(s*12|0)|0}function SSe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),oD(Ng[c&31](s)|0)|0}function oD(s){return s=s|0,s|0}function xSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],bSe(s,c,d,0),C=f}function bSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=jF()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=kSe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,QSe(m,f)|0,f),C=d}function jF(){var s=0,l=0;if(o[7688]|0||(D5(9448),tr(32,9448,U|0)|0,l=7688,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9448)|0)){s=9448,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));D5(9448)}return 9448}function kSe(s){return s=s|0,0}function QSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=jF()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],v5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(FSe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function v5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function FSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=TSe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,RSe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],v5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,NSe(s,k),LSe(k),C=O;return}}function TSe(s){return s=s|0,357913941}function RSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function NSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function LSe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function D5(s){s=s|0,USe(s)}function MSe(s){s=s|0,OSe(s+24|0)}function OSe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function USe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,6,l,P5()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function P5(){return 1204}function _Se(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=HSe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],jSe(l,d,c),C=f}function HSe(s){return s=s|0,(n[(jF()|0)+24>>2]|0)+(s*12|0)|0}function jSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),qF(d,c),d=GF(d,c)|0,tf[f&31](s,d),C=m}function qF(s,l){s=s|0,l=l|0}function GF(s,l){return s=s|0,l=l|0,qSe(l)|0}function qSe(s){return s=s|0,s|0}function GSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],YSe(s,c,d,0),C=f}function YSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=YF()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=WSe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,VSe(m,f)|0,f),C=d}function YF(){var s=0,l=0;if(o[7696]|0||(x5(9484),tr(33,9484,U|0)|0,l=7696,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9484)|0)){s=9484,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));x5(9484)}return 9484}function WSe(s){return s=s|0,0}function VSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=YF()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],S5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(KSe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function S5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function KSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=JSe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,zSe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],S5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,XSe(s,k),ZSe(k),C=O;return}}function JSe(s){return s=s|0,357913941}function zSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function XSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function ZSe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function x5(s){s=s|0,txe(s)}function $Se(s){s=s|0,exe(s+24|0)}function exe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function txe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,1,l,rxe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function rxe(){return 1212}function nxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+16|0,m=d+8|0,B=d,k=ixe(s)|0,s=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=s,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],sxe(l,m,c,f),C=d}function ixe(s){return s=s|0,(n[(YF()|0)+24>>2]|0)+(s*12|0)|0}function sxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;k=C,C=C+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(d=n[(n[s>>2]|0)+d>>2]|0),qF(m,c),m=GF(m,c)|0,Sg(B,f),B=xg(B,f)|0,_w[d&15](s,m,B),C=k}function oxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],axe(s,c,d,1),C=f}function axe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=WF()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=lxe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,cxe(m,f)|0,f),C=d}function WF(){var s=0,l=0;if(o[7704]|0||(k5(9520),tr(34,9520,U|0)|0,l=7704,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9520)|0)){s=9520,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));k5(9520)}return 9520}function lxe(s){return s=s|0,0}function cxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=WF()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],b5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(uxe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function b5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function uxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Axe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,fxe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],b5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,pxe(s,k),hxe(k),C=O;return}}function Axe(s){return s=s|0,357913941}function fxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function pxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function hxe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function k5(s){s=s|0,mxe(s)}function gxe(s){s=s|0,dxe(s+24|0)}function dxe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function mxe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,1,l,yxe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function yxe(){return 1224}function Exe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;return d=C,C=C+16|0,m=d+8|0,B=d,k=Cxe(s)|0,s=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=s,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],f=+wxe(l,m,c),C=d,+f}function Cxe(s){return s=s|0,(n[(WF()|0)+24>>2]|0)+(s*12|0)|0}function wxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),XA(d,c),d=ZA(d,c)|0,B=+xF(+S7[f&7](s,d)),C=m,+B}function Ixe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Bxe(s,c,d,1),C=f}function Bxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=VF()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=vxe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Dxe(m,f)|0,f),C=d}function VF(){var s=0,l=0;if(o[7712]|0||(F5(9556),tr(35,9556,U|0)|0,l=7712,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9556)|0)){s=9556,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));F5(9556)}return 9556}function vxe(s){return s=s|0,0}function Dxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=VF()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Q5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(Pxe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function Q5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function Pxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Sxe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,xxe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],Q5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,bxe(s,k),kxe(k),C=O;return}}function Sxe(s){return s=s|0,357913941}function xxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function bxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function kxe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function F5(s){s=s|0,Txe(s)}function Qxe(s){s=s|0,Fxe(s+24|0)}function Fxe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Txe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,5,l,Rxe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Rxe(){return 1232}function Nxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=Lxe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],c=+Mxe(l,d),C=f,+c}function Lxe(s){return s=s|0,(n[(VF()|0)+24>>2]|0)+(s*12|0)|0}function Mxe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),+ +xF(+P7[c&15](s))}function Oxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Uxe(s,c,d,1),C=f}function Uxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=KF()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=_xe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Hxe(m,f)|0,f),C=d}function KF(){var s=0,l=0;if(o[7720]|0||(R5(9592),tr(36,9592,U|0)|0,l=7720,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9592)|0)){s=9592,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));R5(9592)}return 9592}function _xe(s){return s=s|0,0}function Hxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=KF()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],T5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(jxe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function T5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function jxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=qxe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,Gxe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],T5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Yxe(s,k),Wxe(k),C=O;return}}function qxe(s){return s=s|0,357913941}function Gxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Yxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function Wxe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function R5(s){s=s|0,Jxe(s)}function Vxe(s){s=s|0,Kxe(s+24|0)}function Kxe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Jxe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,7,l,zxe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function zxe(){return 1276}function Xxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=Zxe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=$xe(l,f)|0,C=c,l|0}function Zxe(s){return s=s|0,(n[(KF()|0)+24>>2]|0)+(s*12|0)|0}function $xe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;return d=C,C=C+16|0,f=d,c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),tf[c&31](f,s),f=N5(f)|0,C=d,f|0}function N5(s){s=s|0;var l=0,c=0,f=0,d=0;return d=C,C=C+32|0,l=d+12|0,c=d,f=QF(L5()|0)|0,f?(FF(l,f),TF(c,l),ebe(s,c),s=RF(l)|0):s=tbe(s)|0,C=d,s|0}function L5(){var s=0;return o[7736]|0||(Abe(9640),tr(25,9640,U|0)|0,s=7736,n[s>>2]=1,n[s+4>>2]=0),9640}function ebe(s,l){s=s|0,l=l|0,sbe(l,s,s+8|0)|0}function tbe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0;return c=C,C=C+16|0,d=c+4|0,B=c,f=Wa(8)|0,l=f,k=Vt(16)|0,n[k>>2]=n[s>>2],n[k+4>>2]=n[s+4>>2],n[k+8>>2]=n[s+8>>2],n[k+12>>2]=n[s+12>>2],m=l+4|0,n[m>>2]=k,s=Vt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],JF(s,m,d),n[f>>2]=s,C=c,l|0}function JF(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Vt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1244,n[c+12>>2]=l,n[s+4>>2]=c}function rbe(s){s=s|0,Jm(s),gt(s)}function nbe(s){s=s|0,s=n[s+12>>2]|0,s|0&>(s)}function ibe(s){s=s|0,gt(s)}function sbe(s,l,c){return s=s|0,l=l|0,c=c|0,l=obe(n[s>>2]|0,l,c)|0,c=s+4|0,n[(n[c>>2]|0)+8>>2]=l,n[(n[c>>2]|0)+8>>2]|0}function obe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;return f=C,C=C+16|0,d=f,Va(d),s=da(s)|0,c=abe(s,n[l>>2]|0,+E[c>>3])|0,Ka(d),C=f,c|0}function abe(s,l,c){s=s|0,l=l|0,c=+c;var f=0;return f=Pl(lbe()|0)|0,l=SF(l)|0,ml(0,f|0,s|0,l|0,+ +KA(c))|0}function lbe(){var s=0;return o[7728]|0||(cbe(9628),s=7728,n[s>>2]=1,n[s+4>>2]=0),9628}function cbe(s){s=s|0,Sl(s,ube()|0,2)}function ube(){return 1264}function Abe(s){s=s|0,Bp(s)}function fbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],pbe(s,c,d,1),C=f}function pbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=zF()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=hbe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,gbe(m,f)|0,f),C=d}function zF(){var s=0,l=0;if(o[7744]|0||(O5(9684),tr(37,9684,U|0)|0,l=7744,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9684)|0)){s=9684,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));O5(9684)}return 9684}function hbe(s){return s=s|0,0}function gbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=zF()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],M5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(dbe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function M5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function dbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=mbe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,ybe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],M5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Ebe(s,k),Cbe(k),C=O;return}}function mbe(s){return s=s|0,357913941}function ybe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Ebe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function Cbe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function O5(s){s=s|0,Bbe(s)}function wbe(s){s=s|0,Ibe(s+24|0)}function Ibe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Bbe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,5,l,vbe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function vbe(){return 1280}function Dbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=Pbe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],c=Sbe(l,d,c)|0,C=f,c|0}function Pbe(s){return s=s|0,(n[(zF()|0)+24>>2]|0)+(s*12|0)|0}function Sbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return B=C,C=C+32|0,d=B,m=B+16|0,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),XA(m,c),m=ZA(m,c)|0,_w[f&15](d,s,m),m=N5(d)|0,C=B,m|0}function xbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],bbe(s,c,d,1),C=f}function bbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=XF()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=kbe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Qbe(m,f)|0,f),C=d}function XF(){var s=0,l=0;if(o[7752]|0||(_5(9720),tr(38,9720,U|0)|0,l=7752,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9720)|0)){s=9720,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));_5(9720)}return 9720}function kbe(s){return s=s|0,0}function Qbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=XF()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],U5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(Fbe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function U5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function Fbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Tbe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,Rbe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],U5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Nbe(s,k),Lbe(k),C=O;return}}function Tbe(s){return s=s|0,357913941}function Rbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Nbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function Lbe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function _5(s){s=s|0,Ube(s)}function Mbe(s){s=s|0,Obe(s+24|0)}function Obe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Ube(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,8,l,_be()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function _be(){return 1288}function Hbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=jbe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=qbe(l,f)|0,C=c,l|0}function jbe(s){return s=s|0,(n[(XF()|0)+24>>2]|0)+(s*12|0)|0}function qbe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),t5(Ng[c&31](s)|0)|0}function Gbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Ybe(s,c,d,0),C=f}function Ybe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=ZF()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=Wbe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Vbe(m,f)|0,f),C=d}function ZF(){var s=0,l=0;if(o[7760]|0||(j5(9756),tr(39,9756,U|0)|0,l=7760,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9756)|0)){s=9756,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));j5(9756)}return 9756}function Wbe(s){return s=s|0,0}function Vbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=ZF()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],H5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(Kbe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function H5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function Kbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Jbe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,zbe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],H5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Xbe(s,k),Zbe(k),C=O;return}}function Jbe(s){return s=s|0,357913941}function zbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Xbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function Zbe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function j5(s){s=s|0,tke(s)}function $be(s){s=s|0,eke(s+24|0)}function eke(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function tke(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,8,l,rke()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function rke(){return 1292}function nke(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=ike(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],ske(l,d,c),C=f}function ike(s){return s=s|0,(n[(ZF()|0)+24>>2]|0)+(s*12|0)|0}function ske(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),ku(d,c),c=+Qu(d,c),B7[f&31](s,c),C=m}function oke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],ake(s,c,d,0),C=f}function ake(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=$F()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=lke(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,cke(m,f)|0,f),C=d}function $F(){var s=0,l=0;if(o[7768]|0||(G5(9792),tr(40,9792,U|0)|0,l=7768,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9792)|0)){s=9792,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));G5(9792)}return 9792}function lke(s){return s=s|0,0}function cke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=$F()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],q5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(uke(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function q5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function uke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Ake(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,fke(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],q5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,pke(s,k),hke(k),C=O;return}}function Ake(s){return s=s|0,357913941}function fke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function pke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function hke(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function G5(s){s=s|0,mke(s)}function gke(s){s=s|0,dke(s+24|0)}function dke(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function mke(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,1,l,yke()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function yke(){return 1300}function Eke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=+f;var d=0,m=0,B=0,k=0;d=C,C=C+16|0,m=d+8|0,B=d,k=Cke(s)|0,s=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=s,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],wke(l,m,c,f),C=d}function Cke(s){return s=s|0,(n[($F()|0)+24>>2]|0)+(s*12|0)|0}function wke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=+f;var d=0,m=0,B=0,k=0;k=C,C=C+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(d=n[(n[s>>2]|0)+d>>2]|0),XA(m,c),m=ZA(m,c)|0,ku(B,f),f=+Qu(B,f),Q7[d&15](s,m,f),C=k}function Ike(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Bke(s,c,d,0),C=f}function Bke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=eT()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=vke(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Dke(m,f)|0,f),C=d}function eT(){var s=0,l=0;if(o[7776]|0||(W5(9828),tr(41,9828,U|0)|0,l=7776,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9828)|0)){s=9828,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));W5(9828)}return 9828}function vke(s){return s=s|0,0}function Dke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=eT()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Y5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(Pke(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function Y5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function Pke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Ske(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,xke(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],Y5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,bke(s,k),kke(k),C=O;return}}function Ske(s){return s=s|0,357913941}function xke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function bke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function kke(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function W5(s){s=s|0,Tke(s)}function Qke(s){s=s|0,Fke(s+24|0)}function Fke(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Tke(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,7,l,Rke()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Rke(){return 1312}function Nke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=Lke(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Mke(l,d,c),C=f}function Lke(s){return s=s|0,(n[(eT()|0)+24>>2]|0)+(s*12|0)|0}function Mke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),XA(d,c),d=ZA(d,c)|0,tf[f&31](s,d),C=m}function Oke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Uke(s,c,d,0),C=f}function Uke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=tT()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=_ke(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Hke(m,f)|0,f),C=d}function tT(){var s=0,l=0;if(o[7784]|0||(K5(9864),tr(42,9864,U|0)|0,l=7784,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9864)|0)){s=9864,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));K5(9864)}return 9864}function _ke(s){return s=s|0,0}function Hke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=tT()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],V5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(jke(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function V5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function jke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=qke(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,Gke(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],V5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Yke(s,k),Wke(k),C=O;return}}function qke(s){return s=s|0,357913941}function Gke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Yke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function Wke(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function K5(s){s=s|0,Jke(s)}function Vke(s){s=s|0,Kke(s+24|0)}function Kke(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Jke(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,8,l,zke()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function zke(){return 1320}function Xke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=Zke(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],$ke(l,d,c),C=f}function Zke(s){return s=s|0,(n[(tT()|0)+24>>2]|0)+(s*12|0)|0}function $ke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),eQe(d,c),d=tQe(d,c)|0,tf[f&31](s,d),C=m}function eQe(s,l){s=s|0,l=l|0}function tQe(s,l){return s=s|0,l=l|0,rQe(l)|0}function rQe(s){return s=s|0,s|0}function nQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],iQe(s,c,d,0),C=f}function iQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=rT()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=sQe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,oQe(m,f)|0,f),C=d}function rT(){var s=0,l=0;if(o[7792]|0||(z5(9900),tr(43,9900,U|0)|0,l=7792,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9900)|0)){s=9900,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));z5(9900)}return 9900}function sQe(s){return s=s|0,0}function oQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=rT()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],J5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(aQe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function J5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function aQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=lQe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,cQe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],J5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,uQe(s,k),AQe(k),C=O;return}}function lQe(s){return s=s|0,357913941}function cQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function uQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function AQe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function z5(s){s=s|0,hQe(s)}function fQe(s){s=s|0,pQe(s+24|0)}function pQe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function hQe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,22,l,gQe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function gQe(){return 1344}function dQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;c=C,C=C+16|0,f=c+8|0,d=c,m=mQe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],yQe(l,f),C=c}function mQe(s){return s=s|0,(n[(rT()|0)+24>>2]|0)+(s*12|0)|0}function yQe(s,l){s=s|0,l=l|0;var c=0;c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),ef[c&127](s)}function EQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=nT()|0,s=CQe(c)|0,hn(m,l,d,s,wQe(c,f)|0,f)}function nT(){var s=0,l=0;if(o[7800]|0||(Z5(9936),tr(44,9936,U|0)|0,l=7800,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9936)|0)){s=9936,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));Z5(9936)}return 9936}function CQe(s){return s=s|0,s|0}function wQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=nT()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(X5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(IQe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function X5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function IQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=BQe(s)|0,f>>>0>>0)zr(s);else{Q=n[s>>2]|0,M=(n[s+8>>2]|0)-Q|0,O=M>>2,vQe(d,M>>3>>>0>>1>>>0?O>>>0>>0?B:O:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,X5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,DQe(s,d),PQe(d),C=k;return}}function BQe(s){return s=s|0,536870911}function vQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Tt();else{d=Vt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function DQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function PQe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&>(s)}function Z5(s){s=s|0,bQe(s)}function SQe(s){s=s|0,xQe(s+24|0)}function xQe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function bQe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,1,23,l,P5()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function kQe(s,l){s=s|0,l=l|0,FQe(n[(QQe(s)|0)>>2]|0,l)}function QQe(s){return s=s|0,(n[(nT()|0)+24>>2]|0)+(s<<3)|0}function FQe(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,qF(f,l),l=GF(f,l)|0,ef[s&127](l),C=c}function TQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=iT()|0,s=RQe(c)|0,hn(m,l,d,s,NQe(c,f)|0,f)}function iT(){var s=0,l=0;if(o[7808]|0||(e9(9972),tr(45,9972,U|0)|0,l=7808,n[l>>2]=1,n[l+4>>2]=0),!(Rr(9972)|0)){s=9972,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));e9(9972)}return 9972}function RQe(s){return s=s|0,s|0}function NQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=iT()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?($5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(LQe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function $5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function LQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=MQe(s)|0,f>>>0>>0)zr(s);else{Q=n[s>>2]|0,M=(n[s+8>>2]|0)-Q|0,O=M>>2,OQe(d,M>>3>>>0>>1>>>0?O>>>0>>0?B:O:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,$5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,UQe(s,d),_Qe(d),C=k;return}}function MQe(s){return s=s|0,536870911}function OQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Tt();else{d=Vt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function UQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function _Qe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&>(s)}function e9(s){s=s|0,qQe(s)}function HQe(s){s=s|0,jQe(s+24|0)}function jQe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function qQe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,1,9,l,GQe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function GQe(){return 1348}function YQe(s,l){return s=s|0,l=l|0,VQe(n[(WQe(s)|0)>>2]|0,l)|0}function WQe(s){return s=s|0,(n[(iT()|0)+24>>2]|0)+(s<<3)|0}function VQe(s,l){s=s|0,l=l|0;var c=0,f=0;return c=C,C=C+16|0,f=c,t9(f,l),l=r9(f,l)|0,l=sD(Ng[s&31](l)|0)|0,C=c,l|0}function t9(s,l){s=s|0,l=l|0}function r9(s,l){return s=s|0,l=l|0,KQe(l)|0}function KQe(s){return s=s|0,s|0}function JQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=sT()|0,s=zQe(c)|0,hn(m,l,d,s,XQe(c,f)|0,f)}function sT(){var s=0,l=0;if(o[7816]|0||(i9(10008),tr(46,10008,U|0)|0,l=7816,n[l>>2]=1,n[l+4>>2]=0),!(Rr(10008)|0)){s=10008,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));i9(10008)}return 10008}function zQe(s){return s=s|0,s|0}function XQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=sT()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(n9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(ZQe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function n9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function ZQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=$Qe(s)|0,f>>>0>>0)zr(s);else{Q=n[s>>2]|0,M=(n[s+8>>2]|0)-Q|0,O=M>>2,eFe(d,M>>3>>>0>>1>>>0?O>>>0>>0?B:O:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,n9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,tFe(s,d),rFe(d),C=k;return}}function $Qe(s){return s=s|0,536870911}function eFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Tt();else{d=Vt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function tFe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function rFe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&>(s)}function i9(s){s=s|0,sFe(s)}function nFe(s){s=s|0,iFe(s+24|0)}function iFe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function sFe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,1,15,l,C5()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function oFe(s){return s=s|0,lFe(n[(aFe(s)|0)>>2]|0)|0}function aFe(s){return s=s|0,(n[(sT()|0)+24>>2]|0)+(s<<3)|0}function lFe(s){return s=s|0,sD(CD[s&7]()|0)|0}function cFe(){var s=0;return o[7832]|0||(mFe(10052),tr(25,10052,U|0)|0,s=7832,n[s>>2]=1,n[s+4>>2]=0),10052}function uFe(s,l){s=s|0,l=l|0,n[s>>2]=AFe()|0,n[s+4>>2]=fFe()|0,n[s+12>>2]=l,n[s+8>>2]=pFe()|0,n[s+32>>2]=2}function AFe(){return 11709}function fFe(){return 1188}function pFe(){return aD()|0}function hFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(Sp(f,896)|0)==512?c|0&&(gFe(c),gt(c)):l|0&&(Pu(l),gt(l))}function Sp(s,l){return s=s|0,l=l|0,l&s|0}function gFe(s){s=s|0,s=n[s+4>>2]|0,s|0&&bp(s)}function aD(){var s=0;return o[7824]|0||(n[2511]=dFe()|0,n[2512]=0,s=7824,n[s>>2]=1,n[s+4>>2]=0),10044}function dFe(){return 0}function mFe(s){s=s|0,Bp(s)}function yFe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0;l=C,C=C+32|0,c=l+24|0,m=l+16|0,d=l+8|0,f=l,EFe(s,4827),CFe(s,4834,3)|0,wFe(s,3682,47)|0,n[m>>2]=9,n[m+4>>2]=0,n[c>>2]=n[m>>2],n[c+4>>2]=n[m+4>>2],IFe(s,4841,c)|0,n[d>>2]=1,n[d+4>>2]=0,n[c>>2]=n[d>>2],n[c+4>>2]=n[d+4>>2],BFe(s,4871,c)|0,n[f>>2]=10,n[f+4>>2]=0,n[c>>2]=n[f>>2],n[c+4>>2]=n[f+4>>2],vFe(s,4891,c)|0,C=l}function EFe(s,l){s=s|0,l=l|0;var c=0;c=rRe()|0,n[s>>2]=c,nRe(c,l),xp(n[s>>2]|0)}function CFe(s,l,c){return s=s|0,l=l|0,c=c|0,_Te(s,pn(l)|0,c,0),s|0}function wFe(s,l,c){return s=s|0,l=l|0,c=c|0,DTe(s,pn(l)|0,c,0),s|0}function IFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],oTe(s,l,d),C=f,s|0}function BFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],HFe(s,l,d),C=f,s|0}function vFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],DFe(s,l,d),C=f,s|0}function DFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],PFe(s,c,d,1),C=f}function PFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=oT()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=SFe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,xFe(m,f)|0,f),C=d}function oT(){var s=0,l=0;if(o[7840]|0||(o9(10100),tr(48,10100,U|0)|0,l=7840,n[l>>2]=1,n[l+4>>2]=0),!(Rr(10100)|0)){s=10100,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));o9(10100)}return 10100}function SFe(s){return s=s|0,0}function xFe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=oT()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],s9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(bFe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function s9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function bFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=kFe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,QFe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],s9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,FFe(s,k),TFe(k),C=O;return}}function kFe(s){return s=s|0,357913941}function QFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function FFe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function TFe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function o9(s){s=s|0,LFe(s)}function RFe(s){s=s|0,NFe(s+24|0)}function NFe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function LFe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,6,l,MFe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function MFe(){return 1364}function OFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=UFe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],c=_Fe(l,d,c)|0,C=f,c|0}function UFe(s){return s=s|0,(n[(oT()|0)+24>>2]|0)+(s*12|0)|0}function _Fe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;return m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),XA(d,c),d=ZA(d,c)|0,d=p5(NT[f&15](s,d)|0)|0,C=m,d|0}function HFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],jFe(s,c,d,0),C=f}function jFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=aT()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=qFe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,GFe(m,f)|0,f),C=d}function aT(){var s=0,l=0;if(o[7848]|0||(l9(10136),tr(49,10136,U|0)|0,l=7848,n[l>>2]=1,n[l+4>>2]=0),!(Rr(10136)|0)){s=10136,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));l9(10136)}return 10136}function qFe(s){return s=s|0,0}function GFe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=aT()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],a9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(YFe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function a9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function YFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=WFe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,VFe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],a9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,KFe(s,k),JFe(k),C=O;return}}function WFe(s){return s=s|0,357913941}function VFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function KFe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function JFe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function l9(s){s=s|0,ZFe(s)}function zFe(s){s=s|0,XFe(s+24|0)}function XFe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function ZFe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,9,l,$Fe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function $Fe(){return 1372}function eTe(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=tTe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],rTe(l,d,c),C=f}function tTe(s){return s=s|0,(n[(aT()|0)+24>>2]|0)+(s*12|0)|0}function rTe(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0,B=Ze;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),nTe(d,c),B=y(iTe(d,c)),I7[f&1](s,B),C=m}function nTe(s,l){s=s|0,l=+l}function iTe(s,l){return s=s|0,l=+l,y(sTe(l))}function sTe(s){return s=+s,y(s)}function oTe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],aTe(s,c,d,0),C=f}function aTe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,O=0,M=0;d=C,C=C+32|0,m=d+16|0,M=d+8|0,k=d,O=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=lT()|0,n[M>>2]=O,n[M+4>>2]=Q,n[m>>2]=n[M>>2],n[m+4>>2]=n[M+4>>2],c=lTe(m)|0,n[k>>2]=O,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,cTe(m,f)|0,f),C=d}function lT(){var s=0,l=0;if(o[7856]|0||(u9(10172),tr(50,10172,U|0)|0,l=7856,n[l>>2]=1,n[l+4>>2]=0),!(Rr(10172)|0)){s=10172,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));u9(10172)}return 10172}function lTe(s){return s=s|0,0}function cTe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0;return M=C,C=C+32|0,d=M+24|0,B=M+16|0,k=M,Q=M+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=lT()|0,O=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],c9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(uTe(O,k,Q),s=n[l>>2]|0),C=M,((s-(n[O>>2]|0)|0)/12|0)+-1|0}function c9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function uTe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;if(O=C,C=C+48|0,f=O+32|0,B=O+24|0,k=O,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=ATe(s)|0,m>>>0>>0)zr(s);else{M=n[s>>2]|0,se=((n[s+8>>2]|0)-M|0)/12|0,q=se<<1,fTe(k,se>>>0>>1>>>0?q>>>0>>0?d:q:m,((n[Q>>2]|0)-M|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],c9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,pTe(s,k),hTe(k),C=O;return}}function ATe(s){return s=s|0,357913941}function fTe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Tt();else{d=Vt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function pTe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function hTe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&>(s)}function u9(s){s=s|0,mTe(s)}function gTe(s){s=s|0,dTe(s+24|0)}function dTe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function mTe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,2,3,l,yTe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function yTe(){return 1380}function ETe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+16|0,m=d+8|0,B=d,k=CTe(s)|0,s=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=s,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],wTe(l,m,c,f),C=d}function CTe(s){return s=s|0,(n[(lT()|0)+24>>2]|0)+(s*12|0)|0}function wTe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;k=C,C=C+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(d=n[(n[s>>2]|0)+d>>2]|0),XA(m,c),m=ZA(m,c)|0,ITe(B,f),B=BTe(B,f)|0,_w[d&15](s,m,B),C=k}function ITe(s,l){s=s|0,l=l|0}function BTe(s,l){return s=s|0,l=l|0,vTe(l)|0}function vTe(s){return s=s|0,(s|0)!=0|0}function DTe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=cT()|0,s=PTe(c)|0,hn(m,l,d,s,STe(c,f)|0,f)}function cT(){var s=0,l=0;if(o[7864]|0||(f9(10208),tr(51,10208,U|0)|0,l=7864,n[l>>2]=1,n[l+4>>2]=0),!(Rr(10208)|0)){s=10208,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));f9(10208)}return 10208}function PTe(s){return s=s|0,s|0}function STe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=cT()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(A9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(xTe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function A9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function xTe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=bTe(s)|0,f>>>0>>0)zr(s);else{Q=n[s>>2]|0,M=(n[s+8>>2]|0)-Q|0,O=M>>2,kTe(d,M>>3>>>0>>1>>>0?O>>>0>>0?B:O:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,A9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,QTe(s,d),FTe(d),C=k;return}}function bTe(s){return s=s|0,536870911}function kTe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Tt();else{d=Vt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function QTe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function FTe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&>(s)}function f9(s){s=s|0,NTe(s)}function TTe(s){s=s|0,RTe(s+24|0)}function RTe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function NTe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,1,24,l,LTe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function LTe(){return 1392}function MTe(s,l){s=s|0,l=l|0,UTe(n[(OTe(s)|0)>>2]|0,l)}function OTe(s){return s=s|0,(n[(cT()|0)+24>>2]|0)+(s<<3)|0}function UTe(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,t9(f,l),l=r9(f,l)|0,ef[s&127](l),C=c}function _Te(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=uT()|0,s=HTe(c)|0,hn(m,l,d,s,jTe(c,f)|0,f)}function uT(){var s=0,l=0;if(o[7872]|0||(h9(10244),tr(52,10244,U|0)|0,l=7872,n[l>>2]=1,n[l+4>>2]=0),!(Rr(10244)|0)){s=10244,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));h9(10244)}return 10244}function HTe(s){return s=s|0,s|0}function jTe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=uT()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(p9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(qTe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function p9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function qTe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=GTe(s)|0,f>>>0>>0)zr(s);else{Q=n[s>>2]|0,M=(n[s+8>>2]|0)-Q|0,O=M>>2,YTe(d,M>>3>>>0>>1>>>0?O>>>0>>0?B:O:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,p9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,WTe(s,d),VTe(d),C=k;return}}function GTe(s){return s=s|0,536870911}function YTe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Tt();else{d=Vt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function WTe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function VTe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&>(s)}function h9(s){s=s|0,zTe(s)}function KTe(s){s=s|0,JTe(s+24|0)}function JTe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function zTe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,1,16,l,XTe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function XTe(){return 1400}function ZTe(s){return s=s|0,eRe(n[($Te(s)|0)>>2]|0)|0}function $Te(s){return s=s|0,(n[(uT()|0)+24>>2]|0)+(s<<3)|0}function eRe(s){return s=s|0,tRe(CD[s&7]()|0)|0}function tRe(s){return s=s|0,s|0}function rRe(){var s=0;return o[7880]|0||(cRe(10280),tr(25,10280,U|0)|0,s=7880,n[s>>2]=1,n[s+4>>2]=0),10280}function nRe(s,l){s=s|0,l=l|0,n[s>>2]=iRe()|0,n[s+4>>2]=sRe()|0,n[s+12>>2]=l,n[s+8>>2]=oRe()|0,n[s+32>>2]=4}function iRe(){return 11711}function sRe(){return 1356}function oRe(){return aD()|0}function aRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(Sp(f,896)|0)==512?c|0&&(lRe(c),gt(c)):l|0&&(vg(l),gt(l))}function lRe(s){s=s|0,s=n[s+4>>2]|0,s|0&&bp(s)}function cRe(s){s=s|0,Bp(s)}function uRe(s){s=s|0,ARe(s,4920),fRe(s)|0,pRe(s)|0}function ARe(s,l){s=s|0,l=l|0;var c=0;c=L5()|0,n[s>>2]=c,RRe(c,l),xp(n[s>>2]|0)}function fRe(s){s=s|0;var l=0;return l=n[s>>2]|0,bg(l,vRe()|0),s|0}function pRe(s){s=s|0;var l=0;return l=n[s>>2]|0,bg(l,hRe()|0),s|0}function hRe(){var s=0;return o[7888]|0||(g9(10328),tr(53,10328,U|0)|0,s=7888,n[s>>2]=1,n[s+4>>2]=0),Rr(10328)|0||g9(10328),10328}function bg(s,l){s=s|0,l=l|0,hn(s,0,l,0,0,0)}function g9(s){s=s|0,mRe(s),kg(s,10)}function gRe(s){s=s|0,dRe(s+24|0)}function dRe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function mRe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,5,1,l,wRe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function yRe(s,l,c){s=s|0,l=l|0,c=+c,ERe(s,l,c)}function kg(s,l){s=s|0,l=l|0,n[s+20>>2]=l}function ERe(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,m=f+8|0,k=f+13|0,d=f,B=f+12|0,XA(k,l),n[m>>2]=ZA(k,l)|0,ku(B,c),E[d>>3]=+Qu(B,c),CRe(s,m,d),C=f}function CRe(s,l,c){s=s|0,l=l|0,c=c|0,Y(s+8|0,n[l>>2]|0,+E[c>>3]),o[s+24>>0]=1}function wRe(){return 1404}function IRe(s,l){return s=s|0,l=+l,BRe(s,l)|0}function BRe(s,l){s=s|0,l=+l;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return f=C,C=C+16|0,m=f+4|0,B=f+8|0,k=f,d=Wa(8)|0,c=d,Q=Vt(16)|0,XA(m,s),s=ZA(m,s)|0,ku(B,l),Y(Q,s,+Qu(B,l)),B=c+4|0,n[B>>2]=Q,s=Vt(8)|0,B=n[B>>2]|0,n[k>>2]=0,n[m>>2]=n[k>>2],JF(s,B,m),n[d>>2]=s,C=f,c|0}function vRe(){var s=0;return o[7896]|0||(d9(10364),tr(54,10364,U|0)|0,s=7896,n[s>>2]=1,n[s+4>>2]=0),Rr(10364)|0||d9(10364),10364}function d9(s){s=s|0,SRe(s),kg(s,55)}function DRe(s){s=s|0,PRe(s+24|0)}function PRe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function SRe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,5,4,l,QRe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function xRe(s){s=s|0,bRe(s)}function bRe(s){s=s|0,kRe(s)}function kRe(s){s=s|0,m9(s+8|0),o[s+24>>0]=1}function m9(s){s=s|0,n[s>>2]=0,E[s+8>>3]=0}function QRe(){return 1424}function FRe(){return TRe()|0}function TRe(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0;return l=C,C=C+16|0,d=l+4|0,B=l,c=Wa(8)|0,s=c,f=Vt(16)|0,m9(f),m=s+4|0,n[m>>2]=f,f=Vt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],JF(f,m,d),n[c>>2]=f,C=l,s|0}function RRe(s,l){s=s|0,l=l|0,n[s>>2]=NRe()|0,n[s+4>>2]=LRe()|0,n[s+12>>2]=l,n[s+8>>2]=MRe()|0,n[s+32>>2]=5}function NRe(){return 11710}function LRe(){return 1416}function MRe(){return lD()|0}function ORe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(Sp(f,896)|0)==512?c|0&&(URe(c),gt(c)):l|0&>(l)}function URe(s){s=s|0,s=n[s+4>>2]|0,s|0&&bp(s)}function lD(){var s=0;return o[7904]|0||(n[2600]=_Re()|0,n[2601]=0,s=7904,n[s>>2]=1,n[s+4>>2]=0),10400}function _Re(){return n[357]|0}function HRe(s){s=s|0,jRe(s,4926),qRe(s)|0}function jRe(s,l){s=s|0,l=l|0;var c=0;c=s5()|0,n[s>>2]=c,eNe(c,l),xp(n[s>>2]|0)}function qRe(s){s=s|0;var l=0;return l=n[s>>2]|0,bg(l,GRe()|0),s|0}function GRe(){var s=0;return o[7912]|0||(y9(10412),tr(56,10412,U|0)|0,s=7912,n[s>>2]=1,n[s+4>>2]=0),Rr(10412)|0||y9(10412),10412}function y9(s){s=s|0,VRe(s),kg(s,57)}function YRe(s){s=s|0,WRe(s+24|0)}function WRe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function VRe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,5,5,l,XRe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function KRe(s){s=s|0,JRe(s)}function JRe(s){s=s|0,zRe(s)}function zRe(s){s=s|0;var l=0,c=0;l=s+8|0,c=l+48|0;do n[l>>2]=0,l=l+4|0;while((l|0)<(c|0));o[s+56>>0]=1}function XRe(){return 1432}function ZRe(){return $Re()|0}function $Re(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0,k=0;B=C,C=C+16|0,s=B+4|0,l=B,c=Wa(8)|0,f=c,d=Vt(48)|0,m=d,k=m+48|0;do n[m>>2]=0,m=m+4|0;while((m|0)<(k|0));return m=f+4|0,n[m>>2]=d,k=Vt(8)|0,m=n[m>>2]|0,n[l>>2]=0,n[s>>2]=n[l>>2],o5(k,m,s),n[c>>2]=k,C=B,f|0}function eNe(s,l){s=s|0,l=l|0,n[s>>2]=tNe()|0,n[s+4>>2]=rNe()|0,n[s+12>>2]=l,n[s+8>>2]=nNe()|0,n[s+32>>2]=6}function tNe(){return 11704}function rNe(){return 1436}function nNe(){return lD()|0}function iNe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(Sp(f,896)|0)==512?c|0&&(sNe(c),gt(c)):l|0&>(l)}function sNe(s){s=s|0,s=n[s+4>>2]|0,s|0&&bp(s)}function oNe(s){s=s|0,aNe(s,4933),lNe(s)|0,cNe(s)|0}function aNe(s,l){s=s|0,l=l|0;var c=0;c=TNe()|0,n[s>>2]=c,RNe(c,l),xp(n[s>>2]|0)}function lNe(s){s=s|0;var l=0;return l=n[s>>2]|0,bg(l,BNe()|0),s|0}function cNe(s){s=s|0;var l=0;return l=n[s>>2]|0,bg(l,uNe()|0),s|0}function uNe(){var s=0;return o[7920]|0||(E9(10452),tr(58,10452,U|0)|0,s=7920,n[s>>2]=1,n[s+4>>2]=0),Rr(10452)|0||E9(10452),10452}function E9(s){s=s|0,pNe(s),kg(s,1)}function ANe(s){s=s|0,fNe(s+24|0)}function fNe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function pNe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,5,1,l,mNe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function hNe(s,l,c){s=s|0,l=+l,c=+c,gNe(s,l,c)}function gNe(s,l,c){s=s|0,l=+l,c=+c;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+32|0,m=f+8|0,k=f+17|0,d=f,B=f+16|0,ku(k,l),E[m>>3]=+Qu(k,l),ku(B,c),E[d>>3]=+Qu(B,c),dNe(s,m,d),C=f}function dNe(s,l,c){s=s|0,l=l|0,c=c|0,C9(s+8|0,+E[l>>3],+E[c>>3]),o[s+24>>0]=1}function C9(s,l,c){s=s|0,l=+l,c=+c,E[s>>3]=l,E[s+8>>3]=c}function mNe(){return 1472}function yNe(s,l){return s=+s,l=+l,ENe(s,l)|0}function ENe(s,l){s=+s,l=+l;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return f=C,C=C+16|0,B=f+4|0,k=f+8|0,Q=f,d=Wa(8)|0,c=d,m=Vt(16)|0,ku(B,s),s=+Qu(B,s),ku(k,l),C9(m,s,+Qu(k,l)),k=c+4|0,n[k>>2]=m,m=Vt(8)|0,k=n[k>>2]|0,n[Q>>2]=0,n[B>>2]=n[Q>>2],w9(m,k,B),n[d>>2]=m,C=f,c|0}function w9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Vt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1452,n[c+12>>2]=l,n[s+4>>2]=c}function CNe(s){s=s|0,Jm(s),gt(s)}function wNe(s){s=s|0,s=n[s+12>>2]|0,s|0&>(s)}function INe(s){s=s|0,gt(s)}function BNe(){var s=0;return o[7928]|0||(I9(10488),tr(59,10488,U|0)|0,s=7928,n[s>>2]=1,n[s+4>>2]=0),Rr(10488)|0||I9(10488),10488}function I9(s){s=s|0,PNe(s),kg(s,60)}function vNe(s){s=s|0,DNe(s+24|0)}function DNe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function PNe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,5,6,l,kNe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function SNe(s){s=s|0,xNe(s)}function xNe(s){s=s|0,bNe(s)}function bNe(s){s=s|0,B9(s+8|0),o[s+24>>0]=1}function B9(s){s=s|0,n[s>>2]=0,n[s+4>>2]=0,n[s+8>>2]=0,n[s+12>>2]=0}function kNe(){return 1492}function QNe(){return FNe()|0}function FNe(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0;return l=C,C=C+16|0,d=l+4|0,B=l,c=Wa(8)|0,s=c,f=Vt(16)|0,B9(f),m=s+4|0,n[m>>2]=f,f=Vt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],w9(f,m,d),n[c>>2]=f,C=l,s|0}function TNe(){var s=0;return o[7936]|0||(_Ne(10524),tr(25,10524,U|0)|0,s=7936,n[s>>2]=1,n[s+4>>2]=0),10524}function RNe(s,l){s=s|0,l=l|0,n[s>>2]=NNe()|0,n[s+4>>2]=LNe()|0,n[s+12>>2]=l,n[s+8>>2]=MNe()|0,n[s+32>>2]=7}function NNe(){return 11700}function LNe(){return 1484}function MNe(){return lD()|0}function ONe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(Sp(f,896)|0)==512?c|0&&(UNe(c),gt(c)):l|0&>(l)}function UNe(s){s=s|0,s=n[s+4>>2]|0,s|0&&bp(s)}function _Ne(s){s=s|0,Bp(s)}function HNe(s,l,c){s=s|0,l=l|0,c=c|0,s=pn(l)|0,l=jNe(c)|0,c=qNe(c,0)|0,ELe(s,l,c,AT()|0,0)}function jNe(s){return s=s|0,s|0}function qNe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=AT()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(D9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(zNe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function AT(){var s=0,l=0;if(o[7944]|0||(v9(10568),tr(61,10568,U|0)|0,l=7944,n[l>>2]=1,n[l+4>>2]=0),!(Rr(10568)|0)){s=10568,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));v9(10568)}return 10568}function v9(s){s=s|0,WNe(s)}function GNe(s){s=s|0,YNe(s+24|0)}function YNe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function WNe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,1,17,l,B5()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function VNe(s){return s=s|0,JNe(n[(KNe(s)|0)>>2]|0)|0}function KNe(s){return s=s|0,(n[(AT()|0)+24>>2]|0)+(s<<3)|0}function JNe(s){return s=s|0,oD(CD[s&7]()|0)|0}function D9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function zNe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=XNe(s)|0,f>>>0>>0)zr(s);else{Q=n[s>>2]|0,M=(n[s+8>>2]|0)-Q|0,O=M>>2,ZNe(d,M>>3>>>0>>1>>>0?O>>>0>>0?B:O:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,D9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,$Ne(s,d),eLe(d),C=k;return}}function XNe(s){return s=s|0,536870911}function ZNe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Tt();else{d=Vt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function $Ne(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function eLe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&>(s)}function tLe(){rLe()}function rLe(){nLe(10604)}function nLe(s){s=s|0,iLe(s,4955)}function iLe(s,l){s=s|0,l=l|0;var c=0;c=sLe()|0,n[s>>2]=c,oLe(c,l),xp(n[s>>2]|0)}function sLe(){var s=0;return o[7952]|0||(gLe(10612),tr(25,10612,U|0)|0,s=7952,n[s>>2]=1,n[s+4>>2]=0),10612}function oLe(s,l){s=s|0,l=l|0,n[s>>2]=uLe()|0,n[s+4>>2]=ALe()|0,n[s+12>>2]=l,n[s+8>>2]=fLe()|0,n[s+32>>2]=8}function xp(s){s=s|0;var l=0,c=0;l=C,C=C+16|0,c=l,Gm()|0,n[c>>2]=s,aLe(10608,c),C=l}function Gm(){return o[11714]|0||(n[2652]=0,tr(62,10608,U|0)|0,o[11714]=1),10608}function aLe(s,l){s=s|0,l=l|0;var c=0;c=Vt(8)|0,n[c+4>>2]=n[l>>2],n[c>>2]=n[s>>2],n[s>>2]=c}function lLe(s){s=s|0,cLe(s)}function cLe(s){s=s|0;var l=0,c=0;if(l=n[s>>2]|0,l|0)do c=l,l=n[l>>2]|0,gt(c);while((l|0)!=0);n[s>>2]=0}function uLe(){return 11715}function ALe(){return 1496}function fLe(){return aD()|0}function pLe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(Sp(f,896)|0)==512?c|0&&(hLe(c),gt(c)):l|0&>(l)}function hLe(s){s=s|0,s=n[s+4>>2]|0,s|0&&bp(s)}function gLe(s){s=s|0,Bp(s)}function dLe(s,l){s=s|0,l=l|0;var c=0,f=0;Gm()|0,c=n[2652]|0;e:do if(c|0){for(;f=n[c+4>>2]|0,!(f|0&&(o7(fT(f)|0,s)|0)==0);)if(c=n[c>>2]|0,!c)break e;mLe(f,l)}while(0)}function fT(s){return s=s|0,n[s+12>>2]|0}function mLe(s,l){s=s|0,l=l|0;var c=0;s=s+36|0,c=n[s>>2]|0,c|0&&(jA(c),gt(c)),c=Vt(4)|0,$G(c,l),n[s>>2]=c}function pT(){return o[11716]|0||(n[2664]=0,tr(63,10656,U|0)|0,o[11716]=1),10656}function P9(){var s=0;return o[11717]|0?s=n[2665]|0:(yLe(),n[2665]=1504,o[11717]=1,s=1504),s|0}function yLe(){o[11740]|0||(o[11718]=gr(gr(8,0)|0,0)|0,o[11719]=gr(gr(0,0)|0,0)|0,o[11720]=gr(gr(0,16)|0,0)|0,o[11721]=gr(gr(8,0)|0,0)|0,o[11722]=gr(gr(0,0)|0,0)|0,o[11723]=gr(gr(8,0)|0,0)|0,o[11724]=gr(gr(0,0)|0,0)|0,o[11725]=gr(gr(8,0)|0,0)|0,o[11726]=gr(gr(0,0)|0,0)|0,o[11727]=gr(gr(8,0)|0,0)|0,o[11728]=gr(gr(0,0)|0,0)|0,o[11729]=gr(gr(0,0)|0,32)|0,o[11730]=gr(gr(0,0)|0,32)|0,o[11740]=1)}function S9(){return 1572}function ELe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,O=0,M=0;m=C,C=C+32|0,M=m+16|0,O=m+12|0,Q=m+8|0,k=m+4|0,B=m,n[M>>2]=s,n[O>>2]=l,n[Q>>2]=c,n[k>>2]=f,n[B>>2]=d,pT()|0,CLe(10656,M,O,Q,k,B),C=m}function CLe(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0;B=Vt(24)|0,r5(B+4|0,n[l>>2]|0,n[c>>2]|0,n[f>>2]|0,n[d>>2]|0,n[m>>2]|0),n[B>>2]=n[s>>2],n[s>>2]=B}function x9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0,Ge=0,Oe=0,Fe=0,et=0,Xe=0,at=0;if(at=C,C=C+32|0,Oe=at+20|0,Fe=at+8|0,et=at+4|0,Xe=at,l=n[l>>2]|0,l|0){Ge=Oe+4|0,Q=Oe+8|0,O=Fe+4|0,M=Fe+8|0,q=Fe+8|0,se=Oe+8|0;do{if(B=l+4|0,k=hT(B)|0,k|0){if(d=Rw(k)|0,n[Oe>>2]=0,n[Ge>>2]=0,n[Q>>2]=0,f=(Nw(k)|0)+1|0,wLe(Oe,f),f|0)for(;f=f+-1|0,xc(Fe,n[d>>2]|0),m=n[Ge>>2]|0,m>>>0<(n[se>>2]|0)>>>0?(n[m>>2]=n[Fe>>2],n[Ge>>2]=(n[Ge>>2]|0)+4):gT(Oe,Fe),f;)d=d+4|0;f=Lw(k)|0,n[Fe>>2]=0,n[O>>2]=0,n[M>>2]=0;e:do if(n[f>>2]|0)for(d=0,m=0;;){if((d|0)==(m|0)?ILe(Fe,f):(n[d>>2]=n[f>>2],n[O>>2]=(n[O>>2]|0)+4),f=f+4|0,!(n[f>>2]|0))break e;d=n[O>>2]|0,m=n[q>>2]|0}while(0);n[et>>2]=cD(B)|0,n[Xe>>2]=Rr(k)|0,BLe(c,s,et,Xe,Oe,Fe),dT(Fe),$A(Oe)}l=n[l>>2]|0}while((l|0)!=0)}C=at}function hT(s){return s=s|0,n[s+12>>2]|0}function Rw(s){return s=s|0,n[s+12>>2]|0}function Nw(s){return s=s|0,n[s+16>>2]|0}function wLe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;d=C,C=C+32|0,c=d,f=n[s>>2]|0,(n[s+8>>2]|0)-f>>2>>>0>>0&&(L9(c,l,(n[s+4>>2]|0)-f>>2,s+8|0),M9(s,c),O9(c)),C=d}function gT(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0;if(B=C,C=C+32|0,c=B,f=s+4|0,d=((n[f>>2]|0)-(n[s>>2]|0)>>2)+1|0,m=N9(s)|0,m>>>0>>0)zr(s);else{k=n[s>>2]|0,O=(n[s+8>>2]|0)-k|0,Q=O>>1,L9(c,O>>2>>>0>>1>>>0?Q>>>0>>0?d:Q:m,(n[f>>2]|0)-k>>2,s+8|0),m=c+8|0,n[n[m>>2]>>2]=n[l>>2],n[m>>2]=(n[m>>2]|0)+4,M9(s,c),O9(c),C=B;return}}function Lw(s){return s=s|0,n[s+8>>2]|0}function ILe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0;if(B=C,C=C+32|0,c=B,f=s+4|0,d=((n[f>>2]|0)-(n[s>>2]|0)>>2)+1|0,m=R9(s)|0,m>>>0>>0)zr(s);else{k=n[s>>2]|0,O=(n[s+8>>2]|0)-k|0,Q=O>>1,jLe(c,O>>2>>>0>>1>>>0?Q>>>0>>0?d:Q:m,(n[f>>2]|0)-k>>2,s+8|0),m=c+8|0,n[n[m>>2]>>2]=n[l>>2],n[m>>2]=(n[m>>2]|0)+4,qLe(s,c),GLe(c),C=B;return}}function cD(s){return s=s|0,n[s>>2]|0}function BLe(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,vLe(s,l,c,f,d,m)}function dT(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-4-f|0)>>>2)<<2)),gt(c))}function $A(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-4-f|0)>>>2)<<2)),gt(c))}function vLe(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,O=0,M=0,q=0;B=C,C=C+48|0,M=B+40|0,k=B+32|0,q=B+24|0,Q=B+12|0,O=B,Va(k),s=da(s)|0,n[q>>2]=n[l>>2],c=n[c>>2]|0,f=n[f>>2]|0,mT(Q,d),DLe(O,m),n[M>>2]=n[q>>2],PLe(s,M,c,f,Q,O),dT(O),$A(Q),Ka(k),C=B}function mT(s,l){s=s|0,l=l|0;var c=0,f=0;n[s>>2]=0,n[s+4>>2]=0,n[s+8>>2]=0,c=l+4|0,f=(n[c>>2]|0)-(n[l>>2]|0)>>2,f|0&&(_Le(s,f),HLe(s,n[l>>2]|0,n[c>>2]|0,f))}function DLe(s,l){s=s|0,l=l|0;var c=0,f=0;n[s>>2]=0,n[s+4>>2]=0,n[s+8>>2]=0,c=l+4|0,f=(n[c>>2]|0)-(n[l>>2]|0)>>2,f|0&&(OLe(s,f),ULe(s,n[l>>2]|0,n[c>>2]|0,f))}function PLe(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,O=0,M=0,q=0;B=C,C=C+32|0,M=B+28|0,q=B+24|0,k=B+12|0,Q=B,O=Pl(SLe()|0)|0,n[q>>2]=n[l>>2],n[M>>2]=n[q>>2],l=Qg(M)|0,c=b9(c)|0,f=yT(f)|0,n[k>>2]=n[d>>2],M=d+4|0,n[k+4>>2]=n[M>>2],q=d+8|0,n[k+8>>2]=n[q>>2],n[q>>2]=0,n[M>>2]=0,n[d>>2]=0,d=ET(k)|0,n[Q>>2]=n[m>>2],M=m+4|0,n[Q+4>>2]=n[M>>2],q=m+8|0,n[Q+8>>2]=n[q>>2],n[q>>2]=0,n[M>>2]=0,n[m>>2]=0,ao(0,O|0,s|0,l|0,c|0,f|0,d|0,xLe(Q)|0)|0,dT(Q),$A(k),C=B}function SLe(){var s=0;return o[7968]|0||(LLe(10708),s=7968,n[s>>2]=1,n[s+4>>2]=0),10708}function Qg(s){return s=s|0,Q9(s)|0}function b9(s){return s=s|0,k9(s)|0}function yT(s){return s=s|0,oD(s)|0}function ET(s){return s=s|0,kLe(s)|0}function xLe(s){return s=s|0,bLe(s)|0}function bLe(s){s=s|0;var l=0,c=0,f=0;if(f=(n[s+4>>2]|0)-(n[s>>2]|0)|0,c=f>>2,f=Wa(f+4|0)|0,n[f>>2]=c,c|0){l=0;do n[f+4+(l<<2)>>2]=k9(n[(n[s>>2]|0)+(l<<2)>>2]|0)|0,l=l+1|0;while((l|0)!=(c|0))}return f|0}function k9(s){return s=s|0,s|0}function kLe(s){s=s|0;var l=0,c=0,f=0;if(f=(n[s+4>>2]|0)-(n[s>>2]|0)|0,c=f>>2,f=Wa(f+4|0)|0,n[f>>2]=c,c|0){l=0;do n[f+4+(l<<2)>>2]=Q9((n[s>>2]|0)+(l<<2)|0)|0,l=l+1|0;while((l|0)!=(c|0))}return f|0}function Q9(s){s=s|0;var l=0,c=0,f=0,d=0;return d=C,C=C+32|0,l=d+12|0,c=d,f=QF(F9()|0)|0,f?(FF(l,f),TF(c,l),fUe(s,c),s=RF(l)|0):s=QLe(s)|0,C=d,s|0}function F9(){var s=0;return o[7960]|0||(NLe(10664),tr(25,10664,U|0)|0,s=7960,n[s>>2]=1,n[s+4>>2]=0),10664}function QLe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0;return c=C,C=C+16|0,d=c+4|0,B=c,f=Wa(8)|0,l=f,k=Vt(4)|0,n[k>>2]=n[s>>2],m=l+4|0,n[m>>2]=k,s=Vt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],T9(s,m,d),n[f>>2]=s,C=c,l|0}function T9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Vt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1656,n[c+12>>2]=l,n[s+4>>2]=c}function FLe(s){s=s|0,Jm(s),gt(s)}function TLe(s){s=s|0,s=n[s+12>>2]|0,s|0&>(s)}function RLe(s){s=s|0,gt(s)}function NLe(s){s=s|0,Bp(s)}function LLe(s){s=s|0,Sl(s,MLe()|0,5)}function MLe(){return 1676}function OLe(s,l){s=s|0,l=l|0;var c=0;if((R9(s)|0)>>>0>>0&&zr(s),l>>>0>1073741823)Tt();else{c=Vt(l<<2)|0,n[s+4>>2]=c,n[s>>2]=c,n[s+8>>2]=c+(l<<2);return}}function ULe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,f=s+4|0,s=c-l|0,(s|0)>0&&(Dr(n[f>>2]|0,l|0,s|0)|0,n[f>>2]=(n[f>>2]|0)+(s>>>2<<2))}function R9(s){return s=s|0,1073741823}function _Le(s,l){s=s|0,l=l|0;var c=0;if((N9(s)|0)>>>0>>0&&zr(s),l>>>0>1073741823)Tt();else{c=Vt(l<<2)|0,n[s+4>>2]=c,n[s>>2]=c,n[s+8>>2]=c+(l<<2);return}}function HLe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,f=s+4|0,s=c-l|0,(s|0)>0&&(Dr(n[f>>2]|0,l|0,s|0)|0,n[f>>2]=(n[f>>2]|0)+(s>>>2<<2))}function N9(s){return s=s|0,1073741823}function jLe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>1073741823)Tt();else{d=Vt(l<<2)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<2)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<2)}function qLe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function GLe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-4-l|0)>>>2)<<2)),s=n[s>>2]|0,s|0&>(s)}function L9(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>1073741823)Tt();else{d=Vt(l<<2)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<2)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<2)}function M9(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function O9(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-4-l|0)>>>2)<<2)),s=n[s>>2]|0,s|0&>(s)}function YLe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0,Ge=0,Oe=0,Fe=0;if(Fe=C,C=C+32|0,M=Fe+20|0,q=Fe+12|0,O=Fe+16|0,se=Fe+4|0,Ge=Fe,Oe=Fe+8|0,k=P9()|0,m=n[k>>2]|0,B=n[m>>2]|0,B|0)for(Q=n[k+8>>2]|0,k=n[k+4>>2]|0;xc(M,B),WLe(s,M,k,Q),m=m+4|0,B=n[m>>2]|0,B;)Q=Q+1|0,k=k+1|0;if(m=S9()|0,B=n[m>>2]|0,B|0)do xc(M,B),n[q>>2]=n[m+4>>2],VLe(l,M,q),m=m+8|0,B=n[m>>2]|0;while((B|0)!=0);if(m=n[(Gm()|0)>>2]|0,m|0)do l=n[m+4>>2]|0,xc(M,n[(Ym(l)|0)>>2]|0),n[q>>2]=fT(l)|0,KLe(c,M,q),m=n[m>>2]|0;while((m|0)!=0);if(xc(O,0),m=pT()|0,n[M>>2]=n[O>>2],x9(M,m,d),m=n[(Gm()|0)>>2]|0,m|0){s=M+4|0,l=M+8|0,c=M+8|0;do{if(Q=n[m+4>>2]|0,xc(q,n[(Ym(Q)|0)>>2]|0),JLe(se,U9(Q)|0),B=n[se>>2]|0,B|0){n[M>>2]=0,n[s>>2]=0,n[l>>2]=0;do xc(Ge,n[(Ym(n[B+4>>2]|0)|0)>>2]|0),k=n[s>>2]|0,k>>>0<(n[c>>2]|0)>>>0?(n[k>>2]=n[Ge>>2],n[s>>2]=(n[s>>2]|0)+4):gT(M,Ge),B=n[B>>2]|0;while((B|0)!=0);zLe(f,q,M),$A(M)}n[Oe>>2]=n[q>>2],O=_9(Q)|0,n[M>>2]=n[Oe>>2],x9(M,O,d),l5(se),m=n[m>>2]|0}while((m|0)!=0)}C=Fe}function WLe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,lMe(s,l,c,f)}function VLe(s,l,c){s=s|0,l=l|0,c=c|0,aMe(s,l,c)}function Ym(s){return s=s|0,s|0}function KLe(s,l,c){s=s|0,l=l|0,c=c|0,nMe(s,l,c)}function U9(s){return s=s|0,s+16|0}function JLe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;if(m=C,C=C+16|0,d=m+8|0,c=m,n[s>>2]=0,f=n[l>>2]|0,n[d>>2]=f,n[c>>2]=s,c=rMe(c)|0,f|0){if(f=Vt(12)|0,B=(H9(d)|0)+4|0,s=n[B+4>>2]|0,l=f+4|0,n[l>>2]=n[B>>2],n[l+4>>2]=s,l=n[n[d>>2]>>2]|0,n[d>>2]=l,!l)s=f;else for(l=f;s=Vt(12)|0,Q=(H9(d)|0)+4|0,k=n[Q+4>>2]|0,B=s+4|0,n[B>>2]=n[Q>>2],n[B+4>>2]=k,n[l>>2]=s,B=n[n[d>>2]>>2]|0,n[d>>2]=B,B;)l=s;n[s>>2]=n[c>>2],n[c>>2]=f}C=m}function zLe(s,l,c){s=s|0,l=l|0,c=c|0,XLe(s,l,c)}function _9(s){return s=s|0,s+24|0}function XLe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+32|0,B=f+24|0,d=f+16|0,k=f+12|0,m=f,Va(d),s=da(s)|0,n[k>>2]=n[l>>2],mT(m,c),n[B>>2]=n[k>>2],ZLe(s,B,m),$A(m),Ka(d),C=f}function ZLe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+32|0,B=f+16|0,k=f+12|0,d=f,m=Pl($Le()|0)|0,n[k>>2]=n[l>>2],n[B>>2]=n[k>>2],l=Qg(B)|0,n[d>>2]=n[c>>2],B=c+4|0,n[d+4>>2]=n[B>>2],k=c+8|0,n[d+8>>2]=n[k>>2],n[k>>2]=0,n[B>>2]=0,n[c>>2]=0,oo(0,m|0,s|0,l|0,ET(d)|0)|0,$A(d),C=f}function $Le(){var s=0;return o[7976]|0||(eMe(10720),s=7976,n[s>>2]=1,n[s+4>>2]=0),10720}function eMe(s){s=s|0,Sl(s,tMe()|0,2)}function tMe(){return 1732}function rMe(s){return s=s|0,n[s>>2]|0}function H9(s){return s=s|0,n[s>>2]|0}function nMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+32|0,m=f+16|0,d=f+8|0,B=f,Va(d),s=da(s)|0,n[B>>2]=n[l>>2],c=n[c>>2]|0,n[m>>2]=n[B>>2],j9(s,m,c),Ka(d),C=f}function j9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,m=f+4|0,B=f,d=Pl(iMe()|0)|0,n[B>>2]=n[l>>2],n[m>>2]=n[B>>2],l=Qg(m)|0,oo(0,d|0,s|0,l|0,b9(c)|0)|0,C=f}function iMe(){var s=0;return o[7984]|0||(sMe(10732),s=7984,n[s>>2]=1,n[s+4>>2]=0),10732}function sMe(s){s=s|0,Sl(s,oMe()|0,2)}function oMe(){return 1744}function aMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+32|0,m=f+16|0,d=f+8|0,B=f,Va(d),s=da(s)|0,n[B>>2]=n[l>>2],c=n[c>>2]|0,n[m>>2]=n[B>>2],j9(s,m,c),Ka(d),C=f}function lMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+32|0,B=d+16|0,m=d+8|0,k=d,Va(m),s=da(s)|0,n[k>>2]=n[l>>2],c=o[c>>0]|0,f=o[f>>0]|0,n[B>>2]=n[k>>2],cMe(s,B,c,f),Ka(m),C=d}function cMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+16|0,B=d+4|0,k=d,m=Pl(uMe()|0)|0,n[k>>2]=n[l>>2],n[B>>2]=n[k>>2],l=Qg(B)|0,c=Wm(c)|0,pc(0,m|0,s|0,l|0,c|0,Wm(f)|0)|0,C=d}function uMe(){var s=0;return o[7992]|0||(fMe(10744),s=7992,n[s>>2]=1,n[s+4>>2]=0),10744}function Wm(s){return s=s|0,AMe(s)|0}function AMe(s){return s=s|0,s&255|0}function fMe(s){s=s|0,Sl(s,pMe()|0,3)}function pMe(){return 1756}function hMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;switch(se=C,C=C+32|0,k=se+8|0,Q=se+4|0,O=se+20|0,M=se,OF(s,0),f=AUe(l)|0,n[k>>2]=0,q=k+4|0,n[q>>2]=0,n[k+8>>2]=0,f<<24>>24){case 0:{o[O>>0]=0,gMe(Q,c,O),uD(s,Q)|0,qA(Q);break}case 8:{q=DT(l)|0,o[O>>0]=8,xc(M,n[q+4>>2]|0),dMe(Q,c,O,M,q+8|0),uD(s,Q)|0,qA(Q);break}case 9:{if(m=DT(l)|0,l=n[m+4>>2]|0,l|0)for(B=k+8|0,d=m+12|0;l=l+-1|0,xc(Q,n[d>>2]|0),f=n[q>>2]|0,f>>>0<(n[B>>2]|0)>>>0?(n[f>>2]=n[Q>>2],n[q>>2]=(n[q>>2]|0)+4):gT(k,Q),l;)d=d+4|0;o[O>>0]=9,xc(M,n[m+8>>2]|0),mMe(Q,c,O,M,k),uD(s,Q)|0,qA(Q);break}default:q=DT(l)|0,o[O>>0]=f,xc(M,n[q+4>>2]|0),yMe(Q,c,O,M),uD(s,Q)|0,qA(Q)}$A(k),C=se}function gMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;f=C,C=C+16|0,d=f,Va(d),l=da(l)|0,QMe(s,l,o[c>>0]|0),Ka(d),C=f}function uD(s,l){s=s|0,l=l|0;var c=0;return c=n[s>>2]|0,c|0&&PA(c|0),n[s>>2]=n[l>>2],n[l>>2]=0,s|0}function dMe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0;m=C,C=C+32|0,k=m+16|0,B=m+8|0,Q=m,Va(B),l=da(l)|0,c=o[c>>0]|0,n[Q>>2]=n[f>>2],d=n[d>>2]|0,n[k>>2]=n[Q>>2],SMe(s,l,c,k,d),Ka(B),C=m}function mMe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,O=0;m=C,C=C+32|0,Q=m+24|0,B=m+16|0,O=m+12|0,k=m,Va(B),l=da(l)|0,c=o[c>>0]|0,n[O>>2]=n[f>>2],mT(k,d),n[Q>>2]=n[O>>2],BMe(s,l,c,Q,k),$A(k),Ka(B),C=m}function yMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+32|0,B=d+16|0,m=d+8|0,k=d,Va(m),l=da(l)|0,c=o[c>>0]|0,n[k>>2]=n[f>>2],n[B>>2]=n[k>>2],EMe(s,l,c,B),Ka(m),C=d}function EMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+16|0,m=d+4|0,k=d,B=Pl(CMe()|0)|0,c=Wm(c)|0,n[k>>2]=n[f>>2],n[m>>2]=n[k>>2],AD(s,oo(0,B|0,l|0,c|0,Qg(m)|0)|0),C=d}function CMe(){var s=0;return o[8e3]|0||(wMe(10756),s=8e3,n[s>>2]=1,n[s+4>>2]=0),10756}function AD(s,l){s=s|0,l=l|0,OF(s,l)}function wMe(s){s=s|0,Sl(s,IMe()|0,2)}function IMe(){return 1772}function BMe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,O=0;m=C,C=C+32|0,Q=m+16|0,O=m+12|0,B=m,k=Pl(vMe()|0)|0,c=Wm(c)|0,n[O>>2]=n[f>>2],n[Q>>2]=n[O>>2],f=Qg(Q)|0,n[B>>2]=n[d>>2],Q=d+4|0,n[B+4>>2]=n[Q>>2],O=d+8|0,n[B+8>>2]=n[O>>2],n[O>>2]=0,n[Q>>2]=0,n[d>>2]=0,AD(s,pc(0,k|0,l|0,c|0,f|0,ET(B)|0)|0),$A(B),C=m}function vMe(){var s=0;return o[8008]|0||(DMe(10768),s=8008,n[s>>2]=1,n[s+4>>2]=0),10768}function DMe(s){s=s|0,Sl(s,PMe()|0,3)}function PMe(){return 1784}function SMe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0;m=C,C=C+16|0,k=m+4|0,Q=m,B=Pl(xMe()|0)|0,c=Wm(c)|0,n[Q>>2]=n[f>>2],n[k>>2]=n[Q>>2],f=Qg(k)|0,AD(s,pc(0,B|0,l|0,c|0,f|0,yT(d)|0)|0),C=m}function xMe(){var s=0;return o[8016]|0||(bMe(10780),s=8016,n[s>>2]=1,n[s+4>>2]=0),10780}function bMe(s){s=s|0,Sl(s,kMe()|0,3)}function kMe(){return 1800}function QMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=Pl(FMe()|0)|0,AD(s,Qn(0,f|0,l|0,Wm(c)|0)|0)}function FMe(){var s=0;return o[8024]|0||(TMe(10792),s=8024,n[s>>2]=1,n[s+4>>2]=0),10792}function TMe(s){s=s|0,Sl(s,RMe()|0,1)}function RMe(){return 1816}function NMe(){LMe(),MMe(),OMe()}function LMe(){n[2702]=d7(65536)|0}function MMe(){iOe(10856)}function OMe(){UMe(10816)}function UMe(s){s=s|0,_Me(s,5044),HMe(s)|0}function _Me(s,l){s=s|0,l=l|0;var c=0;c=F9()|0,n[s>>2]=c,ZMe(c,l),xp(n[s>>2]|0)}function HMe(s){s=s|0;var l=0;return l=n[s>>2]|0,bg(l,jMe()|0),s|0}function jMe(){var s=0;return o[8032]|0||(q9(10820),tr(64,10820,U|0)|0,s=8032,n[s>>2]=1,n[s+4>>2]=0),Rr(10820)|0||q9(10820),10820}function q9(s){s=s|0,YMe(s),kg(s,25)}function qMe(s){s=s|0,GMe(s+24|0)}function GMe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function YMe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,5,18,l,JMe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function WMe(s,l){s=s|0,l=l|0,VMe(s,l)}function VMe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;c=C,C=C+16|0,f=c,d=c+4|0,Sg(d,l),n[f>>2]=xg(d,l)|0,KMe(s,f),C=c}function KMe(s,l){s=s|0,l=l|0,G9(s+4|0,n[l>>2]|0),o[s+8>>0]=1}function G9(s,l){s=s|0,l=l|0,n[s>>2]=l}function JMe(){return 1824}function zMe(s){return s=s|0,XMe(s)|0}function XMe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0;return c=C,C=C+16|0,d=c+4|0,B=c,f=Wa(8)|0,l=f,k=Vt(4)|0,Sg(d,s),G9(k,xg(d,s)|0),m=l+4|0,n[m>>2]=k,s=Vt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],T9(s,m,d),n[f>>2]=s,C=c,l|0}function Wa(s){s=s|0;var l=0,c=0;return s=s+7&-8,s>>>0<=32768&&(l=n[2701]|0,s>>>0<=(65536-l|0)>>>0)?(c=(n[2702]|0)+l|0,n[2701]=l+s,s=c):(s=d7(s+8|0)|0,n[s>>2]=n[2703],n[2703]=s,s=s+8|0),s|0}function ZMe(s,l){s=s|0,l=l|0,n[s>>2]=$Me()|0,n[s+4>>2]=eOe()|0,n[s+12>>2]=l,n[s+8>>2]=tOe()|0,n[s+32>>2]=9}function $Me(){return 11744}function eOe(){return 1832}function tOe(){return lD()|0}function rOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(Sp(f,896)|0)==512?c|0&&(nOe(c),gt(c)):l|0&>(l)}function nOe(s){s=s|0,s=n[s+4>>2]|0,s|0&&bp(s)}function iOe(s){s=s|0,sOe(s,5052),oOe(s)|0,aOe(s,5058,26)|0,lOe(s,5069,1)|0,cOe(s,5077,10)|0,uOe(s,5087,19)|0,AOe(s,5094,27)|0}function sOe(s,l){s=s|0,l=l|0;var c=0;c=nUe()|0,n[s>>2]=c,iUe(c,l),xp(n[s>>2]|0)}function oOe(s){s=s|0;var l=0;return l=n[s>>2]|0,bg(l,q4e()|0),s|0}function aOe(s,l,c){return s=s|0,l=l|0,c=c|0,D4e(s,pn(l)|0,c,0),s|0}function lOe(s,l,c){return s=s|0,l=l|0,c=c|0,u4e(s,pn(l)|0,c,0),s|0}function cOe(s,l,c){return s=s|0,l=l|0,c=c|0,jOe(s,pn(l)|0,c,0),s|0}function uOe(s,l,c){return s=s|0,l=l|0,c=c|0,SOe(s,pn(l)|0,c,0),s|0}function Y9(s,l){s=s|0,l=l|0;var c=0,f=0;e:for(;;){for(c=n[2703]|0;;){if((c|0)==(l|0))break e;if(f=n[c>>2]|0,n[2703]=f,!c)c=f;else break}gt(c)}n[2701]=s}function AOe(s,l,c){return s=s|0,l=l|0,c=c|0,fOe(s,pn(l)|0,c,0),s|0}function fOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=CT()|0,s=pOe(c)|0,hn(m,l,d,s,hOe(c,f)|0,f)}function CT(){var s=0,l=0;if(o[8040]|0||(V9(10860),tr(65,10860,U|0)|0,l=8040,n[l>>2]=1,n[l+4>>2]=0),!(Rr(10860)|0)){s=10860,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));V9(10860)}return 10860}function pOe(s){return s=s|0,s|0}function hOe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=CT()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(W9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(gOe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function W9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function gOe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=dOe(s)|0,f>>>0>>0)zr(s);else{Q=n[s>>2]|0,M=(n[s+8>>2]|0)-Q|0,O=M>>2,mOe(d,M>>3>>>0>>1>>>0?O>>>0>>0?B:O:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,W9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,yOe(s,d),EOe(d),C=k;return}}function dOe(s){return s=s|0,536870911}function mOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Tt();else{d=Vt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function yOe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function EOe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&>(s)}function V9(s){s=s|0,IOe(s)}function COe(s){s=s|0,wOe(s+24|0)}function wOe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function IOe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,1,11,l,BOe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function BOe(){return 1840}function vOe(s,l,c){s=s|0,l=l|0,c=c|0,POe(n[(DOe(s)|0)>>2]|0,l,c)}function DOe(s){return s=s|0,(n[(CT()|0)+24>>2]|0)+(s<<3)|0}function POe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;f=C,C=C+16|0,m=f+1|0,d=f,Sg(m,l),l=xg(m,l)|0,Sg(d,c),c=xg(d,c)|0,tf[s&31](l,c),C=f}function SOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=wT()|0,s=xOe(c)|0,hn(m,l,d,s,bOe(c,f)|0,f)}function wT(){var s=0,l=0;if(o[8048]|0||(J9(10896),tr(66,10896,U|0)|0,l=8048,n[l>>2]=1,n[l+4>>2]=0),!(Rr(10896)|0)){s=10896,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));J9(10896)}return 10896}function xOe(s){return s=s|0,s|0}function bOe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=wT()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(K9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(kOe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function K9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function kOe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=QOe(s)|0,f>>>0>>0)zr(s);else{Q=n[s>>2]|0,M=(n[s+8>>2]|0)-Q|0,O=M>>2,FOe(d,M>>3>>>0>>1>>>0?O>>>0>>0?B:O:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,K9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,TOe(s,d),ROe(d),C=k;return}}function QOe(s){return s=s|0,536870911}function FOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Tt();else{d=Vt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function TOe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function ROe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&>(s)}function J9(s){s=s|0,MOe(s)}function NOe(s){s=s|0,LOe(s+24|0)}function LOe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function MOe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,1,11,l,OOe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function OOe(){return 1852}function UOe(s,l){return s=s|0,l=l|0,HOe(n[(_Oe(s)|0)>>2]|0,l)|0}function _Oe(s){return s=s|0,(n[(wT()|0)+24>>2]|0)+(s<<3)|0}function HOe(s,l){s=s|0,l=l|0;var c=0,f=0;return c=C,C=C+16|0,f=c,Sg(f,l),l=xg(f,l)|0,l=oD(Ng[s&31](l)|0)|0,C=c,l|0}function jOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=IT()|0,s=qOe(c)|0,hn(m,l,d,s,GOe(c,f)|0,f)}function IT(){var s=0,l=0;if(o[8056]|0||(X9(10932),tr(67,10932,U|0)|0,l=8056,n[l>>2]=1,n[l+4>>2]=0),!(Rr(10932)|0)){s=10932,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));X9(10932)}return 10932}function qOe(s){return s=s|0,s|0}function GOe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=IT()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(z9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(YOe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function z9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function YOe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=WOe(s)|0,f>>>0>>0)zr(s);else{Q=n[s>>2]|0,M=(n[s+8>>2]|0)-Q|0,O=M>>2,VOe(d,M>>3>>>0>>1>>>0?O>>>0>>0?B:O:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,z9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,KOe(s,d),JOe(d),C=k;return}}function WOe(s){return s=s|0,536870911}function VOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Tt();else{d=Vt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function KOe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function JOe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&>(s)}function X9(s){s=s|0,ZOe(s)}function zOe(s){s=s|0,XOe(s+24|0)}function XOe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function ZOe(s){s=s|0;var l=0;l=Vr()|0,Kr(s,1,7,l,$Oe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function $Oe(){return 1860}function e4e(s,l,c){return s=s|0,l=l|0,c=c|0,r4e(n[(t4e(s)|0)>>2]|0,l,c)|0}function t4e(s){return s=s|0,(n[(IT()|0)+24>>2]|0)+(s<<3)|0}function r4e(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0;return f=C,C=C+32|0,B=f+12|0,m=f+8|0,k=f,Q=f+16|0,d=f+4|0,n4e(Q,l),i4e(k,Q,l),vp(d,c),c=Dp(d,c)|0,n[B>>2]=n[k>>2],_w[s&15](m,B,c),c=s4e(m)|0,qA(m),Pp(d),C=f,c|0}function n4e(s,l){s=s|0,l=l|0}function i4e(s,l,c){s=s|0,l=l|0,c=c|0,o4e(s,c)}function s4e(s){return s=s|0,da(s)|0}function o4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;d=C,C=C+16|0,c=d,f=l,f&1?(a4e(c,0),ii(f|0,c|0)|0,l4e(s,c),c4e(c)):n[s>>2]=n[l>>2],C=d}function a4e(s,l){s=s|0,l=l|0,e5(s,l),n[s+4>>2]=0,o[s+8>>0]=0}function l4e(s,l){s=s|0,l=l|0,n[s>>2]=n[l+4>>2]}function c4e(s){s=s|0,o[s+8>>0]=0}function u4e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=BT()|0,s=A4e(c)|0,hn(m,l,d,s,f4e(c,f)|0,f)}function BT(){var s=0,l=0;if(o[8064]|0||($9(10968),tr(68,10968,U|0)|0,l=8064,n[l>>2]=1,n[l+4>>2]=0),!(Rr(10968)|0)){s=10968,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));$9(10968)}return 10968}function A4e(s){return s=s|0,s|0}function f4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=BT()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(Z9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(p4e(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function Z9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function p4e(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=h4e(s)|0,f>>>0>>0)zr(s);else{Q=n[s>>2]|0,M=(n[s+8>>2]|0)-Q|0,O=M>>2,g4e(d,M>>3>>>0>>1>>>0?O>>>0>>0?B:O:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,Z9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,d4e(s,d),m4e(d),C=k;return}}function h4e(s){return s=s|0,536870911}function g4e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Tt();else{d=Vt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function d4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function m4e(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&>(s)}function $9(s){s=s|0,C4e(s)}function y4e(s){s=s|0,E4e(s+24|0)}function E4e(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function C4e(s){s=s|0;var l=0;l=Vr()|0,Kr(s,1,1,l,w4e()|0,5),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function w4e(){return 1872}function I4e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,v4e(n[(B4e(s)|0)>>2]|0,l,c,f,d,m)}function B4e(s){return s=s|0,(n[(BT()|0)+24>>2]|0)+(s<<3)|0}function v4e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,O=0,M=0,q=0;B=C,C=C+32|0,k=B+16|0,Q=B+12|0,O=B+8|0,M=B+4|0,q=B,vp(k,l),l=Dp(k,l)|0,vp(Q,c),c=Dp(Q,c)|0,vp(O,f),f=Dp(O,f)|0,vp(M,d),d=Dp(M,d)|0,vp(q,m),m=Dp(q,m)|0,w7[s&1](l,c,f,d,m),Pp(q),Pp(M),Pp(O),Pp(Q),Pp(k),C=B}function D4e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=vT()|0,s=P4e(c)|0,hn(m,l,d,s,S4e(c,f)|0,f)}function vT(){var s=0,l=0;if(o[8072]|0||(t7(11004),tr(69,11004,U|0)|0,l=8072,n[l>>2]=1,n[l+4>>2]=0),!(Rr(11004)|0)){s=11004,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));t7(11004)}return 11004}function P4e(s){return s=s|0,s|0}function S4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=vT()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(e7(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(x4e(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function e7(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function x4e(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=b4e(s)|0,f>>>0>>0)zr(s);else{Q=n[s>>2]|0,M=(n[s+8>>2]|0)-Q|0,O=M>>2,k4e(d,M>>3>>>0>>1>>>0?O>>>0>>0?B:O:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,e7(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,Q4e(s,d),F4e(d),C=k;return}}function b4e(s){return s=s|0,536870911}function k4e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Tt();else{d=Vt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function Q4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function F4e(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&>(s)}function t7(s){s=s|0,N4e(s)}function T4e(s){s=s|0,R4e(s+24|0)}function R4e(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function N4e(s){s=s|0;var l=0;l=Vr()|0,Kr(s,1,12,l,L4e()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function L4e(){return 1896}function M4e(s,l,c){s=s|0,l=l|0,c=c|0,U4e(n[(O4e(s)|0)>>2]|0,l,c)}function O4e(s){return s=s|0,(n[(vT()|0)+24>>2]|0)+(s<<3)|0}function U4e(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;f=C,C=C+16|0,m=f+4|0,d=f,_4e(m,l),l=H4e(m,l)|0,vp(d,c),c=Dp(d,c)|0,tf[s&31](l,c),Pp(d),C=f}function _4e(s,l){s=s|0,l=l|0}function H4e(s,l){return s=s|0,l=l|0,j4e(l)|0}function j4e(s){return s=s|0,s|0}function q4e(){var s=0;return o[8080]|0||(r7(11040),tr(70,11040,U|0)|0,s=8080,n[s>>2]=1,n[s+4>>2]=0),Rr(11040)|0||r7(11040),11040}function r7(s){s=s|0,W4e(s),kg(s,71)}function G4e(s){s=s|0,Y4e(s+24|0)}function Y4e(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function W4e(s){s=s|0;var l=0;l=Vr()|0,Kr(s,5,7,l,z4e()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function V4e(s){s=s|0,K4e(s)}function K4e(s){s=s|0,J4e(s)}function J4e(s){s=s|0,o[s+8>>0]=1}function z4e(){return 1936}function X4e(){return Z4e()|0}function Z4e(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0;return l=C,C=C+16|0,d=l+4|0,B=l,c=Wa(8)|0,s=c,m=s+4|0,n[m>>2]=Vt(1)|0,f=Vt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],$4e(f,m,d),n[c>>2]=f,C=l,s|0}function $4e(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Vt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1916,n[c+12>>2]=l,n[s+4>>2]=c}function eUe(s){s=s|0,Jm(s),gt(s)}function tUe(s){s=s|0,s=n[s+12>>2]|0,s|0&>(s)}function rUe(s){s=s|0,gt(s)}function nUe(){var s=0;return o[8088]|0||(uUe(11076),tr(25,11076,U|0)|0,s=8088,n[s>>2]=1,n[s+4>>2]=0),11076}function iUe(s,l){s=s|0,l=l|0,n[s>>2]=sUe()|0,n[s+4>>2]=oUe()|0,n[s+12>>2]=l,n[s+8>>2]=aUe()|0,n[s+32>>2]=10}function sUe(){return 11745}function oUe(){return 1940}function aUe(){return aD()|0}function lUe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(Sp(f,896)|0)==512?c|0&&(cUe(c),gt(c)):l|0&>(l)}function cUe(s){s=s|0,s=n[s+4>>2]|0,s|0&&bp(s)}function uUe(s){s=s|0,Bp(s)}function xc(s,l){s=s|0,l=l|0,n[s>>2]=l}function DT(s){return s=s|0,n[s>>2]|0}function AUe(s){return s=s|0,o[n[s>>2]>>0]|0}function fUe(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,n[f>>2]=n[s>>2],pUe(l,f)|0,C=c}function pUe(s,l){s=s|0,l=l|0;var c=0;return c=hUe(n[s>>2]|0,l)|0,l=s+4|0,n[(n[l>>2]|0)+8>>2]=c,n[(n[l>>2]|0)+8>>2]|0}function hUe(s,l){s=s|0,l=l|0;var c=0,f=0;return c=C,C=C+16|0,f=c,Va(f),s=da(s)|0,l=gUe(s,n[l>>2]|0)|0,Ka(f),C=c,l|0}function Va(s){s=s|0,n[s>>2]=n[2701],n[s+4>>2]=n[2703]}function gUe(s,l){s=s|0,l=l|0;var c=0;return c=Pl(dUe()|0)|0,Qn(0,c|0,s|0,yT(l)|0)|0}function Ka(s){s=s|0,Y9(n[s>>2]|0,n[s+4>>2]|0)}function dUe(){var s=0;return o[8096]|0||(mUe(11120),s=8096,n[s>>2]=1,n[s+4>>2]=0),11120}function mUe(s){s=s|0,Sl(s,yUe()|0,1)}function yUe(){return 1948}function EUe(){CUe()}function CUe(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0,Ge=0,Oe=0,Fe=0;if(Oe=C,C=C+16|0,M=Oe+4|0,q=Oe,Ni(65536,10804,n[2702]|0,10812),c=P9()|0,l=n[c>>2]|0,s=n[l>>2]|0,s|0)for(f=n[c+8>>2]|0,c=n[c+4>>2]|0;uc(s|0,u[c>>0]|0|0,o[f>>0]|0),l=l+4|0,s=n[l>>2]|0,s;)f=f+1|0,c=c+1|0;if(s=S9()|0,l=n[s>>2]|0,l|0)do uu(l|0,n[s+4>>2]|0),s=s+8|0,l=n[s>>2]|0;while((l|0)!=0);uu(wUe()|0,5167),O=Gm()|0,s=n[O>>2]|0;e:do if(s|0){do IUe(n[s+4>>2]|0),s=n[s>>2]|0;while((s|0)!=0);if(s=n[O>>2]|0,s|0){Q=O;do{for(;d=s,s=n[s>>2]|0,d=n[d+4>>2]|0,!!(BUe(d)|0);)if(n[q>>2]=Q,n[M>>2]=n[q>>2],vUe(O,M)|0,!s)break e;if(DUe(d),Q=n[Q>>2]|0,l=n7(d)|0,m=Hi()|0,B=C,C=C+((1*(l<<2)|0)+15&-16)|0,k=C,C=C+((1*(l<<2)|0)+15&-16)|0,l=n[(U9(d)|0)>>2]|0,l|0)for(c=B,f=k;n[c>>2]=n[(Ym(n[l+4>>2]|0)|0)>>2],n[f>>2]=n[l+8>>2],l=n[l>>2]|0,l;)c=c+4|0,f=f+4|0;Fe=Ym(d)|0,l=PUe(d)|0,c=n7(d)|0,f=SUe(d)|0,Au(Fe|0,l|0,B|0,k|0,c|0,f|0,fT(d)|0),_i(m|0)}while((s|0)!=0)}}while(0);if(s=n[(pT()|0)>>2]|0,s|0)do Fe=s+4|0,O=hT(Fe)|0,d=Lw(O)|0,m=Rw(O)|0,B=(Nw(O)|0)+1|0,k=fD(O)|0,Q=i7(Fe)|0,O=Rr(O)|0,M=cD(Fe)|0,q=PT(Fe)|0,El(0,d|0,m|0,B|0,k|0,Q|0,O|0,M|0,q|0,ST(Fe)|0),s=n[s>>2]|0;while((s|0)!=0);s=n[(Gm()|0)>>2]|0;e:do if(s|0){t:for(;;){if(l=n[s+4>>2]|0,l|0&&(se=n[(Ym(l)|0)>>2]|0,Ge=n[(_9(l)|0)>>2]|0,Ge|0)){c=Ge;do{l=c+4|0,f=hT(l)|0;r:do if(f|0)switch(Rr(f)|0){case 0:break t;case 4:case 3:case 2:{k=Lw(f)|0,Q=Rw(f)|0,O=(Nw(f)|0)+1|0,M=fD(f)|0,q=Rr(f)|0,Fe=cD(l)|0,El(se|0,k|0,Q|0,O|0,M|0,0,q|0,Fe|0,PT(l)|0,ST(l)|0);break r}case 1:{B=Lw(f)|0,k=Rw(f)|0,Q=(Nw(f)|0)+1|0,O=fD(f)|0,M=i7(l)|0,q=Rr(f)|0,Fe=cD(l)|0,El(se|0,B|0,k|0,Q|0,O|0,M|0,q|0,Fe|0,PT(l)|0,ST(l)|0);break r}case 5:{O=Lw(f)|0,M=Rw(f)|0,q=(Nw(f)|0)+1|0,Fe=fD(f)|0,El(se|0,O|0,M|0,q|0,Fe|0,xUe(f)|0,Rr(f)|0,0,0,0);break r}default:break r}while(0);c=n[c>>2]|0}while((c|0)!=0)}if(s=n[s>>2]|0,!s)break e}Tt()}while(0);Ce(),C=Oe}function wUe(){return 11703}function IUe(s){s=s|0,o[s+40>>0]=0}function BUe(s){return s=s|0,(o[s+40>>0]|0)!=0|0}function vUe(s,l){return s=s|0,l=l|0,l=bUe(l)|0,s=n[l>>2]|0,n[l>>2]=n[s>>2],gt(s),n[l>>2]|0}function DUe(s){s=s|0,o[s+40>>0]=1}function n7(s){return s=s|0,n[s+20>>2]|0}function PUe(s){return s=s|0,n[s+8>>2]|0}function SUe(s){return s=s|0,n[s+32>>2]|0}function fD(s){return s=s|0,n[s+4>>2]|0}function i7(s){return s=s|0,n[s+4>>2]|0}function PT(s){return s=s|0,n[s+8>>2]|0}function ST(s){return s=s|0,n[s+16>>2]|0}function xUe(s){return s=s|0,n[s+20>>2]|0}function bUe(s){return s=s|0,n[s>>2]|0}function pD(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0,Ge=0,Oe=0,Fe=0,et=0,Xe=0,at=0,Ue=0,qe=0,Lt=0;Lt=C,C=C+16|0,se=Lt;do if(s>>>0<245){if(O=s>>>0<11?16:s+11&-8,s=O>>>3,q=n[2783]|0,c=q>>>s,c&3|0)return l=(c&1^1)+s|0,s=11172+(l<<1<<2)|0,c=s+8|0,f=n[c>>2]|0,d=f+8|0,m=n[d>>2]|0,(s|0)==(m|0)?n[2783]=q&~(1<>2]=s,n[c>>2]=m),qe=l<<3,n[f+4>>2]=qe|3,qe=f+qe+4|0,n[qe>>2]=n[qe>>2]|1,qe=d,C=Lt,qe|0;if(M=n[2785]|0,O>>>0>M>>>0){if(c|0)return l=2<>>12&16,l=l>>>B,c=l>>>5&8,l=l>>>c,d=l>>>2&4,l=l>>>d,s=l>>>1&2,l=l>>>s,f=l>>>1&1,f=(c|B|d|s|f)+(l>>>f)|0,l=11172+(f<<1<<2)|0,s=l+8|0,d=n[s>>2]|0,B=d+8|0,c=n[B>>2]|0,(l|0)==(c|0)?(s=q&~(1<>2]=l,n[s>>2]=c,s=q),m=(f<<3)-O|0,n[d+4>>2]=O|3,f=d+O|0,n[f+4>>2]=m|1,n[f+m>>2]=m,M|0&&(d=n[2788]|0,l=M>>>3,c=11172+(l<<1<<2)|0,l=1<>2]|0):(n[2783]=s|l,l=c,s=c+8|0),n[s>>2]=d,n[l+12>>2]=d,n[d+8>>2]=l,n[d+12>>2]=c),n[2785]=m,n[2788]=f,qe=B,C=Lt,qe|0;if(k=n[2784]|0,k){if(c=(k&0-k)+-1|0,B=c>>>12&16,c=c>>>B,m=c>>>5&8,c=c>>>m,Q=c>>>2&4,c=c>>>Q,f=c>>>1&2,c=c>>>f,s=c>>>1&1,s=n[11436+((m|B|Q|f|s)+(c>>>s)<<2)>>2]|0,c=(n[s+4>>2]&-8)-O|0,f=n[s+16+(((n[s+16>>2]|0)==0&1)<<2)>>2]|0,!f)Q=s,m=c;else{do B=(n[f+4>>2]&-8)-O|0,Q=B>>>0>>0,c=Q?B:c,s=Q?f:s,f=n[f+16+(((n[f+16>>2]|0)==0&1)<<2)>>2]|0;while((f|0)!=0);Q=s,m=c}if(B=Q+O|0,Q>>>0>>0){d=n[Q+24>>2]|0,l=n[Q+12>>2]|0;do if((l|0)==(Q|0)){if(s=Q+20|0,l=n[s>>2]|0,!l&&(s=Q+16|0,l=n[s>>2]|0,!l)){c=0;break}for(;;){if(c=l+20|0,f=n[c>>2]|0,f|0){l=f,s=c;continue}if(c=l+16|0,f=n[c>>2]|0,f)l=f,s=c;else break}n[s>>2]=0,c=l}else c=n[Q+8>>2]|0,n[c+12>>2]=l,n[l+8>>2]=c,c=l;while(0);do if(d|0){if(l=n[Q+28>>2]|0,s=11436+(l<<2)|0,(Q|0)==(n[s>>2]|0)){if(n[s>>2]=c,!c){n[2784]=k&~(1<>2]|0)!=(Q|0)&1)<<2)>>2]=c,!c)break;n[c+24>>2]=d,l=n[Q+16>>2]|0,l|0&&(n[c+16>>2]=l,n[l+24>>2]=c),l=n[Q+20>>2]|0,l|0&&(n[c+20>>2]=l,n[l+24>>2]=c)}while(0);return m>>>0<16?(qe=m+O|0,n[Q+4>>2]=qe|3,qe=Q+qe+4|0,n[qe>>2]=n[qe>>2]|1):(n[Q+4>>2]=O|3,n[B+4>>2]=m|1,n[B+m>>2]=m,M|0&&(f=n[2788]|0,l=M>>>3,c=11172+(l<<1<<2)|0,l=1<>2]|0):(n[2783]=q|l,l=c,s=c+8|0),n[s>>2]=f,n[l+12>>2]=f,n[f+8>>2]=l,n[f+12>>2]=c),n[2785]=m,n[2788]=B),qe=Q+8|0,C=Lt,qe|0}else q=O}else q=O}else q=O}else if(s>>>0<=4294967231)if(s=s+11|0,O=s&-8,Q=n[2784]|0,Q){f=0-O|0,s=s>>>8,s?O>>>0>16777215?k=31:(q=(s+1048320|0)>>>16&8,Ue=s<>>16&4,Ue=Ue<>>16&2,k=14-(M|q|k)+(Ue<>>15)|0,k=O>>>(k+7|0)&1|k<<1):k=0,c=n[11436+(k<<2)>>2]|0;e:do if(!c)c=0,s=0,Ue=57;else for(s=0,B=O<<((k|0)==31?0:25-(k>>>1)|0),m=0;;){if(d=(n[c+4>>2]&-8)-O|0,d>>>0>>0)if(d)s=c,f=d;else{s=c,f=0,d=c,Ue=61;break e}if(d=n[c+20>>2]|0,c=n[c+16+(B>>>31<<2)>>2]|0,m=(d|0)==0|(d|0)==(c|0)?m:d,d=(c|0)==0,d){c=m,Ue=57;break}else B=B<<((d^1)&1)}while(0);if((Ue|0)==57){if((c|0)==0&(s|0)==0){if(s=2<>>12&16,q=q>>>B,m=q>>>5&8,q=q>>>m,k=q>>>2&4,q=q>>>k,M=q>>>1&2,q=q>>>M,c=q>>>1&1,s=0,c=n[11436+((m|B|k|M|c)+(q>>>c)<<2)>>2]|0}c?(d=c,Ue=61):(k=s,B=f)}if((Ue|0)==61)for(;;)if(Ue=0,c=(n[d+4>>2]&-8)-O|0,q=c>>>0>>0,c=q?c:f,s=q?d:s,d=n[d+16+(((n[d+16>>2]|0)==0&1)<<2)>>2]|0,d)f=c,Ue=61;else{k=s,B=c;break}if((k|0)!=0&&B>>>0<((n[2785]|0)-O|0)>>>0){if(m=k+O|0,k>>>0>=m>>>0)return qe=0,C=Lt,qe|0;d=n[k+24>>2]|0,l=n[k+12>>2]|0;do if((l|0)==(k|0)){if(s=k+20|0,l=n[s>>2]|0,!l&&(s=k+16|0,l=n[s>>2]|0,!l)){l=0;break}for(;;){if(c=l+20|0,f=n[c>>2]|0,f|0){l=f,s=c;continue}if(c=l+16|0,f=n[c>>2]|0,f)l=f,s=c;else break}n[s>>2]=0}else qe=n[k+8>>2]|0,n[qe+12>>2]=l,n[l+8>>2]=qe;while(0);do if(d){if(s=n[k+28>>2]|0,c=11436+(s<<2)|0,(k|0)==(n[c>>2]|0)){if(n[c>>2]=l,!l){f=Q&~(1<>2]|0)!=(k|0)&1)<<2)>>2]=l,!l){f=Q;break}n[l+24>>2]=d,s=n[k+16>>2]|0,s|0&&(n[l+16>>2]=s,n[s+24>>2]=l),s=n[k+20>>2]|0,s&&(n[l+20>>2]=s,n[s+24>>2]=l),f=Q}else f=Q;while(0);do if(B>>>0>=16){if(n[k+4>>2]=O|3,n[m+4>>2]=B|1,n[m+B>>2]=B,l=B>>>3,B>>>0<256){c=11172+(l<<1<<2)|0,s=n[2783]|0,l=1<>2]|0):(n[2783]=s|l,l=c,s=c+8|0),n[s>>2]=m,n[l+12>>2]=m,n[m+8>>2]=l,n[m+12>>2]=c;break}if(l=B>>>8,l?B>>>0>16777215?l=31:(Ue=(l+1048320|0)>>>16&8,qe=l<>>16&4,qe=qe<>>16&2,l=14-(at|Ue|l)+(qe<>>15)|0,l=B>>>(l+7|0)&1|l<<1):l=0,c=11436+(l<<2)|0,n[m+28>>2]=l,s=m+16|0,n[s+4>>2]=0,n[s>>2]=0,s=1<>2]=m,n[m+24>>2]=c,n[m+12>>2]=m,n[m+8>>2]=m;break}for(s=B<<((l|0)==31?0:25-(l>>>1)|0),c=n[c>>2]|0;;){if((n[c+4>>2]&-8|0)==(B|0)){Ue=97;break}if(f=c+16+(s>>>31<<2)|0,l=n[f>>2]|0,l)s=s<<1,c=l;else{Ue=96;break}}if((Ue|0)==96){n[f>>2]=m,n[m+24>>2]=c,n[m+12>>2]=m,n[m+8>>2]=m;break}else if((Ue|0)==97){Ue=c+8|0,qe=n[Ue>>2]|0,n[qe+12>>2]=m,n[Ue>>2]=m,n[m+8>>2]=qe,n[m+12>>2]=c,n[m+24>>2]=0;break}}else qe=B+O|0,n[k+4>>2]=qe|3,qe=k+qe+4|0,n[qe>>2]=n[qe>>2]|1;while(0);return qe=k+8|0,C=Lt,qe|0}else q=O}else q=O;else q=-1;while(0);if(c=n[2785]|0,c>>>0>=q>>>0)return l=c-q|0,s=n[2788]|0,l>>>0>15?(qe=s+q|0,n[2788]=qe,n[2785]=l,n[qe+4>>2]=l|1,n[qe+l>>2]=l,n[s+4>>2]=q|3):(n[2785]=0,n[2788]=0,n[s+4>>2]=c|3,qe=s+c+4|0,n[qe>>2]=n[qe>>2]|1),qe=s+8|0,C=Lt,qe|0;if(B=n[2786]|0,B>>>0>q>>>0)return at=B-q|0,n[2786]=at,qe=n[2789]|0,Ue=qe+q|0,n[2789]=Ue,n[Ue+4>>2]=at|1,n[qe+4>>2]=q|3,qe=qe+8|0,C=Lt,qe|0;if(n[2901]|0?s=n[2903]|0:(n[2903]=4096,n[2902]=4096,n[2904]=-1,n[2905]=-1,n[2906]=0,n[2894]=0,s=se&-16^1431655768,n[se>>2]=s,n[2901]=s,s=4096),k=q+48|0,Q=q+47|0,m=s+Q|0,d=0-s|0,O=m&d,O>>>0<=q>>>0||(s=n[2893]|0,s|0&&(M=n[2891]|0,se=M+O|0,se>>>0<=M>>>0|se>>>0>s>>>0)))return qe=0,C=Lt,qe|0;e:do if(n[2894]&4)l=0,Ue=133;else{c=n[2789]|0;t:do if(c){for(f=11580;s=n[f>>2]|0,!(s>>>0<=c>>>0&&(Fe=f+4|0,(s+(n[Fe>>2]|0)|0)>>>0>c>>>0));)if(s=n[f+8>>2]|0,s)f=s;else{Ue=118;break t}if(l=m-B&d,l>>>0<2147483647)if(s=kp(l|0)|0,(s|0)==((n[f>>2]|0)+(n[Fe>>2]|0)|0)){if((s|0)!=-1){B=l,m=s,Ue=135;break e}}else f=s,Ue=126;else l=0}else Ue=118;while(0);do if((Ue|0)==118)if(c=kp(0)|0,(c|0)!=-1&&(l=c,Ge=n[2902]|0,Oe=Ge+-1|0,l=((Oe&l|0)==0?0:(Oe+l&0-Ge)-l|0)+O|0,Ge=n[2891]|0,Oe=l+Ge|0,l>>>0>q>>>0&l>>>0<2147483647)){if(Fe=n[2893]|0,Fe|0&&Oe>>>0<=Ge>>>0|Oe>>>0>Fe>>>0){l=0;break}if(s=kp(l|0)|0,(s|0)==(c|0)){B=l,m=c,Ue=135;break e}else f=s,Ue=126}else l=0;while(0);do if((Ue|0)==126){if(c=0-l|0,!(k>>>0>l>>>0&(l>>>0<2147483647&(f|0)!=-1)))if((f|0)==-1){l=0;break}else{B=l,m=f,Ue=135;break e}if(s=n[2903]|0,s=Q-l+s&0-s,s>>>0>=2147483647){B=l,m=f,Ue=135;break e}if((kp(s|0)|0)==-1){kp(c|0)|0,l=0;break}else{B=s+l|0,m=f,Ue=135;break e}}while(0);n[2894]=n[2894]|4,Ue=133}while(0);if((Ue|0)==133&&O>>>0<2147483647&&(at=kp(O|0)|0,Fe=kp(0)|0,et=Fe-at|0,Xe=et>>>0>(q+40|0)>>>0,!((at|0)==-1|Xe^1|at>>>0>>0&((at|0)!=-1&(Fe|0)!=-1)^1))&&(B=Xe?et:l,m=at,Ue=135),(Ue|0)==135){l=(n[2891]|0)+B|0,n[2891]=l,l>>>0>(n[2892]|0)>>>0&&(n[2892]=l),Q=n[2789]|0;do if(Q){for(l=11580;;){if(s=n[l>>2]|0,c=l+4|0,f=n[c>>2]|0,(m|0)==(s+f|0)){Ue=145;break}if(d=n[l+8>>2]|0,d)l=d;else break}if((Ue|0)==145&&(n[l+12>>2]&8|0)==0&&Q>>>0>>0&Q>>>0>=s>>>0){n[c>>2]=f+B,qe=Q+8|0,qe=(qe&7|0)==0?0:0-qe&7,Ue=Q+qe|0,qe=(n[2786]|0)+(B-qe)|0,n[2789]=Ue,n[2786]=qe,n[Ue+4>>2]=qe|1,n[Ue+qe+4>>2]=40,n[2790]=n[2905];break}for(m>>>0<(n[2787]|0)>>>0&&(n[2787]=m),c=m+B|0,l=11580;;){if((n[l>>2]|0)==(c|0)){Ue=153;break}if(s=n[l+8>>2]|0,s)l=s;else break}if((Ue|0)==153&&(n[l+12>>2]&8|0)==0){n[l>>2]=m,M=l+4|0,n[M>>2]=(n[M>>2]|0)+B,M=m+8|0,M=m+((M&7|0)==0?0:0-M&7)|0,l=c+8|0,l=c+((l&7|0)==0?0:0-l&7)|0,O=M+q|0,k=l-M-q|0,n[M+4>>2]=q|3;do if((l|0)!=(Q|0)){if((l|0)==(n[2788]|0)){qe=(n[2785]|0)+k|0,n[2785]=qe,n[2788]=O,n[O+4>>2]=qe|1,n[O+qe>>2]=qe;break}if(s=n[l+4>>2]|0,(s&3|0)==1){B=s&-8,f=s>>>3;e:do if(s>>>0<256)if(s=n[l+8>>2]|0,c=n[l+12>>2]|0,(c|0)==(s|0)){n[2783]=n[2783]&~(1<>2]=c,n[c+8>>2]=s;break}else{m=n[l+24>>2]|0,s=n[l+12>>2]|0;do if((s|0)==(l|0)){if(f=l+16|0,c=f+4|0,s=n[c>>2]|0,!s)if(s=n[f>>2]|0,s)c=f;else{s=0;break}for(;;){if(f=s+20|0,d=n[f>>2]|0,d|0){s=d,c=f;continue}if(f=s+16|0,d=n[f>>2]|0,d)s=d,c=f;else break}n[c>>2]=0}else qe=n[l+8>>2]|0,n[qe+12>>2]=s,n[s+8>>2]=qe;while(0);if(!m)break;c=n[l+28>>2]|0,f=11436+(c<<2)|0;do if((l|0)!=(n[f>>2]|0)){if(n[m+16+(((n[m+16>>2]|0)!=(l|0)&1)<<2)>>2]=s,!s)break e}else{if(n[f>>2]=s,s|0)break;n[2784]=n[2784]&~(1<>2]=m,c=l+16|0,f=n[c>>2]|0,f|0&&(n[s+16>>2]=f,n[f+24>>2]=s),c=n[c+4>>2]|0,!c)break;n[s+20>>2]=c,n[c+24>>2]=s}while(0);l=l+B|0,d=B+k|0}else d=k;if(l=l+4|0,n[l>>2]=n[l>>2]&-2,n[O+4>>2]=d|1,n[O+d>>2]=d,l=d>>>3,d>>>0<256){c=11172+(l<<1<<2)|0,s=n[2783]|0,l=1<>2]|0):(n[2783]=s|l,l=c,s=c+8|0),n[s>>2]=O,n[l+12>>2]=O,n[O+8>>2]=l,n[O+12>>2]=c;break}l=d>>>8;do if(!l)l=0;else{if(d>>>0>16777215){l=31;break}Ue=(l+1048320|0)>>>16&8,qe=l<>>16&4,qe=qe<>>16&2,l=14-(at|Ue|l)+(qe<>>15)|0,l=d>>>(l+7|0)&1|l<<1}while(0);if(f=11436+(l<<2)|0,n[O+28>>2]=l,s=O+16|0,n[s+4>>2]=0,n[s>>2]=0,s=n[2784]|0,c=1<>2]=O,n[O+24>>2]=f,n[O+12>>2]=O,n[O+8>>2]=O;break}for(s=d<<((l|0)==31?0:25-(l>>>1)|0),c=n[f>>2]|0;;){if((n[c+4>>2]&-8|0)==(d|0)){Ue=194;break}if(f=c+16+(s>>>31<<2)|0,l=n[f>>2]|0,l)s=s<<1,c=l;else{Ue=193;break}}if((Ue|0)==193){n[f>>2]=O,n[O+24>>2]=c,n[O+12>>2]=O,n[O+8>>2]=O;break}else if((Ue|0)==194){Ue=c+8|0,qe=n[Ue>>2]|0,n[qe+12>>2]=O,n[Ue>>2]=O,n[O+8>>2]=qe,n[O+12>>2]=c,n[O+24>>2]=0;break}}else qe=(n[2786]|0)+k|0,n[2786]=qe,n[2789]=O,n[O+4>>2]=qe|1;while(0);return qe=M+8|0,C=Lt,qe|0}for(l=11580;s=n[l>>2]|0,!(s>>>0<=Q>>>0&&(qe=s+(n[l+4>>2]|0)|0,qe>>>0>Q>>>0));)l=n[l+8>>2]|0;d=qe+-47|0,s=d+8|0,s=d+((s&7|0)==0?0:0-s&7)|0,d=Q+16|0,s=s>>>0>>0?Q:s,l=s+8|0,c=m+8|0,c=(c&7|0)==0?0:0-c&7,Ue=m+c|0,c=B+-40-c|0,n[2789]=Ue,n[2786]=c,n[Ue+4>>2]=c|1,n[Ue+c+4>>2]=40,n[2790]=n[2905],c=s+4|0,n[c>>2]=27,n[l>>2]=n[2895],n[l+4>>2]=n[2896],n[l+8>>2]=n[2897],n[l+12>>2]=n[2898],n[2895]=m,n[2896]=B,n[2898]=0,n[2897]=l,l=s+24|0;do Ue=l,l=l+4|0,n[l>>2]=7;while((Ue+8|0)>>>0>>0);if((s|0)!=(Q|0)){if(m=s-Q|0,n[c>>2]=n[c>>2]&-2,n[Q+4>>2]=m|1,n[s>>2]=m,l=m>>>3,m>>>0<256){c=11172+(l<<1<<2)|0,s=n[2783]|0,l=1<>2]|0):(n[2783]=s|l,l=c,s=c+8|0),n[s>>2]=Q,n[l+12>>2]=Q,n[Q+8>>2]=l,n[Q+12>>2]=c;break}if(l=m>>>8,l?m>>>0>16777215?c=31:(Ue=(l+1048320|0)>>>16&8,qe=l<>>16&4,qe=qe<>>16&2,c=14-(at|Ue|c)+(qe<>>15)|0,c=m>>>(c+7|0)&1|c<<1):c=0,f=11436+(c<<2)|0,n[Q+28>>2]=c,n[Q+20>>2]=0,n[d>>2]=0,l=n[2784]|0,s=1<>2]=Q,n[Q+24>>2]=f,n[Q+12>>2]=Q,n[Q+8>>2]=Q;break}for(s=m<<((c|0)==31?0:25-(c>>>1)|0),c=n[f>>2]|0;;){if((n[c+4>>2]&-8|0)==(m|0)){Ue=216;break}if(f=c+16+(s>>>31<<2)|0,l=n[f>>2]|0,l)s=s<<1,c=l;else{Ue=215;break}}if((Ue|0)==215){n[f>>2]=Q,n[Q+24>>2]=c,n[Q+12>>2]=Q,n[Q+8>>2]=Q;break}else if((Ue|0)==216){Ue=c+8|0,qe=n[Ue>>2]|0,n[qe+12>>2]=Q,n[Ue>>2]=Q,n[Q+8>>2]=qe,n[Q+12>>2]=c,n[Q+24>>2]=0;break}}}else{qe=n[2787]|0,(qe|0)==0|m>>>0>>0&&(n[2787]=m),n[2895]=m,n[2896]=B,n[2898]=0,n[2792]=n[2901],n[2791]=-1,l=0;do qe=11172+(l<<1<<2)|0,n[qe+12>>2]=qe,n[qe+8>>2]=qe,l=l+1|0;while((l|0)!=32);qe=m+8|0,qe=(qe&7|0)==0?0:0-qe&7,Ue=m+qe|0,qe=B+-40-qe|0,n[2789]=Ue,n[2786]=qe,n[Ue+4>>2]=qe|1,n[Ue+qe+4>>2]=40,n[2790]=n[2905]}while(0);if(l=n[2786]|0,l>>>0>q>>>0)return at=l-q|0,n[2786]=at,qe=n[2789]|0,Ue=qe+q|0,n[2789]=Ue,n[Ue+4>>2]=at|1,n[qe+4>>2]=q|3,qe=qe+8|0,C=Lt,qe|0}return n[(Vm()|0)>>2]=12,qe=0,C=Lt,qe|0}function hD(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0;if(!!s){c=s+-8|0,d=n[2787]|0,s=n[s+-4>>2]|0,l=s&-8,Q=c+l|0;do if(s&1)k=c,B=c;else{if(f=n[c>>2]|0,!(s&3)||(B=c+(0-f)|0,m=f+l|0,B>>>0>>0))return;if((B|0)==(n[2788]|0)){if(s=Q+4|0,l=n[s>>2]|0,(l&3|0)!=3){k=B,l=m;break}n[2785]=m,n[s>>2]=l&-2,n[B+4>>2]=m|1,n[B+m>>2]=m;return}if(c=f>>>3,f>>>0<256)if(s=n[B+8>>2]|0,l=n[B+12>>2]|0,(l|0)==(s|0)){n[2783]=n[2783]&~(1<>2]=l,n[l+8>>2]=s,k=B,l=m;break}d=n[B+24>>2]|0,s=n[B+12>>2]|0;do if((s|0)==(B|0)){if(c=B+16|0,l=c+4|0,s=n[l>>2]|0,!s)if(s=n[c>>2]|0,s)l=c;else{s=0;break}for(;;){if(c=s+20|0,f=n[c>>2]|0,f|0){s=f,l=c;continue}if(c=s+16|0,f=n[c>>2]|0,f)s=f,l=c;else break}n[l>>2]=0}else k=n[B+8>>2]|0,n[k+12>>2]=s,n[s+8>>2]=k;while(0);if(d){if(l=n[B+28>>2]|0,c=11436+(l<<2)|0,(B|0)==(n[c>>2]|0)){if(n[c>>2]=s,!s){n[2784]=n[2784]&~(1<>2]|0)!=(B|0)&1)<<2)>>2]=s,!s){k=B,l=m;break}n[s+24>>2]=d,l=B+16|0,c=n[l>>2]|0,c|0&&(n[s+16>>2]=c,n[c+24>>2]=s),l=n[l+4>>2]|0,l?(n[s+20>>2]=l,n[l+24>>2]=s,k=B,l=m):(k=B,l=m)}else k=B,l=m}while(0);if(!(B>>>0>=Q>>>0)&&(s=Q+4|0,f=n[s>>2]|0,!!(f&1))){if(f&2)n[s>>2]=f&-2,n[k+4>>2]=l|1,n[B+l>>2]=l,d=l;else{if(s=n[2788]|0,(Q|0)==(n[2789]|0)){if(Q=(n[2786]|0)+l|0,n[2786]=Q,n[2789]=k,n[k+4>>2]=Q|1,(k|0)!=(s|0))return;n[2788]=0,n[2785]=0;return}if((Q|0)==(s|0)){Q=(n[2785]|0)+l|0,n[2785]=Q,n[2788]=B,n[k+4>>2]=Q|1,n[B+Q>>2]=Q;return}d=(f&-8)+l|0,c=f>>>3;do if(f>>>0<256)if(l=n[Q+8>>2]|0,s=n[Q+12>>2]|0,(s|0)==(l|0)){n[2783]=n[2783]&~(1<>2]=s,n[s+8>>2]=l;break}else{m=n[Q+24>>2]|0,s=n[Q+12>>2]|0;do if((s|0)==(Q|0)){if(c=Q+16|0,l=c+4|0,s=n[l>>2]|0,!s)if(s=n[c>>2]|0,s)l=c;else{c=0;break}for(;;){if(c=s+20|0,f=n[c>>2]|0,f|0){s=f,l=c;continue}if(c=s+16|0,f=n[c>>2]|0,f)s=f,l=c;else break}n[l>>2]=0,c=s}else c=n[Q+8>>2]|0,n[c+12>>2]=s,n[s+8>>2]=c,c=s;while(0);if(m|0){if(s=n[Q+28>>2]|0,l=11436+(s<<2)|0,(Q|0)==(n[l>>2]|0)){if(n[l>>2]=c,!c){n[2784]=n[2784]&~(1<>2]|0)!=(Q|0)&1)<<2)>>2]=c,!c)break;n[c+24>>2]=m,s=Q+16|0,l=n[s>>2]|0,l|0&&(n[c+16>>2]=l,n[l+24>>2]=c),s=n[s+4>>2]|0,s|0&&(n[c+20>>2]=s,n[s+24>>2]=c)}}while(0);if(n[k+4>>2]=d|1,n[B+d>>2]=d,(k|0)==(n[2788]|0)){n[2785]=d;return}}if(s=d>>>3,d>>>0<256){c=11172+(s<<1<<2)|0,l=n[2783]|0,s=1<>2]|0):(n[2783]=l|s,s=c,l=c+8|0),n[l>>2]=k,n[s+12>>2]=k,n[k+8>>2]=s,n[k+12>>2]=c;return}s=d>>>8,s?d>>>0>16777215?s=31:(B=(s+1048320|0)>>>16&8,Q=s<>>16&4,Q=Q<>>16&2,s=14-(m|B|s)+(Q<>>15)|0,s=d>>>(s+7|0)&1|s<<1):s=0,f=11436+(s<<2)|0,n[k+28>>2]=s,n[k+20>>2]=0,n[k+16>>2]=0,l=n[2784]|0,c=1<>>1)|0),c=n[f>>2]|0;;){if((n[c+4>>2]&-8|0)==(d|0)){s=73;break}if(f=c+16+(l>>>31<<2)|0,s=n[f>>2]|0,s)l=l<<1,c=s;else{s=72;break}}if((s|0)==72){n[f>>2]=k,n[k+24>>2]=c,n[k+12>>2]=k,n[k+8>>2]=k;break}else if((s|0)==73){B=c+8|0,Q=n[B>>2]|0,n[Q+12>>2]=k,n[B>>2]=k,n[k+8>>2]=Q,n[k+12>>2]=c,n[k+24>>2]=0;break}}else n[2784]=l|c,n[f>>2]=k,n[k+24>>2]=f,n[k+12>>2]=k,n[k+8>>2]=k;while(0);if(Q=(n[2791]|0)+-1|0,n[2791]=Q,!Q)s=11588;else return;for(;s=n[s>>2]|0,s;)s=s+8|0;n[2791]=-1}}}function kUe(){return 11628}function QUe(s){s=s|0;var l=0,c=0;return l=C,C=C+16|0,c=l,n[c>>2]=RUe(n[s+60>>2]|0)|0,s=gD(hc(6,c|0)|0)|0,C=l,s|0}function s7(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0,Ge=0;q=C,C=C+48|0,O=q+16|0,m=q,d=q+32|0,k=s+28|0,f=n[k>>2]|0,n[d>>2]=f,Q=s+20|0,f=(n[Q>>2]|0)-f|0,n[d+4>>2]=f,n[d+8>>2]=l,n[d+12>>2]=c,f=f+c|0,B=s+60|0,n[m>>2]=n[B>>2],n[m+4>>2]=d,n[m+8>>2]=2,m=gD(Li(146,m|0)|0)|0;e:do if((f|0)!=(m|0)){for(l=2;!((m|0)<0);)if(f=f-m|0,Ge=n[d+4>>2]|0,se=m>>>0>Ge>>>0,d=se?d+8|0:d,l=(se<<31>>31)+l|0,Ge=m-(se?Ge:0)|0,n[d>>2]=(n[d>>2]|0)+Ge,se=d+4|0,n[se>>2]=(n[se>>2]|0)-Ge,n[O>>2]=n[B>>2],n[O+4>>2]=d,n[O+8>>2]=l,m=gD(Li(146,O|0)|0)|0,(f|0)==(m|0)){M=3;break e}n[s+16>>2]=0,n[k>>2]=0,n[Q>>2]=0,n[s>>2]=n[s>>2]|32,(l|0)==2?c=0:c=c-(n[d+4>>2]|0)|0}else M=3;while(0);return(M|0)==3&&(Ge=n[s+44>>2]|0,n[s+16>>2]=Ge+(n[s+48>>2]|0),n[k>>2]=Ge,n[Q>>2]=Ge),C=q,c|0}function FUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;return d=C,C=C+32|0,m=d,f=d+20|0,n[m>>2]=n[s+60>>2],n[m+4>>2]=0,n[m+8>>2]=l,n[m+12>>2]=f,n[m+16>>2]=c,(gD(sa(140,m|0)|0)|0)<0?(n[f>>2]=-1,s=-1):s=n[f>>2]|0,C=d,s|0}function gD(s){return s=s|0,s>>>0>4294963200&&(n[(Vm()|0)>>2]=0-s,s=-1),s|0}function Vm(){return(TUe()|0)+64|0}function TUe(){return xT()|0}function xT(){return 2084}function RUe(s){return s=s|0,s|0}function NUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;return d=C,C=C+32|0,f=d,n[s+36>>2]=1,(n[s>>2]&64|0)==0&&(n[f>>2]=n[s+60>>2],n[f+4>>2]=21523,n[f+8>>2]=d+16,fu(54,f|0)|0)&&(o[s+75>>0]=-1),f=s7(s,l,c)|0,C=d,f|0}function o7(s,l){s=s|0,l=l|0;var c=0,f=0;if(c=o[s>>0]|0,f=o[l>>0]|0,c<<24>>24==0||c<<24>>24!=f<<24>>24)s=f;else{do s=s+1|0,l=l+1|0,c=o[s>>0]|0,f=o[l>>0]|0;while(!(c<<24>>24==0||c<<24>>24!=f<<24>>24));s=f}return(c&255)-(s&255)|0}function LUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;e:do if(!c)s=0;else{for(;f=o[s>>0]|0,d=o[l>>0]|0,f<<24>>24==d<<24>>24;)if(c=c+-1|0,c)s=s+1|0,l=l+1|0;else{s=0;break e}s=(f&255)-(d&255)|0}while(0);return s|0}function a7(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0,Ge=0,Oe=0,Fe=0;Fe=C,C=C+224|0,M=Fe+120|0,q=Fe+80|0,Ge=Fe,Oe=Fe+136|0,f=q,d=f+40|0;do n[f>>2]=0,f=f+4|0;while((f|0)<(d|0));return n[M>>2]=n[c>>2],(bT(0,l,M,Ge,q)|0)<0?c=-1:((n[s+76>>2]|0)>-1?se=MUe(s)|0:se=0,c=n[s>>2]|0,O=c&32,(o[s+74>>0]|0)<1&&(n[s>>2]=c&-33),f=s+48|0,n[f>>2]|0?c=bT(s,l,M,Ge,q)|0:(d=s+44|0,m=n[d>>2]|0,n[d>>2]=Oe,B=s+28|0,n[B>>2]=Oe,k=s+20|0,n[k>>2]=Oe,n[f>>2]=80,Q=s+16|0,n[Q>>2]=Oe+80,c=bT(s,l,M,Ge,q)|0,m&&(ED[n[s+36>>2]&7](s,0,0)|0,c=(n[k>>2]|0)==0?-1:c,n[d>>2]=m,n[f>>2]=0,n[Q>>2]=0,n[B>>2]=0,n[k>>2]=0)),f=n[s>>2]|0,n[s>>2]=f|O,se|0&&OUe(s),c=(f&32|0)==0?c:-1),C=Fe,c|0}function bT(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0,Ge=0,Oe=0,Fe=0,et=0,Xe=0,at=0,Ue=0,qe=0,Lt=0,Or=0,or=0,Xt=0,Pr=0,Nr=0,ir=0;ir=C,C=C+64|0,or=ir+16|0,Xt=ir,Lt=ir+24|0,Pr=ir+8|0,Nr=ir+20|0,n[or>>2]=l,at=(s|0)!=0,Ue=Lt+40|0,qe=Ue,Lt=Lt+39|0,Or=Pr+4|0,B=0,m=0,M=0;e:for(;;){do if((m|0)>-1)if((B|0)>(2147483647-m|0)){n[(Vm()|0)>>2]=75,m=-1;break}else{m=B+m|0;break}while(0);if(B=o[l>>0]|0,B<<24>>24)k=l;else{Xe=87;break}t:for(;;){switch(B<<24>>24){case 37:{B=k,Xe=9;break t}case 0:{B=k;break t}default:}et=k+1|0,n[or>>2]=et,B=o[et>>0]|0,k=et}t:do if((Xe|0)==9)for(;;){if(Xe=0,(o[k+1>>0]|0)!=37)break t;if(B=B+1|0,k=k+2|0,n[or>>2]=k,(o[k>>0]|0)==37)Xe=9;else break}while(0);if(B=B-l|0,at&&ss(s,l,B),B|0){l=k;continue}Q=k+1|0,B=(o[Q>>0]|0)+-48|0,B>>>0<10?(et=(o[k+2>>0]|0)==36,Fe=et?B:-1,M=et?1:M,Q=et?k+3|0:Q):Fe=-1,n[or>>2]=Q,B=o[Q>>0]|0,k=(B<<24>>24)+-32|0;t:do if(k>>>0<32)for(O=0,q=B;;){if(B=1<>2]=Q,B=o[Q>>0]|0,k=(B<<24>>24)+-32|0,k>>>0>=32)break;q=B}else O=0;while(0);if(B<<24>>24==42){if(k=Q+1|0,B=(o[k>>0]|0)+-48|0,B>>>0<10&&(o[Q+2>>0]|0)==36)n[d+(B<<2)>>2]=10,B=n[f+((o[k>>0]|0)+-48<<3)>>2]|0,M=1,Q=Q+3|0;else{if(M|0){m=-1;break}at?(M=(n[c>>2]|0)+(4-1)&~(4-1),B=n[M>>2]|0,n[c>>2]=M+4,M=0,Q=k):(B=0,M=0,Q=k)}n[or>>2]=Q,et=(B|0)<0,B=et?0-B|0:B,O=et?O|8192:O}else{if(B=l7(or)|0,(B|0)<0){m=-1;break}Q=n[or>>2]|0}do if((o[Q>>0]|0)==46){if((o[Q+1>>0]|0)!=42){n[or>>2]=Q+1,k=l7(or)|0,Q=n[or>>2]|0;break}if(q=Q+2|0,k=(o[q>>0]|0)+-48|0,k>>>0<10&&(o[Q+3>>0]|0)==36){n[d+(k<<2)>>2]=10,k=n[f+((o[q>>0]|0)+-48<<3)>>2]|0,Q=Q+4|0,n[or>>2]=Q;break}if(M|0){m=-1;break e}at?(et=(n[c>>2]|0)+(4-1)&~(4-1),k=n[et>>2]|0,n[c>>2]=et+4):k=0,n[or>>2]=q,Q=q}else k=-1;while(0);for(Oe=0;;){if(((o[Q>>0]|0)+-65|0)>>>0>57){m=-1;break e}if(et=Q+1|0,n[or>>2]=et,q=o[(o[Q>>0]|0)+-65+(5178+(Oe*58|0))>>0]|0,se=q&255,(se+-1|0)>>>0<8)Oe=se,Q=et;else break}if(!(q<<24>>24)){m=-1;break}Ge=(Fe|0)>-1;do if(q<<24>>24==19)if(Ge){m=-1;break e}else Xe=49;else{if(Ge){n[d+(Fe<<2)>>2]=se,Ge=f+(Fe<<3)|0,Fe=n[Ge+4>>2]|0,Xe=Xt,n[Xe>>2]=n[Ge>>2],n[Xe+4>>2]=Fe,Xe=49;break}if(!at){m=0;break e}c7(Xt,se,c)}while(0);if((Xe|0)==49&&(Xe=0,!at)){B=0,l=et;continue}Q=o[Q>>0]|0,Q=(Oe|0)!=0&(Q&15|0)==3?Q&-33:Q,Ge=O&-65537,Fe=(O&8192|0)==0?O:Ge;t:do switch(Q|0){case 110:switch((Oe&255)<<24>>24){case 0:{n[n[Xt>>2]>>2]=m,B=0,l=et;continue e}case 1:{n[n[Xt>>2]>>2]=m,B=0,l=et;continue e}case 2:{B=n[Xt>>2]|0,n[B>>2]=m,n[B+4>>2]=((m|0)<0)<<31>>31,B=0,l=et;continue e}case 3:{a[n[Xt>>2]>>1]=m,B=0,l=et;continue e}case 4:{o[n[Xt>>2]>>0]=m,B=0,l=et;continue e}case 6:{n[n[Xt>>2]>>2]=m,B=0,l=et;continue e}case 7:{B=n[Xt>>2]|0,n[B>>2]=m,n[B+4>>2]=((m|0)<0)<<31>>31,B=0,l=et;continue e}default:{B=0,l=et;continue e}}case 112:{Q=120,k=k>>>0>8?k:8,l=Fe|8,Xe=61;break}case 88:case 120:{l=Fe,Xe=61;break}case 111:{Q=Xt,l=n[Q>>2]|0,Q=n[Q+4>>2]|0,se=_Ue(l,Q,Ue)|0,Ge=qe-se|0,O=0,q=5642,k=(Fe&8|0)==0|(k|0)>(Ge|0)?k:Ge+1|0,Ge=Fe,Xe=67;break}case 105:case 100:if(Q=Xt,l=n[Q>>2]|0,Q=n[Q+4>>2]|0,(Q|0)<0){l=dD(0,0,l|0,Q|0)|0,Q=De,O=Xt,n[O>>2]=l,n[O+4>>2]=Q,O=1,q=5642,Xe=66;break t}else{O=(Fe&2049|0)!=0&1,q=(Fe&2048|0)==0?(Fe&1|0)==0?5642:5644:5643,Xe=66;break t}case 117:{Q=Xt,O=0,q=5642,l=n[Q>>2]|0,Q=n[Q+4>>2]|0,Xe=66;break}case 99:{o[Lt>>0]=n[Xt>>2],l=Lt,O=0,q=5642,se=Ue,Q=1,k=Ge;break}case 109:{Q=HUe(n[(Vm()|0)>>2]|0)|0,Xe=71;break}case 115:{Q=n[Xt>>2]|0,Q=Q|0?Q:5652,Xe=71;break}case 67:{n[Pr>>2]=n[Xt>>2],n[Or>>2]=0,n[Xt>>2]=Pr,se=-1,Q=Pr,Xe=75;break}case 83:{l=n[Xt>>2]|0,k?(se=k,Q=l,Xe=75):(Bs(s,32,B,0,Fe),l=0,Xe=84);break}case 65:case 71:case 70:case 69:case 97:case 103:case 102:case 101:{B=qUe(s,+E[Xt>>3],B,k,Fe,Q)|0,l=et;continue e}default:O=0,q=5642,se=Ue,Q=k,k=Fe}while(0);t:do if((Xe|0)==61)Fe=Xt,Oe=n[Fe>>2]|0,Fe=n[Fe+4>>2]|0,se=UUe(Oe,Fe,Ue,Q&32)|0,q=(l&8|0)==0|(Oe|0)==0&(Fe|0)==0,O=q?0:2,q=q?5642:5642+(Q>>4)|0,Ge=l,l=Oe,Q=Fe,Xe=67;else if((Xe|0)==66)se=Km(l,Q,Ue)|0,Ge=Fe,Xe=67;else if((Xe|0)==71)Xe=0,Fe=jUe(Q,0,k)|0,Oe=(Fe|0)==0,l=Q,O=0,q=5642,se=Oe?Q+k|0:Fe,Q=Oe?k:Fe-Q|0,k=Ge;else if((Xe|0)==75){for(Xe=0,q=Q,l=0,k=0;O=n[q>>2]|0,!(!O||(k=u7(Nr,O)|0,(k|0)<0|k>>>0>(se-l|0)>>>0));)if(l=k+l|0,se>>>0>l>>>0)q=q+4|0;else break;if((k|0)<0){m=-1;break e}if(Bs(s,32,B,l,Fe),!l)l=0,Xe=84;else for(O=0;;){if(k=n[Q>>2]|0,!k){Xe=84;break t}if(k=u7(Nr,k)|0,O=k+O|0,(O|0)>(l|0)){Xe=84;break t}if(ss(s,Nr,k),O>>>0>=l>>>0){Xe=84;break}else Q=Q+4|0}}while(0);if((Xe|0)==67)Xe=0,Q=(l|0)!=0|(Q|0)!=0,Fe=(k|0)!=0|Q,Q=((Q^1)&1)+(qe-se)|0,l=Fe?se:Ue,se=Ue,Q=Fe?(k|0)>(Q|0)?k:Q:k,k=(k|0)>-1?Ge&-65537:Ge;else if((Xe|0)==84){Xe=0,Bs(s,32,B,l,Fe^8192),B=(B|0)>(l|0)?B:l,l=et;continue}Oe=se-l|0,Ge=(Q|0)<(Oe|0)?Oe:Q,Fe=Ge+O|0,B=(B|0)<(Fe|0)?Fe:B,Bs(s,32,B,Fe,k),ss(s,q,O),Bs(s,48,B,Fe,k^65536),Bs(s,48,Ge,Oe,0),ss(s,l,Oe),Bs(s,32,B,Fe,k^8192),l=et}e:do if((Xe|0)==87&&!s)if(!M)m=0;else{for(m=1;l=n[d+(m<<2)>>2]|0,!!l;)if(c7(f+(m<<3)|0,l,c),m=m+1|0,(m|0)>=10){m=1;break e}for(;;){if(n[d+(m<<2)>>2]|0){m=-1;break e}if(m=m+1|0,(m|0)>=10){m=1;break}}}while(0);return C=ir,m|0}function MUe(s){return s=s|0,0}function OUe(s){s=s|0}function ss(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]&32||ZUe(l,c,s)|0}function l7(s){s=s|0;var l=0,c=0,f=0;if(c=n[s>>2]|0,f=(o[c>>0]|0)+-48|0,f>>>0<10){l=0;do l=f+(l*10|0)|0,c=c+1|0,n[s>>2]=c,f=(o[c>>0]|0)+-48|0;while(f>>>0<10)}else l=0;return l|0}function c7(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;e:do if(l>>>0<=20)do switch(l|0){case 9:{f=(n[c>>2]|0)+(4-1)&~(4-1),l=n[f>>2]|0,n[c>>2]=f+4,n[s>>2]=l;break e}case 10:{f=(n[c>>2]|0)+(4-1)&~(4-1),l=n[f>>2]|0,n[c>>2]=f+4,f=s,n[f>>2]=l,n[f+4>>2]=((l|0)<0)<<31>>31;break e}case 11:{f=(n[c>>2]|0)+(4-1)&~(4-1),l=n[f>>2]|0,n[c>>2]=f+4,f=s,n[f>>2]=l,n[f+4>>2]=0;break e}case 12:{f=(n[c>>2]|0)+(8-1)&~(8-1),l=f,d=n[l>>2]|0,l=n[l+4>>2]|0,n[c>>2]=f+8,f=s,n[f>>2]=d,n[f+4>>2]=l;break e}case 13:{d=(n[c>>2]|0)+(4-1)&~(4-1),f=n[d>>2]|0,n[c>>2]=d+4,f=(f&65535)<<16>>16,d=s,n[d>>2]=f,n[d+4>>2]=((f|0)<0)<<31>>31;break e}case 14:{d=(n[c>>2]|0)+(4-1)&~(4-1),f=n[d>>2]|0,n[c>>2]=d+4,d=s,n[d>>2]=f&65535,n[d+4>>2]=0;break e}case 15:{d=(n[c>>2]|0)+(4-1)&~(4-1),f=n[d>>2]|0,n[c>>2]=d+4,f=(f&255)<<24>>24,d=s,n[d>>2]=f,n[d+4>>2]=((f|0)<0)<<31>>31;break e}case 16:{d=(n[c>>2]|0)+(4-1)&~(4-1),f=n[d>>2]|0,n[c>>2]=d+4,d=s,n[d>>2]=f&255,n[d+4>>2]=0;break e}case 17:{d=(n[c>>2]|0)+(8-1)&~(8-1),m=+E[d>>3],n[c>>2]=d+8,E[s>>3]=m;break e}case 18:{d=(n[c>>2]|0)+(8-1)&~(8-1),m=+E[d>>3],n[c>>2]=d+8,E[s>>3]=m;break e}default:break e}while(0);while(0)}function UUe(s,l,c,f){if(s=s|0,l=l|0,c=c|0,f=f|0,!((s|0)==0&(l|0)==0))do c=c+-1|0,o[c>>0]=u[5694+(s&15)>>0]|0|f,s=mD(s|0,l|0,4)|0,l=De;while(!((s|0)==0&(l|0)==0));return c|0}function _Ue(s,l,c){if(s=s|0,l=l|0,c=c|0,!((s|0)==0&(l|0)==0))do c=c+-1|0,o[c>>0]=s&7|48,s=mD(s|0,l|0,3)|0,l=De;while(!((s|0)==0&(l|0)==0));return c|0}function Km(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;if(l>>>0>0|(l|0)==0&s>>>0>4294967295){for(;f=TT(s|0,l|0,10,0)|0,c=c+-1|0,o[c>>0]=f&255|48,f=s,s=FT(s|0,l|0,10,0)|0,l>>>0>9|(l|0)==9&f>>>0>4294967295;)l=De;l=s}else l=s;if(l)for(;c=c+-1|0,o[c>>0]=(l>>>0)%10|0|48,!(l>>>0<10);)l=(l>>>0)/10|0;return c|0}function HUe(s){return s=s|0,KUe(s,n[(VUe()|0)+188>>2]|0)|0}function jUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;m=l&255,f=(c|0)!=0;e:do if(f&(s&3|0)!=0)for(d=l&255;;){if((o[s>>0]|0)==d<<24>>24){B=6;break e}if(s=s+1|0,c=c+-1|0,f=(c|0)!=0,!(f&(s&3|0)!=0)){B=5;break}}else B=5;while(0);(B|0)==5&&(f?B=6:c=0);e:do if((B|0)==6&&(d=l&255,(o[s>>0]|0)!=d<<24>>24)){f=He(m,16843009)|0;t:do if(c>>>0>3){for(;m=n[s>>2]^f,!((m&-2139062144^-2139062144)&m+-16843009|0);)if(s=s+4|0,c=c+-4|0,c>>>0<=3){B=11;break t}}else B=11;while(0);if((B|0)==11&&!c){c=0;break}for(;;){if((o[s>>0]|0)==d<<24>>24)break e;if(s=s+1|0,c=c+-1|0,!c){c=0;break}}}while(0);return(c|0?s:0)|0}function Bs(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0;if(B=C,C=C+256|0,m=B,(c|0)>(f|0)&(d&73728|0)==0){if(d=c-f|0,zm(m|0,l|0,(d>>>0<256?d:256)|0)|0,d>>>0>255){l=c-f|0;do ss(s,m,256),d=d+-256|0;while(d>>>0>255);d=l&255}ss(s,m,d)}C=B}function u7(s,l){return s=s|0,l=l|0,s?s=YUe(s,l,0)|0:s=0,s|0}function qUe(s,l,c,f,d,m){s=s|0,l=+l,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,O=0,M=0,q=0,se=0,Ge=0,Oe=0,Fe=0,et=0,Xe=0,at=0,Ue=0,qe=0,Lt=0,Or=0,or=0,Xt=0,Pr=0,Nr=0,ir=0,bn=0;bn=C,C=C+560|0,Q=bn+8|0,et=bn,ir=bn+524|0,Nr=ir,O=bn+512|0,n[et>>2]=0,Pr=O+12|0,A7(l)|0,(De|0)<0?(l=-l,or=1,Or=5659):(or=(d&2049|0)!=0&1,Or=(d&2048|0)==0?(d&1|0)==0?5660:5665:5662),A7(l)|0,Xt=De&2146435072;do if(Xt>>>0<2146435072|(Xt|0)==2146435072&0<0){if(Ge=+GUe(l,et)*2,B=Ge!=0,B&&(n[et>>2]=(n[et>>2]|0)+-1),at=m|32,(at|0)==97){Oe=m&32,se=(Oe|0)==0?Or:Or+9|0,q=or|2,B=12-f|0;do if(f>>>0>11|(B|0)==0)l=Ge;else{l=8;do B=B+-1|0,l=l*16;while((B|0)!=0);if((o[se>>0]|0)==45){l=-(l+(-Ge-l));break}else{l=Ge+l-l;break}}while(0);k=n[et>>2]|0,B=(k|0)<0?0-k|0:k,B=Km(B,((B|0)<0)<<31>>31,Pr)|0,(B|0)==(Pr|0)&&(B=O+11|0,o[B>>0]=48),o[B+-1>>0]=(k>>31&2)+43,M=B+-2|0,o[M>>0]=m+15,O=(f|0)<1,Q=(d&8|0)==0,B=ir;do Xt=~~l,k=B+1|0,o[B>>0]=u[5694+Xt>>0]|Oe,l=(l-+(Xt|0))*16,(k-Nr|0)==1&&!(Q&(O&l==0))?(o[k>>0]=46,B=B+2|0):B=k;while(l!=0);Xt=B-Nr|0,Nr=Pr-M|0,Pr=(f|0)!=0&(Xt+-2|0)<(f|0)?f+2|0:Xt,B=Nr+q+Pr|0,Bs(s,32,c,B,d),ss(s,se,q),Bs(s,48,c,B,d^65536),ss(s,ir,Xt),Bs(s,48,Pr-Xt|0,0,0),ss(s,M,Nr),Bs(s,32,c,B,d^8192);break}k=(f|0)<0?6:f,B?(B=(n[et>>2]|0)+-28|0,n[et>>2]=B,l=Ge*268435456):(l=Ge,B=n[et>>2]|0),Xt=(B|0)<0?Q:Q+288|0,Q=Xt;do qe=~~l>>>0,n[Q>>2]=qe,Q=Q+4|0,l=(l-+(qe>>>0))*1e9;while(l!=0);if((B|0)>0)for(O=Xt,q=Q;;){if(M=(B|0)<29?B:29,B=q+-4|0,B>>>0>=O>>>0){Q=0;do Ue=m7(n[B>>2]|0,0,M|0)|0,Ue=QT(Ue|0,De|0,Q|0,0)|0,qe=De,Xe=TT(Ue|0,qe|0,1e9,0)|0,n[B>>2]=Xe,Q=FT(Ue|0,qe|0,1e9,0)|0,B=B+-4|0;while(B>>>0>=O>>>0);Q&&(O=O+-4|0,n[O>>2]=Q)}for(Q=q;!(Q>>>0<=O>>>0);)if(B=Q+-4|0,!(n[B>>2]|0))Q=B;else break;if(B=(n[et>>2]|0)-M|0,n[et>>2]=B,(B|0)>0)q=Q;else break}else O=Xt;if((B|0)<0){f=((k+25|0)/9|0)+1|0,Fe=(at|0)==102;do{if(Oe=0-B|0,Oe=(Oe|0)<9?Oe:9,O>>>0>>0){M=(1<>>Oe,se=0,B=O;do qe=n[B>>2]|0,n[B>>2]=(qe>>>Oe)+se,se=He(qe&M,q)|0,B=B+4|0;while(B>>>0>>0);B=(n[O>>2]|0)==0?O+4|0:O,se?(n[Q>>2]=se,O=B,B=Q+4|0):(O=B,B=Q)}else O=(n[O>>2]|0)==0?O+4|0:O,B=Q;Q=Fe?Xt:O,Q=(B-Q>>2|0)>(f|0)?Q+(f<<2)|0:B,B=(n[et>>2]|0)+Oe|0,n[et>>2]=B}while((B|0)<0);B=O,f=Q}else B=O,f=Q;if(qe=Xt,B>>>0>>0){if(Q=(qe-B>>2)*9|0,M=n[B>>2]|0,M>>>0>=10){O=10;do O=O*10|0,Q=Q+1|0;while(M>>>0>=O>>>0)}}else Q=0;if(Fe=(at|0)==103,Xe=(k|0)!=0,O=k-((at|0)!=102?Q:0)+((Xe&Fe)<<31>>31)|0,(O|0)<(((f-qe>>2)*9|0)+-9|0)){if(O=O+9216|0,Oe=Xt+4+(((O|0)/9|0)+-1024<<2)|0,O=((O|0)%9|0)+1|0,(O|0)<9){M=10;do M=M*10|0,O=O+1|0;while((O|0)!=9)}else M=10;if(q=n[Oe>>2]|0,se=(q>>>0)%(M>>>0)|0,O=(Oe+4|0)==(f|0),O&(se|0)==0)O=Oe;else if(Ge=(((q>>>0)/(M>>>0)|0)&1|0)==0?9007199254740992:9007199254740994,Ue=(M|0)/2|0,l=se>>>0>>0?.5:O&(se|0)==(Ue|0)?1:1.5,or&&(Ue=(o[Or>>0]|0)==45,l=Ue?-l:l,Ge=Ue?-Ge:Ge),O=q-se|0,n[Oe>>2]=O,Ge+l!=Ge){if(Ue=O+M|0,n[Oe>>2]=Ue,Ue>>>0>999999999)for(Q=Oe;O=Q+-4|0,n[Q>>2]=0,O>>>0>>0&&(B=B+-4|0,n[B>>2]=0),Ue=(n[O>>2]|0)+1|0,n[O>>2]=Ue,Ue>>>0>999999999;)Q=O;else O=Oe;if(Q=(qe-B>>2)*9|0,q=n[B>>2]|0,q>>>0>=10){M=10;do M=M*10|0,Q=Q+1|0;while(q>>>0>=M>>>0)}}else O=Oe;O=O+4|0,O=f>>>0>O>>>0?O:f,Ue=B}else O=f,Ue=B;for(at=O;;){if(at>>>0<=Ue>>>0){et=0;break}if(B=at+-4|0,!(n[B>>2]|0))at=B;else{et=1;break}}f=0-Q|0;do if(Fe)if(B=((Xe^1)&1)+k|0,(B|0)>(Q|0)&(Q|0)>-5?(M=m+-1|0,k=B+-1-Q|0):(M=m+-2|0,k=B+-1|0),B=d&8,B)Oe=B;else{if(et&&(Lt=n[at+-4>>2]|0,(Lt|0)!=0))if((Lt>>>0)%10|0)O=0;else{O=0,B=10;do B=B*10|0,O=O+1|0;while(!((Lt>>>0)%(B>>>0)|0|0))}else O=9;if(B=((at-qe>>2)*9|0)+-9|0,(M|32|0)==102){Oe=B-O|0,Oe=(Oe|0)>0?Oe:0,k=(k|0)<(Oe|0)?k:Oe,Oe=0;break}else{Oe=B+Q-O|0,Oe=(Oe|0)>0?Oe:0,k=(k|0)<(Oe|0)?k:Oe,Oe=0;break}}else M=m,Oe=d&8;while(0);if(Fe=k|Oe,q=(Fe|0)!=0&1,se=(M|32|0)==102,se)Xe=0,B=(Q|0)>0?Q:0;else{if(B=(Q|0)<0?f:Q,B=Km(B,((B|0)<0)<<31>>31,Pr)|0,O=Pr,(O-B|0)<2)do B=B+-1|0,o[B>>0]=48;while((O-B|0)<2);o[B+-1>>0]=(Q>>31&2)+43,B=B+-2|0,o[B>>0]=M,Xe=B,B=O-B|0}if(B=or+1+k+q+B|0,Bs(s,32,c,B,d),ss(s,Or,or),Bs(s,48,c,B,d^65536),se){M=Ue>>>0>Xt>>>0?Xt:Ue,Oe=ir+9|0,q=Oe,se=ir+8|0,O=M;do{if(Q=Km(n[O>>2]|0,0,Oe)|0,(O|0)==(M|0))(Q|0)==(Oe|0)&&(o[se>>0]=48,Q=se);else if(Q>>>0>ir>>>0){zm(ir|0,48,Q-Nr|0)|0;do Q=Q+-1|0;while(Q>>>0>ir>>>0)}ss(s,Q,q-Q|0),O=O+4|0}while(O>>>0<=Xt>>>0);if(Fe|0&&ss(s,5710,1),O>>>0>>0&(k|0)>0)for(;;){if(Q=Km(n[O>>2]|0,0,Oe)|0,Q>>>0>ir>>>0){zm(ir|0,48,Q-Nr|0)|0;do Q=Q+-1|0;while(Q>>>0>ir>>>0)}if(ss(s,Q,(k|0)<9?k:9),O=O+4|0,Q=k+-9|0,O>>>0>>0&(k|0)>9)k=Q;else{k=Q;break}}Bs(s,48,k+9|0,9,0)}else{if(Fe=et?at:Ue+4|0,(k|0)>-1){et=ir+9|0,Oe=(Oe|0)==0,f=et,q=0-Nr|0,se=ir+8|0,M=Ue;do{Q=Km(n[M>>2]|0,0,et)|0,(Q|0)==(et|0)&&(o[se>>0]=48,Q=se);do if((M|0)==(Ue|0)){if(O=Q+1|0,ss(s,Q,1),Oe&(k|0)<1){Q=O;break}ss(s,5710,1),Q=O}else{if(Q>>>0<=ir>>>0)break;zm(ir|0,48,Q+q|0)|0;do Q=Q+-1|0;while(Q>>>0>ir>>>0)}while(0);Nr=f-Q|0,ss(s,Q,(k|0)>(Nr|0)?Nr:k),k=k-Nr|0,M=M+4|0}while(M>>>0>>0&(k|0)>-1)}Bs(s,48,k+18|0,18,0),ss(s,Xe,Pr-Xe|0)}Bs(s,32,c,B,d^8192)}else ir=(m&32|0)!=0,B=or+3|0,Bs(s,32,c,B,d&-65537),ss(s,Or,or),ss(s,l!=l|!1?ir?5686:5690:ir?5678:5682,3),Bs(s,32,c,B,d^8192);while(0);return C=bn,((B|0)<(c|0)?c:B)|0}function A7(s){s=+s;var l=0;return E[v>>3]=s,l=n[v>>2]|0,De=n[v+4>>2]|0,l|0}function GUe(s,l){return s=+s,l=l|0,+ +f7(s,l)}function f7(s,l){s=+s,l=l|0;var c=0,f=0,d=0;switch(E[v>>3]=s,c=n[v>>2]|0,f=n[v+4>>2]|0,d=mD(c|0,f|0,52)|0,d&2047){case 0:{s!=0?(s=+f7(s*18446744073709552e3,l),c=(n[l>>2]|0)+-64|0):c=0,n[l>>2]=c;break}case 2047:break;default:n[l>>2]=(d&2047)+-1022,n[v>>2]=c,n[v+4>>2]=f&-2146435073|1071644672,s=+E[v>>3]}return+s}function YUe(s,l,c){s=s|0,l=l|0,c=c|0;do if(s){if(l>>>0<128){o[s>>0]=l,s=1;break}if(!(n[n[(WUe()|0)+188>>2]>>2]|0))if((l&-128|0)==57216){o[s>>0]=l,s=1;break}else{n[(Vm()|0)>>2]=84,s=-1;break}if(l>>>0<2048){o[s>>0]=l>>>6|192,o[s+1>>0]=l&63|128,s=2;break}if(l>>>0<55296|(l&-8192|0)==57344){o[s>>0]=l>>>12|224,o[s+1>>0]=l>>>6&63|128,o[s+2>>0]=l&63|128,s=3;break}if((l+-65536|0)>>>0<1048576){o[s>>0]=l>>>18|240,o[s+1>>0]=l>>>12&63|128,o[s+2>>0]=l>>>6&63|128,o[s+3>>0]=l&63|128,s=4;break}else{n[(Vm()|0)>>2]=84,s=-1;break}}else s=1;while(0);return s|0}function WUe(){return xT()|0}function VUe(){return xT()|0}function KUe(s,l){s=s|0,l=l|0;var c=0,f=0;for(f=0;;){if((u[5712+f>>0]|0)==(s|0)){s=2;break}if(c=f+1|0,(c|0)==87){c=5800,f=87,s=5;break}else f=c}if((s|0)==2&&(f?(c=5800,s=5):c=5800),(s|0)==5)for(;;){do s=c,c=c+1|0;while((o[s>>0]|0)!=0);if(f=f+-1|0,f)s=5;else break}return JUe(c,n[l+20>>2]|0)|0}function JUe(s,l){return s=s|0,l=l|0,zUe(s,l)|0}function zUe(s,l){return s=s|0,l=l|0,l?l=XUe(n[l>>2]|0,n[l+4>>2]|0,s)|0:l=0,(l|0?l:s)|0}function XUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0;se=(n[s>>2]|0)+1794895138|0,m=Fg(n[s+8>>2]|0,se)|0,f=Fg(n[s+12>>2]|0,se)|0,d=Fg(n[s+16>>2]|0,se)|0;e:do if(m>>>0>>2>>>0&&(q=l-(m<<2)|0,f>>>0>>0&d>>>0>>0)&&((d|f)&3|0)==0){for(q=f>>>2,M=d>>>2,O=0;;){if(k=m>>>1,Q=O+k|0,B=Q<<1,d=B+q|0,f=Fg(n[s+(d<<2)>>2]|0,se)|0,d=Fg(n[s+(d+1<<2)>>2]|0,se)|0,!(d>>>0>>0&f>>>0<(l-d|0)>>>0)){f=0;break e}if(o[s+(d+f)>>0]|0){f=0;break e}if(f=o7(c,s+d|0)|0,!f)break;if(f=(f|0)<0,(m|0)==1){f=0;break e}else O=f?O:Q,m=f?k:m-k|0}f=B+M|0,d=Fg(n[s+(f<<2)>>2]|0,se)|0,f=Fg(n[s+(f+1<<2)>>2]|0,se)|0,f>>>0>>0&d>>>0<(l-f|0)>>>0?f=(o[s+(f+d)>>0]|0)==0?s+f|0:0:f=0}else f=0;while(0);return f|0}function Fg(s,l){s=s|0,l=l|0;var c=0;return c=C7(s|0)|0,((l|0)==0?s:c)|0}function ZUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=c+16|0,d=n[f>>2]|0,d?m=5:$Ue(c)|0?f=0:(d=n[f>>2]|0,m=5);e:do if((m|0)==5){if(k=c+20|0,B=n[k>>2]|0,f=B,(d-B|0)>>>0>>0){f=ED[n[c+36>>2]&7](c,s,l)|0;break}t:do if((o[c+75>>0]|0)>-1){for(B=l;;){if(!B){m=0,d=s;break t}if(d=B+-1|0,(o[s+d>>0]|0)==10)break;B=d}if(f=ED[n[c+36>>2]&7](c,s,B)|0,f>>>0>>0)break e;m=B,d=s+B|0,l=l-B|0,f=n[k>>2]|0}else m=0,d=s;while(0);Dr(f|0,d|0,l|0)|0,n[k>>2]=(n[k>>2]|0)+l,f=m+l|0}while(0);return f|0}function $Ue(s){s=s|0;var l=0,c=0;return l=s+74|0,c=o[l>>0]|0,o[l>>0]=c+255|c,l=n[s>>2]|0,l&8?(n[s>>2]=l|32,s=-1):(n[s+8>>2]=0,n[s+4>>2]=0,c=n[s+44>>2]|0,n[s+28>>2]=c,n[s+20>>2]=c,n[s+16>>2]=c+(n[s+48>>2]|0),s=0),s|0}function _n(s,l){s=y(s),l=y(l);var c=0,f=0;c=p7(s)|0;do if((c&2147483647)>>>0<=2139095040){if(f=p7(l)|0,(f&2147483647)>>>0<=2139095040)if((f^c|0)<0){s=(c|0)<0?l:s;break}else{s=s>2]=s,n[v>>2]|0|0}function Tg(s,l){s=y(s),l=y(l);var c=0,f=0;c=h7(s)|0;do if((c&2147483647)>>>0<=2139095040){if(f=h7(l)|0,(f&2147483647)>>>0<=2139095040)if((f^c|0)<0){s=(c|0)<0?s:l;break}else{s=s>2]=s,n[v>>2]|0|0}function kT(s,l){s=y(s),l=y(l);var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,O=0;m=(h[v>>2]=s,n[v>>2]|0),k=(h[v>>2]=l,n[v>>2]|0),c=m>>>23&255,B=k>>>23&255,Q=m&-2147483648,d=k<<1;e:do if((d|0)!=0&&!((c|0)==255|((e3e(l)|0)&2147483647)>>>0>2139095040)){if(f=m<<1,f>>>0<=d>>>0)return l=y(s*y(0)),y((f|0)==(d|0)?l:s);if(c)f=m&8388607|8388608;else{if(c=m<<9,(c|0)>-1){f=c,c=0;do c=c+-1|0,f=f<<1;while((f|0)>-1)}else c=0;f=m<<1-c}if(B)k=k&8388607|8388608;else{if(m=k<<9,(m|0)>-1){d=0;do d=d+-1|0,m=m<<1;while((m|0)>-1)}else d=0;B=d,k=k<<1-d}d=f-k|0,m=(d|0)>-1;t:do if((c|0)>(B|0)){for(;;){if(m)if(d)f=d;else break;if(f=f<<1,c=c+-1|0,d=f-k|0,m=(d|0)>-1,(c|0)<=(B|0))break t}l=y(s*y(0));break e}while(0);if(m)if(d)f=d;else{l=y(s*y(0));break}if(f>>>0<8388608)do f=f<<1,c=c+-1|0;while(f>>>0<8388608);(c|0)>0?c=f+-8388608|c<<23:c=f>>>(1-c|0),l=(n[v>>2]=c|Q,y(h[v>>2]))}else O=3;while(0);return(O|0)==3&&(l=y(s*l),l=y(l/l)),y(l)}function e3e(s){return s=y(s),h[v>>2]=s,n[v>>2]|0|0}function t3e(s,l){return s=s|0,l=l|0,a7(n[582]|0,s,l)|0}function zr(s){s=s|0,Tt()}function Jm(s){s=s|0}function r3e(s,l){return s=s|0,l=l|0,0}function n3e(s){return s=s|0,(g7(s+4|0)|0)==-1?(ef[n[(n[s>>2]|0)+8>>2]&127](s),s=1):s=0,s|0}function g7(s){s=s|0;var l=0;return l=n[s>>2]|0,n[s>>2]=l+-1,l+-1|0}function bp(s){s=s|0,n3e(s)|0&&i3e(s)}function i3e(s){s=s|0;var l=0;l=s+8|0,(n[l>>2]|0)!=0&&(g7(l)|0)!=-1||ef[n[(n[s>>2]|0)+16>>2]&127](s)}function Vt(s){s=s|0;var l=0;for(l=(s|0)==0?1:s;s=pD(l)|0,!(s|0);){if(s=o3e()|0,!s){s=0;break}k7[s&0]()}return s|0}function d7(s){return s=s|0,Vt(s)|0}function gt(s){s=s|0,hD(s)}function s3e(s){s=s|0,(o[s+11>>0]|0)<0&>(n[s>>2]|0)}function o3e(){var s=0;return s=n[2923]|0,n[2923]=s+0,s|0}function a3e(){}function dD(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,f=l-f-(c>>>0>s>>>0|0)>>>0,De=f,s-c>>>0|0|0}function QT(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,c=s+c>>>0,De=l+f+(c>>>0>>0|0)>>>0,c|0|0}function zm(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;if(m=s+c|0,l=l&255,(c|0)>=67){for(;s&3;)o[s>>0]=l,s=s+1|0;for(f=m&-4|0,d=f-64|0,B=l|l<<8|l<<16|l<<24;(s|0)<=(d|0);)n[s>>2]=B,n[s+4>>2]=B,n[s+8>>2]=B,n[s+12>>2]=B,n[s+16>>2]=B,n[s+20>>2]=B,n[s+24>>2]=B,n[s+28>>2]=B,n[s+32>>2]=B,n[s+36>>2]=B,n[s+40>>2]=B,n[s+44>>2]=B,n[s+48>>2]=B,n[s+52>>2]=B,n[s+56>>2]=B,n[s+60>>2]=B,s=s+64|0;for(;(s|0)<(f|0);)n[s>>2]=B,s=s+4|0}for(;(s|0)<(m|0);)o[s>>0]=l,s=s+1|0;return m-c|0}function m7(s,l,c){return s=s|0,l=l|0,c=c|0,(c|0)<32?(De=l<>>32-c,s<>>c,s>>>c|(l&(1<>>c-32|0)}function Dr(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;if((c|0)>=8192)return Ac(s|0,l|0,c|0)|0;if(m=s|0,d=s+c|0,(s&3)==(l&3)){for(;s&3;){if(!c)return m|0;o[s>>0]=o[l>>0]|0,s=s+1|0,l=l+1|0,c=c-1|0}for(c=d&-4|0,f=c-64|0;(s|0)<=(f|0);)n[s>>2]=n[l>>2],n[s+4>>2]=n[l+4>>2],n[s+8>>2]=n[l+8>>2],n[s+12>>2]=n[l+12>>2],n[s+16>>2]=n[l+16>>2],n[s+20>>2]=n[l+20>>2],n[s+24>>2]=n[l+24>>2],n[s+28>>2]=n[l+28>>2],n[s+32>>2]=n[l+32>>2],n[s+36>>2]=n[l+36>>2],n[s+40>>2]=n[l+40>>2],n[s+44>>2]=n[l+44>>2],n[s+48>>2]=n[l+48>>2],n[s+52>>2]=n[l+52>>2],n[s+56>>2]=n[l+56>>2],n[s+60>>2]=n[l+60>>2],s=s+64|0,l=l+64|0;for(;(s|0)<(c|0);)n[s>>2]=n[l>>2],s=s+4|0,l=l+4|0}else for(c=d-4|0;(s|0)<(c|0);)o[s>>0]=o[l>>0]|0,o[s+1>>0]=o[l+1>>0]|0,o[s+2>>0]=o[l+2>>0]|0,o[s+3>>0]=o[l+3>>0]|0,s=s+4|0,l=l+4|0;for(;(s|0)<(d|0);)o[s>>0]=o[l>>0]|0,s=s+1|0,l=l+1|0;return m|0}function y7(s){s=s|0;var l=0;return l=o[L+(s&255)>>0]|0,(l|0)<8?l|0:(l=o[L+(s>>8&255)>>0]|0,(l|0)<8?l+8|0:(l=o[L+(s>>16&255)>>0]|0,(l|0)<8?l+16|0:(o[L+(s>>>24)>>0]|0)+24|0))}function E7(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,O=0,M=0,q=0,se=0,Ge=0,Oe=0;if(M=s,Q=l,O=Q,B=c,se=f,k=se,!O)return m=(d|0)!=0,k?m?(n[d>>2]=s|0,n[d+4>>2]=l&0,se=0,d=0,De=se,d|0):(se=0,d=0,De=se,d|0):(m&&(n[d>>2]=(M>>>0)%(B>>>0),n[d+4>>2]=0),se=0,d=(M>>>0)/(B>>>0)>>>0,De=se,d|0);m=(k|0)==0;do if(B){if(!m){if(m=(S(k|0)|0)-(S(O|0)|0)|0,m>>>0<=31){q=m+1|0,k=31-m|0,l=m-31>>31,B=q,s=M>>>(q>>>0)&l|O<>>(q>>>0)&l,m=0,k=M<>2]=s|0,n[d+4>>2]=Q|l&0,se=0,d=0,De=se,d|0):(se=0,d=0,De=se,d|0)}if(m=B-1|0,m&B|0){k=(S(B|0)|0)+33-(S(O|0)|0)|0,Oe=64-k|0,q=32-k|0,Q=q>>31,Ge=k-32|0,l=Ge>>31,B=k,s=q-1>>31&O>>>(Ge>>>0)|(O<>>(k>>>0))&l,l=l&O>>>(k>>>0),m=M<>>(Ge>>>0))&Q|M<>31;break}return d|0&&(n[d>>2]=m&M,n[d+4>>2]=0),(B|0)==1?(Ge=Q|l&0,Oe=s|0|0,De=Ge,Oe|0):(Oe=y7(B|0)|0,Ge=O>>>(Oe>>>0)|0,Oe=O<<32-Oe|M>>>(Oe>>>0)|0,De=Ge,Oe|0)}else{if(m)return d|0&&(n[d>>2]=(O>>>0)%(B>>>0),n[d+4>>2]=0),Ge=0,Oe=(O>>>0)/(B>>>0)>>>0,De=Ge,Oe|0;if(!M)return d|0&&(n[d>>2]=0,n[d+4>>2]=(O>>>0)%(k>>>0)),Ge=0,Oe=(O>>>0)/(k>>>0)>>>0,De=Ge,Oe|0;if(m=k-1|0,!(m&k))return d|0&&(n[d>>2]=s|0,n[d+4>>2]=m&O|l&0),Ge=0,Oe=O>>>((y7(k|0)|0)>>>0),De=Ge,Oe|0;if(m=(S(k|0)|0)-(S(O|0)|0)|0,m>>>0<=30){l=m+1|0,k=31-m|0,B=l,s=O<>>(l>>>0),l=O>>>(l>>>0),m=0,k=M<>2]=s|0,n[d+4>>2]=Q|l&0,Ge=0,Oe=0,De=Ge,Oe|0):(Ge=0,Oe=0,De=Ge,Oe|0)}while(0);if(!B)O=k,Q=0,k=0;else{q=c|0|0,M=se|f&0,O=QT(q|0,M|0,-1,-1)|0,c=De,Q=k,k=0;do f=Q,Q=m>>>31|Q<<1,m=k|m<<1,f=s<<1|f>>>31|0,se=s>>>31|l<<1|0,dD(O|0,c|0,f|0,se|0)|0,Oe=De,Ge=Oe>>31|((Oe|0)<0?-1:0)<<1,k=Ge&1,s=dD(f|0,se|0,Ge&q|0,(((Oe|0)<0?-1:0)>>31|((Oe|0)<0?-1:0)<<1)&M|0)|0,l=De,B=B-1|0;while((B|0)!=0);O=Q,Q=0}return B=0,d|0&&(n[d>>2]=s,n[d+4>>2]=l),Ge=(m|0)>>>31|(O|B)<<1|(B<<1|m>>>31)&0|Q,Oe=(m<<1|0>>>31)&-2|k,De=Ge,Oe|0}function FT(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,E7(s,l,c,f,0)|0}function kp(s){s=s|0;var l=0,c=0;return c=s+15&-16|0,l=n[I>>2]|0,s=l+c|0,(c|0)>0&(s|0)<(l|0)|(s|0)<0?(ie()|0,vA(12),-1):(n[I>>2]=s,(s|0)>(Z()|0)&&(X()|0)==0?(n[I>>2]=l,vA(12),-1):l|0)}function Mw(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;if((l|0)<(s|0)&(s|0)<(l+c|0)){for(f=s,l=l+c|0,s=s+c|0;(c|0)>0;)s=s-1|0,l=l-1|0,c=c-1|0,o[s>>0]=o[l>>0]|0;s=f}else Dr(s,l,c)|0;return s|0}function TT(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;return m=C,C=C+16|0,d=m|0,E7(s,l,c,f,d)|0,C=m,De=n[d+4>>2]|0,n[d>>2]|0|0}function C7(s){return s=s|0,(s&255)<<24|(s>>8&255)<<16|(s>>16&255)<<8|s>>>24|0}function l3e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,w7[s&1](l|0,c|0,f|0,d|0,m|0)}function c3e(s,l,c){s=s|0,l=l|0,c=y(c),I7[s&1](l|0,y(c))}function u3e(s,l,c){s=s|0,l=l|0,c=+c,B7[s&31](l|0,+c)}function A3e(s,l,c,f){return s=s|0,l=l|0,c=y(c),f=y(f),y(v7[s&0](l|0,y(c),y(f)))}function f3e(s,l){s=s|0,l=l|0,ef[s&127](l|0)}function p3e(s,l,c){s=s|0,l=l|0,c=c|0,tf[s&31](l|0,c|0)}function h3e(s,l){return s=s|0,l=l|0,Ng[s&31](l|0)|0}function g3e(s,l,c,f,d){s=s|0,l=l|0,c=+c,f=+f,d=d|0,D7[s&1](l|0,+c,+f,d|0)}function d3e(s,l,c,f){s=s|0,l=l|0,c=+c,f=+f,z3e[s&1](l|0,+c,+f)}function m3e(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,ED[s&7](l|0,c|0,f|0)|0}function y3e(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,+X3e[s&1](l|0,c|0,f|0)}function E3e(s,l){return s=s|0,l=l|0,+P7[s&15](l|0)}function C3e(s,l,c){return s=s|0,l=l|0,c=+c,Z3e[s&1](l|0,+c)|0}function w3e(s,l,c){return s=s|0,l=l|0,c=c|0,NT[s&15](l|0,c|0)|0}function I3e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=+f,d=+d,m=m|0,$3e[s&1](l|0,c|0,+f,+d,m|0)}function B3e(s,l,c,f,d,m,B){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,B=B|0,e_e[s&1](l|0,c|0,f|0,d|0,m|0,B|0)}function v3e(s,l,c){return s=s|0,l=l|0,c=c|0,+S7[s&7](l|0,c|0)}function D3e(s){return s=s|0,CD[s&7]()|0}function P3e(s,l,c,f,d,m){return s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,x7[s&1](l|0,c|0,f|0,d|0,m|0)|0}function S3e(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=+d,t_e[s&1](l|0,c|0,f|0,+d)}function x3e(s,l,c,f,d,m,B){s=s|0,l=l|0,c=c|0,f=y(f),d=d|0,m=y(m),B=B|0,b7[s&1](l|0,c|0,y(f),d|0,y(m),B|0)}function b3e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,_w[s&15](l|0,c|0,f|0)}function k3e(s){s=s|0,k7[s&0]()}function Q3e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=+f,Q7[s&15](l|0,c|0,+f)}function F3e(s,l,c){return s=s|0,l=+l,c=+c,r_e[s&1](+l,+c)|0}function T3e(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,LT[s&15](l|0,c|0,f|0,d|0)}function R3e(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,F(0)}function N3e(s,l){s=s|0,l=y(l),F(1)}function ma(s,l){s=s|0,l=+l,F(2)}function L3e(s,l,c){return s=s|0,l=y(l),c=y(c),F(3),Ze}function Er(s){s=s|0,F(4)}function Ow(s,l){s=s|0,l=l|0,F(5)}function Ja(s){return s=s|0,F(6),0}function M3e(s,l,c,f){s=s|0,l=+l,c=+c,f=f|0,F(7)}function O3e(s,l,c){s=s|0,l=+l,c=+c,F(8)}function U3e(s,l,c){return s=s|0,l=l|0,c=c|0,F(9),0}function _3e(s,l,c){return s=s|0,l=l|0,c=c|0,F(10),0}function Rg(s){return s=s|0,F(11),0}function H3e(s,l){return s=s|0,l=+l,F(12),0}function Uw(s,l){return s=s|0,l=l|0,F(13),0}function j3e(s,l,c,f,d){s=s|0,l=l|0,c=+c,f=+f,d=d|0,F(14)}function q3e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,F(15)}function RT(s,l){return s=s|0,l=l|0,F(16),0}function G3e(){return F(17),0}function Y3e(s,l,c,f,d){return s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,F(18),0}function W3e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=+f,F(19)}function V3e(s,l,c,f,d,m){s=s|0,l=l|0,c=y(c),f=f|0,d=y(d),m=m|0,F(20)}function yD(s,l,c){s=s|0,l=l|0,c=c|0,F(21)}function K3e(){F(22)}function Xm(s,l,c){s=s|0,l=l|0,c=+c,F(23)}function J3e(s,l){return s=+s,l=+l,F(24),0}function Zm(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,F(25)}var w7=[R3e,YLe],I7=[N3e,fo],B7=[ma,xw,bw,wF,IF,Dl,kw,BF,Hm,xu,Fw,vF,$v,WA,eD,jm,tD,rD,qm,ma,ma,ma,ma,ma,ma,ma,ma,ma,ma,ma,ma,ma],v7=[L3e],ef=[Er,Jm,DDe,PDe,SDe,rbe,nbe,ibe,CNe,wNe,INe,FLe,TLe,RLe,eUe,tUe,rUe,hs,Kv,_m,YA,Qw,wve,Ive,gDe,NDe,VDe,APe,SPe,GPe,aSe,ISe,MSe,$Se,gxe,Qxe,Vxe,wbe,Mbe,$be,gke,Qke,Vke,fQe,SQe,HQe,nFe,Sc,RFe,zFe,gTe,TTe,KTe,gRe,DRe,xRe,YRe,KRe,ANe,vNe,SNe,GNe,lLe,a5,qMe,COe,NOe,zOe,y4e,T4e,G4e,V4e,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er],tf=[Ow,hF,gF,Sw,Su,dF,mF,Ip,yF,EF,CF,Zv,VA,Ke,At,Wt,vr,Sn,Fr,PF,lve,Qve,dQe,kQe,MTe,WMe,dLe,Y9,Ow,Ow,Ow,Ow],Ng=[Ja,QUe,pF,D,fe,ve,vt,wt,bt,_r,di,po,sve,ove,Bve,oFe,ZTe,VNe,zMe,Wa,Ja,Ja,Ja,Ja,Ja,Ja,Ja,Ja,Ja,Ja,Ja,Ja],D7=[M3e,vve],z3e=[O3e,hNe],ED=[U3e,s7,FUe,NUe,KPe,Dbe,OFe,e4e],X3e=[_3e,Exe],P7=[Rg,Yo,rt,xn,Dve,Pve,Sve,xve,bve,kve,Rg,Rg,Rg,Rg,Rg,Rg],Z3e=[H3e,IRe],NT=[Uw,r3e,ave,EDe,gPe,uSe,DSe,Xxe,Hbe,YQe,Wv,UOe,Uw,Uw,Uw,Uw],$3e=[j3e,XDe],e_e=[q3e,I4e],S7=[RT,ai,Fve,Tve,Rve,Nxe,RT,RT],CD=[G3e,Nve,Dw,ga,FRe,ZRe,QNe,X4e],x7=[Y3e,Ew],t_e=[W3e,Eke],b7=[V3e,cve],_w=[yD,R,is,en,ho,QPe,_Se,Nke,Xke,Um,hMe,vOe,M4e,yD,yD,yD],k7=[K3e],Q7=[Xm,Jv,zv,Xv,GA,nD,DF,P,nke,eTe,yRe,Xm,Xm,Xm,Xm,Xm],r_e=[J3e,yNe],LT=[Zm,nxe,hFe,ETe,aRe,ORe,iNe,ONe,pLe,rOe,lUe,Zm,Zm,Zm,Zm,Zm];return{_llvm_bswap_i32:C7,dynCall_idd:F3e,dynCall_i:D3e,_i64Subtract:dD,___udivdi3:FT,dynCall_vif:c3e,setThrew:hu,dynCall_viii:b3e,_bitshift64Lshr:mD,_bitshift64Shl:m7,dynCall_vi:f3e,dynCall_viiddi:I3e,dynCall_diii:y3e,dynCall_iii:w3e,_memset:zm,_sbrk:kp,_memcpy:Dr,__GLOBAL__sub_I_Yoga_cpp:Om,dynCall_vii:p3e,___uremdi3:TT,dynCall_vid:u3e,stackAlloc:lo,_nbind_init:EUe,getTempRet0:Ua,dynCall_di:E3e,dynCall_iid:C3e,setTempRet0:xA,_i64Add:QT,dynCall_fiff:A3e,dynCall_iiii:m3e,_emscripten_get_global_libc:kUe,dynCall_viid:Q3e,dynCall_viiid:S3e,dynCall_viififi:x3e,dynCall_ii:h3e,__GLOBAL__sub_I_Binding_cc:NMe,dynCall_viiii:T3e,dynCall_iiiiii:P3e,stackSave:gc,dynCall_viiiii:l3e,__GLOBAL__sub_I_nbind_cc:Lve,dynCall_vidd:d3e,_free:hD,runPostSets:a3e,dynCall_viiiiii:B3e,establishStackSpace:ji,_memmove:Mw,stackRestore:pu,_malloc:pD,__GLOBAL__sub_I_common_cc:tLe,dynCall_viddi:g3e,dynCall_dii:v3e,dynCall_v:k3e}}(Module.asmGlobalArg,Module.asmLibraryArg,buffer),_llvm_bswap_i32=Module._llvm_bswap_i32=asm._llvm_bswap_i32,getTempRet0=Module.getTempRet0=asm.getTempRet0,___udivdi3=Module.___udivdi3=asm.___udivdi3,setThrew=Module.setThrew=asm.setThrew,_bitshift64Lshr=Module._bitshift64Lshr=asm._bitshift64Lshr,_bitshift64Shl=Module._bitshift64Shl=asm._bitshift64Shl,_memset=Module._memset=asm._memset,_sbrk=Module._sbrk=asm._sbrk,_memcpy=Module._memcpy=asm._memcpy,stackAlloc=Module.stackAlloc=asm.stackAlloc,___uremdi3=Module.___uremdi3=asm.___uremdi3,_nbind_init=Module._nbind_init=asm._nbind_init,_i64Subtract=Module._i64Subtract=asm._i64Subtract,setTempRet0=Module.setTempRet0=asm.setTempRet0,_i64Add=Module._i64Add=asm._i64Add,_emscripten_get_global_libc=Module._emscripten_get_global_libc=asm._emscripten_get_global_libc,__GLOBAL__sub_I_Yoga_cpp=Module.__GLOBAL__sub_I_Yoga_cpp=asm.__GLOBAL__sub_I_Yoga_cpp,__GLOBAL__sub_I_Binding_cc=Module.__GLOBAL__sub_I_Binding_cc=asm.__GLOBAL__sub_I_Binding_cc,stackSave=Module.stackSave=asm.stackSave,__GLOBAL__sub_I_nbind_cc=Module.__GLOBAL__sub_I_nbind_cc=asm.__GLOBAL__sub_I_nbind_cc,_free=Module._free=asm._free,runPostSets=Module.runPostSets=asm.runPostSets,establishStackSpace=Module.establishStackSpace=asm.establishStackSpace,_memmove=Module._memmove=asm._memmove,stackRestore=Module.stackRestore=asm.stackRestore,_malloc=Module._malloc=asm._malloc,__GLOBAL__sub_I_common_cc=Module.__GLOBAL__sub_I_common_cc=asm.__GLOBAL__sub_I_common_cc,dynCall_viiiii=Module.dynCall_viiiii=asm.dynCall_viiiii,dynCall_vif=Module.dynCall_vif=asm.dynCall_vif,dynCall_vid=Module.dynCall_vid=asm.dynCall_vid,dynCall_fiff=Module.dynCall_fiff=asm.dynCall_fiff,dynCall_vi=Module.dynCall_vi=asm.dynCall_vi,dynCall_vii=Module.dynCall_vii=asm.dynCall_vii,dynCall_ii=Module.dynCall_ii=asm.dynCall_ii,dynCall_viddi=Module.dynCall_viddi=asm.dynCall_viddi,dynCall_vidd=Module.dynCall_vidd=asm.dynCall_vidd,dynCall_iiii=Module.dynCall_iiii=asm.dynCall_iiii,dynCall_diii=Module.dynCall_diii=asm.dynCall_diii,dynCall_di=Module.dynCall_di=asm.dynCall_di,dynCall_iid=Module.dynCall_iid=asm.dynCall_iid,dynCall_iii=Module.dynCall_iii=asm.dynCall_iii,dynCall_viiddi=Module.dynCall_viiddi=asm.dynCall_viiddi,dynCall_viiiiii=Module.dynCall_viiiiii=asm.dynCall_viiiiii,dynCall_dii=Module.dynCall_dii=asm.dynCall_dii,dynCall_i=Module.dynCall_i=asm.dynCall_i,dynCall_iiiiii=Module.dynCall_iiiiii=asm.dynCall_iiiiii,dynCall_viiid=Module.dynCall_viiid=asm.dynCall_viiid,dynCall_viififi=Module.dynCall_viififi=asm.dynCall_viififi,dynCall_viii=Module.dynCall_viii=asm.dynCall_viii,dynCall_v=Module.dynCall_v=asm.dynCall_v,dynCall_viid=Module.dynCall_viid=asm.dynCall_viid,dynCall_idd=Module.dynCall_idd=asm.dynCall_idd,dynCall_viiii=Module.dynCall_viiii=asm.dynCall_viiii;Runtime.stackAlloc=Module.stackAlloc,Runtime.stackSave=Module.stackSave,Runtime.stackRestore=Module.stackRestore,Runtime.establishStackSpace=Module.establishStackSpace,Runtime.setTempRet0=Module.setTempRet0,Runtime.getTempRet0=Module.getTempRet0,Module.asm=asm;function ExitStatus(t){this.name="ExitStatus",this.message="Program terminated with exit("+t+")",this.status=t}ExitStatus.prototype=new Error,ExitStatus.prototype.constructor=ExitStatus;var initialStackTop,preloadStartTime=null,calledMain=!1;dependenciesFulfilled=function t(){Module.calledRun||run(),Module.calledRun||(dependenciesFulfilled=t)},Module.callMain=Module.callMain=function t(e){e=e||[],ensureInitRuntime();var r=e.length+1;function o(){for(var p=0;p<4-1;p++)a.push(0)}var a=[allocate(intArrayFromString(Module.thisProgram),"i8",ALLOC_NORMAL)];o();for(var n=0;n0||(preRun(),runDependencies>0)||Module.calledRun)return;function e(){Module.calledRun||(Module.calledRun=!0,!ABORT&&(ensureInitRuntime(),preMain(),Module.onRuntimeInitialized&&Module.onRuntimeInitialized(),Module._main&&shouldRunNow&&Module.callMain(t),postRun()))}Module.setStatus?(Module.setStatus("Running..."),setTimeout(function(){setTimeout(function(){Module.setStatus("")},1),e()},1)):e()}Module.run=Module.run=run;function exit(t,e){e&&Module.noExitRuntime||(Module.noExitRuntime||(ABORT=!0,EXITSTATUS=t,STACKTOP=initialStackTop,exitRuntime(),Module.onExit&&Module.onExit(t)),ENVIRONMENT_IS_NODE&&process.exit(t),Module.quit(t,new ExitStatus(t)))}Module.exit=Module.exit=exit;var abortDecorators=[];function abort(t){Module.onAbort&&Module.onAbort(t),t!==void 0?(Module.print(t),Module.printErr(t),t=JSON.stringify(t)):t="",ABORT=!0,EXITSTATUS=1;var e=` -If this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.`,r="abort("+t+") at "+stackTrace()+e;throw abortDecorators&&abortDecorators.forEach(function(o){r=o(r,t)}),r}if(Module.abort=Module.abort=abort,Module.preInit)for(typeof Module.preInit=="function"&&(Module.preInit=[Module.preInit]);Module.preInit.length>0;)Module.preInit.pop()();var shouldRunNow=!0;Module.noInitialRun&&(shouldRunNow=!1),run()})});var om=_((wVt,OEe)=>{"use strict";var Jyt=LEe(),zyt=MEe(),Q6=!1,F6=null;zyt({},function(t,e){if(!Q6){if(Q6=!0,t)throw t;F6=e}});if(!Q6)throw new Error("Failed to load the yoga module - it needed to be loaded synchronously, but didn't");OEe.exports=Jyt(F6.bind,F6.lib)});var R6=_((IVt,T6)=>{"use strict";var UEe=t=>Number.isNaN(t)?!1:t>=4352&&(t<=4447||t===9001||t===9002||11904<=t&&t<=12871&&t!==12351||12880<=t&&t<=19903||19968<=t&&t<=42182||43360<=t&&t<=43388||44032<=t&&t<=55203||63744<=t&&t<=64255||65040<=t&&t<=65049||65072<=t&&t<=65131||65281<=t&&t<=65376||65504<=t&&t<=65510||110592<=t&&t<=110593||127488<=t&&t<=127569||131072<=t&&t<=262141);T6.exports=UEe;T6.exports.default=UEe});var HEe=_((BVt,_Ee)=>{"use strict";_Ee.exports=function(){return/\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F|\uD83D\uDC68(?:\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68\uD83C\uDFFB|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|[\u2695\u2696\u2708]\uFE0F|\uD83D[\uDC66\uDC67]|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708])\uFE0F|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C[\uDFFB-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)\uD83C\uDFFB|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])|\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)(?:\uD83C[\uDFFB\uDFFC])|\uD83D\uDC69(?:\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)(?:\uD83C[\uDFFB-\uDFFD])|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|(?:(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)\uFE0F|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD6-\uDDDD])(?:(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\u200D[\u2640\u2642])|\uD83C\uDFF4\u200D\u2620)\uFE0F|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDF6\uD83C\uDDE6|[#\*0-9]\uFE0F\u20E3|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83D\uDC69(?:\uD83C[\uDFFB-\uDFFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270A-\u270D]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC70\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDCAA\uDD74\uDD7A\uDD90\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD36\uDDB5\uDDB6\uDDBB\uDDD2-\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5\uDEEB\uDEEC\uDEF4-\uDEFA\uDFE0-\uDFEB]|\uD83E[\uDD0D-\uDD3A\uDD3C-\uDD45\uDD47-\uDD71\uDD73-\uDD76\uDD7A-\uDDA2\uDDA5-\uDDAA\uDDAE-\uDDCA\uDDCD-\uDDFF\uDE70-\uDE73\uDE78-\uDE7A\uDE80-\uDE82\uDE90-\uDE95])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFA\uDFE0-\uDFEB]|\uD83E[\uDD0D-\uDD3A\uDD3C-\uDD45\uDD47-\uDD71\uDD73-\uDD76\uDD7A-\uDDA2\uDDA5-\uDDAA\uDDAE-\uDDCA\uDDCD-\uDDFF\uDE70-\uDE73\uDE78-\uDE7A\uDE80-\uDE82\uDE90-\uDE95])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g}});var Jk=_((vVt,N6)=>{"use strict";var Xyt=MP(),Zyt=R6(),$yt=HEe(),jEe=t=>{if(typeof t!="string"||t.length===0||(t=Xyt(t),t.length===0))return 0;t=t.replace($yt()," ");let e=0;for(let r=0;r=127&&o<=159||o>=768&&o<=879||(o>65535&&r++,e+=Zyt(o)?2:1)}return e};N6.exports=jEe;N6.exports.default=jEe});var M6=_((DVt,L6)=>{"use strict";var eEt=Jk(),qEe=t=>{let e=0;for(let r of t.split(` -`))e=Math.max(e,eEt(r));return e};L6.exports=qEe;L6.exports.default=qEe});var GEe=_(lB=>{"use strict";var tEt=lB&&lB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(lB,"__esModule",{value:!0});var rEt=tEt(M6()),O6={};lB.default=t=>{if(t.length===0)return{width:0,height:0};if(O6[t])return O6[t];let e=rEt.default(t),r=t.split(` -`).length;return O6[t]={width:e,height:r},{width:e,height:r}}});var YEe=_(cB=>{"use strict";var nEt=cB&&cB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(cB,"__esModule",{value:!0});var dn=nEt(om()),iEt=(t,e)=>{"position"in e&&t.setPositionType(e.position==="absolute"?dn.default.POSITION_TYPE_ABSOLUTE:dn.default.POSITION_TYPE_RELATIVE)},sEt=(t,e)=>{"marginLeft"in e&&t.setMargin(dn.default.EDGE_START,e.marginLeft||0),"marginRight"in e&&t.setMargin(dn.default.EDGE_END,e.marginRight||0),"marginTop"in e&&t.setMargin(dn.default.EDGE_TOP,e.marginTop||0),"marginBottom"in e&&t.setMargin(dn.default.EDGE_BOTTOM,e.marginBottom||0)},oEt=(t,e)=>{"paddingLeft"in e&&t.setPadding(dn.default.EDGE_LEFT,e.paddingLeft||0),"paddingRight"in e&&t.setPadding(dn.default.EDGE_RIGHT,e.paddingRight||0),"paddingTop"in e&&t.setPadding(dn.default.EDGE_TOP,e.paddingTop||0),"paddingBottom"in e&&t.setPadding(dn.default.EDGE_BOTTOM,e.paddingBottom||0)},aEt=(t,e)=>{var r;"flexGrow"in e&&t.setFlexGrow((r=e.flexGrow)!==null&&r!==void 0?r:0),"flexShrink"in e&&t.setFlexShrink(typeof e.flexShrink=="number"?e.flexShrink:1),"flexDirection"in e&&(e.flexDirection==="row"&&t.setFlexDirection(dn.default.FLEX_DIRECTION_ROW),e.flexDirection==="row-reverse"&&t.setFlexDirection(dn.default.FLEX_DIRECTION_ROW_REVERSE),e.flexDirection==="column"&&t.setFlexDirection(dn.default.FLEX_DIRECTION_COLUMN),e.flexDirection==="column-reverse"&&t.setFlexDirection(dn.default.FLEX_DIRECTION_COLUMN_REVERSE)),"flexBasis"in e&&(typeof e.flexBasis=="number"?t.setFlexBasis(e.flexBasis):typeof e.flexBasis=="string"?t.setFlexBasisPercent(Number.parseInt(e.flexBasis,10)):t.setFlexBasis(NaN)),"alignItems"in e&&((e.alignItems==="stretch"||!e.alignItems)&&t.setAlignItems(dn.default.ALIGN_STRETCH),e.alignItems==="flex-start"&&t.setAlignItems(dn.default.ALIGN_FLEX_START),e.alignItems==="center"&&t.setAlignItems(dn.default.ALIGN_CENTER),e.alignItems==="flex-end"&&t.setAlignItems(dn.default.ALIGN_FLEX_END)),"alignSelf"in e&&((e.alignSelf==="auto"||!e.alignSelf)&&t.setAlignSelf(dn.default.ALIGN_AUTO),e.alignSelf==="flex-start"&&t.setAlignSelf(dn.default.ALIGN_FLEX_START),e.alignSelf==="center"&&t.setAlignSelf(dn.default.ALIGN_CENTER),e.alignSelf==="flex-end"&&t.setAlignSelf(dn.default.ALIGN_FLEX_END)),"justifyContent"in e&&((e.justifyContent==="flex-start"||!e.justifyContent)&&t.setJustifyContent(dn.default.JUSTIFY_FLEX_START),e.justifyContent==="center"&&t.setJustifyContent(dn.default.JUSTIFY_CENTER),e.justifyContent==="flex-end"&&t.setJustifyContent(dn.default.JUSTIFY_FLEX_END),e.justifyContent==="space-between"&&t.setJustifyContent(dn.default.JUSTIFY_SPACE_BETWEEN),e.justifyContent==="space-around"&&t.setJustifyContent(dn.default.JUSTIFY_SPACE_AROUND))},lEt=(t,e)=>{var r,o;"width"in e&&(typeof e.width=="number"?t.setWidth(e.width):typeof e.width=="string"?t.setWidthPercent(Number.parseInt(e.width,10)):t.setWidthAuto()),"height"in e&&(typeof e.height=="number"?t.setHeight(e.height):typeof e.height=="string"?t.setHeightPercent(Number.parseInt(e.height,10)):t.setHeightAuto()),"minWidth"in e&&(typeof e.minWidth=="string"?t.setMinWidthPercent(Number.parseInt(e.minWidth,10)):t.setMinWidth((r=e.minWidth)!==null&&r!==void 0?r:0)),"minHeight"in e&&(typeof e.minHeight=="string"?t.setMinHeightPercent(Number.parseInt(e.minHeight,10)):t.setMinHeight((o=e.minHeight)!==null&&o!==void 0?o:0))},cEt=(t,e)=>{"display"in e&&t.setDisplay(e.display==="flex"?dn.default.DISPLAY_FLEX:dn.default.DISPLAY_NONE)},uEt=(t,e)=>{if("borderStyle"in e){let r=typeof e.borderStyle=="string"?1:0;t.setBorder(dn.default.EDGE_TOP,r),t.setBorder(dn.default.EDGE_BOTTOM,r),t.setBorder(dn.default.EDGE_LEFT,r),t.setBorder(dn.default.EDGE_RIGHT,r)}};cB.default=(t,e={})=>{iEt(t,e),sEt(t,e),oEt(t,e),aEt(t,e),lEt(t,e),cEt(t,e),uEt(t,e)}});var KEe=_((xVt,VEe)=>{"use strict";var uB=Jk(),AEt=MP(),fEt=vI(),_6=new Set(["\x1B","\x9B"]),pEt=39,WEe=t=>`${_6.values().next().value}[${t}m`,hEt=t=>t.split(" ").map(e=>uB(e)),U6=(t,e,r)=>{let o=[...e],a=!1,n=uB(AEt(t[t.length-1]));for(let[u,A]of o.entries()){let p=uB(A);if(n+p<=r?t[t.length-1]+=A:(t.push(A),n=0),_6.has(A))a=!0;else if(a&&A==="m"){a=!1;continue}a||(n+=p,n===r&&u0&&t.length>1&&(t[t.length-2]+=t.pop())},gEt=t=>{let e=t.split(" "),r=e.length;for(;r>0&&!(uB(e[r-1])>0);)r--;return r===e.length?t:e.slice(0,r).join(" ")+e.slice(r).join("")},dEt=(t,e,r={})=>{if(r.trim!==!1&&t.trim()==="")return"";let o="",a="",n,u=hEt(t),A=[""];for(let[p,h]of t.split(" ").entries()){r.trim!==!1&&(A[A.length-1]=A[A.length-1].trimLeft());let E=uB(A[A.length-1]);if(p!==0&&(E>=e&&(r.wordWrap===!1||r.trim===!1)&&(A.push(""),E=0),(E>0||r.trim===!1)&&(A[A.length-1]+=" ",E++)),r.hard&&u[p]>e){let I=e-E,v=1+Math.floor((u[p]-I-1)/e);Math.floor((u[p]-1)/e)e&&E>0&&u[p]>0){if(r.wordWrap===!1&&Ee&&r.wordWrap===!1){U6(A,h,e);continue}A[A.length-1]+=h}r.trim!==!1&&(A=A.map(gEt)),o=A.join(` -`);for(let[p,h]of[...o].entries()){if(a+=h,_6.has(h)){let I=parseFloat(/\d[^m]*/.exec(o.slice(p,p+4)));n=I===pEt?null:I}let E=fEt.codes.get(Number(n));n&&E&&(o[p+1]===` -`?a+=WEe(E):h===` -`&&(a+=WEe(n)))}return a};VEe.exports=(t,e,r)=>String(t).normalize().replace(/\r\n/g,` -`).split(` -`).map(o=>dEt(o,e,r)).join(` -`)});var XEe=_((bVt,zEe)=>{"use strict";var JEe="[\uD800-\uDBFF][\uDC00-\uDFFF]",mEt=t=>t&&t.exact?new RegExp(`^${JEe}$`):new RegExp(JEe,"g");zEe.exports=mEt});var H6=_((kVt,tCe)=>{"use strict";var yEt=R6(),EEt=XEe(),ZEe=vI(),eCe=["\x1B","\x9B"],zk=t=>`${eCe[0]}[${t}m`,$Ee=(t,e,r)=>{let o=[];t=[...t];for(let a of t){let n=a;a.match(";")&&(a=a.split(";")[0][0]+"0");let u=ZEe.codes.get(parseInt(a,10));if(u){let A=t.indexOf(u.toString());A>=0?t.splice(A,1):o.push(zk(e?u:n))}else if(e){o.push(zk(0));break}else o.push(zk(n))}if(e&&(o=o.filter((a,n)=>o.indexOf(a)===n),r!==void 0)){let a=zk(ZEe.codes.get(parseInt(r,10)));o=o.reduce((n,u)=>u===a?[u,...n]:[...n,u],[])}return o.join("")};tCe.exports=(t,e,r)=>{let o=[...t.normalize()],a=[];r=typeof r=="number"?r:o.length;let n=!1,u,A=0,p="";for(let[h,E]of o.entries()){let I=!1;if(eCe.includes(E)){let v=/\d[^m]*/.exec(t.slice(h,h+18));u=v&&v.length>0?v[0]:void 0,Ae&&A<=r)p+=E;else if(A===e&&!n&&u!==void 0)p=$Ee(a);else if(A>=r){p+=$Ee(a,!0,u);break}}return p}});var nCe=_((QVt,rCe)=>{"use strict";var y0=H6(),CEt=Jk();function Xk(t,e,r){if(t.charAt(e)===" ")return e;for(let o=1;o<=3;o++)if(r){if(t.charAt(e+o)===" ")return e+o}else if(t.charAt(e-o)===" ")return e-o;return e}rCe.exports=(t,e,r)=>{r={position:"end",preferTruncationOnSpace:!1,...r};let{position:o,space:a,preferTruncationOnSpace:n}=r,u="\u2026",A=1;if(typeof t!="string")throw new TypeError(`Expected \`input\` to be a string, got ${typeof t}`);if(typeof e!="number")throw new TypeError(`Expected \`columns\` to be a number, got ${typeof e}`);if(e<1)return"";if(e===1)return u;let p=CEt(t);if(p<=e)return t;if(o==="start"){if(n){let h=Xk(t,p-e+1,!0);return u+y0(t,h,p).trim()}return a===!0&&(u+=" ",A=2),u+y0(t,p-e+A,p)}if(o==="middle"){a===!0&&(u=" "+u+" ",A=3);let h=Math.floor(e/2);if(n){let E=Xk(t,h),I=Xk(t,p-(e-h)+1,!0);return y0(t,0,E)+u+y0(t,I,p).trim()}return y0(t,0,h)+u+y0(t,p-(e-h)+A,p)}if(o==="end"){if(n){let h=Xk(t,e-1);return y0(t,0,h)+u}return a===!0&&(u=" "+u,A=2),y0(t,0,e-A)+u}throw new Error(`Expected \`options.position\` to be either \`start\`, \`middle\` or \`end\`, got ${o}`)}});var q6=_(AB=>{"use strict";var iCe=AB&&AB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(AB,"__esModule",{value:!0});var wEt=iCe(KEe()),IEt=iCe(nCe()),j6={};AB.default=(t,e,r)=>{let o=t+String(e)+String(r);if(j6[o])return j6[o];let a=t;if(r==="wrap"&&(a=wEt.default(t,e,{trim:!1,hard:!0})),r.startsWith("truncate")){let n="end";r==="truncate-middle"&&(n="middle"),r==="truncate-start"&&(n="start"),a=IEt.default(t,e,{position:n})}return j6[o]=a,a}});var Y6=_(G6=>{"use strict";Object.defineProperty(G6,"__esModule",{value:!0});var sCe=t=>{let e="";if(t.childNodes.length>0)for(let r of t.childNodes){let o="";r.nodeName==="#text"?o=r.nodeValue:((r.nodeName==="ink-text"||r.nodeName==="ink-virtual-text")&&(o=sCe(r)),o.length>0&&typeof r.internal_transform=="function"&&(o=r.internal_transform(o))),e+=o}return e};G6.default=sCe});var W6=_(pi=>{"use strict";var fB=pi&&pi.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(pi,"__esModule",{value:!0});pi.setTextNodeValue=pi.createTextNode=pi.setStyle=pi.setAttribute=pi.removeChildNode=pi.insertBeforeNode=pi.appendChildNode=pi.createNode=pi.TEXT_NAME=void 0;var BEt=fB(om()),oCe=fB(GEe()),vEt=fB(YEe()),DEt=fB(q6()),PEt=fB(Y6());pi.TEXT_NAME="#text";pi.createNode=t=>{var e;let r={nodeName:t,style:{},attributes:{},childNodes:[],parentNode:null,yogaNode:t==="ink-virtual-text"?void 0:BEt.default.Node.create()};return t==="ink-text"&&((e=r.yogaNode)===null||e===void 0||e.setMeasureFunc(SEt.bind(null,r))),r};pi.appendChildNode=(t,e)=>{var r;e.parentNode&&pi.removeChildNode(e.parentNode,e),e.parentNode=t,t.childNodes.push(e),e.yogaNode&&((r=t.yogaNode)===null||r===void 0||r.insertChild(e.yogaNode,t.yogaNode.getChildCount())),(t.nodeName==="ink-text"||t.nodeName==="ink-virtual-text")&&Zk(t)};pi.insertBeforeNode=(t,e,r)=>{var o,a;e.parentNode&&pi.removeChildNode(e.parentNode,e),e.parentNode=t;let n=t.childNodes.indexOf(r);if(n>=0){t.childNodes.splice(n,0,e),e.yogaNode&&((o=t.yogaNode)===null||o===void 0||o.insertChild(e.yogaNode,n));return}t.childNodes.push(e),e.yogaNode&&((a=t.yogaNode)===null||a===void 0||a.insertChild(e.yogaNode,t.yogaNode.getChildCount())),(t.nodeName==="ink-text"||t.nodeName==="ink-virtual-text")&&Zk(t)};pi.removeChildNode=(t,e)=>{var r,o;e.yogaNode&&((o=(r=e.parentNode)===null||r===void 0?void 0:r.yogaNode)===null||o===void 0||o.removeChild(e.yogaNode)),e.parentNode=null;let a=t.childNodes.indexOf(e);a>=0&&t.childNodes.splice(a,1),(t.nodeName==="ink-text"||t.nodeName==="ink-virtual-text")&&Zk(t)};pi.setAttribute=(t,e,r)=>{t.attributes[e]=r};pi.setStyle=(t,e)=>{t.style=e,t.yogaNode&&vEt.default(t.yogaNode,e)};pi.createTextNode=t=>{let e={nodeName:"#text",nodeValue:t,yogaNode:void 0,parentNode:null,style:{}};return pi.setTextNodeValue(e,t),e};var SEt=function(t,e){var r,o;let a=t.nodeName==="#text"?t.nodeValue:PEt.default(t),n=oCe.default(a);if(n.width<=e||n.width>=1&&e>0&&e<1)return n;let u=(o=(r=t.style)===null||r===void 0?void 0:r.textWrap)!==null&&o!==void 0?o:"wrap",A=DEt.default(a,e,u);return oCe.default(A)},aCe=t=>{var e;if(!(!t||!t.parentNode))return(e=t.yogaNode)!==null&&e!==void 0?e:aCe(t.parentNode)},Zk=t=>{let e=aCe(t);e?.markDirty()};pi.setTextNodeValue=(t,e)=>{typeof e!="string"&&(e=String(e)),t.nodeValue=e,Zk(t)}});var fCe=_(pB=>{"use strict";var ACe=pB&&pB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(pB,"__esModule",{value:!0});var lCe=x6(),xEt=ACe(kEe()),cCe=ACe(om()),Mo=W6(),uCe=t=>{t?.unsetMeasureFunc(),t?.freeRecursive()};pB.default=xEt.default({schedulePassiveEffects:lCe.unstable_scheduleCallback,cancelPassiveEffects:lCe.unstable_cancelCallback,now:Date.now,getRootHostContext:()=>({isInsideText:!1}),prepareForCommit:()=>{},resetAfterCommit:t=>{if(t.isStaticDirty){t.isStaticDirty=!1,typeof t.onImmediateRender=="function"&&t.onImmediateRender();return}typeof t.onRender=="function"&&t.onRender()},getChildHostContext:(t,e)=>{let r=t.isInsideText,o=e==="ink-text"||e==="ink-virtual-text";return r===o?t:{isInsideText:o}},shouldSetTextContent:()=>!1,createInstance:(t,e,r,o)=>{if(o.isInsideText&&t==="ink-box")throw new Error(" can\u2019t be nested inside component");let a=t==="ink-text"&&o.isInsideText?"ink-virtual-text":t,n=Mo.createNode(a);for(let[u,A]of Object.entries(e))u!=="children"&&(u==="style"?Mo.setStyle(n,A):u==="internal_transform"?n.internal_transform=A:u==="internal_static"?n.internal_static=!0:Mo.setAttribute(n,u,A));return n},createTextInstance:(t,e,r)=>{if(!r.isInsideText)throw new Error(`Text string "${t}" must be rendered inside component`);return Mo.createTextNode(t)},resetTextContent:()=>{},hideTextInstance:t=>{Mo.setTextNodeValue(t,"")},unhideTextInstance:(t,e)=>{Mo.setTextNodeValue(t,e)},getPublicInstance:t=>t,hideInstance:t=>{var e;(e=t.yogaNode)===null||e===void 0||e.setDisplay(cCe.default.DISPLAY_NONE)},unhideInstance:t=>{var e;(e=t.yogaNode)===null||e===void 0||e.setDisplay(cCe.default.DISPLAY_FLEX)},appendInitialChild:Mo.appendChildNode,appendChild:Mo.appendChildNode,insertBefore:Mo.insertBeforeNode,finalizeInitialChildren:(t,e,r,o)=>(t.internal_static&&(o.isStaticDirty=!0,o.staticNode=t),!1),supportsMutation:!0,appendChildToContainer:Mo.appendChildNode,insertInContainerBefore:Mo.insertBeforeNode,removeChildFromContainer:(t,e)=>{Mo.removeChildNode(t,e),uCe(e.yogaNode)},prepareUpdate:(t,e,r,o,a)=>{t.internal_static&&(a.isStaticDirty=!0);let n={},u=Object.keys(o);for(let A of u)if(o[A]!==r[A]){if(A==="style"&&typeof o.style=="object"&&typeof r.style=="object"){let h=o.style,E=r.style,I=Object.keys(h);for(let v of I){if(v==="borderStyle"||v==="borderColor"){if(typeof n.style!="object"){let b={};n.style=b}n.style.borderStyle=h.borderStyle,n.style.borderColor=h.borderColor}if(h[v]!==E[v]){if(typeof n.style!="object"){let b={};n.style=b}n.style[v]=h[v]}}continue}n[A]=o[A]}return n},commitUpdate:(t,e)=>{for(let[r,o]of Object.entries(e))r!=="children"&&(r==="style"?Mo.setStyle(t,o):r==="internal_transform"?t.internal_transform=o:r==="internal_static"?t.internal_static=!0:Mo.setAttribute(t,r,o))},commitTextUpdate:(t,e,r)=>{Mo.setTextNodeValue(t,r)},removeChild:(t,e)=>{Mo.removeChildNode(t,e),uCe(e.yogaNode)}})});var hCe=_((LVt,pCe)=>{"use strict";pCe.exports=(t,e=1,r)=>{if(r={indent:" ",includeEmptyLines:!1,...r},typeof t!="string")throw new TypeError(`Expected \`input\` to be a \`string\`, got \`${typeof t}\``);if(typeof e!="number")throw new TypeError(`Expected \`count\` to be a \`number\`, got \`${typeof e}\``);if(typeof r.indent!="string")throw new TypeError(`Expected \`options.indent\` to be a \`string\`, got \`${typeof r.indent}\``);if(e===0)return t;let o=r.includeEmptyLines?/^/gm:/^(?!\s*$)/gm;return t.replace(o,r.indent.repeat(e))}});var gCe=_(hB=>{"use strict";var bEt=hB&&hB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(hB,"__esModule",{value:!0});var $k=bEt(om());hB.default=t=>t.getComputedWidth()-t.getComputedPadding($k.default.EDGE_LEFT)-t.getComputedPadding($k.default.EDGE_RIGHT)-t.getComputedBorder($k.default.EDGE_LEFT)-t.getComputedBorder($k.default.EDGE_RIGHT)});var dCe=_((OVt,kEt)=>{kEt.exports={single:{topLeft:"\u250C",topRight:"\u2510",bottomRight:"\u2518",bottomLeft:"\u2514",vertical:"\u2502",horizontal:"\u2500"},double:{topLeft:"\u2554",topRight:"\u2557",bottomRight:"\u255D",bottomLeft:"\u255A",vertical:"\u2551",horizontal:"\u2550"},round:{topLeft:"\u256D",topRight:"\u256E",bottomRight:"\u256F",bottomLeft:"\u2570",vertical:"\u2502",horizontal:"\u2500"},bold:{topLeft:"\u250F",topRight:"\u2513",bottomRight:"\u251B",bottomLeft:"\u2517",vertical:"\u2503",horizontal:"\u2501"},singleDouble:{topLeft:"\u2553",topRight:"\u2556",bottomRight:"\u255C",bottomLeft:"\u2559",vertical:"\u2551",horizontal:"\u2500"},doubleSingle:{topLeft:"\u2552",topRight:"\u2555",bottomRight:"\u255B",bottomLeft:"\u2558",vertical:"\u2502",horizontal:"\u2550"},classic:{topLeft:"+",topRight:"+",bottomRight:"+",bottomLeft:"+",vertical:"|",horizontal:"-"}}});var yCe=_((UVt,V6)=>{"use strict";var mCe=dCe();V6.exports=mCe;V6.exports.default=mCe});var CCe=_((_Vt,ECe)=>{"use strict";var QEt=(t,e,r)=>{let o=t.indexOf(e);if(o===-1)return t;let a=e.length,n=0,u="";do u+=t.substr(n,o-n)+e+r,n=o+a,o=t.indexOf(e,n);while(o!==-1);return u+=t.substr(n),u},FEt=(t,e,r,o)=>{let a=0,n="";do{let u=t[o-1]==="\r";n+=t.substr(a,(u?o-1:o)-a)+e+(u?`\r -`:` -`)+r,a=o+1,o=t.indexOf(` -`,a)}while(o!==-1);return n+=t.substr(a),n};ECe.exports={stringReplaceAll:QEt,stringEncaseCRLFWithFirstIndex:FEt}});var DCe=_((HVt,vCe)=>{"use strict";var TEt=/(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi,wCe=/(?:^|\.)(\w+)(?:\(([^)]*)\))?/g,REt=/^(['"])((?:\\.|(?!\1)[^\\])*)\1$/,NEt=/\\(u(?:[a-f\d]{4}|{[a-f\d]{1,6}})|x[a-f\d]{2}|.)|([^\\])/gi,LEt=new Map([["n",` -`],["r","\r"],["t"," "],["b","\b"],["f","\f"],["v","\v"],["0","\0"],["\\","\\"],["e","\x1B"],["a","\x07"]]);function BCe(t){let e=t[0]==="u",r=t[1]==="{";return e&&!r&&t.length===5||t[0]==="x"&&t.length===3?String.fromCharCode(parseInt(t.slice(1),16)):e&&r?String.fromCodePoint(parseInt(t.slice(2,-1),16)):LEt.get(t)||t}function MEt(t,e){let r=[],o=e.trim().split(/\s*,\s*/g),a;for(let n of o){let u=Number(n);if(!Number.isNaN(u))r.push(u);else if(a=n.match(REt))r.push(a[2].replace(NEt,(A,p,h)=>p?BCe(p):h));else throw new Error(`Invalid Chalk template style argument: ${n} (in style '${t}')`)}return r}function OEt(t){wCe.lastIndex=0;let e=[],r;for(;(r=wCe.exec(t))!==null;){let o=r[1];if(r[2]){let a=MEt(o,r[2]);e.push([o].concat(a))}else e.push([o])}return e}function ICe(t,e){let r={};for(let a of e)for(let n of a.styles)r[n[0]]=a.inverse?null:n.slice(1);let o=t;for(let[a,n]of Object.entries(r))if(!!Array.isArray(n)){if(!(a in o))throw new Error(`Unknown Chalk style: ${a}`);o=n.length>0?o[a](...n):o[a]}return o}vCe.exports=(t,e)=>{let r=[],o=[],a=[];if(e.replace(TEt,(n,u,A,p,h,E)=>{if(u)a.push(BCe(u));else if(p){let I=a.join("");a=[],o.push(r.length===0?I:ICe(t,r)(I)),r.push({inverse:A,styles:OEt(p)})}else if(h){if(r.length===0)throw new Error("Found extraneous } in Chalk template literal");o.push(ICe(t,r)(a.join(""))),a=[],r.pop()}else a.push(E)}),o.push(a.join("")),r.length>0){let n=`Chalk template literal is missing ${r.length} closing bracket${r.length===1?"":"s"} (\`}\`)`;throw new Error(n)}return o.join("")}});var iQ=_((jVt,QCe)=>{"use strict";var gB=vI(),{stdout:J6,stderr:z6}=yN(),{stringReplaceAll:UEt,stringEncaseCRLFWithFirstIndex:_Et}=CCe(),{isArray:eQ}=Array,SCe=["ansi","ansi","ansi256","ansi16m"],_C=Object.create(null),HEt=(t,e={})=>{if(e.level&&!(Number.isInteger(e.level)&&e.level>=0&&e.level<=3))throw new Error("The `level` option should be an integer from 0 to 3");let r=J6?J6.level:0;t.level=e.level===void 0?r:e.level},X6=class{constructor(e){return xCe(e)}},xCe=t=>{let e={};return HEt(e,t),e.template=(...r)=>kCe(e.template,...r),Object.setPrototypeOf(e,tQ.prototype),Object.setPrototypeOf(e.template,e),e.template.constructor=()=>{throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.")},e.template.Instance=X6,e.template};function tQ(t){return xCe(t)}for(let[t,e]of Object.entries(gB))_C[t]={get(){let r=rQ(this,Z6(e.open,e.close,this._styler),this._isEmpty);return Object.defineProperty(this,t,{value:r}),r}};_C.visible={get(){let t=rQ(this,this._styler,!0);return Object.defineProperty(this,"visible",{value:t}),t}};var bCe=["rgb","hex","keyword","hsl","hsv","hwb","ansi","ansi256"];for(let t of bCe)_C[t]={get(){let{level:e}=this;return function(...r){let o=Z6(gB.color[SCe[e]][t](...r),gB.color.close,this._styler);return rQ(this,o,this._isEmpty)}}};for(let t of bCe){let e="bg"+t[0].toUpperCase()+t.slice(1);_C[e]={get(){let{level:r}=this;return function(...o){let a=Z6(gB.bgColor[SCe[r]][t](...o),gB.bgColor.close,this._styler);return rQ(this,a,this._isEmpty)}}}}var jEt=Object.defineProperties(()=>{},{..._C,level:{enumerable:!0,get(){return this._generator.level},set(t){this._generator.level=t}}}),Z6=(t,e,r)=>{let o,a;return r===void 0?(o=t,a=e):(o=r.openAll+t,a=e+r.closeAll),{open:t,close:e,openAll:o,closeAll:a,parent:r}},rQ=(t,e,r)=>{let o=(...a)=>eQ(a[0])&&eQ(a[0].raw)?PCe(o,kCe(o,...a)):PCe(o,a.length===1?""+a[0]:a.join(" "));return Object.setPrototypeOf(o,jEt),o._generator=t,o._styler=e,o._isEmpty=r,o},PCe=(t,e)=>{if(t.level<=0||!e)return t._isEmpty?"":e;let r=t._styler;if(r===void 0)return e;let{openAll:o,closeAll:a}=r;if(e.indexOf("\x1B")!==-1)for(;r!==void 0;)e=UEt(e,r.close,r.open),r=r.parent;let n=e.indexOf(` -`);return n!==-1&&(e=_Et(e,a,o,n)),o+e+a},K6,kCe=(t,...e)=>{let[r]=e;if(!eQ(r)||!eQ(r.raw))return e.join(" ");let o=e.slice(1),a=[r.raw[0]];for(let n=1;n{"use strict";var qEt=mB&&mB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(mB,"__esModule",{value:!0});var dB=qEt(iQ()),GEt=/^(rgb|hsl|hsv|hwb)\(\s?(\d+),\s?(\d+),\s?(\d+)\s?\)$/,YEt=/^(ansi|ansi256)\(\s?(\d+)\s?\)$/,sQ=(t,e)=>e==="foreground"?t:"bg"+t[0].toUpperCase()+t.slice(1);mB.default=(t,e,r)=>{if(!e)return t;if(e in dB.default){let a=sQ(e,r);return dB.default[a](t)}if(e.startsWith("#")){let a=sQ("hex",r);return dB.default[a](e)(t)}if(e.startsWith("ansi")){let a=YEt.exec(e);if(!a)return t;let n=sQ(a[1],r),u=Number(a[2]);return dB.default[n](u)(t)}if(e.startsWith("rgb")||e.startsWith("hsl")||e.startsWith("hsv")||e.startsWith("hwb")){let a=GEt.exec(e);if(!a)return t;let n=sQ(a[1],r),u=Number(a[2]),A=Number(a[3]),p=Number(a[4]);return dB.default[n](u,A,p)(t)}return t}});var TCe=_(yB=>{"use strict";var FCe=yB&&yB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(yB,"__esModule",{value:!0});var WEt=FCe(yCe()),ej=FCe($6());yB.default=(t,e,r,o)=>{if(typeof r.style.borderStyle=="string"){let a=r.yogaNode.getComputedWidth(),n=r.yogaNode.getComputedHeight(),u=r.style.borderColor,A=WEt.default[r.style.borderStyle],p=ej.default(A.topLeft+A.horizontal.repeat(a-2)+A.topRight,u,"foreground"),h=(ej.default(A.vertical,u,"foreground")+` -`).repeat(n-2),E=ej.default(A.bottomLeft+A.horizontal.repeat(a-2)+A.bottomRight,u,"foreground");o.write(t,e,p,{transformers:[]}),o.write(t,e+1,h,{transformers:[]}),o.write(t+a-1,e+1,h,{transformers:[]}),o.write(t,e+n-1,E,{transformers:[]})}}});var NCe=_(EB=>{"use strict";var am=EB&&EB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(EB,"__esModule",{value:!0});var VEt=am(om()),KEt=am(M6()),JEt=am(hCe()),zEt=am(q6()),XEt=am(gCe()),ZEt=am(Y6()),$Et=am(TCe()),eCt=(t,e)=>{var r;let o=(r=t.childNodes[0])===null||r===void 0?void 0:r.yogaNode;if(o){let a=o.getComputedLeft(),n=o.getComputedTop();e=` -`.repeat(n)+JEt.default(e,a)}return e},RCe=(t,e,r)=>{var o;let{offsetX:a=0,offsetY:n=0,transformers:u=[],skipStaticElements:A}=r;if(A&&t.internal_static)return;let{yogaNode:p}=t;if(p){if(p.getDisplay()===VEt.default.DISPLAY_NONE)return;let h=a+p.getComputedLeft(),E=n+p.getComputedTop(),I=u;if(typeof t.internal_transform=="function"&&(I=[t.internal_transform,...u]),t.nodeName==="ink-text"){let v=ZEt.default(t);if(v.length>0){let b=KEt.default(v),C=XEt.default(p);if(b>C){let T=(o=t.style.textWrap)!==null&&o!==void 0?o:"wrap";v=zEt.default(v,C,T)}v=eCt(t,v),e.write(h,E,v,{transformers:I})}return}if(t.nodeName==="ink-box"&&$Et.default(h,E,t,e),t.nodeName==="ink-root"||t.nodeName==="ink-box")for(let v of t.childNodes)RCe(v,e,{offsetX:h,offsetY:E,transformers:I,skipStaticElements:A})}};EB.default=RCe});var MCe=_((WVt,LCe)=>{"use strict";LCe.exports=t=>{t=Object.assign({onlyFirst:!1},t);let e=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");return new RegExp(e,t.onlyFirst?void 0:"g")}});var UCe=_((VVt,tj)=>{"use strict";var tCt=MCe(),OCe=t=>typeof t=="string"?t.replace(tCt(),""):t;tj.exports=OCe;tj.exports.default=OCe});var jCe=_((KVt,HCe)=>{"use strict";var _Ce="[\uD800-\uDBFF][\uDC00-\uDFFF]";HCe.exports=t=>t&&t.exact?new RegExp(`^${_Ce}$`):new RegExp(_Ce,"g")});var GCe=_((JVt,rj)=>{"use strict";var rCt=UCe(),nCt=jCe(),qCe=t=>rCt(t).replace(nCt()," ").length;rj.exports=qCe;rj.exports.default=qCe});var VCe=_(CB=>{"use strict";var WCe=CB&&CB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(CB,"__esModule",{value:!0});var YCe=WCe(H6()),iCt=WCe(GCe()),nj=class{constructor(e){this.writes=[];let{width:r,height:o}=e;this.width=r,this.height=o}write(e,r,o,a){let{transformers:n}=a;!o||this.writes.push({x:e,y:r,text:o,transformers:n})}get(){let e=[];for(let o=0;oo.trimRight()).join(` -`),height:e.length}}};CB.default=nj});var zCe=_(wB=>{"use strict";var ij=wB&&wB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(wB,"__esModule",{value:!0});var sCt=ij(om()),KCe=ij(NCe()),JCe=ij(VCe());wB.default=(t,e)=>{var r;if(t.yogaNode.setWidth(e),t.yogaNode){t.yogaNode.calculateLayout(void 0,void 0,sCt.default.DIRECTION_LTR);let o=new JCe.default({width:t.yogaNode.getComputedWidth(),height:t.yogaNode.getComputedHeight()});KCe.default(t,o,{skipStaticElements:!0});let a;!((r=t.staticNode)===null||r===void 0)&&r.yogaNode&&(a=new JCe.default({width:t.staticNode.yogaNode.getComputedWidth(),height:t.staticNode.yogaNode.getComputedHeight()}),KCe.default(t.staticNode,a,{skipStaticElements:!1}));let{output:n,height:u}=o.get();return{output:n,outputHeight:u,staticOutput:a?`${a.get().output} -`:""}}return{output:"",outputHeight:0,staticOutput:""}}});var ewe=_((ZVt,$Ce)=>{"use strict";var XCe=Be("stream"),ZCe=["assert","count","countReset","debug","dir","dirxml","error","group","groupCollapsed","groupEnd","info","log","table","time","timeEnd","timeLog","trace","warn"],sj={},oCt=t=>{let e=new XCe.PassThrough,r=new XCe.PassThrough;e.write=a=>t("stdout",a),r.write=a=>t("stderr",a);let o=new console.Console(e,r);for(let a of ZCe)sj[a]=console[a],console[a]=o[a];return()=>{for(let a of ZCe)console[a]=sj[a];sj={}}};$Ce.exports=oCt});var aj=_(oj=>{"use strict";Object.defineProperty(oj,"__esModule",{value:!0});oj.default=new WeakMap});var cj=_(lj=>{"use strict";Object.defineProperty(lj,"__esModule",{value:!0});var aCt=sn(),twe=aCt.createContext({exit:()=>{}});twe.displayName="InternalAppContext";lj.default=twe});var Aj=_(uj=>{"use strict";Object.defineProperty(uj,"__esModule",{value:!0});var lCt=sn(),rwe=lCt.createContext({stdin:void 0,setRawMode:()=>{},isRawModeSupported:!1,internal_exitOnCtrlC:!0});rwe.displayName="InternalStdinContext";uj.default=rwe});var pj=_(fj=>{"use strict";Object.defineProperty(fj,"__esModule",{value:!0});var cCt=sn(),nwe=cCt.createContext({stdout:void 0,write:()=>{}});nwe.displayName="InternalStdoutContext";fj.default=nwe});var gj=_(hj=>{"use strict";Object.defineProperty(hj,"__esModule",{value:!0});var uCt=sn(),iwe=uCt.createContext({stderr:void 0,write:()=>{}});iwe.displayName="InternalStderrContext";hj.default=iwe});var oQ=_(dj=>{"use strict";Object.defineProperty(dj,"__esModule",{value:!0});var ACt=sn(),swe=ACt.createContext({activeId:void 0,add:()=>{},remove:()=>{},activate:()=>{},deactivate:()=>{},enableFocus:()=>{},disableFocus:()=>{},focusNext:()=>{},focusPrevious:()=>{}});swe.displayName="InternalFocusContext";dj.default=swe});var awe=_((sKt,owe)=>{"use strict";var fCt=/[|\\{}()[\]^$+*?.-]/g;owe.exports=t=>{if(typeof t!="string")throw new TypeError("Expected a string");return t.replace(fCt,"\\$&")}});var Awe=_((oKt,uwe)=>{"use strict";var pCt=awe(),hCt=typeof process=="object"&&process&&typeof process.cwd=="function"?process.cwd():".",cwe=[].concat(Be("module").builtinModules,"bootstrap_node","node").map(t=>new RegExp(`(?:\\((?:node:)?${t}(?:\\.js)?:\\d+:\\d+\\)$|^\\s*at (?:node:)?${t}(?:\\.js)?:\\d+:\\d+$)`));cwe.push(/\((?:node:)?internal\/[^:]+:\d+:\d+\)$/,/\s*at (?:node:)?internal\/[^:]+:\d+:\d+$/,/\/\.node-spawn-wrap-\w+-\w+\/node:\d+:\d+\)?$/);var IB=class{constructor(e){e={ignoredPackages:[],...e},"internals"in e||(e.internals=IB.nodeInternals()),"cwd"in e||(e.cwd=hCt),this._cwd=e.cwd.replace(/\\/g,"/"),this._internals=[].concat(e.internals,gCt(e.ignoredPackages)),this._wrapCallSite=e.wrapCallSite||!1}static nodeInternals(){return[...cwe]}clean(e,r=0){r=" ".repeat(r),Array.isArray(e)||(e=e.split(` -`)),!/^\s*at /.test(e[0])&&/^\s*at /.test(e[1])&&(e=e.slice(1));let o=!1,a=null,n=[];return e.forEach(u=>{if(u=u.replace(/\\/g,"/"),this._internals.some(p=>p.test(u)))return;let A=/^\s*at /.test(u);o?u=u.trimEnd().replace(/^(\s+)at /,"$1"):(u=u.trim(),A&&(u=u.slice(3))),u=u.replace(`${this._cwd}/`,""),u&&(A?(a&&(n.push(a),a=null),n.push(u)):(o=!0,a=u))}),n.map(u=>`${r}${u} -`).join("")}captureString(e,r=this.captureString){typeof e=="function"&&(r=e,e=1/0);let{stackTraceLimit:o}=Error;e&&(Error.stackTraceLimit=e);let a={};Error.captureStackTrace(a,r);let{stack:n}=a;return Error.stackTraceLimit=o,this.clean(n)}capture(e,r=this.capture){typeof e=="function"&&(r=e,e=1/0);let{prepareStackTrace:o,stackTraceLimit:a}=Error;Error.prepareStackTrace=(A,p)=>this._wrapCallSite?p.map(this._wrapCallSite):p,e&&(Error.stackTraceLimit=e);let n={};Error.captureStackTrace(n,r);let{stack:u}=n;return Object.assign(Error,{prepareStackTrace:o,stackTraceLimit:a}),u}at(e=this.at){let[r]=this.capture(1,e);if(!r)return{};let o={line:r.getLineNumber(),column:r.getColumnNumber()};lwe(o,r.getFileName(),this._cwd),r.isConstructor()&&(o.constructor=!0),r.isEval()&&(o.evalOrigin=r.getEvalOrigin()),r.isNative()&&(o.native=!0);let a;try{a=r.getTypeName()}catch{}a&&a!=="Object"&&a!=="[object Object]"&&(o.type=a);let n=r.getFunctionName();n&&(o.function=n);let u=r.getMethodName();return u&&n!==u&&(o.method=u),o}parseLine(e){let r=e&&e.match(dCt);if(!r)return null;let o=r[1]==="new",a=r[2],n=r[3],u=r[4],A=Number(r[5]),p=Number(r[6]),h=r[7],E=r[8],I=r[9],v=r[10]==="native",b=r[11]===")",C,T={};if(E&&(T.line=Number(E)),I&&(T.column=Number(I)),b&&h){let L=0;for(let U=h.length-1;U>0;U--)if(h.charAt(U)===")")L++;else if(h.charAt(U)==="("&&h.charAt(U-1)===" "&&(L--,L===-1&&h.charAt(U-1)===" ")){let J=h.slice(0,U-1);h=h.slice(U+1),a+=` (${J}`;break}}if(a){let L=a.match(mCt);L&&(a=L[1],C=L[2])}return lwe(T,h,this._cwd),o&&(T.constructor=!0),n&&(T.evalOrigin=n,T.evalLine=A,T.evalColumn=p,T.evalFile=u&&u.replace(/\\/g,"/")),v&&(T.native=!0),a&&(T.function=a),C&&a!==C&&(T.method=C),T}};function lwe(t,e,r){e&&(e=e.replace(/\\/g,"/"),e.startsWith(`${r}/`)&&(e=e.slice(r.length+1)),t.file=e)}function gCt(t){if(t.length===0)return[];let e=t.map(r=>pCt(r));return new RegExp(`[/\\\\]node_modules[/\\\\](?:${e.join("|")})[/\\\\][^:]+:\\d+:\\d+`)}var dCt=new RegExp("^(?:\\s*at )?(?:(new) )?(?:(.*?) \\()?(?:eval at ([^ ]+) \\((.+?):(\\d+):(\\d+)\\), )?(?:(.+?):(\\d+):(\\d+)|(native))(\\)?)$"),mCt=/^(.*?) \[as (.*?)\]$/;uwe.exports=IB});var pwe=_((aKt,fwe)=>{"use strict";fwe.exports=(t,e)=>t.replace(/^\t+/gm,r=>" ".repeat(r.length*(e||2)))});var gwe=_((lKt,hwe)=>{"use strict";var yCt=pwe(),ECt=(t,e)=>{let r=[],o=t-e,a=t+e;for(let n=o;n<=a;n++)r.push(n);return r};hwe.exports=(t,e,r)=>{if(typeof t!="string")throw new TypeError("Source code is missing.");if(!e||e<1)throw new TypeError("Line number must start from `1`.");if(t=yCt(t).split(/\r?\n/),!(e>t.length))return r={around:3,...r},ECt(e,r.around).filter(o=>t[o-1]!==void 0).map(o=>({line:o,value:t[o-1]}))}});var aQ=_(ru=>{"use strict";var CCt=ru&&ru.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),wCt=ru&&ru.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),ICt=ru&&ru.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&CCt(e,t,r);return wCt(e,t),e},BCt=ru&&ru.__rest||function(t,e){var r={};for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&e.indexOf(o)<0&&(r[o]=t[o]);if(t!=null&&typeof Object.getOwnPropertySymbols=="function")for(var a=0,o=Object.getOwnPropertySymbols(t);a{var{children:r}=t,o=BCt(t,["children"]);let a=Object.assign(Object.assign({},o),{marginLeft:o.marginLeft||o.marginX||o.margin||0,marginRight:o.marginRight||o.marginX||o.margin||0,marginTop:o.marginTop||o.marginY||o.margin||0,marginBottom:o.marginBottom||o.marginY||o.margin||0,paddingLeft:o.paddingLeft||o.paddingX||o.padding||0,paddingRight:o.paddingRight||o.paddingX||o.padding||0,paddingTop:o.paddingTop||o.paddingY||o.padding||0,paddingBottom:o.paddingBottom||o.paddingY||o.padding||0});return dwe.default.createElement("ink-box",{ref:e,style:a},r)});mj.displayName="Box";mj.defaultProps={flexDirection:"row",flexGrow:0,flexShrink:1};ru.default=mj});var Cj=_(BB=>{"use strict";var yj=BB&&BB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(BB,"__esModule",{value:!0});var vCt=yj(sn()),HC=yj(iQ()),mwe=yj($6()),Ej=({color:t,backgroundColor:e,dimColor:r,bold:o,italic:a,underline:n,strikethrough:u,inverse:A,wrap:p,children:h})=>{if(h==null)return null;let E=I=>(r&&(I=HC.default.dim(I)),t&&(I=mwe.default(I,t,"foreground")),e&&(I=mwe.default(I,e,"background")),o&&(I=HC.default.bold(I)),a&&(I=HC.default.italic(I)),n&&(I=HC.default.underline(I)),u&&(I=HC.default.strikethrough(I)),A&&(I=HC.default.inverse(I)),I);return vCt.default.createElement("ink-text",{style:{flexGrow:0,flexShrink:1,flexDirection:"row",textWrap:p},internal_transform:E},h)};Ej.displayName="Text";Ej.defaultProps={dimColor:!1,bold:!1,italic:!1,underline:!1,strikethrough:!1,wrap:"wrap"};BB.default=Ej});var wwe=_(nu=>{"use strict";var DCt=nu&&nu.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),PCt=nu&&nu.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),SCt=nu&&nu.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&DCt(e,t,r);return PCt(e,t),e},vB=nu&&nu.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(nu,"__esModule",{value:!0});var ywe=SCt(Be("fs")),fs=vB(sn()),Ewe=vB(Awe()),xCt=vB(gwe()),Xf=vB(aQ()),hA=vB(Cj()),Cwe=new Ewe.default({cwd:process.cwd(),internals:Ewe.default.nodeInternals()}),bCt=({error:t})=>{let e=t.stack?t.stack.split(` -`).slice(1):void 0,r=e?Cwe.parseLine(e[0]):void 0,o,a=0;if(r?.file&&r?.line&&ywe.existsSync(r.file)){let n=ywe.readFileSync(r.file,"utf8");if(o=xCt.default(n,r.line),o)for(let{line:u}of o)a=Math.max(a,String(u).length)}return fs.default.createElement(Xf.default,{flexDirection:"column",padding:1},fs.default.createElement(Xf.default,null,fs.default.createElement(hA.default,{backgroundColor:"red",color:"white"}," ","ERROR"," "),fs.default.createElement(hA.default,null," ",t.message)),r&&fs.default.createElement(Xf.default,{marginTop:1},fs.default.createElement(hA.default,{dimColor:!0},r.file,":",r.line,":",r.column)),r&&o&&fs.default.createElement(Xf.default,{marginTop:1,flexDirection:"column"},o.map(({line:n,value:u})=>fs.default.createElement(Xf.default,{key:n},fs.default.createElement(Xf.default,{width:a+1},fs.default.createElement(hA.default,{dimColor:n!==r.line,backgroundColor:n===r.line?"red":void 0,color:n===r.line?"white":void 0},String(n).padStart(a," "),":")),fs.default.createElement(hA.default,{key:n,backgroundColor:n===r.line?"red":void 0,color:n===r.line?"white":void 0}," "+u)))),t.stack&&fs.default.createElement(Xf.default,{marginTop:1,flexDirection:"column"},t.stack.split(` -`).slice(1).map(n=>{let u=Cwe.parseLine(n);return u?fs.default.createElement(Xf.default,{key:n},fs.default.createElement(hA.default,{dimColor:!0},"- "),fs.default.createElement(hA.default,{dimColor:!0,bold:!0},u.function),fs.default.createElement(hA.default,{dimColor:!0,color:"gray"}," ","(",u.file,":",u.line,":",u.column,")")):fs.default.createElement(Xf.default,{key:n},fs.default.createElement(hA.default,{dimColor:!0},"- "),fs.default.createElement(hA.default,{dimColor:!0,bold:!0},n))})))};nu.default=bCt});var Bwe=_(iu=>{"use strict";var kCt=iu&&iu.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),QCt=iu&&iu.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),FCt=iu&&iu.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&kCt(e,t,r);return QCt(e,t),e},cm=iu&&iu.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(iu,"__esModule",{value:!0});var lm=FCt(sn()),Iwe=cm(m6()),TCt=cm(cj()),RCt=cm(Aj()),NCt=cm(pj()),LCt=cm(gj()),MCt=cm(oQ()),OCt=cm(wwe()),UCt=" ",_Ct="\x1B[Z",HCt="\x1B",lQ=class extends lm.PureComponent{constructor(){super(...arguments),this.state={isFocusEnabled:!0,activeFocusId:void 0,focusables:[],error:void 0},this.rawModeEnabledCount=0,this.handleSetRawMode=e=>{let{stdin:r}=this.props;if(!this.isRawModeSupported())throw r===process.stdin?new Error(`Raw mode is not supported on the current process.stdin, which Ink uses as input stream by default. -Read about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`):new Error(`Raw mode is not supported on the stdin provided to Ink. -Read about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`);if(r.setEncoding("utf8"),e){this.rawModeEnabledCount===0&&(r.addListener("data",this.handleInput),r.resume(),r.setRawMode(!0)),this.rawModeEnabledCount++;return}--this.rawModeEnabledCount===0&&(r.setRawMode(!1),r.removeListener("data",this.handleInput),r.pause())},this.handleInput=e=>{e===""&&this.props.exitOnCtrlC&&this.handleExit(),e===HCt&&this.state.activeFocusId&&this.setState({activeFocusId:void 0}),this.state.isFocusEnabled&&this.state.focusables.length>0&&(e===UCt&&this.focusNext(),e===_Ct&&this.focusPrevious())},this.handleExit=e=>{this.isRawModeSupported()&&this.handleSetRawMode(!1),this.props.onExit(e)},this.enableFocus=()=>{this.setState({isFocusEnabled:!0})},this.disableFocus=()=>{this.setState({isFocusEnabled:!1})},this.focusNext=()=>{this.setState(e=>{let r=e.focusables[0].id;return{activeFocusId:this.findNextFocusable(e)||r}})},this.focusPrevious=()=>{this.setState(e=>{let r=e.focusables[e.focusables.length-1].id;return{activeFocusId:this.findPreviousFocusable(e)||r}})},this.addFocusable=(e,{autoFocus:r})=>{this.setState(o=>{let a=o.activeFocusId;return!a&&r&&(a=e),{activeFocusId:a,focusables:[...o.focusables,{id:e,isActive:!0}]}})},this.removeFocusable=e=>{this.setState(r=>({activeFocusId:r.activeFocusId===e?void 0:r.activeFocusId,focusables:r.focusables.filter(o=>o.id!==e)}))},this.activateFocusable=e=>{this.setState(r=>({focusables:r.focusables.map(o=>o.id!==e?o:{id:e,isActive:!0})}))},this.deactivateFocusable=e=>{this.setState(r=>({activeFocusId:r.activeFocusId===e?void 0:r.activeFocusId,focusables:r.focusables.map(o=>o.id!==e?o:{id:e,isActive:!1})}))},this.findNextFocusable=e=>{let r=e.focusables.findIndex(o=>o.id===e.activeFocusId);for(let o=r+1;o{let r=e.focusables.findIndex(o=>o.id===e.activeFocusId);for(let o=r-1;o>=0;o--)if(e.focusables[o].isActive)return e.focusables[o].id}}static getDerivedStateFromError(e){return{error:e}}isRawModeSupported(){return this.props.stdin.isTTY}render(){return lm.default.createElement(TCt.default.Provider,{value:{exit:this.handleExit}},lm.default.createElement(RCt.default.Provider,{value:{stdin:this.props.stdin,setRawMode:this.handleSetRawMode,isRawModeSupported:this.isRawModeSupported(),internal_exitOnCtrlC:this.props.exitOnCtrlC}},lm.default.createElement(NCt.default.Provider,{value:{stdout:this.props.stdout,write:this.props.writeToStdout}},lm.default.createElement(LCt.default.Provider,{value:{stderr:this.props.stderr,write:this.props.writeToStderr}},lm.default.createElement(MCt.default.Provider,{value:{activeId:this.state.activeFocusId,add:this.addFocusable,remove:this.removeFocusable,activate:this.activateFocusable,deactivate:this.deactivateFocusable,enableFocus:this.enableFocus,disableFocus:this.disableFocus,focusNext:this.focusNext,focusPrevious:this.focusPrevious}},this.state.error?lm.default.createElement(OCt.default,{error:this.state.error}):this.props.children)))))}componentDidMount(){Iwe.default.hide(this.props.stdout)}componentWillUnmount(){Iwe.default.show(this.props.stdout),this.isRawModeSupported()&&this.handleSetRawMode(!1)}componentDidCatch(e){this.handleExit(e)}};iu.default=lQ;lQ.displayName="InternalApp"});var Pwe=_(su=>{"use strict";var jCt=su&&su.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),qCt=su&&su.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),GCt=su&&su.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&jCt(e,t,r);return qCt(e,t),e},ou=su&&su.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(su,"__esModule",{value:!0});var YCt=ou(sn()),vwe=uO(),WCt=ou(AEe()),VCt=ou(f6()),KCt=ou(mEe()),JCt=ou(EEe()),wj=ou(fCe()),zCt=ou(zCe()),XCt=ou(d6()),ZCt=ou(ewe()),$Ct=GCt(W6()),ewt=ou(aj()),twt=ou(Bwe()),jC=process.env.CI==="false"?!1:KCt.default,Dwe=()=>{},Ij=class{constructor(e){this.resolveExitPromise=()=>{},this.rejectExitPromise=()=>{},this.unsubscribeExit=()=>{},this.onRender=()=>{if(this.isUnmounted)return;let{output:r,outputHeight:o,staticOutput:a}=zCt.default(this.rootNode,this.options.stdout.columns||80),n=a&&a!==` -`;if(this.options.debug){n&&(this.fullStaticOutput+=a),this.options.stdout.write(this.fullStaticOutput+r);return}if(jC){n&&this.options.stdout.write(a),this.lastOutput=r;return}if(n&&(this.fullStaticOutput+=a),o>=this.options.stdout.rows){this.options.stdout.write(VCt.default.clearTerminal+this.fullStaticOutput+r),this.lastOutput=r;return}n&&(this.log.clear(),this.options.stdout.write(a),this.log(r)),!n&&r!==this.lastOutput&&this.throttledLog(r),this.lastOutput=r},JCt.default(this),this.options=e,this.rootNode=$Ct.createNode("ink-root"),this.rootNode.onRender=e.debug?this.onRender:vwe(this.onRender,32,{leading:!0,trailing:!0}),this.rootNode.onImmediateRender=this.onRender,this.log=WCt.default.create(e.stdout),this.throttledLog=e.debug?this.log:vwe(this.log,void 0,{leading:!0,trailing:!0}),this.isUnmounted=!1,this.lastOutput="",this.fullStaticOutput="",this.container=wj.default.createContainer(this.rootNode,!1,!1),this.unsubscribeExit=XCt.default(this.unmount,{alwaysLast:!1}),e.patchConsole&&this.patchConsole(),jC||(e.stdout.on("resize",this.onRender),this.unsubscribeResize=()=>{e.stdout.off("resize",this.onRender)})}render(e){let r=YCt.default.createElement(twt.default,{stdin:this.options.stdin,stdout:this.options.stdout,stderr:this.options.stderr,writeToStdout:this.writeToStdout,writeToStderr:this.writeToStderr,exitOnCtrlC:this.options.exitOnCtrlC,onExit:this.unmount},e);wj.default.updateContainer(r,this.container,null,Dwe)}writeToStdout(e){if(!this.isUnmounted){if(this.options.debug){this.options.stdout.write(e+this.fullStaticOutput+this.lastOutput);return}if(jC){this.options.stdout.write(e);return}this.log.clear(),this.options.stdout.write(e),this.log(this.lastOutput)}}writeToStderr(e){if(!this.isUnmounted){if(this.options.debug){this.options.stderr.write(e),this.options.stdout.write(this.fullStaticOutput+this.lastOutput);return}if(jC){this.options.stderr.write(e);return}this.log.clear(),this.options.stderr.write(e),this.log(this.lastOutput)}}unmount(e){this.isUnmounted||(this.onRender(),this.unsubscribeExit(),typeof this.restoreConsole=="function"&&this.restoreConsole(),typeof this.unsubscribeResize=="function"&&this.unsubscribeResize(),jC?this.options.stdout.write(this.lastOutput+` -`):this.options.debug||this.log.done(),this.isUnmounted=!0,wj.default.updateContainer(null,this.container,null,Dwe),ewt.default.delete(this.options.stdout),e instanceof Error?this.rejectExitPromise(e):this.resolveExitPromise())}waitUntilExit(){return this.exitPromise||(this.exitPromise=new Promise((e,r)=>{this.resolveExitPromise=e,this.rejectExitPromise=r})),this.exitPromise}clear(){!jC&&!this.options.debug&&this.log.clear()}patchConsole(){this.options.debug||(this.restoreConsole=ZCt.default((e,r)=>{e==="stdout"&&this.writeToStdout(r),e==="stderr"&&(r.startsWith("The above error occurred")||this.writeToStderr(r))}))}};su.default=Ij});var xwe=_(DB=>{"use strict";var Swe=DB&&DB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(DB,"__esModule",{value:!0});var rwt=Swe(Pwe()),cQ=Swe(aj()),nwt=Be("stream"),iwt=(t,e)=>{let r=Object.assign({stdout:process.stdout,stdin:process.stdin,stderr:process.stderr,debug:!1,exitOnCtrlC:!0,patchConsole:!0},swt(e)),o=owt(r.stdout,()=>new rwt.default(r));return o.render(t),{rerender:o.render,unmount:()=>o.unmount(),waitUntilExit:o.waitUntilExit,cleanup:()=>cQ.default.delete(r.stdout),clear:o.clear}};DB.default=iwt;var swt=(t={})=>t instanceof nwt.Stream?{stdout:t,stdin:process.stdin}:t,owt=(t,e)=>{let r;return cQ.default.has(t)?r=cQ.default.get(t):(r=e(),cQ.default.set(t,r)),r}});var kwe=_(Zf=>{"use strict";var awt=Zf&&Zf.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),lwt=Zf&&Zf.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),cwt=Zf&&Zf.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&awt(e,t,r);return lwt(e,t),e};Object.defineProperty(Zf,"__esModule",{value:!0});var PB=cwt(sn()),bwe=t=>{let{items:e,children:r,style:o}=t,[a,n]=PB.useState(0),u=PB.useMemo(()=>e.slice(a),[e,a]);PB.useLayoutEffect(()=>{n(e.length)},[e.length]);let A=u.map((h,E)=>r(h,a+E)),p=PB.useMemo(()=>Object.assign({position:"absolute",flexDirection:"column"},o),[o]);return PB.default.createElement("ink-box",{internal_static:!0,style:p},A)};bwe.displayName="Static";Zf.default=bwe});var Fwe=_(SB=>{"use strict";var uwt=SB&&SB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(SB,"__esModule",{value:!0});var Awt=uwt(sn()),Qwe=({children:t,transform:e})=>t==null?null:Awt.default.createElement("ink-text",{style:{flexGrow:0,flexShrink:1,flexDirection:"row"},internal_transform:e},t);Qwe.displayName="Transform";SB.default=Qwe});var Rwe=_(xB=>{"use strict";var fwt=xB&&xB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(xB,"__esModule",{value:!0});var pwt=fwt(sn()),Twe=({count:t=1})=>pwt.default.createElement("ink-text",null,` -`.repeat(t));Twe.displayName="Newline";xB.default=Twe});var Mwe=_(bB=>{"use strict";var Nwe=bB&&bB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(bB,"__esModule",{value:!0});var hwt=Nwe(sn()),gwt=Nwe(aQ()),Lwe=()=>hwt.default.createElement(gwt.default,{flexGrow:1});Lwe.displayName="Spacer";bB.default=Lwe});var uQ=_(kB=>{"use strict";var dwt=kB&&kB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(kB,"__esModule",{value:!0});var mwt=sn(),ywt=dwt(Aj()),Ewt=()=>mwt.useContext(ywt.default);kB.default=Ewt});var Uwe=_(QB=>{"use strict";var Cwt=QB&&QB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(QB,"__esModule",{value:!0});var Owe=sn(),wwt=Cwt(uQ()),Iwt=(t,e={})=>{let{stdin:r,setRawMode:o,internal_exitOnCtrlC:a}=wwt.default();Owe.useEffect(()=>{if(e.isActive!==!1)return o(!0),()=>{o(!1)}},[e.isActive,o]),Owe.useEffect(()=>{if(e.isActive===!1)return;let n=u=>{let A=String(u),p={upArrow:A==="\x1B[A",downArrow:A==="\x1B[B",leftArrow:A==="\x1B[D",rightArrow:A==="\x1B[C",pageDown:A==="\x1B[6~",pageUp:A==="\x1B[5~",return:A==="\r",escape:A==="\x1B",ctrl:!1,shift:!1,tab:A===" "||A==="\x1B[Z",backspace:A==="\b",delete:A==="\x7F"||A==="\x1B[3~",meta:!1};A<=""&&!p.return&&(A=String.fromCharCode(A.charCodeAt(0)+"a".charCodeAt(0)-1),p.ctrl=!0),A.startsWith("\x1B")&&(A=A.slice(1),p.meta=!0);let h=A>="A"&&A<="Z",E=A>="\u0410"&&A<="\u042F";A.length===1&&(h||E)&&(p.shift=!0),p.tab&&A==="[Z"&&(p.shift=!0),(p.tab||p.backspace||p.delete)&&(A=""),(!(A==="c"&&p.ctrl)||!a)&&t(A,p)};return r?.on("data",n),()=>{r?.off("data",n)}},[e.isActive,r,a,t])};QB.default=Iwt});var _we=_(FB=>{"use strict";var Bwt=FB&&FB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(FB,"__esModule",{value:!0});var vwt=sn(),Dwt=Bwt(cj()),Pwt=()=>vwt.useContext(Dwt.default);FB.default=Pwt});var Hwe=_(TB=>{"use strict";var Swt=TB&&TB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(TB,"__esModule",{value:!0});var xwt=sn(),bwt=Swt(pj()),kwt=()=>xwt.useContext(bwt.default);TB.default=kwt});var jwe=_(RB=>{"use strict";var Qwt=RB&&RB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(RB,"__esModule",{value:!0});var Fwt=sn(),Twt=Qwt(gj()),Rwt=()=>Fwt.useContext(Twt.default);RB.default=Rwt});var Gwe=_(LB=>{"use strict";var qwe=LB&&LB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(LB,"__esModule",{value:!0});var NB=sn(),Nwt=qwe(oQ()),Lwt=qwe(uQ()),Mwt=({isActive:t=!0,autoFocus:e=!1}={})=>{let{isRawModeSupported:r,setRawMode:o}=Lwt.default(),{activeId:a,add:n,remove:u,activate:A,deactivate:p}=NB.useContext(Nwt.default),h=NB.useMemo(()=>Math.random().toString().slice(2,7),[]);return NB.useEffect(()=>(n(h,{autoFocus:e}),()=>{u(h)}),[h,e]),NB.useEffect(()=>{t?A(h):p(h)},[t,h]),NB.useEffect(()=>{if(!(!r||!t))return o(!0),()=>{o(!1)}},[t]),{isFocused:Boolean(h)&&a===h}};LB.default=Mwt});var Ywe=_(MB=>{"use strict";var Owt=MB&&MB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(MB,"__esModule",{value:!0});var Uwt=sn(),_wt=Owt(oQ()),Hwt=()=>{let t=Uwt.useContext(_wt.default);return{enableFocus:t.enableFocus,disableFocus:t.disableFocus,focusNext:t.focusNext,focusPrevious:t.focusPrevious}};MB.default=Hwt});var Wwe=_(Bj=>{"use strict";Object.defineProperty(Bj,"__esModule",{value:!0});Bj.default=t=>{var e,r,o,a;return{width:(r=(e=t.yogaNode)===null||e===void 0?void 0:e.getComputedWidth())!==null&&r!==void 0?r:0,height:(a=(o=t.yogaNode)===null||o===void 0?void 0:o.getComputedHeight())!==null&&a!==void 0?a:0}}});var ic=_(ro=>{"use strict";Object.defineProperty(ro,"__esModule",{value:!0});var jwt=xwe();Object.defineProperty(ro,"render",{enumerable:!0,get:function(){return jwt.default}});var qwt=aQ();Object.defineProperty(ro,"Box",{enumerable:!0,get:function(){return qwt.default}});var Gwt=Cj();Object.defineProperty(ro,"Text",{enumerable:!0,get:function(){return Gwt.default}});var Ywt=kwe();Object.defineProperty(ro,"Static",{enumerable:!0,get:function(){return Ywt.default}});var Wwt=Fwe();Object.defineProperty(ro,"Transform",{enumerable:!0,get:function(){return Wwt.default}});var Vwt=Rwe();Object.defineProperty(ro,"Newline",{enumerable:!0,get:function(){return Vwt.default}});var Kwt=Mwe();Object.defineProperty(ro,"Spacer",{enumerable:!0,get:function(){return Kwt.default}});var Jwt=Uwe();Object.defineProperty(ro,"useInput",{enumerable:!0,get:function(){return Jwt.default}});var zwt=_we();Object.defineProperty(ro,"useApp",{enumerable:!0,get:function(){return zwt.default}});var Xwt=uQ();Object.defineProperty(ro,"useStdin",{enumerable:!0,get:function(){return Xwt.default}});var Zwt=Hwe();Object.defineProperty(ro,"useStdout",{enumerable:!0,get:function(){return Zwt.default}});var $wt=jwe();Object.defineProperty(ro,"useStderr",{enumerable:!0,get:function(){return $wt.default}});var eIt=Gwe();Object.defineProperty(ro,"useFocus",{enumerable:!0,get:function(){return eIt.default}});var tIt=Ywe();Object.defineProperty(ro,"useFocusManager",{enumerable:!0,get:function(){return tIt.default}});var rIt=Wwe();Object.defineProperty(ro,"measureElement",{enumerable:!0,get:function(){return rIt.default}})});var Dj={};Kt(Dj,{Gem:()=>vj});var Vwe,um,vj,AQ=Et(()=>{Vwe=$e(ic()),um=$e(sn()),vj=(0,um.memo)(({active:t})=>{let e=(0,um.useMemo)(()=>t?"\u25C9":"\u25EF",[t]),r=(0,um.useMemo)(()=>t?"green":"yellow",[t]);return um.default.createElement(Vwe.Text,{color:r},e)})});var Jwe={};Kt(Jwe,{useKeypress:()=>Am});function Am({active:t},e,r){let{stdin:o}=(0,Kwe.useStdin)(),a=(0,fQ.useCallback)((n,u)=>e(n,u),r);(0,fQ.useEffect)(()=>{if(!(!t||!o))return o.on("keypress",a),()=>{o.off("keypress",a)}},[t,a,o])}var Kwe,fQ,OB=Et(()=>{Kwe=$e(ic()),fQ=$e(sn())});var Xwe={};Kt(Xwe,{FocusRequest:()=>zwe,useFocusRequest:()=>Pj});var zwe,Pj,Sj=Et(()=>{OB();zwe=(r=>(r.BEFORE="before",r.AFTER="after",r))(zwe||{}),Pj=function({active:t},e,r){Am({active:t},(o,a)=>{a.name==="tab"&&(a.shift?e("before"):e("after"))},r)}});var Zwe={};Kt(Zwe,{useListInput:()=>UB});var UB,pQ=Et(()=>{OB();UB=function(t,e,{active:r,minus:o,plus:a,set:n,loop:u=!0}){Am({active:r},(A,p)=>{let h=e.indexOf(t);switch(p.name){case o:{let E=h-1;if(u){n(e[(e.length+E)%e.length]);return}if(E<0)return;n(e[E])}break;case a:{let E=h+1;if(u){n(e[E%e.length]);return}if(E>=e.length)return;n(e[E])}break}},[e,t,a,n,u])}});var hQ={};Kt(hQ,{ScrollableItems:()=>nIt});var E0,La,nIt,gQ=Et(()=>{E0=$e(ic()),La=$e(sn());Sj();pQ();nIt=({active:t=!0,children:e=[],radius:r=10,size:o=1,loop:a=!0,onFocusRequest:n,willReachEnd:u})=>{let A=L=>{if(L.key===null)throw new Error("Expected all children to have a key");return L.key},p=La.default.Children.map(e,L=>A(L)),h=p[0],[E,I]=(0,La.useState)(h),v=p.indexOf(E);(0,La.useEffect)(()=>{p.includes(E)||I(h)},[e]),(0,La.useEffect)(()=>{u&&v>=p.length-2&&u()},[v]),Pj({active:t&&!!n},L=>{n?.(L)},[n]),UB(E,p,{active:t,minus:"up",plus:"down",set:I,loop:a});let b=v-r,C=v+r;C>p.length&&(b-=C-p.length,C=p.length),b<0&&(C+=-b,b=0),C>=p.length&&(C=p.length-1);let T=[];for(let L=b;L<=C;++L){let U=p[L],J=t&&U===E;T.push(La.default.createElement(E0.Box,{key:U,height:o},La.default.createElement(E0.Box,{marginLeft:1,marginRight:1},La.default.createElement(E0.Text,null,J?La.default.createElement(E0.Text,{color:"cyan",bold:!0},">"):" ")),La.default.createElement(E0.Box,null,La.default.cloneElement(e[L],{active:J}))))}return La.default.createElement(E0.Box,{flexDirection:"column",width:"100%"},T)}});var $we,$f,eIe,xj,tIe,bj=Et(()=>{$we=$e(ic()),$f=$e(sn()),eIe=Be("readline"),xj=$f.default.createContext(null),tIe=({children:t})=>{let{stdin:e,setRawMode:r}=(0,$we.useStdin)();(0,$f.useEffect)(()=>{r&&r(!0),e&&(0,eIe.emitKeypressEvents)(e)},[e,r]);let[o,a]=(0,$f.useState)(new Map),n=(0,$f.useMemo)(()=>({getAll:()=>o,get:u=>o.get(u),set:(u,A)=>a(new Map([...o,[u,A]]))}),[o,a]);return $f.default.createElement(xj.Provider,{value:n,children:t})}});var kj={};Kt(kj,{useMinistore:()=>iIt});function iIt(t,e){let r=(0,dQ.useContext)(xj);if(r===null)throw new Error("Expected this hook to run with a ministore context attached");if(typeof t>"u")return r.getAll();let o=(0,dQ.useCallback)(n=>{r.set(t,n)},[t,r.set]),a=r.get(t);return typeof a>"u"&&(a=e),[a,o]}var dQ,Qj=Et(()=>{dQ=$e(sn());bj()});var yQ={};Kt(yQ,{renderForm:()=>sIt});async function sIt(t,e,{stdin:r,stdout:o,stderr:a}){let n,u=p=>{let{exit:h}=(0,mQ.useApp)();Am({active:!0},(E,I)=>{I.name==="return"&&(n=p,h())},[h,p])},{waitUntilExit:A}=(0,mQ.render)(Fj.default.createElement(tIe,null,Fj.default.createElement(t,{...e,useSubmit:u})),{stdin:r,stdout:o,stderr:a});return await A(),n}var mQ,Fj,EQ=Et(()=>{mQ=$e(ic()),Fj=$e(sn());bj();OB()});var sIe=_(_B=>{"use strict";Object.defineProperty(_B,"__esModule",{value:!0});_B.UncontrolledTextInput=void 0;var nIe=sn(),Tj=sn(),rIe=ic(),fm=iQ(),iIe=({value:t,placeholder:e="",focus:r=!0,mask:o,highlightPastedText:a=!1,showCursor:n=!0,onChange:u,onSubmit:A})=>{let[{cursorOffset:p,cursorWidth:h},E]=Tj.useState({cursorOffset:(t||"").length,cursorWidth:0});Tj.useEffect(()=>{E(T=>{if(!r||!n)return T;let L=t||"";return T.cursorOffset>L.length-1?{cursorOffset:L.length,cursorWidth:0}:T})},[t,r,n]);let I=a?h:0,v=o?o.repeat(t.length):t,b=v,C=e?fm.grey(e):void 0;if(n&&r){C=e.length>0?fm.inverse(e[0])+fm.grey(e.slice(1)):fm.inverse(" "),b=v.length>0?"":fm.inverse(" ");let T=0;for(let L of v)T>=p-I&&T<=p?b+=fm.inverse(L):b+=L,T++;v.length>0&&p===v.length&&(b+=fm.inverse(" "))}return rIe.useInput((T,L)=>{if(L.upArrow||L.downArrow||L.ctrl&&T==="c"||L.tab||L.shift&&L.tab)return;if(L.return){A&&A(t);return}let U=p,J=t,te=0;L.leftArrow?n&&U--:L.rightArrow?n&&U++:L.backspace||L.delete?p>0&&(J=t.slice(0,p-1)+t.slice(p,t.length),U--):(J=t.slice(0,p)+T+t.slice(p,t.length),U+=T.length,T.length>1&&(te=T.length)),p<0&&(U=0),p>t.length&&(U=t.length),E({cursorOffset:U,cursorWidth:te}),J!==t&&u(J)},{isActive:r}),nIe.createElement(rIe.Text,null,e?v.length>0?b:C:b)};_B.default=iIe;_B.UncontrolledTextInput=t=>{let[e,r]=Tj.useState("");return nIe.createElement(iIe,Object.assign({},t,{value:e,onChange:r}))}});var lIe={};Kt(lIe,{Pad:()=>Rj});var oIe,aIe,Rj,Nj=Et(()=>{oIe=$e(ic()),aIe=$e(sn()),Rj=({length:t,active:e})=>{if(t===0)return null;let r=t>1?` ${"-".repeat(t-1)}`:" ";return aIe.default.createElement(oIe.Text,{dimColor:!e},r)}});var cIe={};Kt(cIe,{ItemOptions:()=>oIt});var jB,w0,oIt,uIe=Et(()=>{jB=$e(ic()),w0=$e(sn());pQ();AQ();Nj();oIt=function({active:t,skewer:e,options:r,value:o,onChange:a,sizes:n=[]}){let u=r.filter(({label:p})=>!!p).map(({value:p})=>p),A=r.findIndex(p=>p.value===o&&p.label!="");return UB(o,u,{active:t,minus:"left",plus:"right",set:a}),w0.default.createElement(w0.default.Fragment,null,r.map(({label:p},h)=>{let E=h===A,I=n[h]-1||0,v=p.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,""),b=Math.max(0,I-v.length-2);return p?w0.default.createElement(jB.Box,{key:p,width:I,marginLeft:1},w0.default.createElement(jB.Text,{wrap:"truncate"},w0.default.createElement(vj,{active:E})," ",p),e?w0.default.createElement(Rj,{active:t,length:b}):null):w0.default.createElement(jB.Box,{key:`spacer-${h}`,width:I,marginLeft:1})}))}});var PIe=_((zJt,DIe)=>{var Gj;DIe.exports=()=>(typeof Gj>"u"&&(Gj=Be("zlib").brotliDecompressSync(Buffer.from("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","base64")).toString()),Gj)});var VIe=_((wzt,WIe)=>{var $j=Symbol("arg flag"),Ma=class extends Error{constructor(e,r){super(e),this.name="ArgError",this.code=r,Object.setPrototypeOf(this,Ma.prototype)}};function iv(t,{argv:e=process.argv.slice(2),permissive:r=!1,stopAtPositional:o=!1}={}){if(!t)throw new Ma("argument specification object is required","ARG_CONFIG_NO_SPEC");let a={_:[]},n={},u={};for(let A of Object.keys(t)){if(!A)throw new Ma("argument key cannot be an empty string","ARG_CONFIG_EMPTY_KEY");if(A[0]!=="-")throw new Ma(`argument key must start with '-' but found: '${A}'`,"ARG_CONFIG_NONOPT_KEY");if(A.length===1)throw new Ma(`argument key must have a name; singular '-' keys are not allowed: ${A}`,"ARG_CONFIG_NONAME_KEY");if(typeof t[A]=="string"){n[A]=t[A];continue}let p=t[A],h=!1;if(Array.isArray(p)&&p.length===1&&typeof p[0]=="function"){let[E]=p;p=(I,v,b=[])=>(b.push(E(I,v,b[b.length-1])),b),h=E===Boolean||E[$j]===!0}else if(typeof p=="function")h=p===Boolean||p[$j]===!0;else throw new Ma(`type missing or not a function or valid array type: ${A}`,"ARG_CONFIG_VAD_TYPE");if(A[1]!=="-"&&A.length>2)throw new Ma(`short argument keys (with a single hyphen) must have only one character: ${A}`,"ARG_CONFIG_SHORTOPT_TOOLONG");u[A]=[p,h]}for(let A=0,p=e.length;A0){a._=a._.concat(e.slice(A));break}if(h==="--"){a._=a._.concat(e.slice(A+1));break}if(h.length>1&&h[0]==="-"){let E=h[1]==="-"||h.length===2?[h]:h.slice(1).split("").map(I=>`-${I}`);for(let I=0;I1&&e[A+1][0]==="-"&&!(e[A+1].match(/^-?\d*(\.(?=\d))?\d*$/)&&(L===Number||typeof BigInt<"u"&&L===BigInt))){let J=b===T?"":` (alias for ${T})`;throw new Ma(`option requires argument: ${b}${J}`,"ARG_MISSING_REQUIRED_LONGARG")}a[T]=L(e[A+1],T,a[T]),++A}else a[T]=L(C,T,a[T])}}else a._.push(h)}return a}iv.flag=t=>(t[$j]=!0,t);iv.COUNT=iv.flag((t,e,r)=>(r||0)+1);iv.ArgError=Ma;WIe.exports=iv});var t1e=_((Kzt,e1e)=>{var nq;e1e.exports=()=>(typeof nq>"u"&&(nq=Be("zlib").brotliDecompressSync(Buffer.from("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","base64")).toString()),nq)});var o1e=_((cq,uq)=>{(function(t){cq&&typeof cq=="object"&&typeof uq<"u"?uq.exports=t():typeof define=="function"&&define.amd?define([],t):typeof window<"u"?window.isWindows=t():typeof global<"u"?global.isWindows=t():typeof self<"u"?self.isWindows=t():this.isWindows=t()})(function(){"use strict";return function(){return process&&(process.platform==="win32"||/^(msys|cygwin)$/.test(process.env.OSTYPE))}})});var u1e=_((WXt,c1e)=>{"use strict";Aq.ifExists=n1t;var GC=Be("util"),sc=Be("path"),a1e=o1e(),e1t=/^#!\s*(?:\/usr\/bin\/env)?\s*([^ \t]+)(.*)$/,t1t={createPwshFile:!0,createCmdFile:a1e(),fs:Be("fs")},r1t=new Map([[".js","node"],[".cjs","node"],[".mjs","node"],[".cmd","cmd"],[".bat","cmd"],[".ps1","pwsh"],[".sh","sh"]]);function l1e(t){let e={...t1t,...t},r=e.fs;return e.fs_={chmod:r.chmod?GC.promisify(r.chmod):async()=>{},mkdir:GC.promisify(r.mkdir),readFile:GC.promisify(r.readFile),stat:GC.promisify(r.stat),unlink:GC.promisify(r.unlink),writeFile:GC.promisify(r.writeFile)},e}async function Aq(t,e,r){let o=l1e(r);await o.fs_.stat(t),await s1t(t,e,o)}function n1t(t,e,r){return Aq(t,e,r).catch(()=>{})}function i1t(t,e){return e.fs_.unlink(t).catch(()=>{})}async function s1t(t,e,r){let o=await u1t(t,r);return await o1t(e,r),a1t(t,e,o,r)}function o1t(t,e){return e.fs_.mkdir(sc.dirname(t),{recursive:!0})}function a1t(t,e,r,o){let a=l1e(o),n=[{generator:p1t,extension:""}];return a.createCmdFile&&n.push({generator:f1t,extension:".cmd"}),a.createPwshFile&&n.push({generator:h1t,extension:".ps1"}),Promise.all(n.map(u=>A1t(t,e+u.extension,r,u.generator,a)))}function l1t(t,e){return i1t(t,e)}function c1t(t,e){return g1t(t,e)}async function u1t(t,e){let a=(await e.fs_.readFile(t,"utf8")).trim().split(/\r*\n/)[0].match(e1t);if(!a){let n=sc.extname(t).toLowerCase();return{program:r1t.get(n)||null,additionalArgs:""}}return{program:a[1],additionalArgs:a[2]}}async function A1t(t,e,r,o,a){let n=a.preserveSymlinks?"--preserve-symlinks":"",u=[r.additionalArgs,n].filter(A=>A).join(" ");return a=Object.assign({},a,{prog:r.program,args:u}),await l1t(e,a),await a.fs_.writeFile(e,o(t,e,a),"utf8"),c1t(e,a)}function f1t(t,e,r){let a=sc.relative(sc.dirname(e),t).split("/").join("\\"),n=sc.isAbsolute(a)?`"${a}"`:`"%~dp0\\${a}"`,u,A=r.prog,p=r.args||"",h=fq(r.nodePath).win32;A?(u=`"%~dp0\\${A}.exe"`,a=n):(A=n,p="",a="");let E=r.progArgs?`${r.progArgs.join(" ")} `:"",I=h?`@SET NODE_PATH=${h}\r -`:"";return u?I+=`@IF EXIST ${u} (\r - ${u} ${p} ${a} ${E}%*\r -) ELSE (\r - @SETLOCAL\r - @SET PATHEXT=%PATHEXT:;.JS;=;%\r - ${A} ${p} ${a} ${E}%*\r -)\r -`:I+=`@${A} ${p} ${a} ${E}%*\r -`,I}function p1t(t,e,r){let o=sc.relative(sc.dirname(e),t),a=r.prog&&r.prog.split("\\").join("/"),n;o=o.split("\\").join("/");let u=sc.isAbsolute(o)?`"${o}"`:`"$basedir/${o}"`,A=r.args||"",p=fq(r.nodePath).posix;a?(n=`"$basedir/${r.prog}"`,o=u):(a=u,A="",o="");let h=r.progArgs?`${r.progArgs.join(" ")} `:"",E=`#!/bin/sh -basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')") - -case \`uname\` in - *CYGWIN*) basedir=\`cygpath -w "$basedir"\`;; -esac - -`,I=r.nodePath?`export NODE_PATH="${p}" -`:"";return n?E+=`${I}if [ -x ${n} ]; then - exec ${n} ${A} ${o} ${h}"$@" -else - exec ${a} ${A} ${o} ${h}"$@" -fi -`:E+=`${I}${a} ${A} ${o} ${h}"$@" -exit $? -`,E}function h1t(t,e,r){let o=sc.relative(sc.dirname(e),t),a=r.prog&&r.prog.split("\\").join("/"),n=a&&`"${a}$exe"`,u;o=o.split("\\").join("/");let A=sc.isAbsolute(o)?`"${o}"`:`"$basedir/${o}"`,p=r.args||"",h=fq(r.nodePath),E=h.win32,I=h.posix;n?(u=`"$basedir/${r.prog}$exe"`,o=A):(n=A,p="",o="");let v=r.progArgs?`${r.progArgs.join(" ")} `:"",b=`#!/usr/bin/env pwsh -$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent - -$exe="" -${r.nodePath?`$env_node_path=$env:NODE_PATH -$env:NODE_PATH="${E}" -`:""}if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { - # Fix case when both the Windows and Linux builds of Node - # are installed in the same directory - $exe=".exe" -}`;return r.nodePath&&(b+=` else { - $env:NODE_PATH="${I}" -}`),u?b+=` -$ret=0 -if (Test-Path ${u}) { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & ${u} ${p} ${o} ${v}$args - } else { - & ${u} ${p} ${o} ${v}$args - } - $ret=$LASTEXITCODE -} else { - # Support pipeline input - if ($MyInvocation.ExpectingInput) { - $input | & ${n} ${p} ${o} ${v}$args - } else { - & ${n} ${p} ${o} ${v}$args - } - $ret=$LASTEXITCODE -} -${r.nodePath?`$env:NODE_PATH=$env_node_path -`:""}exit $ret -`:b+=` -# Support pipeline input -if ($MyInvocation.ExpectingInput) { - $input | & ${n} ${p} ${o} ${v}$args -} else { - & ${n} ${p} ${o} ${v}$args -} -${r.nodePath?`$env:NODE_PATH=$env_node_path -`:""}exit $LASTEXITCODE -`,b}function g1t(t,e){return e.fs_.chmod(t,493)}function fq(t){if(!t)return{win32:"",posix:""};let e=typeof t=="string"?t.split(sc.delimiter):Array.from(t),r={};for(let o=0;o`/mnt/${A.toLowerCase()}`):e[o];r.win32=r.win32?`${r.win32};${a}`:a,r.posix=r.posix?`${r.posix}:${n}`:n,r[o]={win32:a,posix:n}}return r}c1e.exports=Aq});var Sq=_((h$t,F1e)=>{F1e.exports=Be("stream")});var L1e=_((g$t,N1e)=>{"use strict";function T1e(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);e&&(o=o.filter(function(a){return Object.getOwnPropertyDescriptor(t,a).enumerable})),r.push.apply(r,o)}return r}function U1t(t){for(var e=1;e0?this.tail.next=o:this.head=o,this.tail=o,++this.length}},{key:"unshift",value:function(r){var o={data:r,next:this.head};this.length===0&&(this.tail=o),this.head=o,++this.length}},{key:"shift",value:function(){if(this.length!==0){var r=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,r}}},{key:"clear",value:function(){this.head=this.tail=null,this.length=0}},{key:"join",value:function(r){if(this.length===0)return"";for(var o=this.head,a=""+o.data;o=o.next;)a+=r+o.data;return a}},{key:"concat",value:function(r){if(this.length===0)return QQ.alloc(0);for(var o=QQ.allocUnsafe(r>>>0),a=this.head,n=0;a;)W1t(a.data,o,n),n+=a.data.length,a=a.next;return o}},{key:"consume",value:function(r,o){var a;return ru.length?u.length:r;if(A===u.length?n+=u:n+=u.slice(0,r),r-=A,r===0){A===u.length?(++a,o.next?this.head=o.next:this.head=this.tail=null):(this.head=o,o.data=u.slice(A));break}++a}return this.length-=a,n}},{key:"_getBuffer",value:function(r){var o=QQ.allocUnsafe(r),a=this.head,n=1;for(a.data.copy(o),r-=a.data.length;a=a.next;){var u=a.data,A=r>u.length?u.length:r;if(u.copy(o,o.length-r,0,A),r-=A,r===0){A===u.length?(++n,a.next?this.head=a.next:this.head=this.tail=null):(this.head=a,a.data=u.slice(A));break}++n}return this.length-=n,o}},{key:Y1t,value:function(r,o){return xq(this,U1t({},o,{depth:0,customInspect:!1}))}}]),t}()});var kq=_((d$t,O1e)=>{"use strict";function V1t(t,e){var r=this,o=this._readableState&&this._readableState.destroyed,a=this._writableState&&this._writableState.destroyed;return o||a?(e?e(t):t&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,process.nextTick(bq,this,t)):process.nextTick(bq,this,t)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(t||null,function(n){!e&&n?r._writableState?r._writableState.errorEmitted?process.nextTick(FQ,r):(r._writableState.errorEmitted=!0,process.nextTick(M1e,r,n)):process.nextTick(M1e,r,n):e?(process.nextTick(FQ,r),e(n)):process.nextTick(FQ,r)}),this)}function M1e(t,e){bq(t,e),FQ(t)}function FQ(t){t._writableState&&!t._writableState.emitClose||t._readableState&&!t._readableState.emitClose||t.emit("close")}function K1t(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function bq(t,e){t.emit("error",e)}function J1t(t,e){var r=t._readableState,o=t._writableState;r&&r.autoDestroy||o&&o.autoDestroy?t.destroy(e):t.emit("error",e)}O1e.exports={destroy:V1t,undestroy:K1t,errorOrDestroy:J1t}});var k0=_((m$t,H1e)=>{"use strict";var _1e={};function ac(t,e,r){r||(r=Error);function o(n,u,A){return typeof e=="string"?e:e(n,u,A)}class a extends r{constructor(u,A,p){super(o(u,A,p))}}a.prototype.name=r.name,a.prototype.code=t,_1e[t]=a}function U1e(t,e){if(Array.isArray(t)){let r=t.length;return t=t.map(o=>String(o)),r>2?`one of ${e} ${t.slice(0,r-1).join(", ")}, or `+t[r-1]:r===2?`one of ${e} ${t[0]} or ${t[1]}`:`of ${e} ${t[0]}`}else return`of ${e} ${String(t)}`}function z1t(t,e,r){return t.substr(!r||r<0?0:+r,e.length)===e}function X1t(t,e,r){return(r===void 0||r>t.length)&&(r=t.length),t.substring(r-e.length,r)===e}function Z1t(t,e,r){return typeof r!="number"&&(r=0),r+e.length>t.length?!1:t.indexOf(e,r)!==-1}ac("ERR_INVALID_OPT_VALUE",function(t,e){return'The value "'+e+'" is invalid for option "'+t+'"'},TypeError);ac("ERR_INVALID_ARG_TYPE",function(t,e,r){let o;typeof e=="string"&&z1t(e,"not ")?(o="must not be",e=e.replace(/^not /,"")):o="must be";let a;if(X1t(t," argument"))a=`The ${t} ${o} ${U1e(e,"type")}`;else{let n=Z1t(t,".")?"property":"argument";a=`The "${t}" ${n} ${o} ${U1e(e,"type")}`}return a+=`. Received type ${typeof r}`,a},TypeError);ac("ERR_STREAM_PUSH_AFTER_EOF","stream.push() after EOF");ac("ERR_METHOD_NOT_IMPLEMENTED",function(t){return"The "+t+" method is not implemented"});ac("ERR_STREAM_PREMATURE_CLOSE","Premature close");ac("ERR_STREAM_DESTROYED",function(t){return"Cannot call "+t+" after a stream was destroyed"});ac("ERR_MULTIPLE_CALLBACK","Callback called multiple times");ac("ERR_STREAM_CANNOT_PIPE","Cannot pipe, not readable");ac("ERR_STREAM_WRITE_AFTER_END","write after end");ac("ERR_STREAM_NULL_VALUES","May not write null values to stream",TypeError);ac("ERR_UNKNOWN_ENCODING",function(t){return"Unknown encoding: "+t},TypeError);ac("ERR_STREAM_UNSHIFT_AFTER_END_EVENT","stream.unshift() after end event");H1e.exports.codes=_1e});var Qq=_((y$t,j1e)=>{"use strict";var $1t=k0().codes.ERR_INVALID_OPT_VALUE;function e2t(t,e,r){return t.highWaterMark!=null?t.highWaterMark:e?t[r]:null}function t2t(t,e,r,o){var a=e2t(e,o,r);if(a!=null){if(!(isFinite(a)&&Math.floor(a)===a)||a<0){var n=o?r:"highWaterMark";throw new $1t(n,a)}return Math.floor(a)}return t.objectMode?16:16*1024}j1e.exports={getHighWaterMark:t2t}});var q1e=_((E$t,Fq)=>{typeof Object.create=="function"?Fq.exports=function(e,r){r&&(e.super_=r,e.prototype=Object.create(r.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:Fq.exports=function(e,r){if(r){e.super_=r;var o=function(){};o.prototype=r.prototype,e.prototype=new o,e.prototype.constructor=e}}});var Q0=_((C$t,Rq)=>{try{if(Tq=Be("util"),typeof Tq.inherits!="function")throw"";Rq.exports=Tq.inherits}catch{Rq.exports=q1e()}var Tq});var Y1e=_((w$t,G1e)=>{G1e.exports=Be("util").deprecate});var Mq=_((I$t,X1e)=>{"use strict";X1e.exports=Ti;function V1e(t){var e=this;this.next=null,this.entry=null,this.finish=function(){x2t(e,t)}}var JC;Ti.WritableState=mv;var r2t={deprecate:Y1e()},K1e=Sq(),RQ=Be("buffer").Buffer,n2t=global.Uint8Array||function(){};function i2t(t){return RQ.from(t)}function s2t(t){return RQ.isBuffer(t)||t instanceof n2t}var Lq=kq(),o2t=Qq(),a2t=o2t.getHighWaterMark,F0=k0().codes,l2t=F0.ERR_INVALID_ARG_TYPE,c2t=F0.ERR_METHOD_NOT_IMPLEMENTED,u2t=F0.ERR_MULTIPLE_CALLBACK,A2t=F0.ERR_STREAM_CANNOT_PIPE,f2t=F0.ERR_STREAM_DESTROYED,p2t=F0.ERR_STREAM_NULL_VALUES,h2t=F0.ERR_STREAM_WRITE_AFTER_END,g2t=F0.ERR_UNKNOWN_ENCODING,zC=Lq.errorOrDestroy;Q0()(Ti,K1e);function d2t(){}function mv(t,e,r){JC=JC||Em(),t=t||{},typeof r!="boolean"&&(r=e instanceof JC),this.objectMode=!!t.objectMode,r&&(this.objectMode=this.objectMode||!!t.writableObjectMode),this.highWaterMark=a2t(this,t,"writableHighWaterMark",r),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var o=t.decodeStrings===!1;this.decodeStrings=!o,this.defaultEncoding=t.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(a){B2t(e,a)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.emitClose=t.emitClose!==!1,this.autoDestroy=!!t.autoDestroy,this.bufferedRequestCount=0,this.corkedRequestsFree=new V1e(this)}mv.prototype.getBuffer=function(){for(var e=this.bufferedRequest,r=[];e;)r.push(e),e=e.next;return r};(function(){try{Object.defineProperty(mv.prototype,"buffer",{get:r2t.deprecate(function(){return this.getBuffer()},"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch{}})();var TQ;typeof Symbol=="function"&&Symbol.hasInstance&&typeof Function.prototype[Symbol.hasInstance]=="function"?(TQ=Function.prototype[Symbol.hasInstance],Object.defineProperty(Ti,Symbol.hasInstance,{value:function(e){return TQ.call(this,e)?!0:this!==Ti?!1:e&&e._writableState instanceof mv}})):TQ=function(e){return e instanceof this};function Ti(t){JC=JC||Em();var e=this instanceof JC;if(!e&&!TQ.call(Ti,this))return new Ti(t);this._writableState=new mv(t,this,e),this.writable=!0,t&&(typeof t.write=="function"&&(this._write=t.write),typeof t.writev=="function"&&(this._writev=t.writev),typeof t.destroy=="function"&&(this._destroy=t.destroy),typeof t.final=="function"&&(this._final=t.final)),K1e.call(this)}Ti.prototype.pipe=function(){zC(this,new A2t)};function m2t(t,e){var r=new h2t;zC(t,r),process.nextTick(e,r)}function y2t(t,e,r,o){var a;return r===null?a=new p2t:typeof r!="string"&&!e.objectMode&&(a=new l2t("chunk",["string","Buffer"],r)),a?(zC(t,a),process.nextTick(o,a),!1):!0}Ti.prototype.write=function(t,e,r){var o=this._writableState,a=!1,n=!o.objectMode&&s2t(t);return n&&!RQ.isBuffer(t)&&(t=i2t(t)),typeof e=="function"&&(r=e,e=null),n?e="buffer":e||(e=o.defaultEncoding),typeof r!="function"&&(r=d2t),o.ending?m2t(this,r):(n||y2t(this,o,t,r))&&(o.pendingcb++,a=C2t(this,o,n,t,e,r)),a};Ti.prototype.cork=function(){this._writableState.corked++};Ti.prototype.uncork=function(){var t=this._writableState;t.corked&&(t.corked--,!t.writing&&!t.corked&&!t.bufferProcessing&&t.bufferedRequest&&J1e(this,t))};Ti.prototype.setDefaultEncoding=function(e){if(typeof e=="string"&&(e=e.toLowerCase()),!(["hex","utf8","utf-8","ascii","binary","base64","ucs2","ucs-2","utf16le","utf-16le","raw"].indexOf((e+"").toLowerCase())>-1))throw new g2t(e);return this._writableState.defaultEncoding=e,this};Object.defineProperty(Ti.prototype,"writableBuffer",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}});function E2t(t,e,r){return!t.objectMode&&t.decodeStrings!==!1&&typeof e=="string"&&(e=RQ.from(e,r)),e}Object.defineProperty(Ti.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}});function C2t(t,e,r,o,a,n){if(!r){var u=E2t(e,o,a);o!==u&&(r=!0,a="buffer",o=u)}var A=e.objectMode?1:o.length;e.length+=A;var p=e.length{"use strict";var b2t=Object.keys||function(t){var e=[];for(var r in t)e.push(r);return e};$1e.exports=yA;var Z1e=_q(),Uq=Mq();Q0()(yA,Z1e);for(Oq=b2t(Uq.prototype),NQ=0;NQ{var MQ=Be("buffer"),np=MQ.Buffer;function e2e(t,e){for(var r in t)e[r]=t[r]}np.from&&np.alloc&&np.allocUnsafe&&np.allocUnsafeSlow?t2e.exports=MQ:(e2e(MQ,Hq),Hq.Buffer=XC);function XC(t,e,r){return np(t,e,r)}e2e(np,XC);XC.from=function(t,e,r){if(typeof t=="number")throw new TypeError("Argument must not be a number");return np(t,e,r)};XC.alloc=function(t,e,r){if(typeof t!="number")throw new TypeError("Argument must be a number");var o=np(t);return e!==void 0?typeof r=="string"?o.fill(e,r):o.fill(e):o.fill(0),o};XC.allocUnsafe=function(t){if(typeof t!="number")throw new TypeError("Argument must be a number");return np(t)};XC.allocUnsafeSlow=function(t){if(typeof t!="number")throw new TypeError("Argument must be a number");return MQ.SlowBuffer(t)}});var Gq=_(i2e=>{"use strict";var qq=r2e().Buffer,n2e=qq.isEncoding||function(t){switch(t=""+t,t&&t.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};function F2t(t){if(!t)return"utf8";for(var e;;)switch(t){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return t;default:if(e)return;t=(""+t).toLowerCase(),e=!0}}function T2t(t){var e=F2t(t);if(typeof e!="string"&&(qq.isEncoding===n2e||!n2e(t)))throw new Error("Unknown encoding: "+t);return e||t}i2e.StringDecoder=yv;function yv(t){this.encoding=T2t(t);var e;switch(this.encoding){case"utf16le":this.text=U2t,this.end=_2t,e=4;break;case"utf8":this.fillLast=L2t,e=4;break;case"base64":this.text=H2t,this.end=j2t,e=3;break;default:this.write=q2t,this.end=G2t;return}this.lastNeed=0,this.lastTotal=0,this.lastChar=qq.allocUnsafe(e)}yv.prototype.write=function(t){if(t.length===0)return"";var e,r;if(this.lastNeed){if(e=this.fillLast(t),e===void 0)return"";r=this.lastNeed,this.lastNeed=0}else r=0;return r>5===6?2:t>>4===14?3:t>>3===30?4:t>>6===2?-1:-2}function R2t(t,e,r){var o=e.length-1;if(o=0?(a>0&&(t.lastNeed=a-1),a):--o=0?(a>0&&(t.lastNeed=a-2),a):--o=0?(a>0&&(a===2?a=0:t.lastNeed=a-3),a):0))}function N2t(t,e,r){if((e[0]&192)!==128)return t.lastNeed=0,"\uFFFD";if(t.lastNeed>1&&e.length>1){if((e[1]&192)!==128)return t.lastNeed=1,"\uFFFD";if(t.lastNeed>2&&e.length>2&&(e[2]&192)!==128)return t.lastNeed=2,"\uFFFD"}}function L2t(t){var e=this.lastTotal-this.lastNeed,r=N2t(this,t,e);if(r!==void 0)return r;if(this.lastNeed<=t.length)return t.copy(this.lastChar,e,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);t.copy(this.lastChar,e,0,t.length),this.lastNeed-=t.length}function M2t(t,e){var r=R2t(this,t,e);if(!this.lastNeed)return t.toString("utf8",e);this.lastTotal=r;var o=t.length-(r-this.lastNeed);return t.copy(this.lastChar,0,o),t.toString("utf8",e,o)}function O2t(t){var e=t&&t.length?this.write(t):"";return this.lastNeed?e+"\uFFFD":e}function U2t(t,e){if((t.length-e)%2===0){var r=t.toString("utf16le",e);if(r){var o=r.charCodeAt(r.length-1);if(o>=55296&&o<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=t[t.length-2],this.lastChar[1]=t[t.length-1],r.slice(0,-1)}return r}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=t[t.length-1],t.toString("utf16le",e,t.length-1)}function _2t(t){var e=t&&t.length?this.write(t):"";if(this.lastNeed){var r=this.lastTotal-this.lastNeed;return e+this.lastChar.toString("utf16le",0,r)}return e}function H2t(t,e){var r=(t.length-e)%3;return r===0?t.toString("base64",e):(this.lastNeed=3-r,this.lastTotal=3,r===1?this.lastChar[0]=t[t.length-1]:(this.lastChar[0]=t[t.length-2],this.lastChar[1]=t[t.length-1]),t.toString("base64",e,t.length-r))}function j2t(t){var e=t&&t.length?this.write(t):"";return this.lastNeed?e+this.lastChar.toString("base64",0,3-this.lastNeed):e}function q2t(t){return t.toString(this.encoding)}function G2t(t){return t&&t.length?this.write(t):""}});var OQ=_((D$t,a2e)=>{"use strict";var s2e=k0().codes.ERR_STREAM_PREMATURE_CLOSE;function Y2t(t){var e=!1;return function(){if(!e){e=!0;for(var r=arguments.length,o=new Array(r),a=0;a{"use strict";var UQ;function T0(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var K2t=OQ(),R0=Symbol("lastResolve"),Cm=Symbol("lastReject"),Ev=Symbol("error"),_Q=Symbol("ended"),wm=Symbol("lastPromise"),Yq=Symbol("handlePromise"),Im=Symbol("stream");function N0(t,e){return{value:t,done:e}}function J2t(t){var e=t[R0];if(e!==null){var r=t[Im].read();r!==null&&(t[wm]=null,t[R0]=null,t[Cm]=null,e(N0(r,!1)))}}function z2t(t){process.nextTick(J2t,t)}function X2t(t,e){return function(r,o){t.then(function(){if(e[_Q]){r(N0(void 0,!0));return}e[Yq](r,o)},o)}}var Z2t=Object.getPrototypeOf(function(){}),$2t=Object.setPrototypeOf((UQ={get stream(){return this[Im]},next:function(){var e=this,r=this[Ev];if(r!==null)return Promise.reject(r);if(this[_Q])return Promise.resolve(N0(void 0,!0));if(this[Im].destroyed)return new Promise(function(u,A){process.nextTick(function(){e[Ev]?A(e[Ev]):u(N0(void 0,!0))})});var o=this[wm],a;if(o)a=new Promise(X2t(o,this));else{var n=this[Im].read();if(n!==null)return Promise.resolve(N0(n,!1));a=new Promise(this[Yq])}return this[wm]=a,a}},T0(UQ,Symbol.asyncIterator,function(){return this}),T0(UQ,"return",function(){var e=this;return new Promise(function(r,o){e[Im].destroy(null,function(a){if(a){o(a);return}r(N0(void 0,!0))})})}),UQ),Z2t),eBt=function(e){var r,o=Object.create($2t,(r={},T0(r,Im,{value:e,writable:!0}),T0(r,R0,{value:null,writable:!0}),T0(r,Cm,{value:null,writable:!0}),T0(r,Ev,{value:null,writable:!0}),T0(r,_Q,{value:e._readableState.endEmitted,writable:!0}),T0(r,Yq,{value:function(n,u){var A=o[Im].read();A?(o[wm]=null,o[R0]=null,o[Cm]=null,n(N0(A,!1))):(o[R0]=n,o[Cm]=u)},writable:!0}),r));return o[wm]=null,K2t(e,function(a){if(a&&a.code!=="ERR_STREAM_PREMATURE_CLOSE"){var n=o[Cm];n!==null&&(o[wm]=null,o[R0]=null,o[Cm]=null,n(a)),o[Ev]=a;return}var u=o[R0];u!==null&&(o[wm]=null,o[R0]=null,o[Cm]=null,u(N0(void 0,!0))),o[_Q]=!0}),e.on("readable",z2t.bind(null,o)),o};l2e.exports=eBt});var p2e=_((S$t,f2e)=>{"use strict";function u2e(t,e,r,o,a,n,u){try{var A=t[n](u),p=A.value}catch(h){r(h);return}A.done?e(p):Promise.resolve(p).then(o,a)}function tBt(t){return function(){var e=this,r=arguments;return new Promise(function(o,a){var n=t.apply(e,r);function u(p){u2e(n,o,a,u,A,"next",p)}function A(p){u2e(n,o,a,u,A,"throw",p)}u(void 0)})}}function A2e(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);e&&(o=o.filter(function(a){return Object.getOwnPropertyDescriptor(t,a).enumerable})),r.push.apply(r,o)}return r}function rBt(t){for(var e=1;e{"use strict";B2e.exports=mn;var ZC;mn.ReadableState=m2e;var x$t=Be("events").EventEmitter,d2e=function(e,r){return e.listeners(r).length},wv=Sq(),HQ=Be("buffer").Buffer,oBt=global.Uint8Array||function(){};function aBt(t){return HQ.from(t)}function lBt(t){return HQ.isBuffer(t)||t instanceof oBt}var Wq=Be("util"),$r;Wq&&Wq.debuglog?$r=Wq.debuglog("stream"):$r=function(){};var cBt=L1e(),$q=kq(),uBt=Qq(),ABt=uBt.getHighWaterMark,jQ=k0().codes,fBt=jQ.ERR_INVALID_ARG_TYPE,pBt=jQ.ERR_STREAM_PUSH_AFTER_EOF,hBt=jQ.ERR_METHOD_NOT_IMPLEMENTED,gBt=jQ.ERR_STREAM_UNSHIFT_AFTER_END_EVENT,$C,Vq,Kq;Q0()(mn,wv);var Cv=$q.errorOrDestroy,Jq=["error","close","destroy","pause","resume"];function dBt(t,e,r){if(typeof t.prependListener=="function")return t.prependListener(e,r);!t._events||!t._events[e]?t.on(e,r):Array.isArray(t._events[e])?t._events[e].unshift(r):t._events[e]=[r,t._events[e]]}function m2e(t,e,r){ZC=ZC||Em(),t=t||{},typeof r!="boolean"&&(r=e instanceof ZC),this.objectMode=!!t.objectMode,r&&(this.objectMode=this.objectMode||!!t.readableObjectMode),this.highWaterMark=ABt(this,t,"readableHighWaterMark",r),this.buffer=new cBt,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.paused=!0,this.emitClose=t.emitClose!==!1,this.autoDestroy=!!t.autoDestroy,this.destroyed=!1,this.defaultEncoding=t.defaultEncoding||"utf8",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,t.encoding&&($C||($C=Gq().StringDecoder),this.decoder=new $C(t.encoding),this.encoding=t.encoding)}function mn(t){if(ZC=ZC||Em(),!(this instanceof mn))return new mn(t);var e=this instanceof ZC;this._readableState=new m2e(t,this,e),this.readable=!0,t&&(typeof t.read=="function"&&(this._read=t.read),typeof t.destroy=="function"&&(this._destroy=t.destroy)),wv.call(this)}Object.defineProperty(mn.prototype,"destroyed",{enumerable:!1,get:function(){return this._readableState===void 0?!1:this._readableState.destroyed},set:function(e){!this._readableState||(this._readableState.destroyed=e)}});mn.prototype.destroy=$q.destroy;mn.prototype._undestroy=$q.undestroy;mn.prototype._destroy=function(t,e){e(t)};mn.prototype.push=function(t,e){var r=this._readableState,o;return r.objectMode?o=!0:typeof t=="string"&&(e=e||r.defaultEncoding,e!==r.encoding&&(t=HQ.from(t,e),e=""),o=!0),y2e(this,t,e,!1,o)};mn.prototype.unshift=function(t){return y2e(this,t,null,!0,!1)};function y2e(t,e,r,o,a){$r("readableAddChunk",e);var n=t._readableState;if(e===null)n.reading=!1,EBt(t,n);else{var u;if(a||(u=mBt(n,e)),u)Cv(t,u);else if(n.objectMode||e&&e.length>0)if(typeof e!="string"&&!n.objectMode&&Object.getPrototypeOf(e)!==HQ.prototype&&(e=aBt(e)),o)n.endEmitted?Cv(t,new gBt):zq(t,n,e,!0);else if(n.ended)Cv(t,new pBt);else{if(n.destroyed)return!1;n.reading=!1,n.decoder&&!r?(e=n.decoder.write(e),n.objectMode||e.length!==0?zq(t,n,e,!1):Zq(t,n)):zq(t,n,e,!1)}else o||(n.reading=!1,Zq(t,n))}return!n.ended&&(n.length=h2e?t=h2e:(t--,t|=t>>>1,t|=t>>>2,t|=t>>>4,t|=t>>>8,t|=t>>>16,t++),t}function g2e(t,e){return t<=0||e.length===0&&e.ended?0:e.objectMode?1:t!==t?e.flowing&&e.length?e.buffer.head.data.length:e.length:(t>e.highWaterMark&&(e.highWaterMark=yBt(t)),t<=e.length?t:e.ended?e.length:(e.needReadable=!0,0))}mn.prototype.read=function(t){$r("read",t),t=parseInt(t,10);var e=this._readableState,r=t;if(t!==0&&(e.emittedReadable=!1),t===0&&e.needReadable&&((e.highWaterMark!==0?e.length>=e.highWaterMark:e.length>0)||e.ended))return $r("read: emitReadable",e.length,e.ended),e.length===0&&e.ended?Xq(this):qQ(this),null;if(t=g2e(t,e),t===0&&e.ended)return e.length===0&&Xq(this),null;var o=e.needReadable;$r("need readable",o),(e.length===0||e.length-t0?a=w2e(t,e):a=null,a===null?(e.needReadable=e.length<=e.highWaterMark,t=0):(e.length-=t,e.awaitDrain=0),e.length===0&&(e.ended||(e.needReadable=!0),r!==t&&e.ended&&Xq(this)),a!==null&&this.emit("data",a),a};function EBt(t,e){if($r("onEofChunk"),!e.ended){if(e.decoder){var r=e.decoder.end();r&&r.length&&(e.buffer.push(r),e.length+=e.objectMode?1:r.length)}e.ended=!0,e.sync?qQ(t):(e.needReadable=!1,e.emittedReadable||(e.emittedReadable=!0,E2e(t)))}}function qQ(t){var e=t._readableState;$r("emitReadable",e.needReadable,e.emittedReadable),e.needReadable=!1,e.emittedReadable||($r("emitReadable",e.flowing),e.emittedReadable=!0,process.nextTick(E2e,t))}function E2e(t){var e=t._readableState;$r("emitReadable_",e.destroyed,e.length,e.ended),!e.destroyed&&(e.length||e.ended)&&(t.emit("readable"),e.emittedReadable=!1),e.needReadable=!e.flowing&&!e.ended&&e.length<=e.highWaterMark,eG(t)}function Zq(t,e){e.readingMore||(e.readingMore=!0,process.nextTick(CBt,t,e))}function CBt(t,e){for(;!e.reading&&!e.ended&&(e.length1&&I2e(o.pipes,t)!==-1)&&!h&&($r("false write response, pause",o.awaitDrain),o.awaitDrain++),r.pause())}function v(L){$r("onerror",L),T(),t.removeListener("error",v),d2e(t,"error")===0&&Cv(t,L)}dBt(t,"error",v);function b(){t.removeListener("finish",C),T()}t.once("close",b);function C(){$r("onfinish"),t.removeListener("close",b),T()}t.once("finish",C);function T(){$r("unpipe"),r.unpipe(t)}return t.emit("pipe",r),o.flowing||($r("pipe resume"),r.resume()),t};function wBt(t){return function(){var r=t._readableState;$r("pipeOnDrain",r.awaitDrain),r.awaitDrain&&r.awaitDrain--,r.awaitDrain===0&&d2e(t,"data")&&(r.flowing=!0,eG(t))}}mn.prototype.unpipe=function(t){var e=this._readableState,r={hasUnpiped:!1};if(e.pipesCount===0)return this;if(e.pipesCount===1)return t&&t!==e.pipes?this:(t||(t=e.pipes),e.pipes=null,e.pipesCount=0,e.flowing=!1,t&&t.emit("unpipe",this,r),this);if(!t){var o=e.pipes,a=e.pipesCount;e.pipes=null,e.pipesCount=0,e.flowing=!1;for(var n=0;n0,o.flowing!==!1&&this.resume()):t==="readable"&&!o.endEmitted&&!o.readableListening&&(o.readableListening=o.needReadable=!0,o.flowing=!1,o.emittedReadable=!1,$r("on readable",o.length,o.reading),o.length?qQ(this):o.reading||process.nextTick(IBt,this)),r};mn.prototype.addListener=mn.prototype.on;mn.prototype.removeListener=function(t,e){var r=wv.prototype.removeListener.call(this,t,e);return t==="readable"&&process.nextTick(C2e,this),r};mn.prototype.removeAllListeners=function(t){var e=wv.prototype.removeAllListeners.apply(this,arguments);return(t==="readable"||t===void 0)&&process.nextTick(C2e,this),e};function C2e(t){var e=t._readableState;e.readableListening=t.listenerCount("readable")>0,e.resumeScheduled&&!e.paused?e.flowing=!0:t.listenerCount("data")>0&&t.resume()}function IBt(t){$r("readable nexttick read 0"),t.read(0)}mn.prototype.resume=function(){var t=this._readableState;return t.flowing||($r("resume"),t.flowing=!t.readableListening,BBt(this,t)),t.paused=!1,this};function BBt(t,e){e.resumeScheduled||(e.resumeScheduled=!0,process.nextTick(vBt,t,e))}function vBt(t,e){$r("resume",e.reading),e.reading||t.read(0),e.resumeScheduled=!1,t.emit("resume"),eG(t),e.flowing&&!e.reading&&t.read(0)}mn.prototype.pause=function(){return $r("call pause flowing=%j",this._readableState.flowing),this._readableState.flowing!==!1&&($r("pause"),this._readableState.flowing=!1,this.emit("pause")),this._readableState.paused=!0,this};function eG(t){var e=t._readableState;for($r("flow",e.flowing);e.flowing&&t.read()!==null;);}mn.prototype.wrap=function(t){var e=this,r=this._readableState,o=!1;t.on("end",function(){if($r("wrapped end"),r.decoder&&!r.ended){var u=r.decoder.end();u&&u.length&&e.push(u)}e.push(null)}),t.on("data",function(u){if($r("wrapped data"),r.decoder&&(u=r.decoder.write(u)),!(r.objectMode&&u==null)&&!(!r.objectMode&&(!u||!u.length))){var A=e.push(u);A||(o=!0,t.pause())}});for(var a in t)this[a]===void 0&&typeof t[a]=="function"&&(this[a]=function(A){return function(){return t[A].apply(t,arguments)}}(a));for(var n=0;n=e.length?(e.decoder?r=e.buffer.join(""):e.buffer.length===1?r=e.buffer.first():r=e.buffer.concat(e.length),e.buffer.clear()):r=e.buffer.consume(t,e.decoder),r}function Xq(t){var e=t._readableState;$r("endReadable",e.endEmitted),e.endEmitted||(e.ended=!0,process.nextTick(DBt,e,t))}function DBt(t,e){if($r("endReadableNT",t.endEmitted,t.length),!t.endEmitted&&t.length===0&&(t.endEmitted=!0,e.readable=!1,e.emit("end"),t.autoDestroy)){var r=e._writableState;(!r||r.autoDestroy&&r.finished)&&e.destroy()}}typeof Symbol=="function"&&(mn.from=function(t,e){return Kq===void 0&&(Kq=p2e()),Kq(mn,t,e)});function I2e(t,e){for(var r=0,o=t.length;r{"use strict";D2e.exports=ip;var GQ=k0().codes,PBt=GQ.ERR_METHOD_NOT_IMPLEMENTED,SBt=GQ.ERR_MULTIPLE_CALLBACK,xBt=GQ.ERR_TRANSFORM_ALREADY_TRANSFORMING,bBt=GQ.ERR_TRANSFORM_WITH_LENGTH_0,YQ=Em();Q0()(ip,YQ);function kBt(t,e){var r=this._transformState;r.transforming=!1;var o=r.writecb;if(o===null)return this.emit("error",new SBt);r.writechunk=null,r.writecb=null,e!=null&&this.push(e),o(t);var a=this._readableState;a.reading=!1,(a.needReadable||a.length{"use strict";S2e.exports=Iv;var P2e=tG();Q0()(Iv,P2e);function Iv(t){if(!(this instanceof Iv))return new Iv(t);P2e.call(this,t)}Iv.prototype._transform=function(t,e,r){r(null,t)}});var T2e=_((F$t,F2e)=>{"use strict";var rG;function FBt(t){var e=!1;return function(){e||(e=!0,t.apply(void 0,arguments))}}var Q2e=k0().codes,TBt=Q2e.ERR_MISSING_ARGS,RBt=Q2e.ERR_STREAM_DESTROYED;function b2e(t){if(t)throw t}function NBt(t){return t.setHeader&&typeof t.abort=="function"}function LBt(t,e,r,o){o=FBt(o);var a=!1;t.on("close",function(){a=!0}),rG===void 0&&(rG=OQ()),rG(t,{readable:e,writable:r},function(u){if(u)return o(u);a=!0,o()});var n=!1;return function(u){if(!a&&!n){if(n=!0,NBt(t))return t.abort();if(typeof t.destroy=="function")return t.destroy();o(u||new RBt("pipe"))}}}function k2e(t){t()}function MBt(t,e){return t.pipe(e)}function OBt(t){return!t.length||typeof t[t.length-1]!="function"?b2e:t.pop()}function UBt(){for(var t=arguments.length,e=new Array(t),r=0;r0;return LBt(u,p,h,function(E){a||(a=E),E&&n.forEach(k2e),!p&&(n.forEach(k2e),o(a))})});return e.reduce(MBt)}F2e.exports=UBt});var ew=_((lc,vv)=>{var Bv=Be("stream");process.env.READABLE_STREAM==="disable"&&Bv?(vv.exports=Bv.Readable,Object.assign(vv.exports,Bv),vv.exports.Stream=Bv):(lc=vv.exports=_q(),lc.Stream=Bv||lc,lc.Readable=lc,lc.Writable=Mq(),lc.Duplex=Em(),lc.Transform=tG(),lc.PassThrough=x2e(),lc.finished=OQ(),lc.pipeline=T2e())});var L2e=_((T$t,N2e)=>{"use strict";var{Buffer:lu}=Be("buffer"),R2e=Symbol.for("BufferList");function ni(t){if(!(this instanceof ni))return new ni(t);ni._init.call(this,t)}ni._init=function(e){Object.defineProperty(this,R2e,{value:!0}),this._bufs=[],this.length=0,e&&this.append(e)};ni.prototype._new=function(e){return new ni(e)};ni.prototype._offset=function(e){if(e===0)return[0,0];let r=0;for(let o=0;othis.length||e<0)return;let r=this._offset(e);return this._bufs[r[0]][r[1]]};ni.prototype.slice=function(e,r){return typeof e=="number"&&e<0&&(e+=this.length),typeof r=="number"&&r<0&&(r+=this.length),this.copy(null,0,e,r)};ni.prototype.copy=function(e,r,o,a){if((typeof o!="number"||o<0)&&(o=0),(typeof a!="number"||a>this.length)&&(a=this.length),o>=this.length||a<=0)return e||lu.alloc(0);let n=!!e,u=this._offset(o),A=a-o,p=A,h=n&&r||0,E=u[1];if(o===0&&a===this.length){if(!n)return this._bufs.length===1?this._bufs[0]:lu.concat(this._bufs,this.length);for(let I=0;Iv)this._bufs[I].copy(e,h,E),h+=v;else{this._bufs[I].copy(e,h,E,E+p),h+=v;break}p-=v,E&&(E=0)}return e.length>h?e.slice(0,h):e};ni.prototype.shallowSlice=function(e,r){if(e=e||0,r=typeof r!="number"?this.length:r,e<0&&(e+=this.length),r<0&&(r+=this.length),e===r)return this._new();let o=this._offset(e),a=this._offset(r),n=this._bufs.slice(o[0],a[0]+1);return a[1]===0?n.pop():n[n.length-1]=n[n.length-1].slice(0,a[1]),o[1]!==0&&(n[0]=n[0].slice(o[1])),this._new(n)};ni.prototype.toString=function(e,r,o){return this.slice(r,o).toString(e)};ni.prototype.consume=function(e){if(e=Math.trunc(e),Number.isNaN(e)||e<=0)return this;for(;this._bufs.length;)if(e>=this._bufs[0].length)e-=this._bufs[0].length,this.length-=this._bufs[0].length,this._bufs.shift();else{this._bufs[0]=this._bufs[0].slice(e),this.length-=e;break}return this};ni.prototype.duplicate=function(){let e=this._new();for(let r=0;rthis.length?this.length:e;let o=this._offset(e),a=o[0],n=o[1];for(;a=t.length){let p=u.indexOf(t,n);if(p!==-1)return this._reverseOffset([a,p]);n=u.length-t.length+1}else{let p=this._reverseOffset([a,n]);if(this._match(p,t))return p;n++}n=0}return-1};ni.prototype._match=function(t,e){if(this.length-t{"use strict";var nG=ew().Duplex,_Bt=Q0(),Dv=L2e();function Uo(t){if(!(this instanceof Uo))return new Uo(t);if(typeof t=="function"){this._callback=t;let e=function(o){this._callback&&(this._callback(o),this._callback=null)}.bind(this);this.on("pipe",function(o){o.on("error",e)}),this.on("unpipe",function(o){o.removeListener("error",e)}),t=null}Dv._init.call(this,t),nG.call(this)}_Bt(Uo,nG);Object.assign(Uo.prototype,Dv.prototype);Uo.prototype._new=function(e){return new Uo(e)};Uo.prototype._write=function(e,r,o){this._appendBuffer(e),typeof o=="function"&&o()};Uo.prototype._read=function(e){if(!this.length)return this.push(null);e=Math.min(e,this.length),this.push(this.slice(0,e)),this.consume(e)};Uo.prototype.end=function(e){nG.prototype.end.call(this,e),this._callback&&(this._callback(null,this.slice()),this._callback=null)};Uo.prototype._destroy=function(e,r){this._bufs.length=0,this.length=0,r(e)};Uo.prototype._isBufferList=function(e){return e instanceof Uo||e instanceof Dv||Uo.isBufferList(e)};Uo.isBufferList=Dv.isBufferList;WQ.exports=Uo;WQ.exports.BufferListStream=Uo;WQ.exports.BufferList=Dv});var oG=_(rw=>{var HBt=Buffer.alloc,jBt="0000000000000000000",qBt="7777777777777777777",O2e="0".charCodeAt(0),U2e=Buffer.from("ustar\0","binary"),GBt=Buffer.from("00","binary"),YBt=Buffer.from("ustar ","binary"),WBt=Buffer.from(" \0","binary"),VBt=parseInt("7777",8),Pv=257,sG=263,KBt=function(t,e,r){return typeof t!="number"?r:(t=~~t,t>=e?e:t>=0||(t+=e,t>=0)?t:0)},JBt=function(t){switch(t){case 0:return"file";case 1:return"link";case 2:return"symlink";case 3:return"character-device";case 4:return"block-device";case 5:return"directory";case 6:return"fifo";case 7:return"contiguous-file";case 72:return"pax-header";case 55:return"pax-global-header";case 27:return"gnu-long-link-path";case 28:case 30:return"gnu-long-path"}return null},zBt=function(t){switch(t){case"file":return 0;case"link":return 1;case"symlink":return 2;case"character-device":return 3;case"block-device":return 4;case"directory":return 5;case"fifo":return 6;case"contiguous-file":return 7;case"pax-header":return 72}return 0},_2e=function(t,e,r,o){for(;re?qBt.slice(0,e)+" ":jBt.slice(0,e-t.length)+t+" "};function XBt(t){var e;if(t[0]===128)e=!0;else if(t[0]===255)e=!1;else return null;for(var r=[],o=t.length-1;o>0;o--){var a=t[o];e?r.push(a):r.push(255-a)}var n=0,u=r.length;for(o=0;o=Math.pow(10,r)&&r++,e+r+t};rw.decodeLongPath=function(t,e){return tw(t,0,t.length,e)};rw.encodePax=function(t){var e="";t.name&&(e+=iG(" path="+t.name+` -`)),t.linkname&&(e+=iG(" linkpath="+t.linkname+` -`));var r=t.pax;if(r)for(var o in r)e+=iG(" "+o+"="+r[o]+` -`);return Buffer.from(e)};rw.decodePax=function(t){for(var e={};t.length;){for(var r=0;r100;){var a=r.indexOf("/");if(a===-1)return null;o+=o?"/"+r.slice(0,a):r.slice(0,a),r=r.slice(a+1)}return Buffer.byteLength(r)>100||Buffer.byteLength(o)>155||t.linkname&&Buffer.byteLength(t.linkname)>100?null:(e.write(r),e.write(L0(t.mode&VBt,6),100),e.write(L0(t.uid,6),108),e.write(L0(t.gid,6),116),e.write(L0(t.size,11),124),e.write(L0(t.mtime.getTime()/1e3|0,11),136),e[156]=O2e+zBt(t.type),t.linkname&&e.write(t.linkname,157),U2e.copy(e,Pv),GBt.copy(e,sG),t.uname&&e.write(t.uname,265),t.gname&&e.write(t.gname,297),e.write(L0(t.devmajor||0,6),329),e.write(L0(t.devminor||0,6),337),o&&e.write(o,345),e.write(L0(H2e(e),6),148),e)};rw.decode=function(t,e,r){var o=t[156]===0?0:t[156]-O2e,a=tw(t,0,100,e),n=M0(t,100,8),u=M0(t,108,8),A=M0(t,116,8),p=M0(t,124,12),h=M0(t,136,12),E=JBt(o),I=t[157]===0?null:tw(t,157,100,e),v=tw(t,265,32),b=tw(t,297,32),C=M0(t,329,8),T=M0(t,337,8),L=H2e(t);if(L===8*32)return null;if(L!==M0(t,148,8))throw new Error("Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?");if(U2e.compare(t,Pv,Pv+6)===0)t[345]&&(a=tw(t,345,155,e)+"/"+a);else if(!(YBt.compare(t,Pv,Pv+6)===0&&WBt.compare(t,sG,sG+2)===0)){if(!r)throw new Error("Invalid tar header: unknown format.")}return o===0&&a&&a[a.length-1]==="/"&&(o=5),{name:a,mode:n,uid:u,gid:A,size:p,mtime:new Date(1e3*h),type:E,linkname:I,uname:v,gname:b,devmajor:C,devminor:T}}});var K2e=_((L$t,V2e)=>{var q2e=Be("util"),ZBt=M2e(),Sv=oG(),G2e=ew().Writable,Y2e=ew().PassThrough,W2e=function(){},j2e=function(t){return t&=511,t&&512-t},$Bt=function(t,e){var r=new VQ(t,e);return r.end(),r},evt=function(t,e){return e.path&&(t.name=e.path),e.linkpath&&(t.linkname=e.linkpath),e.size&&(t.size=parseInt(e.size,10)),t.pax=e,t},VQ=function(t,e){this._parent=t,this.offset=e,Y2e.call(this,{autoDestroy:!1})};q2e.inherits(VQ,Y2e);VQ.prototype.destroy=function(t){this._parent.destroy(t)};var sp=function(t){if(!(this instanceof sp))return new sp(t);G2e.call(this,t),t=t||{},this._offset=0,this._buffer=ZBt(),this._missing=0,this._partial=!1,this._onparse=W2e,this._header=null,this._stream=null,this._overflow=null,this._cb=null,this._locked=!1,this._destroyed=!1,this._pax=null,this._paxGlobal=null,this._gnuLongPath=null,this._gnuLongLinkPath=null;var e=this,r=e._buffer,o=function(){e._continue()},a=function(v){if(e._locked=!1,v)return e.destroy(v);e._stream||o()},n=function(){e._stream=null;var v=j2e(e._header.size);v?e._parse(v,u):e._parse(512,I),e._locked||o()},u=function(){e._buffer.consume(j2e(e._header.size)),e._parse(512,I),o()},A=function(){var v=e._header.size;e._paxGlobal=Sv.decodePax(r.slice(0,v)),r.consume(v),n()},p=function(){var v=e._header.size;e._pax=Sv.decodePax(r.slice(0,v)),e._paxGlobal&&(e._pax=Object.assign({},e._paxGlobal,e._pax)),r.consume(v),n()},h=function(){var v=e._header.size;this._gnuLongPath=Sv.decodeLongPath(r.slice(0,v),t.filenameEncoding),r.consume(v),n()},E=function(){var v=e._header.size;this._gnuLongLinkPath=Sv.decodeLongPath(r.slice(0,v),t.filenameEncoding),r.consume(v),n()},I=function(){var v=e._offset,b;try{b=e._header=Sv.decode(r.slice(0,512),t.filenameEncoding,t.allowUnknownFormat)}catch(C){e.emit("error",C)}if(r.consume(512),!b){e._parse(512,I),o();return}if(b.type==="gnu-long-path"){e._parse(b.size,h),o();return}if(b.type==="gnu-long-link-path"){e._parse(b.size,E),o();return}if(b.type==="pax-global-header"){e._parse(b.size,A),o();return}if(b.type==="pax-header"){e._parse(b.size,p),o();return}if(e._gnuLongPath&&(b.name=e._gnuLongPath,e._gnuLongPath=null),e._gnuLongLinkPath&&(b.linkname=e._gnuLongLinkPath,e._gnuLongLinkPath=null),e._pax&&(e._header=b=evt(b,e._pax),e._pax=null),e._locked=!0,!b.size||b.type==="directory"){e._parse(512,I),e.emit("entry",b,$Bt(e,v),a);return}e._stream=new VQ(e,v),e.emit("entry",b,e._stream,a),e._parse(b.size,n),o()};this._onheader=I,this._parse(512,I)};q2e.inherits(sp,G2e);sp.prototype.destroy=function(t){this._destroyed||(this._destroyed=!0,t&&this.emit("error",t),this.emit("close"),this._stream&&this._stream.emit("close"))};sp.prototype._parse=function(t,e){this._destroyed||(this._offset+=t,this._missing=t,e===this._onheader&&(this._partial=!1),this._onparse=e)};sp.prototype._continue=function(){if(!this._destroyed){var t=this._cb;this._cb=W2e,this._overflow?this._write(this._overflow,void 0,t):t()}};sp.prototype._write=function(t,e,r){if(!this._destroyed){var o=this._stream,a=this._buffer,n=this._missing;if(t.length&&(this._partial=!0),t.lengthn&&(u=t.slice(n),t=t.slice(0,n)),o?o.end(t):a.append(t),this._overflow=u,this._onparse()}};sp.prototype._final=function(t){if(this._partial)return this.destroy(new Error("Unexpected end of data"));t()};V2e.exports=sp});var z2e=_((M$t,J2e)=>{J2e.exports=Be("fs").constants||Be("constants")});var tBe=_((O$t,eBe)=>{var nw=z2e(),X2e=OO(),JQ=Q0(),tvt=Buffer.alloc,Z2e=ew().Readable,iw=ew().Writable,rvt=Be("string_decoder").StringDecoder,KQ=oG(),nvt=parseInt("755",8),ivt=parseInt("644",8),$2e=tvt(1024),lG=function(){},aG=function(t,e){e&=511,e&&t.push($2e.slice(0,512-e))};function svt(t){switch(t&nw.S_IFMT){case nw.S_IFBLK:return"block-device";case nw.S_IFCHR:return"character-device";case nw.S_IFDIR:return"directory";case nw.S_IFIFO:return"fifo";case nw.S_IFLNK:return"symlink"}return"file"}var zQ=function(t){iw.call(this),this.written=0,this._to=t,this._destroyed=!1};JQ(zQ,iw);zQ.prototype._write=function(t,e,r){if(this.written+=t.length,this._to.push(t))return r();this._to._drain=r};zQ.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit("close"))};var XQ=function(){iw.call(this),this.linkname="",this._decoder=new rvt("utf-8"),this._destroyed=!1};JQ(XQ,iw);XQ.prototype._write=function(t,e,r){this.linkname+=this._decoder.write(t),r()};XQ.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit("close"))};var xv=function(){iw.call(this),this._destroyed=!1};JQ(xv,iw);xv.prototype._write=function(t,e,r){r(new Error("No body allowed for this entry"))};xv.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit("close"))};var EA=function(t){if(!(this instanceof EA))return new EA(t);Z2e.call(this,t),this._drain=lG,this._finalized=!1,this._finalizing=!1,this._destroyed=!1,this._stream=null};JQ(EA,Z2e);EA.prototype.entry=function(t,e,r){if(this._stream)throw new Error("already piping an entry");if(!(this._finalized||this._destroyed)){typeof e=="function"&&(r=e,e=null),r||(r=lG);var o=this;if((!t.size||t.type==="symlink")&&(t.size=0),t.type||(t.type=svt(t.mode)),t.mode||(t.mode=t.type==="directory"?nvt:ivt),t.uid||(t.uid=0),t.gid||(t.gid=0),t.mtime||(t.mtime=new Date),typeof e=="string"&&(e=Buffer.from(e)),Buffer.isBuffer(e)){t.size=e.length,this._encode(t);var a=this.push(e);return aG(o,t.size),a?process.nextTick(r):this._drain=r,new xv}if(t.type==="symlink"&&!t.linkname){var n=new XQ;return X2e(n,function(A){if(A)return o.destroy(),r(A);t.linkname=n.linkname,o._encode(t),r()}),n}if(this._encode(t),t.type!=="file"&&t.type!=="contiguous-file")return process.nextTick(r),new xv;var u=new zQ(this);return this._stream=u,X2e(u,function(A){if(o._stream=null,A)return o.destroy(),r(A);if(u.written!==t.size)return o.destroy(),r(new Error("size mismatch"));aG(o,t.size),o._finalizing&&o.finalize(),r()}),u}};EA.prototype.finalize=function(){if(this._stream){this._finalizing=!0;return}this._finalized||(this._finalized=!0,this.push($2e),this.push(null))};EA.prototype.destroy=function(t){this._destroyed||(this._destroyed=!0,t&&this.emit("error",t),this.emit("close"),this._stream&&this._stream.destroy&&this._stream.destroy())};EA.prototype._encode=function(t){if(!t.pax){var e=KQ.encode(t);if(e){this.push(e);return}}this._encodePax(t)};EA.prototype._encodePax=function(t){var e=KQ.encodePax({name:t.name,linkname:t.linkname,pax:t.pax}),r={name:"PaxHeader",mode:t.mode,uid:t.uid,gid:t.gid,size:e.length,mtime:t.mtime,type:"pax-header",linkname:t.linkname&&"PaxHeader",uname:t.uname,gname:t.gname,devmajor:t.devmajor,devminor:t.devminor};this.push(KQ.encode(r)),this.push(e),aG(this,e.length),r.size=t.size,r.type=t.type,this.push(KQ.encode(r))};EA.prototype._read=function(t){var e=this._drain;this._drain=lG,e()};eBe.exports=EA});var rBe=_(cG=>{cG.extract=K2e();cG.pack=tBe()});var hBe=_((ier,pBe)=>{"use strict";var Bm=class{constructor(e,r,o){this.__specs=e||{},Object.keys(this.__specs).forEach(a=>{if(typeof this.__specs[a]=="string"){let n=this.__specs[a],u=this.__specs[n];if(u){let A=u.aliases||[];A.push(a,n),u.aliases=[...new Set(A)],this.__specs[a]=u}else throw new Error(`Alias refers to invalid key: ${n} -> ${a}`)}}),this.__opts=r||{},this.__providers=ABe(o.filter(a=>a!=null&&typeof a=="object")),this.__isFiggyPudding=!0}get(e){return gG(this,e,!0)}get[Symbol.toStringTag](){return"FiggyPudding"}forEach(e,r=this){for(let[o,a]of this.entries())e.call(r,a,o,this)}toJSON(){let e={};return this.forEach((r,o)=>{e[o]=r}),e}*entries(e){for(let o of Object.keys(this.__specs))yield[o,this.get(o)];let r=e||this.__opts.other;if(r){let o=new Set;for(let a of this.__providers){let n=a.entries?a.entries(r):Cvt(a);for(let[u,A]of n)r(u)&&!o.has(u)&&(o.add(u),yield[u,A])}}}*[Symbol.iterator](){for(let[e,r]of this.entries())yield[e,r]}*keys(){for(let[e]of this.entries())yield e}*values(){for(let[,e]of this.entries())yield e}concat(...e){return new Proxy(new Bm(this.__specs,this.__opts,ABe(this.__providers).concat(e)),fBe)}};try{let t=Be("util");Bm.prototype[t.inspect.custom]=function(e,r){return this[Symbol.toStringTag]+" "+t.inspect(this.toJSON(),r)}}catch{}function yvt(t){throw Object.assign(new Error(`invalid config key requested: ${t}`),{code:"EBADKEY"})}function gG(t,e,r){let o=t.__specs[e];if(r&&!o&&(!t.__opts.other||!t.__opts.other(e)))yvt(e);else{o||(o={});let a;for(let n of t.__providers){if(a=uBe(e,n),a===void 0&&o.aliases&&o.aliases.length){for(let u of o.aliases)if(u!==e&&(a=uBe(u,n),a!==void 0))break}if(a!==void 0)break}return a===void 0&&o.default!==void 0?typeof o.default=="function"?o.default(t):o.default:a}}function uBe(t,e){let r;return e.__isFiggyPudding?r=gG(e,t,!1):typeof e.get=="function"?r=e.get(t):r=e[t],r}var fBe={has(t,e){return e in t.__specs&&gG(t,e,!1)!==void 0},ownKeys(t){return Object.keys(t.__specs)},get(t,e){return typeof e=="symbol"||e.slice(0,2)==="__"||e in Bm.prototype?t[e]:t.get(e)},set(t,e,r){if(typeof e=="symbol"||e.slice(0,2)==="__")return t[e]=r,!0;throw new Error("figgyPudding options cannot be modified. Use .concat() instead.")},deleteProperty(){throw new Error("figgyPudding options cannot be deleted. Use .concat() and shadow them instead.")}};pBe.exports=Evt;function Evt(t,e){function r(...o){return new Proxy(new Bm(t,e,o),fBe)}return r}function ABe(t){let e=[];return t.forEach(r=>e.unshift(r)),e}function Cvt(t){return Object.keys(t).map(e=>[e,t[e]])}});var mBe=_((ser,IA)=>{"use strict";var kv=Be("crypto"),wvt=hBe(),Ivt=Be("stream").Transform,gBe=["sha256","sha384","sha512"],Bvt=/^[a-z0-9+/]+(?:=?=?)$/i,vvt=/^([^-]+)-([^?]+)([?\S*]*)$/,Dvt=/^([^-]+)-([A-Za-z0-9+/=]{44,88})(\?[\x21-\x7E]*)*$/,Pvt=/^[\x21-\x7E]+$/,ia=wvt({algorithms:{default:["sha512"]},error:{default:!1},integrity:{},options:{default:[]},pickAlgorithm:{default:()=>Rvt},Promise:{default:()=>Promise},sep:{default:" "},single:{default:!1},size:{},strict:{default:!1}}),U0=class{get isHash(){return!0}constructor(e,r){r=ia(r);let o=!!r.strict;this.source=e.trim();let a=this.source.match(o?Dvt:vvt);if(!a||o&&!gBe.some(u=>u===a[1]))return;this.algorithm=a[1],this.digest=a[2];let n=a[3];this.options=n?n.slice(1).split("?"):[]}hexDigest(){return this.digest&&Buffer.from(this.digest,"base64").toString("hex")}toJSON(){return this.toString()}toString(e){if(e=ia(e),e.strict&&!(gBe.some(o=>o===this.algorithm)&&this.digest.match(Bvt)&&(this.options||[]).every(o=>o.match(Pvt))))return"";let r=this.options&&this.options.length?`?${this.options.join("?")}`:"";return`${this.algorithm}-${this.digest}${r}`}},vm=class{get isIntegrity(){return!0}toJSON(){return this.toString()}toString(e){e=ia(e);let r=e.sep||" ";return e.strict&&(r=r.replace(/\S+/g," ")),Object.keys(this).map(o=>this[o].map(a=>U0.prototype.toString.call(a,e)).filter(a=>a.length).join(r)).filter(o=>o.length).join(r)}concat(e,r){r=ia(r);let o=typeof e=="string"?e:bv(e,r);return wA(`${this.toString(r)} ${o}`,r)}hexDigest(){return wA(this,{single:!0}).hexDigest()}match(e,r){r=ia(r);let o=wA(e,r),a=o.pickAlgorithm(r);return this[a]&&o[a]&&this[a].find(n=>o[a].find(u=>n.digest===u.digest))||!1}pickAlgorithm(e){e=ia(e);let r=e.pickAlgorithm,o=Object.keys(this);if(!o.length)throw new Error(`No algorithms available for ${JSON.stringify(this.toString())}`);return o.reduce((a,n)=>r(a,n)||a)}};IA.exports.parse=wA;function wA(t,e){if(e=ia(e),typeof t=="string")return dG(t,e);if(t.algorithm&&t.digest){let r=new vm;return r[t.algorithm]=[t],dG(bv(r,e),e)}else return dG(bv(t,e),e)}function dG(t,e){return e.single?new U0(t,e):t.trim().split(/\s+/).reduce((r,o)=>{let a=new U0(o,e);if(a.algorithm&&a.digest){let n=a.algorithm;r[n]||(r[n]=[]),r[n].push(a)}return r},new vm)}IA.exports.stringify=bv;function bv(t,e){return e=ia(e),t.algorithm&&t.digest?U0.prototype.toString.call(t,e):typeof t=="string"?bv(wA(t,e),e):vm.prototype.toString.call(t,e)}IA.exports.fromHex=Svt;function Svt(t,e,r){r=ia(r);let o=r.options&&r.options.length?`?${r.options.join("?")}`:"";return wA(`${e}-${Buffer.from(t,"hex").toString("base64")}${o}`,r)}IA.exports.fromData=xvt;function xvt(t,e){e=ia(e);let r=e.algorithms,o=e.options&&e.options.length?`?${e.options.join("?")}`:"";return r.reduce((a,n)=>{let u=kv.createHash(n).update(t).digest("base64"),A=new U0(`${n}-${u}${o}`,e);if(A.algorithm&&A.digest){let p=A.algorithm;a[p]||(a[p]=[]),a[p].push(A)}return a},new vm)}IA.exports.fromStream=bvt;function bvt(t,e){e=ia(e);let r=e.Promise||Promise,o=mG(e);return new r((a,n)=>{t.pipe(o),t.on("error",n),o.on("error",n);let u;o.on("integrity",A=>{u=A}),o.on("end",()=>a(u)),o.on("data",()=>{})})}IA.exports.checkData=kvt;function kvt(t,e,r){if(r=ia(r),e=wA(e,r),!Object.keys(e).length){if(r.error)throw Object.assign(new Error("No valid integrity hashes to check against"),{code:"EINTEGRITY"});return!1}let o=e.pickAlgorithm(r),a=kv.createHash(o).update(t).digest("base64"),n=wA({algorithm:o,digest:a}),u=n.match(e,r);if(u||!r.error)return u;if(typeof r.size=="number"&&t.length!==r.size){let A=new Error(`data size mismatch when checking ${e}. - Wanted: ${r.size} - Found: ${t.length}`);throw A.code="EBADSIZE",A.found=t.length,A.expected=r.size,A.sri=e,A}else{let A=new Error(`Integrity checksum failed when using ${o}: Wanted ${e}, but got ${n}. (${t.length} bytes)`);throw A.code="EINTEGRITY",A.found=n,A.expected=e,A.algorithm=o,A.sri=e,A}}IA.exports.checkStream=Qvt;function Qvt(t,e,r){r=ia(r);let o=r.Promise||Promise,a=mG(r.concat({integrity:e}));return new o((n,u)=>{t.pipe(a),t.on("error",u),a.on("error",u);let A;a.on("verified",p=>{A=p}),a.on("end",()=>n(A)),a.on("data",()=>{})})}IA.exports.integrityStream=mG;function mG(t){t=ia(t);let e=t.integrity&&wA(t.integrity,t),r=e&&Object.keys(e).length,o=r&&e.pickAlgorithm(t),a=r&&e[o],n=Array.from(new Set(t.algorithms.concat(o?[o]:[]))),u=n.map(kv.createHash),A=0,p=new Ivt({transform(h,E,I){A+=h.length,u.forEach(v=>v.update(h,E)),I(null,h,E)}}).on("end",()=>{let h=t.options&&t.options.length?`?${t.options.join("?")}`:"",E=wA(u.map((v,b)=>`${n[b]}-${v.digest("base64")}${h}`).join(" "),t),I=r&&E.match(e,t);if(typeof t.size=="number"&&A!==t.size){let v=new Error(`stream size mismatch when checking ${e}. - Wanted: ${t.size} - Found: ${A}`);v.code="EBADSIZE",v.found=A,v.expected=t.size,v.sri=e,p.emit("error",v)}else if(t.integrity&&!I){let v=new Error(`${e} integrity checksum failed when using ${o}: wanted ${a} but got ${E}. (${A} bytes)`);v.code="EINTEGRITY",v.found=E,v.expected=a,v.algorithm=o,v.sri=e,p.emit("error",v)}else p.emit("size",A),p.emit("integrity",E),I&&p.emit("verified",I)});return p}IA.exports.create=Fvt;function Fvt(t){t=ia(t);let e=t.algorithms,r=t.options.length?`?${t.options.join("?")}`:"",o=e.map(kv.createHash);return{update:function(a,n){return o.forEach(u=>u.update(a,n)),this},digest:function(a){return e.reduce((u,A)=>{let p=o.shift().digest("base64"),h=new U0(`${A}-${p}${r}`,t);if(h.algorithm&&h.digest){let E=h.algorithm;u[E]||(u[E]=[]),u[E].push(h)}return u},new vm)}}}var Tvt=new Set(kv.getHashes()),dBe=["md5","whirlpool","sha1","sha224","sha256","sha384","sha512","sha3","sha3-256","sha3-384","sha3-512","sha3_256","sha3_384","sha3_512"].filter(t=>Tvt.has(t));function Rvt(t,e){return dBe.indexOf(t.toLowerCase())>=dBe.indexOf(e.toLowerCase())?t:e}});var VBe=_((lir,WBe)=>{var TDt=uL();function RDt(t){return TDt(t)?void 0:t}WBe.exports=RDt});var JBe=_((cir,KBe)=>{var NDt=jx(),LDt=Q8(),MDt=N8(),ODt=jd(),UDt=gd(),_Dt=VBe(),HDt=P_(),jDt=k8(),qDt=1,GDt=2,YDt=4,WDt=HDt(function(t,e){var r={};if(t==null)return r;var o=!1;e=NDt(e,function(n){return n=ODt(n,t),o||(o=n.length>1),n}),UDt(t,jDt(t),r),o&&(r=LDt(r,qDt|GDt|YDt,_Dt));for(var a=e.length;a--;)MDt(r,e[a]);return r});KBe.exports=WDt});Pt();Ye();Pt();var eve=Be("child_process"),tve=$e(ed());qt();var uC=new Map([]);var o2={};Kt(o2,{BaseCommand:()=>ut,WorkspaceRequiredError:()=>rr,getCli:()=>the,getDynamicLibs:()=>ehe,getPluginConfiguration:()=>fC,openWorkspace:()=>AC,pluginCommands:()=>uC,runExit:()=>sk});qt();var ut=class extends nt{constructor(){super(...arguments);this.cwd=ge.String("--cwd",{hidden:!0})}validateAndExecute(){if(typeof this.cwd<"u")throw new it("The --cwd option is ambiguous when used anywhere else than the very first parameter provided in the command line, before even the command path");return super.validateAndExecute()}};Ye();Pt();qt();var rr=class extends it{constructor(e,r){let o=K.relative(e,r),a=K.join(e,Mt.fileName);super(`This command can only be run from within a workspace of your project (${o} isn't a workspace of ${a}).`)}};Ye();Pt();nA();Nl();b1();qt();var OAt=$e(zn());Za();var ehe=()=>new Map([["@yarnpkg/cli",o2],["@yarnpkg/core",s2],["@yarnpkg/fslib",Vw],["@yarnpkg/libzip",x1],["@yarnpkg/parsers",tI],["@yarnpkg/shell",T1],["clipanion",pI],["semver",OAt],["typanion",Ko]]);Ye();async function AC(t,e){let{project:r,workspace:o}=await St.find(t,e);if(!o)throw new rr(r.cwd,e);return o}Ye();Pt();nA();Nl();b1();qt();var tPt=$e(zn());Za();var tH={};Kt(tH,{AddCommand:()=>bh,BinCommand:()=>kh,CacheCleanCommand:()=>Qh,ClipanionCommand:()=>Wd,ConfigCommand:()=>Nh,ConfigGetCommand:()=>Fh,ConfigSetCommand:()=>Th,ConfigUnsetCommand:()=>Rh,DedupeCommand:()=>Lh,EntryCommand:()=>dC,ExecCommand:()=>Mh,ExplainCommand:()=>_h,ExplainPeerRequirementsCommand:()=>Oh,HelpCommand:()=>Vd,InfoCommand:()=>Hh,LinkCommand:()=>qh,NodeCommand:()=>Gh,PluginCheckCommand:()=>Yh,PluginImportCommand:()=>Kh,PluginImportSourcesCommand:()=>Jh,PluginListCommand:()=>Wh,PluginRemoveCommand:()=>zh,PluginRuntimeCommand:()=>Xh,RebuildCommand:()=>Zh,RemoveCommand:()=>$h,RunCommand:()=>e0,RunIndexCommand:()=>zd,SetResolutionCommand:()=>t0,SetVersionCommand:()=>Uh,SetVersionSourcesCommand:()=>Vh,UnlinkCommand:()=>r0,UpCommand:()=>Kf,VersionCommand:()=>Kd,WhyCommand:()=>n0,WorkspaceCommand:()=>o0,WorkspacesListCommand:()=>s0,YarnCommand:()=>jh,dedupeUtils:()=>gk,default:()=>Qgt,suggestUtils:()=>zc});var Tde=$e(ed());Ye();Ye();Ye();qt();var j0e=$e(A2());Za();var zc={};Kt(zc,{Modifier:()=>D8,Strategy:()=>fk,Target:()=>f2,WorkspaceModifier:()=>M0e,applyModifier:()=>ipt,extractDescriptorFromPath:()=>P8,extractRangeModifier:()=>O0e,fetchDescriptorFrom:()=>S8,findProjectDescriptors:()=>H0e,getModifier:()=>p2,getSuggestedDescriptors:()=>h2,makeWorkspaceDescriptor:()=>_0e,toWorkspaceModifier:()=>U0e});Ye();Ye();Pt();var v8=$e(zn()),rpt="workspace:",f2=(o=>(o.REGULAR="dependencies",o.DEVELOPMENT="devDependencies",o.PEER="peerDependencies",o))(f2||{}),D8=(o=>(o.CARET="^",o.TILDE="~",o.EXACT="",o))(D8||{}),M0e=(o=>(o.CARET="^",o.TILDE="~",o.EXACT="*",o))(M0e||{}),fk=(n=>(n.KEEP="keep",n.REUSE="reuse",n.PROJECT="project",n.LATEST="latest",n.CACHE="cache",n))(fk||{});function p2(t,e){return t.exact?"":t.caret?"^":t.tilde?"~":e.configuration.get("defaultSemverRangePrefix")}var npt=/^([\^~]?)[0-9]+(?:\.[0-9]+){0,2}(?:-\S+)?$/;function O0e(t,{project:e}){let r=t.match(npt);return r?r[1]:e.configuration.get("defaultSemverRangePrefix")}function ipt(t,e){let{protocol:r,source:o,params:a,selector:n}=W.parseRange(t.range);return v8.default.valid(n)&&(n=`${e}${t.range}`),W.makeDescriptor(t,W.makeRange({protocol:r,source:o,params:a,selector:n}))}function U0e(t){switch(t){case"^":return"^";case"~":return"~";case"":return"*";default:throw new Error(`Assertion failed: Unknown modifier: "${t}"`)}}function _0e(t,e){return W.makeDescriptor(t.anchoredDescriptor,`${rpt}${U0e(e)}`)}async function H0e(t,{project:e,target:r}){let o=new Map,a=n=>{let u=o.get(n.descriptorHash);return u||o.set(n.descriptorHash,u={descriptor:n,locators:[]}),u};for(let n of e.workspaces)if(r==="peerDependencies"){let u=n.manifest.peerDependencies.get(t.identHash);u!==void 0&&a(u).locators.push(n.anchoredLocator)}else{let u=n.manifest.dependencies.get(t.identHash),A=n.manifest.devDependencies.get(t.identHash);r==="devDependencies"?A!==void 0?a(A).locators.push(n.anchoredLocator):u!==void 0&&a(u).locators.push(n.anchoredLocator):u!==void 0?a(u).locators.push(n.anchoredLocator):A!==void 0&&a(A).locators.push(n.anchoredLocator)}return o}async function P8(t,{cwd:e,workspace:r}){return await spt(async o=>{K.isAbsolute(t)||(t=K.relative(r.cwd,K.resolve(e,t)),t.match(/^\.{0,2}\//)||(t=`./${t}`));let{project:a}=r,n=await S8(W.makeIdent(null,"archive"),t,{project:r.project,cache:o,workspace:r});if(!n)throw new Error("Assertion failed: The descriptor should have been found");let u=new Qi,A=a.configuration.makeResolver(),p=a.configuration.makeFetcher(),h={checksums:a.storedChecksums,project:a,cache:o,fetcher:p,report:u,resolver:A},E=A.bindDescriptor(n,r.anchoredLocator,h),I=W.convertDescriptorToLocator(E),v=await p.fetch(I,h),b=await Mt.find(v.prefixPath,{baseFs:v.packageFs});if(!b.name)throw new Error("Target path doesn't have a name");return W.makeDescriptor(b.name,t)})}async function h2(t,{project:e,workspace:r,cache:o,target:a,fixed:n,modifier:u,strategies:A,maxResults:p=1/0}){if(!(p>=0))throw new Error(`Invalid maxResults (${p})`);let[h,E]=t.range!=="unknown"?n||kr.validRange(t.range)||!t.range.match(/^[a-z0-9._-]+$/i)?[t.range,"latest"]:["unknown",t.range]:["unknown","latest"];if(h!=="unknown")return{suggestions:[{descriptor:t,name:`Use ${W.prettyDescriptor(e.configuration,t)}`,reason:"(unambiguous explicit request)"}],rejections:[]};let I=typeof r<"u"&&r!==null&&r.manifest[a].get(t.identHash)||null,v=[],b=[],C=async T=>{try{await T()}catch(L){b.push(L)}};for(let T of A){if(v.length>=p)break;switch(T){case"keep":await C(async()=>{I&&v.push({descriptor:I,name:`Keep ${W.prettyDescriptor(e.configuration,I)}`,reason:"(no changes)"})});break;case"reuse":await C(async()=>{for(let{descriptor:L,locators:U}of(await H0e(t,{project:e,target:a})).values()){if(U.length===1&&U[0].locatorHash===r.anchoredLocator.locatorHash&&A.includes("keep"))continue;let J=`(originally used by ${W.prettyLocator(e.configuration,U[0])}`;J+=U.length>1?` and ${U.length-1} other${U.length>2?"s":""})`:")",v.push({descriptor:L,name:`Reuse ${W.prettyDescriptor(e.configuration,L)}`,reason:J})}});break;case"cache":await C(async()=>{for(let L of e.storedDescriptors.values())L.identHash===t.identHash&&v.push({descriptor:L,name:`Reuse ${W.prettyDescriptor(e.configuration,L)}`,reason:"(already used somewhere in the lockfile)"})});break;case"project":await C(async()=>{if(r.manifest.name!==null&&t.identHash===r.manifest.name.identHash)return;let L=e.tryWorkspaceByIdent(t);if(L===null)return;let U=_0e(L,u);v.push({descriptor:U,name:`Attach ${W.prettyDescriptor(e.configuration,U)}`,reason:`(local workspace at ${de.pretty(e.configuration,L.relativeCwd,de.Type.PATH)})`})});break;case"latest":{let L=e.configuration.get("enableNetwork"),U=e.configuration.get("enableOfflineMode");await C(async()=>{if(a==="peerDependencies")v.push({descriptor:W.makeDescriptor(t,"*"),name:"Use *",reason:"(catch-all peer dependency pattern)"});else if(!L&&!U)v.push({descriptor:null,name:"Resolve from latest",reason:de.pretty(e.configuration,"(unavailable because enableNetwork is toggled off)","grey")});else{let J=await S8(t,E,{project:e,cache:o,workspace:r,modifier:u});J&&v.push({descriptor:J,name:`Use ${W.prettyDescriptor(e.configuration,J)}`,reason:`(resolved from ${U?"the cache":"latest"})`})}})}break}}return{suggestions:v.slice(0,p),rejections:b.slice(0,p)}}async function S8(t,e,{project:r,cache:o,workspace:a,preserveModifier:n=!0,modifier:u}){let A=r.configuration.normalizeDependency(W.makeDescriptor(t,e)),p=new Qi,h=r.configuration.makeFetcher(),E=r.configuration.makeResolver(),I={project:r,fetcher:h,cache:o,checksums:r.storedChecksums,report:p,cacheOptions:{skipIntegrityCheck:!0}},v={...I,resolver:E,fetchOptions:I},b=E.bindDescriptor(A,a.anchoredLocator,v),C=await E.getCandidates(b,{},v);if(C.length===0)return null;let T=C[0],{protocol:L,source:U,params:J,selector:te}=W.parseRange(W.convertToManifestRange(T.reference));if(L===r.configuration.get("defaultProtocol")&&(L=null),v8.default.valid(te)){let le=te;if(typeof u<"u")te=u+te;else if(n!==!1){let ye=typeof n=="string"?n:A.range;te=O0e(ye,{project:r})+te}let pe=W.makeDescriptor(T,W.makeRange({protocol:L,source:U,params:J,selector:te}));(await E.getCandidates(r.configuration.normalizeDependency(pe),{},v)).length!==1&&(te=le)}return W.makeDescriptor(T,W.makeRange({protocol:L,source:U,params:J,selector:te}))}async function spt(t){return await oe.mktempPromise(async e=>{let r=Ve.create(e);return r.useWithSource(e,{enableMirror:!1,compressionLevel:0},e,{overwrite:!0}),await t(new Lr(e,{configuration:r,check:!1,immutable:!1}))})}var bh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.fixed=ge.Boolean("-F,--fixed",!1,{description:"Store dependency tags as-is instead of resolving them"});this.exact=ge.Boolean("-E,--exact",!1,{description:"Don't use any semver modifier on the resolved range"});this.tilde=ge.Boolean("-T,--tilde",!1,{description:"Use the `~` semver modifier on the resolved range"});this.caret=ge.Boolean("-C,--caret",!1,{description:"Use the `^` semver modifier on the resolved range"});this.dev=ge.Boolean("-D,--dev",!1,{description:"Add a package as a dev dependency"});this.peer=ge.Boolean("-P,--peer",!1,{description:"Add a package as a peer dependency"});this.optional=ge.Boolean("-O,--optional",!1,{description:"Add / upgrade a package to an optional regular / peer dependency"});this.preferDev=ge.Boolean("--prefer-dev",!1,{description:"Add / upgrade a package to a dev dependency"});this.interactive=ge.Boolean("-i,--interactive",{description:"Reuse the specified package from other workspaces in the project"});this.cached=ge.Boolean("--cached",!1,{description:"Reuse the highest version already used somewhere within the project"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:Vs(pl)});this.silent=ge.Boolean("--silent",{hidden:!0});this.packages=ge.Rest()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=this.fixed,A=this.interactive??r.get("preferInteractive"),p=A||r.get("preferReuse"),h=p2(this,o),E=[p?"reuse":void 0,"project",this.cached?"cache":void 0,"latest"].filter(U=>typeof U<"u"),I=A?1/0:1,v=await Promise.all(this.packages.map(async U=>{let J=U.match(/^\.{0,2}\//)?await P8(U,{cwd:this.context.cwd,workspace:a}):W.tryParseDescriptor(U),te=U.match(/^(https?:|git@github)/);if(te)throw new it(`It seems you are trying to add a package using a ${de.pretty(r,`${te[0]}...`,de.Type.RANGE)} url; we now require package names to be explicitly specified. -Try running the command again with the package name prefixed: ${de.pretty(r,"yarn add",de.Type.CODE)} ${de.pretty(r,W.makeDescriptor(W.makeIdent(null,"my-package"),`${te[0]}...`),de.Type.DESCRIPTOR)}`);if(!J)throw new it(`The ${de.pretty(r,U,de.Type.CODE)} string didn't match the required format (package-name@range). Did you perhaps forget to explicitly reference the package name?`);let le=opt(a,J,{dev:this.dev,peer:this.peer,preferDev:this.preferDev,optional:this.optional});return await Promise.all(le.map(async Ae=>{let ye=await h2(J,{project:o,workspace:a,cache:n,fixed:u,target:Ae,modifier:h,strategies:E,maxResults:I});return{request:J,suggestedDescriptors:ye,target:Ae}}))})).then(U=>U.flat()),b=await AA.start({configuration:r,stdout:this.context.stdout,suggestInstall:!1},async U=>{for(let{request:J,suggestedDescriptors:{suggestions:te,rejections:le}}of v)if(te.filter(Ae=>Ae.descriptor!==null).length===0){let[Ae]=le;if(typeof Ae>"u")throw new Error("Assertion failed: Expected an error to have been set");o.configuration.get("enableNetwork")?U.reportError(27,`${W.prettyDescriptor(r,J)} can't be resolved to a satisfying range`):U.reportError(27,`${W.prettyDescriptor(r,J)} can't be resolved to a satisfying range (note: network resolution has been disabled)`),U.reportSeparator(),U.reportExceptionOnce(Ae)}});if(b.hasErrors())return b.exitCode();let C=!1,T=[],L=[];for(let{suggestedDescriptors:{suggestions:U},target:J}of v){let te,le=U.filter(ae=>ae.descriptor!==null),pe=le[0].descriptor,Ae=le.every(ae=>W.areDescriptorsEqual(ae.descriptor,pe));le.length===1||Ae?te=pe:(C=!0,{answer:te}=await(0,j0e.prompt)({type:"select",name:"answer",message:"Which range do you want to use?",choices:U.map(({descriptor:ae,name:we,reason:Pe})=>ae?{name:we,hint:Pe,descriptor:ae}:{name:we,hint:Pe,disabled:!0}),onCancel:()=>process.exit(130),result(ae){return this.find(ae,"descriptor")},stdin:this.context.stdin,stdout:this.context.stdout}));let ye=a.manifest[J].get(te.identHash);(typeof ye>"u"||ye.descriptorHash!==te.descriptorHash)&&(a.manifest[J].set(te.identHash,te),this.optional&&(J==="dependencies"?a.manifest.ensureDependencyMeta({...te,range:"unknown"}).optional=!0:J==="peerDependencies"&&(a.manifest.ensurePeerDependencyMeta({...te,range:"unknown"}).optional=!0)),typeof ye>"u"?T.push([a,J,te,E]):L.push([a,J,ye,te]))}return await r.triggerMultipleHooks(U=>U.afterWorkspaceDependencyAddition,T),await r.triggerMultipleHooks(U=>U.afterWorkspaceDependencyReplacement,L),C&&this.context.stdout.write(` -`),await o.installWithNewReport({json:this.json,stdout:this.context.stdout,quiet:this.context.quiet},{cache:n,mode:this.mode})}};bh.paths=[["add"]],bh.usage=nt.Usage({description:"add dependencies to the project",details:"\n This command adds a package to the package.json for the nearest workspace.\n\n - If it didn't exist before, the package will by default be added to the regular `dependencies` field, but this behavior can be overriden thanks to the `-D,--dev` flag (which will cause the dependency to be added to the `devDependencies` field instead) and the `-P,--peer` flag (which will do the same but for `peerDependencies`).\n\n - If the package was already listed in your dependencies, it will by default be upgraded whether it's part of your `dependencies` or `devDependencies` (it won't ever update `peerDependencies`, though).\n\n - If set, the `--prefer-dev` flag will operate as a more flexible `-D,--dev` in that it will add the package to your `devDependencies` if it isn't already listed in either `dependencies` or `devDependencies`, but it will also happily upgrade your `dependencies` if that's what you already use (whereas `-D,--dev` would throw an exception).\n\n - If set, the `-O,--optional` flag will add the package to the `optionalDependencies` field and, in combination with the `-P,--peer` flag, it will add the package as an optional peer dependency. If the package was already listed in your `dependencies`, it will be upgraded to `optionalDependencies`. If the package was already listed in your `peerDependencies`, in combination with the `-P,--peer` flag, it will be upgraded to an optional peer dependency: `\"peerDependenciesMeta\": { \"\": { \"optional\": true } }`\n\n - If the added package doesn't specify a range at all its `latest` tag will be resolved and the returned version will be used to generate a new semver range (using the `^` modifier by default unless otherwise configured via the `defaultSemverRangePrefix` configuration, or the `~` modifier if `-T,--tilde` is specified, or no modifier at all if `-E,--exact` is specified). Two exceptions to this rule: the first one is that if the package is a workspace then its local version will be used, and the second one is that if you use `-P,--peer` the default range will be `*` and won't be resolved at all.\n\n - If the added package specifies a range (such as `^1.0.0`, `latest`, or `rc`), Yarn will add this range as-is in the resulting package.json entry (in particular, tags such as `rc` will be encoded as-is rather than being converted into a semver range).\n\n If the `--cached` option is used, Yarn will preferably reuse the highest version already used somewhere within the project, even if through a transitive dependency.\n\n If the `-i,--interactive` option is used (or if the `preferInteractive` settings is toggled on) the command will first try to check whether other workspaces in the project use the specified package and, if so, will offer to reuse them.\n\n If the `--mode=` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\n\n - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\n\n - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\n\n For a compilation of all the supported protocols, please consult the dedicated page from our website: https://yarnpkg.com/protocols.\n ",examples:[["Add a regular package to the current workspace","$0 add lodash"],["Add a specific version for a package to the current workspace","$0 add lodash@1.2.3"],["Add a package from a GitHub repository (the master branch) to the current workspace using a URL","$0 add lodash@https://github.com/lodash/lodash"],["Add a package from a GitHub repository (the master branch) to the current workspace using the GitHub protocol","$0 add lodash@github:lodash/lodash"],["Add a package from a GitHub repository (the master branch) to the current workspace using the GitHub protocol (shorthand)","$0 add lodash@lodash/lodash"],["Add a package from a specific branch of a GitHub repository to the current workspace using the GitHub protocol (shorthand)","$0 add lodash-es@lodash/lodash#es"]]});function opt(t,e,{dev:r,peer:o,preferDev:a,optional:n}){let u=t.manifest["dependencies"].has(e.identHash),A=t.manifest["devDependencies"].has(e.identHash),p=t.manifest["peerDependencies"].has(e.identHash);if((r||o)&&u)throw new it(`Package "${W.prettyIdent(t.project.configuration,e)}" is already listed as a regular dependency - remove the -D,-P flags or remove it from your dependencies first`);if(!r&&!o&&p)throw new it(`Package "${W.prettyIdent(t.project.configuration,e)}" is already listed as a peer dependency - use either of -D or -P, or remove it from your peer dependencies first`);if(n&&A)throw new it(`Package "${W.prettyIdent(t.project.configuration,e)}" is already listed as a dev dependency - remove the -O flag or remove it from your dev dependencies first`);if(n&&!o&&p)throw new it(`Package "${W.prettyIdent(t.project.configuration,e)}" is already listed as a peer dependency - remove the -O flag or add the -P flag or remove it from your peer dependencies first`);if((r||a)&&n)throw new it(`Package "${W.prettyIdent(t.project.configuration,e)}" cannot simultaneously be a dev dependency and an optional dependency`);let h=[];return o&&h.push("peerDependencies"),(r||a)&&h.push("devDependencies"),n&&h.push("dependencies"),h.length>0?h:A?["devDependencies"]:p?["peerDependencies"]:["dependencies"]}Ye();Ye();qt();var kh=class extends ut{constructor(){super(...arguments);this.verbose=ge.Boolean("-v,--verbose",!1,{description:"Print both the binary name and the locator of the package that provides the binary"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.name=ge.String({required:!1})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,locator:a}=await St.find(r,this.context.cwd);if(await o.restoreInstallState(),this.name){let A=(await un.getPackageAccessibleBinaries(a,{project:o})).get(this.name);if(!A)throw new it(`Couldn't find a binary named "${this.name}" for package "${W.prettyLocator(r,a)}"`);let[,p]=A;return this.context.stdout.write(`${p} -`),0}return(await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout},async u=>{let A=await un.getPackageAccessibleBinaries(a,{project:o}),h=Array.from(A.keys()).reduce((E,I)=>Math.max(E,I.length),0);for(let[E,[I,v]]of A)u.reportJson({name:E,source:W.stringifyIdent(I),path:v});if(this.verbose)for(let[E,[I]]of A)u.reportInfo(null,`${E.padEnd(h," ")} ${W.prettyLocator(r,I)}`);else for(let E of A.keys())u.reportInfo(null,E)})).exitCode()}};kh.paths=[["bin"]],kh.usage=nt.Usage({description:"get the path to a binary script",details:` - When used without arguments, this command will print the list of all the binaries available in the current workspace. Adding the \`-v,--verbose\` flag will cause the output to contain both the binary name and the locator of the package that provides the binary. - - When an argument is specified, this command will just print the path to the binary on the standard output and exit. Note that the reported path may be stored within a zip archive. - `,examples:[["List all the available binaries","$0 bin"],["Print the path to a specific binary","$0 bin eslint"]]});Ye();Pt();qt();var Qh=class extends ut{constructor(){super(...arguments);this.mirror=ge.Boolean("--mirror",!1,{description:"Remove the global cache files instead of the local cache files"});this.all=ge.Boolean("--all",!1,{description:"Remove both the global cache files and the local cache files of the current project"})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),o=await Lr.find(r);return(await Nt.start({configuration:r,stdout:this.context.stdout},async()=>{let n=(this.all||this.mirror)&&o.mirrorCwd!==null,u=!this.mirror;n&&(await oe.removePromise(o.mirrorCwd),await r.triggerHook(A=>A.cleanGlobalArtifacts,r)),u&&await oe.removePromise(o.cwd)})).exitCode()}};Qh.paths=[["cache","clean"],["cache","clear"]],Qh.usage=nt.Usage({description:"remove the shared cache files",details:` - This command will remove all the files from the cache. - `,examples:[["Remove all the local archives","$0 cache clean"],["Remove all the archives stored in the ~/.yarn directory","$0 cache clean --mirror"]]});Ye();qt();var G0e=$e(g2()),x8=Be("util"),Fh=class extends ut{constructor(){super(...arguments);this.why=ge.Boolean("--why",!1,{description:"Print the explanation for why a setting has its value"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.unsafe=ge.Boolean("--no-redacted",!1,{description:"Don't redact secrets (such as tokens) from the output"});this.name=ge.String()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),o=this.name.replace(/[.[].*$/,""),a=this.name.replace(/^[^.[]*/,"");if(typeof r.settings.get(o)>"u")throw new it(`Couldn't find a configuration settings named "${o}"`);let u=r.getSpecial(o,{hideSecrets:!this.unsafe,getNativePaths:!0}),A=je.convertMapsToIndexableObjects(u),p=a?(0,G0e.default)(A,a):A,h=await Nt.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async E=>{E.reportJson(p)});if(!this.json){if(typeof p=="string")return this.context.stdout.write(`${p} -`),h.exitCode();x8.inspect.styles.name="cyan",this.context.stdout.write(`${(0,x8.inspect)(p,{depth:1/0,colors:r.get("enableColors"),compact:!1})} -`)}return h.exitCode()}};Fh.paths=[["config","get"]],Fh.usage=nt.Usage({description:"read a configuration settings",details:` - This command will print a configuration setting. - - Secrets (such as tokens) will be redacted from the output by default. If this behavior isn't desired, set the \`--no-redacted\` to get the untransformed value. - `,examples:[["Print a simple configuration setting","yarn config get yarnPath"],["Print a complex configuration setting","yarn config get packageExtensions"],["Print a nested field from the configuration",`yarn config get 'npmScopes["my-company"].npmRegistryServer'`],["Print a token from the configuration","yarn config get npmAuthToken --no-redacted"],["Print a configuration setting as JSON","yarn config get packageExtensions --json"]]});Ye();qt();var Rge=$e(F8()),Nge=$e(g2()),Lge=$e(T8()),R8=Be("util"),Th=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Set complex configuration settings to JSON values"});this.home=ge.Boolean("-H,--home",!1,{description:"Update the home configuration instead of the project configuration"});this.name=ge.String();this.value=ge.String()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),o=()=>{if(!r.projectCwd)throw new it("This command must be run from within a project folder");return r.projectCwd},a=this.name.replace(/[.[].*$/,""),n=this.name.replace(/^[^.[]*\.?/,"");if(typeof r.settings.get(a)>"u")throw new it(`Couldn't find a configuration settings named "${a}"`);if(a==="enableStrictSettings")throw new it("This setting only affects the file it's in, and thus cannot be set from the CLI");let A=this.json?JSON.parse(this.value):this.value;await(this.home?C=>Ve.updateHomeConfiguration(C):C=>Ve.updateConfiguration(o(),C))(C=>{if(n){let T=(0,Rge.default)(C);return(0,Lge.default)(T,this.name,A),T}else return{...C,[a]:A}});let E=(await Ve.find(this.context.cwd,this.context.plugins)).getSpecial(a,{hideSecrets:!0,getNativePaths:!0}),I=je.convertMapsToIndexableObjects(E),v=n?(0,Nge.default)(I,n):I;return(await Nt.start({configuration:r,includeFooter:!1,stdout:this.context.stdout},async C=>{R8.inspect.styles.name="cyan",C.reportInfo(0,`Successfully set ${this.name} to ${(0,R8.inspect)(v,{depth:1/0,colors:r.get("enableColors"),compact:!1})}`)})).exitCode()}};Th.paths=[["config","set"]],Th.usage=nt.Usage({description:"change a configuration settings",details:` - This command will set a configuration setting. - - When used without the \`--json\` flag, it can only set a simple configuration setting (a string, a number, or a boolean). - - When used with the \`--json\` flag, it can set both simple and complex configuration settings, including Arrays and Objects. - `,examples:[["Set a simple configuration setting (a string, a number, or a boolean)","yarn config set initScope myScope"],["Set a simple configuration setting (a string, a number, or a boolean) using the `--json` flag",'yarn config set initScope --json \\"myScope\\"'],["Set a complex configuration setting (an Array) using the `--json` flag",`yarn config set unsafeHttpWhitelist --json '["*.example.com", "example.com"]'`],["Set a complex configuration setting (an Object) using the `--json` flag",`yarn config set packageExtensions --json '{ "@babel/parser@*": { "dependencies": { "@babel/types": "*" } } }'`],["Set a nested configuration setting",'yarn config set npmScopes.company.npmRegistryServer "https://npm.example.com"'],["Set a nested configuration setting using indexed access for non-simple keys",`yarn config set 'npmRegistries["//npm.example.com"].npmAuthToken' "ffffffff-ffff-ffff-ffff-ffffffffffff"`]]});Ye();qt();var Vge=$e(F8()),Kge=$e(_ge()),Jge=$e(L8()),Rh=class extends ut{constructor(){super(...arguments);this.home=ge.Boolean("-H,--home",!1,{description:"Update the home configuration instead of the project configuration"});this.name=ge.String()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),o=()=>{if(!r.projectCwd)throw new it("This command must be run from within a project folder");return r.projectCwd},a=this.name.replace(/[.[].*$/,""),n=this.name.replace(/^[^.[]*\.?/,"");if(typeof r.settings.get(a)>"u")throw new it(`Couldn't find a configuration settings named "${a}"`);let A=this.home?h=>Ve.updateHomeConfiguration(h):h=>Ve.updateConfiguration(o(),h);return(await Nt.start({configuration:r,includeFooter:!1,stdout:this.context.stdout},async h=>{let E=!1;await A(I=>{if(!(0,Kge.default)(I,this.name))return h.reportWarning(0,`Configuration doesn't contain setting ${this.name}; there is nothing to unset`),E=!0,I;let v=n?(0,Vge.default)(I):{...I};return(0,Jge.default)(v,this.name),v}),E||h.reportInfo(0,`Successfully unset ${this.name}`)})).exitCode()}};Rh.paths=[["config","unset"]],Rh.usage=nt.Usage({description:"unset a configuration setting",details:` - This command will unset a configuration setting. - `,examples:[["Unset a simple configuration setting","yarn config unset initScope"],["Unset a complex configuration setting","yarn config unset packageExtensions"],["Unset a nested configuration setting","yarn config unset npmScopes.company.npmRegistryServer"]]});Ye();Pt();qt();var hk=Be("util"),Nh=class extends ut{constructor(){super(...arguments);this.noDefaults=ge.Boolean("--no-defaults",!1,{description:"Omit the default values from the display"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.verbose=ge.Boolean("-v,--verbose",{hidden:!0});this.why=ge.Boolean("--why",{hidden:!0});this.names=ge.Rest()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins,{strict:!1}),o=await NE({configuration:r,stdout:this.context.stdout,forceError:this.json},[{option:this.verbose,message:"The --verbose option is deprecated, the settings' descriptions are now always displayed"},{option:this.why,message:"The --why option is deprecated, the settings' sources are now always displayed"}]);if(o!==null)return o;let a=this.names.length>0?[...new Set(this.names)].sort():[...r.settings.keys()].sort(),n,u=await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async A=>{if(r.invalid.size>0&&!this.json){for(let[p,h]of r.invalid)A.reportError(34,`Invalid configuration key "${p}" in ${h}`);A.reportSeparator()}if(this.json)for(let p of a){let h=r.settings.get(p);typeof h>"u"&&A.reportError(34,`No configuration key named "${p}"`);let E=r.getSpecial(p,{hideSecrets:!0,getNativePaths:!0}),I=r.sources.get(p)??"",v=I&&I[0]!=="<"?ue.fromPortablePath(I):I;A.reportJson({key:p,effective:E,source:v,...h})}else{let p={breakLength:1/0,colors:r.get("enableColors"),maxArrayLength:2},h={},E={children:h};for(let I of a){if(this.noDefaults&&!r.sources.has(I))continue;let v=r.settings.get(I),b=r.sources.get(I)??"",C=r.getSpecial(I,{hideSecrets:!0,getNativePaths:!0}),T={Description:{label:"Description",value:de.tuple(de.Type.MARKDOWN,{text:v.description,format:this.cli.format(),paragraphs:!1})},Source:{label:"Source",value:de.tuple(b[0]==="<"?de.Type.CODE:de.Type.PATH,b)}};h[I]={value:de.tuple(de.Type.CODE,I),children:T};let L=(U,J)=>{for(let[te,le]of J)if(le instanceof Map){let pe={};U[te]={children:pe},L(pe,le)}else U[te]={label:te,value:de.tuple(de.Type.NO_HINT,(0,hk.inspect)(le,p))}};C instanceof Map?L(T,C):T.Value={label:"Value",value:de.tuple(de.Type.NO_HINT,(0,hk.inspect)(C,p))}}a.length!==1&&(n=void 0),$s.emitTree(E,{configuration:r,json:this.json,stdout:this.context.stdout,separators:2})}});if(!this.json&&typeof n<"u"){let A=a[0],p=(0,hk.inspect)(r.getSpecial(A,{hideSecrets:!0,getNativePaths:!0}),{colors:r.get("enableColors")});this.context.stdout.write(` -`),this.context.stdout.write(`${p} -`)}return u.exitCode()}};Nh.paths=[["config"]],Nh.usage=nt.Usage({description:"display the current configuration",details:` - This command prints the current active configuration settings. - `,examples:[["Print the active configuration settings","$0 config"]]});Ye();qt();Za();var gk={};Kt(gk,{Strategy:()=>d2,acceptedStrategies:()=>j0t,dedupe:()=>M8});Ye();Ye();var zge=$e(Zo()),d2=(e=>(e.HIGHEST="highest",e))(d2||{}),j0t=new Set(Object.values(d2)),q0t={highest:async(t,e,{resolver:r,fetcher:o,resolveOptions:a,fetchOptions:n})=>{let u=new Map;for(let[p,h]of t.storedResolutions){let E=t.storedDescriptors.get(p);if(typeof E>"u")throw new Error(`Assertion failed: The descriptor (${p}) should have been registered`);je.getSetWithDefault(u,E.identHash).add(h)}let A=new Map(je.mapAndFilter(t.storedDescriptors.values(),p=>W.isVirtualDescriptor(p)?je.mapAndFilter.skip:[p.descriptorHash,je.makeDeferred()]));for(let p of t.storedDescriptors.values()){let h=A.get(p.descriptorHash);if(typeof h>"u")throw new Error(`Assertion failed: The descriptor (${p.descriptorHash}) should have been registered`);let E=t.storedResolutions.get(p.descriptorHash);if(typeof E>"u")throw new Error(`Assertion failed: The resolution (${p.descriptorHash}) should have been registered`);let I=t.originalPackages.get(E);if(typeof I>"u")throw new Error(`Assertion failed: The package (${E}) should have been registered`);Promise.resolve().then(async()=>{let v=r.getResolutionDependencies(p,a),b=Object.fromEntries(await je.allSettledSafe(Object.entries(v).map(async([te,le])=>{let pe=A.get(le.descriptorHash);if(typeof pe>"u")throw new Error(`Assertion failed: The descriptor (${le.descriptorHash}) should have been registered`);let Ae=await pe.promise;if(!Ae)throw new Error("Assertion failed: Expected the dependency to have been through the dedupe process itself");return[te,Ae.updatedPackage]})));if(e.length&&!zge.default.isMatch(W.stringifyIdent(p),e)||!r.shouldPersistResolution(I,a))return I;let C=u.get(p.identHash);if(typeof C>"u")throw new Error(`Assertion failed: The resolutions (${p.identHash}) should have been registered`);if(C.size===1)return I;let T=[...C].map(te=>{let le=t.originalPackages.get(te);if(typeof le>"u")throw new Error(`Assertion failed: The package (${te}) should have been registered`);return le}),L=await r.getSatisfying(p,b,T,a),U=L.locators?.[0];if(typeof U>"u"||!L.sorted)return I;let J=t.originalPackages.get(U.locatorHash);if(typeof J>"u")throw new Error(`Assertion failed: The package (${U.locatorHash}) should have been registered`);return J}).then(async v=>{let b=await t.preparePackage(v,{resolver:r,resolveOptions:a});h.resolve({descriptor:p,currentPackage:I,updatedPackage:v,resolvedPackage:b})}).catch(v=>{h.reject(v)})}return[...A.values()].map(p=>p.promise)}};async function M8(t,{strategy:e,patterns:r,cache:o,report:a}){let{configuration:n}=t,u=new Qi,A=n.makeResolver(),p=n.makeFetcher(),h={cache:o,checksums:t.storedChecksums,fetcher:p,project:t,report:u,cacheOptions:{skipIntegrityCheck:!0}},E={project:t,resolver:A,report:u,fetchOptions:h};return await a.startTimerPromise("Deduplication step",async()=>{let I=q0t[e],v=await I(t,r,{resolver:A,resolveOptions:E,fetcher:p,fetchOptions:h}),b=Xs.progressViaCounter(v.length);await a.reportProgress(b);let C=0;await Promise.all(v.map(U=>U.then(J=>{if(J===null||J.currentPackage.locatorHash===J.updatedPackage.locatorHash)return;C++;let{descriptor:te,currentPackage:le,updatedPackage:pe}=J;a.reportInfo(0,`${W.prettyDescriptor(n,te)} can be deduped from ${W.prettyLocator(n,le)} to ${W.prettyLocator(n,pe)}`),a.reportJson({descriptor:W.stringifyDescriptor(te),currentResolution:W.stringifyLocator(le),updatedResolution:W.stringifyLocator(pe)}),t.storedResolutions.set(te.descriptorHash,pe.locatorHash)}).finally(()=>b.tick())));let T;switch(C){case 0:T="No packages";break;case 1:T="One package";break;default:T=`${C} packages`}let L=de.pretty(n,e,de.Type.CODE);return a.reportInfo(0,`${T} can be deduped using the ${L} strategy`),C})}var Lh=class extends ut{constructor(){super(...arguments);this.strategy=ge.String("-s,--strategy","highest",{description:"The strategy to use when deduping dependencies",validator:Vs(d2)});this.check=ge.Boolean("-c,--check",!1,{description:"Exit with exit code 1 when duplicates are found, without persisting the dependency tree"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:Vs(pl)});this.patterns=ge.Rest()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd),a=await Lr.find(r);await o.restoreInstallState({restoreResolutions:!1});let n=0,u=await Nt.start({configuration:r,includeFooter:!1,stdout:this.context.stdout,json:this.json},async A=>{n=await M8(o,{strategy:this.strategy,patterns:this.patterns,cache:a,report:A})});return u.hasErrors()?u.exitCode():this.check?n?1:0:await o.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:a,mode:this.mode})}};Lh.paths=[["dedupe"]],Lh.usage=nt.Usage({description:"deduplicate dependencies with overlapping ranges",details:"\n Duplicates are defined as descriptors with overlapping ranges being resolved and locked to different locators. They are a natural consequence of Yarn's deterministic installs, but they can sometimes pile up and unnecessarily increase the size of your project.\n\n This command dedupes dependencies in the current project using different strategies (only one is implemented at the moment):\n\n - `highest`: Reuses (where possible) the locators with the highest versions. This means that dependencies can only be upgraded, never downgraded. It's also guaranteed that it never takes more than a single pass to dedupe the entire dependency tree.\n\n **Note:** Even though it never produces a wrong dependency tree, this command should be used with caution, as it modifies the dependency tree, which can sometimes cause problems when packages don't strictly follow semver recommendations. Because of this, it is recommended to also review the changes manually.\n\n If set, the `-c,--check` flag will only report the found duplicates, without persisting the modified dependency tree. If changes are found, the command will exit with a non-zero exit code, making it suitable for CI purposes.\n\n If the `--mode=` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\n\n - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\n\n - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\n\n This command accepts glob patterns as arguments (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\n\n ### In-depth explanation:\n\n Yarn doesn't deduplicate dependencies by default, otherwise installs wouldn't be deterministic and the lockfile would be useless. What it actually does is that it tries to not duplicate dependencies in the first place.\n\n **Example:** If `foo@^2.3.4` (a dependency of a dependency) has already been resolved to `foo@2.3.4`, running `yarn add foo@*`will cause Yarn to reuse `foo@2.3.4`, even if the latest `foo` is actually `foo@2.10.14`, thus preventing unnecessary duplication.\n\n Duplication happens when Yarn can't unlock dependencies that have already been locked inside the lockfile.\n\n **Example:** If `foo@^2.3.4` (a dependency of a dependency) has already been resolved to `foo@2.3.4`, running `yarn add foo@2.10.14` will cause Yarn to install `foo@2.10.14` because the existing resolution doesn't satisfy the range `2.10.14`. This behavior can lead to (sometimes) unwanted duplication, since now the lockfile contains 2 separate resolutions for the 2 `foo` descriptors, even though they have overlapping ranges, which means that the lockfile can be simplified so that both descriptors resolve to `foo@2.10.14`.\n ",examples:[["Dedupe all packages","$0 dedupe"],["Dedupe all packages using a specific strategy","$0 dedupe --strategy highest"],["Dedupe a specific package","$0 dedupe lodash"],["Dedupe all packages with the `@babel/*` scope","$0 dedupe '@babel/*'"],["Check for duplicates (can be used as a CI step)","$0 dedupe --check"]]});Ye();qt();var Wd=class extends ut{async execute(){let{plugins:e}=await Ve.find(this.context.cwd,this.context.plugins),r=[];for(let u of e){let{commands:A}=u[1];if(A){let h=as.from(A).definitions();r.push([u[0],h])}}let o=this.cli.definitions(),a=(u,A)=>u.split(" ").slice(1).join()===A.split(" ").slice(1).join(),n=Xge()["@yarnpkg/builder"].bundles.standard;for(let u of r){let A=u[1];for(let p of A)o.find(h=>a(h.path,p.path)).plugin={name:u[0],isDefault:n.includes(u[0])}}this.context.stdout.write(`${JSON.stringify(o,null,2)} -`)}};Wd.paths=[["--clipanion=definitions"]];var Vd=class extends ut{async execute(){this.context.stdout.write(this.cli.usage(null))}};Vd.paths=[["help"],["--help"],["-h"]];Ye();Pt();qt();var dC=class extends ut{constructor(){super(...arguments);this.leadingArgument=ge.String();this.args=ge.Proxy()}async execute(){if(this.leadingArgument.match(/[\\/]/)&&!W.tryParseIdent(this.leadingArgument)){let r=K.resolve(this.context.cwd,ue.toPortablePath(this.leadingArgument));return await this.cli.run(this.args,{cwd:r})}else return await this.cli.run(["run",this.leadingArgument,...this.args])}};Ye();var Kd=class extends ut{async execute(){this.context.stdout.write(`${tn||""} -`)}};Kd.paths=[["-v"],["--version"]];Ye();Ye();qt();var Mh=class extends ut{constructor(){super(...arguments);this.commandName=ge.String();this.args=ge.Proxy()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,locator:a}=await St.find(r,this.context.cwd);return await o.restoreInstallState(),await un.executePackageShellcode(a,this.commandName,this.args,{cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,project:o})}};Mh.paths=[["exec"]],Mh.usage=nt.Usage({description:"execute a shell script",details:` - This command simply executes a shell script within the context of the root directory of the active workspace using the portable shell. - - It also makes sure to call it in a way that's compatible with the current project (for example, on PnP projects the environment will be setup in such a way that PnP will be correctly injected into the environment). - `,examples:[["Execute a single shell command","$0 exec echo Hello World"],["Execute a shell script",'$0 exec "tsc & babel src --out-dir lib"']]});Ye();qt();Za();var Oh=class extends ut{constructor(){super(...arguments);this.hash=ge.String({validator:aP(Ey(),[sI(/^p[0-9a-f]{5}$/)])})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd);return await o.restoreInstallState({restoreResolutions:!1}),await o.applyLightResolution(),await Y0t(this.hash,o,{stdout:this.context.stdout})}};Oh.paths=[["explain","peer-requirements"]],Oh.usage=nt.Usage({description:"explain a set of peer requirements",details:` - A set of peer requirements represents all peer requirements that a dependent must satisfy when providing a given peer request to a requester and its descendants. - - When the hash argument is specified, this command prints a detailed explanation of all requirements of the set corresponding to the hash and whether they're satisfied or not. - - When used without arguments, this command lists all sets of peer requirements and the corresponding hash that can be used to get detailed information about a given set. - - **Note:** A hash is a six-letter p-prefixed code that can be obtained from peer dependency warnings or from the list of all peer requirements (\`yarn explain peer-requirements\`). - `,examples:[["Explain the corresponding set of peer requirements for a hash","$0 explain peer-requirements p1a4ed"],["List all sets of peer requirements","$0 explain peer-requirements"]]});async function Y0t(t,e,r){let o=e.peerWarnings.find(n=>n.hash===t);if(typeof o>"u")throw new Error(`No peerDependency requirements found for hash: "${t}"`);return(await Nt.start({configuration:e.configuration,stdout:r.stdout,includeFooter:!1,includePrefix:!1},async n=>{let u=de.mark(e.configuration);switch(o.type){case 2:{n.reportInfo(0,`We have a problem with ${de.pretty(e.configuration,o.requested,de.Type.IDENT)}, which is provided with version ${W.prettyReference(e.configuration,o.version)}.`),n.reportInfo(0,"It is needed by the following direct dependencies of workspaces in your project:"),n.reportSeparator();for(let h of o.requesters.values()){let E=e.storedPackages.get(h.locatorHash);if(!E)throw new Error("Assertion failed: Expected the package to be registered");let I=E?.peerDependencies.get(o.requested.identHash);if(!I)throw new Error("Assertion failed: Expected the package to list the peer dependency");let v=kr.satisfiesWithPrereleases(o.version,I.range)?u.Check:u.Cross;n.reportInfo(null,` ${v} ${W.prettyLocator(e.configuration,h)} (via ${W.prettyRange(e.configuration,I.range)})`)}let A=[...o.links.values()].filter(h=>!o.requesters.has(h.locatorHash));if(A.length>0){n.reportSeparator(),n.reportInfo(0,`However, those packages themselves have more dependencies listing ${W.prettyIdent(e.configuration,o.requested)} as peer dependency:`),n.reportSeparator();for(let h of A){let E=e.storedPackages.get(h.locatorHash);if(!E)throw new Error("Assertion failed: Expected the package to be registered");let I=E?.peerDependencies.get(o.requested.identHash);if(!I)throw new Error("Assertion failed: Expected the package to list the peer dependency");let v=kr.satisfiesWithPrereleases(o.version,I.range)?u.Check:u.Cross;n.reportInfo(null,` ${v} ${W.prettyLocator(e.configuration,h)} (via ${W.prettyRange(e.configuration,I.range)})`)}}let p=Array.from(o.links.values(),h=>{let E=e.storedPackages.get(h.locatorHash);if(typeof E>"u")throw new Error("Assertion failed: Expected the package to be registered");let I=E.peerDependencies.get(o.requested.identHash);if(typeof I>"u")throw new Error("Assertion failed: Expected the ident to be registered");return I.range});if(p.length>1){let h=kr.simplifyRanges(p);n.reportSeparator(),h===null?(n.reportInfo(0,"Unfortunately, put together, we found no single range that can satisfy all those peer requirements."),n.reportInfo(0,`Your best option may be to try to upgrade some dependencies with ${de.pretty(e.configuration,"yarn up",de.Type.CODE)}, or silence the warning via ${de.pretty(e.configuration,"logFilters",de.Type.CODE)}.`)):n.reportInfo(0,`Put together, the final range we computed is ${de.pretty(e.configuration,h,de.Type.RANGE)}`)}}break;default:n.reportInfo(0,`The ${de.pretty(e.configuration,"yarn explain peer-requirements",de.Type.CODE)} command doesn't support this warning type yet.`);break}})).exitCode()}Ye();qt();Za();Ye();Ye();Pt();qt();var Zge=$e(zn()),Uh=class extends ut{constructor(){super(...arguments);this.useYarnPath=ge.Boolean("--yarn-path",{description:"Set the yarnPath setting even if the version can be accessed by Corepack"});this.onlyIfNeeded=ge.Boolean("--only-if-needed",!1,{description:"Only lock the Yarn version if it isn't already locked"});this.version=ge.String()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins);if(this.onlyIfNeeded&&r.get("yarnPath")){let A=r.sources.get("yarnPath");if(!A)throw new Error("Assertion failed: Expected 'yarnPath' to have a source");let p=r.projectCwd??r.startingCwd;if(K.contains(p,A))return 0}let o=()=>{if(typeof tn>"u")throw new it("The --install flag can only be used without explicit version specifier from the Yarn CLI");return`file://${process.argv[1]}`},a,n=(A,p)=>({version:p,url:A.replace(/\{\}/g,p)});if(this.version==="self")a={url:o(),version:tn??"self"};else if(this.version==="latest"||this.version==="berry"||this.version==="stable")a=n("https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js",await m2(r,"stable"));else if(this.version==="canary")a=n("https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js",await m2(r,"canary"));else if(this.version==="classic")a={url:"https://classic.yarnpkg.com/latest.js",version:"classic"};else if(this.version.match(/^https?:/))a={url:this.version,version:"remote"};else if(this.version.match(/^\.{0,2}[\\/]/)||ue.isAbsolute(this.version))a={url:`file://${K.resolve(ue.toPortablePath(this.version))}`,version:"file"};else if(kr.satisfiesWithPrereleases(this.version,">=2.0.0"))a=n("https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js",this.version);else if(kr.satisfiesWithPrereleases(this.version,"^0.x || ^1.x"))a=n("https://github.com/yarnpkg/yarn/releases/download/v{}/yarn-{}.js",this.version);else if(kr.validRange(this.version))a=n("https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js",await W0t(r,this.version));else throw new it(`Invalid version descriptor "${this.version}"`);return(await Nt.start({configuration:r,stdout:this.context.stdout,includeLogs:!this.context.quiet},async A=>{let p=async()=>{let h="file://";return a.url.startsWith(h)?(A.reportInfo(0,`Retrieving ${de.pretty(r,a.url,de.Type.PATH)}`),await oe.readFilePromise(a.url.slice(h.length))):(A.reportInfo(0,`Downloading ${de.pretty(r,a.url,de.Type.URL)}`),await rn.get(a.url,{configuration:r}))};await O8(r,a.version,p,{report:A,useYarnPath:this.useYarnPath})})).exitCode()}};Uh.paths=[["set","version"]],Uh.usage=nt.Usage({description:"lock the Yarn version used by the project",details:"\n This command will set a specific release of Yarn to be used by Corepack: https://nodejs.org/api/corepack.html.\n\n By default it only will set the `packageManager` field at the root of your project, but if the referenced release cannot be represented this way, if you already have `yarnPath` configured, or if you set the `--yarn-path` command line flag, then the release will also be downloaded from the Yarn GitHub repository, stored inside your project, and referenced via the `yarnPath` settings from your project `.yarnrc.yml` file.\n\n A very good use case for this command is to enforce the version of Yarn used by any single member of your team inside the same project - by doing this you ensure that you have control over Yarn upgrades and downgrades (including on your deployment servers), and get rid of most of the headaches related to someone using a slightly different version and getting different behavior.\n\n The version specifier can be:\n\n - a tag:\n - `latest` / `berry` / `stable` -> the most recent stable berry (`>=2.0.0`) release\n - `canary` -> the most recent canary (release candidate) berry (`>=2.0.0`) release\n - `classic` -> the most recent classic (`^0.x || ^1.x`) release\n\n - a semver range (e.g. `2.x`) -> the most recent version satisfying the range (limited to berry releases)\n\n - a semver version (e.g. `2.4.1`, `1.22.1`)\n\n - a local file referenced through either a relative or absolute path\n\n - `self` -> the version used to invoke the command\n ",examples:[["Download the latest release from the Yarn repository","$0 set version latest"],["Download the latest canary release from the Yarn repository","$0 set version canary"],["Download the latest classic release from the Yarn repository","$0 set version classic"],["Download the most recent Yarn 3 build","$0 set version 3.x"],["Download a specific Yarn 2 build","$0 set version 2.0.0-rc.30"],["Switch back to a specific Yarn 1 release","$0 set version 1.22.1"],["Use a release from the local filesystem","$0 set version ./yarn.cjs"],["Use a release from a URL","$0 set version https://repo.yarnpkg.com/3.1.0/packages/yarnpkg-cli/bin/yarn.js"],["Download the version used to invoke the command","$0 set version self"]]});async function W0t(t,e){let o=(await rn.get("https://repo.yarnpkg.com/tags",{configuration:t,jsonResponse:!0})).tags.filter(a=>kr.satisfiesWithPrereleases(a,e));if(o.length===0)throw new it(`No matching release found for range ${de.pretty(t,e,de.Type.RANGE)}.`);return o[0]}async function m2(t,e){let r=await rn.get("https://repo.yarnpkg.com/tags",{configuration:t,jsonResponse:!0});if(!r.latest[e])throw new it(`Tag ${de.pretty(t,e,de.Type.RANGE)} not found`);return r.latest[e]}async function O8(t,e,r,{report:o,useYarnPath:a}){let n,u=async()=>(typeof n>"u"&&(n=await r()),n);if(e===null){let te=await u();await oe.mktempPromise(async le=>{let pe=K.join(le,"yarn.cjs");await oe.writeFilePromise(pe,te);let{stdout:Ae}=await Ur.execvp(process.execPath,[ue.fromPortablePath(pe),"--version"],{cwd:le,env:{...t.env,YARN_IGNORE_PATH:"1"}});if(e=Ae.trim(),!Zge.default.valid(e))throw new Error(`Invalid semver version. ${de.pretty(t,"yarn --version",de.Type.CODE)} returned: -${e}`)})}let A=t.projectCwd??t.startingCwd,p=K.resolve(A,".yarn/releases"),h=K.resolve(p,`yarn-${e}.cjs`),E=K.relative(t.startingCwd,h),I=je.isTaggedYarnVersion(e),v=t.get("yarnPath"),b=!I,C=b||!!v||!!a;if(a===!1){if(b)throw new zt(0,"You explicitly opted out of yarnPath usage in your command line, but the version you specified cannot be represented by Corepack");C=!1}else!C&&!process.env.COREPACK_ROOT&&(o.reportWarning(0,`You don't seem to have ${de.applyHyperlink(t,"Corepack","https://nodejs.org/api/corepack.html")} enabled; we'll have to rely on ${de.applyHyperlink(t,"yarnPath","https://yarnpkg.com/configuration/yarnrc#yarnPath")} instead`),C=!0);if(C){let te=await u();o.reportInfo(0,`Saving the new release in ${de.pretty(t,E,"magenta")}`),await oe.removePromise(K.dirname(h)),await oe.mkdirPromise(K.dirname(h),{recursive:!0}),await oe.writeFilePromise(h,te,{mode:493}),await Ve.updateConfiguration(A,{yarnPath:K.relative(A,h)})}else await oe.removePromise(K.dirname(h)),await Ve.updateConfiguration(A,{yarnPath:Ve.deleteProperty});let T=await Mt.tryFind(A)||new Mt;T.packageManager=`yarn@${I?e:await m2(t,"stable")}`;let L={};T.exportTo(L);let U=K.join(A,Mt.fileName),J=`${JSON.stringify(L,null,T.indent)} -`;return await oe.changeFilePromise(U,J,{automaticNewlines:!0}),{bundleVersion:e}}function $ge(t){return wr[fP(t)]}var V0t=/## (?YN[0-9]{4}) - `(?[A-Z_]+)`\n\n(?
(?:.(?!##))+)/gs;async function K0t(t){let r=`https://repo.yarnpkg.com/${je.isTaggedYarnVersion(tn)?tn:await m2(t,"canary")}/packages/gatsby/content/advanced/error-codes.md`,o=await rn.get(r,{configuration:t});return new Map(Array.from(o.toString().matchAll(V0t),({groups:a})=>{if(!a)throw new Error("Assertion failed: Expected the match to have been successful");let n=$ge(a.code);if(a.name!==n)throw new Error(`Assertion failed: Invalid error code data: Expected "${a.name}" to be named "${n}"`);return[a.code,a.details]}))}var _h=class extends ut{constructor(){super(...arguments);this.code=ge.String({required:!1,validator:oI(Ey(),[sI(/^YN[0-9]{4}$/)])});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins);if(typeof this.code<"u"){let o=$ge(this.code),a=de.pretty(r,o,de.Type.CODE),n=this.cli.format().header(`${this.code} - ${a}`),A=(await K0t(r)).get(this.code),p=typeof A<"u"?de.jsonOrPretty(this.json,r,de.tuple(de.Type.MARKDOWN,{text:A,format:this.cli.format(),paragraphs:!0})):`This error code does not have a description. - -You can help us by editing this page on GitHub \u{1F642}: -${de.jsonOrPretty(this.json,r,de.tuple(de.Type.URL,"https://github.com/yarnpkg/berry/blob/master/packages/gatsby/content/advanced/error-codes.md"))} -`;this.json?this.context.stdout.write(`${JSON.stringify({code:this.code,name:o,details:p})} -`):this.context.stdout.write(`${n} - -${p} -`)}else{let o={children:je.mapAndFilter(Object.entries(wr),([a,n])=>Number.isNaN(Number(a))?je.mapAndFilter.skip:{label:Wu(Number(a)),value:de.tuple(de.Type.CODE,n)})};$s.emitTree(o,{configuration:r,stdout:this.context.stdout,json:this.json})}}};_h.paths=[["explain"]],_h.usage=nt.Usage({description:"explain an error code",details:` - When the code argument is specified, this command prints its name and its details. - - When used without arguments, this command lists all error codes and their names. - `,examples:[["Explain an error code","$0 explain YN0006"],["List all error codes","$0 explain"]]});Ye();Pt();qt();var ede=$e(Zo()),Hh=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Print versions of a package from the whole project"});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Print information for all packages, including transitive dependencies"});this.extra=ge.Array("-X,--extra",[],{description:"An array of requests of extra data provided by plugins"});this.cache=ge.Boolean("--cache",!1,{description:"Print information about the cache entry of a package (path, size, checksum)"});this.dependents=ge.Boolean("--dependents",!1,{description:"Print all dependents for each matching package"});this.manifest=ge.Boolean("--manifest",!1,{description:"Print data obtained by looking at the package archive (license, homepage, ...)"});this.nameOnly=ge.Boolean("--name-only",!1,{description:"Only print the name for the matching packages"});this.virtuals=ge.Boolean("--virtuals",!1,{description:"Print each instance of the virtual packages"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.patterns=ge.Rest()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a&&!this.all)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState();let u=new Set(this.extra);this.cache&&u.add("cache"),this.dependents&&u.add("dependents"),this.manifest&&u.add("manifest");let A=(le,{recursive:pe})=>{let Ae=le.anchoredLocator.locatorHash,ye=new Map,ae=[Ae];for(;ae.length>0;){let we=ae.shift();if(ye.has(we))continue;let Pe=o.storedPackages.get(we);if(typeof Pe>"u")throw new Error("Assertion failed: Expected the package to be registered");if(ye.set(we,Pe),W.isVirtualLocator(Pe)&&ae.push(W.devirtualizeLocator(Pe).locatorHash),!(!pe&&we!==Ae))for(let g of Pe.dependencies.values()){let Ee=o.storedResolutions.get(g.descriptorHash);if(typeof Ee>"u")throw new Error("Assertion failed: Expected the resolution to be registered");ae.push(Ee)}}return ye.values()},p=({recursive:le})=>{let pe=new Map;for(let Ae of o.workspaces)for(let ye of A(Ae,{recursive:le}))pe.set(ye.locatorHash,ye);return pe.values()},h=({all:le,recursive:pe})=>le&&pe?o.storedPackages.values():le?p({recursive:pe}):A(a,{recursive:pe}),E=({all:le,recursive:pe})=>{let Ae=h({all:le,recursive:pe}),ye=this.patterns.map(Pe=>{let g=W.parseLocator(Pe),Ee=ede.default.makeRe(W.stringifyIdent(g)),De=W.isVirtualLocator(g),ce=De?W.devirtualizeLocator(g):g;return ne=>{let ee=W.stringifyIdent(ne);if(!Ee.test(ee))return!1;if(g.reference==="unknown")return!0;let Ie=W.isVirtualLocator(ne),ke=Ie?W.devirtualizeLocator(ne):ne;return!(De&&Ie&&g.reference!==ne.reference||ce.reference!==ke.reference)}}),ae=je.sortMap([...Ae],Pe=>W.stringifyLocator(Pe));return{selection:ae.filter(Pe=>ye.length===0||ye.some(g=>g(Pe))),sortedLookup:ae}},{selection:I,sortedLookup:v}=E({all:this.all,recursive:this.recursive});if(I.length===0)throw new it("No package matched your request");let b=new Map;if(this.dependents)for(let le of v)for(let pe of le.dependencies.values()){let Ae=o.storedResolutions.get(pe.descriptorHash);if(typeof Ae>"u")throw new Error("Assertion failed: Expected the resolution to be registered");je.getArrayWithDefault(b,Ae).push(le)}let C=new Map;for(let le of v){if(!W.isVirtualLocator(le))continue;let pe=W.devirtualizeLocator(le);je.getArrayWithDefault(C,pe.locatorHash).push(le)}let T={},L={children:T},U=r.makeFetcher(),J={project:o,fetcher:U,cache:n,checksums:o.storedChecksums,report:new Qi,cacheOptions:{skipIntegrityCheck:!0}},te=[async(le,pe,Ae)=>{if(!pe.has("manifest"))return;let ye=await U.fetch(le,J),ae;try{ae=await Mt.find(ye.prefixPath,{baseFs:ye.packageFs})}finally{ye.releaseFs?.()}Ae("Manifest",{License:de.tuple(de.Type.NO_HINT,ae.license),Homepage:de.tuple(de.Type.URL,ae.raw.homepage??null)})},async(le,pe,Ae)=>{if(!pe.has("cache"))return;let ye=o.storedChecksums.get(le.locatorHash)??null,ae=n.getLocatorPath(le,ye),we;if(ae!==null)try{we=await oe.statPromise(ae)}catch{}let Pe=typeof we<"u"?[we.size,de.Type.SIZE]:void 0;Ae("Cache",{Checksum:de.tuple(de.Type.NO_HINT,ye),Path:de.tuple(de.Type.PATH,ae),Size:Pe})}];for(let le of I){let pe=W.isVirtualLocator(le);if(!this.virtuals&&pe)continue;let Ae={},ye={value:[le,de.Type.LOCATOR],children:Ae};if(T[W.stringifyLocator(le)]=ye,this.nameOnly){delete ye.children;continue}let ae=C.get(le.locatorHash);typeof ae<"u"&&(Ae.Instances={label:"Instances",value:de.tuple(de.Type.NUMBER,ae.length)}),Ae.Version={label:"Version",value:de.tuple(de.Type.NO_HINT,le.version)};let we=(g,Ee)=>{let De={};if(Ae[g]=De,Array.isArray(Ee))De.children=Ee.map(ce=>({value:ce}));else{let ce={};De.children=ce;for(let[ne,ee]of Object.entries(Ee))typeof ee>"u"||(ce[ne]={label:ne,value:ee})}};if(!pe){for(let g of te)await g(le,u,we);await r.triggerHook(g=>g.fetchPackageInfo,le,u,we)}le.bin.size>0&&!pe&&we("Exported Binaries",[...le.bin.keys()].map(g=>de.tuple(de.Type.PATH,g)));let Pe=b.get(le.locatorHash);typeof Pe<"u"&&Pe.length>0&&we("Dependents",Pe.map(g=>de.tuple(de.Type.LOCATOR,g))),le.dependencies.size>0&&!pe&&we("Dependencies",[...le.dependencies.values()].map(g=>{let Ee=o.storedResolutions.get(g.descriptorHash),De=typeof Ee<"u"?o.storedPackages.get(Ee)??null:null;return de.tuple(de.Type.RESOLUTION,{descriptor:g,locator:De})})),le.peerDependencies.size>0&&pe&&we("Peer dependencies",[...le.peerDependencies.values()].map(g=>{let Ee=le.dependencies.get(g.identHash),De=typeof Ee<"u"?o.storedResolutions.get(Ee.descriptorHash)??null:null,ce=De!==null?o.storedPackages.get(De)??null:null;return de.tuple(de.Type.RESOLUTION,{descriptor:g,locator:ce})}))}$s.emitTree(L,{configuration:r,json:this.json,stdout:this.context.stdout,separators:this.nameOnly?0:2})}};Hh.paths=[["info"]],Hh.usage=nt.Usage({description:"see information related to packages",details:"\n This command prints various information related to the specified packages, accepting glob patterns.\n\n By default, if the locator reference is missing, Yarn will default to print the information about all the matching direct dependencies of the package for the active workspace. To instead print all versions of the package that are direct dependencies of any of your workspaces, use the `-A,--all` flag. Adding the `-R,--recursive` flag will also report transitive dependencies.\n\n Some fields will be hidden by default in order to keep the output readable, but can be selectively displayed by using additional options (`--dependents`, `--manifest`, `--virtuals`, ...) described in the option descriptions.\n\n Note that this command will only print the information directly related to the selected packages - if you wish to know why the package is there in the first place, use `yarn why` which will do just that (it also provides a `-R,--recursive` flag that may be of some help).\n ",examples:[["Show information about Lodash","$0 info lodash"]]});Ye();Pt();Nl();var dk=$e(ed());qt();var U8=$e(zn());Za();var J0t=[{selector:t=>t===-1,name:"nodeLinker",value:"node-modules"},{selector:t=>t!==-1&&t<8,name:"enableGlobalCache",value:!1},{selector:t=>t!==-1&&t<8,name:"compressionLevel",value:"mixed"}],jh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.immutable=ge.Boolean("--immutable",{description:"Abort with an error exit code if the lockfile was to be modified"});this.immutableCache=ge.Boolean("--immutable-cache",{description:"Abort with an error exit code if the cache folder was to be modified"});this.refreshLockfile=ge.Boolean("--refresh-lockfile",{description:"Refresh the package metadata stored in the lockfile"});this.checkCache=ge.Boolean("--check-cache",{description:"Always refetch the packages and ensure that their checksums are consistent"});this.checkResolutions=ge.Boolean("--check-resolutions",{description:"Validates that the package resolutions are coherent"});this.inlineBuilds=ge.Boolean("--inline-builds",{description:"Verbosely print the output of the build steps of dependencies"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:Vs(pl)});this.cacheFolder=ge.String("--cache-folder",{hidden:!0});this.frozenLockfile=ge.Boolean("--frozen-lockfile",{hidden:!0});this.ignoreEngines=ge.Boolean("--ignore-engines",{hidden:!0});this.nonInteractive=ge.Boolean("--non-interactive",{hidden:!0});this.preferOffline=ge.Boolean("--prefer-offline",{hidden:!0});this.production=ge.Boolean("--production",{hidden:!0});this.registry=ge.String("--registry",{hidden:!0});this.silent=ge.Boolean("--silent",{hidden:!0});this.networkTimeout=ge.String("--network-timeout",{hidden:!0})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins);typeof this.inlineBuilds<"u"&&r.useWithSource("",{enableInlineBuilds:this.inlineBuilds},r.startingCwd,{overwrite:!0});let o=!!process.env.FUNCTION_TARGET||!!process.env.GOOGLE_RUNTIME,a=await NE({configuration:r,stdout:this.context.stdout},[{option:this.ignoreEngines,message:"The --ignore-engines option is deprecated; engine checking isn't a core feature anymore",error:!dk.default.VERCEL},{option:this.registry,message:"The --registry option is deprecated; prefer setting npmRegistryServer in your .yarnrc.yml file"},{option:this.preferOffline,message:"The --prefer-offline flag is deprecated; use the --cached flag with 'yarn add' instead",error:!dk.default.VERCEL},{option:this.production,message:"The --production option is deprecated on 'install'; use 'yarn workspaces focus' instead",error:!0},{option:this.nonInteractive,message:"The --non-interactive option is deprecated",error:!o},{option:this.frozenLockfile,message:"The --frozen-lockfile option is deprecated; use --immutable and/or --immutable-cache instead",callback:()=>this.immutable=this.frozenLockfile},{option:this.cacheFolder,message:"The cache-folder option has been deprecated; use rc settings instead",error:!dk.default.NETLIFY}]);if(a!==null)return a;let n=this.mode==="update-lockfile";if(n&&(this.immutable||this.immutableCache))throw new it(`${de.pretty(r,"--immutable",de.Type.CODE)} and ${de.pretty(r,"--immutable-cache",de.Type.CODE)} cannot be used with ${de.pretty(r,"--mode=update-lockfile",de.Type.CODE)}`);let u=(this.immutable??r.get("enableImmutableInstalls"))&&!n,A=this.immutableCache&&!n;if(r.projectCwd!==null){let T=await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async L=>{let U=!1;await Z0t(r,u)&&(L.reportInfo(48,"Automatically removed core plugins that are now builtins \u{1F44D}"),U=!0),await X0t(r,u)&&(L.reportInfo(48,"Automatically fixed merge conflicts \u{1F44D}"),U=!0),U&&L.reportSeparator()});if(T.hasErrors())return T.exitCode()}if(r.projectCwd!==null){let T=await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async L=>{if(Ve.telemetry?.isNew)Ve.telemetry.commitTips(),L.reportInfo(65,"Yarn will periodically gather anonymous telemetry: https://yarnpkg.com/advanced/telemetry"),L.reportInfo(65,`Run ${de.pretty(r,"yarn config set --home enableTelemetry 0",de.Type.CODE)} to disable`),L.reportSeparator();else if(Ve.telemetry?.shouldShowTips){let U=await rn.get("https://repo.yarnpkg.com/tags",{configuration:r,jsonResponse:!0}).catch(()=>null);if(U!==null){let J=null;if(tn!==null){let le=U8.default.prerelease(tn)?"canary":"stable",pe=U.latest[le];U8.default.gt(pe,tn)&&(J=[le,pe])}if(J)Ve.telemetry.commitTips(),L.reportInfo(88,`${de.applyStyle(r,`A new ${J[0]} version of Yarn is available:`,de.Style.BOLD)} ${W.prettyReference(r,J[1])}!`),L.reportInfo(88,`Upgrade now by running ${de.pretty(r,`yarn set version ${J[1]}`,de.Type.CODE)}`),L.reportSeparator();else{let te=Ve.telemetry.selectTip(U.tips);te&&(L.reportInfo(89,de.pretty(r,te.message,de.Type.MARKDOWN_INLINE)),te.url&&L.reportInfo(89,`Learn more at ${te.url}`),L.reportSeparator())}}}});if(T.hasErrors())return T.exitCode()}let{project:p,workspace:h}=await St.find(r,this.context.cwd),E=p.lockfileLastVersion;if(E!==null){let T=await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async L=>{let U={};for(let J of J0t)J.selector(E)&&typeof r.sources.get(J.name)>"u"&&(r.use("",{[J.name]:J.value},p.cwd,{overwrite:!0}),U[J.name]=J.value);Object.keys(U).length>0&&(await Ve.updateConfiguration(p.cwd,U),L.reportInfo(87,"Migrated your project to the latest Yarn version \u{1F680}"),L.reportSeparator())});if(T.hasErrors())return T.exitCode()}let I=await Lr.find(r,{immutable:A,check:this.checkCache});if(!h)throw new rr(p.cwd,this.context.cwd);await p.restoreInstallState({restoreResolutions:!1});let v=r.get("enableHardenedMode");v&&typeof r.sources.get("enableHardenedMode")>"u"&&await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async T=>{T.reportWarning(0,"Yarn detected that the current workflow is executed from a public pull request. For safety the hardened mode has been enabled."),T.reportWarning(0,`It will prevent malicious lockfile manipulations, in exchange for a slower install time. You can opt-out if necessary; check our ${de.applyHyperlink(r,"documentation","https://yarnpkg.com/features/security#hardened-mode")} for more details.`),T.reportSeparator()}),(this.refreshLockfile??v)&&(p.lockfileNeedsRefresh=!0);let b=this.checkResolutions??v;return(await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout,forceSectionAlignment:!0,includeLogs:!0,includeVersion:!0},async T=>{await p.install({cache:I,report:T,immutable:u,checkResolutions:b,mode:this.mode})})).exitCode()}};jh.paths=[["install"],nt.Default],jh.usage=nt.Usage({description:"install the project dependencies",details:"\n This command sets up your project if needed. The installation is split into four different steps that each have their own characteristics:\n\n - **Resolution:** First the package manager will resolve your dependencies. The exact way a dependency version is privileged over another isn't standardized outside of the regular semver guarantees. If a package doesn't resolve to what you would expect, check that all dependencies are correctly declared (also check our website for more information: ).\n\n - **Fetch:** Then we download all the dependencies if needed, and make sure that they're all stored within our cache (check the value of `cacheFolder` in `yarn config` to see where the cache files are stored).\n\n - **Link:** Then we send the dependency tree information to internal plugins tasked with writing them on the disk in some form (for example by generating the .pnp.cjs file you might know).\n\n - **Build:** Once the dependency tree has been written on the disk, the package manager will now be free to run the build scripts for all packages that might need it, in a topological order compatible with the way they depend on one another. See https://yarnpkg.com/advanced/lifecycle-scripts for detail.\n\n Note that running this command is not part of the recommended workflow. Yarn supports zero-installs, which means that as long as you store your cache and your .pnp.cjs file inside your repository, everything will work without requiring any install right after cloning your repository or switching branches.\n\n If the `--immutable` option is set (defaults to true on CI), Yarn will abort with an error exit code if the lockfile was to be modified (other paths can be added using the `immutablePatterns` configuration setting). For backward compatibility we offer an alias under the name of `--frozen-lockfile`, but it will be removed in a later release.\n\n If the `--immutable-cache` option is set, Yarn will abort with an error exit code if the cache folder was to be modified (either because files would be added, or because they'd be removed).\n\n If the `--refresh-lockfile` option is set, Yarn will keep the same resolution for the packages currently in the lockfile but will refresh their metadata. If used together with `--immutable`, it can validate that the lockfile information are consistent. This flag is enabled by default when Yarn detects it runs within a pull request context.\n\n If the `--check-cache` option is set, Yarn will always refetch the packages and will ensure that their checksum matches what's 1/ described in the lockfile 2/ inside the existing cache files (if present). This is recommended as part of your CI workflow if you're both following the Zero-Installs model and accepting PRs from third-parties, as they'd otherwise have the ability to alter the checked-in packages before submitting them.\n\n If the `--inline-builds` option is set, Yarn will verbosely print the output of the build steps of your dependencies (instead of writing them into individual files). This is likely useful mostly for debug purposes only when using Docker-like environments.\n\n If the `--mode=` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\n\n - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\n\n - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\n ",examples:[["Install the project","$0 install"],["Validate a project when using Zero-Installs","$0 install --immutable --immutable-cache"],["Validate a project when using Zero-Installs (slightly safer if you accept external PRs)","$0 install --immutable --immutable-cache --check-cache"]]});var z0t="<<<<<<<";async function X0t(t,e){if(!t.projectCwd)return!1;let r=K.join(t.projectCwd,dr.lockfile);if(!await oe.existsPromise(r)||!(await oe.readFilePromise(r,"utf8")).includes(z0t))return!1;if(e)throw new zt(47,"Cannot autofix a lockfile when running an immutable install");let a=await Ur.execvp("git",["rev-parse","MERGE_HEAD","HEAD"],{cwd:t.projectCwd});if(a.code!==0&&(a=await Ur.execvp("git",["rev-parse","REBASE_HEAD","HEAD"],{cwd:t.projectCwd})),a.code!==0&&(a=await Ur.execvp("git",["rev-parse","CHERRY_PICK_HEAD","HEAD"],{cwd:t.projectCwd})),a.code!==0)throw new zt(83,"Git returned an error when trying to find the commits pertaining to the conflict");let n=await Promise.all(a.stdout.trim().split(/\n/).map(async A=>{let p=await Ur.execvp("git",["show",`${A}:./${dr.lockfile}`],{cwd:t.projectCwd});if(p.code!==0)throw new zt(83,`Git returned an error when trying to access the lockfile content in ${A}`);try{return Vi(p.stdout)}catch{throw new zt(46,"A variant of the conflicting lockfile failed to parse")}}));n=n.filter(A=>!!A.__metadata);for(let A of n){if(A.__metadata.version<7)for(let p of Object.keys(A)){if(p==="__metadata")continue;let h=W.parseDescriptor(p,!0),E=t.normalizeDependency(h),I=W.stringifyDescriptor(E);I!==p&&(A[I]=A[p],delete A[p])}for(let p of Object.keys(A)){if(p==="__metadata")continue;let h=A[p].checksum;typeof h=="string"&&h.includes("/")||(A[p].checksum=`${A.__metadata.cacheKey}/${h}`)}}let u=Object.assign({},...n);u.__metadata.version=`${Math.min(...n.map(A=>parseInt(A.__metadata.version??0)))}`,u.__metadata.cacheKey="merged";for(let[A,p]of Object.entries(u))typeof p=="string"&&delete u[A];return await oe.changeFilePromise(r,Ba(u),{automaticNewlines:!0}),!0}async function Z0t(t,e){if(!t.projectCwd)return!1;let r=[],o=K.join(t.projectCwd,".yarn/plugins/@yarnpkg");return await Ve.updateConfiguration(t.projectCwd,{plugins:n=>{if(!Array.isArray(n))return n;let u=n.filter(A=>{if(!A.path)return!0;let p=K.resolve(t.projectCwd,A.path),h=B1.has(A.spec)&&K.contains(o,p);return h&&r.push(p),!h});return u.length===0?Ve.deleteProperty:u.length===n.length?n:u}},{immutable:e})?(await Promise.all(r.map(async n=>{await oe.removePromise(n)})),!0):!1}Ye();Pt();qt();var qh=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Link all workspaces belonging to the target projects to the current one"});this.private=ge.Boolean("-p,--private",!1,{description:"Also link private workspaces belonging to the target projects to the current one"});this.relative=ge.Boolean("-r,--relative",!1,{description:"Link workspaces using relative paths instead of absolute paths"});this.destinations=ge.Rest()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=o.topLevelWorkspace,A=[];for(let p of this.destinations){let h=K.resolve(this.context.cwd,ue.toPortablePath(p)),E=await Ve.find(h,this.context.plugins,{useRc:!1,strict:!1}),{project:I,workspace:v}=await St.find(E,h);if(o.cwd===I.cwd)throw new it(`Invalid destination '${p}'; Can't link the project to itself`);if(!v)throw new rr(I.cwd,h);if(this.all){let b=!1;for(let C of I.workspaces)C.manifest.name&&(!C.manifest.private||this.private)&&(A.push(C),b=!0);if(!b)throw new it(`No workspace found to be linked in the target project: ${p}`)}else{if(!v.manifest.name)throw new it(`The target workspace at '${p}' doesn't have a name and thus cannot be linked`);if(v.manifest.private&&!this.private)throw new it(`The target workspace at '${p}' is marked private - use the --private flag to link it anyway`);A.push(v)}}for(let p of A){let h=W.stringifyIdent(p.anchoredLocator),E=this.relative?K.relative(o.cwd,p.cwd):p.cwd;u.manifest.resolutions.push({pattern:{descriptor:{fullName:h}},reference:`portal:${E}`})}return await o.installWithNewReport({stdout:this.context.stdout},{cache:n})}};qh.paths=[["link"]],qh.usage=nt.Usage({description:"connect the local project to another one",details:"\n This command will set a new `resolutions` field in the project-level manifest and point it to the workspace at the specified location (even if part of another project).\n ",examples:[["Register one or more remote workspaces for use in the current project","$0 link ~/ts-loader ~/jest"],["Register all workspaces from a remote project for use in the current project","$0 link ~/jest --all"]]});qt();var Gh=class extends ut{constructor(){super(...arguments);this.args=ge.Proxy()}async execute(){return this.cli.run(["exec","node",...this.args])}};Gh.paths=[["node"]],Gh.usage=nt.Usage({description:"run node with the hook already setup",details:` - This command simply runs Node. It also makes sure to call it in a way that's compatible with the current project (for example, on PnP projects the environment will be setup in such a way that PnP will be correctly injected into the environment). - - The Node process will use the exact same version of Node as the one used to run Yarn itself, which might be a good way to ensure that your commands always use a consistent Node version. - `,examples:[["Run a Node script","$0 node ./my-script.js"]]});Ye();qt();var Yh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),o=await Ve.findRcFiles(this.context.cwd);return(await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout},async n=>{for(let u of o)if(!!u.data?.plugins)for(let A of u.data.plugins){if(!A.checksum||!A.spec.match(/^https?:/))continue;let p=await rn.get(A.spec,{configuration:r}),h=wn.makeHash(p);if(A.checksum===h)continue;let E=de.pretty(r,A.path,de.Type.PATH),I=de.pretty(r,A.spec,de.Type.URL),v=`${E} is different from the file provided by ${I}`;n.reportJson({...A,newChecksum:h}),n.reportError(0,v)}})).exitCode()}};Yh.paths=[["plugin","check"]],Yh.usage=nt.Usage({category:"Plugin-related commands",description:"find all third-party plugins that differ from their own spec",details:` - Check only the plugins from https. - - If this command detects any plugin differences in the CI environment, it will throw an error. - `,examples:[["find all third-party plugins that differ from their own spec","$0 plugin check"]]});Ye();Ye();Pt();qt();var ode=Be("os");Ye();Pt();qt();var tde=Be("os");Ye();Nl();qt();var $0t="https://raw.githubusercontent.com/yarnpkg/berry/master/plugins.yml";async function Jd(t,e){let r=await rn.get($0t,{configuration:t}),o=Vi(r.toString());return Object.fromEntries(Object.entries(o).filter(([a,n])=>!e||kr.satisfiesWithPrereleases(e,n.range??"<4.0.0-rc.1")))}var Wh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins);return(await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout},async a=>{let n=await Jd(r,tn);for(let[u,{experimental:A,...p}]of Object.entries(n)){let h=u;A&&(h+=" [experimental]"),a.reportJson({name:u,experimental:A,...p}),a.reportInfo(null,h)}})).exitCode()}};Wh.paths=[["plugin","list"]],Wh.usage=nt.Usage({category:"Plugin-related commands",description:"list the available official plugins",details:"\n This command prints the plugins available directly from the Yarn repository. Only those plugins can be referenced by name in `yarn plugin import`.\n ",examples:[["List the official plugins","$0 plugin list"]]});var egt=/^[0-9]+$/,tgt=process.platform==="win32";function rde(t){return egt.test(t)?`pull/${t}/head`:t}var rgt=({repository:t,branch:e},r)=>[["git","init",ue.fromPortablePath(r)],["git","remote","add","origin",t],["git","fetch","origin","--depth=1",rde(e)],["git","reset","--hard","FETCH_HEAD"]],ngt=({branch:t})=>[["git","fetch","origin","--depth=1",rde(t),"--force"],["git","reset","--hard","FETCH_HEAD"],["git","clean","-dfx","-e","packages/yarnpkg-cli/bundles"]],igt=({plugins:t,noMinify:e},r,o)=>[["yarn","build:cli",...new Array().concat(...t.map(a=>["--plugin",K.resolve(o,a)])),...e?["--no-minify"]:[],"|"],[tgt?"move":"mv","packages/yarnpkg-cli/bundles/yarn.js",ue.fromPortablePath(r),"|"]],Vh=class extends ut{constructor(){super(...arguments);this.installPath=ge.String("--path",{description:"The path where the repository should be cloned to"});this.repository=ge.String("--repository","https://github.com/yarnpkg/berry.git",{description:"The repository that should be cloned"});this.branch=ge.String("--branch","master",{description:"The branch of the repository that should be cloned"});this.plugins=ge.Array("--plugin",[],{description:"An array of additional plugins that should be included in the bundle"});this.dryRun=ge.Boolean("-n,--dry-run",!1,{description:"If set, the bundle will be built but not added to the project"});this.noMinify=ge.Boolean("--no-minify",!1,{description:"Build a bundle for development (debugging) - non-minified and non-mangled"});this.force=ge.Boolean("-f,--force",!1,{description:"Always clone the repository instead of trying to fetch the latest commits"});this.skipPlugins=ge.Boolean("--skip-plugins",!1,{description:"Skip updating the contrib plugins"})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd),a=typeof this.installPath<"u"?K.resolve(this.context.cwd,ue.toPortablePath(this.installPath)):K.resolve(ue.toPortablePath((0,tde.tmpdir)()),"yarnpkg-sources",wn.makeHash(this.repository).slice(0,6));return(await Nt.start({configuration:r,stdout:this.context.stdout},async u=>{await _8(this,{configuration:r,report:u,target:a}),u.reportSeparator(),u.reportInfo(0,"Building a fresh bundle"),u.reportSeparator();let A=await Ur.execvp("git",["rev-parse","--short","HEAD"],{cwd:a,strict:!0}),p=K.join(a,`packages/yarnpkg-cli/bundles/yarn-${A.stdout.trim()}.js`);oe.existsSync(p)||(await y2(igt(this,p,a),{configuration:r,context:this.context,target:a}),u.reportSeparator());let h=await oe.readFilePromise(p);if(!this.dryRun){let{bundleVersion:E}=await O8(r,null,async()=>h,{report:u});this.skipPlugins||await sgt(this,E,{project:o,report:u,target:a})}})).exitCode()}};Vh.paths=[["set","version","from","sources"]],Vh.usage=nt.Usage({description:"build Yarn from master",details:` - This command will clone the Yarn repository into a temporary folder, then build it. The resulting bundle will then be copied into the local project. - - By default, it also updates all contrib plugins to the same commit the bundle is built from. This behavior can be disabled by using the \`--skip-plugins\` flag. - `,examples:[["Build Yarn from master","$0 set version from sources"]]});async function y2(t,{configuration:e,context:r,target:o}){for(let[a,...n]of t){let u=n[n.length-1]==="|";if(u&&n.pop(),u)await Ur.pipevp(a,n,{cwd:o,stdin:r.stdin,stdout:r.stdout,stderr:r.stderr,strict:!0});else{r.stdout.write(`${de.pretty(e,` $ ${[a,...n].join(" ")}`,"grey")} -`);try{await Ur.execvp(a,n,{cwd:o,strict:!0})}catch(A){throw r.stdout.write(A.stdout||A.stack),A}}}}async function _8(t,{configuration:e,report:r,target:o}){let a=!1;if(!t.force&&oe.existsSync(K.join(o,".git"))){r.reportInfo(0,"Fetching the latest commits"),r.reportSeparator();try{await y2(ngt(t),{configuration:e,context:t.context,target:o}),a=!0}catch{r.reportSeparator(),r.reportWarning(0,"Repository update failed; we'll try to regenerate it")}}a||(r.reportInfo(0,"Cloning the remote repository"),r.reportSeparator(),await oe.removePromise(o),await oe.mkdirPromise(o,{recursive:!0}),await y2(rgt(t,o),{configuration:e,context:t.context,target:o}))}async function sgt(t,e,{project:r,report:o,target:a}){let n=await Jd(r.configuration,e),u=new Set(Object.keys(n));for(let A of r.configuration.plugins.keys())!u.has(A)||await H8(A,t,{project:r,report:o,target:a})}Ye();Ye();Pt();qt();var nde=$e(zn()),ide=Be("url"),sde=Be("vm");var Kh=class extends ut{constructor(){super(...arguments);this.name=ge.String();this.checksum=ge.Boolean("--checksum",!0,{description:"Whether to care if this plugin is modified"})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins);return(await Nt.start({configuration:r,stdout:this.context.stdout},async a=>{let{project:n}=await St.find(r,this.context.cwd),u,A;if(this.name.match(/^\.{0,2}[\\/]/)||ue.isAbsolute(this.name)){let p=K.resolve(this.context.cwd,ue.toPortablePath(this.name));a.reportInfo(0,`Reading ${de.pretty(r,p,de.Type.PATH)}`),u=K.relative(n.cwd,p),A=await oe.readFilePromise(p)}else{let p;if(this.name.match(/^https?:/)){try{new ide.URL(this.name)}catch{throw new zt(52,`Plugin specifier "${this.name}" is neither a plugin name nor a valid url`)}u=this.name,p=this.name}else{let h=W.parseLocator(this.name.replace(/^((@yarnpkg\/)?plugin-)?/,"@yarnpkg/plugin-"));if(h.reference!=="unknown"&&!nde.default.valid(h.reference))throw new zt(0,"Official plugins only accept strict version references. Use an explicit URL if you wish to download them from another location.");let E=W.stringifyIdent(h),I=await Jd(r,tn);if(!Object.hasOwn(I,E)){let v=`Couldn't find a plugin named ${W.prettyIdent(r,h)} on the remote registry. -`;throw r.plugins.has(E)?v+=`A plugin named ${W.prettyIdent(r,h)} is already installed; possibly attempting to import a built-in plugin.`:v+=`Note that only the plugins referenced on our website (${de.pretty(r,"https://github.com/yarnpkg/berry/blob/master/plugins.yml",de.Type.URL)}) can be referenced by their name; any other plugin will have to be referenced through its public url (for example ${de.pretty(r,"https://github.com/yarnpkg/berry/raw/master/packages/plugin-typescript/bin/%40yarnpkg/plugin-typescript.js",de.Type.URL)}).`,new zt(51,v)}u=E,p=I[E].url,h.reference!=="unknown"?p=p.replace(/\/master\//,`/${E}/${h.reference}/`):tn!==null&&(p=p.replace(/\/master\//,`/@yarnpkg/cli/${tn}/`))}a.reportInfo(0,`Downloading ${de.pretty(r,p,"green")}`),A=await rn.get(p,{configuration:r})}await j8(u,A,{checksum:this.checksum,project:n,report:a})})).exitCode()}};Kh.paths=[["plugin","import"]],Kh.usage=nt.Usage({category:"Plugin-related commands",description:"download a plugin",details:` - This command downloads the specified plugin from its remote location and updates the configuration to reference it in further CLI invocations. - - Three types of plugin references are accepted: - - - If the plugin is stored within the Yarn repository, it can be referenced by name. - - Third-party plugins can be referenced directly through their public urls. - - Local plugins can be referenced by their path on the disk. - - If the \`--no-checksum\` option is set, Yarn will no longer care if the plugin is modified. - - Plugins cannot be downloaded from the npm registry, and aren't allowed to have dependencies (they need to be bundled into a single file, possibly thanks to the \`@yarnpkg/builder\` package). - `,examples:[['Download and activate the "@yarnpkg/plugin-exec" plugin',"$0 plugin import @yarnpkg/plugin-exec"],['Download and activate the "@yarnpkg/plugin-exec" plugin (shorthand)',"$0 plugin import exec"],["Download and activate a community plugin","$0 plugin import https://example.org/path/to/plugin.js"],["Activate a local plugin","$0 plugin import ./path/to/plugin.js"]]});async function j8(t,e,{checksum:r=!0,project:o,report:a}){let{configuration:n}=o,u={},A={exports:u};(0,sde.runInNewContext)(e.toString(),{module:A,exports:u});let h=`.yarn/plugins/${A.exports.name}.cjs`,E=K.resolve(o.cwd,h);a.reportInfo(0,`Saving the new plugin in ${de.pretty(n,h,"magenta")}`),await oe.mkdirPromise(K.dirname(E),{recursive:!0}),await oe.writeFilePromise(E,e);let I={path:h,spec:t};r&&(I.checksum=wn.makeHash(e)),await Ve.addPlugin(o.cwd,[I])}var ogt=({pluginName:t,noMinify:e},r)=>[["yarn",`build:${t}`,...e?["--no-minify"]:[],"|"]],Jh=class extends ut{constructor(){super(...arguments);this.installPath=ge.String("--path",{description:"The path where the repository should be cloned to"});this.repository=ge.String("--repository","https://github.com/yarnpkg/berry.git",{description:"The repository that should be cloned"});this.branch=ge.String("--branch","master",{description:"The branch of the repository that should be cloned"});this.noMinify=ge.Boolean("--no-minify",!1,{description:"Build a plugin for development (debugging) - non-minified and non-mangled"});this.force=ge.Boolean("-f,--force",!1,{description:"Always clone the repository instead of trying to fetch the latest commits"});this.name=ge.String()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),o=typeof this.installPath<"u"?K.resolve(this.context.cwd,ue.toPortablePath(this.installPath)):K.resolve(ue.toPortablePath((0,ode.tmpdir)()),"yarnpkg-sources",wn.makeHash(this.repository).slice(0,6));return(await Nt.start({configuration:r,stdout:this.context.stdout},async n=>{let{project:u}=await St.find(r,this.context.cwd),A=W.parseIdent(this.name.replace(/^((@yarnpkg\/)?plugin-)?/,"@yarnpkg/plugin-")),p=W.stringifyIdent(A),h=await Jd(r,tn);if(!Object.hasOwn(h,p))throw new zt(51,`Couldn't find a plugin named "${p}" on the remote registry. Note that only the plugins referenced on our website (https://github.com/yarnpkg/berry/blob/master/plugins.yml) can be built and imported from sources.`);let E=p;await _8(this,{configuration:r,report:n,target:o}),await H8(E,this,{project:u,report:n,target:o})})).exitCode()}};Jh.paths=[["plugin","import","from","sources"]],Jh.usage=nt.Usage({category:"Plugin-related commands",description:"build a plugin from sources",details:` - This command clones the Yarn repository into a temporary folder, builds the specified contrib plugin and updates the configuration to reference it in further CLI invocations. - - The plugins can be referenced by their short name if sourced from the official Yarn repository. - `,examples:[['Build and activate the "@yarnpkg/plugin-exec" plugin',"$0 plugin import from sources @yarnpkg/plugin-exec"],['Build and activate the "@yarnpkg/plugin-exec" plugin (shorthand)',"$0 plugin import from sources exec"]]});async function H8(t,{context:e,noMinify:r},{project:o,report:a,target:n}){let u=t.replace(/@yarnpkg\//,""),{configuration:A}=o;a.reportSeparator(),a.reportInfo(0,`Building a fresh ${u}`),a.reportSeparator(),await y2(ogt({pluginName:u,noMinify:r},n),{configuration:A,context:e,target:n}),a.reportSeparator();let p=K.resolve(n,`packages/${u}/bundles/${t}.js`),h=await oe.readFilePromise(p);await j8(t,h,{project:o,report:a})}Ye();Pt();qt();var zh=class extends ut{constructor(){super(...arguments);this.name=ge.String()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd);return(await Nt.start({configuration:r,stdout:this.context.stdout},async n=>{let u=this.name,A=W.parseIdent(u);if(!r.plugins.has(u))throw new it(`${W.prettyIdent(r,A)} isn't referenced by the current configuration`);let p=`.yarn/plugins/${u}.cjs`,h=K.resolve(o.cwd,p);oe.existsSync(h)&&(n.reportInfo(0,`Removing ${de.pretty(r,p,de.Type.PATH)}...`),await oe.removePromise(h)),n.reportInfo(0,"Updating the configuration..."),await Ve.updateConfiguration(o.cwd,{plugins:E=>{if(!Array.isArray(E))return E;let I=E.filter(v=>v.path!==p);return I.length===0?Ve.deleteProperty:I.length===E.length?E:I}})})).exitCode()}};zh.paths=[["plugin","remove"]],zh.usage=nt.Usage({category:"Plugin-related commands",description:"remove a plugin",details:` - This command deletes the specified plugin from the .yarn/plugins folder and removes it from the configuration. - - **Note:** The plugins have to be referenced by their name property, which can be obtained using the \`yarn plugin runtime\` command. Shorthands are not allowed. - `,examples:[["Remove a plugin imported from the Yarn repository","$0 plugin remove @yarnpkg/plugin-typescript"],["Remove a plugin imported from a local file","$0 plugin remove my-local-plugin"]]});Ye();qt();var Xh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins);return(await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout},async a=>{for(let n of r.plugins.keys()){let u=this.context.plugins.plugins.has(n),A=n;u&&(A+=" [builtin]"),a.reportJson({name:n,builtin:u}),a.reportInfo(null,`${A}`)}})).exitCode()}};Xh.paths=[["plugin","runtime"]],Xh.usage=nt.Usage({category:"Plugin-related commands",description:"list the active plugins",details:` - This command prints the currently active plugins. Will be displayed both builtin plugins and external plugins. - `,examples:[["List the currently active plugins","$0 plugin runtime"]]});Ye();Ye();qt();var Zh=class extends ut{constructor(){super(...arguments);this.idents=ge.Rest()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);let u=new Set;for(let A of this.idents)u.add(W.parseIdent(A).identHash);if(await o.restoreInstallState({restoreResolutions:!1}),await o.resolveEverything({cache:n,report:new Qi}),u.size>0)for(let A of o.storedPackages.values())u.has(A.identHash)&&(o.storedBuildState.delete(A.locatorHash),o.skippedBuilds.delete(A.locatorHash));else o.storedBuildState.clear(),o.skippedBuilds.clear();return await o.installWithNewReport({stdout:this.context.stdout,quiet:this.context.quiet},{cache:n})}};Zh.paths=[["rebuild"]],Zh.usage=nt.Usage({description:"rebuild the project's native packages",details:` - This command will automatically cause Yarn to forget about previous compilations of the given packages and to run them again. - - Note that while Yarn forgets the compilation, the previous artifacts aren't erased from the filesystem and may affect the next builds (in good or bad). To avoid this, you may remove the .yarn/unplugged folder, or any other relevant location where packages might have been stored (Yarn may offer a way to do that automatically in the future). - - By default all packages will be rebuilt, but you can filter the list by specifying the names of the packages you want to clear from memory. - `,examples:[["Rebuild all packages","$0 rebuild"],["Rebuild fsevents only","$0 rebuild fsevents"]]});Ye();Ye();Ye();qt();var q8=$e(Zo());Za();var $h=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Apply the operation to all workspaces from the current project"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:Vs(pl)});this.patterns=ge.Rest()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=this.all?o.workspaces:[a],A=["dependencies","devDependencies","peerDependencies"],p=[],h=!1,E=[];for(let C of this.patterns){let T=!1,L=W.parseIdent(C);for(let U of u){let J=[...U.manifest.peerDependenciesMeta.keys()];for(let te of(0,q8.default)(J,C))U.manifest.peerDependenciesMeta.delete(te),h=!0,T=!0;for(let te of A){let le=U.manifest.getForScope(te),pe=[...le.values()].map(Ae=>W.stringifyIdent(Ae));for(let Ae of(0,q8.default)(pe,W.stringifyIdent(L))){let{identHash:ye}=W.parseIdent(Ae),ae=le.get(ye);if(typeof ae>"u")throw new Error("Assertion failed: Expected the descriptor to be registered");U.manifest[te].delete(ye),E.push([U,te,ae]),h=!0,T=!0}}}T||p.push(C)}let I=p.length>1?"Patterns":"Pattern",v=p.length>1?"don't":"doesn't",b=this.all?"any":"this";if(p.length>0)throw new it(`${I} ${de.prettyList(r,p,de.Type.CODE)} ${v} match any packages referenced by ${b} workspace`);return h?(await r.triggerMultipleHooks(C=>C.afterWorkspaceDependencyRemoval,E),await o.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})):0}};$h.paths=[["remove"]],$h.usage=nt.Usage({description:"remove dependencies from the project",details:` - This command will remove the packages matching the specified patterns from the current workspace. - - If the \`--mode=\` option is set, Yarn will change which artifacts are generated. The modes currently supported are: - - - \`skip-build\` will not run the build scripts at all. Note that this is different from setting \`enableScripts\` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run. - - - \`update-lockfile\` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost. - - This command accepts glob patterns as arguments (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them. - `,examples:[["Remove a dependency from the current project","$0 remove lodash"],["Remove a dependency from all workspaces at once","$0 remove lodash --all"],["Remove all dependencies starting with `eslint-`","$0 remove 'eslint-*'"],["Remove all dependencies with the `@babel` scope","$0 remove '@babel/*'"],["Remove all dependencies matching `react-dom` or `react-helmet`","$0 remove 'react-{dom,helmet}'"]]});Ye();Ye();var ade=Be("util"),zd=class extends ut{async execute(){let e=await Ve.find(this.context.cwd,this.context.plugins),{project:r,workspace:o}=await St.find(e,this.context.cwd);if(!o)throw new rr(r.cwd,this.context.cwd);return(await Nt.start({configuration:e,stdout:this.context.stdout},async n=>{let u=o.manifest.scripts,A=je.sortMap(u.keys(),E=>E),p={breakLength:1/0,colors:e.get("enableColors"),maxArrayLength:2},h=A.reduce((E,I)=>Math.max(E,I.length),0);for(let[E,I]of u.entries())n.reportInfo(null,`${E.padEnd(h," ")} ${(0,ade.inspect)(I,p)}`)})).exitCode()}};zd.paths=[["run"]];Ye();Ye();qt();var e0=class extends ut{constructor(){super(...arguments);this.inspect=ge.String("--inspect",!1,{tolerateBoolean:!0,description:"Forwarded to the underlying Node process when executing a binary"});this.inspectBrk=ge.String("--inspect-brk",!1,{tolerateBoolean:!0,description:"Forwarded to the underlying Node process when executing a binary"});this.topLevel=ge.Boolean("-T,--top-level",!1,{description:"Check the root workspace for scripts and/or binaries instead of the current one"});this.binariesOnly=ge.Boolean("-B,--binaries-only",!1,{description:"Ignore any user defined scripts and only check for binaries"});this.require=ge.String("--require",{description:"Forwarded to the underlying Node process when executing a binary"});this.silent=ge.Boolean("--silent",{hidden:!0});this.scriptName=ge.String();this.args=ge.Proxy()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a,locator:n}=await St.find(r,this.context.cwd);await o.restoreInstallState();let u=this.topLevel?o.topLevelWorkspace.anchoredLocator:n;if(!this.binariesOnly&&await un.hasPackageScript(u,this.scriptName,{project:o}))return await un.executePackageScript(u,this.scriptName,this.args,{project:o,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});let A=await un.getPackageAccessibleBinaries(u,{project:o});if(A.get(this.scriptName)){let h=[];return this.inspect&&(typeof this.inspect=="string"?h.push(`--inspect=${this.inspect}`):h.push("--inspect")),this.inspectBrk&&(typeof this.inspectBrk=="string"?h.push(`--inspect-brk=${this.inspectBrk}`):h.push("--inspect-brk")),this.require&&h.push(`--require=${this.require}`),await un.executePackageAccessibleBinary(u,this.scriptName,this.args,{cwd:this.context.cwd,project:o,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,nodeArgs:h,packageAccessibleBinaries:A})}if(!this.topLevel&&!this.binariesOnly&&a&&this.scriptName.includes(":")){let E=(await Promise.all(o.workspaces.map(async I=>I.manifest.scripts.has(this.scriptName)?I:null))).filter(I=>I!==null);if(E.length===1)return await un.executeWorkspaceScript(E[0],this.scriptName,this.args,{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})}if(this.topLevel)throw this.scriptName==="node-gyp"?new it(`Couldn't find a script name "${this.scriptName}" in the top-level (used by ${W.prettyLocator(r,n)}). This typically happens because some package depends on "node-gyp" to build itself, but didn't list it in their dependencies. To fix that, please run "yarn add node-gyp" into your top-level workspace. You also can open an issue on the repository of the specified package to suggest them to use an optional peer dependency.`):new it(`Couldn't find a script name "${this.scriptName}" in the top-level (used by ${W.prettyLocator(r,n)}).`);{if(this.scriptName==="global")throw new it("The 'yarn global' commands have been removed in 2.x - consider using 'yarn dlx' or a third-party plugin instead");let h=[this.scriptName].concat(this.args);for(let[E,I]of uC)for(let v of I)if(h.length>=v.length&&JSON.stringify(h.slice(0,v.length))===JSON.stringify(v))throw new it(`Couldn't find a script named "${this.scriptName}", but a matching command can be found in the ${E} plugin. You can install it with "yarn plugin import ${E}".`);throw new it(`Couldn't find a script named "${this.scriptName}".`)}}};e0.paths=[["run"]],e0.usage=nt.Usage({description:"run a script defined in the package.json",details:` - This command will run a tool. The exact tool that will be executed will depend on the current state of your workspace: - - - If the \`scripts\` field from your local package.json contains a matching script name, its definition will get executed. - - - Otherwise, if one of the local workspace's dependencies exposes a binary with a matching name, this binary will get executed. - - - Otherwise, if the specified name contains a colon character and if one of the workspaces in the project contains exactly one script with a matching name, then this script will get executed. - - Whatever happens, the cwd of the spawned process will be the workspace that declares the script (which makes it possible to call commands cross-workspaces using the third syntax). - `,examples:[["Run the tests from the local workspace","$0 run test"],['Same thing, but without the "run" keyword',"$0 test"],["Inspect Webpack while running","$0 run --inspect-brk webpack"]]});Ye();Ye();qt();var t0=class extends ut{constructor(){super(...arguments);this.descriptor=ge.String();this.resolution=ge.String()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(await o.restoreInstallState({restoreResolutions:!1}),!a)throw new rr(o.cwd,this.context.cwd);let u=W.parseDescriptor(this.descriptor,!0),A=W.makeDescriptor(u,this.resolution);return o.storedDescriptors.set(u.descriptorHash,u),o.storedDescriptors.set(A.descriptorHash,A),o.resolutionAliases.set(u.descriptorHash,A.descriptorHash),await o.installWithNewReport({stdout:this.context.stdout},{cache:n})}};t0.paths=[["set","resolution"]],t0.usage=nt.Usage({description:"enforce a package resolution",details:'\n This command updates the resolution table so that `descriptor` is resolved by `resolution`.\n\n Note that by default this command only affect the current resolution table - meaning that this "manual override" will disappear if you remove the lockfile, or if the package disappear from the table. If you wish to make the enforced resolution persist whatever happens, edit the `resolutions` field in your top-level manifest.\n\n Note that no attempt is made at validating that `resolution` is a valid resolution entry for `descriptor`.\n ',examples:[["Force all instances of lodash@npm:^1.2.3 to resolve to 1.5.0","$0 set resolution lodash@npm:^1.2.3 1.5.0"]]});Ye();Pt();qt();var lde=$e(Zo()),r0=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Unlink all workspaces belonging to the target project from the current one"});this.leadingArguments=ge.Rest()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);let u=o.topLevelWorkspace,A=new Set;if(this.leadingArguments.length===0&&this.all)for(let{pattern:p,reference:h}of u.manifest.resolutions)h.startsWith("portal:")&&A.add(p.descriptor.fullName);if(this.leadingArguments.length>0)for(let p of this.leadingArguments){let h=K.resolve(this.context.cwd,ue.toPortablePath(p));if(je.isPathLike(p)){let E=await Ve.find(h,this.context.plugins,{useRc:!1,strict:!1}),{project:I,workspace:v}=await St.find(E,h);if(!v)throw new rr(I.cwd,h);if(this.all){for(let b of I.workspaces)b.manifest.name&&A.add(W.stringifyIdent(b.anchoredLocator));if(A.size===0)throw new it("No workspace found to be unlinked in the target project")}else{if(!v.manifest.name)throw new it("The target workspace doesn't have a name and thus cannot be unlinked");A.add(W.stringifyIdent(v.anchoredLocator))}}else{let E=[...u.manifest.resolutions.map(({pattern:I})=>I.descriptor.fullName)];for(let I of(0,lde.default)(E,p))A.add(I)}}return u.manifest.resolutions=u.manifest.resolutions.filter(({pattern:p})=>!A.has(p.descriptor.fullName)),await o.installWithNewReport({stdout:this.context.stdout,quiet:this.context.quiet},{cache:n})}};r0.paths=[["unlink"]],r0.usage=nt.Usage({description:"disconnect the local project from another one",details:` - This command will remove any resolutions in the project-level manifest that would have been added via a yarn link with similar arguments. - `,examples:[["Unregister a remote workspace in the current project","$0 unlink ~/ts-loader"],["Unregister all workspaces from a remote project in the current project","$0 unlink ~/jest --all"],["Unregister all previously linked workspaces","$0 unlink --all"],["Unregister all workspaces matching a glob","$0 unlink '@babel/*' 'pkg-{a,b}'"]]});Ye();Ye();Ye();qt();var cde=$e(A2()),G8=$e(Zo());Za();var Kf=class extends ut{constructor(){super(...arguments);this.interactive=ge.Boolean("-i,--interactive",{description:"Offer various choices, depending on the detected upgrade paths"});this.fixed=ge.Boolean("-F,--fixed",!1,{description:"Store dependency tags as-is instead of resolving them"});this.exact=ge.Boolean("-E,--exact",!1,{description:"Don't use any semver modifier on the resolved range"});this.tilde=ge.Boolean("-T,--tilde",!1,{description:"Use the `~` semver modifier on the resolved range"});this.caret=ge.Boolean("-C,--caret",!1,{description:"Use the `^` semver modifier on the resolved range"});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Resolve again ALL resolutions for those packages"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:Vs(pl)});this.patterns=ge.Rest()}async execute(){return this.recursive?await this.executeUpRecursive():await this.executeUpClassic()}async executeUpRecursive(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=[...o.storedDescriptors.values()],A=u.map(E=>W.stringifyIdent(E)),p=new Set;for(let E of this.patterns){if(W.parseDescriptor(E).range!=="unknown")throw new it("Ranges aren't allowed when using --recursive");for(let I of(0,G8.default)(A,E)){let v=W.parseIdent(I);p.add(v.identHash)}}let h=u.filter(E=>p.has(E.identHash));for(let E of h)o.storedDescriptors.delete(E.descriptorHash),o.storedResolutions.delete(E.descriptorHash);return await o.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})}async executeUpClassic(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=this.fixed,A=this.interactive??r.get("preferInteractive"),p=p2(this,o),h=A?["keep","reuse","project","latest"]:["project","latest"],E=[],I=[];for(let L of this.patterns){let U=!1,J=W.parseDescriptor(L),te=W.stringifyIdent(J);for(let le of o.workspaces)for(let pe of["dependencies","devDependencies"]){let ye=[...le.manifest.getForScope(pe).values()].map(we=>W.stringifyIdent(we)),ae=te==="*"?ye:(0,G8.default)(ye,te);for(let we of ae){let Pe=W.parseIdent(we),g=le.manifest[pe].get(Pe.identHash);if(typeof g>"u")throw new Error("Assertion failed: Expected the descriptor to be registered");let Ee=W.makeDescriptor(Pe,J.range);E.push(Promise.resolve().then(async()=>[le,pe,g,await h2(Ee,{project:o,workspace:le,cache:n,target:pe,fixed:u,modifier:p,strategies:h})])),U=!0}}U||I.push(L)}if(I.length>1)throw new it(`Patterns ${de.prettyList(r,I,de.Type.CODE)} don't match any packages referenced by any workspace`);if(I.length>0)throw new it(`Pattern ${de.prettyList(r,I,de.Type.CODE)} doesn't match any packages referenced by any workspace`);let v=await Promise.all(E),b=await AA.start({configuration:r,stdout:this.context.stdout,suggestInstall:!1},async L=>{for(let[,,U,{suggestions:J,rejections:te}]of v){let le=J.filter(pe=>pe.descriptor!==null);if(le.length===0){let[pe]=te;if(typeof pe>"u")throw new Error("Assertion failed: Expected an error to have been set");let Ae=this.cli.error(pe);o.configuration.get("enableNetwork")?L.reportError(27,`${W.prettyDescriptor(r,U)} can't be resolved to a satisfying range - -${Ae}`):L.reportError(27,`${W.prettyDescriptor(r,U)} can't be resolved to a satisfying range (note: network resolution has been disabled) - -${Ae}`)}else le.length>1&&!A&&L.reportError(27,`${W.prettyDescriptor(r,U)} has multiple possible upgrade strategies; use -i to disambiguate manually`)}});if(b.hasErrors())return b.exitCode();let C=!1,T=[];for(let[L,U,,{suggestions:J}]of v){let te,le=J.filter(ae=>ae.descriptor!==null),pe=le[0].descriptor,Ae=le.every(ae=>W.areDescriptorsEqual(ae.descriptor,pe));le.length===1||Ae?te=pe:(C=!0,{answer:te}=await(0,cde.prompt)({type:"select",name:"answer",message:`Which range do you want to use in ${W.prettyWorkspace(r,L)} \u276F ${U}?`,choices:J.map(({descriptor:ae,name:we,reason:Pe})=>ae?{name:we,hint:Pe,descriptor:ae}:{name:we,hint:Pe,disabled:!0}),onCancel:()=>process.exit(130),result(ae){return this.find(ae,"descriptor")},stdin:this.context.stdin,stdout:this.context.stdout}));let ye=L.manifest[U].get(te.identHash);if(typeof ye>"u")throw new Error("Assertion failed: This descriptor should have a matching entry");if(ye.descriptorHash!==te.descriptorHash)L.manifest[U].set(te.identHash,te),T.push([L,U,ye,te]);else{let ae=r.makeResolver(),we={project:o,resolver:ae},Pe=r.normalizeDependency(ye),g=ae.bindDescriptor(Pe,L.anchoredLocator,we);o.forgetResolution(g)}}return await r.triggerMultipleHooks(L=>L.afterWorkspaceDependencyReplacement,T),C&&this.context.stdout.write(` -`),await o.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})}};Kf.paths=[["up"]],Kf.usage=nt.Usage({description:"upgrade dependencies across the project",details:"\n This command upgrades the packages matching the list of specified patterns to their latest available version across the whole project (regardless of whether they're part of `dependencies` or `devDependencies` - `peerDependencies` won't be affected). This is a project-wide command: all workspaces will be upgraded in the process.\n\n If `-R,--recursive` is set the command will change behavior and no other switch will be allowed. When operating under this mode `yarn up` will force all ranges matching the selected packages to be resolved again (often to the highest available versions) before being stored in the lockfile. It however won't touch your manifests anymore, so depending on your needs you might want to run both `yarn up` and `yarn up -R` to cover all bases.\n\n If `-i,--interactive` is set (or if the `preferInteractive` settings is toggled on) the command will offer various choices, depending on the detected upgrade paths. Some upgrades require this flag in order to resolve ambiguities.\n\n The, `-C,--caret`, `-E,--exact` and `-T,--tilde` options have the same meaning as in the `add` command (they change the modifier used when the range is missing or a tag, and are ignored when the range is explicitly set).\n\n If the `--mode=` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\n\n - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\n\n - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\n\n Generally you can see `yarn up` as a counterpart to what was `yarn upgrade --latest` in Yarn 1 (ie it ignores the ranges previously listed in your manifests), but unlike `yarn upgrade` which only upgraded dependencies in the current workspace, `yarn up` will upgrade all workspaces at the same time.\n\n This command accepts glob patterns as arguments (if valid Descriptors and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\n\n **Note:** The ranges have to be static, only the package scopes and names can contain glob patterns.\n ",examples:[["Upgrade all instances of lodash to the latest release","$0 up lodash"],["Upgrade all instances of lodash to the latest release, but ask confirmation for each","$0 up lodash -i"],["Upgrade all instances of lodash to 1.2.3","$0 up lodash@1.2.3"],["Upgrade all instances of packages with the `@babel` scope to the latest release","$0 up '@babel/*'"],["Upgrade all instances of packages containing the word `jest` to the latest release","$0 up '*jest*'"],["Upgrade all instances of packages with the `@babel` scope to 7.0.0","$0 up '@babel/*@7.0.0'"]]}),Kf.schema=[lI("recursive",Gu.Forbids,["interactive","exact","tilde","caret"],{ignore:[void 0,!1]})];Ye();Ye();Ye();qt();var n0=class extends ut{constructor(){super(...arguments);this.recursive=ge.Boolean("-R,--recursive",!1,{description:"List, for each workspace, what are all the paths that lead to the dependency"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.peers=ge.Boolean("--peers",!1,{description:"Also print the peer dependencies that match the specified name"});this.package=ge.String()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState();let n=W.parseIdent(this.package).identHash,u=this.recursive?lgt(o,n,{configuration:r,peers:this.peers}):agt(o,n,{configuration:r,peers:this.peers});$s.emitTree(u,{configuration:r,stdout:this.context.stdout,json:this.json,separators:1})}};n0.paths=[["why"]],n0.usage=nt.Usage({description:"display the reason why a package is needed",details:` - This command prints the exact reasons why a package appears in the dependency tree. - - If \`-R,--recursive\` is set, the listing will go in depth and will list, for each workspaces, what are all the paths that lead to the dependency. Note that the display is somewhat optimized in that it will not print the package listing twice for a single package, so if you see a leaf named "Foo" when looking for "Bar", it means that "Foo" already got printed higher in the tree. - `,examples:[["Explain why lodash is used in your project","$0 why lodash"]]});function agt(t,e,{configuration:r,peers:o}){let a=je.sortMap(t.storedPackages.values(),A=>W.stringifyLocator(A)),n={},u={children:n};for(let A of a){let p={};for(let E of A.dependencies.values()){if(!o&&A.peerDependencies.has(E.identHash))continue;let I=t.storedResolutions.get(E.descriptorHash);if(!I)throw new Error("Assertion failed: The resolution should have been registered");let v=t.storedPackages.get(I);if(!v)throw new Error("Assertion failed: The package should have been registered");if(v.identHash!==e)continue;{let C=W.stringifyLocator(A);n[C]={value:[A,de.Type.LOCATOR],children:p}}let b=W.stringifyLocator(v);p[b]={value:[{descriptor:E,locator:v},de.Type.DEPENDENT]}}}return u}function lgt(t,e,{configuration:r,peers:o}){let a=je.sortMap(t.workspaces,v=>W.stringifyLocator(v.anchoredLocator)),n=new Set,u=new Set,A=v=>{if(n.has(v.locatorHash))return u.has(v.locatorHash);if(n.add(v.locatorHash),v.identHash===e)return u.add(v.locatorHash),!0;let b=!1;v.identHash===e&&(b=!0);for(let C of v.dependencies.values()){if(!o&&v.peerDependencies.has(C.identHash))continue;let T=t.storedResolutions.get(C.descriptorHash);if(!T)throw new Error("Assertion failed: The resolution should have been registered");let L=t.storedPackages.get(T);if(!L)throw new Error("Assertion failed: The package should have been registered");A(L)&&(b=!0)}return b&&u.add(v.locatorHash),b};for(let v of a)A(v.anchoredPackage);let p=new Set,h={},E={children:h},I=(v,b,C)=>{if(!u.has(v.locatorHash))return;let T=C!==null?de.tuple(de.Type.DEPENDENT,{locator:v,descriptor:C}):de.tuple(de.Type.LOCATOR,v),L={},U={value:T,children:L},J=W.stringifyLocator(v);if(b[J]=U,!p.has(v.locatorHash)&&(p.add(v.locatorHash),!(C!==null&&t.tryWorkspaceByLocator(v))))for(let te of v.dependencies.values()){if(!o&&v.peerDependencies.has(te.identHash))continue;let le=t.storedResolutions.get(te.descriptorHash);if(!le)throw new Error("Assertion failed: The resolution should have been registered");let pe=t.storedPackages.get(le);if(!pe)throw new Error("Assertion failed: The package should have been registered");I(pe,L,te)}};for(let v of a)I(v.anchoredPackage,h,null);return E}Ye();var eH={};Kt(eH,{GitFetcher:()=>C2,GitResolver:()=>w2,default:()=>bgt,gitUtils:()=>ra});Ye();Pt();var ra={};Kt(ra,{TreeishProtocols:()=>E2,clone:()=>$8,fetchBase:()=>Qde,fetchChangedFiles:()=>Fde,fetchChangedWorkspaces:()=>Sgt,fetchRoot:()=>kde,isGitUrl:()=>EC,lsRemote:()=>bde,normalizeLocator:()=>Pgt,normalizeRepoUrl:()=>mC,resolveUrl:()=>Z8,splitRepoUrl:()=>i0,validateRepoUrl:()=>X8});Ye();Pt();qt();var Pde=$e(Bde()),Sde=$e(EU()),yC=$e(Be("querystring")),J8=$e(zn());function K8(t,e,r){let o=t.indexOf(r);return t.lastIndexOf(e,o>-1?o:1/0)}function vde(t){try{return new URL(t)}catch{return}}function vgt(t){let e=K8(t,"@","#"),r=K8(t,":","#");return r>e&&(t=`${t.slice(0,r)}/${t.slice(r+1)}`),K8(t,":","#")===-1&&t.indexOf("//")===-1&&(t=`ssh://${t}`),t}function Dde(t){return vde(t)||vde(vgt(t))}function mC(t,{git:e=!1}={}){if(t=t.replace(/^git\+https:/,"https:"),t=t.replace(/^(?:github:|https:\/\/github\.com\/|git:\/\/github\.com\/)?(?!\.{1,2}\/)([a-zA-Z0-9._-]+)\/(?!\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)(?:\.git)?(#.*)?$/,"https://github.com/$1/$2.git$3"),t=t.replace(/^https:\/\/github\.com\/(?!\.{1,2}\/)([a-zA-Z0-9._-]+)\/(?!\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)\/tarball\/(.+)?$/,"https://github.com/$1/$2.git#$3"),e){let r=Dde(t);r&&(t=r.href),t=t.replace(/^git\+([^:]+):/,"$1:")}return t}function xde(){return{...process.env,GIT_SSH_COMMAND:process.env.GIT_SSH_COMMAND||`${process.env.GIT_SSH||"ssh"} -o BatchMode=yes`}}var Dgt=[/^ssh:/,/^git(?:\+[^:]+)?:/,/^(?:git\+)?https?:[^#]+\/[^#]+(?:\.git)(?:#.*)?$/,/^git@[^#]+\/[^#]+\.git(?:#.*)?$/,/^(?:github:|https:\/\/github\.com\/)?(?!\.{1,2}\/)([a-zA-Z._0-9-]+)\/(?!\.{1,2}(?:#|$))([a-zA-Z._0-9-]+?)(?:\.git)?(?:#.*)?$/,/^https:\/\/github\.com\/(?!\.{1,2}\/)([a-zA-Z0-9._-]+)\/(?!\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)\/tarball\/(.+)?$/],E2=(a=>(a.Commit="commit",a.Head="head",a.Tag="tag",a.Semver="semver",a))(E2||{});function EC(t){return t?Dgt.some(e=>!!t.match(e)):!1}function i0(t){t=mC(t);let e=t.indexOf("#");if(e===-1)return{repo:t,treeish:{protocol:"head",request:"HEAD"},extra:{}};let r=t.slice(0,e),o=t.slice(e+1);if(o.match(/^[a-z]+=/)){let a=yC.default.parse(o);for(let[p,h]of Object.entries(a))if(typeof h!="string")throw new Error(`Assertion failed: The ${p} parameter must be a literal string`);let n=Object.values(E2).find(p=>Object.hasOwn(a,p)),[u,A]=typeof n<"u"?[n,a[n]]:["head","HEAD"];for(let p of Object.values(E2))delete a[p];return{repo:r,treeish:{protocol:u,request:A},extra:a}}else{let a=o.indexOf(":"),[n,u]=a===-1?[null,o]:[o.slice(0,a),o.slice(a+1)];return{repo:r,treeish:{protocol:n,request:u},extra:{}}}}function Pgt(t){return W.makeLocator(t,mC(t.reference))}function X8(t,{configuration:e}){let r=mC(t,{git:!0});if(!rn.getNetworkSettings(`https://${(0,Pde.default)(r).resource}`,{configuration:e}).enableNetwork)throw new zt(80,`Request to '${r}' has been blocked because of your configuration settings`);return r}async function bde(t,e){let r=X8(t,{configuration:e}),o=await z8("listing refs",["ls-remote",r],{cwd:e.startingCwd,env:xde()},{configuration:e,normalizedRepoUrl:r}),a=new Map,n=/^([a-f0-9]{40})\t([^\n]+)/gm,u;for(;(u=n.exec(o.stdout))!==null;)a.set(u[2],u[1]);return a}async function Z8(t,e){let{repo:r,treeish:{protocol:o,request:a},extra:n}=i0(t),u=await bde(r,e),A=(h,E)=>{switch(h){case"commit":{if(!E.match(/^[a-f0-9]{40}$/))throw new Error("Invalid commit hash");return yC.default.stringify({...n,commit:E})}case"head":{let I=u.get(E==="HEAD"?E:`refs/heads/${E}`);if(typeof I>"u")throw new Error(`Unknown head ("${E}")`);return yC.default.stringify({...n,commit:I})}case"tag":{let I=u.get(`refs/tags/${E}`);if(typeof I>"u")throw new Error(`Unknown tag ("${E}")`);return yC.default.stringify({...n,commit:I})}case"semver":{let I=kr.validRange(E);if(!I)throw new Error(`Invalid range ("${E}")`);let v=new Map([...u.entries()].filter(([C])=>C.startsWith("refs/tags/")).map(([C,T])=>[J8.default.parse(C.slice(10)),T]).filter(C=>C[0]!==null)),b=J8.default.maxSatisfying([...v.keys()],I);if(b===null)throw new Error(`No matching range ("${E}")`);return yC.default.stringify({...n,commit:v.get(b)})}case null:{let I;if((I=p("commit",E))!==null||(I=p("tag",E))!==null||(I=p("head",E))!==null)return I;throw E.match(/^[a-f0-9]+$/)?new Error(`Couldn't resolve "${E}" as either a commit, a tag, or a head - if a commit, use the 40-characters commit hash`):new Error(`Couldn't resolve "${E}" as either a commit, a tag, or a head`)}default:throw new Error(`Invalid Git resolution protocol ("${h}")`)}},p=(h,E)=>{try{return A(h,E)}catch{return null}};return mC(`${r}#${A(o,a)}`)}async function $8(t,e){return await e.getLimit("cloneConcurrency")(async()=>{let{repo:r,treeish:{protocol:o,request:a}}=i0(t);if(o!=="commit")throw new Error("Invalid treeish protocol when cloning");let n=X8(r,{configuration:e}),u=await oe.mktempPromise(),A={cwd:u,env:xde()};return await z8("cloning the repository",["clone","-c core.autocrlf=false",n,ue.fromPortablePath(u)],A,{configuration:e,normalizedRepoUrl:n}),await z8("switching branch",["checkout",`${a}`],A,{configuration:e,normalizedRepoUrl:n}),u})}async function kde(t){let e,r=t;do{if(e=r,await oe.existsPromise(K.join(e,".git")))return e;r=K.dirname(e)}while(r!==e);return null}async function Qde(t,{baseRefs:e}){if(e.length===0)throw new it("Can't run this command with zero base refs specified.");let r=[];for(let A of e){let{code:p}=await Ur.execvp("git",["merge-base",A,"HEAD"],{cwd:t});p===0&&r.push(A)}if(r.length===0)throw new it(`No ancestor could be found between any of HEAD and ${e.join(", ")}`);let{stdout:o}=await Ur.execvp("git",["merge-base","HEAD",...r],{cwd:t,strict:!0}),a=o.trim(),{stdout:n}=await Ur.execvp("git",["show","--quiet","--pretty=format:%s",a],{cwd:t,strict:!0}),u=n.trim();return{hash:a,title:u}}async function Fde(t,{base:e,project:r}){let o=je.buildIgnorePattern(r.configuration.get("changesetIgnorePatterns")),{stdout:a}=await Ur.execvp("git",["diff","--name-only",`${e}`],{cwd:t,strict:!0}),n=a.split(/\r\n|\r|\n/).filter(h=>h.length>0).map(h=>K.resolve(t,ue.toPortablePath(h))),{stdout:u}=await Ur.execvp("git",["ls-files","--others","--exclude-standard"],{cwd:t,strict:!0}),A=u.split(/\r\n|\r|\n/).filter(h=>h.length>0).map(h=>K.resolve(t,ue.toPortablePath(h))),p=[...new Set([...n,...A].sort())];return o?p.filter(h=>!K.relative(r.cwd,h).match(o)):p}async function Sgt({ref:t,project:e}){if(e.configuration.projectCwd===null)throw new it("This command can only be run from within a Yarn project");let r=[K.resolve(e.cwd,dr.lockfile),K.resolve(e.cwd,e.configuration.get("cacheFolder")),K.resolve(e.cwd,e.configuration.get("installStatePath")),K.resolve(e.cwd,e.configuration.get("virtualFolder"))];await e.configuration.triggerHook(u=>u.populateYarnPaths,e,u=>{u!=null&&r.push(u)});let o=await kde(e.configuration.projectCwd);if(o==null)throw new it("This command can only be run on Git repositories");let a=await Qde(o,{baseRefs:typeof t=="string"?[t]:e.configuration.get("changesetBaseRefs")}),n=await Fde(o,{base:a.hash,project:e});return new Set(je.mapAndFilter(n,u=>{let A=e.tryWorkspaceByFilePath(u);return A===null?je.mapAndFilter.skip:r.some(p=>u.startsWith(p))?je.mapAndFilter.skip:A}))}async function z8(t,e,r,{configuration:o,normalizedRepoUrl:a}){try{return await Ur.execvp("git",e,{...r,strict:!0})}catch(n){if(!(n instanceof Ur.ExecError))throw n;let u=n.reportExtra,A=n.stderr.toString();throw new zt(1,`Failed ${t}`,p=>{p.reportError(1,` ${de.prettyField(o,{label:"Repository URL",value:de.tuple(de.Type.URL,a)})}`);for(let h of A.matchAll(/^(.+?): (.*)$/gm)){let[,E,I]=h;E=E.toLowerCase();let v=E==="error"?"Error":`${(0,Sde.default)(E)} Error`;p.reportError(1,` ${de.prettyField(o,{label:v,value:de.tuple(de.Type.NO_HINT,I)})}`)}u?.(p)})}}var C2=class{supports(e,r){return EC(e.reference)}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,a=new Map(r.checksums);a.set(e.locatorHash,o);let n={...r,checksums:a},u=await this.downloadHosted(e,n);if(u!==null)return u;let[A,p,h]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote repository`),loader:()=>this.cloneFromRemote(e,n),...r.cacheOptions});return{packageFs:A,releaseFs:p,prefixPath:W.getIdentVendorPath(e),checksum:h}}async downloadHosted(e,r){return r.project.configuration.reduceHook(o=>o.fetchHostedRepository,null,e,r)}async cloneFromRemote(e,r){let o=await $8(e.reference,r.project.configuration),a=i0(e.reference),n=K.join(o,"package.tgz");await un.prepareExternalProject(o,n,{configuration:r.project.configuration,report:r.report,workspace:a.extra.workspace,locator:e});let u=await oe.readFilePromise(n);return await je.releaseAfterUseAsync(async()=>await Xi.convertToZip(u,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1}))}};Ye();Ye();var w2=class{supportsDescriptor(e,r){return EC(e.range)}supportsLocator(e,r){return EC(e.reference)}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=await Z8(e.range,o.project.configuration);return[W.makeLocator(e,a)]}async getSatisfying(e,r,o,a){let n=i0(e.range);return{locators:o.filter(A=>{if(A.identHash!==e.identHash)return!1;let p=i0(A.reference);return!(n.repo!==p.repo||n.treeish.protocol==="commit"&&n.treeish.request!==p.treeish.request)}),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Mt.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"HARD",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var xgt={configuration:{changesetBaseRefs:{description:"The base git refs that the current HEAD is compared against when detecting changes. Supports git branches, tags, and commits.",type:"STRING",isArray:!0,isNullable:!1,default:["master","origin/master","upstream/master","main","origin/main","upstream/main"]},changesetIgnorePatterns:{description:"Array of glob patterns; files matching them will be ignored when fetching the changed files",type:"STRING",default:[],isArray:!0},cloneConcurrency:{description:"Maximal number of concurrent clones",type:"NUMBER",default:2}},fetchers:[C2],resolvers:[w2]};var bgt=xgt;qt();var s0=class extends ut{constructor(){super(...arguments);this.since=ge.String("--since",{description:"Only include workspaces that have been changed since the specified ref.",tolerateBoolean:!0});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Find packages via dependencies/devDependencies instead of using the workspaces field"});this.noPrivate=ge.Boolean("--no-private",{description:"Exclude workspaces that have the private field set to true"});this.verbose=ge.Boolean("-v,--verbose",!1,{description:"Also return the cross-dependencies between workspaces"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd);return(await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout},async n=>{let u=this.since?await ra.fetchChangedWorkspaces({ref:this.since,project:o}):o.workspaces,A=new Set(u);if(this.recursive)for(let p of[...u].map(h=>h.getRecursiveWorkspaceDependents()))for(let h of p)A.add(h);for(let p of A){let{manifest:h}=p;if(h.private&&this.noPrivate)continue;let E;if(this.verbose){let I=new Set,v=new Set;for(let b of Mt.hardDependencies)for(let[C,T]of h.getForScope(b)){let L=o.tryWorkspaceByDescriptor(T);L===null?o.workspacesByIdent.has(C)&&v.add(T):I.add(L)}E={workspaceDependencies:Array.from(I).map(b=>b.relativeCwd),mismatchedWorkspaceDependencies:Array.from(v).map(b=>W.stringifyDescriptor(b))}}n.reportInfo(null,`${p.relativeCwd}`),n.reportJson({location:p.relativeCwd,name:h.name?W.stringifyIdent(h.name):null,...E})}})).exitCode()}};s0.paths=[["workspaces","list"]],s0.usage=nt.Usage({category:"Workspace-related commands",description:"list all available workspaces",details:"\n This command will print the list of all workspaces in the project.\n\n - If `--since` is set, Yarn will only list workspaces that have been modified since the specified ref. By default Yarn will use the refs specified by the `changesetBaseRefs` configuration option.\n\n - If `-R,--recursive` is set, Yarn will find workspaces to run the command on by recursively evaluating `dependencies` and `devDependencies` fields, instead of looking at the `workspaces` fields.\n\n - If `--no-private` is set, Yarn will not list any workspaces that have the `private` field set to `true`.\n\n - If both the `-v,--verbose` and `--json` options are set, Yarn will also return the cross-dependencies between each workspaces (useful when you wish to automatically generate Buck / Bazel rules).\n "});Ye();Ye();qt();var o0=class extends ut{constructor(){super(...arguments);this.workspaceName=ge.String();this.commandName=ge.String();this.args=ge.Proxy()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);let n=o.workspaces,u=new Map(n.map(p=>[W.stringifyIdent(p.anchoredLocator),p])),A=u.get(this.workspaceName);if(A===void 0){let p=Array.from(u.keys()).sort();throw new it(`Workspace '${this.workspaceName}' not found. Did you mean any of the following: - - ${p.join(` - - `)}?`)}return this.cli.run([this.commandName,...this.args],{cwd:A.cwd})}};o0.paths=[["workspace"]],o0.usage=nt.Usage({category:"Workspace-related commands",description:"run a command within the specified workspace",details:` - This command will run a given sub-command on a single workspace. - `,examples:[["Add a package to a single workspace","yarn workspace components add -D react"],["Run build script on a single workspace","yarn workspace components run build"]]});var kgt={configuration:{enableImmutableInstalls:{description:"If true (the default on CI), prevents the install command from modifying the lockfile",type:"BOOLEAN",default:Tde.isCI},defaultSemverRangePrefix:{description:"The default save prefix: '^', '~' or ''",type:"STRING",values:["^","~",""],default:"^"},preferReuse:{description:"If true, `yarn add` will attempt to reuse the most common dependency range in other workspaces.",type:"BOOLEAN",default:!1}},commands:[Qh,Fh,Th,Rh,t0,Vh,Uh,s0,Wd,Vd,dC,Kd,bh,kh,Nh,Lh,Mh,Oh,_h,Hh,jh,qh,r0,Gh,Yh,Jh,Kh,zh,Wh,Xh,Zh,$h,zd,e0,Kf,n0,o0]},Qgt=kgt;var oH={};Kt(oH,{default:()=>Tgt});Ye();var kt={optional:!0},rH=[["@tailwindcss/aspect-ratio@<0.2.1",{peerDependencies:{tailwindcss:"^2.0.2"}}],["@tailwindcss/line-clamp@<0.2.1",{peerDependencies:{tailwindcss:"^2.0.2"}}],["@fullhuman/postcss-purgecss@3.1.3 || 3.1.3-alpha.0",{peerDependencies:{postcss:"^8.0.0"}}],["@samverschueren/stream-to-observable@<0.3.1",{peerDependenciesMeta:{rxjs:kt,zenObservable:kt}}],["any-observable@<0.5.1",{peerDependenciesMeta:{rxjs:kt,zenObservable:kt}}],["@pm2/agent@<1.0.4",{dependencies:{debug:"*"}}],["debug@<4.2.0",{peerDependenciesMeta:{["supports-color"]:kt}}],["got@<11",{dependencies:{["@types/responselike"]:"^1.0.0",["@types/keyv"]:"^3.1.1"}}],["cacheable-lookup@<4.1.2",{dependencies:{["@types/keyv"]:"^3.1.1"}}],["http-link-dataloader@*",{peerDependencies:{graphql:"^0.13.1 || ^14.0.0"}}],["typescript-language-server@*",{dependencies:{["vscode-jsonrpc"]:"^5.0.1",["vscode-languageserver-protocol"]:"^3.15.0"}}],["postcss-syntax@*",{peerDependenciesMeta:{["postcss-html"]:kt,["postcss-jsx"]:kt,["postcss-less"]:kt,["postcss-markdown"]:kt,["postcss-scss"]:kt}}],["jss-plugin-rule-value-function@<=10.1.1",{dependencies:{["tiny-warning"]:"^1.0.2"}}],["ink-select-input@<4.1.0",{peerDependencies:{react:"^16.8.2"}}],["license-webpack-plugin@<2.3.18",{peerDependenciesMeta:{webpack:kt}}],["snowpack@>=3.3.0",{dependencies:{["node-gyp"]:"^7.1.0"}}],["promise-inflight@*",{peerDependenciesMeta:{bluebird:kt}}],["reactcss@*",{peerDependencies:{react:"*"}}],["react-color@<=2.19.0",{peerDependencies:{react:"*"}}],["gatsby-plugin-i18n@*",{dependencies:{ramda:"^0.24.1"}}],["useragent@^2.0.0",{dependencies:{request:"^2.88.0",yamlparser:"0.0.x",semver:"5.5.x"}}],["@apollographql/apollo-tools@<=0.5.2",{peerDependencies:{graphql:"^14.2.1 || ^15.0.0"}}],["material-table@^2.0.0",{dependencies:{"@babel/runtime":"^7.11.2"}}],["@babel/parser@*",{dependencies:{"@babel/types":"^7.8.3"}}],["fork-ts-checker-webpack-plugin@<=6.3.4",{peerDependencies:{eslint:">= 6",typescript:">= 2.7",webpack:">= 4","vue-template-compiler":"*"},peerDependenciesMeta:{eslint:kt,"vue-template-compiler":kt}}],["rc-animate@<=3.1.1",{peerDependencies:{react:">=16.9.0","react-dom":">=16.9.0"}}],["react-bootstrap-table2-paginator@*",{dependencies:{classnames:"^2.2.6"}}],["react-draggable@<=4.4.3",{peerDependencies:{react:">= 16.3.0","react-dom":">= 16.3.0"}}],["apollo-upload-client@<14",{peerDependencies:{graphql:"14 - 15"}}],["react-instantsearch-core@<=6.7.0",{peerDependencies:{algoliasearch:">= 3.1 < 5"}}],["react-instantsearch-dom@<=6.7.0",{dependencies:{"react-fast-compare":"^3.0.0"}}],["ws@<7.2.1",{peerDependencies:{bufferutil:"^4.0.1","utf-8-validate":"^5.0.2"},peerDependenciesMeta:{bufferutil:kt,"utf-8-validate":kt}}],["react-portal@<4.2.2",{peerDependencies:{"react-dom":"^15.0.0-0 || ^16.0.0-0 || ^17.0.0-0"}}],["react-scripts@<=4.0.1",{peerDependencies:{react:"*"}}],["testcafe@<=1.10.1",{dependencies:{"@babel/plugin-transform-for-of":"^7.12.1","@babel/runtime":"^7.12.5"}}],["testcafe-legacy-api@<=4.2.0",{dependencies:{"testcafe-hammerhead":"^17.0.1","read-file-relative":"^1.2.0"}}],["@google-cloud/firestore@<=4.9.3",{dependencies:{protobufjs:"^6.8.6"}}],["gatsby-source-apiserver@*",{dependencies:{["babel-polyfill"]:"^6.26.0"}}],["@webpack-cli/package-utils@<=1.0.1-alpha.4",{dependencies:{["cross-spawn"]:"^7.0.3"}}],["gatsby-remark-prismjs@<3.3.28",{dependencies:{lodash:"^4"}}],["gatsby-plugin-favicon@*",{peerDependencies:{webpack:"*"}}],["gatsby-plugin-sharp@<=4.6.0-next.3",{dependencies:{debug:"^4.3.1"}}],["gatsby-react-router-scroll@<=5.6.0-next.0",{dependencies:{["prop-types"]:"^15.7.2"}}],["@rebass/forms@*",{dependencies:{["@styled-system/should-forward-prop"]:"^5.0.0"},peerDependencies:{react:"^16.8.6"}}],["rebass@*",{peerDependencies:{react:"^16.8.6"}}],["@ant-design/react-slick@<=0.28.3",{peerDependencies:{react:">=16.0.0"}}],["mqtt@<4.2.7",{dependencies:{duplexify:"^4.1.1"}}],["vue-cli-plugin-vuetify@<=2.0.3",{dependencies:{semver:"^6.3.0"},peerDependenciesMeta:{"sass-loader":kt,"vuetify-loader":kt}}],["vue-cli-plugin-vuetify@<=2.0.4",{dependencies:{"null-loader":"^3.0.0"}}],["vue-cli-plugin-vuetify@>=2.4.3",{peerDependencies:{vue:"*"}}],["@vuetify/cli-plugin-utils@<=0.0.4",{dependencies:{semver:"^6.3.0"},peerDependenciesMeta:{"sass-loader":kt}}],["@vue/cli-plugin-typescript@<=5.0.0-alpha.0",{dependencies:{"babel-loader":"^8.1.0"}}],["@vue/cli-plugin-typescript@<=5.0.0-beta.0",{dependencies:{"@babel/core":"^7.12.16"},peerDependencies:{"vue-template-compiler":"^2.0.0"},peerDependenciesMeta:{"vue-template-compiler":kt}}],["cordova-ios@<=6.3.0",{dependencies:{underscore:"^1.9.2"}}],["cordova-lib@<=10.0.1",{dependencies:{underscore:"^1.9.2"}}],["git-node-fs@*",{peerDependencies:{"js-git":"^0.7.8"},peerDependenciesMeta:{"js-git":kt}}],["consolidate@<0.16.0",{peerDependencies:{mustache:"^3.0.0"},peerDependenciesMeta:{mustache:kt}}],["consolidate@<=0.16.0",{peerDependencies:{velocityjs:"^2.0.1",tinyliquid:"^0.2.34","liquid-node":"^3.0.1",jade:"^1.11.0","then-jade":"*",dust:"^0.3.0","dustjs-helpers":"^1.7.4","dustjs-linkedin":"^2.7.5",swig:"^1.4.2","swig-templates":"^2.0.3","razor-tmpl":"^1.3.1",atpl:">=0.7.6",liquor:"^0.0.5",twig:"^1.15.2",ejs:"^3.1.5",eco:"^1.1.0-rc-3",jazz:"^0.0.18",jqtpl:"~1.1.0",hamljs:"^0.6.2",hamlet:"^0.3.3",whiskers:"^0.4.0","haml-coffee":"^1.14.1","hogan.js":"^3.0.2",templayed:">=0.2.3",handlebars:"^4.7.6",underscore:"^1.11.0",lodash:"^4.17.20",pug:"^3.0.0","then-pug":"*",qejs:"^3.0.5",walrus:"^0.10.1",mustache:"^4.0.1",just:"^0.1.8",ect:"^0.5.9",mote:"^0.2.0",toffee:"^0.3.6",dot:"^1.1.3","bracket-template":"^1.1.5",ractive:"^1.3.12",nunjucks:"^3.2.2",htmling:"^0.0.8","babel-core":"^6.26.3",plates:"~0.4.11","react-dom":"^16.13.1",react:"^16.13.1","arc-templates":"^0.5.3",vash:"^0.13.0",slm:"^2.0.0",marko:"^3.14.4",teacup:"^2.0.0","coffee-script":"^1.12.7",squirrelly:"^5.1.0",twing:"^5.0.2"},peerDependenciesMeta:{velocityjs:kt,tinyliquid:kt,"liquid-node":kt,jade:kt,"then-jade":kt,dust:kt,"dustjs-helpers":kt,"dustjs-linkedin":kt,swig:kt,"swig-templates":kt,"razor-tmpl":kt,atpl:kt,liquor:kt,twig:kt,ejs:kt,eco:kt,jazz:kt,jqtpl:kt,hamljs:kt,hamlet:kt,whiskers:kt,"haml-coffee":kt,"hogan.js":kt,templayed:kt,handlebars:kt,underscore:kt,lodash:kt,pug:kt,"then-pug":kt,qejs:kt,walrus:kt,mustache:kt,just:kt,ect:kt,mote:kt,toffee:kt,dot:kt,"bracket-template":kt,ractive:kt,nunjucks:kt,htmling:kt,"babel-core":kt,plates:kt,"react-dom":kt,react:kt,"arc-templates":kt,vash:kt,slm:kt,marko:kt,teacup:kt,"coffee-script":kt,squirrelly:kt,twing:kt}}],["vue-loader@<=16.3.3",{peerDependencies:{"@vue/compiler-sfc":"^3.0.8",webpack:"^4.1.0 || ^5.0.0-0"},peerDependenciesMeta:{"@vue/compiler-sfc":kt}}],["vue-loader@^16.7.0",{peerDependencies:{"@vue/compiler-sfc":"^3.0.8",vue:"^3.2.13"},peerDependenciesMeta:{"@vue/compiler-sfc":kt,vue:kt}}],["scss-parser@<=1.0.5",{dependencies:{lodash:"^4.17.21"}}],["query-ast@<1.0.5",{dependencies:{lodash:"^4.17.21"}}],["redux-thunk@<=2.3.0",{peerDependencies:{redux:"^4.0.0"}}],["skypack@<=0.3.2",{dependencies:{tar:"^6.1.0"}}],["@npmcli/metavuln-calculator@<2.0.0",{dependencies:{"json-parse-even-better-errors":"^2.3.1"}}],["bin-links@<2.3.0",{dependencies:{"mkdirp-infer-owner":"^1.0.2"}}],["rollup-plugin-polyfill-node@<=0.8.0",{peerDependencies:{rollup:"^1.20.0 || ^2.0.0"}}],["snowpack@<3.8.6",{dependencies:{"magic-string":"^0.25.7"}}],["elm-webpack-loader@*",{dependencies:{temp:"^0.9.4"}}],["winston-transport@<=4.4.0",{dependencies:{logform:"^2.2.0"}}],["jest-vue-preprocessor@*",{dependencies:{"@babel/core":"7.8.7","@babel/template":"7.8.6"},peerDependencies:{pug:"^2.0.4"},peerDependenciesMeta:{pug:kt}}],["redux-persist@*",{peerDependencies:{react:">=16"},peerDependenciesMeta:{react:kt}}],["sodium@>=3",{dependencies:{"node-gyp":"^3.8.0"}}],["babel-plugin-graphql-tag@<=3.1.0",{peerDependencies:{graphql:"^14.0.0 || ^15.0.0"}}],["@playwright/test@<=1.14.1",{dependencies:{"jest-matcher-utils":"^26.4.2"}}],...["babel-plugin-remove-graphql-queries@<3.14.0-next.1","babel-preset-gatsby-package@<1.14.0-next.1","create-gatsby@<1.14.0-next.1","gatsby-admin@<0.24.0-next.1","gatsby-cli@<3.14.0-next.1","gatsby-core-utils@<2.14.0-next.1","gatsby-design-tokens@<3.14.0-next.1","gatsby-legacy-polyfills@<1.14.0-next.1","gatsby-plugin-benchmark-reporting@<1.14.0-next.1","gatsby-plugin-graphql-config@<0.23.0-next.1","gatsby-plugin-image@<1.14.0-next.1","gatsby-plugin-mdx@<2.14.0-next.1","gatsby-plugin-netlify-cms@<5.14.0-next.1","gatsby-plugin-no-sourcemaps@<3.14.0-next.1","gatsby-plugin-page-creator@<3.14.0-next.1","gatsby-plugin-preact@<5.14.0-next.1","gatsby-plugin-preload-fonts@<2.14.0-next.1","gatsby-plugin-schema-snapshot@<2.14.0-next.1","gatsby-plugin-styletron@<6.14.0-next.1","gatsby-plugin-subfont@<3.14.0-next.1","gatsby-plugin-utils@<1.14.0-next.1","gatsby-recipes@<0.25.0-next.1","gatsby-source-shopify@<5.6.0-next.1","gatsby-source-wikipedia@<3.14.0-next.1","gatsby-transformer-screenshot@<3.14.0-next.1","gatsby-worker@<0.5.0-next.1"].map(t=>[t,{dependencies:{"@babel/runtime":"^7.14.8"}}]),["gatsby-core-utils@<2.14.0-next.1",{dependencies:{got:"8.3.2"}}],["gatsby-plugin-gatsby-cloud@<=3.1.0-next.0",{dependencies:{"gatsby-core-utils":"^2.13.0-next.0"}}],["gatsby-plugin-gatsby-cloud@<=3.2.0-next.1",{peerDependencies:{webpack:"*"}}],["babel-plugin-remove-graphql-queries@<=3.14.0-next.1",{dependencies:{"gatsby-core-utils":"^2.8.0-next.1"}}],["gatsby-plugin-netlify@3.13.0-next.1",{dependencies:{"gatsby-core-utils":"^2.13.0-next.0"}}],["clipanion-v3-codemod@<=0.2.0",{peerDependencies:{jscodeshift:"^0.11.0"}}],["react-live@*",{peerDependencies:{"react-dom":"*",react:"*"}}],["webpack@<4.44.1",{peerDependenciesMeta:{"webpack-cli":kt,"webpack-command":kt}}],["webpack@<5.0.0-beta.23",{peerDependenciesMeta:{"webpack-cli":kt}}],["webpack-dev-server@<3.10.2",{peerDependenciesMeta:{"webpack-cli":kt}}],["@docusaurus/responsive-loader@<1.5.0",{peerDependenciesMeta:{sharp:kt,jimp:kt}}],["eslint-module-utils@*",{peerDependenciesMeta:{"eslint-import-resolver-node":kt,"eslint-import-resolver-typescript":kt,"eslint-import-resolver-webpack":kt,"@typescript-eslint/parser":kt}}],["eslint-plugin-import@*",{peerDependenciesMeta:{"@typescript-eslint/parser":kt}}],["critters-webpack-plugin@<3.0.2",{peerDependenciesMeta:{"html-webpack-plugin":kt}}],["terser@<=5.10.0",{dependencies:{acorn:"^8.5.0"}}],["babel-preset-react-app@10.0.x",{dependencies:{"@babel/plugin-proposal-private-property-in-object":"^7.16.0"}}],["eslint-config-react-app@*",{peerDependenciesMeta:{typescript:kt}}],["@vue/eslint-config-typescript@<11.0.0",{peerDependenciesMeta:{typescript:kt}}],["unplugin-vue2-script-setup@<0.9.1",{peerDependencies:{"@vue/composition-api":"^1.4.3","@vue/runtime-dom":"^3.2.26"}}],["@cypress/snapshot@*",{dependencies:{debug:"^3.2.7"}}],["auto-relay@<=0.14.0",{peerDependencies:{"reflect-metadata":"^0.1.13"}}],["vue-template-babel-compiler@<1.2.0",{peerDependencies:{["vue-template-compiler"]:"^2.6.0"}}],["@parcel/transformer-image@<2.5.0",{peerDependencies:{["@parcel/core"]:"*"}}],["@parcel/transformer-js@<2.5.0",{peerDependencies:{["@parcel/core"]:"*"}}],["parcel@*",{peerDependenciesMeta:{["@parcel/core"]:kt}}],["react-scripts@*",{peerDependencies:{eslint:"*"}}],["focus-trap-react@^8.0.0",{dependencies:{tabbable:"^5.3.2"}}],["react-rnd@<10.3.7",{peerDependencies:{react:">=16.3.0","react-dom":">=16.3.0"}}],["connect-mongo@*",{peerDependencies:{"express-session":"^1.17.1"}}],["vue-i18n@<9",{peerDependencies:{vue:"^2"}}],["vue-router@<4",{peerDependencies:{vue:"^2"}}],["unified@<10",{dependencies:{"@types/unist":"^2.0.0"}}],["react-github-btn@<=1.3.0",{peerDependencies:{react:">=16.3.0"}}],["react-dev-utils@*",{peerDependencies:{typescript:">=2.7",webpack:">=4"},peerDependenciesMeta:{typescript:kt}}],["@asyncapi/react-component@<=1.0.0-next.39",{peerDependencies:{react:">=16.8.0","react-dom":">=16.8.0"}}],["xo@*",{peerDependencies:{webpack:">=1.11.0"},peerDependenciesMeta:{webpack:kt}}],["babel-plugin-remove-graphql-queries@<=4.20.0-next.0",{dependencies:{"@babel/types":"^7.15.4"}}],["gatsby-plugin-page-creator@<=4.20.0-next.1",{dependencies:{"fs-extra":"^10.1.0"}}],["gatsby-plugin-utils@<=3.14.0-next.1",{dependencies:{fastq:"^1.13.0"},peerDependencies:{graphql:"^15.0.0"}}],["gatsby-plugin-mdx@<3.1.0-next.1",{dependencies:{mkdirp:"^1.0.4"}}],["gatsby-plugin-mdx@^2",{peerDependencies:{gatsby:"^3.0.0-next"}}],["fdir@<=5.2.0",{peerDependencies:{picomatch:"2.x"},peerDependenciesMeta:{picomatch:kt}}],["babel-plugin-transform-typescript-metadata@<=0.3.2",{peerDependencies:{"@babel/core":"^7","@babel/traverse":"^7"},peerDependenciesMeta:{"@babel/traverse":kt}}],["graphql-compose@>=9.0.10",{peerDependencies:{graphql:"^14.2.0 || ^15.0.0 || ^16.0.0"}}]];var nH;function Rde(){return typeof nH>"u"&&(nH=Be("zlib").brotliDecompressSync(Buffer.from("G7weAByFTVk3Vs7UfHhq4yykgEM7pbW7TI43SG2S5tvGrwHBAzdz+s/npQ6tgEvobvxisrPIadkXeUAJotBn5bDZ5kAhcRqsIHe3F75Walet5hNalwgFDtxb0BiDUjiUQkjG0yW2hto9HPgiCkm316d6bC0kST72YN7D7rfkhCE9x4J0XwB0yavalxpUu2t9xszHrmtwalOxT7VslsxWcB1qpqZwERUra4psWhTV8BgwWeizurec82Caf1ABL11YMfbf8FJ9JBceZOkgmvrQPbC9DUldX/yMbmX06UQluCEjSwUoyO+EZPIjofr+/oAZUck2enraRD+oWLlnlYnj8xB+gwSo9lmmks4fXv574qSqcWA6z21uYkzMu3EWj+K23RxeQlLqiE35/rC8GcS4CGkKHKKq+zAIQwD9iRDNfiAqueLLpicFFrNsAI4zeTD/eO9MHcnRa5m8UT+M2+V+AkFST4BlKneiAQRSdST8KEAIyFlULt6wa9EBd0Ds28VmpaxquJdVt+nwdEs5xUskI13OVtFyY0UrQIRAlCuvvWivvlSKQfTO+2Q8OyUR1W5RvetaPz4jD27hdtwHFFA1Ptx6Ee/t2cY2rg2G46M1pNDRf2pWhvpy8pqMnuI3++4OF3+7OFIWXGjh+o7Nr2jNvbiYcQdQS1h903/jVFgOpA0yJ78z+x759bFA0rq+6aY5qPB4FzS3oYoLupDUhD9nDz6F6H7hpnlMf18KNKDu4IKjTWwrAnY6MFQw1W6ymOALHlFyCZmQhldg1MQHaMVVQTVgDC60TfaBqG++Y8PEoFhN/PBTZT175KNP/BlHDYGOOBmnBdzqJKplZ/ljiVG0ZBzfqeBRrrUkn6rA54462SgiliKoYVnbeptMdXNfAuaupIEi0bApF10TlgHfmEJAPUVidRVFyDupSem5po5vErPqWKhKbUIp0LozpYsIKK57dM/HKr+nguF+7924IIWMICkQ8JUigs9D+W+c4LnNoRtPPKNRUiCYmP+Jfo2lfKCKw8qpraEeWU3uiNRO6zcyKQoXPR5htmzzLznke7b4YbXW3I1lIRzmgG02Udb58U+7TpwyN7XymCgH+wuPDthZVQvRZuEP+SnLtMicz9m5zASWOBiAcLmkuFlTKuHspSIhCBD0yUPKcxu81A+4YD78rA2vtwsUEday9WNyrShyrl60rWmA+SmbYZkQOwFJWArxRYYc5jGhA5ikxYw1rx3ei4NmeX/lKiwpZ9Ln1tV2Ae7sArvxuVLbJjqJRjW1vFXAyHpvLG+8MJ6T2Ubx5M2KDa2SN6vuIGxJ9WQM9Mk3Q7aCNiZONXllhqq24DmoLbQfW2rYWsOgHWjtOmIQMyMKdiHZDjoyIq5+U700nZ6odJAoYXPQBvFNiQ78d5jaXliBqLTJEqUCwi+LiH2mx92EmNKDsJL74Z613+3lf20pxkV1+erOrjj8pW00vsPaahKUM+05ssd5uwM7K482KWEf3TCwlg/o3e5ngto7qSMz7YteIgCsF1UOcsLk7F7MxWbvrPMY473ew0G+noVL8EPbkmEMftMSeL6HFub/zy+2JQ==","base64")).toString()),nH}var iH;function Nde(){return typeof iH>"u"&&(iH=Be("zlib").brotliDecompressSync(Buffer.from("G8MSIIzURnVBnObTcvb3XE6v2S9Qgc2K801Oa5otNKEtK8BINZNcaQHy+9/vf/WXBimwutXC33P2DPc64pps5rz7NGGWaOKNSPL4Y2KRE8twut2lFOIN+OXPtRmPMRhMTILib2bEQx43az2I5d3YS8Roa5UZpF/ujHb3Djd3GDvYUfvFYSUQ39vb2cmifp/rgB4J/65JK3wRBTvMBoNBmn3mbXC63/gbBkW/2IRPri0O8bcsRBsmarF328pAln04nyJFkwUAvNu934supAqLtyerZZpJ8I8suJHhf/ocMV+scKwa8NOiDKIPXw6Ex/EEZD6TEGaW8N5zvNHYF10l6Lfooj7D5W2k3dgvQSbp2Wv8TGOayS978gxlOLVjTGXs66ozewbrjwElLtyrYNnWTfzzdEutgROUFPVMhnMoy8EjJLLlWwIEoySxliim9kYW30JUHiPVyjt0iAw/ZpPmCbUCltYPnq6ZNblIKhTNhqS/oqC9iya5sGKZTOVsTEg34n92uZTf2iPpcZih8rPW8CzA+adIGmyCPcKdLMsBLShd+zuEbTrqpwuh+DLmracZcjPC5Sdf5odDAhKpFuOsQS67RT+1VgWWygSv3YwxDnylc04/PYuaMeIzhBkLrvs7e/OUzRTF56MmfY6rI63QtEjEQzq637zQqJ39nNhu3NmoRRhW/086bHGBUtx0PE0j3aEGvkdh9WJC8y8j8mqqke9/dQ5la+Q3ba4RlhvTbnfQhPDDab3tUifkjKuOsp13mXEmO00Mu88F/M67R7LXfoFDFLNtgCSWjWX+3Jn1371pJTK9xPBiMJafvDjtFyAzu8rxeQ0TKMQXNPs5xxiBOd+BRJP8KP88XPtJIbZKh/cdW8KvBUkpqKpGoiIaA32c3/JnQr4efXt85mXvidOvn/eU3Pase1typLYBalJ14mCso9h79nuMOuCa/kZAOkJHmTjP5RM2WNoPasZUAnT1TAE/NH25hUxcQv6hQWR/m1PKk4ooXMcM4SR1iYU3fUohvqk4RY2hbmTVVIXv6TvqO+0doOjgeVFAcom+RlwJQmOVH7pr1Q9LoJT6n1DeQEB+NHygsATbIwTcOKZlJsY8G4+suX1uQLjUWwLjjs0mvSvZcLTpIGAekeR7GCgl8eo3ndAqEe2XCav4huliHjdbIPBsGJuPX7lrO9HX1UbXRH5opOe1x6JsOSgHZR+EaxuXVhpLLxm6jk1LJtZfHSc6BKPun3CpYYVMJGwEUyk8MTGG0XL5MfEwaXpnc9TKnBmlGn6nHiGREc3ysn47XIBDzA+YvFdjZzVIEDcKGpS6PbUJehFRjEne8D0lVU1XuRtlgszq6pTNlQ/3MzNOEgCWPyTct22V2mEi2krizn5VDo9B19/X2DB3hCGRMM7ONbtnAcIx/OWB1u5uPbW1gsH8irXxT/IzG0PoXWYjhbMsH3KTuoOl5o17PulcgvsfTSnKFM354GWI8luqZnrswWjiXy3G+Vbyo1KMopFmmvBwNELgaS8z8dNZchx/Cl/xjddxhMcyqtzFyONb2Zdu90NkI8pAeufe7YlXrp53v8Dj/l8vWeVspRKBGXScBBPI/HinSTGmLDOGGOCIyH0JFdOZx0gWsacNlQLJMIrBhqRxXxHF/5pseWwejlAAvZ3klZSDSYY8mkToaWejXhgNomeGtx1DTLEUFMRkgF5yFB22WYdJnaWN14r1YJj81hGi45+jrADS5nYRhCiSlCJJ1nL8pYX+HDSMhdTEWyRcgHVp/IsUIZYMfT+YYncUQPgcxNGCHfZ88vDdrcUuaGIl6zhAsiaq7R5dfqrqXH/JcBhfjT8D0azayIyEz75Nxp6YkcyDxlJq3EXnJUpqDohJJOysL1t1uNiHESlvsxPb5cpbW0+ICZqJmUZus1BMW0F5IVBODLIo2zHHjA0=","base64")).toString()),iH}var sH;function Lde(){return typeof sH>"u"&&(sH=Be("zlib").brotliDecompressSync(Buffer.from("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","base64")).toString()),sH}var Mde=new Map([[W.makeIdent(null,"fsevents").identHash,Rde],[W.makeIdent(null,"resolve").identHash,Nde],[W.makeIdent(null,"typescript").identHash,Lde]]),Fgt={hooks:{registerPackageExtensions:async(t,e)=>{for(let[r,o]of rH)e(W.parseDescriptor(r,!0),o)},getBuiltinPatch:async(t,e)=>{let r="compat/";if(!e.startsWith(r))return;let o=W.parseIdent(e.slice(r.length)),a=Mde.get(o.identHash)?.();return typeof a<"u"?a:null},reduceDependency:async(t,e,r,o)=>typeof Mde.get(t.identHash)>"u"?t:W.makeDescriptor(t,W.makeRange({protocol:"patch:",source:W.stringifyDescriptor(t),selector:`optional!builtin`,params:null}))}},Tgt=Fgt;var BH={};Kt(BH,{ConstraintsCheckCommand:()=>p0,ConstraintsQueryCommand:()=>A0,ConstraintsSourceCommand:()=>f0,default:()=>odt});Ye();Ye();B2();var wC=class{constructor(e){this.project=e}createEnvironment(){let e=new CC(["cwd","ident"]),r=new CC(["workspace","type","ident"]),o=new CC(["ident"]),a={manifestUpdates:new Map,reportedErrors:new Map},n=new Map,u=new Map;for(let A of this.project.storedPackages.values()){let p=Array.from(A.peerDependencies.values(),h=>[W.stringifyIdent(h),h.range]);n.set(A.locatorHash,{workspace:null,ident:W.stringifyIdent(A),version:A.version,dependencies:new Map,peerDependencies:new Map(p.filter(([h])=>A.peerDependenciesMeta.get(h)?.optional!==!0)),optionalPeerDependencies:new Map(p.filter(([h])=>A.peerDependenciesMeta.get(h)?.optional===!0))})}for(let A of this.project.storedPackages.values()){let p=n.get(A.locatorHash);p.dependencies=new Map(Array.from(A.dependencies.values(),h=>{let E=this.project.storedResolutions.get(h.descriptorHash);if(typeof E>"u")throw new Error("Assertion failed: The resolution should have been registered");let I=n.get(E);if(typeof I>"u")throw new Error("Assertion failed: The package should have been registered");return[W.stringifyIdent(h),I]})),p.dependencies.delete(p.ident)}for(let A of this.project.workspaces){let p=W.stringifyIdent(A.anchoredLocator),h=A.manifest.exportTo({}),E=n.get(A.anchoredLocator.locatorHash);if(typeof E>"u")throw new Error("Assertion failed: The package should have been registered");let I=(T,L,{caller:U=Ji.getCaller()}={})=>{let J=I2(T),te=je.getMapWithDefault(a.manifestUpdates,A.cwd),le=je.getMapWithDefault(te,J),pe=je.getSetWithDefault(le,L);U!==null&&pe.add(U)},v=T=>I(T,void 0,{caller:Ji.getCaller()}),b=T=>{je.getArrayWithDefault(a.reportedErrors,A.cwd).push(T)},C=e.insert({cwd:A.relativeCwd,ident:p,manifest:h,pkg:E,set:I,unset:v,error:b});u.set(A,C);for(let T of Mt.allDependencies)for(let L of A.manifest[T].values()){let U=W.stringifyIdent(L),J=()=>{I([T,U],void 0,{caller:Ji.getCaller()})},te=pe=>{I([T,U],pe,{caller:Ji.getCaller()})},le=null;if(T!=="peerDependencies"&&(T!=="dependencies"||!A.manifest.devDependencies.has(L.identHash))){let pe=A.anchoredPackage.dependencies.get(L.identHash);if(pe){if(typeof pe>"u")throw new Error("Assertion failed: The dependency should have been registered");let Ae=this.project.storedResolutions.get(pe.descriptorHash);if(typeof Ae>"u")throw new Error("Assertion failed: The resolution should have been registered");let ye=n.get(Ae);if(typeof ye>"u")throw new Error("Assertion failed: The package should have been registered");le=ye}}r.insert({workspace:C,ident:U,range:L.range,type:T,resolution:le,update:te,delete:J,error:b})}}for(let A of this.project.storedPackages.values()){let p=this.project.tryWorkspaceByLocator(A);if(!p)continue;let h=u.get(p);if(typeof h>"u")throw new Error("Assertion failed: The workspace should have been registered");let E=n.get(A.locatorHash);if(typeof E>"u")throw new Error("Assertion failed: The package should have been registered");E.workspace=h}return{workspaces:e,dependencies:r,packages:o,result:a}}async process(){let e=this.createEnvironment(),r={Yarn:{workspace:a=>e.workspaces.find(a)[0]??null,workspaces:a=>e.workspaces.find(a),dependency:a=>e.dependencies.find(a)[0]??null,dependencies:a=>e.dependencies.find(a),package:a=>e.packages.find(a)[0]??null,packages:a=>e.packages.find(a)}},o=await this.project.loadUserConfig();return o?.constraints?(await o.constraints(r),e.result):null}};Ye();Ye();qt();var A0=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.query=ge.String()}async execute(){let{Constraints:r}=await Promise.resolve().then(()=>(x2(),S2)),o=await Ve.find(this.context.cwd,this.context.plugins),{project:a}=await St.find(o,this.context.cwd),n=await r.find(a),u=this.query;return u.endsWith(".")||(u=`${u}.`),(await Nt.start({configuration:o,json:this.json,stdout:this.context.stdout},async p=>{for await(let h of n.query(u)){let E=Array.from(Object.entries(h)),I=E.length,v=E.reduce((b,[C])=>Math.max(b,C.length),0);for(let b=0;b(x2(),S2)),o=await Ve.find(this.context.cwd,this.context.plugins),{project:a}=await St.find(o,this.context.cwd),n=await r.find(a);this.context.stdout.write(this.verbose?n.fullSource:n.source)}};f0.paths=[["constraints","source"]],f0.usage=nt.Usage({category:"Constraints-related commands",description:"print the source code for the constraints",details:"\n This command will print the Prolog source code used by the constraints engine. Adding the `-v,--verbose` flag will print the *full* source code, including the fact database automatically compiled from the workspace manifests.\n ",examples:[["Prints the source code","yarn constraints source"],["Print the source code and the fact database","yarn constraints source -v"]]});Ye();Ye();qt();B2();var p0=class extends ut{constructor(){super(...arguments);this.fix=ge.Boolean("--fix",!1,{description:"Attempt to automatically fix unambiguous issues, following a multi-pass process"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd);await o.restoreInstallState();let a=await o.loadUserConfig(),n;if(a?.constraints)n=new wC(o);else{let{Constraints:h}=await Promise.resolve().then(()=>(x2(),S2));n=await h.find(o)}let u,A=!1,p=!1;for(let h=this.fix?10:1;h>0;--h){let E=await n.process();if(!E)break;let{changedWorkspaces:I,remainingErrors:v}=mk(o,E,{fix:this.fix}),b=[];for(let[C,T]of I){let L=C.manifest.indent;C.manifest=new Mt,C.manifest.indent=L,C.manifest.load(T),b.push(C.persistManifest())}if(await Promise.all(b),!(I.size>0&&h>1)){u=Gde(v,{configuration:r}),A=!1,p=!0;for(let[,C]of v)for(let T of C)T.fixable?A=!0:p=!1}}if(u.children.length===0)return 0;if(A){let h=p?`Those errors can all be fixed by running ${de.pretty(r,"yarn constraints --fix",de.Type.CODE)}`:`Errors prefixed by '\u2699' can be fixed by running ${de.pretty(r,"yarn constraints --fix",de.Type.CODE)}`;await Nt.start({configuration:r,stdout:this.context.stdout,includeNames:!1,includeFooter:!1},async E=>{E.reportInfo(0,h),E.reportSeparator()})}return u.children=je.sortMap(u.children,h=>h.value[1]),$s.emitTree(u,{configuration:r,stdout:this.context.stdout,json:this.json,separators:1}),1}};p0.paths=[["constraints"]],p0.usage=nt.Usage({category:"Constraints-related commands",description:"check that the project constraints are met",details:` - This command will run constraints on your project and emit errors for each one that is found but isn't met. If any error is emitted the process will exit with a non-zero exit code. - - If the \`--fix\` flag is used, Yarn will attempt to automatically fix the issues the best it can, following a multi-pass process (with a maximum of 10 iterations). Some ambiguous patterns cannot be autofixed, in which case you'll have to manually specify the right resolution. - - For more information as to how to write constraints, please consult our dedicated page on our website: https://yarnpkg.com/features/constraints. - `,examples:[["Check that all constraints are satisfied","yarn constraints"],["Autofix all unmet constraints","yarn constraints --fix"]]});B2();var sdt={configuration:{enableConstraintsChecks:{description:"If true, constraints will run during installs",type:"BOOLEAN",default:!1},constraintsPath:{description:"The path of the constraints file.",type:"ABSOLUTE_PATH",default:"./constraints.pro"}},commands:[A0,f0,p0],hooks:{async validateProjectAfterInstall(t,{reportError:e}){if(!t.configuration.get("enableConstraintsChecks"))return;let r=await t.loadUserConfig(),o;if(r?.constraints)o=new wC(t);else{let{Constraints:u}=await Promise.resolve().then(()=>(x2(),S2));o=await u.find(t)}let a=await o.process();if(!a)return;let{remainingErrors:n}=mk(t,a);if(n.size!==0)if(t.configuration.isCI)for(let[u,A]of n)for(let p of A)e(84,`${de.pretty(t.configuration,u.anchoredLocator,de.Type.IDENT)}: ${p.text}`);else e(84,`Constraint check failed; run ${de.pretty(t.configuration,"yarn constraints",de.Type.CODE)} for more details`)}}},odt=sdt;var vH={};Kt(vH,{CreateCommand:()=>em,DlxCommand:()=>h0,default:()=>ldt});Ye();qt();var em=class extends ut{constructor(){super(...arguments);this.pkg=ge.String("-p,--package",{description:"The package to run the provided command from"});this.quiet=ge.Boolean("-q,--quiet",!1,{description:"Only report critical errors instead of printing the full install logs"});this.command=ge.String();this.args=ge.Proxy()}async execute(){let r=[];this.pkg&&r.push("--package",this.pkg),this.quiet&&r.push("--quiet");let o=this.command.replace(/^(@[^@/]+)(@|$)/,"$1/create$2"),a=W.parseDescriptor(o),n=a.name.match(/^create(-|$)/)?a:a.scope?W.makeIdent(a.scope,`create-${a.name}`):W.makeIdent(null,`create-${a.name}`),u=W.stringifyIdent(n);return a.range!=="unknown"&&(u+=`@${a.range}`),this.cli.run(["dlx",...r,u,...this.args])}};em.paths=[["create"]];Ye();Ye();Pt();qt();var h0=class extends ut{constructor(){super(...arguments);this.packages=ge.Array("-p,--package",{description:"The package(s) to install before running the command"});this.quiet=ge.Boolean("-q,--quiet",!1,{description:"Only report critical errors instead of printing the full install logs"});this.command=ge.String();this.args=ge.Proxy()}async execute(){return Ve.telemetry=null,await oe.mktempPromise(async r=>{let o=K.join(r,`dlx-${process.pid}`);await oe.mkdirPromise(o),await oe.writeFilePromise(K.join(o,"package.json"),`{} -`),await oe.writeFilePromise(K.join(o,"yarn.lock"),"");let a=K.join(o,".yarnrc.yml"),n=await Ve.findProjectCwd(this.context.cwd),A={enableGlobalCache:!(await Ve.find(this.context.cwd,null,{strict:!1})).get("enableGlobalCache"),enableTelemetry:!1,logFilters:[{code:Wu(68),level:de.LogLevel.Discard}]},p=n!==null?K.join(n,".yarnrc.yml"):null;p!==null&&oe.existsSync(p)?(await oe.copyFilePromise(p,a),await Ve.updateConfiguration(o,L=>{let U=je.toMerged(L,A);return Array.isArray(L.plugins)&&(U.plugins=L.plugins.map(J=>{let te=typeof J=="string"?J:J.path,le=ue.isAbsolute(te)?te:ue.resolve(ue.fromPortablePath(n),te);return typeof J=="string"?le:{path:le,spec:J.spec}})),U})):await oe.writeJsonPromise(a,A);let h=this.packages??[this.command],E=W.parseDescriptor(this.command).name,I=await this.cli.run(["add","--fixed","--",...h],{cwd:o,quiet:this.quiet});if(I!==0)return I;this.quiet||this.context.stdout.write(` -`);let v=await Ve.find(o,this.context.plugins),{project:b,workspace:C}=await St.find(v,o);if(C===null)throw new rr(b.cwd,o);await b.restoreInstallState();let T=await un.getWorkspaceAccessibleBinaries(C);return T.has(E)===!1&&T.size===1&&typeof this.packages>"u"&&(E=Array.from(T)[0][0]),await un.executeWorkspaceAccessibleBinary(C,E,this.args,{packageAccessibleBinaries:T,cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})})}};h0.paths=[["dlx"]],h0.usage=nt.Usage({description:"run a package in a temporary environment",details:"\n This command will install a package within a temporary environment, and run its binary script if it contains any. The binary will run within the current cwd.\n\n By default Yarn will download the package named `command`, but this can be changed through the use of the `-p,--package` flag which will instruct Yarn to still run the same command but from a different package.\n\n Using `yarn dlx` as a replacement of `yarn add` isn't recommended, as it makes your project non-deterministic (Yarn doesn't keep track of the packages installed through `dlx` - neither their name, nor their version).\n ",examples:[["Use create-react-app to create a new React app","yarn dlx create-react-app ./my-app"],["Install multiple packages for a single command",`yarn dlx -p typescript -p ts-node ts-node --transpile-only -e "console.log('hello!')"`]]});var adt={commands:[em,h0]},ldt=adt;var SH={};Kt(SH,{ExecFetcher:()=>k2,ExecResolver:()=>Q2,default:()=>Adt,execUtils:()=>wk});Ye();Ye();Pt();var fA="exec:";var wk={};Kt(wk,{loadGeneratorFile:()=>b2,makeLocator:()=>PH,makeSpec:()=>dme,parseSpec:()=>DH});Ye();Pt();function DH(t){let{params:e,selector:r}=W.parseRange(t),o=ue.toPortablePath(r);return{parentLocator:e&&typeof e.locator=="string"?W.parseLocator(e.locator):null,path:o}}function dme({parentLocator:t,path:e,generatorHash:r,protocol:o}){let a=t!==null?{locator:W.stringifyLocator(t)}:{},n=typeof r<"u"?{hash:r}:{};return W.makeRange({protocol:o,source:e,selector:e,params:{...n,...a}})}function PH(t,{parentLocator:e,path:r,generatorHash:o,protocol:a}){return W.makeLocator(t,dme({parentLocator:e,path:r,generatorHash:o,protocol:a}))}async function b2(t,e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(t,{protocol:e}),n=K.isAbsolute(a)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await r.fetcher.fetch(o,r),u=n.localPath?{packageFs:new gn(Bt.root),prefixPath:K.relative(Bt.root,n.localPath)}:n;n!==u&&n.releaseFs&&n.releaseFs();let A=u.packageFs,p=K.join(u.prefixPath,a);return await A.readFilePromise(p,"utf8")}var k2=class{supports(e,r){return!!e.reference.startsWith(fA)}getLocalPath(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:fA});if(K.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(o,r);return n===null?null:K.resolve(n,a)}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:u}}async fetchFromDisk(e,r){let o=await b2(e.reference,fA,r);return oe.mktempPromise(async a=>{let n=K.join(a,"generator.js");return await oe.writeFilePromise(n,o),oe.mktempPromise(async u=>{if(await this.generatePackage(u,e,n,r),!oe.existsSync(K.join(u,"build")))throw new Error("The script should have generated a build directory");return await Xi.makeArchiveFromDirectory(K.join(u,"build"),{prefixPath:W.getIdentVendorPath(e),compressionLevel:r.project.configuration.get("compressionLevel")})})})}async generatePackage(e,r,o,a){return await oe.mktempPromise(async n=>{let u=await un.makeScriptEnv({project:a.project,binFolder:n}),A=K.join(e,"runtime.js");return await oe.mktempPromise(async p=>{let h=K.join(p,"buildfile.log"),E=K.join(e,"generator"),I=K.join(e,"build");await oe.mkdirPromise(E),await oe.mkdirPromise(I);let v={tempDir:ue.fromPortablePath(E),buildDir:ue.fromPortablePath(I),locator:W.stringifyLocator(r)};await oe.writeFilePromise(A,` - // Expose 'Module' as a global variable - Object.defineProperty(global, 'Module', { - get: () => require('module'), - configurable: true, - enumerable: false, - }); - - // Expose non-hidden built-in modules as global variables - for (const name of Module.builtinModules.filter((name) => name !== 'module' && !name.startsWith('_'))) { - Object.defineProperty(global, name, { - get: () => require(name), - configurable: true, - enumerable: false, - }); - } - - // Expose the 'execEnv' global variable - Object.defineProperty(global, 'execEnv', { - value: { - ...${JSON.stringify(v)}, - }, - enumerable: true, - }); - `);let b=u.NODE_OPTIONS||"",C=/\s*--require\s+\S*\.pnp\.c?js\s*/g;b=b.replace(C," ").trim(),u.NODE_OPTIONS=b;let{stdout:T,stderr:L}=a.project.configuration.getSubprocessStreams(h,{header:`# This file contains the result of Yarn generating a package (${W.stringifyLocator(r)}) -`,prefix:W.prettyLocator(a.project.configuration,r),report:a.report}),{code:U}=await Ur.pipevp(process.execPath,["--require",ue.fromPortablePath(A),ue.fromPortablePath(o),W.stringifyIdent(r)],{cwd:e,env:u,stdin:null,stdout:T,stderr:L});if(U!==0)throw oe.detachTemp(p),new Error(`Package generation failed (exit code ${U}, logs can be found here: ${de.pretty(a.project.configuration,h,de.Type.PATH)})`)})})}};Ye();Ye();var cdt=2,Q2=class{supportsDescriptor(e,r){return!!e.range.startsWith(fA)}supportsLocator(e,r){return!!e.reference.startsWith(fA)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){if(!o.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let{path:a,parentLocator:n}=DH(e.range);if(n===null)throw new Error("Assertion failed: The descriptor should have been bound");let u=await b2(W.makeRange({protocol:fA,source:a,selector:a,params:{locator:W.stringifyLocator(n)}}),fA,o.fetchOptions),A=wn.makeHash(`${cdt}`,u).slice(0,6);return[PH(e,{parentLocator:n,path:a,generatorHash:A,protocol:fA})]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Mt.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"HARD",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var udt={fetchers:[k2],resolvers:[Q2]},Adt=udt;var bH={};Kt(bH,{FileFetcher:()=>N2,FileResolver:()=>L2,TarballFileFetcher:()=>M2,TarballFileResolver:()=>O2,default:()=>hdt,fileUtils:()=>tm});Ye();Pt();var DC=/^(?:[a-zA-Z]:[\\/]|\.{0,2}\/)/,F2=/^[^?]*\.(?:tar\.gz|tgz)(?:::.*)?$/,Ui="file:";var tm={};Kt(tm,{fetchArchiveFromLocator:()=>R2,makeArchiveFromLocator:()=>Ik,makeBufferFromLocator:()=>xH,makeLocator:()=>PC,makeSpec:()=>mme,parseSpec:()=>T2});Ye();Pt();function T2(t){let{params:e,selector:r}=W.parseRange(t),o=ue.toPortablePath(r);return{parentLocator:e&&typeof e.locator=="string"?W.parseLocator(e.locator):null,path:o}}function mme({parentLocator:t,path:e,hash:r,protocol:o}){let a=t!==null?{locator:W.stringifyLocator(t)}:{},n=typeof r<"u"?{hash:r}:{};return W.makeRange({protocol:o,source:e,selector:e,params:{...n,...a}})}function PC(t,{parentLocator:e,path:r,hash:o,protocol:a}){return W.makeLocator(t,mme({parentLocator:e,path:r,hash:o,protocol:a}))}async function R2(t,e){let{parentLocator:r,path:o}=W.parseFileStyleRange(t.reference,{protocol:Ui}),a=K.isAbsolute(o)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await e.fetcher.fetch(r,e),n=a.localPath?{packageFs:new gn(Bt.root),prefixPath:K.relative(Bt.root,a.localPath)}:a;a!==n&&a.releaseFs&&a.releaseFs();let u=n.packageFs,A=K.join(n.prefixPath,o);return await je.releaseAfterUseAsync(async()=>await u.readFilePromise(A),n.releaseFs)}async function Ik(t,{protocol:e,fetchOptions:r,inMemory:o=!1}){let{parentLocator:a,path:n}=W.parseFileStyleRange(t.reference,{protocol:e}),u=K.isAbsolute(n)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await r.fetcher.fetch(a,r),A=u.localPath?{packageFs:new gn(Bt.root),prefixPath:K.relative(Bt.root,u.localPath)}:u;u!==A&&u.releaseFs&&u.releaseFs();let p=A.packageFs,h=K.join(A.prefixPath,n);return await je.releaseAfterUseAsync(async()=>await Xi.makeArchiveFromDirectory(h,{baseFs:p,prefixPath:W.getIdentVendorPath(t),compressionLevel:r.project.configuration.get("compressionLevel"),inMemory:o}),A.releaseFs)}async function xH(t,{protocol:e,fetchOptions:r}){return(await Ik(t,{protocol:e,fetchOptions:r,inMemory:!0})).getBufferAndClose()}var N2=class{supports(e,r){return!!e.reference.startsWith(Ui)}getLocalPath(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:Ui});if(K.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(o,r);return n===null?null:K.resolve(n,a)}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:u}}async fetchFromDisk(e,r){return Ik(e,{protocol:Ui,fetchOptions:r})}};Ye();Ye();var fdt=2,L2=class{supportsDescriptor(e,r){return e.range.match(DC)?!0:!!e.range.startsWith(Ui)}supportsLocator(e,r){return!!e.reference.startsWith(Ui)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return DC.test(e.range)&&(e=W.makeDescriptor(e,`${Ui}${e.range}`)),W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){if(!o.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let{path:a,parentLocator:n}=T2(e.range);if(n===null)throw new Error("Assertion failed: The descriptor should have been bound");let u=await xH(W.makeLocator(e,W.makeRange({protocol:Ui,source:a,selector:a,params:{locator:W.stringifyLocator(n)}})),{protocol:Ui,fetchOptions:o.fetchOptions}),A=wn.makeHash(`${fdt}`,u).slice(0,6);return[PC(e,{parentLocator:n,path:a,hash:A,protocol:Ui})]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Mt.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"HARD",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};Ye();var M2=class{supports(e,r){return F2.test(e.reference)?!!e.reference.startsWith(Ui):!1}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromDisk(e,r){let o=await R2(e,r);return await Xi.convertToZip(o,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})}};Ye();Ye();Ye();var O2=class{supportsDescriptor(e,r){return F2.test(e.range)?!!(e.range.startsWith(Ui)||DC.test(e.range)):!1}supportsLocator(e,r){return F2.test(e.reference)?!!e.reference.startsWith(Ui):!1}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return DC.test(e.range)&&(e=W.makeDescriptor(e,`${Ui}${e.range}`)),W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){if(!o.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let{path:a,parentLocator:n}=T2(e.range);if(n===null)throw new Error("Assertion failed: The descriptor should have been bound");let u=PC(e,{parentLocator:n,path:a,hash:"",protocol:Ui}),A=await R2(u,o.fetchOptions),p=wn.makeHash(A).slice(0,6);return[PC(e,{parentLocator:n,path:a,hash:p,protocol:Ui})]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Mt.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"HARD",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var pdt={fetchers:[M2,N2],resolvers:[O2,L2]},hdt=pdt;var FH={};Kt(FH,{GithubFetcher:()=>U2,default:()=>ddt,githubUtils:()=>Bk});Ye();Pt();var Bk={};Kt(Bk,{invalidGithubUrlMessage:()=>Cme,isGithubUrl:()=>kH,parseGithubUrl:()=>QH});var yme=$e(Be("querystring")),Eme=[/^https?:\/\/(?:([^/]+?)@)?github.com\/([^/#]+)\/([^/#]+)\/tarball\/([^/#]+)(?:#(.*))?$/,/^https?:\/\/(?:([^/]+?)@)?github.com\/([^/#]+)\/([^/#]+?)(?:\.git)?(?:#(.*))?$/];function kH(t){return t?Eme.some(e=>!!t.match(e)):!1}function QH(t){let e;for(let A of Eme)if(e=t.match(A),e)break;if(!e)throw new Error(Cme(t));let[,r,o,a,n="master"]=e,{commit:u}=yme.default.parse(n);return n=u||n.replace(/[^:]*:/,""),{auth:r,username:o,reponame:a,treeish:n}}function Cme(t){return`Input cannot be parsed as a valid GitHub URL ('${t}').`}var U2=class{supports(e,r){return!!kH(e.reference)}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from GitHub`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromNetwork(e,r){let o=await rn.get(this.getLocatorUrl(e,r),{configuration:r.project.configuration});return await oe.mktempPromise(async a=>{let n=new gn(a);await Xi.extractArchiveTo(o,n,{stripComponents:1});let u=ra.splitRepoUrl(e.reference),A=K.join(a,"package.tgz");await un.prepareExternalProject(a,A,{configuration:r.project.configuration,report:r.report,workspace:u.extra.workspace,locator:e});let p=await oe.readFilePromise(A);return await Xi.convertToZip(p,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})})}getLocatorUrl(e,r){let{auth:o,username:a,reponame:n,treeish:u}=QH(e.reference);return`https://${o?`${o}@`:""}github.com/${a}/${n}/archive/${u}.tar.gz`}};var gdt={hooks:{async fetchHostedRepository(t,e,r){if(t!==null)return t;let o=new U2;if(!o.supports(e,r))return null;try{return await o.fetch(e,r)}catch{return null}}}},ddt=gdt;var TH={};Kt(TH,{TarballHttpFetcher:()=>H2,TarballHttpResolver:()=>j2,default:()=>ydt});Ye();function _2(t){let e;try{e=new URL(t)}catch{return!1}return!(e.protocol!=="http:"&&e.protocol!=="https:"||!e.pathname.match(/(\.tar\.gz|\.tgz|\/[^.]+)$/))}var H2=class{supports(e,r){return _2(e.reference)}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote server`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromNetwork(e,r){let o=await rn.get(e.reference,{configuration:r.project.configuration});return await Xi.convertToZip(o,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})}};Ye();Ye();var j2=class{supportsDescriptor(e,r){return _2(e.range)}supportsLocator(e,r){return _2(e.reference)}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){return[W.convertDescriptorToLocator(e)]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Mt.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"HARD",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var mdt={fetchers:[H2],resolvers:[j2]},ydt=mdt;var RH={};Kt(RH,{InitCommand:()=>g0,default:()=>Cdt});Ye();Ye();Pt();qt();var g0=class extends ut{constructor(){super(...arguments);this.private=ge.Boolean("-p,--private",!1,{description:"Initialize a private package"});this.workspace=ge.Boolean("-w,--workspace",!1,{description:"Initialize a workspace root with a `packages/` directory"});this.install=ge.String("-i,--install",!1,{tolerateBoolean:!0,description:"Initialize a package with a specific bundle that will be locked in the project"});this.name=ge.String("-n,--name",{description:"Initialize a package with the given name"});this.usev2=ge.Boolean("-2",!1,{hidden:!0});this.yes=ge.Boolean("-y,--yes",{hidden:!0})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),o=typeof this.install=="string"?this.install:this.usev2||this.install===!0?"latest":null;return o!==null?await this.executeProxy(r,o):await this.executeRegular(r)}async executeProxy(r,o){if(r.projectCwd!==null&&r.projectCwd!==this.context.cwd)throw new it("Cannot use the --install flag from within a project subdirectory");oe.existsSync(this.context.cwd)||await oe.mkdirPromise(this.context.cwd,{recursive:!0});let a=K.join(this.context.cwd,dr.lockfile);oe.existsSync(a)||await oe.writeFilePromise(a,"");let n=await this.cli.run(["set","version",o],{quiet:!0});if(n!==0)return n;let u=[];return this.private&&u.push("-p"),this.workspace&&u.push("-w"),this.name&&u.push(`-n=${this.name}`),this.yes&&u.push("-y"),await oe.mktempPromise(async A=>{let{code:p}=await Ur.pipevp("yarn",["init",...u],{cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,env:await un.makeScriptEnv({binFolder:A})});return p})}async executeRegular(r){let o=null;try{o=(await St.find(r,this.context.cwd)).project}catch{o=null}oe.existsSync(this.context.cwd)||await oe.mkdirPromise(this.context.cwd,{recursive:!0});let a=await Mt.tryFind(this.context.cwd),n=a??new Mt,u=Object.fromEntries(r.get("initFields").entries());n.load(u),n.name=n.name??W.makeIdent(r.get("initScope"),this.name??K.basename(this.context.cwd)),n.packageManager=tn&&je.isTaggedYarnVersion(tn)?`yarn@${tn}`:null,(!a&&this.workspace||this.private)&&(n.private=!0),this.workspace&&n.workspaceDefinitions.length===0&&(await oe.mkdirPromise(K.join(this.context.cwd,"packages"),{recursive:!0}),n.workspaceDefinitions=[{pattern:"packages/*"}]);let A={};n.exportTo(A);let p=K.join(this.context.cwd,Mt.fileName);await oe.changeFilePromise(p,`${JSON.stringify(A,null,2)} -`,{automaticNewlines:!0});let h=[p],E=K.join(this.context.cwd,"README.md");if(oe.existsSync(E)||(await oe.writeFilePromise(E,`# ${W.stringifyIdent(n.name)} -`),h.push(E)),!o||o.cwd===this.context.cwd){let I=K.join(this.context.cwd,dr.lockfile);oe.existsSync(I)||(await oe.writeFilePromise(I,""),h.push(I));let b=[".yarn/*","!.yarn/patches","!.yarn/plugins","!.yarn/releases","!.yarn/sdks","!.yarn/versions","","# Swap the comments on the following lines if you wish to use zero-installs","# In that case, don't forget to run `yarn config set enableGlobalCache false`!","# Documentation here: https://yarnpkg.com/features/caching#zero-installs","","#!.yarn/cache",".pnp.*"].map(pe=>`${pe} -`).join(""),C=K.join(this.context.cwd,".gitignore");oe.existsSync(C)||(await oe.writeFilePromise(C,b),h.push(C));let L=["/.yarn/** linguist-vendored","/.yarn/releases/* binary","/.yarn/plugins/**/* binary","/.pnp.* binary linguist-generated"].map(pe=>`${pe} -`).join(""),U=K.join(this.context.cwd,".gitattributes");oe.existsSync(U)||(await oe.writeFilePromise(U,L),h.push(U));let J={["*"]:{endOfLine:"lf",insertFinalNewline:!0},["*.{js,json,yml}"]:{charset:"utf-8",indentStyle:"space",indentSize:2}};je.mergeIntoTarget(J,r.get("initEditorConfig"));let te=`root = true -`;for(let[pe,Ae]of Object.entries(J)){te+=` -[${pe}] -`;for(let[ye,ae]of Object.entries(Ae)){let we=ye.replace(/[A-Z]/g,Pe=>`_${Pe.toLowerCase()}`);te+=`${we} = ${ae} -`}}let le=K.join(this.context.cwd,".editorconfig");oe.existsSync(le)||(await oe.writeFilePromise(le,te),h.push(le)),await this.cli.run(["install"],{quiet:!0}),oe.existsSync(K.join(this.context.cwd,".git"))||(await Ur.execvp("git",["init"],{cwd:this.context.cwd}),await Ur.execvp("git",["add","--",...h],{cwd:this.context.cwd}),await Ur.execvp("git",["commit","--allow-empty","-m","First commit"],{cwd:this.context.cwd}))}}};g0.paths=[["init"]],g0.usage=nt.Usage({description:"create a new package",details:"\n This command will setup a new package in your local directory.\n\n If the `-p,--private` or `-w,--workspace` options are set, the package will be private by default.\n\n If the `-w,--workspace` option is set, the package will be configured to accept a set of workspaces in the `packages/` directory.\n\n If the `-i,--install` option is given a value, Yarn will first download it using `yarn set version` and only then forward the init call to the newly downloaded bundle. Without arguments, the downloaded bundle will be `latest`.\n\n The initial settings of the manifest can be changed by using the `initScope` and `initFields` configuration values. Additionally, Yarn will generate an EditorConfig file whose rules can be altered via `initEditorConfig`, and will initialize a Git repository in the current directory.\n ",examples:[["Create a new package in the local directory","yarn init"],["Create a new private package in the local directory","yarn init -p"],["Create a new package and store the Yarn release inside","yarn init -i=latest"],["Create a new private package and defines it as a workspace root","yarn init -w"]]});var Edt={configuration:{initScope:{description:"Scope used when creating packages via the init command",type:"STRING",default:null},initFields:{description:"Additional fields to set when creating packages via the init command",type:"MAP",valueDefinition:{description:"",type:"ANY"}},initEditorConfig:{description:"Extra rules to define in the generator editorconfig",type:"MAP",valueDefinition:{description:"",type:"ANY"}}},commands:[g0]},Cdt=Edt;var Lj={};Kt(Lj,{SearchCommand:()=>C0,UpgradeInteractiveCommand:()=>I0,default:()=>lIt});Ye();var Ime=$e(Be("os"));function SC({stdout:t}){if(Ime.default.endianness()==="BE")throw new Error("Interactive commands cannot be used on big-endian systems because ink depends on yoga-layout-prebuilt which only supports little-endian architectures");if(!t.isTTY)throw new Error("Interactive commands can only be used inside a TTY environment")}qt();var Rye=$e(ZH()),$H={appId:"OFCNCOG2CU",apiKey:"6fe4476ee5a1832882e326b506d14126",indexName:"npm-search"},myt=(0,Rye.default)($H.appId,$H.apiKey).initIndex($H.indexName),e6=async(t,e=0)=>await myt.search(t,{analyticsTags:["yarn-plugin-interactive-tools"],attributesToRetrieve:["name","version","owner","repository","humanDownloadsLast30Days"],page:e,hitsPerPage:10});var HB=["regular","dev","peer"],C0=class extends ut{async execute(){SC(this.context);let{Gem:e}=await Promise.resolve().then(()=>(AQ(),Dj)),{ScrollableItems:r}=await Promise.resolve().then(()=>(gQ(),hQ)),{useKeypress:o}=await Promise.resolve().then(()=>(OB(),Jwe)),{useMinistore:a}=await Promise.resolve().then(()=>(Qj(),kj)),{renderForm:n}=await Promise.resolve().then(()=>(EQ(),yQ)),{default:u}=await Promise.resolve().then(()=>$e(sIe())),{Box:A,Text:p}=await Promise.resolve().then(()=>$e(ic())),{default:h,useEffect:E,useState:I}=await Promise.resolve().then(()=>$e(sn())),v=await Ve.find(this.context.cwd,this.context.plugins),b=()=>h.createElement(A,{flexDirection:"row"},h.createElement(A,{flexDirection:"column",width:48},h.createElement(A,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},""),"/",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to move between packages.")),h.createElement(A,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to select a package.")),h.createElement(A,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"")," again to change the target."))),h.createElement(A,{flexDirection:"column"},h.createElement(A,{marginLeft:1},h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to install the selected packages.")),h.createElement(A,{marginLeft:1},h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to abort.")))),C=()=>h.createElement(h.Fragment,null,h.createElement(A,{width:15},h.createElement(p,{bold:!0,underline:!0,color:"gray"},"Owner")),h.createElement(A,{width:11},h.createElement(p,{bold:!0,underline:!0,color:"gray"},"Version")),h.createElement(A,{width:10},h.createElement(p,{bold:!0,underline:!0,color:"gray"},"Downloads"))),T=()=>h.createElement(A,{width:17},h.createElement(p,{bold:!0,underline:!0,color:"gray"},"Target")),L=({hit:ae,active:we})=>{let[Pe,g]=a(ae.name,null);o({active:we},(ce,ne)=>{if(ne.name!=="space")return;if(!Pe){g(HB[0]);return}let ee=HB.indexOf(Pe)+1;ee===HB.length?g(null):g(HB[ee])},[Pe,g]);let Ee=W.parseIdent(ae.name),De=W.prettyIdent(v,Ee);return h.createElement(A,null,h.createElement(A,{width:45},h.createElement(p,{bold:!0,wrap:"wrap"},De)),h.createElement(A,{width:14,marginLeft:1},h.createElement(p,{bold:!0,wrap:"truncate"},ae.owner.name)),h.createElement(A,{width:10,marginLeft:1},h.createElement(p,{italic:!0,wrap:"truncate"},ae.version)),h.createElement(A,{width:16,marginLeft:1},h.createElement(p,null,ae.humanDownloadsLast30Days)))},U=({name:ae,active:we})=>{let[Pe]=a(ae,null),g=W.parseIdent(ae);return h.createElement(A,null,h.createElement(A,{width:47},h.createElement(p,{bold:!0}," - ",W.prettyIdent(v,g))),HB.map(Ee=>h.createElement(A,{key:Ee,width:14,marginLeft:1},h.createElement(p,null," ",h.createElement(e,{active:Pe===Ee})," ",h.createElement(p,{bold:!0},Ee)))))},J=()=>h.createElement(A,{marginTop:1},h.createElement(p,null,"Powered by Algolia.")),le=await n(({useSubmit:ae})=>{let we=a();ae(we);let Pe=Array.from(we.keys()).filter(H=>we.get(H)!==null),[g,Ee]=I(""),[De,ce]=I(0),[ne,ee]=I([]),Ie=H=>{H.match(/\t| /)||Ee(H)},ke=async()=>{ce(0);let H=await e6(g);H.query===g&&ee(H.hits)},ht=async()=>{let H=await e6(g,De+1);H.query===g&&H.page-1===De&&(ce(H.page),ee([...ne,...H.hits]))};return E(()=>{g?ke():ee([])},[g]),h.createElement(A,{flexDirection:"column"},h.createElement(b,null),h.createElement(A,{flexDirection:"row",marginTop:1},h.createElement(p,{bold:!0},"Search: "),h.createElement(A,{width:41},h.createElement(u,{value:g,onChange:Ie,placeholder:"i.e. babel, webpack, react...",showCursor:!1})),h.createElement(C,null)),ne.length?h.createElement(r,{radius:2,loop:!1,children:ne.map(H=>h.createElement(L,{key:H.name,hit:H,active:!1})),willReachEnd:ht}):h.createElement(p,{color:"gray"},"Start typing..."),h.createElement(A,{flexDirection:"row",marginTop:1},h.createElement(A,{width:49},h.createElement(p,{bold:!0},"Selected:")),h.createElement(T,null)),Pe.length?Pe.map(H=>h.createElement(U,{key:H,name:H,active:!1})):h.createElement(p,{color:"gray"},"No selected packages..."),h.createElement(J,null))},{},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof le>"u")return 1;let pe=Array.from(le.keys()).filter(ae=>le.get(ae)==="regular"),Ae=Array.from(le.keys()).filter(ae=>le.get(ae)==="dev"),ye=Array.from(le.keys()).filter(ae=>le.get(ae)==="peer");return pe.length&&await this.cli.run(["add",...pe]),Ae.length&&await this.cli.run(["add","--dev",...Ae]),ye&&await this.cli.run(["add","--peer",...ye]),0}};C0.paths=[["search"]],C0.usage=nt.Usage({category:"Interactive commands",description:"open the search interface",details:` - This command opens a fullscreen terminal interface where you can search for and install packages from the npm registry. - `,examples:[["Open the search window","yarn search"]]});Ye();qt();w_();var fIe=$e(zn()),AIe=/^((?:[\^~]|>=?)?)([0-9]+)(\.[0-9]+)(\.[0-9]+)((?:-\S+)?)$/,pIe=(t,e)=>t.length>0?[t.slice(0,e)].concat(pIe(t.slice(e),e)):[],I0=class extends ut{async execute(){SC(this.context);let{ItemOptions:e}=await Promise.resolve().then(()=>(uIe(),cIe)),{Pad:r}=await Promise.resolve().then(()=>(Nj(),lIe)),{ScrollableItems:o}=await Promise.resolve().then(()=>(gQ(),hQ)),{useMinistore:a}=await Promise.resolve().then(()=>(Qj(),kj)),{renderForm:n}=await Promise.resolve().then(()=>(EQ(),yQ)),{Box:u,Text:A}=await Promise.resolve().then(()=>$e(ic())),{default:p,useEffect:h,useRef:E,useState:I}=await Promise.resolve().then(()=>$e(sn())),v=await Ve.find(this.context.cwd,this.context.plugins),{project:b,workspace:C}=await St.find(v,this.context.cwd),T=await Lr.find(v);if(!C)throw new rr(b.cwd,this.context.cwd);await b.restoreInstallState({restoreResolutions:!1});let L=this.context.stdout.rows-7,U=(Ee,De)=>{let ce=fpe(Ee,De),ne="";for(let ee of ce)ee.added?ne+=de.pretty(v,ee.value,"green"):ee.removed||(ne+=ee.value);return ne},J=(Ee,De)=>{if(Ee===De)return De;let ce=W.parseRange(Ee),ne=W.parseRange(De),ee=ce.selector.match(AIe),Ie=ne.selector.match(AIe);if(!ee||!Ie)return U(Ee,De);let ke=["gray","red","yellow","green","magenta"],ht=null,H="";for(let lt=1;lt{let ne=await zc.fetchDescriptorFrom(Ee,ce,{project:b,cache:T,preserveModifier:De,workspace:C});return ne!==null?ne.range:Ee.range},le=async Ee=>{let De=fIe.default.valid(Ee.range)?`^${Ee.range}`:Ee.range,[ce,ne]=await Promise.all([te(Ee,Ee.range,De).catch(()=>null),te(Ee,Ee.range,"latest").catch(()=>null)]),ee=[{value:null,label:Ee.range}];return ce&&ce!==Ee.range?ee.push({value:ce,label:J(Ee.range,ce)}):ee.push({value:null,label:""}),ne&&ne!==ce&&ne!==Ee.range?ee.push({value:ne,label:J(Ee.range,ne)}):ee.push({value:null,label:""}),ee},pe=()=>p.createElement(u,{flexDirection:"row"},p.createElement(u,{flexDirection:"column",width:49},p.createElement(u,{marginLeft:1},p.createElement(A,null,"Press ",p.createElement(A,{bold:!0,color:"cyanBright"},""),"/",p.createElement(A,{bold:!0,color:"cyanBright"},"")," to select packages.")),p.createElement(u,{marginLeft:1},p.createElement(A,null,"Press ",p.createElement(A,{bold:!0,color:"cyanBright"},""),"/",p.createElement(A,{bold:!0,color:"cyanBright"},"")," to select versions."))),p.createElement(u,{flexDirection:"column"},p.createElement(u,{marginLeft:1},p.createElement(A,null,"Press ",p.createElement(A,{bold:!0,color:"cyanBright"},"")," to install.")),p.createElement(u,{marginLeft:1},p.createElement(A,null,"Press ",p.createElement(A,{bold:!0,color:"cyanBright"},"")," to abort.")))),Ae=()=>p.createElement(u,{flexDirection:"row",paddingTop:1,paddingBottom:1},p.createElement(u,{width:50},p.createElement(A,{bold:!0},p.createElement(A,{color:"greenBright"},"?")," Pick the packages you want to upgrade.")),p.createElement(u,{width:17},p.createElement(A,{bold:!0,underline:!0,color:"gray"},"Current")),p.createElement(u,{width:17},p.createElement(A,{bold:!0,underline:!0,color:"gray"},"Range")),p.createElement(u,{width:17},p.createElement(A,{bold:!0,underline:!0,color:"gray"},"Latest"))),ye=({active:Ee,descriptor:De,suggestions:ce})=>{let[ne,ee]=a(De.descriptorHash,null),Ie=W.stringifyIdent(De),ke=Math.max(0,45-Ie.length);return p.createElement(p.Fragment,null,p.createElement(u,null,p.createElement(u,{width:45},p.createElement(A,{bold:!0},W.prettyIdent(v,De)),p.createElement(r,{active:Ee,length:ke})),p.createElement(e,{active:Ee,options:ce,value:ne,skewer:!0,onChange:ee,sizes:[17,17,17]})))},ae=({dependencies:Ee})=>{let[De,ce]=I(Ee.map(()=>null)),ne=E(!0),ee=async Ie=>{let ke=await le(Ie);return ke.filter(ht=>ht.label!=="").length<=1?null:{descriptor:Ie,suggestions:ke}};return h(()=>()=>{ne.current=!1},[]),h(()=>{let Ie=Math.trunc(L*1.75),ke=Ee.slice(0,Ie),ht=Ee.slice(Ie),H=pIe(ht,L),lt=ke.map(ee).reduce(async(Re,Qe)=>{await Re;let be=await Qe;be!==null&&(!ne.current||ce(_e=>{let Te=_e.findIndex(He=>He===null),Je=[..._e];return Je[Te]=be,Je}))},Promise.resolve());H.reduce((Re,Qe)=>Promise.all(Qe.map(be=>Promise.resolve().then(()=>ee(be)))).then(async be=>{be=be.filter(_e=>_e!==null),await Re,ne.current&&ce(_e=>{let Te=_e.findIndex(Je=>Je===null);return _e.slice(0,Te).concat(be).concat(_e.slice(Te+be.length))})}),lt).then(()=>{ne.current&&ce(Re=>Re.filter(Qe=>Qe!==null))})},[]),De.length?p.createElement(o,{radius:L>>1,children:De.map((Ie,ke)=>Ie!==null?p.createElement(ye,{key:ke,active:!1,descriptor:Ie.descriptor,suggestions:Ie.suggestions}):p.createElement(A,{key:ke},"Loading..."))}):p.createElement(A,null,"No upgrades found")},Pe=await n(({useSubmit:Ee})=>{Ee(a());let De=new Map;for(let ne of b.workspaces)for(let ee of["dependencies","devDependencies"])for(let Ie of ne.manifest[ee].values())b.tryWorkspaceByDescriptor(Ie)===null&&(Ie.range.startsWith("link:")||De.set(Ie.descriptorHash,Ie));let ce=je.sortMap(De.values(),ne=>W.stringifyDescriptor(ne));return p.createElement(u,{flexDirection:"column"},p.createElement(pe,null),p.createElement(Ae,null),p.createElement(ae,{dependencies:ce}))},{},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof Pe>"u")return 1;let g=!1;for(let Ee of b.workspaces)for(let De of["dependencies","devDependencies"]){let ce=Ee.manifest[De];for(let ne of ce.values()){let ee=Pe.get(ne.descriptorHash);typeof ee<"u"&&ee!==null&&(ce.set(ne.identHash,W.makeDescriptor(ne,ee)),g=!0)}}return g?await b.installWithNewReport({quiet:this.context.quiet,stdout:this.context.stdout},{cache:T}):0}};I0.paths=[["upgrade-interactive"]],I0.usage=nt.Usage({category:"Interactive commands",description:"open the upgrade interface",details:` - This command opens a fullscreen terminal interface where you can see any out of date packages used by your application, their status compared to the latest versions available on the remote registry, and select packages to upgrade. - `,examples:[["Open the upgrade window","yarn upgrade-interactive"]]});var aIt={commands:[C0,I0]},lIt=aIt;var Mj={};Kt(Mj,{LinkFetcher:()=>qB,LinkResolver:()=>GB,PortalFetcher:()=>YB,PortalResolver:()=>WB,default:()=>uIt});Ye();Pt();var ep="portal:",tp="link:";var qB=class{supports(e,r){return!!e.reference.startsWith(tp)}getLocalPath(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:tp});if(K.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(o,r);return n===null?null:K.resolve(n,a)}async fetch(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:tp}),n=K.isAbsolute(a)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await r.fetcher.fetch(o,r),u=n.localPath?{packageFs:new gn(Bt.root),prefixPath:K.relative(Bt.root,n.localPath),localPath:Bt.root}:n;n!==u&&n.releaseFs&&n.releaseFs();let A=u.packageFs,p=K.resolve(u.localPath??u.packageFs.getRealPath(),u.prefixPath,a);return n.localPath?{packageFs:new gn(p,{baseFs:A}),releaseFs:u.releaseFs,prefixPath:Bt.dot,discardFromLookup:!0,localPath:p}:{packageFs:new _u(p,{baseFs:A}),releaseFs:u.releaseFs,prefixPath:Bt.dot,discardFromLookup:!0}}};Ye();Pt();var GB=class{supportsDescriptor(e,r){return!!e.range.startsWith(tp)}supportsLocator(e,r){return!!e.reference.startsWith(tp)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=e.range.slice(tp.length);return[W.makeLocator(e,`${tp}${ue.toPortablePath(a)}`)]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){return{...e,version:"0.0.0",languageName:r.project.configuration.get("defaultLanguageName"),linkType:"SOFT",conditions:null,dependencies:new Map,peerDependencies:new Map,dependenciesMeta:new Map,peerDependenciesMeta:new Map,bin:new Map}}};Ye();Pt();var YB=class{supports(e,r){return!!e.reference.startsWith(ep)}getLocalPath(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:ep});if(K.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(o,r);return n===null?null:K.resolve(n,a)}async fetch(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:ep}),n=K.isAbsolute(a)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await r.fetcher.fetch(o,r),u=n.localPath?{packageFs:new gn(Bt.root),prefixPath:K.relative(Bt.root,n.localPath),localPath:Bt.root}:n;n!==u&&n.releaseFs&&n.releaseFs();let A=u.packageFs,p=K.resolve(u.localPath??u.packageFs.getRealPath(),u.prefixPath,a);return n.localPath?{packageFs:new gn(p,{baseFs:A}),releaseFs:u.releaseFs,prefixPath:Bt.dot,localPath:p}:{packageFs:new _u(p,{baseFs:A}),releaseFs:u.releaseFs,prefixPath:Bt.dot}}};Ye();Ye();Pt();var WB=class{supportsDescriptor(e,r){return!!e.range.startsWith(ep)}supportsLocator(e,r){return!!e.reference.startsWith(ep)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=e.range.slice(ep.length);return[W.makeLocator(e,`${ep}${ue.toPortablePath(a)}`)]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Mt.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"SOFT",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var cIt={fetchers:[qB,YB],resolvers:[GB,WB]},uIt=cIt;var Cq={};Kt(Cq,{NodeModulesLinker:()=>lv,NodeModulesMode:()=>dq,PnpLooseLinker:()=>cv,default:()=>P1t});Pt();Ye();Pt();Pt();var Uj=(t,e)=>`${t}@${e}`,hIe=(t,e)=>{let r=e.indexOf("#"),o=r>=0?e.substring(r+1):e;return Uj(t,o)};var mIe=(t,e={})=>{let r=e.debugLevel||Number(process.env.NM_DEBUG_LEVEL||-1),o=e.check||r>=9,a=e.hoistingLimits||new Map,n={check:o,debugLevel:r,hoistingLimits:a,fastLookupPossible:!0},u;n.debugLevel>=0&&(u=Date.now());let A=mIt(t,n),p=!1,h=0;do p=_j(A,[A],new Set([A.locator]),new Map,n).anotherRoundNeeded,n.fastLookupPossible=!1,h++;while(p);if(n.debugLevel>=0&&console.log(`hoist time: ${Date.now()-u}ms, rounds: ${h}`),n.debugLevel>=1){let E=VB(A);if(_j(A,[A],new Set([A.locator]),new Map,n).isGraphChanged)throw new Error(`The hoisting result is not terminal, prev tree: -${E}, next tree: -${VB(A)}`);let v=yIe(A);if(v)throw new Error(`${v}, after hoisting finished: -${VB(A)}`)}return n.debugLevel>=2&&console.log(VB(A)),yIt(A)},AIt=t=>{let e=t[t.length-1],r=new Map,o=new Set,a=n=>{if(!o.has(n)){o.add(n);for(let u of n.hoistedDependencies.values())r.set(u.name,u);for(let u of n.dependencies.values())n.peerNames.has(u.name)||a(u)}};return a(e),r},fIt=t=>{let e=t[t.length-1],r=new Map,o=new Set,a=new Set,n=(u,A)=>{if(o.has(u))return;o.add(u);for(let h of u.hoistedDependencies.values())if(!A.has(h.name)){let E;for(let I of t)E=I.dependencies.get(h.name),E&&r.set(E.name,E)}let p=new Set;for(let h of u.dependencies.values())p.add(h.name);for(let h of u.dependencies.values())u.peerNames.has(h.name)||n(h,p)};return n(e,a),r},gIe=(t,e)=>{if(e.decoupled)return e;let{name:r,references:o,ident:a,locator:n,dependencies:u,originalDependencies:A,hoistedDependencies:p,peerNames:h,reasons:E,isHoistBorder:I,hoistPriority:v,dependencyKind:b,hoistedFrom:C,hoistedTo:T}=e,L={name:r,references:new Set(o),ident:a,locator:n,dependencies:new Map(u),originalDependencies:new Map(A),hoistedDependencies:new Map(p),peerNames:new Set(h),reasons:new Map(E),decoupled:!0,isHoistBorder:I,hoistPriority:v,dependencyKind:b,hoistedFrom:new Map(C),hoistedTo:new Map(T)},U=L.dependencies.get(r);return U&&U.ident==L.ident&&L.dependencies.set(r,L),t.dependencies.set(L.name,L),L},pIt=(t,e)=>{let r=new Map([[t.name,[t.ident]]]);for(let a of t.dependencies.values())t.peerNames.has(a.name)||r.set(a.name,[a.ident]);let o=Array.from(e.keys());o.sort((a,n)=>{let u=e.get(a),A=e.get(n);return A.hoistPriority!==u.hoistPriority?A.hoistPriority-u.hoistPriority:A.peerDependents.size!==u.peerDependents.size?A.peerDependents.size-u.peerDependents.size:A.dependents.size-u.dependents.size});for(let a of o){let n=a.substring(0,a.indexOf("@",1)),u=a.substring(n.length+1);if(!t.peerNames.has(n)){let A=r.get(n);A||(A=[],r.set(n,A)),A.indexOf(u)<0&&A.push(u)}}return r},Oj=t=>{let e=new Set,r=(o,a=new Set)=>{if(!a.has(o)){a.add(o);for(let n of o.peerNames)if(!t.peerNames.has(n)){let u=t.dependencies.get(n);u&&!e.has(u)&&r(u,a)}e.add(o)}};for(let o of t.dependencies.values())t.peerNames.has(o.name)||r(o);return e},_j=(t,e,r,o,a,n=new Set)=>{let u=e[e.length-1];if(n.has(u))return{anotherRoundNeeded:!1,isGraphChanged:!1};n.add(u);let A=EIt(u),p=pIt(u,A),h=t==u?new Map:a.fastLookupPossible?AIt(e):fIt(e),E,I=!1,v=!1,b=new Map(Array.from(p.entries()).map(([T,L])=>[T,L[0]])),C=new Map;do{let T=dIt(t,e,r,h,b,p,o,C,a);T.isGraphChanged&&(v=!0),T.anotherRoundNeeded&&(I=!0),E=!1;for(let[L,U]of p)U.length>1&&!u.dependencies.has(L)&&(b.delete(L),U.shift(),b.set(L,U[0]),E=!0)}while(E);for(let T of u.dependencies.values())if(!u.peerNames.has(T.name)&&!r.has(T.locator)){r.add(T.locator);let L=_j(t,[...e,T],r,C,a);L.isGraphChanged&&(v=!0),L.anotherRoundNeeded&&(I=!0),r.delete(T.locator)}return{anotherRoundNeeded:I,isGraphChanged:v}},hIt=t=>{for(let[e,r]of t.dependencies)if(!t.peerNames.has(e)&&r.ident!==t.ident)return!0;return!1},gIt=(t,e,r,o,a,n,u,A,{outputReason:p,fastLookupPossible:h})=>{let E,I=null,v=new Set;p&&(E=`${Array.from(e).map(L=>no(L)).join("\u2192")}`);let b=r[r.length-1],T=!(o.ident===b.ident);if(p&&!T&&(I="- self-reference"),T&&(T=o.dependencyKind!==1,p&&!T&&(I="- workspace")),T&&o.dependencyKind===2&&(T=!hIt(o),p&&!T&&(I="- external soft link with unhoisted dependencies")),T&&(T=b.dependencyKind!==1||b.hoistedFrom.has(o.name)||e.size===1,p&&!T&&(I=b.reasons.get(o.name))),T&&(T=!t.peerNames.has(o.name),p&&!T&&(I=`- cannot shadow peer: ${no(t.originalDependencies.get(o.name).locator)} at ${E}`)),T){let L=!1,U=a.get(o.name);if(L=!U||U.ident===o.ident,p&&!L&&(I=`- filled by: ${no(U.locator)} at ${E}`),L)for(let J=r.length-1;J>=1;J--){let le=r[J].dependencies.get(o.name);if(le&&le.ident!==o.ident){L=!1;let pe=A.get(b);pe||(pe=new Set,A.set(b,pe)),pe.add(o.name),p&&(I=`- filled by ${no(le.locator)} at ${r.slice(0,J).map(Ae=>no(Ae.locator)).join("\u2192")}`);break}}T=L}if(T&&(T=n.get(o.name)===o.ident,p&&!T&&(I=`- filled by: ${no(u.get(o.name)[0])} at ${E}`)),T){let L=!0,U=new Set(o.peerNames);for(let J=r.length-1;J>=1;J--){let te=r[J];for(let le of U){if(te.peerNames.has(le)&&te.originalDependencies.has(le))continue;let pe=te.dependencies.get(le);pe&&t.dependencies.get(le)!==pe&&(J===r.length-1?v.add(pe):(v=null,L=!1,p&&(I=`- peer dependency ${no(pe.locator)} from parent ${no(te.locator)} was not hoisted to ${E}`))),U.delete(le)}if(!L)break}T=L}if(T&&!h)for(let L of o.hoistedDependencies.values()){let U=a.get(L.name)||t.dependencies.get(L.name);if(!U||L.ident!==U.ident){T=!1,p&&(I=`- previously hoisted dependency mismatch, needed: ${no(L.locator)}, available: ${no(U?.locator)}`);break}}return v!==null&&v.size>0?{isHoistable:2,dependsOn:v,reason:I}:{isHoistable:T?0:1,reason:I}},CQ=t=>`${t.name}@${t.locator}`,dIt=(t,e,r,o,a,n,u,A,p)=>{let h=e[e.length-1],E=new Set,I=!1,v=!1,b=(U,J,te,le,pe)=>{if(E.has(le))return;let Ae=[...J,CQ(le)],ye=[...te,CQ(le)],ae=new Map,we=new Map;for(let ce of Oj(le)){let ne=gIt(h,r,[h,...U,le],ce,o,a,n,A,{outputReason:p.debugLevel>=2,fastLookupPossible:p.fastLookupPossible});if(we.set(ce,ne),ne.isHoistable===2)for(let ee of ne.dependsOn){let Ie=ae.get(ee.name)||new Set;Ie.add(ce.name),ae.set(ee.name,Ie)}}let Pe=new Set,g=(ce,ne,ee)=>{if(!Pe.has(ce)){Pe.add(ce),we.set(ce,{isHoistable:1,reason:ee});for(let Ie of ae.get(ce.name)||[])g(le.dependencies.get(Ie),ne,p.debugLevel>=2?`- peer dependency ${no(ce.locator)} from parent ${no(le.locator)} was not hoisted`:"")}};for(let[ce,ne]of we)ne.isHoistable===1&&g(ce,ne,ne.reason);let Ee=!1;for(let ce of we.keys())if(!Pe.has(ce)){v=!0;let ne=u.get(le);ne&&ne.has(ce.name)&&(I=!0),Ee=!0,le.dependencies.delete(ce.name),le.hoistedDependencies.set(ce.name,ce),le.reasons.delete(ce.name);let ee=h.dependencies.get(ce.name);if(p.debugLevel>=2){let Ie=Array.from(J).concat([le.locator]).map(ht=>no(ht)).join("\u2192"),ke=h.hoistedFrom.get(ce.name);ke||(ke=[],h.hoistedFrom.set(ce.name,ke)),ke.push(Ie),le.hoistedTo.set(ce.name,Array.from(e).map(ht=>no(ht.locator)).join("\u2192"))}if(!ee)h.ident!==ce.ident&&(h.dependencies.set(ce.name,ce),pe.add(ce));else for(let Ie of ce.references)ee.references.add(Ie)}if(le.dependencyKind===2&&Ee&&(I=!0),p.check){let ce=yIe(t);if(ce)throw new Error(`${ce}, after hoisting dependencies of ${[h,...U,le].map(ne=>no(ne.locator)).join("\u2192")}: -${VB(t)}`)}let De=Oj(le);for(let ce of De)if(Pe.has(ce)){let ne=we.get(ce);if((a.get(ce.name)===ce.ident||!le.reasons.has(ce.name))&&ne.isHoistable!==0&&le.reasons.set(ce.name,ne.reason),!ce.isHoistBorder&&ye.indexOf(CQ(ce))<0){E.add(le);let Ie=gIe(le,ce);b([...U,le],Ae,ye,Ie,T),E.delete(le)}}},C,T=new Set(Oj(h)),L=Array.from(e).map(U=>CQ(U));do{C=T,T=new Set;for(let U of C){if(U.locator===h.locator||U.isHoistBorder)continue;let J=gIe(h,U);b([],Array.from(r),L,J,T)}}while(T.size>0);return{anotherRoundNeeded:I,isGraphChanged:v}},yIe=t=>{let e=[],r=new Set,o=new Set,a=(n,u,A)=>{if(r.has(n)||(r.add(n),o.has(n)))return;let p=new Map(u);for(let h of n.dependencies.values())n.peerNames.has(h.name)||p.set(h.name,h);for(let h of n.originalDependencies.values()){let E=p.get(h.name),I=()=>`${Array.from(o).concat([n]).map(v=>no(v.locator)).join("\u2192")}`;if(n.peerNames.has(h.name)){let v=u.get(h.name);(v!==E||!v||v.ident!==h.ident)&&e.push(`${I()} - broken peer promise: expected ${h.ident} but found ${v&&v.ident}`)}else{let v=A.hoistedFrom.get(n.name),b=n.hoistedTo.get(h.name),C=`${v?` hoisted from ${v.join(", ")}`:""}`,T=`${b?` hoisted to ${b}`:""}`,L=`${I()}${C}`;E?E.ident!==h.ident&&e.push(`${L} - broken require promise for ${h.name}${T}: expected ${h.ident}, but found: ${E.ident}`):e.push(`${L} - broken require promise: no required dependency ${h.name}${T} found`)}}o.add(n);for(let h of n.dependencies.values())n.peerNames.has(h.name)||a(h,p,n);o.delete(n)};return a(t,t.dependencies,t),e.join(` -`)},mIt=(t,e)=>{let{identName:r,name:o,reference:a,peerNames:n}=t,u={name:o,references:new Set([a]),locator:Uj(r,a),ident:hIe(r,a),dependencies:new Map,originalDependencies:new Map,hoistedDependencies:new Map,peerNames:new Set(n),reasons:new Map,decoupled:!0,isHoistBorder:!0,hoistPriority:0,dependencyKind:1,hoistedFrom:new Map,hoistedTo:new Map},A=new Map([[t,u]]),p=(h,E)=>{let I=A.get(h),v=!!I;if(!I){let{name:b,identName:C,reference:T,peerNames:L,hoistPriority:U,dependencyKind:J}=h,te=e.hoistingLimits.get(E.locator);I={name:b,references:new Set([T]),locator:Uj(C,T),ident:hIe(C,T),dependencies:new Map,originalDependencies:new Map,hoistedDependencies:new Map,peerNames:new Set(L),reasons:new Map,decoupled:!0,isHoistBorder:te?te.has(b):!1,hoistPriority:U||0,dependencyKind:J||0,hoistedFrom:new Map,hoistedTo:new Map},A.set(h,I)}if(E.dependencies.set(h.name,I),E.originalDependencies.set(h.name,I),v){let b=new Set,C=T=>{if(!b.has(T)){b.add(T),T.decoupled=!1;for(let L of T.dependencies.values())T.peerNames.has(L.name)||C(L)}};C(I)}else for(let b of h.dependencies)p(b,I)};for(let h of t.dependencies)p(h,u);return u},Hj=t=>t.substring(0,t.indexOf("@",1)),yIt=t=>{let e={name:t.name,identName:Hj(t.locator),references:new Set(t.references),dependencies:new Set},r=new Set([t]),o=(a,n,u)=>{let A=r.has(a),p;if(n===a)p=u;else{let{name:h,references:E,locator:I}=a;p={name:h,identName:Hj(I),references:E,dependencies:new Set}}if(u.dependencies.add(p),!A){r.add(a);for(let h of a.dependencies.values())a.peerNames.has(h.name)||o(h,a,p);r.delete(a)}};for(let a of t.dependencies.values())o(a,t,e);return e},EIt=t=>{let e=new Map,r=new Set([t]),o=u=>`${u.name}@${u.ident}`,a=u=>{let A=o(u),p=e.get(A);return p||(p={dependents:new Set,peerDependents:new Set,hoistPriority:0},e.set(A,p)),p},n=(u,A)=>{let p=!!r.has(A);if(a(A).dependents.add(u.ident),!p){r.add(A);for(let E of A.dependencies.values()){let I=a(E);I.hoistPriority=Math.max(I.hoistPriority,E.hoistPriority),A.peerNames.has(E.name)?I.peerDependents.add(A.ident):n(A,E)}}};for(let u of t.dependencies.values())t.peerNames.has(u.name)||n(t,u);return e},no=t=>{if(!t)return"none";let e=t.indexOf("@",1),r=t.substring(0,e);r.endsWith("$wsroot$")&&(r=`wh:${r.replace("$wsroot$","")}`);let o=t.substring(e+1);if(o==="workspace:.")return".";if(o){let a=(o.indexOf("#")>0?o.split("#")[1]:o).replace("npm:","");return o.startsWith("virtual")&&(r=`v:${r}`),a.startsWith("workspace")&&(r=`w:${r}`,a=""),`${r}${a?`@${a}`:""}`}else return`${r}`},dIe=5e4,VB=t=>{let e=0,r=(a,n,u="")=>{if(e>dIe||n.has(a))return"";e++;let A=Array.from(a.dependencies.values()).sort((h,E)=>h.name===E.name?0:h.name>E.name?1:-1),p="";n.add(a);for(let h=0;h":"")+(v!==E.name?`a:${E.name}:`:"")+no(E.locator)+(I?` ${I}`:"")} -`,p+=r(E,n,`${u}${hdIe?` -Tree is too large, part of the tree has been dunped -`:"")};var KB=(o=>(o.WORKSPACES="workspaces",o.DEPENDENCIES="dependencies",o.NONE="none",o))(KB||{}),EIe="node_modules",B0="$wsroot$";var JB=(t,e)=>{let{packageTree:r,hoistingLimits:o,errors:a,preserveSymlinksRequired:n}=wIt(t,e),u=null;if(a.length===0){let A=mIe(r,{hoistingLimits:o});u=BIt(t,A,e)}return{tree:u,errors:a,preserveSymlinksRequired:n}},gA=t=>`${t.name}@${t.reference}`,qj=t=>{let e=new Map;for(let[r,o]of t.entries())if(!o.dirList){let a=e.get(o.locator);a||(a={target:o.target,linkType:o.linkType,locations:[],aliases:o.aliases},e.set(o.locator,a)),a.locations.push(r)}for(let r of e.values())r.locations=r.locations.sort((o,a)=>{let n=o.split(K.delimiter).length,u=a.split(K.delimiter).length;return a===o?0:n!==u?u-n:a>o?1:-1});return e},CIe=(t,e)=>{let r=W.isVirtualLocator(t)?W.devirtualizeLocator(t):t,o=W.isVirtualLocator(e)?W.devirtualizeLocator(e):e;return W.areLocatorsEqual(r,o)},jj=(t,e,r,o)=>{if(t.linkType!=="SOFT")return!1;let a=ue.toPortablePath(r.resolveVirtual&&e.reference&&e.reference.startsWith("virtual:")?r.resolveVirtual(t.packageLocation):t.packageLocation);return K.contains(o,a)===null},CIt=t=>{let e=t.getPackageInformation(t.topLevel);if(e===null)throw new Error("Assertion failed: Expected the top-level package to have been registered");if(t.findPackageLocator(e.packageLocation)===null)throw new Error("Assertion failed: Expected the top-level package to have a physical locator");let o=ue.toPortablePath(e.packageLocation.slice(0,-1)),a=new Map,n={children:new Map},u=t.getDependencyTreeRoots(),A=new Map,p=new Set,h=(v,b)=>{let C=gA(v);if(p.has(C))return;p.add(C);let T=t.getPackageInformation(v);if(T){let L=b?gA(b):"";if(gA(v)!==L&&T.linkType==="SOFT"&&!jj(T,v,t,o)){let U=wIe(T,v,t);(!A.get(U)||v.reference.startsWith("workspace:"))&&A.set(U,v)}for(let[U,J]of T.packageDependencies)J!==null&&(T.packagePeers.has(U)||h(t.getLocator(U,J),v))}};for(let v of u)h(v,null);let E=o.split(K.sep);for(let v of A.values()){let b=t.getPackageInformation(v),T=ue.toPortablePath(b.packageLocation.slice(0,-1)).split(K.sep).slice(E.length),L=n;for(let U of T){let J=L.children.get(U);J||(J={children:new Map},L.children.set(U,J)),L=J}L.workspaceLocator=v}let I=(v,b)=>{if(v.workspaceLocator){let C=gA(b),T=a.get(C);T||(T=new Set,a.set(C,T)),T.add(v.workspaceLocator)}for(let C of v.children.values())I(C,v.workspaceLocator||b)};for(let v of n.children.values())I(v,n.workspaceLocator);return a},wIt=(t,e)=>{let r=[],o=!1,a=new Map,n=CIt(t),u=t.getPackageInformation(t.topLevel);if(u===null)throw new Error("Assertion failed: Expected the top-level package to have been registered");let A=t.findPackageLocator(u.packageLocation);if(A===null)throw new Error("Assertion failed: Expected the top-level package to have a physical locator");let p=ue.toPortablePath(u.packageLocation.slice(0,-1)),h={name:A.name,identName:A.name,reference:A.reference,peerNames:u.packagePeers,dependencies:new Set,dependencyKind:1},E=new Map,I=(b,C)=>`${gA(C)}:${b}`,v=(b,C,T,L,U,J,te,le)=>{let pe=I(b,T),Ae=E.get(pe),ye=!!Ae;!ye&&T.name===A.name&&T.reference===A.reference&&(Ae=h,E.set(pe,h));let ae=jj(C,T,t,p);if(!Ae){let ce=0;ae?ce=2:C.linkType==="SOFT"&&T.name.endsWith(B0)&&(ce=1),Ae={name:b,identName:T.name,reference:T.reference,dependencies:new Set,peerNames:ce===1?new Set:C.packagePeers,dependencyKind:ce},E.set(pe,Ae)}let we;if(ae?we=2:U.linkType==="SOFT"?we=1:we=0,Ae.hoistPriority=Math.max(Ae.hoistPriority||0,we),le&&!ae){let ce=gA({name:L.identName,reference:L.reference}),ne=a.get(ce)||new Set;a.set(ce,ne),ne.add(Ae.name)}let Pe=new Map(C.packageDependencies);if(e.project){let ce=e.project.workspacesByCwd.get(ue.toPortablePath(C.packageLocation.slice(0,-1)));if(ce){let ne=new Set([...Array.from(ce.manifest.peerDependencies.values(),ee=>W.stringifyIdent(ee)),...Array.from(ce.manifest.peerDependenciesMeta.keys())]);for(let ee of ne)Pe.has(ee)||(Pe.set(ee,J.get(ee)||null),Ae.peerNames.add(ee))}}let g=gA({name:T.name.replace(B0,""),reference:T.reference}),Ee=n.get(g);if(Ee)for(let ce of Ee)Pe.set(`${ce.name}${B0}`,ce.reference);(C!==U||C.linkType!=="SOFT"||!ae&&(!e.selfReferencesByCwd||e.selfReferencesByCwd.get(te)))&&L.dependencies.add(Ae);let De=T!==A&&C.linkType==="SOFT"&&!T.name.endsWith(B0)&&!ae;if(!ye&&!De){let ce=new Map;for(let[ne,ee]of Pe)if(ee!==null){let Ie=t.getLocator(ne,ee),ke=t.getLocator(ne.replace(B0,""),ee),ht=t.getPackageInformation(ke);if(ht===null)throw new Error("Assertion failed: Expected the package to have been registered");let H=jj(ht,Ie,t,p);if(e.validateExternalSoftLinks&&e.project&&H){ht.packageDependencies.size>0&&(o=!0);for(let[_e,Te]of ht.packageDependencies)if(Te!==null){let Je=W.parseLocator(Array.isArray(Te)?`${Te[0]}@${Te[1]}`:`${_e}@${Te}`);if(gA(Je)!==gA(Ie)){let He=Pe.get(_e);if(He){let x=W.parseLocator(Array.isArray(He)?`${He[0]}@${He[1]}`:`${_e}@${He}`);CIe(x,Je)||r.push({messageName:71,text:`Cannot link ${W.prettyIdent(e.project.configuration,W.parseIdent(Ie.name))} into ${W.prettyLocator(e.project.configuration,W.parseLocator(`${T.name}@${T.reference}`))} dependency ${W.prettyLocator(e.project.configuration,Je)} conflicts with parent dependency ${W.prettyLocator(e.project.configuration,x)}`})}else{let x=ce.get(_e);if(x){let w=x.target,S=W.parseLocator(Array.isArray(w)?`${w[0]}@${w[1]}`:`${_e}@${w}`);CIe(S,Je)||r.push({messageName:71,text:`Cannot link ${W.prettyIdent(e.project.configuration,W.parseIdent(Ie.name))} into ${W.prettyLocator(e.project.configuration,W.parseLocator(`${T.name}@${T.reference}`))} dependency ${W.prettyLocator(e.project.configuration,Je)} conflicts with dependency ${W.prettyLocator(e.project.configuration,S)} from sibling portal ${W.prettyIdent(e.project.configuration,W.parseIdent(x.portal.name))}`})}else ce.set(_e,{target:Je.reference,portal:Ie})}}}}let lt=e.hoistingLimitsByCwd?.get(te),Re=H?te:K.relative(p,ue.toPortablePath(ht.packageLocation))||Bt.dot,Qe=e.hoistingLimitsByCwd?.get(Re);v(ne,ht,Ie,Ae,C,Pe,Re,lt==="dependencies"||Qe==="dependencies"||Qe==="workspaces")}}};return v(A.name,u,A,h,u,u.packageDependencies,Bt.dot,!1),{packageTree:h,hoistingLimits:a,errors:r,preserveSymlinksRequired:o}};function wIe(t,e,r){let o=r.resolveVirtual&&e.reference&&e.reference.startsWith("virtual:")?r.resolveVirtual(t.packageLocation):t.packageLocation;return ue.toPortablePath(o||t.packageLocation)}function IIt(t,e,r){let o=e.getLocator(t.name.replace(B0,""),t.reference),a=e.getPackageInformation(o);if(a===null)throw new Error("Assertion failed: Expected the package to be registered");return r.pnpifyFs?{linkType:"SOFT",target:ue.toPortablePath(a.packageLocation)}:{linkType:a.linkType,target:wIe(a,t,e)}}var BIt=(t,e,r)=>{let o=new Map,a=(E,I,v)=>{let{linkType:b,target:C}=IIt(E,t,r);return{locator:gA(E),nodePath:I,target:C,linkType:b,aliases:v}},n=E=>{let[I,v]=E.split("/");return v?{scope:I,name:v}:{scope:null,name:I}},u=new Set,A=(E,I,v)=>{if(u.has(E))return;u.add(E);let b=Array.from(E.references).sort().join("#");for(let C of E.dependencies){let T=Array.from(C.references).sort().join("#");if(C.identName===E.identName.replace(B0,"")&&T===b)continue;let L=Array.from(C.references).sort(),U={name:C.identName,reference:L[0]},{name:J,scope:te}=n(C.name),le=te?[te,J]:[J],pe=K.join(I,EIe),Ae=K.join(pe,...le),ye=`${v}/${U.name}`,ae=a(U,v,L.slice(1)),we=!1;if(ae.linkType==="SOFT"&&r.project){let Pe=r.project.workspacesByCwd.get(ae.target.slice(0,-1));we=!!(Pe&&!Pe.manifest.name)}if(!C.name.endsWith(B0)&&!we){let Pe=o.get(Ae);if(Pe){if(Pe.dirList)throw new Error(`Assertion failed: ${Ae} cannot merge dir node with leaf node`);{let De=W.parseLocator(Pe.locator),ce=W.parseLocator(ae.locator);if(Pe.linkType!==ae.linkType)throw new Error(`Assertion failed: ${Ae} cannot merge nodes with different link types ${Pe.nodePath}/${W.stringifyLocator(De)} and ${v}/${W.stringifyLocator(ce)}`);if(De.identHash!==ce.identHash)throw new Error(`Assertion failed: ${Ae} cannot merge nodes with different idents ${Pe.nodePath}/${W.stringifyLocator(De)} and ${v}/s${W.stringifyLocator(ce)}`);ae.aliases=[...ae.aliases,...Pe.aliases,W.parseLocator(Pe.locator).reference]}}o.set(Ae,ae);let g=Ae.split("/"),Ee=g.indexOf(EIe);for(let De=g.length-1;Ee>=0&&De>Ee;De--){let ce=ue.toPortablePath(g.slice(0,De).join(K.sep)),ne=g[De],ee=o.get(ce);if(!ee)o.set(ce,{dirList:new Set([ne])});else if(ee.dirList){if(ee.dirList.has(ne))break;ee.dirList.add(ne)}}}A(C,ae.linkType==="SOFT"?ae.target:Ae,ye)}},p=a({name:e.name,reference:Array.from(e.references)[0]},"",[]),h=p.target;return o.set(h,p),A(e,h,""),o};Ye();Ye();Pt();Pt();nA();Nl();var lq={};Kt(lq,{PnpInstaller:()=>dm,PnpLinker:()=>P0,UnplugCommand:()=>x0,default:()=>$It,getPnpPath:()=>S0,jsInstallUtils:()=>mA,pnpUtils:()=>av,quotePathIfNeeded:()=>s1e});Pt();var i1e=Be("url");Ye();Ye();Pt();Pt();var IIe={["DEFAULT"]:{collapsed:!1,next:{["*"]:"DEFAULT"}},["TOP_LEVEL"]:{collapsed:!1,next:{fallbackExclusionList:"FALLBACK_EXCLUSION_LIST",packageRegistryData:"PACKAGE_REGISTRY_DATA",["*"]:"DEFAULT"}},["FALLBACK_EXCLUSION_LIST"]:{collapsed:!1,next:{["*"]:"FALLBACK_EXCLUSION_ENTRIES"}},["FALLBACK_EXCLUSION_ENTRIES"]:{collapsed:!0,next:{["*"]:"FALLBACK_EXCLUSION_DATA"}},["FALLBACK_EXCLUSION_DATA"]:{collapsed:!0,next:{["*"]:"DEFAULT"}},["PACKAGE_REGISTRY_DATA"]:{collapsed:!1,next:{["*"]:"PACKAGE_REGISTRY_ENTRIES"}},["PACKAGE_REGISTRY_ENTRIES"]:{collapsed:!0,next:{["*"]:"PACKAGE_STORE_DATA"}},["PACKAGE_STORE_DATA"]:{collapsed:!1,next:{["*"]:"PACKAGE_STORE_ENTRIES"}},["PACKAGE_STORE_ENTRIES"]:{collapsed:!0,next:{["*"]:"PACKAGE_INFORMATION_DATA"}},["PACKAGE_INFORMATION_DATA"]:{collapsed:!1,next:{packageDependencies:"PACKAGE_DEPENDENCIES",["*"]:"DEFAULT"}},["PACKAGE_DEPENDENCIES"]:{collapsed:!1,next:{["*"]:"PACKAGE_DEPENDENCY"}},["PACKAGE_DEPENDENCY"]:{collapsed:!0,next:{["*"]:"DEFAULT"}}};function vIt(t,e,r){let o="";o+="[";for(let a=0,n=t.length;a"u"||(A!==0&&(a+=", "),a+=JSON.stringify(p),a+=": ",a+=wQ(p,h,e,r).replace(/^ +/g,""),A+=1)}return a+="}",a}function SIt(t,e,r){let o=Object.keys(t),a=`${r} `,n="";n+=r,n+=`{ -`;let u=0;for(let A=0,p=o.length;A"u"||(u!==0&&(n+=",",n+=` -`),n+=a,n+=JSON.stringify(h),n+=": ",n+=wQ(h,E,e,a).replace(/^ +/g,""),u+=1)}return u!==0&&(n+=` -`),n+=r,n+="}",n}function wQ(t,e,r,o){let{next:a}=IIe[r],n=a[t]||a["*"];return BIe(e,n,o)}function BIe(t,e,r){let{collapsed:o}=IIe[e];return Array.isArray(t)?o?vIt(t,e,r):DIt(t,e,r):typeof t=="object"&&t!==null?o?PIt(t,e,r):SIt(t,e,r):JSON.stringify(t)}function vIe(t){return BIe(t,"TOP_LEVEL","")}function zB(t,e){let r=Array.from(t);Array.isArray(e)||(e=[e]);let o=[];for(let n of e)o.push(r.map(u=>n(u)));let a=r.map((n,u)=>u);return a.sort((n,u)=>{for(let A of o){let p=A[n]A[u]?1:0;if(p!==0)return p}return 0}),a.map(n=>r[n])}function xIt(t){let e=new Map,r=zB(t.fallbackExclusionList||[],[({name:o,reference:a})=>o,({name:o,reference:a})=>a]);for(let{name:o,reference:a}of r){let n=e.get(o);typeof n>"u"&&e.set(o,n=new Set),n.add(a)}return Array.from(e).map(([o,a])=>[o,Array.from(a)])}function bIt(t){return zB(t.fallbackPool||[],([e])=>e)}function kIt(t){let e=[];for(let[r,o]of zB(t.packageRegistry,([a])=>a===null?"0":`1${a}`)){let a=[];e.push([r,a]);for(let[n,{packageLocation:u,packageDependencies:A,packagePeers:p,linkType:h,discardFromLookup:E}]of zB(o,([I])=>I===null?"0":`1${I}`)){let I=[];r!==null&&n!==null&&!A.has(r)&&I.push([r,n]);for(let[C,T]of zB(A.entries(),([L])=>L))I.push([C,T]);let v=p&&p.size>0?Array.from(p):void 0,b=E||void 0;a.push([n,{packageLocation:u,packageDependencies:I,packagePeers:v,linkType:h,discardFromLookup:b}])}}return e}function XB(t){return{__info:["This file is automatically generated. Do not touch it, or risk","your modifications being lost."],dependencyTreeRoots:t.dependencyTreeRoots,enableTopLevelFallback:t.enableTopLevelFallback||!1,ignorePatternData:t.ignorePattern||null,fallbackExclusionList:xIt(t),fallbackPool:bIt(t),packageRegistryData:kIt(t)}}var SIe=$e(PIe());function xIe(t,e){return[t?`${t} -`:"",`/* eslint-disable */ -`,`"use strict"; -`,` -`,e,` -`,(0,SIe.default)()].join("")}function QIt(t){return JSON.stringify(t,null,2)}function FIt(t){return`'${t.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/\n/g,`\\ -`)}'`}function TIt(t){return[`const RAW_RUNTIME_STATE = -`,`${FIt(vIe(t))}; - -`,`function $$SETUP_STATE(hydrateRuntimeState, basePath) { -`,` return hydrateRuntimeState(JSON.parse(RAW_RUNTIME_STATE), {basePath: basePath || __dirname}); -`,`} -`].join("")}function RIt(){return[`function $$SETUP_STATE(hydrateRuntimeState, basePath) { -`,` const fs = require('fs'); -`,` const path = require('path'); -`,` const pnpDataFilepath = path.resolve(__dirname, ${JSON.stringify(dr.pnpData)}); -`,` return hydrateRuntimeState(JSON.parse(fs.readFileSync(pnpDataFilepath, 'utf8')), {basePath: basePath || __dirname}); -`,`} -`].join("")}function bIe(t){let e=XB(t),r=TIt(e);return xIe(t.shebang,r)}function kIe(t){let e=XB(t),r=RIt(),o=xIe(t.shebang,r);return{dataFile:QIt(e),loaderFile:o}}Pt();function Yj(t,{basePath:e}){let r=ue.toPortablePath(e),o=K.resolve(r),a=t.ignorePatternData!==null?new RegExp(t.ignorePatternData):null,n=new Map,u=new Map(t.packageRegistryData.map(([I,v])=>[I,new Map(v.map(([b,C])=>{if(I===null!=(b===null))throw new Error("Assertion failed: The name and reference should be null, or neither should");let T=C.discardFromLookup??!1,L={name:I,reference:b},U=n.get(C.packageLocation);U?(U.discardFromLookup=U.discardFromLookup&&T,T||(U.locator=L)):n.set(C.packageLocation,{locator:L,discardFromLookup:T});let J=null;return[b,{packageDependencies:new Map(C.packageDependencies),packagePeers:new Set(C.packagePeers),linkType:C.linkType,discardFromLookup:T,get packageLocation(){return J||(J=K.join(o,C.packageLocation))}}]}))])),A=new Map(t.fallbackExclusionList.map(([I,v])=>[I,new Set(v)])),p=new Map(t.fallbackPool),h=t.dependencyTreeRoots,E=t.enableTopLevelFallback;return{basePath:r,dependencyTreeRoots:h,enableTopLevelFallback:E,fallbackExclusionList:A,fallbackPool:p,ignorePattern:a,packageLocatorsByLocations:n,packageRegistry:u}}Pt();Pt();var rp=Be("module"),gm=Be("url"),tq=Be("util");var Oo=Be("url");var RIe=$e(Be("assert"));var Wj=Array.isArray,ZB=JSON.stringify,$B=Object.getOwnPropertyNames,pm=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),Vj=(t,e)=>RegExp.prototype.exec.call(t,e),Kj=(t,...e)=>RegExp.prototype[Symbol.replace].apply(t,e),v0=(t,...e)=>String.prototype.endsWith.apply(t,e),Jj=(t,...e)=>String.prototype.includes.apply(t,e),zj=(t,...e)=>String.prototype.lastIndexOf.apply(t,e),ev=(t,...e)=>String.prototype.indexOf.apply(t,e),QIe=(t,...e)=>String.prototype.replace.apply(t,e),D0=(t,...e)=>String.prototype.slice.apply(t,e),dA=(t,...e)=>String.prototype.startsWith.apply(t,e),FIe=Map,TIe=JSON.parse;function tv(t,e,r){return class extends r{constructor(...o){super(e(...o)),this.code=t,this.name=`${r.name} [${t}]`}}}var NIe=tv("ERR_PACKAGE_IMPORT_NOT_DEFINED",(t,e,r)=>`Package import specifier "${t}" is not defined${e?` in package ${e}package.json`:""} imported from ${r}`,TypeError),Xj=tv("ERR_INVALID_MODULE_SPECIFIER",(t,e,r=void 0)=>`Invalid module "${t}" ${e}${r?` imported from ${r}`:""}`,TypeError),LIe=tv("ERR_INVALID_PACKAGE_TARGET",(t,e,r,o=!1,a=void 0)=>{let n=typeof r=="string"&&!o&&r.length&&!dA(r,"./");return e==="."?((0,RIe.default)(o===!1),`Invalid "exports" main target ${ZB(r)} defined in the package config ${t}package.json${a?` imported from ${a}`:""}${n?'; targets must start with "./"':""}`):`Invalid "${o?"imports":"exports"}" target ${ZB(r)} defined for '${e}' in the package config ${t}package.json${a?` imported from ${a}`:""}${n?'; targets must start with "./"':""}`},Error),rv=tv("ERR_INVALID_PACKAGE_CONFIG",(t,e,r)=>`Invalid package config ${t}${e?` while importing ${e}`:""}${r?`. ${r}`:""}`,Error),MIe=tv("ERR_PACKAGE_PATH_NOT_EXPORTED",(t,e,r=void 0)=>e==="."?`No "exports" main defined in ${t}package.json${r?` imported from ${r}`:""}`:`Package subpath '${e}' is not defined by "exports" in ${t}package.json${r?` imported from ${r}`:""}`,Error);var BQ=Be("url");function OIe(t,e){let r=Object.create(null);for(let o=0;oe):t+e}nv(r,t,o,u,a)}Vj(_Ie,D0(t,2))!==null&&nv(r,t,o,u,a);let p=new URL(t,o),h=p.pathname,E=new URL(".",o).pathname;if(dA(h,E)||nv(r,t,o,u,a),e==="")return p;if(Vj(_Ie,e)!==null){let I=n?QIe(r,"*",()=>e):r+e;MIt(I,o,u,a)}return n?new URL(Kj(HIe,p.href,()=>e)):new URL(e,p)}function UIt(t){let e=+t;return`${e}`!==t?!1:e>=0&&e<4294967295}function qC(t,e,r,o,a,n,u,A){if(typeof e=="string")return OIt(e,r,o,t,a,n,u,A);if(Wj(e)){if(e.length===0)return null;let p;for(let h=0;hn?-1:n>a||r===-1?1:o===-1||t.length>e.length?-1:e.length>t.length?1:0}function _It(t,e,r){if(typeof t=="string"||Wj(t))return!0;if(typeof t!="object"||t===null)return!1;let o=$B(t),a=!1,n=0;for(let u=0;u=h.length&&v0(e,I)&&qIe(n,h)===1&&zj(h,"*")===E&&(n=h,u=D0(e,E,e.length-I.length))}}if(n){let p=r[n],h=qC(t,p,u,n,o,!0,!1,a);return h==null&&Zj(e,t,o),h}Zj(e,t,o)}function YIe({name:t,base:e,conditions:r,readFileSyncFn:o}){if(t==="#"||dA(t,"#/")||v0(t,"/")){let u="is not a valid internal imports specifier name";throw new Xj(t,u,(0,Oo.fileURLToPath)(e))}let a,n=UIe(e,o);if(n.exists){a=(0,Oo.pathToFileURL)(n.pjsonPath);let u=n.imports;if(u)if(pm(u,t)&&!Jj(t,"*")){let A=qC(a,u[t],"",t,e,!1,!0,r);if(A!=null)return A}else{let A="",p,h=$B(u);for(let E=0;E=I.length&&v0(t,b)&&qIe(A,I)===1&&zj(I,"*")===v&&(A=I,p=D0(t,v,t.length-b.length))}}if(A){let E=u[A],I=qC(a,E,p,A,e,!0,!0,r);if(I!=null)return I}}}LIt(t,a,e)}Pt();var jIt=new Set(["BUILTIN_NODE_RESOLUTION_FAILED","MISSING_DEPENDENCY","MISSING_PEER_DEPENDENCY","QUALIFIED_PATH_RESOLUTION_FAILED","UNDECLARED_DEPENDENCY"]);function $i(t,e,r={},o){o??=jIt.has(t)?"MODULE_NOT_FOUND":t;let a={configurable:!0,writable:!0,enumerable:!1};return Object.defineProperties(new Error(e),{code:{...a,value:o},pnpCode:{...a,value:t},data:{...a,value:r}})}function au(t){return ue.normalize(ue.fromPortablePath(t))}var JIe=$e(VIe());function zIe(t){return qIt(),eq[t]}var eq;function qIt(){eq||(eq={"--conditions":[],...KIe(GIt()),...KIe(process.execArgv)})}function KIe(t){return(0,JIe.default)({"--conditions":[String],"-C":"--conditions"},{argv:t,permissive:!0})}function GIt(){let t=[],e=YIt(process.env.NODE_OPTIONS||"",t);return t.length,e}function YIt(t,e){let r=[],o=!1,a=!0;for(let n=0;nparseInt(t,10)),XIe=hm>19||hm===19&&sv>=2||hm===18&&sv>=13,Bzt=hm===20&&sv<6||hm===19&&sv>=3,vzt=hm>19||hm===19&&sv>=6;function ZIe(t){if(process.env.WATCH_REPORT_DEPENDENCIES&&process.send)if(t=t.map(e=>ue.fromPortablePath(mi.resolveVirtual(ue.toPortablePath(e)))),XIe)process.send({"watch:require":t});else for(let e of t)process.send({"watch:require":e})}function rq(t,e){let r=Number(process.env.PNP_ALWAYS_WARN_ON_FALLBACK)>0,o=Number(process.env.PNP_DEBUG_LEVEL),a=/^(?![a-zA-Z]:[\\/]|\\\\|\.{0,2}(?:\/|$))((?:node:)?(?:@[^/]+\/)?[^/]+)\/*(.*|)$/,n=/^(\/|\.{1,2}(\/|$))/,u=/\/$/,A=/^\.{0,2}\//,p={name:null,reference:null},h=[],E=new Set;if(t.enableTopLevelFallback===!0&&h.push(p),e.compatibilityMode!==!1)for(let Re of["react-scripts","gatsby"]){let Qe=t.packageRegistry.get(Re);if(Qe)for(let be of Qe.keys()){if(be===null)throw new Error("Assertion failed: This reference shouldn't be null");h.push({name:Re,reference:be})}}let{ignorePattern:I,packageRegistry:v,packageLocatorsByLocations:b}=t;function C(Re,Qe){return{fn:Re,args:Qe,error:null,result:null}}function T(Re){let Qe=process.stderr?.hasColors?.()??process.stdout.isTTY,be=(Je,He)=>`\x1B[${Je}m${He}\x1B[0m`,_e=Re.error;console.error(_e?be("31;1",`\u2716 ${Re.error?.message.replace(/\n.*/s,"")}`):be("33;1","\u203C Resolution")),Re.args.length>0&&console.error();for(let Je of Re.args)console.error(` ${be("37;1","In \u2190")} ${(0,tq.inspect)(Je,{colors:Qe,compact:!0})}`);Re.result&&(console.error(),console.error(` ${be("37;1","Out \u2192")} ${(0,tq.inspect)(Re.result,{colors:Qe,compact:!0})}`));let Te=new Error().stack.match(/(?<=^ +)at.*/gm)?.slice(2)??[];if(Te.length>0){console.error();for(let Je of Te)console.error(` ${be("38;5;244",Je)}`)}console.error()}function L(Re,Qe){if(e.allowDebug===!1)return Qe;if(Number.isFinite(o)){if(o>=2)return(...be)=>{let _e=C(Re,be);try{return _e.result=Qe(...be)}catch(Te){throw _e.error=Te}finally{T(_e)}};if(o>=1)return(...be)=>{try{return Qe(...be)}catch(_e){let Te=C(Re,be);throw Te.error=_e,T(Te),_e}}}return Qe}function U(Re){let Qe=g(Re);if(!Qe)throw $i("INTERNAL","Couldn't find a matching entry in the dependency tree for the specified parent (this is probably an internal error)");return Qe}function J(Re){if(Re.name===null)return!0;for(let Qe of t.dependencyTreeRoots)if(Qe.name===Re.name&&Qe.reference===Re.reference)return!0;return!1}let te=new Set(["node","require",...zIe("--conditions")]);function le(Re,Qe=te,be){let _e=ce(K.join(Re,"internal.js"),{resolveIgnored:!0,includeDiscardFromLookup:!0});if(_e===null)throw $i("INTERNAL",`The locator that owns the "${Re}" path can't be found inside the dependency tree (this is probably an internal error)`);let{packageLocation:Te}=U(_e),Je=K.join(Te,dr.manifest);if(!e.fakeFs.existsSync(Je))return null;let He=JSON.parse(e.fakeFs.readFileSync(Je,"utf8"));if(He.exports==null)return null;let x=K.contains(Te,Re);if(x===null)throw $i("INTERNAL","unqualifiedPath doesn't contain the packageLocation (this is probably an internal error)");x!=="."&&!A.test(x)&&(x=`./${x}`);try{let w=GIe({packageJSONUrl:(0,gm.pathToFileURL)(ue.fromPortablePath(Je)),packageSubpath:x,exports:He.exports,base:be?(0,gm.pathToFileURL)(ue.fromPortablePath(be)):null,conditions:Qe});return ue.toPortablePath((0,gm.fileURLToPath)(w))}catch(w){throw $i("EXPORTS_RESOLUTION_FAILED",w.message,{unqualifiedPath:au(Re),locator:_e,pkgJson:He,subpath:au(x),conditions:Qe},w.code)}}function pe(Re,Qe,{extensions:be}){let _e;try{Qe.push(Re),_e=e.fakeFs.statSync(Re)}catch{}if(_e&&!_e.isDirectory())return e.fakeFs.realpathSync(Re);if(_e&&_e.isDirectory()){let Te;try{Te=JSON.parse(e.fakeFs.readFileSync(K.join(Re,dr.manifest),"utf8"))}catch{}let Je;if(Te&&Te.main&&(Je=K.resolve(Re,Te.main)),Je&&Je!==Re){let He=pe(Je,Qe,{extensions:be});if(He!==null)return He}}for(let Te=0,Je=be.length;Te{let x=JSON.stringify(He.name);if(_e.has(x))return;_e.add(x);let w=Ee(He);for(let S of w)if(U(S).packagePeers.has(Re))Te(S);else{let F=be.get(S.name);typeof F>"u"&&be.set(S.name,F=new Set),F.add(S.reference)}};Te(Qe);let Je=[];for(let He of[...be.keys()].sort())for(let x of[...be.get(He)].sort())Je.push({name:He,reference:x});return Je}function ce(Re,{resolveIgnored:Qe=!1,includeDiscardFromLookup:be=!1}={}){if(ae(Re)&&!Qe)return null;let _e=K.relative(t.basePath,Re);_e.match(n)||(_e=`./${_e}`),_e.endsWith("/")||(_e=`${_e}/`);do{let Te=b.get(_e);if(typeof Te>"u"||Te.discardFromLookup&&!be){_e=_e.substring(0,_e.lastIndexOf("/",_e.length-2)+1);continue}return Te.locator}while(_e!=="");return null}function ne(Re){try{return e.fakeFs.readFileSync(ue.toPortablePath(Re),"utf8")}catch(Qe){if(Qe.code==="ENOENT")return;throw Qe}}function ee(Re,Qe,{considerBuiltins:be=!0}={}){if(Re.startsWith("#"))throw new Error("resolveToUnqualified can not handle private import mappings");if(Re==="pnpapi")return ue.toPortablePath(e.pnpapiResolution);if(be&&(0,rp.isBuiltin)(Re))return null;let _e=au(Re),Te=Qe&&au(Qe);if(Qe&&ae(Qe)&&(!K.isAbsolute(Re)||ce(Re)===null)){let x=ye(Re,Qe);if(x===!1)throw $i("BUILTIN_NODE_RESOLUTION_FAILED",`The builtin node resolution algorithm was unable to resolve the requested module (it didn't go through the pnp resolver because the issuer was explicitely ignored by the regexp) - -Require request: "${_e}" -Required by: ${Te} -`,{request:_e,issuer:Te});return ue.toPortablePath(x)}let Je,He=Re.match(a);if(He){if(!Qe)throw $i("API_ERROR","The resolveToUnqualified function must be called with a valid issuer when the path isn't a builtin nor absolute",{request:_e,issuer:Te});let[,x,w]=He,S=ce(Qe);if(!S){let Ne=ye(Re,Qe);if(Ne===!1)throw $i("BUILTIN_NODE_RESOLUTION_FAILED",`The builtin node resolution algorithm was unable to resolve the requested module (it didn't go through the pnp resolver because the issuer doesn't seem to be part of the Yarn-managed dependency tree). - -Require path: "${_e}" -Required by: ${Te} -`,{request:_e,issuer:Te});return ue.toPortablePath(Ne)}let F=U(S).packageDependencies.get(x),z=null;if(F==null&&S.name!==null){let Ne=t.fallbackExclusionList.get(S.name);if(!Ne||!Ne.has(S.reference)){for(let dt=0,jt=h.length;dtJ(ot))?X=$i("MISSING_PEER_DEPENDENCY",`${S.name} tried to access ${x} (a peer dependency) but it isn't provided by your application; this makes the require call ambiguous and unsound. - -Required package: ${x}${x!==_e?` (via "${_e}")`:""} -Required by: ${S.name}@${S.reference} (via ${Te}) -${Ne.map(ot=>`Ancestor breaking the chain: ${ot.name}@${ot.reference} -`).join("")} -`,{request:_e,issuer:Te,issuerLocator:Object.assign({},S),dependencyName:x,brokenAncestors:Ne}):X=$i("MISSING_PEER_DEPENDENCY",`${S.name} tried to access ${x} (a peer dependency) but it isn't provided by its ancestors; this makes the require call ambiguous and unsound. - -Required package: ${x}${x!==_e?` (via "${_e}")`:""} -Required by: ${S.name}@${S.reference} (via ${Te}) - -${Ne.map(ot=>`Ancestor breaking the chain: ${ot.name}@${ot.reference} -`).join("")} -`,{request:_e,issuer:Te,issuerLocator:Object.assign({},S),dependencyName:x,brokenAncestors:Ne})}else F===void 0&&(!be&&(0,rp.isBuiltin)(Re)?J(S)?X=$i("UNDECLARED_DEPENDENCY",`Your application tried to access ${x}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since ${x} isn't otherwise declared in your dependencies, this makes the require call ambiguous and unsound. - -Required package: ${x}${x!==_e?` (via "${_e}")`:""} -Required by: ${Te} -`,{request:_e,issuer:Te,dependencyName:x}):X=$i("UNDECLARED_DEPENDENCY",`${S.name} tried to access ${x}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since ${x} isn't otherwise declared in ${S.name}'s dependencies, this makes the require call ambiguous and unsound. - -Required package: ${x}${x!==_e?` (via "${_e}")`:""} -Required by: ${Te} -`,{request:_e,issuer:Te,issuerLocator:Object.assign({},S),dependencyName:x}):J(S)?X=$i("UNDECLARED_DEPENDENCY",`Your application tried to access ${x}, but it isn't declared in your dependencies; this makes the require call ambiguous and unsound. - -Required package: ${x}${x!==_e?` (via "${_e}")`:""} -Required by: ${Te} -`,{request:_e,issuer:Te,dependencyName:x}):X=$i("UNDECLARED_DEPENDENCY",`${S.name} tried to access ${x}, but it isn't declared in its dependencies; this makes the require call ambiguous and unsound. - -Required package: ${x}${x!==_e?` (via "${_e}")`:""} -Required by: ${S.name}@${S.reference} (via ${Te}) -`,{request:_e,issuer:Te,issuerLocator:Object.assign({},S),dependencyName:x}));if(F==null){if(z===null||X===null)throw X||new Error("Assertion failed: Expected an error to have been set");F=z;let Ne=X.message.replace(/\n.*/g,"");X.message=Ne,!E.has(Ne)&&o!==0&&(E.add(Ne),process.emitWarning(X))}let Z=Array.isArray(F)?{name:F[0],reference:F[1]}:{name:x,reference:F},ie=U(Z);if(!ie.packageLocation)throw $i("MISSING_DEPENDENCY",`A dependency seems valid but didn't get installed for some reason. This might be caused by a partial install, such as dev vs prod. - -Required package: ${Z.name}@${Z.reference}${Z.name!==_e?` (via "${_e}")`:""} -Required by: ${S.name}@${S.reference} (via ${Te}) -`,{request:_e,issuer:Te,dependencyLocator:Object.assign({},Z)});let Se=ie.packageLocation;w?Je=K.join(Se,w):Je=Se}else if(K.isAbsolute(Re))Je=K.normalize(Re);else{if(!Qe)throw $i("API_ERROR","The resolveToUnqualified function must be called with a valid issuer when the path isn't a builtin nor absolute",{request:_e,issuer:Te});let x=K.resolve(Qe);Qe.match(u)?Je=K.normalize(K.join(x,Re)):Je=K.normalize(K.join(K.dirname(x),Re))}return K.normalize(Je)}function Ie(Re,Qe,be=te,_e){if(n.test(Re))return Qe;let Te=le(Qe,be,_e);return Te?K.normalize(Te):Qe}function ke(Re,{extensions:Qe=Object.keys(rp.Module._extensions)}={}){let be=[],_e=pe(Re,be,{extensions:Qe});if(_e)return K.normalize(_e);{ZIe(be.map(He=>ue.fromPortablePath(He)));let Te=au(Re),Je=ce(Re);if(Je){let{packageLocation:He}=U(Je),x=!0;try{e.fakeFs.accessSync(He)}catch(w){if(w?.code==="ENOENT")x=!1;else{let S=(w?.message??w??"empty exception thrown").replace(/^[A-Z]/,y=>y.toLowerCase());throw $i("QUALIFIED_PATH_RESOLUTION_FAILED",`Required package exists but could not be accessed (${S}). - -Missing package: ${Je.name}@${Je.reference} -Expected package location: ${au(He)} -`,{unqualifiedPath:Te,extensions:Qe})}}if(!x){let w=He.includes("/unplugged/")?"Required unplugged package missing from disk. This may happen when switching branches without running installs (unplugged packages must be fully materialized on disk to work).":"Required package missing from disk. If you keep your packages inside your repository then restarting the Node process may be enough. Otherwise, try to run an install first.";throw $i("QUALIFIED_PATH_RESOLUTION_FAILED",`${w} - -Missing package: ${Je.name}@${Je.reference} -Expected package location: ${au(He)} -`,{unqualifiedPath:Te,extensions:Qe})}}throw $i("QUALIFIED_PATH_RESOLUTION_FAILED",`Qualified path resolution failed: we looked for the following paths, but none could be accessed. - -Source path: ${Te} -${be.map(He=>`Not found: ${au(He)} -`).join("")}`,{unqualifiedPath:Te,extensions:Qe})}}function ht(Re,Qe,be){if(!Qe)throw new Error("Assertion failed: An issuer is required to resolve private import mappings");let _e=YIe({name:Re,base:(0,gm.pathToFileURL)(ue.fromPortablePath(Qe)),conditions:be.conditions??te,readFileSyncFn:ne});if(_e instanceof URL)return ke(ue.toPortablePath((0,gm.fileURLToPath)(_e)),{extensions:be.extensions});if(_e.startsWith("#"))throw new Error("Mapping from one private import to another isn't allowed");return H(_e,Qe,be)}function H(Re,Qe,be={}){try{if(Re.startsWith("#"))return ht(Re,Qe,be);let{considerBuiltins:_e,extensions:Te,conditions:Je}=be,He=ee(Re,Qe,{considerBuiltins:_e});if(Re==="pnpapi")return He;if(He===null)return null;let x=()=>Qe!==null?ae(Qe):!1,w=(!_e||!(0,rp.isBuiltin)(Re))&&!x()?Ie(Re,He,Je,Qe):He;return ke(w,{extensions:Te})}catch(_e){throw Object.hasOwn(_e,"pnpCode")&&Object.assign(_e.data,{request:au(Re),issuer:Qe&&au(Qe)}),_e}}function lt(Re){let Qe=K.normalize(Re),be=mi.resolveVirtual(Qe);return be!==Qe?be:null}return{VERSIONS:we,topLevel:Pe,getLocator:(Re,Qe)=>Array.isArray(Qe)?{name:Qe[0],reference:Qe[1]}:{name:Re,reference:Qe},getDependencyTreeRoots:()=>[...t.dependencyTreeRoots],getAllLocators(){let Re=[];for(let[Qe,be]of v)for(let _e of be.keys())Qe!==null&&_e!==null&&Re.push({name:Qe,reference:_e});return Re},getPackageInformation:Re=>{let Qe=g(Re);if(Qe===null)return null;let be=ue.fromPortablePath(Qe.packageLocation);return{...Qe,packageLocation:be}},findPackageLocator:Re=>ce(ue.toPortablePath(Re)),resolveToUnqualified:L("resolveToUnqualified",(Re,Qe,be)=>{let _e=Qe!==null?ue.toPortablePath(Qe):null,Te=ee(ue.toPortablePath(Re),_e,be);return Te===null?null:ue.fromPortablePath(Te)}),resolveUnqualified:L("resolveUnqualified",(Re,Qe)=>ue.fromPortablePath(ke(ue.toPortablePath(Re),Qe))),resolveRequest:L("resolveRequest",(Re,Qe,be)=>{let _e=Qe!==null?ue.toPortablePath(Qe):null,Te=H(ue.toPortablePath(Re),_e,be);return Te===null?null:ue.fromPortablePath(Te)}),resolveVirtual:L("resolveVirtual",Re=>{let Qe=lt(ue.toPortablePath(Re));return Qe!==null?ue.fromPortablePath(Qe):null})}}Pt();var $Ie=(t,e,r)=>{let o=XB(t),a=Yj(o,{basePath:e}),n=ue.join(e,dr.pnpCjs);return rq(a,{fakeFs:r,pnpapiResolution:n})};var iq=$e(t1e());qt();var mA={};Kt(mA,{checkManifestCompatibility:()=>r1e,extractBuildRequest:()=>vQ,getExtractHint:()=>sq,hasBindingGyp:()=>oq});Ye();Pt();function r1e(t){return W.isPackageCompatible(t,Ji.getArchitectureSet())}function vQ(t,e,r,{configuration:o}){let a=[];for(let n of["preinstall","install","postinstall"])e.manifest.scripts.has(n)&&a.push({type:0,script:n});return!e.manifest.scripts.has("install")&&e.misc.hasBindingGyp&&a.push({type:1,script:"node-gyp rebuild"}),a.length===0?null:t.linkType!=="HARD"?{skipped:!0,explain:n=>n.reportWarningOnce(6,`${W.prettyLocator(o,t)} lists build scripts, but is referenced through a soft link. Soft links don't support build scripts, so they'll be ignored.`)}:r&&r.built===!1?{skipped:!0,explain:n=>n.reportInfoOnce(5,`${W.prettyLocator(o,t)} lists build scripts, but its build has been explicitly disabled through configuration.`)}:!o.get("enableScripts")&&!r.built?{skipped:!0,explain:n=>n.reportWarningOnce(4,`${W.prettyLocator(o,t)} lists build scripts, but all build scripts have been disabled.`)}:r1e(t)?{skipped:!1,directives:a}:{skipped:!0,explain:n=>n.reportWarningOnce(76,`${W.prettyLocator(o,t)} The ${Ji.getArchitectureName()} architecture is incompatible with this package, build skipped.`)}}var VIt=new Set([".exe",".bin",".h",".hh",".hpp",".c",".cc",".cpp",".java",".jar",".node"]);function sq(t){return t.packageFs.getExtractHint({relevantExtensions:VIt})}function oq(t){let e=K.join(t.prefixPath,"binding.gyp");return t.packageFs.existsSync(e)}var av={};Kt(av,{getUnpluggedPath:()=>ov});Ye();Pt();function ov(t,{configuration:e}){return K.resolve(e.get("pnpUnpluggedFolder"),W.slugifyLocator(t))}var KIt=new Set([W.makeIdent(null,"open").identHash,W.makeIdent(null,"opn").identHash]),P0=class{constructor(){this.mode="strict";this.pnpCache=new Map}getCustomDataKey(){return JSON.stringify({name:"PnpLinker",version:2})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error("Assertion failed: Expected the PnP linker to be enabled");let o=S0(r.project).cjs;if(!oe.existsSync(o))throw new it(`The project in ${de.pretty(r.project.configuration,`${r.project.cwd}/package.json`,de.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let a=je.getFactoryWithDefault(this.pnpCache,o,()=>je.dynamicRequire(o,{cachingStrategy:je.CachingStrategy.FsTime})),n={name:W.stringifyIdent(e),reference:e.reference},u=a.getPackageInformation(n);if(!u)throw new it(`Couldn't find ${W.prettyLocator(r.project.configuration,e)} in the currently installed PnP map - running an install might help`);return ue.toPortablePath(u.packageLocation)}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let o=S0(r.project).cjs;if(!oe.existsSync(o))return null;let n=je.getFactoryWithDefault(this.pnpCache,o,()=>je.dynamicRequire(o,{cachingStrategy:je.CachingStrategy.FsTime})).findPackageLocator(ue.fromPortablePath(e));return n?W.makeLocator(W.parseIdent(n.name),n.reference):null}makeInstaller(e){return new dm(e)}isEnabled(e){return!(e.project.configuration.get("nodeLinker")!=="pnp"||e.project.configuration.get("pnpMode")!==this.mode)}},dm=class{constructor(e){this.opts=e;this.mode="strict";this.asyncActions=new je.AsyncActions(10);this.packageRegistry=new Map;this.virtualTemplates=new Map;this.isESMLoaderRequired=!1;this.customData={store:new Map};this.unpluggedPaths=new Set;this.opts=e}attachCustomData(e){this.customData=e}async installPackage(e,r,o){let a=W.stringifyIdent(e),n=e.reference,u=!!this.opts.project.tryWorkspaceByLocator(e),A=W.isVirtualLocator(e),p=e.peerDependencies.size>0&&!A,h=!p&&!u,E=!p&&e.linkType!=="SOFT",I,v;if(h||E){let te=A?W.devirtualizeLocator(e):e;I=this.customData.store.get(te.locatorHash),typeof I>"u"&&(I=await JIt(r),e.linkType==="HARD"&&this.customData.store.set(te.locatorHash,I)),I.manifest.type==="module"&&(this.isESMLoaderRequired=!0),v=this.opts.project.getDependencyMeta(te,e.version)}let b=h?vQ(e,I,v,{configuration:this.opts.project.configuration}):null,C=E?await this.unplugPackageIfNeeded(e,I,r,v,o):r.packageFs;if(K.isAbsolute(r.prefixPath))throw new Error(`Assertion failed: Expected the prefix path (${r.prefixPath}) to be relative to the parent`);let T=K.resolve(C.getRealPath(),r.prefixPath),L=aq(this.opts.project.cwd,T),U=new Map,J=new Set;if(A){for(let te of e.peerDependencies.values())U.set(W.stringifyIdent(te),null),J.add(W.stringifyIdent(te));if(!u){let te=W.devirtualizeLocator(e);this.virtualTemplates.set(te.locatorHash,{location:aq(this.opts.project.cwd,mi.resolveVirtual(T)),locator:te})}}return je.getMapWithDefault(this.packageRegistry,a).set(n,{packageLocation:L,packageDependencies:U,packagePeers:J,linkType:e.linkType,discardFromLookup:r.discardFromLookup||!1}),{packageLocation:T,buildRequest:b}}async attachInternalDependencies(e,r){let o=this.getPackageInformation(e);for(let[a,n]of r){let u=W.areIdentsEqual(a,n)?n.reference:[W.stringifyIdent(n),n.reference];o.packageDependencies.set(W.stringifyIdent(a),u)}}async attachExternalDependents(e,r){for(let o of r)this.getDiskInformation(o).packageDependencies.set(W.stringifyIdent(e),e.reference)}async finalizeInstall(){if(this.opts.project.configuration.get("pnpMode")!==this.mode)return;let e=S0(this.opts.project);if(this.isEsmEnabled()||await oe.removePromise(e.esmLoader),this.opts.project.configuration.get("nodeLinker")!=="pnp"){await oe.removePromise(e.cjs),await oe.removePromise(e.data),await oe.removePromise(e.esmLoader),await oe.removePromise(this.opts.project.configuration.get("pnpUnpluggedFolder"));return}for(let{locator:E,location:I}of this.virtualTemplates.values())je.getMapWithDefault(this.packageRegistry,W.stringifyIdent(E)).set(E.reference,{packageLocation:I,packageDependencies:new Map,packagePeers:new Set,linkType:"SOFT",discardFromLookup:!1});this.packageRegistry.set(null,new Map([[null,this.getPackageInformation(this.opts.project.topLevelWorkspace.anchoredLocator)]]));let r=this.opts.project.configuration.get("pnpFallbackMode"),o=this.opts.project.workspaces.map(({anchoredLocator:E})=>({name:W.stringifyIdent(E),reference:E.reference})),a=r!=="none",n=[],u=new Map,A=je.buildIgnorePattern([".yarn/sdks/**",...this.opts.project.configuration.get("pnpIgnorePatterns")]),p=this.packageRegistry,h=this.opts.project.configuration.get("pnpShebang");if(r==="dependencies-only")for(let E of this.opts.project.storedPackages.values())this.opts.project.tryWorkspaceByLocator(E)&&n.push({name:W.stringifyIdent(E),reference:E.reference});return await this.asyncActions.wait(),await this.finalizeInstallWithPnp({dependencyTreeRoots:o,enableTopLevelFallback:a,fallbackExclusionList:n,fallbackPool:u,ignorePattern:A,packageRegistry:p,shebang:h}),{customData:this.customData}}async transformPnpSettings(e){}isEsmEnabled(){if(this.opts.project.configuration.sources.has("pnpEnableEsmLoader"))return this.opts.project.configuration.get("pnpEnableEsmLoader");if(this.isESMLoaderRequired)return!0;for(let e of this.opts.project.workspaces)if(e.manifest.type==="module")return!0;return!1}async finalizeInstallWithPnp(e){let r=S0(this.opts.project),o=await this.locateNodeModules(e.ignorePattern);if(o.length>0){this.opts.report.reportWarning(31,"One or more node_modules have been detected and will be removed. This operation may take some time.");for(let n of o)await oe.removePromise(n)}if(await this.transformPnpSettings(e),this.opts.project.configuration.get("pnpEnableInlining")){let n=bIe(e);await oe.changeFilePromise(r.cjs,n,{automaticNewlines:!0,mode:493}),await oe.removePromise(r.data)}else{let{dataFile:n,loaderFile:u}=kIe(e);await oe.changeFilePromise(r.cjs,u,{automaticNewlines:!0,mode:493}),await oe.changeFilePromise(r.data,n,{automaticNewlines:!0,mode:420})}this.isEsmEnabled()&&(this.opts.report.reportWarning(0,"ESM support for PnP uses the experimental loader API and is therefore experimental"),await oe.changeFilePromise(r.esmLoader,(0,iq.default)(),{automaticNewlines:!0,mode:420}));let a=this.opts.project.configuration.get("pnpUnpluggedFolder");if(this.unpluggedPaths.size===0)await oe.removePromise(a);else for(let n of await oe.readdirPromise(a)){let u=K.resolve(a,n);this.unpluggedPaths.has(u)||await oe.removePromise(u)}}async locateNodeModules(e){let r=[],o=e?new RegExp(e):null;for(let a of this.opts.project.workspaces){let n=K.join(a.cwd,"node_modules");if(o&&o.test(K.relative(this.opts.project.cwd,a.cwd))||!oe.existsSync(n))continue;let u=await oe.readdirPromise(n,{withFileTypes:!0}),A=u.filter(p=>!p.isDirectory()||p.name===".bin"||!p.name.startsWith("."));if(A.length===u.length)r.push(n);else for(let p of A)r.push(K.join(n,p.name))}return r}async unplugPackageIfNeeded(e,r,o,a,n){return this.shouldBeUnplugged(e,r,a)?this.unplugPackage(e,o,n):o.packageFs}shouldBeUnplugged(e,r,o){return typeof o.unplugged<"u"?o.unplugged:KIt.has(e.identHash)||e.conditions!=null?!0:r.manifest.preferUnplugged!==null?r.manifest.preferUnplugged:!!(vQ(e,r,o,{configuration:this.opts.project.configuration})?.skipped===!1||r.misc.extractHint)}async unplugPackage(e,r,o){let a=ov(e,{configuration:this.opts.project.configuration});return this.opts.project.disabledLocators.has(e.locatorHash)?new Uu(a,{baseFs:r.packageFs,pathUtils:K}):(this.unpluggedPaths.add(a),o.holdFetchResult(this.asyncActions.set(e.locatorHash,async()=>{let n=K.join(a,r.prefixPath,".ready");await oe.existsPromise(n)||(this.opts.project.storedBuildState.delete(e.locatorHash),await oe.mkdirPromise(a,{recursive:!0}),await oe.copyPromise(a,Bt.dot,{baseFs:r.packageFs,overwrite:!1}),await oe.writeFilePromise(n,""))})),new gn(a))}getPackageInformation(e){let r=W.stringifyIdent(e),o=e.reference,a=this.packageRegistry.get(r);if(!a)throw new Error(`Assertion failed: The package information store should have been available (for ${W.prettyIdent(this.opts.project.configuration,e)})`);let n=a.get(o);if(!n)throw new Error(`Assertion failed: The package information should have been available (for ${W.prettyLocator(this.opts.project.configuration,e)})`);return n}getDiskInformation(e){let r=je.getMapWithDefault(this.packageRegistry,"@@disk"),o=aq(this.opts.project.cwd,e);return je.getFactoryWithDefault(r,o,()=>({packageLocation:o,packageDependencies:new Map,packagePeers:new Set,linkType:"SOFT",discardFromLookup:!1}))}};function aq(t,e){let r=K.relative(t,e);return r.match(/^\.{0,2}\//)||(r=`./${r}`),r.replace(/\/?$/,"/")}async function JIt(t){let e=await Mt.tryFind(t.prefixPath,{baseFs:t.packageFs})??new Mt,r=new Set(["preinstall","install","postinstall"]);for(let o of e.scripts.keys())r.has(o)||e.scripts.delete(o);return{manifest:{scripts:e.scripts,preferUnplugged:e.preferUnplugged,type:e.type},misc:{extractHint:sq(t),hasBindingGyp:oq(t)}}}Ye();Ye();qt();var n1e=$e(Zo());var x0=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Unplug direct dependencies from the entire project"});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Unplug both direct and transitive dependencies"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.patterns=ge.Rest()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);if(r.get("nodeLinker")!=="pnp")throw new it("This command can only be used if the `nodeLinker` option is set to `pnp`");await o.restoreInstallState();let u=new Set(this.patterns),A=this.patterns.map(b=>{let C=W.parseDescriptor(b),T=C.range!=="unknown"?C:W.makeDescriptor(C,"*");if(!kr.validRange(T.range))throw new it(`The range of the descriptor patterns must be a valid semver range (${W.prettyDescriptor(r,T)})`);return L=>{let U=W.stringifyIdent(L);return!n1e.default.isMatch(U,W.stringifyIdent(T))||L.version&&!kr.satisfiesWithPrereleases(L.version,T.range)?!1:(u.delete(b),!0)}}),p=()=>{let b=[];for(let C of o.storedPackages.values())!o.tryWorkspaceByLocator(C)&&!W.isVirtualLocator(C)&&A.some(T=>T(C))&&b.push(C);return b},h=b=>{let C=new Set,T=[],L=(U,J)=>{if(C.has(U.locatorHash))return;let te=!!o.tryWorkspaceByLocator(U);if(!(J>0&&!this.recursive&&te)&&(C.add(U.locatorHash),!o.tryWorkspaceByLocator(U)&&A.some(le=>le(U))&&T.push(U),!(J>0&&!this.recursive)))for(let le of U.dependencies.values()){let pe=o.storedResolutions.get(le.descriptorHash);if(!pe)throw new Error("Assertion failed: The resolution should have been registered");let Ae=o.storedPackages.get(pe);if(!Ae)throw new Error("Assertion failed: The package should have been registered");L(Ae,J+1)}};for(let U of b)L(U.anchoredPackage,0);return T},E,I;if(this.all&&this.recursive?(E=p(),I="the project"):this.all?(E=h(o.workspaces),I="any workspace"):(E=h([a]),I="this workspace"),u.size>1)throw new it(`Patterns ${de.prettyList(r,u,de.Type.CODE)} don't match any packages referenced by ${I}`);if(u.size>0)throw new it(`Pattern ${de.prettyList(r,u,de.Type.CODE)} doesn't match any packages referenced by ${I}`);E=je.sortMap(E,b=>W.stringifyLocator(b));let v=await Nt.start({configuration:r,stdout:this.context.stdout,json:this.json},async b=>{for(let C of E){let T=C.version??"unknown",L=o.topLevelWorkspace.manifest.ensureDependencyMeta(W.makeDescriptor(C,T));L.unplugged=!0,b.reportInfo(0,`Will unpack ${W.prettyLocator(r,C)} to ${de.pretty(r,ov(C,{configuration:r}),de.Type.PATH)}`),b.reportJson({locator:W.stringifyLocator(C),version:T})}await o.topLevelWorkspace.persistManifest(),this.json||b.reportSeparator()});return v.hasErrors()?v.exitCode():await o.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n})}};x0.paths=[["unplug"]],x0.usage=nt.Usage({description:"force the unpacking of a list of packages",details:"\n This command will add the selectors matching the specified patterns to the list of packages that must be unplugged when installed.\n\n A package being unplugged means that instead of being referenced directly through its archive, it will be unpacked at install time in the directory configured via `pnpUnpluggedFolder`. Note that unpacking packages this way is generally not recommended because it'll make it harder to store your packages within the repository. However, it's a good approach to quickly and safely debug some packages, and can even sometimes be required depending on the context (for example when the package contains shellscripts).\n\n Running the command will set a persistent flag inside your top-level `package.json`, in the `dependenciesMeta` field. As such, to undo its effects, you'll need to revert the changes made to the manifest and run `yarn install` to apply the modification.\n\n By default, only direct dependencies from the current workspace are affected. If `-A,--all` is set, direct dependencies from the entire project are affected. Using the `-R,--recursive` flag will affect transitive dependencies as well as direct ones.\n\n This command accepts glob patterns inside the scope and name components (not the range). Make sure to escape the patterns to prevent your own shell from trying to expand them.\n ",examples:[["Unplug the lodash dependency from the active workspace","yarn unplug lodash"],["Unplug all instances of lodash referenced by any workspace","yarn unplug lodash -A"],["Unplug all instances of lodash referenced by the active workspace and its dependencies","yarn unplug lodash -R"],["Unplug all instances of lodash, anywhere","yarn unplug lodash -AR"],["Unplug one specific version of lodash","yarn unplug lodash@1.2.3"],["Unplug all packages with the `@babel` scope","yarn unplug '@babel/*'"],["Unplug all packages (only for testing, not recommended)","yarn unplug -R '*'"]]});var S0=t=>({cjs:K.join(t.cwd,dr.pnpCjs),data:K.join(t.cwd,dr.pnpData),esmLoader:K.join(t.cwd,dr.pnpEsmLoader)}),s1e=t=>/\s/.test(t)?JSON.stringify(t):t;async function zIt(t,e,r){let o=/\s*--require\s+\S*\.pnp\.c?js\s*/g,a=/\s*--experimental-loader\s+\S*\.pnp\.loader\.mjs\s*/,n=(e.NODE_OPTIONS??"").replace(o," ").replace(a," ").trim();if(t.configuration.get("nodeLinker")!=="pnp"){e.NODE_OPTIONS=n;return}let u=S0(t),A=`--require ${s1e(ue.fromPortablePath(u.cjs))}`;oe.existsSync(u.esmLoader)&&(A=`${A} --experimental-loader ${(0,i1e.pathToFileURL)(ue.fromPortablePath(u.esmLoader)).href}`),oe.existsSync(u.cjs)&&(e.NODE_OPTIONS=n?`${A} ${n}`:A)}async function XIt(t,e){let r=S0(t);e(r.cjs),e(r.data),e(r.esmLoader),e(t.configuration.get("pnpUnpluggedFolder"))}var ZIt={hooks:{populateYarnPaths:XIt,setupScriptEnvironment:zIt},configuration:{nodeLinker:{description:'The linker used for installing Node packages, one of: "pnp", "pnpm", or "node-modules"',type:"STRING",default:"pnp"},winLinkType:{description:"Whether Yarn should use Windows Junctions or symlinks when creating links on Windows.",type:"STRING",values:["junctions","symlinks"],default:"junctions"},pnpMode:{description:"If 'strict', generates standard PnP maps. If 'loose', merges them with the n_m resolution.",type:"STRING",default:"strict"},pnpShebang:{description:"String to prepend to the generated PnP script",type:"STRING",default:"#!/usr/bin/env node"},pnpIgnorePatterns:{description:"Array of glob patterns; files matching them will use the classic resolution",type:"STRING",default:[],isArray:!0},pnpEnableEsmLoader:{description:"If true, Yarn will generate an ESM loader (`.pnp.loader.mjs`). If this is not explicitly set Yarn tries to automatically detect whether ESM support is required.",type:"BOOLEAN",default:!1},pnpEnableInlining:{description:"If true, the PnP data will be inlined along with the generated loader",type:"BOOLEAN",default:!0},pnpFallbackMode:{description:"If true, the generated PnP loader will follow the top-level fallback rule",type:"STRING",default:"dependencies-only"},pnpUnpluggedFolder:{description:"Folder where the unplugged packages must be stored",type:"ABSOLUTE_PATH",default:"./.yarn/unplugged"}},linkers:[P0],commands:[x0]},$It=ZIt;var p1e=$e(u1e());qt();var gq=$e(Be("crypto")),h1e=$e(Be("fs")),g1e=1,Pi="node_modules",DQ=".bin",d1e=".yarn-state.yml",d1t=1e3,dq=(o=>(o.CLASSIC="classic",o.HARDLINKS_LOCAL="hardlinks-local",o.HARDLINKS_GLOBAL="hardlinks-global",o))(dq||{}),lv=class{constructor(){this.installStateCache=new Map}getCustomDataKey(){return JSON.stringify({name:"NodeModulesLinker",version:3})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error("Assertion failed: Expected the node-modules linker to be enabled");let o=r.project.tryWorkspaceByLocator(e);if(o)return o.cwd;let a=await je.getFactoryWithDefault(this.installStateCache,r.project.cwd,async()=>await hq(r.project,{unrollAliases:!0}));if(a===null)throw new it("Couldn't find the node_modules state file - running an install might help (findPackageLocation)");let n=a.locatorMap.get(W.stringifyLocator(e));if(!n){let p=new it(`Couldn't find ${W.prettyLocator(r.project.configuration,e)} in the currently installed node_modules map - running an install might help`);throw p.code="LOCATOR_NOT_INSTALLED",p}let u=n.locations.sort((p,h)=>p.split(K.sep).length-h.split(K.sep).length),A=K.join(r.project.configuration.startingCwd,Pi);return u.find(p=>K.contains(A,p))||n.locations[0]}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let o=await je.getFactoryWithDefault(this.installStateCache,r.project.cwd,async()=>await hq(r.project,{unrollAliases:!0}));if(o===null)return null;let{locationRoot:a,segments:n}=PQ(K.resolve(e),{skipPrefix:r.project.cwd}),u=o.locationTree.get(a);if(!u)return null;let A=u.locator;for(let p of n){if(u=u.children.get(p),!u)break;A=u.locator||A}return W.parseLocator(A)}makeInstaller(e){return new pq(e)}isEnabled(e){return e.project.configuration.get("nodeLinker")==="node-modules"}},pq=class{constructor(e){this.opts=e;this.localStore=new Map;this.realLocatorChecksums=new Map;this.customData={store:new Map}}attachCustomData(e){this.customData=e}async installPackage(e,r){let o=K.resolve(r.packageFs.getRealPath(),r.prefixPath),a=this.customData.store.get(e.locatorHash);if(typeof a>"u"&&(a=await m1t(e,r),e.linkType==="HARD"&&this.customData.store.set(e.locatorHash,a)),!W.isPackageCompatible(e,this.opts.project.configuration.getSupportedArchitectures()))return{packageLocation:null,buildRequest:null};let n=new Map,u=new Set;n.has(W.stringifyIdent(e))||n.set(W.stringifyIdent(e),e.reference);let A=e;if(W.isVirtualLocator(e)){A=W.devirtualizeLocator(e);for(let E of e.peerDependencies.values())n.set(W.stringifyIdent(E),null),u.add(W.stringifyIdent(E))}let p={packageLocation:`${ue.fromPortablePath(o)}/`,packageDependencies:n,packagePeers:u,linkType:e.linkType,discardFromLookup:r.discardFromLookup??!1};this.localStore.set(e.locatorHash,{pkg:e,customPackageData:a,dependencyMeta:this.opts.project.getDependencyMeta(e,e.version),pnpNode:p});let h=r.checksum?r.checksum.substring(r.checksum.indexOf("/")+1):null;return this.realLocatorChecksums.set(A.locatorHash,h),{packageLocation:o,buildRequest:null}}async attachInternalDependencies(e,r){let o=this.localStore.get(e.locatorHash);if(typeof o>"u")throw new Error("Assertion failed: Expected information object to have been registered");for(let[a,n]of r){let u=W.areIdentsEqual(a,n)?n.reference:[W.stringifyIdent(n),n.reference];o.pnpNode.packageDependencies.set(W.stringifyIdent(a),u)}}async attachExternalDependents(e,r){throw new Error("External dependencies haven't been implemented for the node-modules linker")}async finalizeInstall(){if(this.opts.project.configuration.get("nodeLinker")!=="node-modules")return;let e=new mi({baseFs:new Jl({maxOpenFiles:80,readOnlyArchives:!0})}),r=await hq(this.opts.project),o=this.opts.project.configuration.get("nmMode");(r===null||o!==r.nmMode)&&(this.opts.project.storedBuildState.clear(),r={locatorMap:new Map,binSymlinks:new Map,locationTree:new Map,nmMode:o,mtimeMs:0});let a=new Map(this.opts.project.workspaces.map(v=>{let b=this.opts.project.configuration.get("nmHoistingLimits");try{b=je.validateEnum(KB,v.manifest.installConfig?.hoistingLimits??b)}catch{let T=W.prettyWorkspace(this.opts.project.configuration,v);this.opts.report.reportWarning(57,`${T}: Invalid 'installConfig.hoistingLimits' value. Expected one of ${Object.values(KB).join(", ")}, using default: "${b}"`)}return[v.relativeCwd,b]})),n=new Map(this.opts.project.workspaces.map(v=>{let b=this.opts.project.configuration.get("nmSelfReferences");return b=v.manifest.installConfig?.selfReferences??b,[v.relativeCwd,b]})),u={VERSIONS:{std:1},topLevel:{name:null,reference:null},getLocator:(v,b)=>Array.isArray(b)?{name:b[0],reference:b[1]}:{name:v,reference:b},getDependencyTreeRoots:()=>this.opts.project.workspaces.map(v=>{let b=v.anchoredLocator;return{name:W.stringifyIdent(b),reference:b.reference}}),getPackageInformation:v=>{let b=v.reference===null?this.opts.project.topLevelWorkspace.anchoredLocator:W.makeLocator(W.parseIdent(v.name),v.reference),C=this.localStore.get(b.locatorHash);if(typeof C>"u")throw new Error("Assertion failed: Expected the package reference to have been registered");return C.pnpNode},findPackageLocator:v=>{let b=this.opts.project.tryWorkspaceByCwd(ue.toPortablePath(v));if(b!==null){let C=b.anchoredLocator;return{name:W.stringifyIdent(C),reference:C.reference}}throw new Error("Assertion failed: Unimplemented")},resolveToUnqualified:()=>{throw new Error("Assertion failed: Unimplemented")},resolveUnqualified:()=>{throw new Error("Assertion failed: Unimplemented")},resolveRequest:()=>{throw new Error("Assertion failed: Unimplemented")},resolveVirtual:v=>ue.fromPortablePath(mi.resolveVirtual(ue.toPortablePath(v)))},{tree:A,errors:p,preserveSymlinksRequired:h}=JB(u,{pnpifyFs:!1,validateExternalSoftLinks:!0,hoistingLimitsByCwd:a,project:this.opts.project,selfReferencesByCwd:n});if(!A){for(let{messageName:v,text:b}of p)this.opts.report.reportError(v,b);return}let E=qj(A);await B1t(r,E,{baseFs:e,project:this.opts.project,report:this.opts.report,realLocatorChecksums:this.realLocatorChecksums,loadManifest:async v=>{let b=W.parseLocator(v),C=this.localStore.get(b.locatorHash);if(typeof C>"u")throw new Error("Assertion failed: Expected the slot to exist");return C.customPackageData.manifest}});let I=[];for(let[v,b]of E.entries()){if(C1e(v))continue;let C=W.parseLocator(v),T=this.localStore.get(C.locatorHash);if(typeof T>"u")throw new Error("Assertion failed: Expected the slot to exist");if(this.opts.project.tryWorkspaceByLocator(T.pkg))continue;let L=mA.extractBuildRequest(T.pkg,T.customPackageData,T.dependencyMeta,{configuration:this.opts.project.configuration});!L||I.push({buildLocations:b.locations,locator:C,buildRequest:L})}return h&&this.opts.report.reportWarning(72,`The application uses portals and that's why ${de.pretty(this.opts.project.configuration,"--preserve-symlinks",de.Type.CODE)} Node option is required for launching it`),{customData:this.customData,records:I}}};async function m1t(t,e){let r=await Mt.tryFind(e.prefixPath,{baseFs:e.packageFs})??new Mt,o=new Set(["preinstall","install","postinstall"]);for(let a of r.scripts.keys())o.has(a)||r.scripts.delete(a);return{manifest:{bin:r.bin,scripts:r.scripts},misc:{hasBindingGyp:mA.hasBindingGyp(e)}}}async function y1t(t,e,r,o,{installChangedByUser:a}){let n="";n+=`# Warning: This file is automatically generated. Removing it is fine, but will -`,n+=`# cause your node_modules installation to become invalidated. -`,n+=` -`,n+=`__metadata: -`,n+=` version: ${g1e} -`,n+=` nmMode: ${o.value} -`;let u=Array.from(e.keys()).sort(),A=W.stringifyLocator(t.topLevelWorkspace.anchoredLocator);for(let E of u){let I=e.get(E);n+=` -`,n+=`${JSON.stringify(E)}: -`,n+=` locations: -`;for(let v of I.locations){let b=K.contains(t.cwd,v);if(b===null)throw new Error(`Assertion failed: Expected the path to be within the project (${v})`);n+=` - ${JSON.stringify(b)} -`}if(I.aliases.length>0){n+=` aliases: -`;for(let v of I.aliases)n+=` - ${JSON.stringify(v)} -`}if(E===A&&r.size>0){n+=` bin: -`;for(let[v,b]of r){let C=K.contains(t.cwd,v);if(C===null)throw new Error(`Assertion failed: Expected the path to be within the project (${v})`);n+=` ${JSON.stringify(C)}: -`;for(let[T,L]of b){let U=K.relative(K.join(v,Pi),L);n+=` ${JSON.stringify(T)}: ${JSON.stringify(U)} -`}}}}let p=t.cwd,h=K.join(p,Pi,d1e);a&&await oe.removePromise(h),await oe.changeFilePromise(h,n,{automaticNewlines:!0})}async function hq(t,{unrollAliases:e=!1}={}){let r=t.cwd,o=K.join(r,Pi,d1e),a;try{a=await oe.statPromise(o)}catch{}if(!a)return null;let n=Vi(await oe.readFilePromise(o,"utf8"));if(n.__metadata.version>g1e)return null;let u=n.__metadata.nmMode||"classic",A=new Map,p=new Map;delete n.__metadata;for(let[h,E]of Object.entries(n)){let I=E.locations.map(b=>K.join(r,b)),v=E.bin;if(v)for(let[b,C]of Object.entries(v)){let T=K.join(r,ue.toPortablePath(b)),L=je.getMapWithDefault(p,T);for(let[U,J]of Object.entries(C))L.set(U,ue.toPortablePath([T,Pi,J].join(K.sep)))}if(A.set(h,{target:Bt.dot,linkType:"HARD",locations:I,aliases:E.aliases||[]}),e&&E.aliases)for(let b of E.aliases){let{scope:C,name:T}=W.parseLocator(h),L=W.makeLocator(W.makeIdent(C,T),b),U=W.stringifyLocator(L);A.set(U,{target:Bt.dot,linkType:"HARD",locations:I,aliases:[]})}}return{locatorMap:A,binSymlinks:p,locationTree:m1e(A,{skipPrefix:t.cwd}),nmMode:u,mtimeMs:a.mtimeMs}}var YC=async(t,e)=>{if(t.split(K.sep).indexOf(Pi)<0)throw new Error(`Assertion failed: trying to remove dir that doesn't contain node_modules: ${t}`);try{if(!e.innerLoop){let o=e.allowSymlink?await oe.statPromise(t):await oe.lstatPromise(t);if(e.allowSymlink&&!o.isDirectory()||!e.allowSymlink&&o.isSymbolicLink()){await oe.unlinkPromise(t);return}}let r=await oe.readdirPromise(t,{withFileTypes:!0});for(let o of r){let a=K.join(t,o.name);o.isDirectory()?(o.name!==Pi||e&&e.innerLoop)&&await YC(a,{innerLoop:!0,contentsOnly:!1}):await oe.unlinkPromise(a)}e.contentsOnly||await oe.rmdirPromise(t)}catch(r){if(r.code!=="ENOENT"&&r.code!=="ENOTEMPTY")throw r}},A1e=4,PQ=(t,{skipPrefix:e})=>{let r=K.contains(e,t);if(r===null)throw new Error(`Assertion failed: Writing attempt prevented to ${t} which is outside project root: ${e}`);let o=r.split(K.sep).filter(p=>p!==""),a=o.indexOf(Pi),n=o.slice(0,a).join(K.sep),u=K.join(e,n),A=o.slice(a);return{locationRoot:u,segments:A}},m1e=(t,{skipPrefix:e})=>{let r=new Map;if(t===null)return r;let o=()=>({children:new Map,linkType:"HARD"});for(let[a,n]of t.entries()){if(n.linkType==="SOFT"&&K.contains(e,n.target)!==null){let A=je.getFactoryWithDefault(r,n.target,o);A.locator=a,A.linkType=n.linkType}for(let u of n.locations){let{locationRoot:A,segments:p}=PQ(u,{skipPrefix:e}),h=je.getFactoryWithDefault(r,A,o);for(let E=0;E{if(process.platform==="win32"&&r==="junctions"){let o;try{o=await oe.lstatPromise(t)}catch{}if(!o||o.isDirectory()){await oe.symlinkPromise(t,e,"junction");return}}await oe.symlinkPromise(K.relative(K.dirname(e),t),e)};async function y1e(t,e,r){let o=K.join(t,`${gq.default.randomBytes(16).toString("hex")}.tmp`);try{await oe.writeFilePromise(o,r);try{await oe.linkPromise(o,e)}catch{}}finally{await oe.unlinkPromise(o)}}async function E1t({srcPath:t,dstPath:e,entry:r,globalHardlinksStore:o,baseFs:a,nmMode:n}){if(r.kind===E1e.FILE){if(n.value==="hardlinks-global"&&o&&r.digest){let A=K.join(o,r.digest.substring(0,2),`${r.digest.substring(2)}.dat`),p;try{let h=await oe.statPromise(A);if(h&&(!r.mtimeMs||h.mtimeMs>r.mtimeMs||h.mtimeMs(o.FILE="file",o.DIRECTORY="directory",o.SYMLINK="symlink",o))(E1e||{}),C1t=async(t,e,{baseFs:r,globalHardlinksStore:o,nmMode:a,windowsLinkType:n,packageChecksum:u})=>{await oe.mkdirPromise(t,{recursive:!0});let A=async(E=Bt.dot)=>{let I=K.join(e,E),v=await r.readdirPromise(I,{withFileTypes:!0}),b=new Map;for(let C of v){let T=K.join(E,C.name),L,U=K.join(I,C.name);if(C.isFile()){if(L={kind:"file",mode:(await r.lstatPromise(U)).mode},a.value==="hardlinks-global"){let J=await wn.checksumFile(U,{baseFs:r,algorithm:"sha1"});L.digest=J}}else if(C.isDirectory())L={kind:"directory"};else if(C.isSymbolicLink())L={kind:"symlink",symlinkTo:await r.readlinkPromise(U)};else throw new Error(`Unsupported file type (file: ${U}, mode: 0o${await r.statSync(U).mode.toString(8).padStart(6,"0")})`);if(b.set(T,L),C.isDirectory()&&T!==Pi){let J=await A(T);for(let[te,le]of J)b.set(te,le)}}return b},p;if(a.value==="hardlinks-global"&&o&&u){let E=K.join(o,u.substring(0,2),`${u.substring(2)}.json`);try{p=new Map(Object.entries(JSON.parse(await oe.readFilePromise(E,"utf8"))))}catch{p=await A()}}else p=await A();let h=!1;for(let[E,I]of p){let v=K.join(e,E),b=K.join(t,E);if(I.kind==="directory")await oe.mkdirPromise(b,{recursive:!0});else if(I.kind==="file"){let C=I.mtimeMs;await E1t({srcPath:v,dstPath:b,entry:I,nmMode:a,baseFs:r,globalHardlinksStore:o}),I.mtimeMs!==C&&(h=!0)}else I.kind==="symlink"&&await mq(K.resolve(K.dirname(b),I.symlinkTo),b,n)}if(a.value==="hardlinks-global"&&o&&h&&u){let E=K.join(o,u.substring(0,2),`${u.substring(2)}.json`);await oe.removePromise(E),await y1e(o,E,Buffer.from(JSON.stringify(Object.fromEntries(p))))}};function w1t(t,e,r,o){let a=new Map,n=new Map,u=new Map,A=!1,p=(h,E,I,v,b)=>{let C=!0,T=K.join(h,E),L=new Set;if(E===Pi||E.startsWith("@")){let J;try{J=oe.statSync(T)}catch{}C=!!J,J?J.mtimeMs>r?(A=!0,L=new Set(oe.readdirSync(T))):L=new Set(I.children.get(E).children.keys()):A=!0;let te=e.get(h);if(te){let le=K.join(h,Pi,DQ),pe;try{pe=oe.statSync(le)}catch{}if(!pe)A=!0;else if(pe.mtimeMs>r){A=!0;let Ae=new Set(oe.readdirSync(le)),ye=new Map;n.set(h,ye);for(let[ae,we]of te)Ae.has(ae)&&ye.set(ae,we)}else n.set(h,te)}}else C=b.has(E);let U=I.children.get(E);if(C){let{linkType:J,locator:te}=U,le={children:new Map,linkType:J,locator:te};if(v.children.set(E,le),te){let pe=je.getSetWithDefault(u,te);pe.add(T),u.set(te,pe)}for(let pe of U.children.keys())p(T,pe,U,le,L)}else U.locator&&o.storedBuildState.delete(W.parseLocator(U.locator).locatorHash)};for(let[h,E]of t){let{linkType:I,locator:v}=E,b={children:new Map,linkType:I,locator:v};if(a.set(h,b),v){let C=je.getSetWithDefault(u,E.locator);C.add(h),u.set(E.locator,C)}E.children.has(Pi)&&p(h,Pi,E,b,new Set)}return{locationTree:a,binSymlinks:n,locatorLocations:u,installChangedByUser:A}}function C1e(t){let e=W.parseDescriptor(t);return W.isVirtualDescriptor(e)&&(e=W.devirtualizeDescriptor(e)),e.range.startsWith("link:")}async function I1t(t,e,r,{loadManifest:o}){let a=new Map;for(let[A,{locations:p}]of t){let h=C1e(A)?null:await o(A,p[0]),E=new Map;if(h)for(let[I,v]of h.bin){let b=K.join(p[0],v);v!==""&&oe.existsSync(b)&&E.set(I,v)}a.set(A,E)}let n=new Map,u=(A,p,h)=>{let E=new Map,I=K.contains(r,A);if(h.locator&&I!==null){let v=a.get(h.locator);for(let[b,C]of v){let T=K.join(A,ue.toPortablePath(C));E.set(b,T)}for(let[b,C]of h.children){let T=K.join(A,b),L=u(T,T,C);L.size>0&&n.set(A,new Map([...n.get(A)||new Map,...L]))}}else for(let[v,b]of h.children){let C=u(K.join(A,v),p,b);for(let[T,L]of C)E.set(T,L)}return E};for(let[A,p]of e){let h=u(A,A,p);h.size>0&&n.set(A,new Map([...n.get(A)||new Map,...h]))}return n}var f1e=(t,e)=>{if(!t||!e)return t===e;let r=W.parseLocator(t);W.isVirtualLocator(r)&&(r=W.devirtualizeLocator(r));let o=W.parseLocator(e);return W.isVirtualLocator(o)&&(o=W.devirtualizeLocator(o)),W.areLocatorsEqual(r,o)};function yq(t){return K.join(t.get("globalFolder"),"store")}async function B1t(t,e,{baseFs:r,project:o,report:a,loadManifest:n,realLocatorChecksums:u}){let A=K.join(o.cwd,Pi),{locationTree:p,binSymlinks:h,locatorLocations:E,installChangedByUser:I}=w1t(t.locationTree,t.binSymlinks,t.mtimeMs,o),v=m1e(e,{skipPrefix:o.cwd}),b=[],C=async({srcDir:we,dstDir:Pe,linkType:g,globalHardlinksStore:Ee,nmMode:De,windowsLinkType:ce,packageChecksum:ne})=>{let ee=(async()=>{try{g==="SOFT"?(await oe.mkdirPromise(K.dirname(Pe),{recursive:!0}),await mq(K.resolve(we),Pe,ce)):await C1t(Pe,we,{baseFs:r,globalHardlinksStore:Ee,nmMode:De,windowsLinkType:ce,packageChecksum:ne})}catch(Ie){throw Ie.message=`While persisting ${we} -> ${Pe} ${Ie.message}`,Ie}finally{le.tick()}})().then(()=>b.splice(b.indexOf(ee),1));b.push(ee),b.length>A1e&&await Promise.race(b)},T=async(we,Pe,g)=>{let Ee=(async()=>{let De=async(ce,ne,ee)=>{try{ee.innerLoop||await oe.mkdirPromise(ne,{recursive:!0});let Ie=await oe.readdirPromise(ce,{withFileTypes:!0});for(let ke of Ie){if(!ee.innerLoop&&ke.name===DQ)continue;let ht=K.join(ce,ke.name),H=K.join(ne,ke.name);ke.isDirectory()?(ke.name!==Pi||ee&&ee.innerLoop)&&(await oe.mkdirPromise(H,{recursive:!0}),await De(ht,H,{...ee,innerLoop:!0})):ye.value==="hardlinks-local"||ye.value==="hardlinks-global"?await oe.linkPromise(ht,H):await oe.copyFilePromise(ht,H,h1e.default.constants.COPYFILE_FICLONE)}}catch(Ie){throw ee.innerLoop||(Ie.message=`While cloning ${ce} -> ${ne} ${Ie.message}`),Ie}finally{ee.innerLoop||le.tick()}};await De(we,Pe,g)})().then(()=>b.splice(b.indexOf(Ee),1));b.push(Ee),b.length>A1e&&await Promise.race(b)},L=async(we,Pe,g)=>{if(g)for(let[Ee,De]of Pe.children){let ce=g.children.get(Ee);await L(K.join(we,Ee),De,ce)}else{Pe.children.has(Pi)&&await YC(K.join(we,Pi),{contentsOnly:!1});let Ee=K.basename(we)===Pi&&v.has(K.join(K.dirname(we),K.sep));await YC(we,{contentsOnly:we===A,allowSymlink:Ee})}};for(let[we,Pe]of p){let g=v.get(we);for(let[Ee,De]of Pe.children){if(Ee===".")continue;let ce=g&&g.children.get(Ee),ne=K.join(we,Ee);await L(ne,De,ce)}}let U=async(we,Pe,g)=>{if(g){f1e(Pe.locator,g.locator)||await YC(we,{contentsOnly:Pe.linkType==="HARD"});for(let[Ee,De]of Pe.children){let ce=g.children.get(Ee);await U(K.join(we,Ee),De,ce)}}else{Pe.children.has(Pi)&&await YC(K.join(we,Pi),{contentsOnly:!0});let Ee=K.basename(we)===Pi&&v.has(K.join(K.dirname(we),K.sep));await YC(we,{contentsOnly:Pe.linkType==="HARD",allowSymlink:Ee})}};for(let[we,Pe]of v){let g=p.get(we);for(let[Ee,De]of Pe.children){if(Ee===".")continue;let ce=g&&g.children.get(Ee);await U(K.join(we,Ee),De,ce)}}let J=new Map,te=[];for(let[we,Pe]of E)for(let g of Pe){let{locationRoot:Ee,segments:De}=PQ(g,{skipPrefix:o.cwd}),ce=v.get(Ee),ne=Ee;if(ce){for(let ee of De)if(ne=K.join(ne,ee),ce=ce.children.get(ee),!ce)break;if(ce){let ee=f1e(ce.locator,we),Ie=e.get(ce.locator),ke=Ie.target,ht=ne,H=Ie.linkType;if(ee)J.has(ke)||J.set(ke,ht);else if(ke!==ht){let lt=W.parseLocator(ce.locator);W.isVirtualLocator(lt)&&(lt=W.devirtualizeLocator(lt)),te.push({srcDir:ke,dstDir:ht,linkType:H,realLocatorHash:lt.locatorHash})}}}}for(let[we,{locations:Pe}]of e.entries())for(let g of Pe){let{locationRoot:Ee,segments:De}=PQ(g,{skipPrefix:o.cwd}),ce=p.get(Ee),ne=v.get(Ee),ee=Ee,Ie=e.get(we),ke=W.parseLocator(we);W.isVirtualLocator(ke)&&(ke=W.devirtualizeLocator(ke));let ht=ke.locatorHash,H=Ie.target,lt=g;if(H===lt)continue;let Re=Ie.linkType;for(let Qe of De)ne=ne.children.get(Qe);if(!ce)te.push({srcDir:H,dstDir:lt,linkType:Re,realLocatorHash:ht});else for(let Qe of De)if(ee=K.join(ee,Qe),ce=ce.children.get(Qe),!ce){te.push({srcDir:H,dstDir:lt,linkType:Re,realLocatorHash:ht});break}}let le=Xs.progressViaCounter(te.length),pe=a.reportProgress(le),Ae=o.configuration.get("nmMode"),ye={value:Ae},ae=o.configuration.get("winLinkType");try{let we=ye.value==="hardlinks-global"?`${yq(o.configuration)}/v1`:null;if(we&&!await oe.existsPromise(we)){await oe.mkdirpPromise(we);for(let g=0;g<256;g++)await oe.mkdirPromise(K.join(we,g.toString(16).padStart(2,"0")))}for(let g of te)(g.linkType==="SOFT"||!J.has(g.srcDir))&&(J.set(g.srcDir,g.dstDir),await C({...g,globalHardlinksStore:we,nmMode:ye,windowsLinkType:ae,packageChecksum:u.get(g.realLocatorHash)||null}));await Promise.all(b),b.length=0;for(let g of te){let Ee=J.get(g.srcDir);g.linkType!=="SOFT"&&g.dstDir!==Ee&&await T(Ee,g.dstDir,{nmMode:ye})}await Promise.all(b),await oe.mkdirPromise(A,{recursive:!0});let Pe=await I1t(e,v,o.cwd,{loadManifest:n});await v1t(h,Pe,o.cwd,ae),await y1t(o,e,Pe,ye,{installChangedByUser:I}),Ae=="hardlinks-global"&&ye.value=="hardlinks-local"&&a.reportWarningOnce(74,"'nmMode' has been downgraded to 'hardlinks-local' due to global cache and install folder being on different devices")}finally{pe.stop()}}async function v1t(t,e,r,o){for(let a of t.keys()){if(K.contains(r,a)===null)throw new Error(`Assertion failed. Excepted bin symlink location to be inside project dir, instead it was at ${a}`);if(!e.has(a)){let n=K.join(a,Pi,DQ);await oe.removePromise(n)}}for(let[a,n]of e){if(K.contains(r,a)===null)throw new Error(`Assertion failed. Excepted bin symlink location to be inside project dir, instead it was at ${a}`);let u=K.join(a,Pi,DQ),A=t.get(a)||new Map;await oe.mkdirPromise(u,{recursive:!0});for(let p of A.keys())n.has(p)||(await oe.removePromise(K.join(u,p)),process.platform==="win32"&&await oe.removePromise(K.join(u,`${p}.cmd`)));for(let[p,h]of n){let E=A.get(p),I=K.join(u,p);E!==h&&(process.platform==="win32"?await(0,p1e.default)(ue.fromPortablePath(h),ue.fromPortablePath(I),{createPwshFile:!1}):(await oe.removePromise(I),await mq(h,I,o),K.contains(r,await oe.realpathPromise(h))!==null&&await oe.chmodPromise(h,493)))}}}Ye();Pt();nA();var cv=class extends P0{constructor(){super(...arguments);this.mode="loose"}makeInstaller(r){return new Eq(r)}},Eq=class extends dm{constructor(){super(...arguments);this.mode="loose"}async transformPnpSettings(r){let o=new mi({baseFs:new Jl({maxOpenFiles:80,readOnlyArchives:!0})}),a=$Ie(r,this.opts.project.cwd,o),{tree:n,errors:u}=JB(a,{pnpifyFs:!1,project:this.opts.project});if(!n){for(let{messageName:I,text:v}of u)this.opts.report.reportError(I,v);return}let A=new Map;r.fallbackPool=A;let p=(I,v)=>{let b=W.parseLocator(v.locator),C=W.stringifyIdent(b);C===I?A.set(I,b.reference):A.set(I,[C,b.reference])},h=K.join(this.opts.project.cwd,dr.nodeModules),E=n.get(h);if(!(typeof E>"u")){if("target"in E)throw new Error("Assertion failed: Expected the root junction point to be a directory");for(let I of E.dirList){let v=K.join(h,I),b=n.get(v);if(typeof b>"u")throw new Error("Assertion failed: Expected the child to have been registered");if("target"in b)p(I,b);else for(let C of b.dirList){let T=K.join(v,C),L=n.get(T);if(typeof L>"u")throw new Error("Assertion failed: Expected the subchild to have been registered");if("target"in L)p(`${I}/${C}`,L);else throw new Error("Assertion failed: Expected the leaf junction to be a package")}}}}};var D1t={hooks:{cleanGlobalArtifacts:async t=>{let e=yq(t);await oe.removePromise(e)}},configuration:{nmHoistingLimits:{description:"Prevents packages to be hoisted past specific levels",type:"STRING",values:["workspaces","dependencies","none"],default:"none"},nmMode:{description:"Defines in which measure Yarn must use hardlinks and symlinks when generated `node_modules` directories.",type:"STRING",values:["classic","hardlinks-local","hardlinks-global"],default:"classic"},nmSelfReferences:{description:"Defines whether the linker should generate self-referencing symlinks for workspaces.",type:"BOOLEAN",default:!0}},linkers:[lv,cv]},P1t=D1t;var EG={};Kt(EG,{NpmHttpFetcher:()=>fv,NpmRemapResolver:()=>pv,NpmSemverFetcher:()=>dl,NpmSemverResolver:()=>hv,NpmTagResolver:()=>gv,default:()=>Ovt,npmConfigUtils:()=>Zn,npmHttpUtils:()=>on,npmPublishUtils:()=>sw});Ye();var x1e=$e(zn());var Wn="npm:";var on={};Kt(on,{AuthType:()=>P1e,customPackageError:()=>mm,del:()=>N1t,get:()=>ym,getIdentUrl:()=>SQ,getPackageMetadata:()=>KC,handleInvalidAuthenticationError:()=>b0,post:()=>T1t,put:()=>R1t});Ye();Ye();Pt();var Bq=$e(A2()),v1e=$e(S_()),D1e=$e(zn()),vq=Be("url");var Zn={};Kt(Zn,{RegistryType:()=>w1e,getAuditRegistry:()=>S1t,getAuthConfiguration:()=>Iq,getDefaultRegistry:()=>uv,getPublishRegistry:()=>x1t,getRegistryConfiguration:()=>I1e,getScopeConfiguration:()=>wq,getScopeRegistry:()=>WC,normalizeRegistry:()=>oc});var w1e=(o=>(o.AUDIT_REGISTRY="npmAuditRegistry",o.FETCH_REGISTRY="npmRegistryServer",o.PUBLISH_REGISTRY="npmPublishRegistry",o))(w1e||{});function oc(t){return t.replace(/\/$/,"")}function S1t({configuration:t}){return uv({configuration:t,type:"npmAuditRegistry"})}function x1t(t,{configuration:e}){return t.publishConfig?.registry?oc(t.publishConfig.registry):t.name?WC(t.name.scope,{configuration:e,type:"npmPublishRegistry"}):uv({configuration:e,type:"npmPublishRegistry"})}function WC(t,{configuration:e,type:r="npmRegistryServer"}){let o=wq(t,{configuration:e});if(o===null)return uv({configuration:e,type:r});let a=o.get(r);return a===null?uv({configuration:e,type:r}):oc(a)}function uv({configuration:t,type:e="npmRegistryServer"}){let r=t.get(e);return oc(r!==null?r:t.get("npmRegistryServer"))}function I1e(t,{configuration:e}){let r=e.get("npmRegistries"),o=oc(t),a=r.get(o);if(typeof a<"u")return a;let n=r.get(o.replace(/^[a-z]+:/,""));return typeof n<"u"?n:null}function wq(t,{configuration:e}){if(t===null)return null;let o=e.get("npmScopes").get(t);return o||null}function Iq(t,{configuration:e,ident:r}){let o=r&&wq(r.scope,{configuration:e});return o?.get("npmAuthIdent")||o?.get("npmAuthToken")?o:I1e(t,{configuration:e})||e}var P1e=(a=>(a[a.NO_AUTH=0]="NO_AUTH",a[a.BEST_EFFORT=1]="BEST_EFFORT",a[a.CONFIGURATION=2]="CONFIGURATION",a[a.ALWAYS_AUTH=3]="ALWAYS_AUTH",a))(P1e||{});async function b0(t,{attemptedAs:e,registry:r,headers:o,configuration:a}){if(bQ(t))throw new zt(41,"Invalid OTP token");if(t.originalError?.name==="HTTPError"&&t.originalError?.response.statusCode===401)throw new zt(41,`Invalid authentication (${typeof e!="string"?`as ${await M1t(r,o,{configuration:a})}`:`attempted as ${e}`})`)}function mm(t,e){let r=t.response?.statusCode;return r?r===404?"Package not found":r>=500&&r<600?`The registry appears to be down (using a ${de.applyHyperlink(e,"local cache","https://yarnpkg.com/advanced/lexicon#local-cache")} might have protected you against such outages)`:null:null}function SQ(t){return t.scope?`/@${t.scope}%2f${t.name}`:`/${t.name}`}var B1e=new Map;async function KC(t,{cache:e,project:r,registry:o,headers:a,version:n,...u}){return await je.getFactoryWithDefault(B1e,t.identHash,async()=>{let{configuration:A}=r;o=Av(A,{ident:t,registry:o});let p=Q1t(A,o),h=K.join(p,`${W.slugifyIdent(t)}.json`),E=null;if(!r.lockfileNeedsRefresh){try{E=await oe.readJsonPromise(h)}catch{}if(E){if(typeof n<"u"&&typeof E.metadata.versions[n]<"u")return E.metadata;if(A.get("enableOfflineMode")){let I=structuredClone(E.metadata),v=new Set;if(e){for(let C of Object.keys(I.versions)){let T=W.makeLocator(t,`npm:${C}`),L=e.getLocatorMirrorPath(T);(!L||!oe.existsSync(L))&&(delete I.versions[C],v.add(C))}let b=I["dist-tags"].latest;if(v.has(b)){let C=Object.keys(E.metadata.versions).sort(D1e.default.compare),T=C.indexOf(b);for(;v.has(C[T])&&T>=0;)T-=1;T>=0?I["dist-tags"].latest=C[T]:delete I["dist-tags"].latest}}return I}}}return await ym(SQ(t),{...u,customErrorMessage:mm,configuration:A,registry:o,ident:t,headers:{...a,["If-None-Match"]:E?.etag,["If-Modified-Since"]:E?.lastModified},wrapNetworkRequest:async I=>async()=>{let v=await I();if(v.statusCode===304){if(E===null)throw new Error("Assertion failed: cachedMetadata should not be null");return{...v,body:E.metadata}}let b=b1t(JSON.parse(v.body.toString()));B1e.set(t.identHash,b);let C={metadata:b,etag:v.headers.etag,lastModified:v.headers["last-modified"]},T=`${h}-${process.pid}.tmp`;return await oe.mkdirPromise(p,{recursive:!0}),await oe.writeJsonPromise(T,C,{compact:!0}),await oe.renamePromise(T,h),{...v,body:b}}})})}var S1e=["name","dist.tarball","bin","scripts","os","cpu","libc","dependencies","dependenciesMeta","optionalDependencies","peerDependencies","peerDependenciesMeta","deprecated"];function b1t(t){return{"dist-tags":t["dist-tags"],versions:Object.fromEntries(Object.entries(t.versions).map(([e,r])=>[e,(0,v1e.default)(r,S1e)]))}}var k1t=wn.makeHash(...S1e).slice(0,6);function Q1t(t,e){let r=F1t(t),o=new vq.URL(e);return K.join(r,k1t,o.hostname)}function F1t(t){return K.join(t.get("globalFolder"),"metadata/npm")}async function ym(t,{configuration:e,headers:r,ident:o,authType:a,registry:n,...u}){n=Av(e,{ident:o,registry:n}),o&&o.scope&&typeof a>"u"&&(a=1);let A=await xQ(n,{authType:a,configuration:e,ident:o});A&&(r={...r,authorization:A});try{return await rn.get(t.charAt(0)==="/"?`${n}${t}`:t,{configuration:e,headers:r,...u})}catch(p){throw await b0(p,{registry:n,configuration:e,headers:r}),p}}async function T1t(t,e,{attemptedAs:r,configuration:o,headers:a,ident:n,authType:u=3,registry:A,otp:p,...h}){A=Av(o,{ident:n,registry:A});let E=await xQ(A,{authType:u,configuration:o,ident:n});E&&(a={...a,authorization:E}),p&&(a={...a,...VC(p)});try{return await rn.post(A+t,e,{configuration:o,headers:a,...h})}catch(I){if(!bQ(I)||p)throw await b0(I,{attemptedAs:r,registry:A,configuration:o,headers:a}),I;p=await Dq(I,{configuration:o});let v={...a,...VC(p)};try{return await rn.post(`${A}${t}`,e,{configuration:o,headers:v,...h})}catch(b){throw await b0(b,{attemptedAs:r,registry:A,configuration:o,headers:a}),b}}}async function R1t(t,e,{attemptedAs:r,configuration:o,headers:a,ident:n,authType:u=3,registry:A,otp:p,...h}){A=Av(o,{ident:n,registry:A});let E=await xQ(A,{authType:u,configuration:o,ident:n});E&&(a={...a,authorization:E}),p&&(a={...a,...VC(p)});try{return await rn.put(A+t,e,{configuration:o,headers:a,...h})}catch(I){if(!bQ(I))throw await b0(I,{attemptedAs:r,registry:A,configuration:o,headers:a}),I;p=await Dq(I,{configuration:o});let v={...a,...VC(p)};try{return await rn.put(`${A}${t}`,e,{configuration:o,headers:v,...h})}catch(b){throw await b0(b,{attemptedAs:r,registry:A,configuration:o,headers:a}),b}}}async function N1t(t,{attemptedAs:e,configuration:r,headers:o,ident:a,authType:n=3,registry:u,otp:A,...p}){u=Av(r,{ident:a,registry:u});let h=await xQ(u,{authType:n,configuration:r,ident:a});h&&(o={...o,authorization:h}),A&&(o={...o,...VC(A)});try{return await rn.del(u+t,{configuration:r,headers:o,...p})}catch(E){if(!bQ(E)||A)throw await b0(E,{attemptedAs:e,registry:u,configuration:r,headers:o}),E;A=await Dq(E,{configuration:r});let I={...o,...VC(A)};try{return await rn.del(`${u}${t}`,{configuration:r,headers:I,...p})}catch(v){throw await b0(v,{attemptedAs:e,registry:u,configuration:r,headers:o}),v}}}function Av(t,{ident:e,registry:r}){if(typeof r>"u"&&e)return WC(e.scope,{configuration:t});if(typeof r!="string")throw new Error("Assertion failed: The registry should be a string");return oc(r)}async function xQ(t,{authType:e=2,configuration:r,ident:o}){let a=Iq(t,{configuration:r,ident:o}),n=L1t(a,e);if(!n)return null;let u=await r.reduceHook(A=>A.getNpmAuthenticationHeader,void 0,t,{configuration:r,ident:o});if(u)return u;if(a.get("npmAuthToken"))return`Bearer ${a.get("npmAuthToken")}`;if(a.get("npmAuthIdent")){let A=a.get("npmAuthIdent");return A.includes(":")?`Basic ${Buffer.from(A).toString("base64")}`:`Basic ${A}`}if(n&&e!==1)throw new zt(33,"No authentication configured for request");return null}function L1t(t,e){switch(e){case 2:return t.get("npmAlwaysAuth");case 1:case 3:return!0;case 0:return!1;default:throw new Error("Unreachable")}}async function M1t(t,e,{configuration:r}){if(typeof e>"u"||typeof e.authorization>"u")return"an anonymous user";try{return(await rn.get(new vq.URL(`${t}/-/whoami`).href,{configuration:r,headers:e,jsonResponse:!0})).username??"an unknown user"}catch{return"an unknown user"}}async function Dq(t,{configuration:e}){let r=t.originalError?.response.headers["npm-notice"];if(r&&(await Nt.start({configuration:e,stdout:process.stdout,includeFooter:!1},async a=>{if(a.reportInfo(0,r.replace(/(https?:\/\/\S+)/g,de.pretty(e,"$1",de.Type.URL))),!process.env.YARN_IS_TEST_ENV){let n=r.match(/open (https?:\/\/\S+)/i);if(n&&Ji.openUrl){let{openNow:u}=await(0,Bq.prompt)({type:"confirm",name:"openNow",message:"Do you want to try to open this url now?",required:!0,initial:!0,onCancel:()=>process.exit(130)});u&&(await Ji.openUrl(n[1])||(a.reportSeparator(),a.reportWarning(0,"We failed to automatically open the url; you'll have to open it yourself in your browser of choice.")))}}}),process.stdout.write(` -`)),process.env.YARN_IS_TEST_ENV)return process.env.YARN_INJECT_NPM_2FA_TOKEN||"";let{otp:o}=await(0,Bq.prompt)({type:"password",name:"otp",message:"One-time password:",required:!0,onCancel:()=>process.exit(130)});return process.stdout.write(` -`),o}function bQ(t){if(t.originalError?.name!=="HTTPError")return!1;try{return(t.originalError?.response.headers["www-authenticate"].split(/,\s*/).map(r=>r.toLowerCase())).includes("otp")}catch{return!1}}function VC(t){return{["npm-otp"]:t}}var fv=class{supports(e,r){if(!e.reference.startsWith(Wn))return!1;let{selector:o,params:a}=W.parseRange(e.reference);return!(!x1e.default.valid(o)||a===null||typeof a.__archiveUrl!="string")}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote server`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromNetwork(e,r){let{params:o}=W.parseRange(e.reference);if(o===null||typeof o.__archiveUrl!="string")throw new Error("Assertion failed: The archiveUrl querystring parameter should have been available");let a=await ym(o.__archiveUrl,{customErrorMessage:mm,configuration:r.project.configuration,ident:e});return await Xi.convertToZip(a,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})}};Ye();var pv=class{supportsDescriptor(e,r){return!(!e.range.startsWith(Wn)||!W.tryParseDescriptor(e.range.slice(Wn.length),!0))}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error("Unreachable")}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){let o=r.project.configuration.normalizeDependency(W.parseDescriptor(e.range.slice(Wn.length),!0));return r.resolver.getResolutionDependencies(o,r)}async getCandidates(e,r,o){let a=o.project.configuration.normalizeDependency(W.parseDescriptor(e.range.slice(Wn.length),!0));return await o.resolver.getCandidates(a,r,o)}async getSatisfying(e,r,o,a){let n=a.project.configuration.normalizeDependency(W.parseDescriptor(e.range.slice(Wn.length),!0));return a.resolver.getSatisfying(n,r,o,a)}resolve(e,r){throw new Error("Unreachable")}};Ye();Ye();var b1e=$e(zn()),k1e=Be("url");var dl=class{supports(e,r){if(!e.reference.startsWith(Wn))return!1;let o=new k1e.URL(e.reference);return!(!b1e.default.valid(o.pathname)||o.searchParams.has("__archiveUrl"))}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote registry`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromNetwork(e,r){let o;try{o=await ym(dl.getLocatorUrl(e),{customErrorMessage:mm,configuration:r.project.configuration,ident:e})}catch{o=await ym(dl.getLocatorUrl(e).replace(/%2f/g,"/"),{customErrorMessage:mm,configuration:r.project.configuration,ident:e})}return await Xi.convertToZip(o,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})}static isConventionalTarballUrl(e,r,{configuration:o}){let a=WC(e.scope,{configuration:o}),n=dl.getLocatorUrl(e);return r=r.replace(/^https?:(\/\/(?:[^/]+\.)?npmjs.org(?:$|\/))/,"https:$1"),a=a.replace(/^https:\/\/registry\.npmjs\.org($|\/)/,"https://registry.yarnpkg.com$1"),r=r.replace(/^https:\/\/registry\.npmjs\.org($|\/)/,"https://registry.yarnpkg.com$1"),r===a+n||r===a+n.replace(/%2f/g,"/")}static getLocatorUrl(e){let r=kr.clean(e.reference.slice(Wn.length));if(r===null)throw new zt(10,"The npm semver resolver got selected, but the version isn't semver");return`${SQ(e)}/-/${e.name}-${r}.tgz`}};Ye();Ye();Ye();var Pq=$e(zn());var kQ=W.makeIdent(null,"node-gyp"),O1t=/\b(node-gyp|prebuild-install)\b/,hv=class{supportsDescriptor(e,r){return e.range.startsWith(Wn)?!!kr.validRange(e.range.slice(Wn.length)):!1}supportsLocator(e,r){if(!e.reference.startsWith(Wn))return!1;let{selector:o}=W.parseRange(e.reference);return!!Pq.default.valid(o)}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=kr.validRange(e.range.slice(Wn.length));if(a===null)throw new Error(`Expected a valid range, got ${e.range.slice(Wn.length)}`);let n=await KC(e,{cache:o.fetchOptions?.cache,project:o.project,version:Pq.default.valid(a.raw)?a.raw:void 0}),u=je.mapAndFilter(Object.keys(n.versions),h=>{try{let E=new kr.SemVer(h);if(a.test(E))return E}catch{}return je.mapAndFilter.skip}),A=u.filter(h=>!n.versions[h.raw].deprecated),p=A.length>0?A:u;return p.sort((h,E)=>-h.compare(E)),p.map(h=>{let E=W.makeLocator(e,`${Wn}${h.raw}`),I=n.versions[h.raw].dist.tarball;return dl.isConventionalTarballUrl(E,I,{configuration:o.project.configuration})?E:W.bindLocator(E,{__archiveUrl:I})})}async getSatisfying(e,r,o,a){let n=kr.validRange(e.range.slice(Wn.length));if(n===null)throw new Error(`Expected a valid range, got ${e.range.slice(Wn.length)}`);return{locators:je.mapAndFilter(o,p=>{if(p.identHash!==e.identHash)return je.mapAndFilter.skip;let h=W.tryParseRange(p.reference,{requireProtocol:Wn});if(!h)return je.mapAndFilter.skip;let E=new kr.SemVer(h.selector);return n.test(E)?{locator:p,version:E}:je.mapAndFilter.skip}).sort((p,h)=>-p.version.compare(h.version)).map(({locator:p})=>p),sorted:!0}}async resolve(e,r){let{selector:o}=W.parseRange(e.reference),a=kr.clean(o);if(a===null)throw new zt(10,"The npm semver resolver got selected, but the version isn't semver");let n=await KC(e,{cache:r.fetchOptions?.cache,project:r.project,version:a});if(!Object.hasOwn(n,"versions"))throw new zt(15,'Registry returned invalid data for - missing "versions" field');if(!Object.hasOwn(n.versions,a))throw new zt(16,`Registry failed to return reference "${a}"`);let u=new Mt;if(u.load(n.versions[a]),!u.dependencies.has(kQ.identHash)&&!u.peerDependencies.has(kQ.identHash)){for(let A of u.scripts.values())if(A.match(O1t)){u.dependencies.set(kQ.identHash,W.makeDescriptor(kQ,"latest"));break}}return{...e,version:a,languageName:"node",linkType:"HARD",conditions:u.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(u.dependencies),peerDependencies:u.peerDependencies,dependenciesMeta:u.dependenciesMeta,peerDependenciesMeta:u.peerDependenciesMeta,bin:u.bin}}};Ye();Ye();var Q1e=$e(zn());var gv=class{supportsDescriptor(e,r){return!(!e.range.startsWith(Wn)||!QE.test(e.range.slice(Wn.length)))}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error("Unreachable")}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=e.range.slice(Wn.length),n=await KC(e,{cache:o.fetchOptions?.cache,project:o.project});if(!Object.hasOwn(n,"dist-tags"))throw new zt(15,'Registry returned invalid data - missing "dist-tags" field');let u=n["dist-tags"];if(!Object.hasOwn(u,a))throw new zt(16,`Registry failed to return tag "${a}"`);let A=u[a],p=W.makeLocator(e,`${Wn}${A}`),h=n.versions[A].dist.tarball;return dl.isConventionalTarballUrl(p,h,{configuration:o.project.configuration})?[p]:[W.bindLocator(p,{__archiveUrl:h})]}async getSatisfying(e,r,o,a){let n=[];for(let u of o){if(u.identHash!==e.identHash)continue;let A=W.tryParseRange(u.reference,{requireProtocol:Wn});if(!(!A||!Q1e.default.valid(A.selector))){if(A.params?.__archiveUrl){let p=W.makeRange({protocol:Wn,selector:A.selector,source:null,params:null}),[h]=await a.resolver.getCandidates(W.makeDescriptor(e,p),r,a);if(u.reference!==h.reference)continue}n.push(u)}}return{locators:n,sorted:!1}}async resolve(e,r){throw new Error("Unreachable")}};var sw={};Kt(sw,{getGitHead:()=>Lvt,getPublishAccess:()=>wBe,getReadmeContent:()=>IBe,makePublishBody:()=>Nvt});Ye();Ye();Pt();var hG={};Kt(hG,{PackCommand:()=>O0,default:()=>mvt,packUtils:()=>CA});Ye();Ye();Ye();Pt();qt();var CA={};Kt(CA,{genPackList:()=>$Q,genPackStream:()=>pG,genPackageManifest:()=>lBe,hasPackScripts:()=>AG,prepareForPack:()=>fG});Ye();Pt();var uG=$e(Zo()),oBe=$e(rBe()),aBe=Be("zlib"),ovt=["/package.json","/readme","/readme.*","/license","/license.*","/licence","/licence.*","/changelog","/changelog.*"],avt=["/package.tgz",".github",".git",".hg","node_modules",".npmignore",".gitignore",".#*",".DS_Store"];async function AG(t){return!!(un.hasWorkspaceScript(t,"prepack")||un.hasWorkspaceScript(t,"postpack"))}async function fG(t,{report:e},r){await un.maybeExecuteWorkspaceLifecycleScript(t,"prepack",{report:e});try{let o=K.join(t.cwd,Mt.fileName);await oe.existsPromise(o)&&await t.manifest.loadFile(o,{baseFs:oe}),await r()}finally{await un.maybeExecuteWorkspaceLifecycleScript(t,"postpack",{report:e})}}async function pG(t,e){typeof e>"u"&&(e=await $Q(t));let r=new Set;for(let n of t.manifest.publishConfig?.executableFiles??new Set)r.add(K.normalize(n));for(let n of t.manifest.bin.values())r.add(K.normalize(n));let o=oBe.default.pack();process.nextTick(async()=>{for(let n of e){let u=K.normalize(n),A=K.resolve(t.cwd,u),p=K.join("package",u),h=await oe.lstatPromise(A),E={name:p,mtime:new Date(vi.SAFE_TIME*1e3)},I=r.has(u)?493:420,v,b,C=new Promise((L,U)=>{v=L,b=U}),T=L=>{L?b(L):v()};if(h.isFile()){let L;u==="package.json"?L=Buffer.from(JSON.stringify(await lBe(t),null,2)):L=await oe.readFilePromise(A),o.entry({...E,mode:I,type:"file"},L,T)}else h.isSymbolicLink()?o.entry({...E,mode:I,type:"symlink",linkname:await oe.readlinkPromise(A)},T):T(new Error(`Unsupported file type ${h.mode} for ${ue.fromPortablePath(u)}`));await C}o.finalize()});let a=(0,aBe.createGzip)();return o.pipe(a),a}async function lBe(t){let e=JSON.parse(JSON.stringify(t.manifest.raw));return await t.project.configuration.triggerHook(r=>r.beforeWorkspacePacking,t,e),e}async function $Q(t){let e=t.project,r=e.configuration,o={accept:[],reject:[]};for(let I of avt)o.reject.push(I);for(let I of ovt)o.accept.push(I);o.reject.push(r.get("rcFilename"));let a=I=>{if(I===null||!I.startsWith(`${t.cwd}/`))return;let v=K.relative(t.cwd,I),b=K.resolve(Bt.root,v);o.reject.push(b)};a(K.resolve(e.cwd,dr.lockfile)),a(r.get("cacheFolder")),a(r.get("globalFolder")),a(r.get("installStatePath")),a(r.get("virtualFolder")),a(r.get("yarnPath")),await r.triggerHook(I=>I.populateYarnPaths,e,I=>{a(I)});for(let I of e.workspaces){let v=K.relative(t.cwd,I.cwd);v!==""&&!v.match(/^(\.\.)?\//)&&o.reject.push(`/${v}`)}let n={accept:[],reject:[]},u=t.manifest.publishConfig?.main??t.manifest.main,A=t.manifest.publishConfig?.module??t.manifest.module,p=t.manifest.publishConfig?.browser??t.manifest.browser,h=t.manifest.publishConfig?.bin??t.manifest.bin;u!=null&&n.accept.push(K.resolve(Bt.root,u)),A!=null&&n.accept.push(K.resolve(Bt.root,A)),typeof p=="string"&&n.accept.push(K.resolve(Bt.root,p));for(let I of h.values())n.accept.push(K.resolve(Bt.root,I));if(p instanceof Map)for(let[I,v]of p.entries())n.accept.push(K.resolve(Bt.root,I)),typeof v=="string"&&n.accept.push(K.resolve(Bt.root,v));let E=t.manifest.files!==null;if(E){n.reject.push("/*");for(let I of t.manifest.files)cBe(n.accept,I,{cwd:Bt.root})}return await lvt(t.cwd,{hasExplicitFileList:E,globalList:o,ignoreList:n})}async function lvt(t,{hasExplicitFileList:e,globalList:r,ignoreList:o}){let a=[],n=new _u(t),u=[[Bt.root,[o]]];for(;u.length>0;){let[A,p]=u.pop(),h=await n.lstatPromise(A);if(!iBe(A,{globalList:r,ignoreLists:h.isDirectory()?null:p}))if(h.isDirectory()){let E=await n.readdirPromise(A),I=!1,v=!1;if(!e||A!==Bt.root)for(let T of E)I=I||T===".gitignore",v=v||T===".npmignore";let b=v?await nBe(n,A,".npmignore"):I?await nBe(n,A,".gitignore"):null,C=b!==null?[b].concat(p):p;iBe(A,{globalList:r,ignoreLists:p})&&(C=[...p,{accept:[],reject:["**/*"]}]);for(let T of E)u.push([K.resolve(A,T),C])}else(h.isFile()||h.isSymbolicLink())&&a.push(K.relative(Bt.root,A))}return a.sort()}async function nBe(t,e,r){let o={accept:[],reject:[]},a=await t.readFilePromise(K.join(e,r),"utf8");for(let n of a.split(/\n/g))cBe(o.reject,n,{cwd:e});return o}function cvt(t,{cwd:e}){let r=t[0]==="!";return r&&(t=t.slice(1)),t.match(/\.{0,1}\//)&&(t=K.resolve(e,t)),r&&(t=`!${t}`),t}function cBe(t,e,{cwd:r}){let o=e.trim();o===""||o[0]==="#"||t.push(cvt(o,{cwd:r}))}function iBe(t,{globalList:e,ignoreLists:r}){let o=ZQ(t,e.accept);if(o!==0)return o===2;let a=ZQ(t,e.reject);if(a!==0)return a===1;if(r!==null)for(let n of r){let u=ZQ(t,n.accept);if(u!==0)return u===2;let A=ZQ(t,n.reject);if(A!==0)return A===1}return!1}function ZQ(t,e){let r=e,o=[];for(let a=0;a{await fG(a,{report:p},async()=>{p.reportJson({base:ue.fromPortablePath(a.cwd)});let h=await $Q(a);for(let E of h)p.reportInfo(null,ue.fromPortablePath(E)),p.reportJson({location:ue.fromPortablePath(E)});if(!this.dryRun){let E=await pG(a,h),I=oe.createWriteStream(u);E.pipe(I),await new Promise(v=>{I.on("finish",v)})}}),this.dryRun||(p.reportInfo(0,`Package archive generated in ${de.pretty(r,u,de.Type.PATH)}`),p.reportJson({output:ue.fromPortablePath(u)}))})).exitCode()}};O0.paths=[["pack"]],O0.usage=nt.Usage({description:"generate a tarball from the active workspace",details:"\n This command will turn the active workspace into a compressed archive suitable for publishing. The archive will by default be stored at the root of the workspace (`package.tgz`).\n\n If the `-o,---out` is set the archive will be created at the specified path. The `%s` and `%v` variables can be used within the path and will be respectively replaced by the package name and version.\n ",examples:[["Create an archive from the active workspace","yarn pack"],["List the files that would be made part of the workspace's archive","yarn pack --dry-run"],["Name and output the archive in a dedicated folder","yarn pack --out /artifacts/%s-%v.tgz"]]});function uvt(t,{workspace:e}){let r=t.replace("%s",Avt(e)).replace("%v",fvt(e));return ue.toPortablePath(r)}function Avt(t){return t.manifest.name!==null?W.slugifyIdent(t.manifest.name):"package"}function fvt(t){return t.manifest.version!==null?t.manifest.version:"unknown"}var pvt=["dependencies","devDependencies","peerDependencies"],hvt="workspace:",gvt=(t,e)=>{e.publishConfig&&(e.publishConfig.type&&(e.type=e.publishConfig.type),e.publishConfig.main&&(e.main=e.publishConfig.main),e.publishConfig.browser&&(e.browser=e.publishConfig.browser),e.publishConfig.module&&(e.module=e.publishConfig.module),e.publishConfig.exports&&(e.exports=e.publishConfig.exports),e.publishConfig.imports&&(e.imports=e.publishConfig.imports),e.publishConfig.bin&&(e.bin=e.publishConfig.bin));let r=t.project;for(let o of pvt)for(let a of t.manifest.getForScope(o).values()){let n=r.tryWorkspaceByDescriptor(a),u=W.parseRange(a.range);if(u.protocol===hvt)if(n===null){if(r.tryWorkspaceByIdent(a)===null)throw new zt(21,`${W.prettyDescriptor(r.configuration,a)}: No local workspace found for this range`)}else{let A;W.areDescriptorsEqual(a,n.anchoredDescriptor)||u.selector==="*"?A=n.manifest.version??"0.0.0":u.selector==="~"||u.selector==="^"?A=`${u.selector}${n.manifest.version??"0.0.0"}`:A=u.selector;let p=o==="dependencies"?W.makeDescriptor(a,"unknown"):null,h=p!==null&&t.manifest.ensureDependencyMeta(p).optional?"optionalDependencies":o;e[h][W.stringifyIdent(a)]=A}}},dvt={hooks:{beforeWorkspacePacking:gvt},commands:[O0]},mvt=dvt;var yBe=Be("crypto"),EBe=$e(mBe()),CBe=Be("url");async function Nvt(t,e,{access:r,tag:o,registry:a,gitHead:n}){let u=t.manifest.name,A=t.manifest.version,p=W.stringifyIdent(u),h=(0,yBe.createHash)("sha1").update(e).digest("hex"),E=EBe.default.fromData(e).toString(),I=r??wBe(t,u),v=await IBe(t),b=await CA.genPackageManifest(t),C=`${p}-${A}.tgz`,T=new CBe.URL(`${oc(a)}/${p}/-/${C}`);return{_id:p,_attachments:{[C]:{content_type:"application/octet-stream",data:e.toString("base64"),length:e.length}},name:p,access:I,["dist-tags"]:{[o]:A},versions:{[A]:{...b,_id:`${p}@${A}`,name:p,version:A,gitHead:n,dist:{shasum:h,integrity:E,tarball:T.toString()}}},readme:v}}async function Lvt(t){try{let{stdout:e}=await Ur.execvp("git",["rev-parse","--revs-only","HEAD"],{cwd:t});return e.trim()===""?void 0:e.trim()}catch{return}}function wBe(t,e){let r=t.project.configuration;return t.manifest.publishConfig&&typeof t.manifest.publishConfig.access=="string"?t.manifest.publishConfig.access:r.get("npmPublishAccess")!==null?r.get("npmPublishAccess"):e.scope?"restricted":"public"}async function IBe(t){let e=ue.toPortablePath(`${t.cwd}/README.md`),r=t.manifest.name,a=`# ${W.stringifyIdent(r)} -`;try{a=await oe.readFilePromise(e,"utf8")}catch(n){if(n.code==="ENOENT")return a;throw n}return a}var yG={npmAlwaysAuth:{description:"URL of the selected npm registry (note: npm enterprise isn't supported)",type:"BOOLEAN",default:!1},npmAuthIdent:{description:"Authentication identity for the npm registry (_auth in npm and yarn v1)",type:"SECRET",default:null},npmAuthToken:{description:"Authentication token for the npm registry (_authToken in npm and yarn v1)",type:"SECRET",default:null}},BBe={npmAuditRegistry:{description:"Registry to query for audit reports",type:"STRING",default:null},npmPublishRegistry:{description:"Registry to push packages to",type:"STRING",default:null},npmRegistryServer:{description:"URL of the selected npm registry (note: npm enterprise isn't supported)",type:"STRING",default:"https://registry.yarnpkg.com"}},Mvt={configuration:{...yG,...BBe,npmScopes:{description:"Settings per package scope",type:"MAP",valueDefinition:{description:"",type:"SHAPE",properties:{...yG,...BBe}}},npmRegistries:{description:"Settings per registry",type:"MAP",normalizeKeys:oc,valueDefinition:{description:"",type:"SHAPE",properties:{...yG}}}},fetchers:[fv,dl],resolvers:[pv,hv,gv]},Ovt=Mvt;var xG={};Kt(xG,{NpmAuditCommand:()=>_0,NpmInfoCommand:()=>H0,NpmLoginCommand:()=>j0,NpmLogoutCommand:()=>q0,NpmPublishCommand:()=>G0,NpmTagAddCommand:()=>W0,NpmTagListCommand:()=>Y0,NpmTagRemoveCommand:()=>V0,NpmWhoamiCommand:()=>K0,default:()=>Gvt,npmAuditTypes:()=>Tv,npmAuditUtils:()=>eF});Ye();Ye();qt();var vG=$e(Zo());Za();var Tv={};Kt(Tv,{Environment:()=>Qv,Severity:()=>Fv});var Qv=(o=>(o.All="all",o.Production="production",o.Development="development",o))(Qv||{}),Fv=(n=>(n.Info="info",n.Low="low",n.Moderate="moderate",n.High="high",n.Critical="critical",n))(Fv||{});var eF={};Kt(eF,{allSeverities:()=>ow,getPackages:()=>BG,getReportTree:()=>wG,getSeverityInclusions:()=>CG,getTopLevelDependencies:()=>IG});Ye();var vBe=$e(zn());var ow=["info","low","moderate","high","critical"];function CG(t){if(typeof t>"u")return new Set(ow);let e=ow.indexOf(t),r=ow.slice(e);return new Set(r)}function wG(t){let e={},r={children:e};for(let[o,a]of je.sortMap(Object.entries(t),n=>n[0]))for(let n of je.sortMap(a,u=>`${u.id}`))e[`${o}/${n.id}`]={value:de.tuple(de.Type.IDENT,W.parseIdent(o)),children:{ID:typeof n.id<"u"&&{label:"ID",value:de.tuple(de.Type.ID,n.id)},Issue:{label:"Issue",value:de.tuple(de.Type.NO_HINT,n.title)},URL:typeof n.url<"u"&&{label:"URL",value:de.tuple(de.Type.URL,n.url)},Severity:{label:"Severity",value:de.tuple(de.Type.NO_HINT,n.severity)},["Vulnerable Versions"]:{label:"Vulnerable Versions",value:de.tuple(de.Type.RANGE,n.vulnerable_versions)},["Tree Versions"]:{label:"Tree Versions",children:[...n.versions].sort(vBe.default.compare).map(u=>({value:de.tuple(de.Type.REFERENCE,u)}))},Dependents:{label:"Dependents",children:je.sortMap(n.dependents,u=>W.stringifyLocator(u)).map(u=>({value:de.tuple(de.Type.LOCATOR,u)}))}}};return r}function IG(t,e,{all:r,environment:o}){let a=[],n=r?t.workspaces:[e],u=["all","production"].includes(o),A=["all","development"].includes(o);for(let p of n)for(let h of p.anchoredPackage.dependencies.values())(p.manifest.devDependencies.has(h.identHash)?!A:!u)||a.push({workspace:p,dependency:h});return a}function BG(t,e,{recursive:r}){let o=new Map,a=new Set,n=[],u=(A,p)=>{let h=t.storedResolutions.get(p.descriptorHash);if(typeof h>"u")throw new Error("Assertion failed: The resolution should have been registered");if(!a.has(h))a.add(h);else return;let E=t.storedPackages.get(h);if(typeof E>"u")throw new Error("Assertion failed: The package should have been registered");if(W.ensureDevirtualizedLocator(E).reference.startsWith("npm:")&&E.version!==null){let v=W.stringifyIdent(E),b=je.getMapWithDefault(o,v);je.getArrayWithDefault(b,E.version).push(A)}if(r)for(let v of E.dependencies.values())n.push([E,v])};for(let{workspace:A,dependency:p}of e)n.push([A.anchoredLocator,p]);for(;n.length>0;){let[A,p]=n.shift();u(A,p)}return o}var _0=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Audit dependencies from all workspaces"});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Audit transitive dependencies as well"});this.environment=ge.String("--environment","all",{description:"Which environments to cover",validator:Vs(Qv)});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.noDeprecations=ge.Boolean("--no-deprecations",!1,{description:"Don't warn about deprecated packages"});this.severity=ge.String("--severity","info",{description:"Minimal severity requested for packages to be displayed",validator:Vs(Fv)});this.excludes=ge.Array("--exclude",[],{description:"Array of glob patterns of packages to exclude from audit"});this.ignores=ge.Array("--ignore",[],{description:"Array of glob patterns of advisory ID's to ignore in the audit report"})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState();let n=IG(o,a,{all:this.all,environment:this.environment}),u=BG(o,n,{recursive:this.recursive}),A=Array.from(new Set([...r.get("npmAuditExcludePackages"),...this.excludes])),p=Object.create(null);for(let[L,U]of u)A.some(J=>vG.default.isMatch(L,J))||(p[L]=[...U.keys()]);let h=Zn.getAuditRegistry({configuration:r}),E,I=await AA.start({configuration:r,stdout:this.context.stdout},async()=>{let L=on.post("/-/npm/v1/security/advisories/bulk",p,{authType:on.AuthType.BEST_EFFORT,configuration:r,jsonResponse:!0,registry:h}),U=this.noDeprecations?[]:await Promise.all(Array.from(Object.entries(p),async([te,le])=>{let pe=await on.getPackageMetadata(W.parseIdent(te),{project:o});return je.mapAndFilter(le,Ae=>{let{deprecated:ye}=pe.versions[Ae];return ye?[te,Ae,ye]:je.mapAndFilter.skip})})),J=await L;for(let[te,le,pe]of U.flat(1))Object.hasOwn(J,te)&&J[te].some(Ae=>kr.satisfiesWithPrereleases(le,Ae.vulnerable_versions))||(J[te]??=[],J[te].push({id:`${te} (deprecation)`,title:pe.trim()||"This package has been deprecated.",severity:"moderate",vulnerable_versions:le}));E=J});if(I.hasErrors())return I.exitCode();let v=CG(this.severity),b=Array.from(new Set([...r.get("npmAuditIgnoreAdvisories"),...this.ignores])),C=Object.create(null);for(let[L,U]of Object.entries(E)){let J=U.filter(te=>!vG.default.isMatch(`${te.id}`,b)&&v.has(te.severity));J.length>0&&(C[L]=J.map(te=>{let le=u.get(L);if(typeof le>"u")throw new Error("Assertion failed: Expected the registry to only return packages that were requested");let pe=[...le.keys()].filter(ye=>kr.satisfiesWithPrereleases(ye,te.vulnerable_versions)),Ae=new Map;for(let ye of pe)for(let ae of le.get(ye))Ae.set(ae.locatorHash,ae);return{...te,versions:pe,dependents:[...Ae.values()]}}))}let T=Object.keys(C).length>0;return T?($s.emitTree(wG(C),{configuration:r,json:this.json,stdout:this.context.stdout,separators:2}),1):(await Nt.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async L=>{L.reportInfo(1,"No audit suggestions")}),T?1:0)}};_0.paths=[["npm","audit"]],_0.usage=nt.Usage({description:"perform a vulnerability audit against the installed packages",details:` - This command checks for known security reports on the packages you use. The reports are by default extracted from the npm registry, and may or may not be relevant to your actual program (not all vulnerabilities affect all code paths). - - For consistency with our other commands the default is to only check the direct dependencies for the active workspace. To extend this search to all workspaces, use \`-A,--all\`. To extend this search to both direct and transitive dependencies, use \`-R,--recursive\`. - - Applying the \`--severity\` flag will limit the audit table to vulnerabilities of the corresponding severity and above. Valid values are ${ow.map(r=>`\`${r}\``).join(", ")}. - - If the \`--json\` flag is set, Yarn will print the output exactly as received from the registry. Regardless of this flag, the process will exit with a non-zero exit code if a report is found for the selected packages. - - If certain packages produce false positives for a particular environment, the \`--exclude\` flag can be used to exclude any number of packages from the audit. This can also be set in the configuration file with the \`npmAuditExcludePackages\` option. - - If particular advisories are needed to be ignored, the \`--ignore\` flag can be used with Advisory ID's to ignore any number of advisories in the audit report. This can also be set in the configuration file with the \`npmAuditIgnoreAdvisories\` option. - - To understand the dependency tree requiring vulnerable packages, check the raw report with the \`--json\` flag or use \`yarn why package\` to get more information as to who depends on them. - `,examples:[["Checks for known security issues with the installed packages. The output is a list of known issues.","yarn npm audit"],["Audit dependencies in all workspaces","yarn npm audit --all"],["Limit auditing to `dependencies` (excludes `devDependencies`)","yarn npm audit --environment production"],["Show audit report as valid JSON","yarn npm audit --json"],["Audit all direct and transitive dependencies","yarn npm audit --recursive"],["Output moderate (or more severe) vulnerabilities","yarn npm audit --severity moderate"],["Exclude certain packages","yarn npm audit --exclude package1 --exclude package2"],["Ignore specific advisories","yarn npm audit --ignore 1234567 --ignore 7654321"]]});Ye();Ye();Pt();qt();var DG=$e(zn()),PG=Be("util"),H0=class extends ut{constructor(){super(...arguments);this.fields=ge.String("-f,--fields",{description:"A comma-separated list of manifest fields that should be displayed"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.packages=ge.Rest()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd),a=typeof this.fields<"u"?new Set(["name",...this.fields.split(/\s*,\s*/)]):null,n=[],u=!1,A=await Nt.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async p=>{for(let h of this.packages){let E;if(h==="."){let le=o.topLevelWorkspace;if(!le.manifest.name)throw new it(`Missing ${de.pretty(r,"name",de.Type.CODE)} field in ${ue.fromPortablePath(K.join(le.cwd,dr.manifest))}`);E=W.makeDescriptor(le.manifest.name,"unknown")}else E=W.parseDescriptor(h);let I=on.getIdentUrl(E),v=SG(await on.get(I,{configuration:r,ident:E,jsonResponse:!0,customErrorMessage:on.customPackageError})),b=Object.keys(v.versions).sort(DG.default.compareLoose),T=v["dist-tags"].latest||b[b.length-1],L=kr.validRange(E.range);if(L){let le=DG.default.maxSatisfying(b,L);le!==null?T=le:(p.reportWarning(0,`Unmet range ${W.prettyRange(r,E.range)}; falling back to the latest version`),u=!0)}else Object.hasOwn(v["dist-tags"],E.range)?T=v["dist-tags"][E.range]:E.range!=="unknown"&&(p.reportWarning(0,`Unknown tag ${W.prettyRange(r,E.range)}; falling back to the latest version`),u=!0);let U=v.versions[T],J={...v,...U,version:T,versions:b},te;if(a!==null){te={};for(let le of a){let pe=J[le];if(typeof pe<"u")te[le]=pe;else{p.reportWarning(1,`The ${de.pretty(r,le,de.Type.CODE)} field doesn't exist inside ${W.prettyIdent(r,E)}'s information`),u=!0;continue}}}else this.json||(delete J.dist,delete J.readme,delete J.users),te=J;p.reportJson(te),this.json||n.push(te)}});PG.inspect.styles.name="cyan";for(let p of n)(p!==n[0]||u)&&this.context.stdout.write(` -`),this.context.stdout.write(`${(0,PG.inspect)(p,{depth:1/0,colors:!0,compact:!1})} -`);return A.exitCode()}};H0.paths=[["npm","info"]],H0.usage=nt.Usage({category:"Npm-related commands",description:"show information about a package",details:"\n This command fetches information about a package from the npm registry and prints it in a tree format.\n\n The package does not have to be installed locally, but needs to have been published (in particular, local changes will be ignored even for workspaces).\n\n Append `@` to the package argument to provide information specific to the latest version that satisfies the range or to the corresponding tagged version. If the range is invalid or if there is no version satisfying the range, the command will print a warning and fall back to the latest version.\n\n If the `-f,--fields` option is set, it's a comma-separated list of fields which will be used to only display part of the package information.\n\n By default, this command won't return the `dist`, `readme`, and `users` fields, since they are often very long. To explicitly request those fields, explicitly list them with the `--fields` flag or request the output in JSON mode.\n ",examples:[["Show all available information about react (except the `dist`, `readme`, and `users` fields)","yarn npm info react"],["Show all available information about react as valid JSON (including the `dist`, `readme`, and `users` fields)","yarn npm info react --json"],["Show all available information about react@16.12.0","yarn npm info react@16.12.0"],["Show all available information about react@next","yarn npm info react@next"],["Show the description of react","yarn npm info react --fields description"],["Show all available versions of react","yarn npm info react --fields versions"],["Show the readme of react","yarn npm info react --fields readme"],["Show a few fields of react","yarn npm info react --fields homepage,repository"]]});function SG(t){if(Array.isArray(t)){let e=[];for(let r of t)r=SG(r),r&&e.push(r);return e}else if(typeof t=="object"&&t!==null){let e={};for(let r of Object.keys(t)){if(r.startsWith("_"))continue;let o=SG(t[r]);o&&(e[r]=o)}return e}else return t||null}Ye();Ye();qt();var DBe=$e(A2()),j0=class extends ut{constructor(){super(...arguments);this.scope=ge.String("-s,--scope",{description:"Login to the registry configured for a given scope"});this.publish=ge.Boolean("--publish",!1,{description:"Login to the publish registry"});this.alwaysAuth=ge.Boolean("--always-auth",{description:"Set the npmAlwaysAuth configuration"})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),o=await tF({configuration:r,cwd:this.context.cwd,publish:this.publish,scope:this.scope});return(await Nt.start({configuration:r,stdout:this.context.stdout,includeFooter:!1},async n=>{let u=await _vt({configuration:r,registry:o,report:n,stdin:this.context.stdin,stdout:this.context.stdout}),A=`/-/user/org.couchdb.user:${encodeURIComponent(u.name)}`,p=await on.put(A,u,{attemptedAs:u.name,configuration:r,registry:o,jsonResponse:!0,authType:on.AuthType.NO_AUTH});return await Uvt(o,p.token,{alwaysAuth:this.alwaysAuth,scope:this.scope}),n.reportInfo(0,"Successfully logged in")})).exitCode()}};j0.paths=[["npm","login"]],j0.usage=nt.Usage({category:"Npm-related commands",description:"store new login info to access the npm registry",details:"\n This command will ask you for your username, password, and 2FA One-Time-Password (when it applies). It will then modify your local configuration (in your home folder, never in the project itself) to reference the new tokens thus generated.\n\n Adding the `-s,--scope` flag will cause the authentication to be done against whatever registry is configured for the associated scope (see also `npmScopes`).\n\n Adding the `--publish` flag will cause the authentication to be done against the registry used when publishing the package (see also `publishConfig.registry` and `npmPublishRegistry`).\n ",examples:[["Login to the default registry","yarn npm login"],["Login to the registry linked to the @my-scope registry","yarn npm login --scope my-scope"],["Login to the publish registry for the current package","yarn npm login --publish"]]});async function tF({scope:t,publish:e,configuration:r,cwd:o}){return t&&e?Zn.getScopeRegistry(t,{configuration:r,type:Zn.RegistryType.PUBLISH_REGISTRY}):t?Zn.getScopeRegistry(t,{configuration:r}):e?Zn.getPublishRegistry((await AC(r,o)).manifest,{configuration:r}):Zn.getDefaultRegistry({configuration:r})}async function Uvt(t,e,{alwaysAuth:r,scope:o}){let a=u=>A=>{let p=je.isIndexableObject(A)?A:{},h=p[u],E=je.isIndexableObject(h)?h:{};return{...p,[u]:{...E,...r!==void 0?{npmAlwaysAuth:r}:{},npmAuthToken:e}}},n=o?{npmScopes:a(o)}:{npmRegistries:a(t)};return await Ve.updateHomeConfiguration(n)}async function _vt({configuration:t,registry:e,report:r,stdin:o,stdout:a}){r.reportInfo(0,`Logging in to ${de.pretty(t,e,de.Type.URL)}`);let n=!1;if(e.match(/^https:\/\/npm\.pkg\.github\.com(\/|$)/)&&(r.reportInfo(0,"You seem to be using the GitHub Package Registry. Tokens must be generated with the 'repo', 'write:packages', and 'read:packages' permissions."),n=!0),r.reportSeparator(),t.env.YARN_IS_TEST_ENV)return{name:t.env.YARN_INJECT_NPM_USER||"",password:t.env.YARN_INJECT_NPM_PASSWORD||""};let{username:u,password:A}=await(0,DBe.prompt)([{type:"input",name:"username",message:"Username:",required:!0,onCancel:()=>process.exit(130),stdin:o,stdout:a},{type:"password",name:"password",message:n?"Token:":"Password:",required:!0,onCancel:()=>process.exit(130),stdin:o,stdout:a}]);return r.reportSeparator(),{name:u,password:A}}Ye();Ye();qt();var aw=new Set(["npmAuthIdent","npmAuthToken"]),q0=class extends ut{constructor(){super(...arguments);this.scope=ge.String("-s,--scope",{description:"Logout of the registry configured for a given scope"});this.publish=ge.Boolean("--publish",!1,{description:"Logout of the publish registry"});this.all=ge.Boolean("-A,--all",!1,{description:"Logout of all registries"})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),o=async()=>{let n=await tF({configuration:r,cwd:this.context.cwd,publish:this.publish,scope:this.scope}),u=await Ve.find(this.context.cwd,this.context.plugins),A=W.makeIdent(this.scope??null,"pkg");return!Zn.getAuthConfiguration(n,{configuration:u,ident:A}).get("npmAuthToken")};return(await Nt.start({configuration:r,stdout:this.context.stdout},async n=>{if(this.all&&(await jvt(),n.reportInfo(0,"Successfully logged out from everything")),this.scope){await PBe("npmScopes",this.scope),await o()?n.reportInfo(0,`Successfully logged out from ${this.scope}`):n.reportWarning(0,"Scope authentication settings removed, but some other ones settings still apply to it");return}let u=await tF({configuration:r,cwd:this.context.cwd,publish:this.publish});await PBe("npmRegistries",u),await o()?n.reportInfo(0,`Successfully logged out from ${u}`):n.reportWarning(0,"Registry authentication settings removed, but some other ones settings still apply to it")})).exitCode()}};q0.paths=[["npm","logout"]],q0.usage=nt.Usage({category:"Npm-related commands",description:"logout of the npm registry",details:"\n This command will log you out by modifying your local configuration (in your home folder, never in the project itself) to delete all credentials linked to a registry.\n\n Adding the `-s,--scope` flag will cause the deletion to be done against whatever registry is configured for the associated scope (see also `npmScopes`).\n\n Adding the `--publish` flag will cause the deletion to be done against the registry used when publishing the package (see also `publishConfig.registry` and `npmPublishRegistry`).\n\n Adding the `-A,--all` flag will cause the deletion to be done against all registries and scopes.\n ",examples:[["Logout of the default registry","yarn npm logout"],["Logout of the @my-scope scope","yarn npm logout --scope my-scope"],["Logout of the publish registry for the current package","yarn npm logout --publish"],["Logout of all registries","yarn npm logout --all"]]});function Hvt(t,e){let r=t[e];if(!je.isIndexableObject(r))return!1;let o=new Set(Object.keys(r));if([...aw].every(n=>!o.has(n)))return!1;for(let n of aw)o.delete(n);if(o.size===0)return t[e]=void 0,!0;let a={...r};for(let n of aw)delete a[n];return t[e]=a,!0}async function jvt(){let t=e=>{let r=!1,o=je.isIndexableObject(e)?{...e}:{};o.npmAuthToken&&(delete o.npmAuthToken,r=!0);for(let a of Object.keys(o))Hvt(o,a)&&(r=!0);if(Object.keys(o).length!==0)return r?o:e};return await Ve.updateHomeConfiguration({npmRegistries:t,npmScopes:t})}async function PBe(t,e){return await Ve.updateHomeConfiguration({[t]:r=>{let o=je.isIndexableObject(r)?r:{};if(!Object.hasOwn(o,e))return r;let a=o[e],n=je.isIndexableObject(a)?a:{},u=new Set(Object.keys(n));if([...aw].every(p=>!u.has(p)))return r;for(let p of aw)u.delete(p);if(u.size===0)return Object.keys(o).length===1?void 0:{...o,[e]:void 0};let A={};for(let p of aw)A[p]=void 0;return{...o,[e]:{...n,...A}}}})}Ye();qt();var G0=class extends ut{constructor(){super(...arguments);this.access=ge.String("--access",{description:"The access for the published package (public or restricted)"});this.tag=ge.String("--tag","latest",{description:"The tag on the registry that the package should be attached to"});this.tolerateRepublish=ge.Boolean("--tolerate-republish",!1,{description:"Warn and exit when republishing an already existing version of a package"});this.otp=ge.String("--otp",{description:"The OTP token to use with the command"})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);if(a.manifest.private)throw new it("Private workspaces cannot be published");if(a.manifest.name===null||a.manifest.version===null)throw new it("Workspaces must have valid names and versions to be published on an external registry");await o.restoreInstallState();let n=a.manifest.name,u=a.manifest.version,A=Zn.getPublishRegistry(a.manifest,{configuration:r});return(await Nt.start({configuration:r,stdout:this.context.stdout},async h=>{if(this.tolerateRepublish)try{let E=await on.get(on.getIdentUrl(n),{configuration:r,registry:A,ident:n,jsonResponse:!0});if(!Object.hasOwn(E,"versions"))throw new zt(15,'Registry returned invalid data for - missing "versions" field');if(Object.hasOwn(E.versions,u)){h.reportWarning(0,`Registry already knows about version ${u}; skipping.`);return}}catch(E){if(E.originalError?.response?.statusCode!==404)throw E}await un.maybeExecuteWorkspaceLifecycleScript(a,"prepublish",{report:h}),await CA.prepareForPack(a,{report:h},async()=>{let E=await CA.genPackList(a);for(let T of E)h.reportInfo(null,T);let I=await CA.genPackStream(a,E),v=await je.bufferStream(I),b=await sw.getGitHead(a.cwd),C=await sw.makePublishBody(a,v,{access:this.access,tag:this.tag,registry:A,gitHead:b});await on.put(on.getIdentUrl(n),C,{configuration:r,registry:A,ident:n,otp:this.otp,jsonResponse:!0})}),h.reportInfo(0,"Package archive published")})).exitCode()}};G0.paths=[["npm","publish"]],G0.usage=nt.Usage({category:"Npm-related commands",description:"publish the active workspace to the npm registry",details:'\n This command will pack the active workspace into a fresh archive and upload it to the npm registry.\n\n The package will by default be attached to the `latest` tag on the registry, but this behavior can be overriden by using the `--tag` option.\n\n Note that for legacy reasons scoped packages are by default published with an access set to `restricted` (aka "private packages"). This requires you to register for a paid npm plan. In case you simply wish to publish a public scoped package to the registry (for free), just add the `--access public` flag. This behavior can be enabled by default through the `npmPublishAccess` settings.\n ',examples:[["Publish the active workspace","yarn npm publish"]]});Ye();qt();var SBe=$e(zn());Ye();Pt();qt();var Y0=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.package=ge.String({required:!1})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n;if(typeof this.package<"u")n=W.parseIdent(this.package);else{if(!a)throw new rr(o.cwd,this.context.cwd);if(!a.manifest.name)throw new it(`Missing 'name' field in ${ue.fromPortablePath(K.join(a.cwd,dr.manifest))}`);n=a.manifest.name}let u=await Rv(n,r),p={children:je.sortMap(Object.entries(u),([h])=>h).map(([h,E])=>({value:de.tuple(de.Type.RESOLUTION,{descriptor:W.makeDescriptor(n,h),locator:W.makeLocator(n,E)})}))};return $s.emitTree(p,{configuration:r,json:this.json,stdout:this.context.stdout})}};Y0.paths=[["npm","tag","list"]],Y0.usage=nt.Usage({category:"Npm-related commands",description:"list all dist-tags of a package",details:` - This command will list all tags of a package from the npm registry. - - If the package is not specified, Yarn will default to the current workspace. - `,examples:[["List all tags of package `my-pkg`","yarn npm tag list my-pkg"]]});async function Rv(t,e){let r=`/-/package${on.getIdentUrl(t)}/dist-tags`;return on.get(r,{configuration:e,ident:t,jsonResponse:!0,customErrorMessage:on.customPackageError})}var W0=class extends ut{constructor(){super(...arguments);this.package=ge.String();this.tag=ge.String()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);let n=W.parseDescriptor(this.package,!0),u=n.range;if(!SBe.default.valid(u))throw new it(`The range ${de.pretty(r,n.range,de.Type.RANGE)} must be a valid semver version`);let A=Zn.getPublishRegistry(a.manifest,{configuration:r}),p=de.pretty(r,n,de.Type.IDENT),h=de.pretty(r,u,de.Type.RANGE),E=de.pretty(r,this.tag,de.Type.CODE);return(await Nt.start({configuration:r,stdout:this.context.stdout},async v=>{let b=await Rv(n,r);Object.hasOwn(b,this.tag)&&b[this.tag]===u&&v.reportWarning(0,`Tag ${E} is already set to version ${h}`);let C=`/-/package${on.getIdentUrl(n)}/dist-tags/${encodeURIComponent(this.tag)}`;await on.put(C,u,{configuration:r,registry:A,ident:n,jsonRequest:!0,jsonResponse:!0}),v.reportInfo(0,`Tag ${E} added to version ${h} of package ${p}`)})).exitCode()}};W0.paths=[["npm","tag","add"]],W0.usage=nt.Usage({category:"Npm-related commands",description:"add a tag for a specific version of a package",details:` - This command will add a tag to the npm registry for a specific version of a package. If the tag already exists, it will be overwritten. - `,examples:[["Add a `beta` tag for version `2.3.4-beta.4` of package `my-pkg`","yarn npm tag add my-pkg@2.3.4-beta.4 beta"]]});Ye();qt();var V0=class extends ut{constructor(){super(...arguments);this.package=ge.String();this.tag=ge.String()}async execute(){if(this.tag==="latest")throw new it("The 'latest' tag cannot be removed.");let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);let n=W.parseIdent(this.package),u=Zn.getPublishRegistry(a.manifest,{configuration:r}),A=de.pretty(r,this.tag,de.Type.CODE),p=de.pretty(r,n,de.Type.IDENT),h=await Rv(n,r);if(!Object.hasOwn(h,this.tag))throw new it(`${A} is not a tag of package ${p}`);return(await Nt.start({configuration:r,stdout:this.context.stdout},async I=>{let v=`/-/package${on.getIdentUrl(n)}/dist-tags/${encodeURIComponent(this.tag)}`;await on.del(v,{configuration:r,registry:u,ident:n,jsonResponse:!0}),I.reportInfo(0,`Tag ${A} removed from package ${p}`)})).exitCode()}};V0.paths=[["npm","tag","remove"]],V0.usage=nt.Usage({category:"Npm-related commands",description:"remove a tag from a package",details:` - This command will remove a tag from a package from the npm registry. - `,examples:[["Remove the `beta` tag from package `my-pkg`","yarn npm tag remove my-pkg beta"]]});Ye();Ye();qt();var K0=class extends ut{constructor(){super(...arguments);this.scope=ge.String("-s,--scope",{description:"Print username for the registry configured for a given scope"});this.publish=ge.Boolean("--publish",!1,{description:"Print username for the publish registry"})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),o;return this.scope&&this.publish?o=Zn.getScopeRegistry(this.scope,{configuration:r,type:Zn.RegistryType.PUBLISH_REGISTRY}):this.scope?o=Zn.getScopeRegistry(this.scope,{configuration:r}):this.publish?o=Zn.getPublishRegistry((await AC(r,this.context.cwd)).manifest,{configuration:r}):o=Zn.getDefaultRegistry({configuration:r}),(await Nt.start({configuration:r,stdout:this.context.stdout},async n=>{let u;try{u=await on.get("/-/whoami",{configuration:r,registry:o,authType:on.AuthType.ALWAYS_AUTH,jsonResponse:!0,ident:this.scope?W.makeIdent(this.scope,""):void 0})}catch(A){if(A.response?.statusCode===401||A.response?.statusCode===403){n.reportError(41,"Authentication failed - your credentials may have expired");return}else throw A}n.reportInfo(0,u.username)})).exitCode()}};K0.paths=[["npm","whoami"]],K0.usage=nt.Usage({category:"Npm-related commands",description:"display the name of the authenticated user",details:"\n Print the username associated with the current authentication settings to the standard output.\n\n When using `-s,--scope`, the username printed will be the one that matches the authentication settings of the registry associated with the given scope (those settings can be overriden using the `npmRegistries` map, and the registry associated with the scope is configured via the `npmScopes` map).\n\n When using `--publish`, the registry we'll select will by default be the one used when publishing packages (`publishConfig.registry` or `npmPublishRegistry` if available, otherwise we'll fallback to the regular `npmRegistryServer`).\n ",examples:[["Print username for the default registry","yarn npm whoami"],["Print username for the registry on a given scope","yarn npm whoami --scope company"]]});var qvt={configuration:{npmPublishAccess:{description:"Default access of the published packages",type:"STRING",default:null},npmAuditExcludePackages:{description:"Array of glob patterns of packages to exclude from npm audit",type:"STRING",default:[],isArray:!0},npmAuditIgnoreAdvisories:{description:"Array of glob patterns of advisory IDs to exclude from npm audit",type:"STRING",default:[],isArray:!0}},commands:[_0,H0,j0,q0,G0,W0,Y0,V0,K0]},Gvt=qvt;var NG={};Kt(NG,{PatchCommand:()=>X0,PatchCommitCommand:()=>z0,PatchFetcher:()=>Uv,PatchResolver:()=>_v,default:()=>lDt,patchUtils:()=>Dm});Ye();Ye();Pt();nA();var Dm={};Kt(Dm,{applyPatchFile:()=>nF,diffFolders:()=>TG,ensureUnpatchedDescriptor:()=>bG,ensureUnpatchedLocator:()=>sF,extractPackageToDisk:()=>FG,extractPatchFlags:()=>RBe,isParentRequired:()=>QG,isPatchDescriptor:()=>iF,isPatchLocator:()=>J0,loadPatchFiles:()=>Ov,makeDescriptor:()=>oF,makeLocator:()=>kG,makePatchHash:()=>RG,parseDescriptor:()=>Lv,parseLocator:()=>Mv,parsePatchFile:()=>Nv,unpatchDescriptor:()=>sDt,unpatchLocator:()=>oDt});Ye();Pt();Ye();Pt();var Yvt=/^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@.*/;function lw(t){return K.relative(Bt.root,K.resolve(Bt.root,ue.toPortablePath(t)))}function Wvt(t){let e=t.trim().match(Yvt);if(!e)throw new Error(`Bad header line: '${t}'`);return{original:{start:Math.max(Number(e[1]),1),length:Number(e[3]||1)},patched:{start:Math.max(Number(e[4]),1),length:Number(e[6]||1)}}}var Vvt=420,Kvt=493;var xBe=()=>({semverExclusivity:null,diffLineFromPath:null,diffLineToPath:null,oldMode:null,newMode:null,deletedFileMode:null,newFileMode:null,renameFrom:null,renameTo:null,beforeHash:null,afterHash:null,fromPath:null,toPath:null,hunks:null}),Jvt=t=>({header:Wvt(t),parts:[]}),zvt={["@"]:"header",["-"]:"deletion",["+"]:"insertion",[" "]:"context",["\\"]:"pragma",undefined:"context"};function Xvt(t){let e=[],r=xBe(),o="parsing header",a=null,n=null;function u(){a&&(n&&(a.parts.push(n),n=null),r.hunks.push(a),a=null)}function A(){u(),e.push(r),r=xBe()}for(let p=0;p0?"patch":"mode change",J=null;switch(U){case"rename":{if(!E||!I)throw new Error("Bad parser state: rename from & to not given");e.push({type:"rename",semverExclusivity:o,fromPath:lw(E),toPath:lw(I)}),J=I}break;case"file deletion":{let te=a||C;if(!te)throw new Error("Bad parse state: no path given for file deletion");e.push({type:"file deletion",semverExclusivity:o,hunk:L&&L[0]||null,path:lw(te),mode:rF(p),hash:v})}break;case"file creation":{let te=n||T;if(!te)throw new Error("Bad parse state: no path given for file creation");e.push({type:"file creation",semverExclusivity:o,hunk:L&&L[0]||null,path:lw(te),mode:rF(h),hash:b})}break;case"patch":case"mode change":J=T||n;break;default:je.assertNever(U);break}J&&u&&A&&u!==A&&e.push({type:"mode change",semverExclusivity:o,path:lw(J),oldMode:rF(u),newMode:rF(A)}),J&&L&&L.length&&e.push({type:"patch",semverExclusivity:o,path:lw(J),hunks:L,beforeHash:v,afterHash:b})}if(e.length===0)throw new Error("Unable to parse patch file: No changes found. Make sure the patch is a valid UTF8 encoded string");return e}function rF(t){let e=parseInt(t,8)&511;if(e!==Vvt&&e!==Kvt)throw new Error(`Unexpected file mode string: ${t}`);return e}function Nv(t){let e=t.split(/\n/g);return e[e.length-1]===""&&e.pop(),Zvt(Xvt(e))}function $vt(t){let e=0,r=0;for(let{type:o,lines:a}of t.parts)switch(o){case"context":r+=a.length,e+=a.length;break;case"deletion":e+=a.length;break;case"insertion":r+=a.length;break;default:je.assertNever(o);break}if(e!==t.header.original.length||r!==t.header.patched.length){let o=a=>a<0?a:`+${a}`;throw new Error(`hunk header integrity check failed (expected @@ ${o(t.header.original.length)} ${o(t.header.patched.length)} @@, got @@ ${o(e)} ${o(r)} @@)`)}}Ye();Pt();var cw=class extends Error{constructor(r,o){super(`Cannot apply hunk #${r+1}`);this.hunk=o}};async function uw(t,e,r){let o=await t.lstatPromise(e),a=await r();typeof a<"u"&&(e=a),await t.lutimesPromise(e,o.atime,o.mtime)}async function nF(t,{baseFs:e=new Rn,dryRun:r=!1,version:o=null}={}){for(let a of t)if(!(a.semverExclusivity!==null&&o!==null&&!kr.satisfiesWithPrereleases(o,a.semverExclusivity)))switch(a.type){case"file deletion":if(r){if(!e.existsSync(a.path))throw new Error(`Trying to delete a file that doesn't exist: ${a.path}`)}else await uw(e,K.dirname(a.path),async()=>{await e.unlinkPromise(a.path)});break;case"rename":if(r){if(!e.existsSync(a.fromPath))throw new Error(`Trying to move a file that doesn't exist: ${a.fromPath}`)}else await uw(e,K.dirname(a.fromPath),async()=>{await uw(e,K.dirname(a.toPath),async()=>{await uw(e,a.fromPath,async()=>(await e.movePromise(a.fromPath,a.toPath),a.toPath))})});break;case"file creation":if(r){if(e.existsSync(a.path))throw new Error(`Trying to create a file that already exists: ${a.path}`)}else{let n=a.hunk?a.hunk.parts[0].lines.join(` -`)+(a.hunk.parts[0].noNewlineAtEndOfFile?"":` -`):"";await e.mkdirpPromise(K.dirname(a.path),{chmod:493,utimes:[vi.SAFE_TIME,vi.SAFE_TIME]}),await e.writeFilePromise(a.path,n,{mode:a.mode}),await e.utimesPromise(a.path,vi.SAFE_TIME,vi.SAFE_TIME)}break;case"patch":await uw(e,a.path,async()=>{await rDt(a,{baseFs:e,dryRun:r})});break;case"mode change":{let u=(await e.statPromise(a.path)).mode;if(bBe(a.newMode)!==bBe(u))continue;await uw(e,a.path,async()=>{await e.chmodPromise(a.path,a.newMode)})}break;default:je.assertNever(a);break}}function bBe(t){return(t&64)>0}function kBe(t){return t.replace(/\s+$/,"")}function tDt(t,e){return kBe(t)===kBe(e)}async function rDt({hunks:t,path:e},{baseFs:r,dryRun:o=!1}){let a=await r.statSync(e).mode,u=(await r.readFileSync(e,"utf8")).split(/\n/),A=[],p=0,h=0;for(let I of t){let v=Math.max(h,I.header.patched.start+p),b=Math.max(0,v-h),C=Math.max(0,u.length-v-I.header.original.length),T=Math.max(b,C),L=0,U=0,J=null;for(;L<=T;){if(L<=b&&(U=v-L,J=QBe(I,u,U),J!==null)){L=-L;break}if(L<=C&&(U=v+L,J=QBe(I,u,U),J!==null))break;L+=1}if(J===null)throw new cw(t.indexOf(I),I);A.push(J),p+=L,h=U+I.header.original.length}if(o)return;let E=0;for(let I of A)for(let v of I)switch(v.type){case"splice":{let b=v.index+E;u.splice(b,v.numToDelete,...v.linesToInsert),E+=v.linesToInsert.length-v.numToDelete}break;case"pop":u.pop();break;case"push":u.push(v.line);break;default:je.assertNever(v);break}await r.writeFilePromise(e,u.join(` -`),{mode:a})}function QBe(t,e,r){let o=[];for(let a of t.parts)switch(a.type){case"context":case"deletion":{for(let n of a.lines){let u=e[r];if(u==null||!tDt(u,n))return null;r+=1}a.type==="deletion"&&(o.push({type:"splice",index:r-a.lines.length,numToDelete:a.lines.length,linesToInsert:[]}),a.noNewlineAtEndOfFile&&o.push({type:"push",line:""}))}break;case"insertion":o.push({type:"splice",index:r,numToDelete:0,linesToInsert:a.lines}),a.noNewlineAtEndOfFile&&o.push({type:"pop"});break;default:je.assertNever(a.type);break}return o}var iDt=/^builtin<([^>]+)>$/;function Aw(t,e){let{protocol:r,source:o,selector:a,params:n}=W.parseRange(t);if(r!=="patch:")throw new Error("Invalid patch range");if(o===null)throw new Error("Patch locators must explicitly define their source");let u=a?a.split(/&/).map(E=>ue.toPortablePath(E)):[],A=n&&typeof n.locator=="string"?W.parseLocator(n.locator):null,p=n&&typeof n.version=="string"?n.version:null,h=e(o);return{parentLocator:A,sourceItem:h,patchPaths:u,sourceVersion:p}}function iF(t){return t.range.startsWith("patch:")}function J0(t){return t.reference.startsWith("patch:")}function Lv(t){let{sourceItem:e,...r}=Aw(t.range,W.parseDescriptor);return{...r,sourceDescriptor:e}}function Mv(t){let{sourceItem:e,...r}=Aw(t.reference,W.parseLocator);return{...r,sourceLocator:e}}function sDt(t){let{sourceItem:e}=Aw(t.range,W.parseDescriptor);return e}function oDt(t){let{sourceItem:e}=Aw(t.reference,W.parseLocator);return e}function bG(t){if(!iF(t))return t;let{sourceItem:e}=Aw(t.range,W.parseDescriptor);return e}function sF(t){if(!J0(t))return t;let{sourceItem:e}=Aw(t.reference,W.parseLocator);return e}function FBe({parentLocator:t,sourceItem:e,patchPaths:r,sourceVersion:o,patchHash:a},n){let u=t!==null?{locator:W.stringifyLocator(t)}:{},A=typeof o<"u"?{version:o}:{},p=typeof a<"u"?{hash:a}:{};return W.makeRange({protocol:"patch:",source:n(e),selector:r.join("&"),params:{...A,...p,...u}})}function oF(t,{parentLocator:e,sourceDescriptor:r,patchPaths:o}){return W.makeDescriptor(t,FBe({parentLocator:e,sourceItem:r,patchPaths:o},W.stringifyDescriptor))}function kG(t,{parentLocator:e,sourcePackage:r,patchPaths:o,patchHash:a}){return W.makeLocator(t,FBe({parentLocator:e,sourceItem:r,sourceVersion:r.version,patchPaths:o,patchHash:a},W.stringifyLocator))}function TBe({onAbsolute:t,onRelative:e,onProject:r,onBuiltin:o},a){let n=a.lastIndexOf("!");n!==-1&&(a=a.slice(n+1));let u=a.match(iDt);return u!==null?o(u[1]):a.startsWith("~/")?r(a.slice(2)):K.isAbsolute(a)?t(a):e(a)}function RBe(t){let e=t.lastIndexOf("!");return{optional:(e!==-1?new Set(t.slice(0,e).split(/!/)):new Set).has("optional")}}function QG(t){return TBe({onAbsolute:()=>!1,onRelative:()=>!0,onProject:()=>!1,onBuiltin:()=>!1},t)}async function Ov(t,e,r){let o=t!==null?await r.fetcher.fetch(t,r):null,a=o&&o.localPath?{packageFs:new gn(Bt.root),prefixPath:K.relative(Bt.root,o.localPath)}:o;o&&o!==a&&o.releaseFs&&o.releaseFs();let n=await je.releaseAfterUseAsync(async()=>await Promise.all(e.map(async u=>{let A=RBe(u),p=await TBe({onAbsolute:async h=>await oe.readFilePromise(h,"utf8"),onRelative:async h=>{if(a===null)throw new Error("Assertion failed: The parent locator should have been fetched");return await a.packageFs.readFilePromise(K.join(a.prefixPath,h),"utf8")},onProject:async h=>await oe.readFilePromise(K.join(r.project.cwd,h),"utf8"),onBuiltin:async h=>await r.project.configuration.firstHook(E=>E.getBuiltinPatch,r.project,h)},u);return{...A,source:p}})));for(let u of n)typeof u.source=="string"&&(u.source=u.source.replace(/\r\n?/g,` -`));return n}async function FG(t,{cache:e,project:r}){let o=r.storedPackages.get(t.locatorHash);if(typeof o>"u")throw new Error("Assertion failed: Expected the package to be registered");let a=sF(t),n=r.storedChecksums,u=new Qi,A=await oe.mktempPromise(),p=K.join(A,"source"),h=K.join(A,"user"),E=K.join(A,".yarn-patch.json"),I=r.configuration.makeFetcher(),v=[];try{let b,C;if(t.locatorHash===a.locatorHash){let T=await I.fetch(t,{cache:e,project:r,fetcher:I,checksums:n,report:u});v.push(()=>T.releaseFs?.()),b=T,C=T}else b=await I.fetch(t,{cache:e,project:r,fetcher:I,checksums:n,report:u}),v.push(()=>b.releaseFs?.()),C=await I.fetch(t,{cache:e,project:r,fetcher:I,checksums:n,report:u}),v.push(()=>C.releaseFs?.());await Promise.all([oe.copyPromise(p,b.prefixPath,{baseFs:b.packageFs}),oe.copyPromise(h,C.prefixPath,{baseFs:C.packageFs}),oe.writeJsonPromise(E,{locator:W.stringifyLocator(t),version:o.version})])}finally{for(let b of v)b()}return oe.detachTemp(A),h}async function TG(t,e){let r=ue.fromPortablePath(t).replace(/\\/g,"/"),o=ue.fromPortablePath(e).replace(/\\/g,"/"),{stdout:a,stderr:n}=await Ur.execvp("git",["-c","core.safecrlf=false","diff","--src-prefix=a/","--dst-prefix=b/","--ignore-cr-at-eol","--full-index","--no-index","--no-renames","--text",r,o],{cwd:ue.toPortablePath(process.cwd()),env:{...process.env,GIT_CONFIG_NOSYSTEM:"1",HOME:"",XDG_CONFIG_HOME:"",USERPROFILE:""}});if(n.length>0)throw new Error(`Unable to diff directories. Make sure you have a recent version of 'git' available in PATH. -The following error was reported by 'git': -${n}`);let u=r.startsWith("/")?A=>A.slice(1):A=>A;return a.replace(new RegExp(`(a|b)(${je.escapeRegExp(`/${u(r)}/`)})`,"g"),"$1/").replace(new RegExp(`(a|b)${je.escapeRegExp(`/${u(o)}/`)}`,"g"),"$1/").replace(new RegExp(je.escapeRegExp(`${r}/`),"g"),"").replace(new RegExp(je.escapeRegExp(`${o}/`),"g"),"")}function RG(t,e){let r=[];for(let{source:o}of t){if(o===null)continue;let a=Nv(o);for(let n of a){let{semverExclusivity:u,...A}=n;u!==null&&e!==null&&!kr.satisfiesWithPrereleases(e,u)||r.push(JSON.stringify(A))}}return wn.makeHash(`${3}`,...r).slice(0,6)}Ye();function NBe(t,{configuration:e,report:r}){for(let o of t.parts)for(let a of o.lines)switch(o.type){case"context":r.reportInfo(null,` ${de.pretty(e,a,"grey")}`);break;case"deletion":r.reportError(28,`- ${de.pretty(e,a,de.Type.REMOVED)}`);break;case"insertion":r.reportError(28,`+ ${de.pretty(e,a,de.Type.ADDED)}`);break;default:je.assertNever(o.type)}}var Uv=class{supports(e,r){return!!J0(e)}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.patchPackage(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:u}}async patchPackage(e,r){let{parentLocator:o,sourceLocator:a,sourceVersion:n,patchPaths:u}=Mv(e),A=await Ov(o,u,r),p=await oe.mktempPromise(),h=K.join(p,"current.zip"),E=await r.fetcher.fetch(a,r),I=W.getIdentVendorPath(e),v=new zi(h,{create:!0,level:r.project.configuration.get("compressionLevel")});await je.releaseAfterUseAsync(async()=>{await v.copyPromise(I,E.prefixPath,{baseFs:E.packageFs,stableSort:!0})},E.releaseFs),v.saveAndClose();for(let{source:b,optional:C}of A){if(b===null)continue;let T=new zi(h,{level:r.project.configuration.get("compressionLevel")}),L=new gn(K.resolve(Bt.root,I),{baseFs:T});try{await nF(Nv(b),{baseFs:L,version:n})}catch(U){if(!(U instanceof cw))throw U;let J=r.project.configuration.get("enableInlineHunks"),te=!J&&!C?" (set enableInlineHunks for details)":"",le=`${W.prettyLocator(r.project.configuration,e)}: ${U.message}${te}`,pe=Ae=>{!J||NBe(U.hunk,{configuration:r.project.configuration,report:Ae})};if(T.discardAndClose(),C){r.report.reportWarningOnce(66,le,{reportExtra:pe});continue}else throw new zt(66,le,pe)}T.saveAndClose()}return new zi(h,{level:r.project.configuration.get("compressionLevel")})}};Ye();var _v=class{supportsDescriptor(e,r){return!!iF(e)}supportsLocator(e,r){return!!J0(e)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){let{patchPaths:a}=Lv(e);return a.every(n=>!QG(n))?e:W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){let{sourceDescriptor:o}=Lv(e);return{sourceDescriptor:r.project.configuration.normalizeDependency(o)}}async getCandidates(e,r,o){if(!o.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let{parentLocator:a,patchPaths:n}=Lv(e),u=await Ov(a,n,o.fetchOptions),A=r.sourceDescriptor;if(typeof A>"u")throw new Error("Assertion failed: The dependency should have been resolved");let p=RG(u,A.version);return[kG(e,{parentLocator:a,sourcePackage:A,patchPaths:n,patchHash:p})]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let{sourceLocator:o}=Mv(e);return{...await r.resolver.resolve(o,r),...e}}};Ye();Pt();qt();var z0=class extends ut{constructor(){super(...arguments);this.save=ge.Boolean("-s,--save",!1,{description:"Add the patch to your resolution entries"});this.patchFolder=ge.String()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState();let n=K.resolve(this.context.cwd,ue.toPortablePath(this.patchFolder)),u=K.join(n,"../source"),A=K.join(n,"../.yarn-patch.json");if(!oe.existsSync(u))throw new it("The argument folder didn't get created by 'yarn patch'");let p=await TG(u,n),h=await oe.readJsonPromise(A),E=W.parseLocator(h.locator,!0);if(!o.storedPackages.has(E.locatorHash))throw new it("No package found in the project for the given locator");if(!this.save){this.context.stdout.write(p);return}let I=r.get("patchFolder"),v=K.join(I,`${W.slugifyLocator(E)}.patch`);await oe.mkdirPromise(I,{recursive:!0}),await oe.writeFilePromise(v,p);let b=[],C=new Map;for(let T of o.storedPackages.values()){if(W.isVirtualLocator(T))continue;let L=T.dependencies.get(E.identHash);if(!L)continue;let U=W.ensureDevirtualizedDescriptor(L),J=bG(U),te=o.storedResolutions.get(J.descriptorHash);if(!te)throw new Error("Assertion failed: Expected the resolution to have been registered");if(!o.storedPackages.get(te))throw new Error("Assertion failed: Expected the package to have been registered");let pe=o.tryWorkspaceByLocator(T);if(pe)b.push(pe);else{let Ae=o.originalPackages.get(T.locatorHash);if(!Ae)throw new Error("Assertion failed: Expected the original package to have been registered");let ye=Ae.dependencies.get(L.identHash);if(!ye)throw new Error("Assertion failed: Expected the original dependency to have been registered");C.set(ye.descriptorHash,ye)}}for(let T of b)for(let L of Mt.hardDependencies){let U=T.manifest[L].get(E.identHash);if(!U)continue;let J=oF(U,{parentLocator:null,sourceDescriptor:W.convertLocatorToDescriptor(E),patchPaths:[K.join(dr.home,K.relative(o.cwd,v))]});T.manifest[L].set(U.identHash,J)}for(let T of C.values()){let L=oF(T,{parentLocator:null,sourceDescriptor:W.convertLocatorToDescriptor(E),patchPaths:[K.join(dr.home,K.relative(o.cwd,v))]});o.topLevelWorkspace.manifest.resolutions.push({pattern:{descriptor:{fullName:W.stringifyIdent(L),description:T.range}},reference:L.range})}await o.persist()}};z0.paths=[["patch-commit"]],z0.usage=nt.Usage({description:"generate a patch out of a directory",details:"\n By default, this will print a patchfile on stdout based on the diff between the folder passed in and the original version of the package. Such file is suitable for consumption with the `patch:` protocol.\n\n With the `-s,--save` option set, the patchfile won't be printed on stdout anymore and will instead be stored within a local file (by default kept within `.yarn/patches`, but configurable via the `patchFolder` setting). A `resolutions` entry will also be added to your top-level manifest, referencing the patched package via the `patch:` protocol.\n\n Note that only folders generated by `yarn patch` are accepted as valid input for `yarn patch-commit`.\n "});Ye();Pt();qt();var X0=class extends ut{constructor(){super(...arguments);this.update=ge.Boolean("-u,--update",!1,{description:"Reapply local patches that already apply to this packages"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.package=ge.String()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState();let u=W.parseLocator(this.package);if(u.reference==="unknown"){let A=je.mapAndFilter([...o.storedPackages.values()],p=>p.identHash!==u.identHash?je.mapAndFilter.skip:W.isVirtualLocator(p)?je.mapAndFilter.skip:J0(p)!==this.update?je.mapAndFilter.skip:p);if(A.length===0)throw new it("No package found in the project for the given locator");if(A.length>1)throw new it(`Multiple candidate packages found; explicitly choose one of them (use \`yarn why \` to get more information as to who depends on them): -${A.map(p=>` -- ${W.prettyLocator(r,p)}`).join("")}`);u=A[0]}if(!o.storedPackages.has(u.locatorHash))throw new it("No package found in the project for the given locator");await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout},async A=>{let p=sF(u),h=await FG(u,{cache:n,project:o});A.reportJson({locator:W.stringifyLocator(p),path:ue.fromPortablePath(h)});let E=this.update?" along with its current modifications":"";A.reportInfo(0,`Package ${W.prettyLocator(r,p)} got extracted with success${E}!`),A.reportInfo(0,`You can now edit the following folder: ${de.pretty(r,ue.fromPortablePath(h),"magenta")}`),A.reportInfo(0,`Once you are done run ${de.pretty(r,`yarn patch-commit -s ${process.platform==="win32"?'"':""}${ue.fromPortablePath(h)}${process.platform==="win32"?'"':""}`,"cyan")} and Yarn will store a patchfile based on your changes.`)})}};X0.paths=[["patch"]],X0.usage=nt.Usage({description:"prepare a package for patching",details:"\n This command will cause a package to be extracted in a temporary directory intended to be editable at will.\n\n Once you're done with your changes, run `yarn patch-commit -s path` (with `path` being the temporary directory you received) to generate a patchfile and register it into your top-level manifest via the `patch:` protocol. Run `yarn patch-commit -h` for more details.\n\n Calling the command when you already have a patch won't import it by default (in other words, the default behavior is to reset existing patches). However, adding the `-u,--update` flag will import any current patch.\n "});var aDt={configuration:{enableInlineHunks:{description:"If true, the installs will print unmatched patch hunks",type:"BOOLEAN",default:!1},patchFolder:{description:"Folder where the patch files must be written",type:"ABSOLUTE_PATH",default:"./.yarn/patches"}},commands:[z0,X0],fetchers:[Uv],resolvers:[_v]},lDt=aDt;var OG={};Kt(OG,{PnpmLinker:()=>Hv,default:()=>pDt});Ye();Pt();qt();var Hv=class{getCustomDataKey(){return JSON.stringify({name:"PnpmLinker",version:3})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error("Assertion failed: Expected the pnpm linker to be enabled");let o=this.getCustomDataKey(),a=r.project.linkersCustomData.get(o);if(!a)throw new it(`The project in ${de.pretty(r.project.configuration,`${r.project.cwd}/package.json`,de.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let n=a.pathsByLocator.get(e.locatorHash);if(typeof n>"u")throw new it(`Couldn't find ${W.prettyLocator(r.project.configuration,e)} in the currently installed pnpm map - running an install might help`);return n.packageLocation}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let o=this.getCustomDataKey(),a=r.project.linkersCustomData.get(o);if(!a)throw new it(`The project in ${de.pretty(r.project.configuration,`${r.project.cwd}/package.json`,de.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let n=e.match(/(^.*\/node_modules\/(@[^/]*\/)?[^/]+)(\/.*$)/);if(n){let p=a.locatorByPath.get(n[1]);if(p)return p}let u=e,A=e;do{A=u,u=K.dirname(A);let p=a.locatorByPath.get(A);if(p)return p}while(u!==A);return null}makeInstaller(e){return new LG(e)}isEnabled(e){return e.project.configuration.get("nodeLinker")==="pnpm"}},LG=class{constructor(e){this.opts=e;this.asyncActions=new je.AsyncActions(10);this.customData={pathsByLocator:new Map,locatorByPath:new Map};this.indexFolderPromise=PD(oe,{indexPath:K.join(e.project.configuration.get("globalFolder"),"index")})}attachCustomData(e){}async installPackage(e,r,o){switch(e.linkType){case"SOFT":return this.installPackageSoft(e,r,o);case"HARD":return this.installPackageHard(e,r,o)}throw new Error("Assertion failed: Unsupported package link type")}async installPackageSoft(e,r,o){let a=K.resolve(r.packageFs.getRealPath(),r.prefixPath),n=this.opts.project.tryWorkspaceByLocator(e)?K.join(a,dr.nodeModules):null;return this.customData.pathsByLocator.set(e.locatorHash,{packageLocation:a,dependenciesLocation:n}),{packageLocation:a,buildRequest:null}}async installPackageHard(e,r,o){let a=cDt(e,{project:this.opts.project}),n=a.packageLocation;this.customData.locatorByPath.set(n,W.stringifyLocator(e)),this.customData.pathsByLocator.set(e.locatorHash,a),o.holdFetchResult(this.asyncActions.set(e.locatorHash,async()=>{await oe.mkdirPromise(n,{recursive:!0}),await oe.copyPromise(n,r.prefixPath,{baseFs:r.packageFs,overwrite:!1,linkStrategy:{type:"HardlinkFromIndex",indexPath:await this.indexFolderPromise,autoRepair:!0}})}));let A=W.isVirtualLocator(e)?W.devirtualizeLocator(e):e,p={manifest:await Mt.tryFind(r.prefixPath,{baseFs:r.packageFs})??new Mt,misc:{hasBindingGyp:mA.hasBindingGyp(r)}},h=this.opts.project.getDependencyMeta(A,e.version),E=mA.extractBuildRequest(e,p,h,{configuration:this.opts.project.configuration});return{packageLocation:n,buildRequest:E}}async attachInternalDependencies(e,r){if(this.opts.project.configuration.get("nodeLinker")!=="pnpm"||!LBe(e,{project:this.opts.project}))return;let o=this.customData.pathsByLocator.get(e.locatorHash);if(typeof o>"u")throw new Error(`Assertion failed: Expected the package to have been registered (${W.stringifyLocator(e)})`);let{dependenciesLocation:a}=o;!a||this.asyncActions.reduce(e.locatorHash,async n=>{await oe.mkdirPromise(a,{recursive:!0});let u=await uDt(a),A=new Map(u),p=[n],h=(I,v)=>{let b=v;LBe(v,{project:this.opts.project})||(this.opts.report.reportWarningOnce(0,"The pnpm linker doesn't support providing different versions to workspaces' peer dependencies"),b=W.devirtualizeLocator(v));let C=this.customData.pathsByLocator.get(b.locatorHash);if(typeof C>"u")throw new Error(`Assertion failed: Expected the package to have been registered (${W.stringifyLocator(v)})`);let T=W.stringifyIdent(I),L=K.join(a,T),U=K.relative(K.dirname(L),C.packageLocation),J=A.get(T);A.delete(T),p.push(Promise.resolve().then(async()=>{if(J){if(J.isSymbolicLink()&&await oe.readlinkPromise(L)===U)return;await oe.removePromise(L)}await oe.mkdirpPromise(K.dirname(L)),process.platform=="win32"&&this.opts.project.configuration.get("winLinkType")==="junctions"?await oe.symlinkPromise(C.packageLocation,L,"junction"):await oe.symlinkPromise(U,L)}))},E=!1;for(let[I,v]of r)I.identHash===e.identHash&&(E=!0),h(I,v);!E&&!this.opts.project.tryWorkspaceByLocator(e)&&h(W.convertLocatorToDescriptor(e),e),p.push(ADt(a,A)),await Promise.all(p)})}async attachExternalDependents(e,r){throw new Error("External dependencies haven't been implemented for the pnpm linker")}async finalizeInstall(){let e=OBe(this.opts.project);if(this.opts.project.configuration.get("nodeLinker")!=="pnpm")await oe.removePromise(e);else{let r;try{r=new Set(await oe.readdirPromise(e))}catch{r=new Set}for(let{dependenciesLocation:o}of this.customData.pathsByLocator.values()){if(!o)continue;let a=K.contains(e,o);if(a===null)continue;let[n]=a.split(K.sep);r.delete(n)}await Promise.all([...r].map(async o=>{await oe.removePromise(K.join(e,o))}))}return await this.asyncActions.wait(),await MG(e),this.opts.project.configuration.get("nodeLinker")!=="node-modules"&&await MG(MBe(this.opts.project)),{customData:this.customData}}};function MBe(t){return K.join(t.cwd,dr.nodeModules)}function OBe(t){return K.join(MBe(t),".store")}function cDt(t,{project:e}){let r=W.slugifyLocator(t),o=OBe(e),a=K.join(o,r,"package"),n=K.join(o,r,dr.nodeModules);return{packageLocation:a,dependenciesLocation:n}}function LBe(t,{project:e}){return!W.isVirtualLocator(t)||!e.tryWorkspaceByLocator(t)}async function uDt(t){let e=new Map,r=[];try{r=await oe.readdirPromise(t,{withFileTypes:!0})}catch(o){if(o.code!=="ENOENT")throw o}try{for(let o of r)if(!o.name.startsWith("."))if(o.name.startsWith("@")){let a=await oe.readdirPromise(K.join(t,o.name),{withFileTypes:!0});if(a.length===0)e.set(o.name,o);else for(let n of a)e.set(`${o.name}/${n.name}`,n)}else e.set(o.name,o)}catch(o){if(o.code!=="ENOENT")throw o}return e}async function ADt(t,e){let r=[],o=new Set;for(let a of e.keys()){r.push(oe.removePromise(K.join(t,a)));let n=W.tryParseIdent(a)?.scope;n&&o.add(`@${n}`)}return Promise.all(r).then(()=>Promise.all([...o].map(a=>MG(K.join(t,a)))))}async function MG(t){try{await oe.rmdirPromise(t)}catch(e){if(e.code!=="ENOENT"&&e.code!=="ENOTEMPTY")throw e}}var fDt={linkers:[Hv]},pDt=fDt;var YG={};Kt(YG,{StageCommand:()=>Z0,default:()=>vDt,stageUtils:()=>lF});Ye();Pt();qt();Ye();Pt();var lF={};Kt(lF,{ActionType:()=>UG,checkConsensus:()=>aF,expandDirectory:()=>jG,findConsensus:()=>qG,findVcsRoot:()=>_G,genCommitMessage:()=>GG,getCommitPrefix:()=>UBe,isYarnFile:()=>HG});Pt();var UG=(n=>(n[n.CREATE=0]="CREATE",n[n.DELETE=1]="DELETE",n[n.ADD=2]="ADD",n[n.REMOVE=3]="REMOVE",n[n.MODIFY=4]="MODIFY",n))(UG||{});async function _G(t,{marker:e}){do if(!oe.existsSync(K.join(t,e)))t=K.dirname(t);else return t;while(t!=="/");return null}function HG(t,{roots:e,names:r}){if(r.has(K.basename(t)))return!0;do if(!e.has(t))t=K.dirname(t);else return!0;while(t!=="/");return!1}function jG(t){let e=[],r=[t];for(;r.length>0;){let o=r.pop(),a=oe.readdirSync(o);for(let n of a){let u=K.resolve(o,n);oe.lstatSync(u).isDirectory()?r.push(u):e.push(u)}}return e}function aF(t,e){let r=0,o=0;for(let a of t)a!=="wip"&&(e.test(a)?r+=1:o+=1);return r>=o}function qG(t){let e=aF(t,/^(\w\(\w+\):\s*)?\w+s/),r=aF(t,/^(\w\(\w+\):\s*)?[A-Z]/),o=aF(t,/^\w\(\w+\):/);return{useThirdPerson:e,useUpperCase:r,useComponent:o}}function UBe(t){return t.useComponent?"chore(yarn): ":""}var hDt=new Map([[0,"create"],[1,"delete"],[2,"add"],[3,"remove"],[4,"update"]]);function GG(t,e){let r=UBe(t),o=[],a=e.slice().sort((n,u)=>n[0]-u[0]);for(;a.length>0;){let[n,u]=a.shift(),A=hDt.get(n);t.useUpperCase&&o.length===0&&(A=`${A[0].toUpperCase()}${A.slice(1)}`),t.useThirdPerson&&(A+="s");let p=[u];for(;a.length>0&&a[0][0]===n;){let[,E]=a.shift();p.push(E)}p.sort();let h=p.shift();p.length===1?h+=" (and one other)":p.length>1&&(h+=` (and ${p.length} others)`),o.push(`${A} ${h}`)}return`${r}${o.join(", ")}`}var gDt="Commit generated via `yarn stage`",dDt=11;async function _Be(t){let{code:e,stdout:r}=await Ur.execvp("git",["log","-1","--pretty=format:%H"],{cwd:t});return e===0?r.trim():null}async function mDt(t,e){let r=[],o=e.filter(h=>K.basename(h.path)==="package.json");for(let{action:h,path:E}of o){let I=K.relative(t,E);if(h===4){let v=await _Be(t),{stdout:b}=await Ur.execvp("git",["show",`${v}:${I}`],{cwd:t,strict:!0}),C=await Mt.fromText(b),T=await Mt.fromFile(E),L=new Map([...T.dependencies,...T.devDependencies]),U=new Map([...C.dependencies,...C.devDependencies]);for(let[J,te]of U){let le=W.stringifyIdent(te),pe=L.get(J);pe?pe.range!==te.range&&r.push([4,`${le} to ${pe.range}`]):r.push([3,le])}for(let[J,te]of L)U.has(J)||r.push([2,W.stringifyIdent(te)])}else if(h===0){let v=await Mt.fromFile(E);v.name?r.push([0,W.stringifyIdent(v.name)]):r.push([0,"a package"])}else if(h===1){let v=await _Be(t),{stdout:b}=await Ur.execvp("git",["show",`${v}:${I}`],{cwd:t,strict:!0}),C=await Mt.fromText(b);C.name?r.push([1,W.stringifyIdent(C.name)]):r.push([1,"a package"])}else throw new Error("Assertion failed: Unsupported action type")}let{code:a,stdout:n}=await Ur.execvp("git",["log",`-${dDt}`,"--pretty=format:%s"],{cwd:t}),u=a===0?n.split(/\n/g).filter(h=>h!==""):[],A=qG(u);return GG(A,r)}var yDt={[0]:[" A ","?? "],[4]:[" M "],[1]:[" D "]},EDt={[0]:["A "],[4]:["M "],[1]:["D "]},HBe={async findRoot(t){return await _G(t,{marker:".git"})},async filterChanges(t,e,r,o){let{stdout:a}=await Ur.execvp("git",["status","-s"],{cwd:t,strict:!0}),n=a.toString().split(/\n/g),u=o?.staged?EDt:yDt;return[].concat(...n.map(p=>{if(p==="")return[];let h=p.slice(0,3),E=K.resolve(t,p.slice(3));if(!o?.staged&&h==="?? "&&p.endsWith("/"))return jG(E).map(I=>({action:0,path:I}));{let v=[0,4,1].find(b=>u[b].includes(h));return v!==void 0?[{action:v,path:E}]:[]}})).filter(p=>HG(p.path,{roots:e,names:r}))},async genCommitMessage(t,e){return await mDt(t,e)},async makeStage(t,e){let r=e.map(o=>ue.fromPortablePath(o.path));await Ur.execvp("git",["add","--",...r],{cwd:t,strict:!0})},async makeCommit(t,e,r){let o=e.map(a=>ue.fromPortablePath(a.path));await Ur.execvp("git",["add","-N","--",...o],{cwd:t,strict:!0}),await Ur.execvp("git",["commit","-m",`${r} - -${gDt} -`,"--",...o],{cwd:t,strict:!0})},async makeReset(t,e){let r=e.map(o=>ue.fromPortablePath(o.path));await Ur.execvp("git",["reset","HEAD","--",...r],{cwd:t,strict:!0})}};var CDt=[HBe],Z0=class extends ut{constructor(){super(...arguments);this.commit=ge.Boolean("-c,--commit",!1,{description:"Commit the staged files"});this.reset=ge.Boolean("-r,--reset",!1,{description:"Remove all files from the staging area"});this.dryRun=ge.Boolean("-n,--dry-run",!1,{description:"Print the commit message and the list of modified files without staging / committing"});this.update=ge.Boolean("-u,--update",!1,{hidden:!0})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd),{driver:a,root:n}=await wDt(o.cwd),u=[r.get("cacheFolder"),r.get("globalFolder"),r.get("virtualFolder"),r.get("yarnPath")];await r.triggerHook(I=>I.populateYarnPaths,o,I=>{u.push(I)});let A=new Set;for(let I of u)for(let v of IDt(n,I))A.add(v);let p=new Set([r.get("rcFilename"),dr.lockfile,dr.manifest]),h=await a.filterChanges(n,A,p),E=await a.genCommitMessage(n,h);if(this.dryRun)if(this.commit)this.context.stdout.write(`${E} -`);else for(let I of h)this.context.stdout.write(`${ue.fromPortablePath(I.path)} -`);else if(this.reset){let I=await a.filterChanges(n,A,p,{staged:!0});I.length===0?this.context.stdout.write("No staged changes found!"):await a.makeReset(n,I)}else h.length===0?this.context.stdout.write("No changes found!"):this.commit?await a.makeCommit(n,h,E):(await a.makeStage(n,h),this.context.stdout.write(E))}};Z0.paths=[["stage"]],Z0.usage=nt.Usage({description:"add all yarn files to your vcs",details:"\n This command will add to your staging area the files belonging to Yarn (typically any modified `package.json` and `.yarnrc.yml` files, but also linker-generated files, cache data, etc). It will take your ignore list into account, so the cache files won't be added if the cache is ignored in a `.gitignore` file (assuming you use Git).\n\n Running `--reset` will instead remove them from the staging area (the changes will still be there, but won't be committed until you stage them back).\n\n Since the staging area is a non-existent concept in Mercurial, Yarn will always create a new commit when running this command on Mercurial repositories. You can get this behavior when using Git by using the `--commit` flag which will directly create a commit.\n ",examples:[["Adds all modified project files to the staging area","yarn stage"],["Creates a new commit containing all modified project files","yarn stage --commit"]]});async function wDt(t){let e=null,r=null;for(let o of CDt)if((r=await o.findRoot(t))!==null){e=o;break}if(e===null||r===null)throw new it("No stage driver has been found for your current project");return{driver:e,root:r}}function IDt(t,e){let r=[];if(e===null)return r;for(;;){(e===t||e.startsWith(`${t}/`))&&r.push(e);let o;try{o=oe.statSync(e)}catch{break}if(o.isSymbolicLink())e=K.resolve(K.dirname(e),oe.readlinkSync(e));else break}return r}var BDt={commands:[Z0]},vDt=BDt;var WG={};Kt(WG,{default:()=>FDt});Ye();Ye();Pt();var GBe=$e(zn());Ye();var jBe=$e(ZH()),DDt="e8e1bd300d860104bb8c58453ffa1eb4",PDt="OFCNCOG2CU",qBe=async(t,e)=>{let r=W.stringifyIdent(t),a=SDt(e).initIndex("npm-search");try{return(await a.getObject(r,{attributesToRetrieve:["types"]})).types?.ts==="definitely-typed"}catch{return!1}},SDt=t=>(0,jBe.default)(PDt,DDt,{requester:{async send(r){try{let o=await rn.request(r.url,r.data||null,{configuration:t,headers:r.headers});return{content:o.body,isTimedOut:!1,status:o.statusCode}}catch(o){return{content:o.response.body,isTimedOut:!1,status:o.response.statusCode}}}}});var YBe=t=>t.scope?`${t.scope}__${t.name}`:`${t.name}`,xDt=async(t,e,r,o)=>{if(r.scope==="types")return;let{project:a}=t,{configuration:n}=a;if(!(n.get("tsEnableAutoTypes")??oe.existsSync(K.join(a.cwd,"tsconfig.json"))))return;let A=n.makeResolver(),p={project:a,resolver:A,report:new Qi};if(!await qBe(r,n))return;let E=YBe(r),I=W.parseRange(r.range).selector;if(!kr.validRange(I)){let L=n.normalizeDependency(r),U=await A.getCandidates(L,{},p);I=W.parseRange(U[0].reference).selector}let v=GBe.default.coerce(I);if(v===null)return;let b=`${zc.Modifier.CARET}${v.major}`,C=W.makeDescriptor(W.makeIdent("types",E),b),T=je.mapAndFind(a.workspaces,L=>{let U=L.manifest.dependencies.get(r.identHash)?.descriptorHash,J=L.manifest.devDependencies.get(r.identHash)?.descriptorHash;if(U!==r.descriptorHash&&J!==r.descriptorHash)return je.mapAndFind.skip;let te=[];for(let le of Mt.allDependencies){let pe=L.manifest[le].get(C.identHash);typeof pe>"u"||te.push([le,pe])}return te.length===0?je.mapAndFind.skip:te});if(typeof T<"u")for(let[L,U]of T)t.manifest[L].set(U.identHash,U);else{try{let L=n.normalizeDependency(C);if((await A.getCandidates(L,{},p)).length===0)return}catch{return}t.manifest[zc.Target.DEVELOPMENT].set(C.identHash,C)}},bDt=async(t,e,r)=>{if(r.scope==="types")return;let{project:o}=t,{configuration:a}=o;if(!(a.get("tsEnableAutoTypes")??oe.existsSync(K.join(o.cwd,"tsconfig.json"))))return;let u=YBe(r),A=W.makeIdent("types",u);for(let p of Mt.allDependencies)typeof t.manifest[p].get(A.identHash)>"u"||t.manifest[p].delete(A.identHash)},kDt=(t,e)=>{e.publishConfig&&e.publishConfig.typings&&(e.typings=e.publishConfig.typings),e.publishConfig&&e.publishConfig.types&&(e.types=e.publishConfig.types)},QDt={configuration:{tsEnableAutoTypes:{description:"Whether Yarn should auto-install @types/ dependencies on 'yarn add'",type:"BOOLEAN",isNullable:!0,default:null}},hooks:{afterWorkspaceDependencyAddition:xDt,afterWorkspaceDependencyRemoval:bDt,beforeWorkspacePacking:kDt}},FDt=QDt;var XG={};Kt(XG,{VersionApplyCommand:()=>$0,VersionCheckCommand:()=>eg,VersionCommand:()=>tg,default:()=>XDt,versionUtils:()=>gw});Ye();Ye();qt();var gw={};Kt(gw,{Decision:()=>pw,applyPrerelease:()=>XBe,applyReleases:()=>zG,applyStrategy:()=>uF,clearVersionFiles:()=>VG,getUndecidedDependentWorkspaces:()=>qv,getUndecidedWorkspaces:()=>cF,openVersionFile:()=>hw,requireMoreDecisions:()=>KDt,resolveVersionFiles:()=>jv,suggestStrategy:()=>JG,updateVersionFiles:()=>KG,validateReleaseDecision:()=>fw});Ye();Pt();Nl();qt();var zBe=$e(JBe()),BA=$e(zn()),VDt=/^(>=|[~^]|)(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\+[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*)?$/,pw=(u=>(u.UNDECIDED="undecided",u.DECLINE="decline",u.MAJOR="major",u.MINOR="minor",u.PATCH="patch",u.PRERELEASE="prerelease",u))(pw||{});function fw(t){let e=BA.default.valid(t);return e||je.validateEnum((0,zBe.default)(pw,"UNDECIDED"),t)}async function jv(t,{prerelease:e=null}={}){let r=new Map,o=t.configuration.get("deferredVersionFolder");if(!oe.existsSync(o))return r;let a=await oe.readdirPromise(o);for(let n of a){if(!n.endsWith(".yml"))continue;let u=K.join(o,n),A=await oe.readFilePromise(u,"utf8"),p=Vi(A);for(let[h,E]of Object.entries(p.releases||{})){if(E==="decline")continue;let I=W.parseIdent(h),v=t.tryWorkspaceByIdent(I);if(v===null)throw new Error(`Assertion failed: Expected a release definition file to only reference existing workspaces (${K.basename(u)} references ${h})`);if(v.manifest.version===null)throw new Error(`Assertion failed: Expected the workspace to have a version (${W.prettyLocator(t.configuration,v.anchoredLocator)})`);let b=v.manifest.raw.stableVersion??v.manifest.version,C=r.get(v),T=uF(b,fw(E));if(T===null)throw new Error(`Assertion failed: Expected ${b} to support being bumped via strategy ${E}`);let L=typeof C<"u"?BA.default.gt(T,C)?T:C:T;r.set(v,L)}}return e&&(r=new Map([...r].map(([n,u])=>[n,XBe(u,{current:n.manifest.version,prerelease:e})]))),r}async function VG(t){let e=t.configuration.get("deferredVersionFolder");!oe.existsSync(e)||await oe.removePromise(e)}async function KG(t,e){let r=new Set(e),o=t.configuration.get("deferredVersionFolder");if(!oe.existsSync(o))return;let a=await oe.readdirPromise(o);for(let n of a){if(!n.endsWith(".yml"))continue;let u=K.join(o,n),A=await oe.readFilePromise(u,"utf8"),p=Vi(A),h=p?.releases;if(!!h){for(let E of Object.keys(h)){let I=W.parseIdent(E),v=t.tryWorkspaceByIdent(I);(v===null||r.has(v))&&delete p.releases[E]}Object.keys(p.releases).length>0?await oe.changeFilePromise(u,Ba(new Ba.PreserveOrdering(p))):await oe.unlinkPromise(u)}}}async function hw(t,{allowEmpty:e=!1}={}){let r=t.configuration;if(r.projectCwd===null)throw new it("This command can only be run from within a Yarn project");let o=await ra.fetchRoot(r.projectCwd),a=o!==null?await ra.fetchBase(o,{baseRefs:r.get("changesetBaseRefs")}):null,n=o!==null?await ra.fetchChangedFiles(o,{base:a.hash,project:t}):[],u=r.get("deferredVersionFolder"),A=n.filter(b=>K.contains(u,b)!==null);if(A.length>1)throw new it(`Your current branch contains multiple versioning files; this isn't supported: -- ${A.map(b=>ue.fromPortablePath(b)).join(` -- `)}`);let p=new Set(je.mapAndFilter(n,b=>{let C=t.tryWorkspaceByFilePath(b);return C===null?je.mapAndFilter.skip:C}));if(A.length===0&&p.size===0&&!e)return null;let h=A.length===1?A[0]:K.join(u,`${wn.makeHash(Math.random().toString()).slice(0,8)}.yml`),E=oe.existsSync(h)?await oe.readFilePromise(h,"utf8"):"{}",I=Vi(E),v=new Map;for(let b of I.declined||[]){let C=W.parseIdent(b),T=t.getWorkspaceByIdent(C);v.set(T,"decline")}for(let[b,C]of Object.entries(I.releases||{})){let T=W.parseIdent(b),L=t.getWorkspaceByIdent(T);v.set(L,fw(C))}return{project:t,root:o,baseHash:a!==null?a.hash:null,baseTitle:a!==null?a.title:null,changedFiles:new Set(n),changedWorkspaces:p,releaseRoots:new Set([...p].filter(b=>b.manifest.version!==null)),releases:v,async saveAll(){let b={},C=[],T=[];for(let L of t.workspaces){if(L.manifest.version===null)continue;let U=W.stringifyIdent(L.anchoredLocator),J=v.get(L);J==="decline"?C.push(U):typeof J<"u"?b[U]=fw(J):p.has(L)&&T.push(U)}await oe.mkdirPromise(K.dirname(h),{recursive:!0}),await oe.changeFilePromise(h,Ba(new Ba.PreserveOrdering({releases:Object.keys(b).length>0?b:void 0,declined:C.length>0?C:void 0,undecided:T.length>0?T:void 0})))}}}function KDt(t){return cF(t).size>0||qv(t).length>0}function cF(t){let e=new Set;for(let r of t.changedWorkspaces)r.manifest.version!==null&&(t.releases.has(r)||e.add(r));return e}function qv(t,{include:e=new Set}={}){let r=[],o=new Map(je.mapAndFilter([...t.releases],([n,u])=>u==="decline"?je.mapAndFilter.skip:[n.anchoredLocator.locatorHash,n])),a=new Map(je.mapAndFilter([...t.releases],([n,u])=>u!=="decline"?je.mapAndFilter.skip:[n.anchoredLocator.locatorHash,n]));for(let n of t.project.workspaces)if(!(!e.has(n)&&(a.has(n.anchoredLocator.locatorHash)||o.has(n.anchoredLocator.locatorHash)))&&n.manifest.version!==null)for(let u of Mt.hardDependencies)for(let A of n.manifest.getForScope(u).values()){let p=t.project.tryWorkspaceByDescriptor(A);p!==null&&o.has(p.anchoredLocator.locatorHash)&&r.push([n,p])}return r}function JG(t,e){let r=BA.default.clean(e);for(let o of Object.values(pw))if(o!=="undecided"&&o!=="decline"&&BA.default.inc(t,o)===r)return o;return null}function uF(t,e){if(BA.default.valid(e))return e;if(t===null)throw new it(`Cannot apply the release strategy "${e}" unless the workspace already has a valid version`);if(!BA.default.valid(t))throw new it(`Cannot apply the release strategy "${e}" on a non-semver version (${t})`);let r=BA.default.inc(t,e);if(r===null)throw new it(`Cannot apply the release strategy "${e}" on the specified version (${t})`);return r}function zG(t,e,{report:r}){let o=new Map;for(let a of t.workspaces)for(let n of Mt.allDependencies)for(let u of a.manifest[n].values()){let A=t.tryWorkspaceByDescriptor(u);if(A===null||!e.has(A))continue;je.getArrayWithDefault(o,A).push([a,n,u.identHash])}for(let[a,n]of e){let u=a.manifest.version;a.manifest.version=n,BA.default.prerelease(n)===null?delete a.manifest.raw.stableVersion:a.manifest.raw.stableVersion||(a.manifest.raw.stableVersion=u);let A=a.manifest.name!==null?W.stringifyIdent(a.manifest.name):null;r.reportInfo(0,`${W.prettyLocator(t.configuration,a.anchoredLocator)}: Bumped to ${n}`),r.reportJson({cwd:ue.fromPortablePath(a.cwd),ident:A,oldVersion:u,newVersion:n});let p=o.get(a);if(!(typeof p>"u"))for(let[h,E,I]of p){let v=h.manifest[E].get(I);if(typeof v>"u")throw new Error("Assertion failed: The dependency should have existed");let b=v.range,C=!1;if(b.startsWith(Xn.protocol)&&(b=b.slice(Xn.protocol.length),C=!0,b===a.relativeCwd))continue;let T=b.match(VDt);if(!T){r.reportWarning(0,`Couldn't auto-upgrade range ${b} (in ${W.prettyLocator(t.configuration,h.anchoredLocator)})`);continue}let L=`${T[1]}${n}`;C&&(L=`${Xn.protocol}${L}`);let U=W.makeDescriptor(v,L);h.manifest[E].set(I,U)}}}var JDt=new Map([["%n",{extract:t=>t.length>=1?[t[0],t.slice(1)]:null,generate:(t=0)=>`${t+1}`}]]);function XBe(t,{current:e,prerelease:r}){let o=new BA.default.SemVer(e),a=o.prerelease.slice(),n=[];o.prerelease=[],o.format()!==t&&(a.length=0);let u=!0,A=r.split(/\./g);for(let p of A){let h=JDt.get(p);if(typeof h>"u")n.push(p),a[0]===p?a.shift():u=!1;else{let E=u?h.extract(a):null;E!==null&&typeof E[0]=="number"?(n.push(h.generate(E[0])),a=E[1]):(n.push(h.generate()),u=!1)}}return o.prerelease&&(o.prerelease=[]),`${t}-${n.join(".")}`}var $0=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean("--all",!1,{description:"Apply the deferred version changes on all workspaces"});this.dryRun=ge.Boolean("--dry-run",!1,{description:"Print the versions without actually generating the package archive"});this.prerelease=ge.String("--prerelease",{description:"Add a prerelease identifier to new versions",tolerateBoolean:!0});this.recursive=ge.Boolean("-R,--recursive",{description:"Release the transitive workspaces as well"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout},async A=>{let p=this.prerelease?typeof this.prerelease!="boolean"?this.prerelease:"rc.%n":null,h=await jv(o,{prerelease:p}),E=new Map;if(this.all)E=h;else{let I=this.recursive?a.getRecursiveWorkspaceDependencies():[a];for(let v of I){let b=h.get(v);typeof b<"u"&&E.set(v,b)}}if(E.size===0){let I=h.size>0?" Did you want to add --all?":"";A.reportWarning(0,`The current workspace doesn't seem to require a version bump.${I}`);return}zG(o,E,{report:A}),this.dryRun||(p||(this.all?await VG(o):await KG(o,[...E.keys()])),A.reportSeparator())});return u.hasErrors()?u.exitCode():await o.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n})}};$0.paths=[["version","apply"]],$0.usage=nt.Usage({category:"Release-related commands",description:"apply all the deferred version bumps at once",details:` - This command will apply the deferred version changes and remove their definitions from the repository. - - Note that if \`--prerelease\` is set, the given prerelease identifier (by default \`rc.%d\`) will be used on all new versions and the version definitions will be kept as-is. - - By default only the current workspace will be bumped, but you can configure this behavior by using one of: - - - \`--recursive\` to also apply the version bump on its dependencies - - \`--all\` to apply the version bump on all packages in the repository - - Note that this command will also update the \`workspace:\` references across all your local workspaces, thus ensuring that they keep referring to the same workspaces even after the version bump. - `,examples:[["Apply the version change to the local workspace","yarn version apply"],["Apply the version change to all the workspaces in the local workspace","yarn version apply --all"]]});Ye();Pt();qt();var AF=$e(zn());var eg=class extends ut{constructor(){super(...arguments);this.interactive=ge.Boolean("-i,--interactive",{description:"Open an interactive interface used to set version bumps"})}async execute(){return this.interactive?await this.executeInteractive():await this.executeStandard()}async executeInteractive(){SC(this.context);let{Gem:r}=await Promise.resolve().then(()=>(AQ(),Dj)),{ScrollableItems:o}=await Promise.resolve().then(()=>(gQ(),hQ)),{FocusRequest:a}=await Promise.resolve().then(()=>(Sj(),Xwe)),{useListInput:n}=await Promise.resolve().then(()=>(pQ(),Zwe)),{renderForm:u}=await Promise.resolve().then(()=>(EQ(),yQ)),{Box:A,Text:p}=await Promise.resolve().then(()=>$e(ic())),{default:h,useCallback:E,useState:I}=await Promise.resolve().then(()=>$e(sn())),v=await Ve.find(this.context.cwd,this.context.plugins),{project:b,workspace:C}=await St.find(v,this.context.cwd);if(!C)throw new rr(b.cwd,this.context.cwd);await b.restoreInstallState();let T=await hw(b);if(T===null||T.releaseRoots.size===0)return 0;if(T.root===null)throw new it("This command can only be run on Git repositories");let L=()=>h.createElement(A,{flexDirection:"row",paddingBottom:1},h.createElement(A,{flexDirection:"column",width:60},h.createElement(A,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},""),"/",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to select workspaces.")),h.createElement(A,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},""),"/",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to select release strategies."))),h.createElement(A,{flexDirection:"column"},h.createElement(A,{marginLeft:1},h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to save.")),h.createElement(A,{marginLeft:1},h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to abort.")))),U=({workspace:ye,active:ae,decision:we,setDecision:Pe})=>{let g=ye.manifest.raw.stableVersion??ye.manifest.version;if(g===null)throw new Error(`Assertion failed: The version should have been set (${W.prettyLocator(v,ye.anchoredLocator)})`);if(AF.default.prerelease(g)!==null)throw new Error(`Assertion failed: Prerelease identifiers shouldn't be found (${g})`);let Ee=["undecided","decline","patch","minor","major"];n(we,Ee,{active:ae,minus:"left",plus:"right",set:Pe});let De=we==="undecided"?h.createElement(p,{color:"yellow"},g):we==="decline"?h.createElement(p,{color:"green"},g):h.createElement(p,null,h.createElement(p,{color:"magenta"},g)," \u2192 ",h.createElement(p,{color:"green"},AF.default.valid(we)?we:AF.default.inc(g,we)));return h.createElement(A,{flexDirection:"column"},h.createElement(A,null,h.createElement(p,null,W.prettyLocator(v,ye.anchoredLocator)," - ",De)),h.createElement(A,null,Ee.map(ce=>h.createElement(A,{key:ce,paddingLeft:2},h.createElement(p,null,h.createElement(r,{active:ce===we})," ",ce)))))},J=ye=>{let ae=new Set(T.releaseRoots),we=new Map([...ye].filter(([Pe])=>ae.has(Pe)));for(;;){let Pe=qv({project:T.project,releases:we}),g=!1;if(Pe.length>0){for(let[Ee]of Pe)if(!ae.has(Ee)){ae.add(Ee),g=!0;let De=ye.get(Ee);typeof De<"u"&&we.set(Ee,De)}}if(!g)break}return{relevantWorkspaces:ae,relevantReleases:we}},te=()=>{let[ye,ae]=I(()=>new Map(T.releases)),we=E((Pe,g)=>{let Ee=new Map(ye);g!=="undecided"?Ee.set(Pe,g):Ee.delete(Pe);let{relevantReleases:De}=J(Ee);ae(De)},[ye,ae]);return[ye,we]},le=({workspaces:ye,releases:ae})=>{let we=[];we.push(`${ye.size} total`);let Pe=0,g=0;for(let Ee of ye){let De=ae.get(Ee);typeof De>"u"?g+=1:De!=="decline"&&(Pe+=1)}return we.push(`${Pe} release${Pe===1?"":"s"}`),we.push(`${g} remaining`),h.createElement(p,{color:"yellow"},we.join(", "))},Ae=await u(({useSubmit:ye})=>{let[ae,we]=te();ye(ae);let{relevantWorkspaces:Pe}=J(ae),g=new Set([...Pe].filter(ne=>!T.releaseRoots.has(ne))),[Ee,De]=I(0),ce=E(ne=>{switch(ne){case a.BEFORE:De(Ee-1);break;case a.AFTER:De(Ee+1);break}},[Ee,De]);return h.createElement(A,{flexDirection:"column"},h.createElement(L,null),h.createElement(A,null,h.createElement(p,{wrap:"wrap"},"The following files have been modified in your local checkout.")),h.createElement(A,{flexDirection:"column",marginTop:1,paddingLeft:2},[...T.changedFiles].map(ne=>h.createElement(A,{key:ne},h.createElement(p,null,h.createElement(p,{color:"grey"},ue.fromPortablePath(T.root)),ue.sep,ue.relative(ue.fromPortablePath(T.root),ue.fromPortablePath(ne)))))),T.releaseRoots.size>0&&h.createElement(h.Fragment,null,h.createElement(A,{marginTop:1},h.createElement(p,{wrap:"wrap"},"Because of those files having been modified, the following workspaces may need to be released again (note that private workspaces are also shown here, because even though they won't be published, releasing them will allow us to flag their dependents for potential re-release):")),g.size>3?h.createElement(A,{marginTop:1},h.createElement(le,{workspaces:T.releaseRoots,releases:ae})):null,h.createElement(A,{marginTop:1,flexDirection:"column"},h.createElement(o,{active:Ee%2===0,radius:1,size:2,onFocusRequest:ce},[...T.releaseRoots].map(ne=>h.createElement(U,{key:ne.cwd,workspace:ne,decision:ae.get(ne)||"undecided",setDecision:ee=>we(ne,ee)}))))),g.size>0?h.createElement(h.Fragment,null,h.createElement(A,{marginTop:1},h.createElement(p,{wrap:"wrap"},"The following workspaces depend on other workspaces that have been marked for release, and thus may need to be released as well:")),h.createElement(A,null,h.createElement(p,null,"(Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"")," to move the focus between the workspace groups.)")),g.size>5?h.createElement(A,{marginTop:1},h.createElement(le,{workspaces:g,releases:ae})):null,h.createElement(A,{marginTop:1,flexDirection:"column"},h.createElement(o,{active:Ee%2===1,radius:2,size:2,onFocusRequest:ce},[...g].map(ne=>h.createElement(U,{key:ne.cwd,workspace:ne,decision:ae.get(ne)||"undecided",setDecision:ee=>we(ne,ee)}))))):null)},{versionFile:T},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof Ae>"u")return 1;T.releases.clear();for(let[ye,ae]of Ae)T.releases.set(ye,ae);await T.saveAll()}async executeStandard(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);return await o.restoreInstallState(),(await Nt.start({configuration:r,stdout:this.context.stdout},async u=>{let A=await hw(o);if(A===null||A.releaseRoots.size===0)return;if(A.root===null)throw new it("This command can only be run on Git repositories");if(u.reportInfo(0,`Your PR was started right after ${de.pretty(r,A.baseHash.slice(0,7),"yellow")} ${de.pretty(r,A.baseTitle,"magenta")}`),A.changedFiles.size>0){u.reportInfo(0,"You have changed the following files since then:"),u.reportSeparator();for(let v of A.changedFiles)u.reportInfo(null,`${de.pretty(r,ue.fromPortablePath(A.root),"gray")}${ue.sep}${ue.relative(ue.fromPortablePath(A.root),ue.fromPortablePath(v))}`)}let p=!1,h=!1,E=cF(A);if(E.size>0){p||u.reportSeparator();for(let v of E)u.reportError(0,`${W.prettyLocator(r,v.anchoredLocator)} has been modified but doesn't have a release strategy attached`);p=!0}let I=qv(A);for(let[v,b]of I)h||u.reportSeparator(),u.reportError(0,`${W.prettyLocator(r,v.anchoredLocator)} doesn't have a release strategy attached, but depends on ${W.prettyWorkspace(r,b)} which is planned for release.`),h=!0;(p||h)&&(u.reportSeparator(),u.reportInfo(0,"This command detected that at least some workspaces have received modifications without explicit instructions as to how they had to be released (if needed)."),u.reportInfo(0,"To correct these errors, run `yarn version check --interactive` then follow the instructions."))})).exitCode()}};eg.paths=[["version","check"]],eg.usage=nt.Usage({category:"Release-related commands",description:"check that all the relevant packages have been bumped",details:"\n **Warning:** This command currently requires Git.\n\n This command will check that all the packages covered by the files listed in argument have been properly bumped or declined to bump.\n\n In the case of a bump, the check will also cover transitive packages - meaning that should `Foo` be bumped, a package `Bar` depending on `Foo` will require a decision as to whether `Bar` will need to be bumped. This check doesn't cross packages that have declined to bump.\n\n In case no arguments are passed to the function, the list of modified files will be generated by comparing the HEAD against `master`.\n ",examples:[["Check whether the modified packages need a bump","yarn version check"]]});Ye();qt();var fF=$e(zn());var tg=class extends ut{constructor(){super(...arguments);this.deferred=ge.Boolean("-d,--deferred",{description:"Prepare the version to be bumped during the next release cycle"});this.immediate=ge.Boolean("-i,--immediate",{description:"Bump the version immediately"});this.strategy=ge.String()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);let n=r.get("preferDeferredVersions");this.deferred&&(n=!0),this.immediate&&(n=!1);let u=fF.default.valid(this.strategy),A=this.strategy==="decline",p;if(u)if(a.manifest.version!==null){let E=JG(a.manifest.version,this.strategy);E!==null?p=E:p=this.strategy}else p=this.strategy;else{let E=a.manifest.version;if(!A){if(E===null)throw new it("Can't bump the version if there wasn't a version to begin with - use 0.0.0 as initial version then run the command again.");if(typeof E!="string"||!fF.default.valid(E))throw new it(`Can't bump the version (${E}) if it's not valid semver`)}p=fw(this.strategy)}if(!n){let I=(await jv(o)).get(a);if(typeof I<"u"&&p!=="decline"){let v=uF(a.manifest.version,p);if(fF.default.lt(v,I))throw new it(`Can't bump the version to one that would be lower than the current deferred one (${I})`)}}let h=await hw(o,{allowEmpty:!0});return h.releases.set(a,p),await h.saveAll(),n?0:await this.cli.run(["version","apply"])}};tg.paths=[["version"]],tg.usage=nt.Usage({category:"Release-related commands",description:"apply a new version to the current package",details:"\n This command will bump the version number for the given package, following the specified strategy:\n\n - If `major`, the first number from the semver range will be increased (`X.0.0`).\n - If `minor`, the second number from the semver range will be increased (`0.X.0`).\n - If `patch`, the third number from the semver range will be increased (`0.0.X`).\n - If prefixed by `pre` (`premajor`, ...), a `-0` suffix will be set (`0.0.0-0`).\n - If `prerelease`, the suffix will be increased (`0.0.0-X`); the third number from the semver range will also be increased if there was no suffix in the previous version.\n - If `decline`, the nonce will be increased for `yarn version check` to pass without version bump.\n - If a valid semver range, it will be used as new version.\n - If unspecified, Yarn will ask you for guidance.\n\n For more information about the `--deferred` flag, consult our documentation (https://yarnpkg.com/features/release-workflow#deferred-versioning).\n ",examples:[["Immediately bump the version to the next major","yarn version major"],["Prepare the version to be bumped to the next major","yarn version major --deferred"]]});var zDt={configuration:{deferredVersionFolder:{description:"Folder where are stored the versioning files",type:"ABSOLUTE_PATH",default:"./.yarn/versions"},preferDeferredVersions:{description:"If true, running `yarn version` will assume the `--deferred` flag unless `--immediate` is set",type:"BOOLEAN",default:!1}},commands:[$0,eg,tg]},XDt=zDt;var ZG={};Kt(ZG,{WorkspacesFocusCommand:()=>rg,WorkspacesForeachCommand:()=>op,default:()=>ePt});Ye();Ye();qt();var rg=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.production=ge.Boolean("--production",!1,{description:"Only install regular dependencies by omitting dev dependencies"});this.all=ge.Boolean("-A,--all",!1,{description:"Install the entire project"});this.workspaces=ge.Rest()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);await o.restoreInstallState({restoreResolutions:!1});let u;if(this.all)u=new Set(o.workspaces);else if(this.workspaces.length===0){if(!a)throw new rr(o.cwd,this.context.cwd);u=new Set([a])}else u=new Set(this.workspaces.map(A=>o.getWorkspaceByIdent(W.parseIdent(A))));for(let A of u)for(let p of this.production?["dependencies"]:Mt.hardDependencies)for(let h of A.manifest.getForScope(p).values()){let E=o.tryWorkspaceByDescriptor(h);E!==null&&u.add(E)}for(let A of o.workspaces)u.has(A)?this.production&&A.manifest.devDependencies.clear():(A.manifest.installConfig=A.manifest.installConfig||{},A.manifest.installConfig.selfReferences=!1,A.manifest.dependencies.clear(),A.manifest.devDependencies.clear(),A.manifest.peerDependencies.clear(),A.manifest.scripts.clear());return await o.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n,persistProject:!1})}};rg.paths=[["workspaces","focus"]],rg.usage=nt.Usage({category:"Workspace-related commands",description:"install a single workspace and its dependencies",details:"\n This command will run an install as if the specified workspaces (and all other workspaces they depend on) were the only ones in the project. If no workspaces are explicitly listed, the active one will be assumed.\n\n Note that this command is only very moderately useful when using zero-installs, since the cache will contain all the packages anyway - meaning that the only difference between a full install and a focused install would just be a few extra lines in the `.pnp.cjs` file, at the cost of introducing an extra complexity.\n\n If the `-A,--all` flag is set, the entire project will be installed. Combine with `--production` to replicate the old `yarn install --production`.\n "});Ye();Ye();Ye();qt();var dw=$e(Zo()),$Be=$e(nd());Za();var op=class extends ut{constructor(){super(...arguments);this.from=ge.Array("--from",{description:"An array of glob pattern idents or paths from which to base any recursion"});this.all=ge.Boolean("-A,--all",{description:"Run the command on all workspaces of a project"});this.recursive=ge.Boolean("-R,--recursive",{description:"Run the command on the current workspace and all of its recursive dependencies"});this.worktree=ge.Boolean("-W,--worktree",{description:"Run the command on all workspaces of the current worktree"});this.verbose=ge.Boolean("-v,--verbose",{description:"Prefix each output line with the name of the originating workspace"});this.parallel=ge.Boolean("-p,--parallel",!1,{description:"Run the commands in parallel"});this.interlaced=ge.Boolean("-i,--interlaced",!1,{description:"Print the output of commands in real-time instead of buffering it"});this.jobs=ge.String("-j,--jobs",{description:"The maximum number of parallel tasks that the execution will be limited to; or `unlimited`",validator:LR([Vs(["unlimited"]),oI(NR(),[OR(),MR(1)])])});this.topological=ge.Boolean("-t,--topological",!1,{description:"Run the command after all workspaces it depends on (regular) have finished"});this.topologicalDev=ge.Boolean("--topological-dev",!1,{description:"Run the command after all workspaces it depends on (regular + dev) have finished"});this.include=ge.Array("--include",[],{description:"An array of glob pattern idents or paths; only matching workspaces will be traversed"});this.exclude=ge.Array("--exclude",[],{description:"An array of glob pattern idents or paths; matching workspaces won't be traversed"});this.publicOnly=ge.Boolean("--no-private",{description:"Avoid running the command on private workspaces"});this.since=ge.String("--since",{description:"Only include workspaces that have been changed since the specified ref.",tolerateBoolean:!0});this.dryRun=ge.Boolean("-n,--dry-run",{description:"Print the commands that would be run, without actually running them"});this.commandName=ge.String();this.args=ge.Proxy()}async execute(){let r=await Ve.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!this.all&&!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState();let n=this.cli.process([this.commandName,...this.args]),u=n.path.length===1&&n.path[0]==="run"&&typeof n.scriptName<"u"?n.scriptName:null;if(n.path.length===0)throw new it("Invalid subcommand name for iteration - use the 'run' keyword if you wish to execute a script");let A=ae=>{!this.dryRun||this.context.stdout.write(`${ae} -`)},p=()=>{let ae=this.from.map(we=>dw.default.matcher(we));return o.workspaces.filter(we=>{let Pe=W.stringifyIdent(we.anchoredLocator),g=we.relativeCwd;return ae.some(Ee=>Ee(Pe)||Ee(g))})},h=[];if(this.since?(A("Option --since is set; selecting the changed workspaces as root for workspace selection"),h=Array.from(await ra.fetchChangedWorkspaces({ref:this.since,project:o}))):this.from?(A("Option --from is set; selecting the specified workspaces"),h=[...p()]):this.worktree?(A("Option --worktree is set; selecting the current workspace"),h=[a]):this.recursive?(A("Option --recursive is set; selecting the current workspace"),h=[a]):this.all&&(A("Option --all is set; selecting all workspaces"),h=[...o.workspaces]),this.dryRun&&!this.all){for(let ae of h)A(` -- ${ae.relativeCwd} - ${W.prettyLocator(r,ae.anchoredLocator)}`);h.length>0&&A("")}let E;if(this.recursive?this.since?(A("Option --recursive --since is set; recursively selecting all dependent workspaces"),E=new Set(h.map(ae=>[...ae.getRecursiveWorkspaceDependents()]).flat())):(A("Option --recursive is set; recursively selecting all transitive dependencies"),E=new Set(h.map(ae=>[...ae.getRecursiveWorkspaceDependencies()]).flat())):this.worktree?(A("Option --worktree is set; recursively selecting all nested workspaces"),E=new Set(h.map(ae=>[...ae.getRecursiveWorkspaceChildren()]).flat())):E=null,E!==null&&(h=[...new Set([...h,...E])],this.dryRun))for(let ae of E)A(` -- ${ae.relativeCwd} - ${W.prettyLocator(r,ae.anchoredLocator)}`);let I=[],v=!1;if(u?.includes(":")){for(let ae of o.workspaces)if(ae.manifest.scripts.has(u)&&(v=!v,v===!1))break}for(let ae of h){if(u&&!ae.manifest.scripts.has(u)&&!v&&!(await un.getWorkspaceAccessibleBinaries(ae)).has(u)){A(`Excluding ${ae.relativeCwd} because it doesn't have a "${u}" script`);continue}if(!(u===r.env.npm_lifecycle_event&&ae.cwd===a.cwd)){if(this.include.length>0&&!dw.default.isMatch(W.stringifyIdent(ae.anchoredLocator),this.include)&&!dw.default.isMatch(ae.relativeCwd,this.include)){A(`Excluding ${ae.relativeCwd} because it doesn't match the --include filter`);continue}if(this.exclude.length>0&&(dw.default.isMatch(W.stringifyIdent(ae.anchoredLocator),this.exclude)||dw.default.isMatch(ae.relativeCwd,this.exclude))){A(`Excluding ${ae.relativeCwd} because it matches the --include filter`);continue}if(this.publicOnly&&ae.manifest.private===!0){A(`Excluding ${ae.relativeCwd} because it's a private workspace and --no-private was set`);continue}I.push(ae)}}if(this.dryRun)return 0;let b=this.verbose??this.context.stdout.isTTY,C=this.parallel?this.jobs==="unlimited"?1/0:Number(this.jobs)||Math.ceil(Ji.availableParallelism()/2):1,T=C===1?!1:this.parallel,L=T?this.interlaced:!0,U=(0,$Be.default)(C),J=new Map,te=new Set,le=0,pe=null,Ae=!1,ye=await Nt.start({configuration:r,stdout:this.context.stdout,includePrefix:!1},async ae=>{let we=async(Pe,{commandIndex:g})=>{if(Ae)return-1;!T&&b&&g>1&&ae.reportSeparator();let Ee=ZDt(Pe,{configuration:r,verbose:b,commandIndex:g}),[De,ce]=ZBe(ae,{prefix:Ee,interlaced:L}),[ne,ee]=ZBe(ae,{prefix:Ee,interlaced:L});try{b&&ae.reportInfo(null,`${Ee} Process started`);let Ie=Date.now(),ke=await this.cli.run([this.commandName,...this.args],{cwd:Pe.cwd,stdout:De,stderr:ne})||0;De.end(),ne.end(),await ce,await ee;let ht=Date.now();if(b){let H=r.get("enableTimers")?`, completed in ${de.pretty(r,ht-Ie,de.Type.DURATION)}`:"";ae.reportInfo(null,`${Ee} Process exited (exit code ${ke})${H}`)}return ke===130&&(Ae=!0,pe=ke),ke}catch(Ie){throw De.end(),ne.end(),await ce,await ee,Ie}};for(let Pe of I)J.set(Pe.anchoredLocator.locatorHash,Pe);for(;J.size>0&&!ae.hasErrors();){let Pe=[];for(let[De,ce]of J){if(te.has(ce.anchoredDescriptor.descriptorHash))continue;let ne=!0;if(this.topological||this.topologicalDev){let ee=this.topologicalDev?new Map([...ce.manifest.dependencies,...ce.manifest.devDependencies]):ce.manifest.dependencies;for(let Ie of ee.values()){let ke=o.tryWorkspaceByDescriptor(Ie);if(ne=ke===null||!J.has(ke.anchoredLocator.locatorHash),!ne)break}}if(!!ne&&(te.add(ce.anchoredDescriptor.descriptorHash),Pe.push(U(async()=>{let ee=await we(ce,{commandIndex:++le});return J.delete(De),te.delete(ce.anchoredDescriptor.descriptorHash),ee})),!T))break}if(Pe.length===0){let De=Array.from(J.values()).map(ce=>W.prettyLocator(r,ce.anchoredLocator)).join(", ");ae.reportError(3,`Dependency cycle detected (${De})`);return}let Ee=(await Promise.all(Pe)).find(De=>De!==0);pe===null&&(pe=typeof Ee<"u"?1:pe),(this.topological||this.topologicalDev)&&typeof Ee<"u"&&ae.reportError(0,"The command failed for workspaces that are depended upon by other workspaces; can't satisfy the dependency graph")}});return pe!==null?pe:ye.exitCode()}};op.paths=[["workspaces","foreach"]],op.usage=nt.Usage({category:"Workspace-related commands",description:"run a command on all workspaces",details:"\n This command will run a given sub-command on current and all its descendant workspaces. Various flags can alter the exact behavior of the command:\n\n - If `-p,--parallel` is set, the commands will be ran in parallel; they'll by default be limited to a number of parallel tasks roughly equal to half your core number, but that can be overridden via `-j,--jobs`, or disabled by setting `-j unlimited`.\n\n - If `-p,--parallel` and `-i,--interlaced` are both set, Yarn will print the lines from the output as it receives them. If `-i,--interlaced` wasn't set, it would instead buffer the output from each process and print the resulting buffers only after their source processes have exited.\n\n - If `-t,--topological` is set, Yarn will only run the command after all workspaces that it depends on through the `dependencies` field have successfully finished executing. If `--topological-dev` is set, both the `dependencies` and `devDependencies` fields will be considered when figuring out the wait points.\n\n - If `-A,--all` is set, Yarn will run the command on all the workspaces of a project.\n\n - If `-R,--recursive` is set, Yarn will find workspaces to run the command on by recursively evaluating `dependencies` and `devDependencies` fields, instead of looking at the `workspaces` fields.\n\n - If `-W,--worktree` is set, Yarn will find workspaces to run the command on by looking at the current worktree.\n\n - If `--from` is set, Yarn will use the packages matching the 'from' glob as the starting point for any recursive search.\n\n - If `--since` is set, Yarn will only run the command on workspaces that have been modified since the specified ref. By default Yarn will use the refs specified by the `changesetBaseRefs` configuration option.\n\n - If `--dry-run` is set, Yarn will explain what it would do without actually doing anything.\n\n - The command may apply to only some workspaces through the use of `--include` which acts as a whitelist. The `--exclude` flag will do the opposite and will be a list of packages that mustn't execute the script. Both flags accept glob patterns (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\n\n Adding the `-v,--verbose` flag (automatically enabled in interactive terminal environments) will cause Yarn to print more information; in particular the name of the workspace that generated the output will be printed at the front of each line.\n\n If the command is `run` and the script being run does not exist the child workspace will be skipped without error.\n ",examples:[["Publish all packages","yarn workspaces foreach -A npm publish --tolerate-republish"],["Run the build script on all descendant packages","yarn workspaces foreach -A run build"],["Run the build script on current and all descendant packages in parallel, building package dependencies first","yarn workspaces foreach -Apt run build"],["Run the build script on several packages and all their dependencies, building dependencies first","yarn workspaces foreach -Rpt --from '{workspace-a,workspace-b}' run build"]]}),op.schema=[lI("all",Gu.Forbids,["from","recursive","since","worktree"],{missingIf:"undefined"}),UR(["all","recursive","since","worktree"],{missingIf:"undefined"})];function ZBe(t,{prefix:e,interlaced:r}){let o=t.createStreamReporter(e),a=new je.DefaultStream;a.pipe(o,{end:!1}),a.on("finish",()=>{o.end()});let n=new Promise(A=>{o.on("finish",()=>{A(a.active)})});if(r)return[a,n];let u=new je.BufferStream;return u.pipe(a,{end:!1}),u.on("finish",()=>{a.end()}),[u,n]}function ZDt(t,{configuration:e,commandIndex:r,verbose:o}){if(!o)return null;let n=`[${W.stringifyIdent(t.anchoredLocator)}]:`,u=["#2E86AB","#A23B72","#F18F01","#C73E1D","#CCE2A3"],A=u[r%u.length];return de.pretty(e,n,A)}var $Dt={commands:[rg,op]},ePt=$Dt;var fC=()=>({modules:new Map([["@yarnpkg/cli",o2],["@yarnpkg/core",s2],["@yarnpkg/fslib",Vw],["@yarnpkg/libzip",x1],["@yarnpkg/parsers",tI],["@yarnpkg/shell",T1],["clipanion",pI],["semver",tPt],["typanion",Ko],["@yarnpkg/plugin-essentials",tH],["@yarnpkg/plugin-compat",oH],["@yarnpkg/plugin-constraints",BH],["@yarnpkg/plugin-dlx",vH],["@yarnpkg/plugin-exec",SH],["@yarnpkg/plugin-file",bH],["@yarnpkg/plugin-git",eH],["@yarnpkg/plugin-github",FH],["@yarnpkg/plugin-http",TH],["@yarnpkg/plugin-init",RH],["@yarnpkg/plugin-interactive-tools",Lj],["@yarnpkg/plugin-link",Mj],["@yarnpkg/plugin-nm",Cq],["@yarnpkg/plugin-npm",EG],["@yarnpkg/plugin-npm-cli",xG],["@yarnpkg/plugin-pack",hG],["@yarnpkg/plugin-patch",NG],["@yarnpkg/plugin-pnp",lq],["@yarnpkg/plugin-pnpm",OG],["@yarnpkg/plugin-stage",YG],["@yarnpkg/plugin-typescript",WG],["@yarnpkg/plugin-version",XG],["@yarnpkg/plugin-workspace-tools",ZG]]),plugins:new Set(["@yarnpkg/plugin-essentials","@yarnpkg/plugin-compat","@yarnpkg/plugin-constraints","@yarnpkg/plugin-dlx","@yarnpkg/plugin-exec","@yarnpkg/plugin-file","@yarnpkg/plugin-git","@yarnpkg/plugin-github","@yarnpkg/plugin-http","@yarnpkg/plugin-init","@yarnpkg/plugin-interactive-tools","@yarnpkg/plugin-link","@yarnpkg/plugin-nm","@yarnpkg/plugin-npm","@yarnpkg/plugin-npm-cli","@yarnpkg/plugin-pack","@yarnpkg/plugin-patch","@yarnpkg/plugin-pnp","@yarnpkg/plugin-pnpm","@yarnpkg/plugin-stage","@yarnpkg/plugin-typescript","@yarnpkg/plugin-version","@yarnpkg/plugin-workspace-tools"])});function rve({cwd:t,pluginConfiguration:e}){let r=new as({binaryLabel:"Yarn Package Manager",binaryName:"yarn",binaryVersion:tn??""});return Object.assign(r,{defaultContext:{...as.defaultContext,cwd:t,plugins:e,quiet:!1,stdin:process.stdin,stdout:process.stdout,stderr:process.stderr}})}function rPt(t){if(je.parseOptionalBoolean(process.env.YARN_IGNORE_NODE))return!0;let r=process.versions.node,o=">=18.12.0";if(kr.satisfiesWithPrereleases(r,o))return!0;let a=new it(`This tool requires a Node version compatible with ${o} (got ${r}). Upgrade Node, or set \`YARN_IGNORE_NODE=1\` in your environment.`);return as.defaultContext.stdout.write(t.error(a)),!1}async function nve({selfPath:t,pluginConfiguration:e}){return await Ve.find(ue.toPortablePath(process.cwd()),e,{strict:!1,usePathCheck:t})}function nPt(t,e,{yarnPath:r}){if(!oe.existsSync(r))return t.error(new Error(`The "yarn-path" option has been set, but the specified location doesn't exist (${r}).`)),1;process.on("SIGINT",()=>{});let o={stdio:"inherit",env:{...process.env,YARN_IGNORE_PATH:"1"}};try{(0,eve.execFileSync)(process.execPath,[ue.fromPortablePath(r),...e],o)}catch(a){return a.status??1}return 0}function iPt(t,e){let r=null,o=e;return e.length>=2&&e[0]==="--cwd"?(r=ue.toPortablePath(e[1]),o=e.slice(2)):e.length>=1&&e[0].startsWith("--cwd=")?(r=ue.toPortablePath(e[0].slice(6)),o=e.slice(1)):e[0]==="add"&&e[e.length-2]==="--cwd"&&(r=ue.toPortablePath(e[e.length-1]),o=e.slice(0,e.length-2)),t.defaultContext.cwd=r!==null?K.resolve(r):K.cwd(),o}function sPt(t,{configuration:e}){if(!e.get("enableTelemetry")||tve.isCI||!process.stdout.isTTY)return;Ve.telemetry=new cC(e,"puba9cdc10ec5790a2cf4969dd413a47270");let o=/^@yarnpkg\/plugin-(.*)$/;for(let a of e.plugins.keys())uC.has(a.match(o)?.[1]??"")&&Ve.telemetry?.reportPluginName(a);t.binaryVersion&&Ve.telemetry.reportVersion(t.binaryVersion)}function ive(t,{configuration:e}){for(let r of e.plugins.values())for(let o of r.commands||[])t.register(o)}async function oPt(t,e,{selfPath:r,pluginConfiguration:o}){if(!rPt(t))return 1;let a=await nve({selfPath:r,pluginConfiguration:o}),n=a.get("yarnPath"),u=a.get("ignorePath");if(n&&!u)return nPt(t,e,{yarnPath:n});delete process.env.YARN_IGNORE_PATH;let A=iPt(t,e);sPt(t,{configuration:a}),ive(t,{configuration:a});let p=t.process(A,t.defaultContext);return p.help||Ve.telemetry?.reportCommandName(p.path.join(" ")),await t.run(p,t.defaultContext)}async function the({cwd:t=K.cwd(),pluginConfiguration:e=fC()}={}){let r=rve({cwd:t,pluginConfiguration:e}),o=await nve({pluginConfiguration:e,selfPath:null});return ive(r,{configuration:o}),r}async function sk(t,{cwd:e=K.cwd(),selfPath:r,pluginConfiguration:o}){let a=rve({cwd:e,pluginConfiguration:o});try{process.exitCode=await oPt(a,t,{selfPath:r,pluginConfiguration:o})}catch(n){as.defaultContext.stdout.write(a.error(n)),process.exitCode=1}finally{await oe.rmtempPromise()}}sk(process.argv.slice(2),{cwd:K.cwd(),selfPath:ue.toPortablePath(ue.resolve(process.argv[1])),pluginConfiguration:fC()});})(); -/* -object-assign -(c) Sindre Sorhus -@license MIT -*/ -/*! - * buildToken - * Builds OAuth token prefix (helper function) - * - * @name buildToken - * @function - * @param {GitUrl} obj The parsed Git url object. - * @return {String} token prefix - */ -/*! - * fill-range - * - * Copyright (c) 2014-present, Jon Schlinkert. - * Licensed under the MIT License. - */ -/*! - * is-extglob - * - * Copyright (c) 2014-2016, Jon Schlinkert. - * Licensed under the MIT License. - */ -/*! - * is-glob - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ -/*! - * is-number - * - * Copyright (c) 2014-present, Jon Schlinkert. - * Released under the MIT License. - */ -/*! - * is-windows - * - * Copyright © 2015-2018, Jon Schlinkert. - * Released under the MIT License. - */ -/*! - * to-regex-range - * - * Copyright (c) 2015-present, Jon Schlinkert. - * Released under the MIT License. - */ -/** - @license - Copyright (c) 2015, Rebecca Turner - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. - */ -/** - @license - Copyright Joyent, Inc. and other Node contributors. - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to permit - persons to whom the Software is furnished to do so, subject to the - following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ -/** - @license - Copyright Node.js contributors. All rights reserved. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to - deal in the Software without restriction, including without limitation the - rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - sell copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. -*/ -/** - @license - The MIT License (MIT) - - Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ -/** @license React v0.18.0 - * scheduler.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -/** @license React v0.24.0 - * react-reconciler.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -/** @license React v16.13.1 - * react.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ diff --git a/.yarnrc.yml b/.yarnrc.yml index 374745715f05..252333917781 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -43,7 +43,6 @@ npmAuditIgnoreAdvisories: # not appear to be used. - 1092461 - # Temp fix for https://github.com/MetaMask/metamask-extension/pull/16920 for the sake of 11.7.1 hotfix # This will be removed in this ticket https://github.com/MetaMask/metamask-extension/issues/22299 - 'ts-custom-error (deprecation)' @@ -93,7 +92,7 @@ npmAuditIgnoreAdvisories: # MetaMask owned repositories brought in by other MetaMask dependencies that # can be resolved by updating the versions throughout the dependency tree - 'eth-sig-util (deprecation)' # via @metamask/eth-ledger-bridge-keyring - - '@metamask/controller-utils (deprecation)' # via @metamask/phishin-controller + - '@metamask/controller-utils (deprecation)' # via @metamask/phishing-controller - 'safe-event-emitter (deprecation)' # via eth-block-tracker and others # @metamask-institutional relies upon crypto which is deprecated @@ -126,18 +125,16 @@ npmAuditIgnoreAdvisories: - '@metamask/snaps-ui (deprecation)' npmRegistries: - "https://npm.pkg.github.com": + 'https://npm.pkg.github.com': npmAlwaysAuth: true - npmAuthToken: "${GITHUB_PACKAGE_READ_TOKEN-}" + npmAuthToken: '${GITHUB_PACKAGE_READ_TOKEN-}' npmScopes: metamask: - npmRegistryServer: "${METAMASK_NPM_REGISTRY:-https://registry.yarnpkg.com}" + npmRegistryServer: '${METAMASK_NPM_REGISTRY:-https://registry.yarnpkg.com}' plugins: - path: .yarn/plugins/@yarnpkg/plugin-allow-scripts.cjs - spec: "https://raw.githubusercontent.com/LavaMoat/LavaMoat/main/packages/yarn-plugin-allow-scripts/bundles/@yarnpkg/plugin-allow-scripts.js" + spec: 'https://raw.githubusercontent.com/LavaMoat/LavaMoat/main/packages/yarn-plugin-allow-scripts/bundles/@yarnpkg/plugin-allow-scripts.js' - path: .yarn/plugins/@yarnpkg/plugin-engines.cjs - spec: "https://raw.githubusercontent.com/devoto13/yarn-plugin-engines/main/bundles/%40yarnpkg/plugin-engines.js" - -yarnPath: .yarn/releases/yarn-4.0.2.cjs + spec: 'https://raw.githubusercontent.com/devoto13/yarn-plugin-engines/main/bundles/%40yarnpkg/plugin-engines.js' diff --git a/CHANGELOG.md b/CHANGELOG.md index 18db909ce3ad..a8bc947c4c01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,401 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [11.16.7] +### Fixed +- Fix bug that breaks dapps that expect users to switch chains manually([#25046]https://github.com/MetaMask/metamask-extension/pull/25046) + +## [11.16.6] +### Added +- Add a Basic Functionality Toggle to settings, enabling users to opt-out of some features that send network requests to external services ([#23456](https://github.com/MetaMask/metamask-extension/pull/23456)) + +### Changed +- Update MetaMask Chrome builds to Manifest V3 ([#24746](https://github.com/MetaMask/metamask-extension/pull/24746)) + +### Fixed +- Ensure network requests are not made during onboarding + - ([#24890](https://github.com/MetaMask/metamask-extension/pull/24890)) + - ([#24891](https://github.com/MetaMask/metamask-extension/pull/24891)) + - ([#24887](https://github.com/MetaMask/metamask-extension/pull/24887)) + +## [11.16.5] +### Changed +- Re-enable the opt-in modal (2df1eb566b) + +## [11.16.4] +### Changed +- Temporarily disable the opt-in modal ([#25007](https://github.com/MetaMask/metamask-extension/pull/25007)) + +## [11.16.3] +### Changed +- Update Trezor logo ([#24343](https://github.com/MetaMask/metamask-extension/pull/24343)) + +## [11.16.2] +### Fixed +- Fix gas fee displays on the Scroll network ([#24854](https://github.com/MetaMask/metamask-extension/pull/24854)) + +## [11.16.1] +### Changed +- Update Smart Transactions opt-in moda ([#24771](https://github.com/MetaMask/metamask-extension/pull/24771)) + +## [11.16.0] +### Added +- Revamped the UI for Snap installation and update processes ([#23870](https://github.com/MetaMask/metamask-extension/pull/23870)) +- Added a 'Restore' onboarding option for seamless recovery from backup ([#23739](https://github.com/MetaMask/metamask-extension/pull/23739)) +- Enabled ERC20 token detection on seven new networks ([#24121](https://github.com/MetaMask/metamask-extension/pull/24121)) +- Activated token and NFT Auto-Detect by default for new mobile users ([#23700](https://github.com/MetaMask/metamask-extension/pull/23700)) +- Introduced the Filecoin SVG logo ([#24039](https://github.com/MetaMask/metamask-extension/pull/24039)) +- Enhanced transaction confirmations with a tooltip and icon for busy network status ([#24104](https://github.com/MetaMask/metamask-extension/pull/24104)) +- Added a setting to experiment with redesigned confirmation pages through a feature flag ([#24052](https://github.com/MetaMask/metamask-extension/pull/24052)) +- Introduced 'Developer Options' in settings for easier app state management and feature toggling during development ([#22382](https://github.com/MetaMask/metamask-extension/pull/22382)) +- Automated Layer 1 gas fee inclusion for Scroll network transactions ([#23991](https://github.com/MetaMask/metamask-extension/pull/23991)) +- Enhanced the Smart Transactions status page to display simulation details for native balance changes ([#24075](https://github.com/MetaMask/metamask-extension/pull/24075)) +- Enhanced security by disabling paste functionality in the Snap removal confirmation field ([#23993](https://github.com/MetaMask/metamask-extension/pull/23993)) +- Launched Transaction Insights V2 and Signature Insights to all users ([#23630](https://github.com/MetaMask/metamask-extension/pull/23630)) + +### Changed +- Updated the messaging for Blockaid warnings to provide clearer information to users during transactions ([#24037](https://github.com/MetaMask/metamask-extension/pull/24037)) +- Optimized Smart Transactions by hiding the 'retry' button and displaying cancelled transactions only for Swaps in the Activity tab ([#24176](https://github.com/MetaMask/metamask-extension/pull/24176)) +- Refreshed the Smart Transactions Opt In modal with updated UI and content, alongside a rebranding to 'Smart Transactions' ([#24053](https://github.com/MetaMask/metamask-extension/pull/24053)) +- Eliminated the product tour from the home page ([#24051](https://github.com/MetaMask/metamask-extension/pull/24051)) +- Refreshed the look of toggle buttons ([#24090](https://github.com/MetaMask/metamask-extension/pull/24090)) + +### Fixed +- Improved the redirect screen by caching dapp icons to prevent disappearance during loading ([#23999](https://github.com/MetaMask/metamask-extension/pull/23999)) +- Fixed PPOM/Blockaid functionality in MV3 builds ([#24115](https://github.com/MetaMask/metamask-extension/pull/24115)) +- Fixed offscreen document loading errors in MV3 ([#24083](https://github.com/MetaMask/metamask-extension/pull/24083)) +- Improved account connection process by automatically filtering out duplicate or already connected accounts ([#24057](https://github.com/MetaMask/metamask-extension/pull/24057)) +- Fixed an issue where the token list was cleared upon network switch ([#24212](https://github.com/MetaMask/metamask-extension/pull/24212)) +- Improved how NFTs appear in MetaMask by addressing an issue with fetching details for certain NFTs ([#24029](https://github.com/MetaMask/metamask-extension/pull/24029)) +- Resolved an issue where fiat prices for ERC20 tokens were not updating ([#24021](https://github.com/MetaMask/metamask-extension/pull/24021)) +- Deprecated the Mumbai and Linea Goerli test networks ([#23695](https://github.com/MetaMask/metamask-extension/pull/23695)) +- Fixed the issue where the checkmark icon was missing in the confirmation message after importing an ERC20 token ([#24005](https://github.com/MetaMask/metamask-extension/pull/24005)) +- Resolved an issue where transactions triggered during a pending signature request caused an indefinite loading state ([#24173](https://github.com/MetaMask/metamask-extension/pull/24173)) +- Implemented UI improvements on redesigned signature request pages based on feedback ([#24135](https://github.com/MetaMask/metamask-extension/pull/24135)) +- Enhanced the 'scroll to bottom' button with improved hover effects ([#24147](https://github.com/MetaMask/metamask-extension/pull/24147)) +- Enabled Ledger wallet users to sign signature requests seamlessly on the newly designed confirmation pages ([#23780](https://github.com/MetaMask/metamask-extension/pull/23780)) +- Optimized gas estimation failure warnings to display a single alert ([#23886](https://github.com/MetaMask/metamask-extension/pull/23886)) +- Improved the readability of footer button labels in the new-network component for both light and dark modes ([#23988](https://github.com/MetaMask/metamask-extension/pull/23988)) +- Fixed synchronization issues with per-dapp selected network preferences across toggle changes ([#24093](https://github.com/MetaMask/metamask-extension/pull/24093)) +- Fixed a problem where changing site permissions didn't immediately update the network used by the site ([#23525](https://github.com/MetaMask/metamask-extension/pull/23525)) +- Corrected the display and spacing of the permissions tooltip within the connect accounts modal ([#24098](https://github.com/MetaMask/metamask-extension/pull/24098)) +- Disabled the 'Connect more accounts' button when all accounts are already connected ([#24084](https://github.com/MetaMask/metamask-extension/pull/24084)) +- Improved back navigation from Connected Accounts ([#24085](https://github.com/MetaMask/metamask-extension/pull/24085)) +- Updated the wallet, permissions, and connections screens to align with the latest design improvements ([#24023](https://github.com/MetaMask/metamask-extension/pull/24023)) +- Improved the permissions page to correctly display all permissions across networks ([#23986](https://github.com/MetaMask/metamask-extension/pull/23986)) +- Enhanced the connections page to accurately display connected dApp information and status ([#24022](https://github.com/MetaMask/metamask-extension/pull/24022)) +- Fixed an issue to ensure smooth disconnection of a single account from a dApp without breaking the page ([#23935](https://github.com/MetaMask/metamask-extension/pull/23935)) + +## [11.15.6] +### Changed +- Disable smart transaction opt-in modal ([#24715](https://github.com/MetaMask/metamask-extension/pull/24715)) + +## [11.15.5] +### Changed +- Update copy in Smart Transactions opt-in modal([#24461](https://github.com/MetaMask/metamask-extension/pull/24461)) + +## [11.15.4] +### Changed +- Update UI for the Smart Transactions Opt In modal ([#24441](https://github.com/MetaMask/metamask-extension/pull/24441)) + +## [11.15.3] +### Changed +- Smart transaction improvements ([#24340](https://github.com/MetaMask/metamask-extension/pull/24340)) + - disable Smart Transactions on Sepolia + - improve Smart Transaction status page layout on full screen view + - Conditionally close the extension when a user clicks on "View transaction" on the Smart Transaction status page + - Update animation UI for non-popup view of Smart Transactions + +### Fixed +- Add animation on the smart transaction status page ([#24389](https://github.com/MetaMask/metamask-extension/pull/24389)) + +## [11.15.2] +### Fixed +- Ensure smart transaction modal is shown for users upgrading from previous versions ([#24377](https://github.com/MetaMask/metamask-extension/pull/24377)) + +## [11.15.1] +### Changed +- Restores 11.15.0, and also incorporates the 11.14.4 and 11.14.5 changes + +## [11.15.0] +### Added +- Expanded Smart Transactions (STX) functionality to include non-Swaps transactions on Ethereum Mainnet for users opted into STX ([#23155](https://github.com/MetaMask/metamask-extension/pull/23155)) +- Added Base Mainnet and removed Gnosis and Celo networks from popular networks list ([#23880](https://github.com/MetaMask/metamask-extension/pull/23880)) +- Enhanced balance fetching efficiency by supporting bulk balance checks on Linea, Aurora, Base, and ZkSync ([#23436](https://github.com/MetaMask/metamask-extension/pull/23436)) +- Introduced a 'Learn more' link to the simulations toggle in privacy and onboarding settings ([#23890](https://github.com/MetaMask/metamask-extension/pull/23890)) +- Introduced a confirmation step for approving higher token spending limits ([#23560](https://github.com/MetaMask/metamask-extension/pull/23560)) +- Added a dismissible alert for users migrated from OpenSea to Blockaid on unsupported networks ([#23743](https://github.com/MetaMask/metamask-extension/pull/23743)) +- Implemented support for signature requests with a redesigned interface ([#23539](https://github.com/MetaMask/metamask-extension/pull/23539)) +- Introduced support for the new Linea Sepolia network and deprecated the Linea Goerli network ([#23459](https://github.com/MetaMask/metamask-extension/pull/23459)) + +### Changed +- Removed outdated announcements for 'Snaps Open Beta' and 'Buy & Sell' features ([#23940](https://github.com/MetaMask/metamask-extension/pull/23940)) +- Enhanced Smart Transactions swaps with detailed simulation views ([#23963](https://github.com/MetaMask/metamask-extension/pull/23963)) +- Updated the Arbitrum logo ([#23969](https://github.com/MetaMask/metamask-extension/pull/23969)) +- Enhanced the appearance of links in Snap dialogs ([#23840](https://github.com/MetaMask/metamask-extension/pull/23840)) +- Improved the layout of the security alert option in the settings page ([#23718](https://github.com/MetaMask/metamask-extension/pull/23718)) +- Enhanced the appearance of security alerts by fine-tuning their spacing ([#23900](https://github.com/MetaMask/metamask-extension/pull/23900)) +- Unified the color scheme for secondary titles in settings ([#23764](https://github.com/MetaMask/metamask-extension/pull/23764)) +- Adjusted asset icon display and sizing in simulation details ([#23760](https://github.com/MetaMask/metamask-extension/pull/23760)) +- Enhanced display for near-zero amounts and updated native token visuals for all chains ([#23711](https://github.com/MetaMask/metamask-extension/pull/23711)) +- Enhanced default token name visibility by always using the remote token list for petnames ([#23919](https://github.com/MetaMask/metamask-extension/pull/23919)) +- Improved transaction confirmation clarity by hiding totals for successful simulations ([#23899](https://github.com/MetaMask/metamask-extension/pull/23899)) +- Updated transaction controller to display balance changes for wrapped ERC-20 tokens and legacy ERC-721 tokens ([#23915](https://github.com/MetaMask/metamask-extension/pull/23915)) + +### Fixed +- Enhanced the send flow by fine-tuning input fields to keep trailing zeros and decimals ([#23808](https://github.com/MetaMask/metamask-extension/pull/23808)) +- Resolved token detection and import issues ([#23798](https://github.com/MetaMask/metamask-extension/pull/23798)) +- Implemented a deprecation warning for users switching to the Mumbai network ([#23846](https://github.com/MetaMask/metamask-extension/pull/23846)) +- Corrected the display of crypto balances in the presence of scam network warnings ([#23645](https://github.com/MetaMask/metamask-extension/pull/23645)) +- Enhanced UI for simulation details by wrapping and adding tooltips to long asset names and amounts ([#23768](https://github.com/MetaMask/metamask-extension/pull/23768)) +- Expanded the deprecation warning for OpenSea security alerts to include typed signature confirmations ([#23743](https://github.com/MetaMask/metamask-extension/pull/23743)) +- Fixed an issue in Firefox where security alerts weren't displaying due to permission settings ([#23958](https://github.com/MetaMask/metamask-extension/pull/23958)) +- Resolved an issue where the loading indicator overlapped with the UI in security alerts ([#23927](https://github.com/MetaMask/metamask-extension/pull/23927)) +- Resolved an issue with an infinite loading spinner on blockaid alerts ([#23480](https://github.com/MetaMask/metamask-extension/pull/23480)) +- Improved accessibility in the app's network selection by ensuring screen readers announce network names more clearly ([#23842](https://github.com/MetaMask/metamask-extension/pull/23842)) +- Resolved an issue preventing QR code-based hardware wallet connections ([#23903](https://github.com/MetaMask/metamask-extension/pull/23903)) +- Resolved an issue where the connected accounts modal would crash if a dApp with an installed Snap was accessed ([#23928](https://github.com/MetaMask/metamask-extension/pull/23928)) + +## [11.14.5] +### Fixed +- Prevent users from making fund loss errors while editing transactions by removing the edit button when on any confirmation screen for a transaction proposed by a dapp ([#24322](https://github.com/MetaMask/metamask-extension/pull/24322)) +- Reduce failed simulations on NFT mint confirmations ([#24350]https://github.com/MetaMask/metamask-extension/pull/24350) + +## [11.14.4] +### Fixed +- Fix bug that could cause safe-transfer-from transactions to be converted to transfer-from transactions, by removing the edit button on the safe-transfer-from confirmation screens ([#24287](https://github.com/MetaMask/metamask-extension/pull/24287)) + +## [11.14.3] +### Fixed +- Fixed getMinimumGasTotalInHexWei error by updating the "fee_market" gasEstimateType logic ([#24287](https://github.com/MetaMask/metamask-extension/pull/24287)) + +## [11.14.2] +### Changed +- Update Blockaid to ensure user's have the latest protections ([#24171](https://github.com/MetaMask/metamask-extension/pull/24171)) + +### Fixed +- Ensure gas estimates always reflect the correct network ([#24253](https://github.com/MetaMask/metamask-extension/pull/24253)) + +## [11.14.1] +### Fixed +- Fix crashes on transaction screens for some users with es_419, pt_BR, pt_PT, zh_CN, zh_TW locales ([#24068](https://github.com/MetaMask/metamask-extension/pull/24068)) + +## [11.14.0] +### Added +- Transaction Simulations + - Integrated transaction simulation features into all builds, with the option to disable via privacy settings ([#23651](https://github.com/MetaMask/metamask-extension/pull/23651)) + - Added a toggle for transaction simulations under settings, with a feature highlight in the 'What's New' modal ([#23604](https://github.com/MetaMask/metamask-extension/pull/23604)) + - Introduced Simulation Preview for Token Balance Adjustments([#23529] https://github.com/MetaMask/metamask-extension/pull/23529) +- Introduced a feature to toggle visibility of private keys during import ([#23371](https://github.com/MetaMask/metamask-extension/pull/23371)) +- Enhanced network addition with a direct link to MetaMask Portfolio bridge ([#23475](https://github.com/MetaMask/metamask-extension/pull/23475)) +- Added a MetaMask Bridges link in Swaps ([#23437](https://github.com/MetaMask/metamask-extension/pull/23437)) +- Enhanced the display of watched NFTs with default petnames and icons ([#23438](https://github.com/MetaMask/metamask-extension/pull/23438)) +- Introduced support for Base network in Blockaid validations ([#23452](https://github.com/MetaMask/metamask-extension/pull/23452)) +- Enabled direct redirection to Snap confirmations from the home page ([#23584](https://github.com/MetaMask/metamask-extension/pull/23584)) +- Introduced support for localized Snap manifests ([#21909](https://github.com/MetaMask/metamask-extension/pull/21909)) +- Enabled Base network support for swaps ([#23394](https://github.com/MetaMask/metamask-extension/pull/23394)) +- Introduced a 'What's New' notification for MetaMask Portfolio ([#23359](https://github.com/MetaMask/metamask-extension/pull/23359)) +- Activated Snaps home pages in the stable release ([#23383](https://github.com/MetaMask/metamask-extension/pull/23383)) +- Added a custom screen for `increaseAllowance` contract interactions ([#23883](https://github.com/MetaMask/metamask-extension/pull/23883)) +- [MMI] Enhanced the custody view with a search bar ([#23492](https://github.com/MetaMask/metamask-extension/pull/23492)) +- [MMI] Implemented message text verification for contract call operations ([#23462](https://github.com/MetaMask/metamask-extension/pull/23462)) + +### Changed +- Updated security settings by removing the OpenSea provider option ([#23546](https://github.com/MetaMask/metamask-extension/pull/23546)) +- Transitioned users from the OpenSea security alert feature to Blockaid ([#23460](https://github.com/MetaMask/metamask-extension/pull/23460)) +- Improved display of accounts within Snaps Permissions UI ([#23454](https://github.com/MetaMask/metamask-extension/pull/23454)) +- Removed the banner from the account list menu ([#23447](https://github.com/MetaMask/metamask-extension/pull/23447)) +- Updated the Fuse mainnet logo to its latest branding ([#23542](https://github.com/MetaMask/metamask-extension/pull/23542)) +- Enhanced the per-dapp network selection feature to ensure subscribe and filter requests adhere to the selected network ([#23386](https://github.com/MetaMask/metamask-extension/pull/23386)) +- Improved wallet setup by allowing onboarding and unlocking without needing Infura mainnet connectivity ([#23388](https://github.com/MetaMask/metamask-extension/pull/23388)) +- Enhanced the hardware wallet import process with clearer instructions to switch networks if accounts appear empty ([#23443](https://github.com/MetaMask/metamask-extension/pull/23443)) +- Implemented minor adjustments to Insights V2 ([#23248](https://github.com/MetaMask/metamask-extension/pull/23248)) +- Updated snaps-registry to the latest version to address validation issues with certain signature lengths ([#23380](https://github.com/MetaMask/metamask-extension/pull/23380)) +- Improved Snap layout by adopting gap for element spacing ([#23369](https://github.com/MetaMask/metamask-extension/pull/23369)) +- [MMI] Updated MMI support URLs to direct users to the new support site ([#23656](https://github.com/MetaMask/metamask-extension/pull/23656)) + +### Fixed +- Refined the asset picker design ([#23264](https://github.com/MetaMask/metamask-extension/pull/23264)) +- Improved token matching by making symbol checks case insensitive ([#23637](https://github.com/MetaMask/metamask-extension/pull/23637)) +- Fixed an issue where very small transaction amounts were displayed in scientific notation ([#23341](https://github.com/MetaMask/metamask-extension/pull/23341)) +- Resolved an issue where approving a transaction could inadvertently reset its status due to concurrent updates ([#23647](https://github.com/MetaMask/metamask-extension/pull/23647)) +- Corrected the extension popup client connection count to support multiple open popups ([#23583](https://github.com/MetaMask/metamask-extension/pull/23583)) +- Resolved text overflow in the Snaps list for long Snap IDs or names ([#23517](https://github.com/MetaMask/metamask-extension/pull/23517)) +- Corrected an issue where domain resolution results persisted on the send screen after inputs were cleared ([#23595](https://github.com/MetaMask/metamask-extension/pull/23595)) +- Resolved an issue causing a crash when attempting to connect to multiple Snaps simultaneously ([#23646](https://github.com/MetaMask/metamask-extension/pull/23646)) +- Resolved an issue where Snap names were not displayed in the permission list due to a missing prop ([#23627](https://github.com/MetaMask/metamask-extension/pull/23627)) +- Corrected the calculation of maximum gas displayed and the gas limit determination for swap transactions ([#23545](https://github.com/MetaMask/metamask-extension/pull/23545)) +- [FLASK] Updated the send screen placeholder text in Flask to accurately reflect support for full domain resolution, not just ENS ([#22192](https://github.com/MetaMask/metamask-extension/pull/22192)) + +## [11.13.3] +### Fixed +- [MMI] Adds required variable to prod env ([#23879](https://github.com/MetaMask/metamask-extension/pull/23879)) + +## [11.13.2] +### Fixed +- [MMI] Updates MMI packages to latest versions ([#23841](https://github.com/MetaMask/metamask-extension/pull/23841)) +- [MMI] Updates MMI RPC methods to use latest method ([#23827](https://github.com/MetaMask/metamask-extension/pull/23827)) +- [MMI] Adds MMI Sentry DSN key ([#23826](https://github.com/MetaMask/metamask-extension/pull/23826)) + +## [11.13.1] + +## [11.13.0] +### Added +- Added support for ERC-1155 tokens across multiple chains ([#23297](https://github.com/MetaMask/metamask-extension/pull/23297)) +- Introduced a modal with a block explorer link for attempts to cancel already confirmed transactions ([#22943](https://github.com/MetaMask/metamask-extension/pull/22943)) +- Added a message section to the personal sign page ([#22766](https://github.com/MetaMask/metamask-extension/pull/22766)) +- Enabled Blockaid support for Sepolia ([#23298](https://github.com/MetaMask/metamask-extension/pull/23298)) +- Added Snaps authorship modals ([#22163](https://github.com/MetaMask/metamask-extension/pull/22163)) +- Added a prompt for users to connect their current account if it's not connected to a dApp ([#22966](https://github.com/MetaMask/metamask-extension/pull/22966)) +- Implemented updated Linea gas fee estimates for more accurate transaction costs ([#22918](https://github.com/MetaMask/metamask-extension/pull/22918)) + +### Changed +- Removed Goerli network from settings and added warning modal for manual attempts to add it ([#22995](https://github.com/MetaMask/metamask-extension/pull/22995)) +- Enhanced display names for first-party contracts ([#23092](https://github.com/MetaMask/metamask-extension/pull/23092)) +- Added new footer buttons for easier account connections and management in the Connected Account view ([#23241](https://github.com/MetaMask/metamask-extension/pull/23241)) +- Update Palm network logo with support for both light and dark modes ([#23191](https://github.com/MetaMask/metamask-extension/pull/23191)) +- Improved account naming in transactions ([#23046](https://github.com/MetaMask/metamask-extension/pull/23046)) + +### Fixed +- Improved interface by disabling transaction buttons for accounts that can't sign ([#23178](https://github.com/MetaMask/metamask-extension/pull/23178)) +- Fixed an issue where account permissions persisted after account removal ([#23247](https://github.com/MetaMask/metamask-extension/pull/23247)) +- Fixed a glitch that prevented some NFTs from being listed due to a mix-up with token types ([#22822](https://github.com/MetaMask/metamask-extension/pull/22822)) +- Fixed an issue with ERC1155 token transfers where decimal input amounts were incorrectly interpreted as hexadecimal ([#23151](https://github.com/MetaMask/metamask-extension/pull/23151)) +- Corrected the display of suggested ticker symbols to only appear for new custom networks ([#23169](https://github.com/MetaMask/metamask-extension/pull/23169)) +- Improved flexibility for dApp transactions, enabling them from any authorized account ([#23269](https://github.com/MetaMask/metamask-extension/pull/23269)) +- Updated the Transaction Confirmation to clearly show estimated and maximum fees ([#23203](https://github.com/MetaMask/metamask-extension/pull/23203)) +- Fixed missing Chain Name in the 'Report False Positives' ([#23195](https://github.com/MetaMask/metamask-extension/pull/23195)) +- Updated network tracking to only include sites you've connected to ([#23130](https://github.com/MetaMask/metamask-extension/pull/23130)) +- Excluded preinstalled Snaps from the Snaps list view ([#23167](https://github.com/MetaMask/metamask-extension/pull/23167)) +- Updated Snap UI to ensure input labels are properly shown ([#23153](https://github.com/MetaMask/metamask-extension/pull/23153)) +- Fixed an issue ensuring account avatars are displayed in both popup and full screen views ([#23265](https://github.com/MetaMask/metamask-extension/pull/23265)) +- Improved send flow by ensuring pinned accounts are prominently displayed at the top and correctly labeled ([#23176](https://github.com/MetaMask/metamask-extension/pull/23176)) +- Updated the Connections Page to include tabs and show connected accounts when an account is connected ([#23125](https://github.com/MetaMask/metamask-extension/pull/23125)) +- Resolved text highlight color conflicts by reverting to hex code usage ([#23188](https://github.com/MetaMask/metamask-extension/pull/23188)) +- [MMI] Simplified the home screen by removing the Buy, Sell, and NFT options ([#23199](https://github.com/MetaMask/metamask-extension/pull/23199)) + +## [11.12.4] +### Fixed +- Ensure native network balance is visible in home screen balance display ([#23614](https://github.com/MetaMask/metamask-extension/pull/23614)) + +## [11.12.3] +### Fixed +- [MMI] Fixes an error related with a missing code fence, when the MMI build didn't have the blockaid feature ([#23516](https://github.com/MetaMask/metamask-extension/pull/23516)) +- [MMI] Fixes a bug for some custodians that don't send us the env property when connection to MMI ([#23494](https://github.com/MetaMask/metamask-extension/pull/23494)) + +## [11.12.2] +### Fixed +- Fix transaction confirmations so that they correctly show estimated fees instead of max possible fees + - For non-layer 2 network, and non-token send, transactions([#23203](https://github.com/MetaMask/metamask-extension/pull/23203)) + - For layer 2 networks and for erc20 transfers ([#23511](https://github.com/MetaMask/metamask-extension/pull/23511)) + +## [11.12.1] +### Changed +- Updated styling for missing petnames to prevent misinterpretation as malicious ([#23458](https://github.com/MetaMask/metamask-extension/pull/23458)) + +## [11.12.0] +### Added +- Introduced deprecation warnings for Arbitrum Goerli and OP Goerli test networks ([#23071](https://github.com/MetaMask/metamask-extension/pull/23071)) +- Added origin details to personal sign page ([#22763](https://github.com/MetaMask/metamask-extension/pull/22763)) +- Enhanced snap functionality with dynamic interfaces, customizable timeouts, and faster installations ([#22828](https://github.com/MetaMask/metamask-extension/pull/22828)) +- Added a 'Connect Account' button in the account list menu for easier account connections ([#22941](https://github.com/MetaMask/metamask-extension/pull/22941)) +- [FLASK] Added signature insights ([#22485](https://github.com/MetaMask/metamask-extension/pull/22485)) +- [MMI] Enhanced error tracking in MMI controllers ([#22994](https://github.com/MetaMask/metamask-extension/pull/22994)) +- [MMI] Updated MMI dependencies and refactored code ([#22546](https://github.com/MetaMask/metamask-extension/pull/22546)) + +### Changed +- Updated Confirm/Sign button to red for malicious requests ([#23004](https://github.com/MetaMask/metamask-extension/pull/23004)) +- Updated the 'Discover Snaps' link to direct users to snaps.metamask.io ([#22909](https://github.com/MetaMask/metamask-extension/pull/22909)) +- Displayed total account balances on Accounts Menu and home screen ([#22186](https://github.com/MetaMask/metamask-extension/pull/22186)) +- Updated style of app header ([#22637](https://github.com/MetaMask/metamask-extension/pull/22637)) +- Enhanced settings search for better navigation ([#22967](https://github.com/MetaMask/metamask-extension/pull/22967)) +- Enhanced Send Flow by displaying account names during search ([#22824](https://github.com/MetaMask/metamask-extension/pull/22824)) +- Improved send flow by directly showing NFTs tab when sending an NFT ([#23033](https://github.com/MetaMask/metamask-extension/pull/23033)) +- Simplified send flow by removing outdated gas options ([#22951](https://github.com/MetaMask/metamask-extension/pull/22951)) +- [MMI] Improved custodian search by using environment names for unique identification ([#23073](https://github.com/MetaMask/metamask-extension/pull/23073)) +- [MMI] Enhanced MMI keyring configuration for improved mv3 version compatibility ([#22968](https://github.com/MetaMask/metamask-extension/pull/22968)) + +### Fixed +- Improved accuracy of fee details for Optimism transactions ([#22997](https://github.com/MetaMask/metamask-extension/pull/22997)) +- Ensured password prompt appears every time 'Show private key' is selected ([#22867](https://github.com/MetaMask/metamask-extension/pull/22867)) +- Adjusted menu positioning ensuring visibility of all options ([#22889](https://github.com/MetaMask/metamask-extension/pull/22889)) +- Corrected asset list to display native currency symbols instead of fiat on the home page ([#22760](https://github.com/MetaMask/metamask-extension/pull/22760)) +- Fixed tokens being added to incorrect networks after switching networks ([#22814](https://github.com/MetaMask/metamask-extension/pull/22814)) +- Fixed an issue where NFTs disappeared or couldn't be re-imported after account switching ([#22856](https://github.com/MetaMask/metamask-extension/pull/22856)) +- Fixed an issue with saving very low default gas fees ([#22790](https://github.com/MetaMask/metamask-extension/pull/22790)) +- Removed the subtle background behind setting icons ([#22982](https://github.com/MetaMask/metamask-extension/pull/22982)) +- Improved 'See Details' in alerts to stop auto-scrolling ([#22932](https://github.com/MetaMask/metamask-extension/pull/22932)) +- Improved security checks for transactions ([#22978](https://github.com/MetaMask/metamask-extension/pull/22978)) +- Ensured gas fee editing remains accessible even when currency rate checks are disabled ([#22890](https://github.com/MetaMask/metamask-extension/pull/22890)) +- Updated modal overlay for better visibility and focus on content in both light and dark modes ([#23102](https://github.com/MetaMask/metamask-extension/pull/23102)) +- Fixed behavior for manually added networks to show a modal with the option to switch, rather than auto-switching ([#22832](https://github.com/MetaMask/metamask-extension/pull/22832)) +- Corrected link alignment in Snap UI ([#23045](https://github.com/MetaMask/metamask-extension/pull/23045)) +- Resolved an issue that prevented cancelling permission requests without crashing the extension ([#22915](https://github.com/MetaMask/metamask-extension/pull/22915)) +- Fixed badge color in app-header to accurately reflect connection status ([#23126](https://github.com/MetaMask/metamask-extension/pull/23126)) +- Fixed a glitch in the Product Tour where step numbers were not displaying correctly ([#23100](https://github.com/MetaMask/metamask-extension/pull/23100)) +- Enhanced handling of long account names ([#23096](https://github.com/MetaMask/metamask-extension/pull/23096)) +- Resolved issue with tabs overlapping content in the send flow ([#23028](https://github.com/MetaMask/metamask-extension/pull/23028)) +- Ensured consistent balance display in Eth Overview and account list ([#23059](https://github.com/MetaMask/metamask-extension/pull/23059)) +- [MMI] Corrected custody type determination to support various types ([#22950](https://github.com/MetaMask/metamask-extension/pull/22950)) + +## [11.11.4] +### Changed +- Enable Snaps home pages ([#23383](https://github.com/MetaMask/metamask-extension/pull/23383)) + +### Fixed +- Fix intermittent Snaps installation issues due to faulty validation ([#23380](https://github.com/MetaMask/metamask-extension/pull/23380)) + +## [11.11.3] + +## [11.11.2] +### Changed +- Update the image in the Staking button What's New popup ([#23330](https://github.com/MetaMask/metamask-extension/pull/23330)) + +### Fixed +- [MMI] Fixed bug that prevents MMI users from submitting multiple Txs ([#23342](https://github.com/MetaMask/metamask-extension/pull/23342)) +- Fix the display of the native currency token symbol in the asset list + - ([#23355](https://github.com/MetaMask/metamask-extension/pull/23355)) + - ([#23327](https://github.com/MetaMask/metamask-extension/pull/23327)) + +## [11.11.1] +### Added +- Adds a staking button to the mainnet Ethereum token list item ([#22347](https://github.com/MetaMask/metamask-extension/pull/22347)) + +## [11.11.0] +### Added +- Added 'Pet Names' feature, allowing users to see preferred or suggested nicknames in the places of addesses + - Added 'What's New' popup for Petnames feature ([#22780](https://github.com/MetaMask/metamask-extension/pull/22780)) + - Introduced toggle for Petnames in experimental settings ([#22456](https://github.com/MetaMask/metamask-extension/pull/22456)) + - UI enhancements for initial petnames release, including new "Recognized" category and visual refinements ([#22772](https://github.com/MetaMask/metamask-extension/pull/22772)) + - Enhanced token name display with pet names ([#22734](https://github.com/MetaMask/metamask-extension/pull/22734)) +- Added title to Personal Sign component in confirmation design ([#22749](https://github.com/MetaMask/metamask-extension/pull/22749)) +- Added progress indicator for scanning QR codes with hardware wallets ([#20947](https://github.com/MetaMask/metamask-extension/pull/20947)) + +### Changed +- Moved security alerts from Experimental to Security & Privacy settings ([#22813](https://github.com/MetaMask/metamask-extension/pull/22813)) +- Updated BlockaidBannerAlert to support false positive reporting for failed types ([#22742](https://github.com/MetaMask/metamask-extension/pull/22742)) +- Enhanced BlockaidBannerAlert functionality and display ([#22625](https://github.com/MetaMask/metamask-extension/pull/22625)) +- Disabled smart swaps for Snap accounts ([#22731](https://github.com/MetaMask/metamask-extension/pull/22731)) +- Disabled MetaMask on Battle.net to fix a 2FA login issue ([#20396](https://github.com/MetaMask/metamask-extension/pull/20396)) +- Revised warning copy for mismatched chainID and currency symbol when adding custom networks ([#22648](https://github.com/MetaMask/metamask-extension/pull/22648)) +- Improved UX to display multiple custom networks with the same ID but different RPC URLs in network selection ([#22693](https://github.com/MetaMask/metamask-extension/pull/22693)) +- Updated the connections icon to display the connected dapp icon ([#22634](https://github.com/MetaMask/metamask-extension/pull/22634)) +- Added title to Personal Sign page ([#22749](https://github.com/MetaMask/metamask-extension/pull/22749)) +- Update padding in accounts details modal ([#22775](https://github.com/MetaMask/metamask-extension/pull/22775)) +- [MMI] Refactored display of custodian deep link to improve efficiency and fix potential race conditions ([#22825](https://github.com/MetaMask/metamask-extension/pull/22825)) +- [MMI] Hid the new buy & receive button under MMI build for a cleaner interface ([#22384](https://github.com/MetaMask/metamask-extension/pull/22384)) + +### Fixed +- Fixed cancel transaction signing from activity list ([#22676](https://github.com/MetaMask/metamask-extension/pull/22676)) +- Fixed incorrect account name display in account details and receive list ([#22844](https://github.com/MetaMask/metamask-extension/pull/22844)) +- Fixed IPFS NFTs fetching issue for manually imported NFTs ([#22627](https://github.com/MetaMask/metamask-extension/pull/22627)) +- Fixed "send max" ETH calculation issue to adjust for gas changes ([#22694](https://github.com/MetaMask/metamask-extension/pull/22694)) +- Fixed sign button color and updated deprecated components in SignatureRequestOriginalWarning for visual consistency ([#22741](https://github.com/MetaMask/metamask-extension/pull/22741)) + +## [11.10.1] +### Fixed +- Fix custom network editing, via Settings, for some networks ([#23140](https://github.com/MetaMask/metamask-extension/pull/23140)) + ## [11.10.0] ### Added - Added preset network image avatars in the 'Select a network' pop-up ([#22643](https://github.com/MetaMask/metamask-extension/pull/22643)) @@ -4389,7 +4784,44 @@ Update styles and spacing on the critical error page ([#20350](https://github.c ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.10.0...HEAD + +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.16.7...HEAD +[11.16.7]: https://github.com/MetaMask/metamask-extension/compare/v11.16.6...v11.16.7 +[11.16.6]: https://github.com/MetaMask/metamask-extension/compare/v11.16.5...v11.16.6 +[11.16.5]: https://github.com/MetaMask/metamask-extension/compare/v11.16.4...v11.16.5 +[11.16.4]: https://github.com/MetaMask/metamask-extension/compare/v11.16.3...v11.16.4 +[11.16.3]: https://github.com/MetaMask/metamask-extension/compare/v11.16.2...v11.16.3 +[11.16.2]: https://github.com/MetaMask/metamask-extension/compare/v11.16.1...v11.16.2 +[11.16.1]: https://github.com/MetaMask/metamask-extension/compare/v11.16.0...v11.16.1 +[11.16.0]: https://github.com/MetaMask/metamask-extension/compare/v11.15.6...v11.16.0 +[11.15.6]: https://github.com/MetaMask/metamask-extension/compare/v11.15.5...v11.15.6 +[11.15.5]: https://github.com/MetaMask/metamask-extension/compare/v11.15.4...v11.15.5 +[11.15.4]: https://github.com/MetaMask/metamask-extension/compare/v11.15.3...v11.15.4 +[11.15.3]: https://github.com/MetaMask/metamask-extension/compare/v11.15.2...v11.15.3 +[11.15.2]: https://github.com/MetaMask/metamask-extension/compare/v11.15.1...v11.15.2 +[11.15.1]: https://github.com/MetaMask/metamask-extension/compare/v11.15.0...v11.15.1 +[11.15.0]: https://github.com/MetaMask/metamask-extension/compare/v11.14.5...v11.15.0 +[11.14.5]: https://github.com/MetaMask/metamask-extension/compare/v11.14.4...v11.14.5 +[11.14.4]: https://github.com/MetaMask/metamask-extension/compare/v11.14.3...v11.14.4 +[11.14.3]: https://github.com/MetaMask/metamask-extension/compare/v11.14.2...v11.14.3 +[11.14.2]: https://github.com/MetaMask/metamask-extension/compare/v11.14.1...v11.14.2 +[11.14.1]: https://github.com/MetaMask/metamask-extension/compare/v11.14.0...v11.14.1 +[11.14.0]: https://github.com/MetaMask/metamask-extension/compare/v11.13.3...v11.14.0 +[11.13.3]: https://github.com/MetaMask/metamask-extension/compare/v11.13.2...v11.13.3 +[11.13.2]: https://github.com/MetaMask/metamask-extension/compare/v11.13.1...v11.13.2 +[11.13.1]: https://github.com/MetaMask/metamask-extension/compare/v11.13.0...v11.13.1 +[11.13.0]: https://github.com/MetaMask/metamask-extension/compare/v11.12.4...v11.13.0 +[11.12.4]: https://github.com/MetaMask/metamask-extension/compare/v11.12.3...v11.12.4 +[11.12.3]: https://github.com/MetaMask/metamask-extension/compare/v11.12.2...v11.12.3 +[11.12.2]: https://github.com/MetaMask/metamask-extension/compare/v11.12.1...v11.12.2 +[11.12.1]: https://github.com/MetaMask/metamask-extension/compare/v11.12.0...v11.12.1 +[11.12.0]: https://github.com/MetaMask/metamask-extension/compare/v11.11.4...v11.12.0 +[11.11.4]: https://github.com/MetaMask/metamask-extension/compare/v11.11.3...v11.11.4 +[11.11.3]: https://github.com/MetaMask/metamask-extension/compare/v11.11.2...v11.11.3 +[11.11.2]: https://github.com/MetaMask/metamask-extension/compare/v11.11.1...v11.11.2 +[11.11.1]: https://github.com/MetaMask/metamask-extension/compare/v11.11.0...v11.11.1 +[11.11.0]: https://github.com/MetaMask/metamask-extension/compare/v11.10.1...v11.11.0 +[11.10.1]: https://github.com/MetaMask/metamask-extension/compare/v11.10.0...v11.10.1 [11.10.0]: https://github.com/MetaMask/metamask-extension/compare/v11.9.5...v11.10.0 [11.9.5]: https://github.com/MetaMask/metamask-extension/compare/v11.9.4...v11.9.5 [11.9.4]: https://github.com/MetaMask/metamask-extension/compare/v11.9.3...v11.9.4 diff --git a/README.md b/README.md index d9a31a86a8b0..efa0be51019b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,9 @@ For up to the minute news, follow our [Twitter](https://twitter.com/metamask) or To learn how to develop MetaMask-compatible applications, visit our [Developer Docs](https://metamask.github.io/metamask-docs/). -To learn how to contribute to the MetaMask project itself, visit our [Internal Docs](https://github.com/MetaMask/metamask-extension/tree/develop/docs). +To learn how to contribute to the MetaMask codebase, visit our [Contributor Docs](https://github.com/MetaMask/contributor-docs). + +To learn how to contribute to the MetaMask Extension project itself, visit our [Extension Docs](https://github.com/MetaMask/metamask-extension/tree/develop/docs). ## GitHub Codespaces quickstart @@ -81,6 +83,9 @@ If you are using VS Code and are unable to make commits from the source control To start a development build (e.g. with logging and file watching) run `yarn start`. +Alternatively, one can skip wallet onboarding and preload the vault state with a specific SRP by adding `TEST_SRP=''` and `PASSWORD=''` to the `.metamaskrc` file and running `yarn start:skip-onboarding`. + + #### React and Redux DevTools To start the [React DevTools](https://github.com/facebook/react-devtools), run `yarn devtools:react` with a development build installed in a browser. This will open in a separate window; no browser extension is required. @@ -117,21 +122,23 @@ Before running e2e tests, ensure you've run `yarn install` to download dependenc 1. Use `yarn download-builds:test` to quickly download and unzip test builds for Chrome and Firefox into the `./dist/` folder. This method is fast and convenient for standard testing. 2. Create a custom test build: for testing against different build types, use `yarn build:test`. This command allows you to generate test builds for various types, including: - - `yarn build:test` for main build - - `yarn build:test:flask` for flask build - - `yarn build:test:mmi` for mmi build - - `yarn build:test:mv3` for mv3 build -3. Start a test build with live changes: `yarn start:test` is particularly useful for development. It starts a test build that automatically recompiles application code upon changes.This option is ideal for iterative testing and development. -This command also allows you to generate test builds for various types, including: - - `yarn start:test` for main build - - `yarn start:test:flask` for flask build - - `yarn start:test:mv3` for mv3 build + - `yarn build:test` for main build + - `yarn build:test:flask` for flask build + - `yarn build:test:mmi` for mmi build + - `yarn build:test:mv2` for mv2 build +3. Start a test build with live changes: `yarn start:test` is particularly useful for development. It starts a test build that automatically recompiles application code upon changes. This option is ideal for iterative testing and development. This command also allows you to generate test builds for various types, including: + - `yarn start:test` for main build + - `yarn start:test:flask` for flask build + - `yarn start:test:mv2` for mv2 build Note: The `yarn start:test` command (which initiates the testDev build type) has LavaMoat disabled for both the build system and the application, offering a streamlined testing experience during development. On the other hand, `yarn build:test` enables LavaMoat for enhanced security in both the build system and application, mirroring production environments more closely. #### Running Tests + Once you have your test build ready, choose the browser for your e2e tests: + - For Firefox, run `yarn test:e2e:firefox`. + - Note: If you are running Firefox as a snap package on Linux, ensure you enable the appropriate environment variable: `FIREFOX_SNAP=true yarn test:e2e:firefox` - For Chrome, run `yarn test:e2e:chrome`. These scripts support additional options for debugging. Use `--help`to see all available options. @@ -141,10 +148,11 @@ These scripts support additional options for debugging. Use `--help`to see all a Single e2e tests can be run with `yarn test:e2e:single test/e2e/tests/TEST_NAME.spec.js` along with the options below. ```console - --browser Set the browser used; either 'chrome' or 'firefox'. - [string] [choices: "chrome", "firefox"] + --browser Set the browser to be used; specify 'chrome', 'firefox', 'all' + or leave unset to run on 'all' by default. + [string] [default: 'all'] --debug Run tests in debug mode, logging each driver interaction - [boolean] [default: false] + [boolean] [default: true] --retries Set how many times the test should be retried upon failure. [number] [default: 0] --leave-running Leaves the browser running after a test fails, along with @@ -155,10 +163,10 @@ Single e2e tests can be run with `yarn test:e2e:single test/e2e/tests/TEST_NAME. ``` For example, to run the `account-details` tests using Chrome, with debug logging and with the browser set to remain open upon failure, you would use: -`yarn test:e2e:single test/e2e/tests/account-menu/account-details.spec.js --browser=chrome --debug --leave-running` - +`yarn test:e2e:single test/e2e/tests/account-menu/account-details.spec.js --browser=chrome --leave-running` #### Running e2e tests against specific feature flag + While developing new features, we often use feature flags. As we prepare to make these features generally available (GA), we remove the feature flags. Existing feature flags are listed in the `.metamaskrc.dist` file. To execute e2e tests with a particular feature flag enabled, it's necessary to first generate a test build with that feature flag activated. There are two ways to achieve this: - To enable a feature flag in your local configuration, you should first ensure you have a `.metamaskrc` file copied from `.metamaskrc.dist`. Then, within your local `.metamaskrc` file, you can set the desired feature flag to true. Following this, a test build with the feature flag enabled can be created by executing `yarn build:test`. @@ -166,7 +174,7 @@ While developing new features, we often use feature flags. As we prepare to make - Alternatively, for enabling a feature flag directly during the test build creation, you can pass the parameter as true via the command line. For instance, activating the MULTICHAIN feature flag can be done by running `MULTICHAIN=1 yarn build:test` or `MULTICHAIN=1 yarn start:test` . This method allows for quick adjustments to feature flags without altering the `.metamaskrc` file. Once you've created a test build with the desired feature flag enabled, proceed to run your tests as usual. Your tests will now run against the version of the extension with the specific feature flag activated. For example: -`yarn test:e2e:single test/e2e/tests/account-menu/account-details.spec.js --browser=chrome --debug --leave-running` +`yarn test:e2e:single test/e2e/tests/account-menu/account-details.spec.js --browser=chrome` This approach ensures that your e2e tests accurately reflect the user experience for the upcoming GA features. @@ -177,7 +185,7 @@ Different build types have different e2e tests sets. In order to run them look i ```console "test:e2e:chrome:mmi": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --mmi", "test:e2e:chrome:snaps": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --snaps", - "test:e2e:chrome:mv3": "ENABLE_MV3=true SELENIUM_BROWSER=chrome node test/e2e/run-all.js", + "test:e2e:firefox": "ENABLE_MV3=false SELENIUM_BROWSER=firefox node test/e2e/run-all.js", ``` #### Note: Running MMI e2e tests @@ -213,6 +221,9 @@ Whenever you change dependencies (adding, removing, or updating, either in `pack - `rm -rf node_modules/ && yarn && yarn lavamoat:auto` - Keep in mind that any kind of dynamic import or dynamic use of globals may elude LavaMoat's static analysis. Refer to the LavaMoat documentation or ask for help if you run into any issues. +- The Attributions file + - If you are a MetaMask team member and your PR is on a repository branch, you can use the bot command `@metamaskbot update-attributions` to ask the MetaMask bot to automatically update the attributions file for you. + - Manual update: run `yarn attributions:generate`. ## Architecture diff --git a/app/_locales/am/messages.json b/app/_locales/am/messages.json index ef3814839fa5..a4a0dc58e868 100644 --- a/app/_locales/am/messages.json +++ b/app/_locales/am/messages.json @@ -615,9 +615,6 @@ "send": { "message": "ላክ" }, - "sendTokens": { - "message": "ተለዋጭ ስሞችን ላክ" - }, "settings": { "message": "ቅንብሮች" }, diff --git a/app/_locales/ar/messages.json b/app/_locales/ar/messages.json index 870380bab435..bc33690c7945 100644 --- a/app/_locales/ar/messages.json +++ b/app/_locales/ar/messages.json @@ -627,9 +627,6 @@ "send": { "message": "إرسال" }, - "sendTokens": { - "message": "إرسال عملات رمزية" - }, "settings": { "message": "الإعدادات" }, diff --git a/app/_locales/bg/messages.json b/app/_locales/bg/messages.json index 079db998a72f..cfe0f8de68a3 100644 --- a/app/_locales/bg/messages.json +++ b/app/_locales/bg/messages.json @@ -626,9 +626,6 @@ "send": { "message": "Изпращане" }, - "sendTokens": { - "message": "Изпращане на жетони" - }, "settings": { "message": "Настройки" }, diff --git a/app/_locales/bn/messages.json b/app/_locales/bn/messages.json index af9750c07cb8..592a9a593f28 100644 --- a/app/_locales/bn/messages.json +++ b/app/_locales/bn/messages.json @@ -624,9 +624,6 @@ "send": { "message": "পাঠান" }, - "sendTokens": { - "message": "টোকেনগুলি পাঠান" - }, "settings": { "message": "সেটিংস" }, diff --git a/app/_locales/ca/messages.json b/app/_locales/ca/messages.json index ddc4306f04e5..93555423be6d 100644 --- a/app/_locales/ca/messages.json +++ b/app/_locales/ca/messages.json @@ -611,9 +611,6 @@ "send": { "message": "Envia" }, - "sendTokens": { - "message": "Enviar Fitxes" - }, "settings": { "message": "Configuració" }, diff --git a/app/_locales/cs/messages.json b/app/_locales/cs/messages.json index 32573b29bf0a..fc050b199d2d 100644 --- a/app/_locales/cs/messages.json +++ b/app/_locales/cs/messages.json @@ -289,9 +289,6 @@ "send": { "message": "Odeslat" }, - "sendTokens": { - "message": "Odeslat tokeny" - }, "settings": { "message": "Nastavení" }, diff --git a/app/_locales/da/messages.json b/app/_locales/da/messages.json index 25fc8668fd0d..9d89b573a536 100644 --- a/app/_locales/da/messages.json +++ b/app/_locales/da/messages.json @@ -608,9 +608,6 @@ "selectType": { "message": "Vælg type" }, - "sendTokens": { - "message": "Send tokens" - }, "settings": { "message": "Indstillinger " }, diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 257611b700c5..731a805b1f2a 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -130,12 +130,21 @@ "account": { "message": "Konto" }, + "accountActivity": { + "message": "Kontoaktivität" + }, + "accountActivityText": { + "message": "Wählen Sie die Konten aus, über die Sie benachrichtigt werden möchten:" + }, "accountDetails": { "message": "Kontodetails" }, "accountIdenticon": { "message": "Konto-Identicon" }, + "accountIsntConnectedToastText": { + "message": "$1 ist nicht mit $2 verbunden" + }, "accountName": { "message": "Kontoname" }, @@ -153,6 +162,12 @@ "accountSelectionRequired": { "message": "Sie müssen ein Konto auswählen!" }, + "accounts": { + "message": "Konten" + }, + "accountsConnected": { + "message": "Konten wurden verbunden" + }, "active": { "message": "Aktiv" }, @@ -243,6 +258,9 @@ "addIPFSGateway": { "message": "Fügen Sie Ihr bevorzugtes IPFS-Gateway hinzu." }, + "addImportAccount": { + "message": "Konto oder Hardware-Wallet hinzufügen" + }, "addMemo": { "message": "Notiz hinzufügen" }, @@ -256,6 +274,9 @@ "message": "Diese Netzwerkverbindung ist von Dritten abhängig. Diese Verbindung könnte unzuverlässiger sein oder Dritten erlauben, Ihre Aktivitäten zu verfolgen. $1", "description": "$1 is Learn more link" }, + "addNewAccount": { + "message": "Ein neues Konto hinzufügen" + }, "addNewToken": { "message": "Neues Token hinzufügen" }, @@ -265,6 +286,12 @@ "addNfts": { "message": "NFTs hinzufügen" }, + "addSnapAccountToggle": { + "message": "„Konto-Snap (Beta) hinzufügen“ aktivieren" + }, + "addSnapAccountsDescription": { + "message": "Wenn Sie diese Funktion aktivieren, haben Sie die Möglichkeit, die neuen Beta-Konto-Snaps direkt aus Ihrer Kontoliste hinzuzufügen. Denken Sie bei der Installation eines Konto-Snaps bitte daran, dass es sich dabei um einen Dienst von Drittanbietern handelt." + }, "addSuggestedNFTs": { "message": "Vorgeschlagene NFTs hinzufügen" }, @@ -281,6 +308,9 @@ "addingCustomNetwork": { "message": "Netzwerk wird hinzugefügt" }, + "addingTokens": { + "message": "Hinzufügen von Token" + }, "address": { "message": "Adresse" }, @@ -316,9 +346,27 @@ "airgapVault": { "message": "AirGap-Tresor" }, + "alert": { + "message": "Warnhinweis" + }, + "alertBannerMultipleAlertsDescription": { + "message": "Wenn Sie diese Anfrage genehmigen, könnten Dritte, die für Betrügereien bekannt sind, alle Ihre Assets an sich reißen." + }, + "alertBannerMultipleAlertsTitle": { + "message": "Mehrere Benachrichtigungen!" + }, "alertDisableTooltip": { "message": "Dies kann in „Einstellungen > Benachrichtigungen“ geändert werden." }, + "alertModalAcknowledge": { + "message": "Ich habe das Risiko erkannt und möchte trotzdem fortfahren" + }, + "alertModalDetails": { + "message": "Details zum Warnhinweis" + }, + "alertModalReviewAllAlerts": { + "message": "Alle Benachrichtigungen überprüfen" + }, "alertSettingsUnconnectedAccount": { "message": "Eine Webseite mit einem nicht verknüpften Konto durchsuchen" }, @@ -334,6 +382,9 @@ "alerts": { "message": "Benachrichtigungen" }, + "all": { + "message": "Alle" + }, "allCustodianAccountsConnectedSubtitle": { "message": "Sie haben entweder bereits alle Ihre Verwahrungskonten verbunden oder haben kein Konto, dass Sie mit MetaMask Institutional verbinden könnten." }, @@ -344,23 +395,26 @@ "message": "Alle Ihre $1.", "description": "$1 is the symbol or name of the token that the user is approving spending" }, + "allPermissions": { + "message": "Alle Genehmigungen" + }, "allYourNFTsOf": { "message": "Alle Ihre NFTs von $1.", "description": "$1 is a link to contract on the block explorer when we're not able to retrieve a erc721 or erc1155 name" }, - "allowExternalExtensionTo": { - "message": "Erlauben dieser externen Erweiterung auf:" + "allow": { + "message": "Genehmigen" + }, + "allowMmiToConnectToCustodian": { + "message": "Dadurch kann MMI sich zum Importieren Ihrer Konten mit $1 verbinden." + }, + "allowNotifications": { + "message": "Benachrichtigungen erlauben" }, "allowSpendToken": { "message": "Genehmigung zum Zugriff auf Ihr $1 erteilen?", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "Erlauben Sie dieser Seite:" - }, - "allowThisSnapTo": { - "message": "Erlauben Sie diesem Snap Folgendes:" - }, "allowWithdrawAndSpend": { "message": "$1 erlauben, bis zu dem folgenden Betrag abzuheben und auszugeben:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -368,6 +422,23 @@ "amount": { "message": "Betrag" }, + "amountReceived": { + "message": "Empfangener Betrag" + }, + "amountSent": { + "message": "Gesendeter Betrag" + }, + "andForListItems": { + "message": "$1 und $2", + "description": "$1 is the first item, $2 is the last item in a list of items. Used in Snap Install Warning modal." + }, + "andForTwoItems": { + "message": "$1 und $2 ", + "description": "$1 is the first item, $2 is the second item. Used in Snap Install Warning modal." + }, + "announcements": { + "message": "Ankündigungen" + }, "appDescription": { "message": "Ethereum Browsererweiterung", "description": "The description of the application" @@ -402,6 +473,10 @@ "approveButtonText": { "message": "Genehmigen" }, + "approveIncreaseAllowance": { + "message": "$1 Ausgabenobergrenze erhöhen", + "description": "The token symbol that is being approved" + }, "approveSpendingCap": { "message": "$1 Ausgabenobergrenze genehmigen", "description": "The token symbol that is being approved" @@ -427,6 +502,10 @@ "message": "Genehmigt am $1", "description": "$1 is the approval date for a permission" }, + "approvedOnForAccounts": { + "message": "Genehmigt am $1 für $2", + "description": "$1 is the approval date for a permission. $2 is the AvatarGroup component displaying account images." + }, "areYouSure": { "message": "Sind Sie sicher?" }, @@ -439,12 +518,21 @@ "attemptSendingAssets": { "message": "Wenn Sie versuchen, Assets direkt von einem Netzwerk in ein anderes zu senden, kann dies zu einem dauerhaften Asset-Verlust führen. Verwenden Sie unbedingt eine Bridge." }, + "attemptSendingAssetsWithPortfolio": { + "message": "Sie können Ihre Assets verlieren, wenn Sie versuchen, sie von einem anderen Netzwerk zu versenden. Übertragen Sie Gelder sicher zwischen den Netzwerken, indem Sie eine Bridge wie $1 verwenden." + }, + "attemptToCancelSwapForFree": { + "message": "Versuch, den Swap kostenlos zu stornieren" + }, "attemptingConnect": { "message": "Versuch einer Verbindung zur Blockchain." }, "attributions": { "message": "Zuschreibungen" }, + "auroraRpcDeprecationMessage": { + "message": "Die Infura RPC URL unterstützt Aurora nicht mehr." + }, "authorizedPermissions": { "message": "Sie haben die folgenden Genehmigungen autorisiert." }, @@ -471,22 +559,25 @@ "message": "Zurück" }, "backup": { - "message": "Datensicherung" + "message": "Sichern" }, "backupApprovalInfo": { "message": "Dieser geheime Code ist zum Wiedererlangen Ihrer Wallet erforderlich, falls Sie Ihr Gerät verlieren, Ihr Passwort vergessen, MetaMask neu installieren müssen oder auf einem anderen Gerät auf Ihre Wallet zugreifen möchten." }, "backupApprovalNotice": { - "message": "Sichern Sie Ihren geheimen Wiederherstellungscode, um Ihre Wallet und Ihr Geld geschützt zu halten." + "message": "Sichern Sie Ihre geheime Wiederherstellungsphrase, um Ihre Wallet und Ihr Geld geschützt zu halten." + }, + "backupKeyringSnapReminder": { + "message": "Vergewissern Sie sich, dass Sie eigenständig Zugang zu von diesem Snap erstellten Konten haben, bevor sie ihn entfernen" }, "backupNow": { "message": "Jetzt sichern" }, "backupUserData": { - "message": "Erstellen Sie ein Backup Ihrer Daten." + "message": "Sichern Sie Ihre Daten" }, "backupUserDataDescription": { - "message": "Sie können ein Backup der Benutzereinstellungen, die Präferenzen und Kontoadressen enthalten, in einer JSON-Datei erstellen." + "message": "Sie können Daten wie Ihre Kontakte und Einstellungen sichern." }, "balance": { "message": "Guthaben:" @@ -500,6 +591,30 @@ "basic": { "message": "Grundlegend" }, + "basicConfigurationBannerCTA": { + "message": "Grundfunktionalität einschalten" + }, + "basicConfigurationBannerTitle": { + "message": "Grundfunktionalität ist ausgeschaltet" + }, + "basicConfigurationLabel": { + "message": "Grundfunktionalität" + }, + "basicConfigurationModalCheckbox": { + "message": "Ich verstehe und möchte fortfahren" + }, + "basicConfigurationModalDisclaimerOff": { + "message": "Das bedeutet, dass Sie Ihre Zeit auf MetaMask nicht vollständig optimieren können. Grundlegende Funktionen (wie Token-Details, optimale Gas-Einstellungen und andere) stehen Ihnen nicht zur Verfügung." + }, + "basicConfigurationModalDisclaimerOn": { + "message": "Um Ihre Zeit auf MetaMask zu optimieren, müssen Sie diese Funktion einschalten. Grundlegende Funktionen (wie Token-Details, optimale Gas-Einstellungen und andere) sind für das Web3-Erlebnis wichtig." + }, + "basicConfigurationModalHeadingOff": { + "message": "Grundfunktionalität ausschalten" + }, + "basicConfigurationModalHeadingOn": { + "message": "Grundfunktionalität einschalten" + }, "beCareful": { "message": "Sein Sie vorsichtig." }, @@ -571,6 +686,9 @@ "blockaidDescriptionTransferFarming": { "message": "Wenn Sie diese Anfrage genehmigen, wird eine dritte Partei, die für Betrügereien bekannt ist, Ihre gesamten Assets an sich reißen." }, + "blockaidMessage": { + "message": "Wahrung der Privatsphäre – keine Daten werden an Dritte weitergegeben. Verfügbar auf Arbitrum, Avalanche, BNB chain, Ethereum Mainnet, Linea, Optimism, Polygon, Base und Sepolia." + }, "blockaidTitleDeceptive": { "message": "Dies ist eine betrügerische Anfrage." }, @@ -586,6 +704,9 @@ "bridge": { "message": "Bridge" }, + "bridgeDontSend": { + "message": "Bridge, nicht senden" + }, "browserNotSupported": { "message": "Ihr Browser wird nicht unterstützt …" }, @@ -598,6 +719,9 @@ "busy": { "message": "Ausgelastet" }, + "buyAndSell": { + "message": "Kaufen und Verkaufen" + }, "buyAsset": { "message": "$1 kaufen", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -609,6 +733,10 @@ "buyNow": { "message": "Jetzt kaufen" }, + "buyToken": { + "message": "$1 kaufen", + "description": "$1 is the token symbol" + }, "bytes": { "message": "Bytes" }, @@ -618,9 +746,6 @@ "cancel": { "message": "Stornieren" }, - "cancelEdit": { - "message": "Bearbeiten stornieren" - }, "cancelPopoverTitle": { "message": "Transaktion stornieren" }, @@ -647,6 +772,9 @@ "chainIdExistsErrorMsg": { "message": "Diese Chain-ID wird derzeit vom $1-Netzwerk verwendet." }, + "chainListReturnedDifferentTickerSymbol": { + "message": "Dieses Token-Symbol stimmt nicht mit dem eingegebenen Netzwerknamen oder der Chain-ID überein. Viele beliebte Token verwenden ähnliche Symbole, die Betrüger nutzen können, um Sie dazu zu bringen, ihnen im Gegenzug einen wertvolleren Token zu senden. Überprüfen Sie alles, bevor Sie fortfahren." + }, "chooseYourNetwork": { "message": "Wählen Sie Ihr Netzwerk" }, @@ -682,9 +810,19 @@ "close": { "message": "Schließen" }, + "closeExtension": { + "message": "Erweiterung schließen" + }, + "closeWindowAnytime": { + "message": "Sie können dieses Fenster jederzeit schließen." + }, "coingecko": { "message": "CoinGecko" }, + "comboNoOptions": { + "message": "Keine Option gefunden", + "description": "Default text shown in the combo field dropdown if no options." + }, "configureSnapPopupDescription": { "message": "Sie verlassen jetzt MetaMask, um diesen Snap zu konfigurieren." }, @@ -703,12 +841,42 @@ "confirm": { "message": "Bestätigen" }, + "confirmAlertModalAcknowledge": { + "message": "Ich habe die Benachrichtigungen zur Kenntnis genommen und möchte trotzdem fortfahren" + }, + "confirmAlertModalDetails": { + "message": "Wenn Sie sich anmelden, könnten Dritte, die für Betrügereien bekannt sind, all Ihre Assets an sich reißen. Lesen Sie bitte die Benachrichtigungen, bevor Sie fortfahren." + }, + "confirmAlertModalTitle": { + "message": "Ihre Assets könnten gefährdet sein" + }, + "confirmConnectCustodianRedirect": { + "message": "Sobald Sie auf „Weiter“ klicken, leiten wir Sie weiter zu $1." + }, + "confirmConnectCustodianText": { + "message": "Zum Verbinden Ihrer Konten melden Sie sich bitte bei Ihrem $1-Konto an und klicken dann auf die Schaltfläche „Mit MMI verbinden“." + }, + "confirmConnectionTitle": { + "message": "Verbindung mit $1 bestätigen" + }, "confirmPassword": { "message": "Passwort bestätigen" }, "confirmRecoveryPhrase": { "message": "Geheime Wiederherstellungsphrase bestätigen" }, + "confirmTitleDescContractInteractionTransaction": { + "message": "Bestätigen Sie diese Transaktion nur, wenn Sie den Inhalt vollständig verstehen und der anfragenden Website vertrauen." + }, + "confirmTitleDescSignature": { + "message": "Bestätigen Sie diese Nachricht nur, wenn Sie dem Inhalt zustimmen und der anfragenden Website vertrauen." + }, + "confirmTitleSignature": { + "message": "Signaturanfrage" + }, + "confirmTitleTransaction": { + "message": "Transaktionsanfrage" + }, "confirmed": { "message": "Bestätigt" }, @@ -724,9 +892,15 @@ "connect": { "message": "Verbinden" }, + "connectAccount": { + "message": "Konto verbinden" + }, "connectAccountOrCreate": { "message": "Konto verbinden oder neues erstellen" }, + "connectAccounts": { + "message": "Konten verbinden" + }, "connectCustodialAccountMenu": { "message": "Verwahrungskonto verbinden" }, @@ -736,36 +910,25 @@ "connectCustodialAccountTitle": { "message": "Verwahrungskonten" }, + "connectCustodianAccounts": { + "message": "$1 Konten verbinden" + }, "connectManually": { "message": "Manuelle Verbindung zur aktuellen Seite" }, + "connectMoreAccounts": { + "message": "Weitere Konten verbinden" + }, "connectSnap": { "message": "Mit $1 verbinden", "description": "$1 is the snap for which a connection is being requested." }, - "connectTo": { - "message": "Verbindung mit $1 wird hergestellt", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "Mit all Ihren $1 verbinden", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "Konten", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "Verbindung mit $1 wird hergestellt", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1-Konten", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "Mit MetaMask verbinden" }, + "connectedAccounts": { + "message": "Verbundene Konten" + }, "connectedAccountsDescriptionPlural": { "message": "Sie haben $1 Konten mit dieser Seite verbunden.", "description": "$1 is the number of accounts" @@ -776,6 +939,13 @@ "connectedAccountsEmptyDescription": { "message": "MetaMask ist nicht mit dieser Seite verbunden. Um sich mit einer Web3-Seite zu verbinden, finden und klicken Sie auf die Schaltfläche „Verbinden“." }, + "connectedAccountsListTooltip": { + "message": "$1 kann den Kontostand, die Adresse und die Aktivitäten einsehen und Transaktionen vorschlagen, um für verbundene Konten zu genehmigen.", + "description": "$1 is the origin name" + }, + "connectedAccountsToast": { + "message": "Verbundene Konten aktualisiert" + }, "connectedSites": { "message": "Verbundene Seiten" }, @@ -787,12 +957,21 @@ "message": "$1 ist mit keiner Seite verbunden.", "description": "$1 is the account name" }, + "connectedSnapAndNoAccountDescription": { + "message": "MetaMask ist mit dieser Seite verbunden, aber es sind noch keine Konten verbunden" + }, + "connectedWith": { + "message": "Verbunden mit" + }, "connecting": { "message": "Verbindung wird hergestellt ..." }, "connectingTo": { "message": "Verbindung mit $1 wird hergestellt" }, + "connectingToDeprecatedNetwork": { + "message": "‚$1‘ wird eingestellt und funktioniert möglicherweise nicht mehr. Versuchen Sie ein anderes Netzwerk." + }, "connectingToGoerli": { "message": "Verbindungsaufbau zum Goerli-Testnetzwerk" }, @@ -802,6 +981,9 @@ "connectingToLineaMainnet": { "message": "Verbindung zum Linea Mainnet wird hergestellt" }, + "connectingToLineaSepolia": { + "message": "Herstellung der Verbindung zum Linea-Sepolia-Testnetzwerk" + }, "connectingToMainnet": { "message": "Verbindung zum Ethereum Mainnet wird hergestellt" }, @@ -831,6 +1013,12 @@ "continue": { "message": "Weiter" }, + "continueMmiOnboarding": { + "message": "Mit Einführung in MetaMask Institutional fortfahren" + }, + "continueToWallet": { + "message": "Weiter zur Wallet" + }, "contract": { "message": "Contract" }, @@ -882,6 +1070,9 @@ "copyAddress": { "message": "Adresse in die Zwischenablage kopieren" }, + "copyPrivateKey": { + "message": "Privaten Schlüssel kopieren" + }, "copyRawTransactionData": { "message": "Roh-Transaktionsdaten kopieren" }, @@ -900,6 +1091,15 @@ "createPassword": { "message": "Passwort erstellen" }, + "createSnapAccountDescription": { + "message": "$1 möchte ein neues Konto zu MetaMask hinzufügen." + }, + "createSnapAccountTitle": { + "message": "Konto erstellen" + }, + "crossChainSwapsLink": { + "message": "Netzwerkübergreifender Austausch mit MetaMask Portfolio" + }, "cryptoCompare": { "message": "CryptoCompare" }, @@ -950,10 +1150,16 @@ "message": "Verwahrer" }, "custodianAccountAddedDesc": { - "message": "Sie können jetzt Verwahrungskonten in MetaMask Institutional verwenden." + "message": "Sie können jetzt Ihre Konten in MetaMask Institutional verwenden." }, "custodianAccountAddedTitle": { - "message": "Ausgewählte Verwahrungskonten wurden hinzugefügt." + "message": "Ausgewählte $1-Konten wurden hinzugefügt." + }, + "custodianQRCodeScan": { + "message": "QR-Code mit Ihrer $1-Mobilapp scannen" + }, + "custodianQRCodeScanDescription": { + "message": "Oder melden Sie sich bei Ihrem $1-Konto an und klicken Sie auf die Schaltfläche „Mit MMI verbinden“." }, "custodianReplaceRefreshTokenChangedFailed": { "message": "Bitte gehen Sie zu $1 und klicken Sie in der Benutzeroberfläche auf die Schaltfläche „Mit MMI verbinden“, um Ihre Konten erneut mit MMI zu verbinden." @@ -1017,7 +1223,7 @@ "message": "Die Token-Erkennung ist in diesem Netzwerk noch nicht verfügbar. Bitte importieren Sie das Token manuell und stellen Sie sicher, dass Sie ihm vertrauen. Erfahren Sie mehr über $1." }, "customTokenWarningInTokenDetectionNetwork": { - "message": "Vergewissern Sie sich vor dem manuellen Importieren eines Tokens, dass Sie ihm vertrauen. Erfahren Sie mehr über $1." + "message": "Jeder kann einen Token erstellen, auch gefälschte Versionen von bestehenden Token. Erfahren Sie mehr über $1." }, "customTokenWarningInTokenDetectionNetworkWithTDOFF": { "message": "Stellen Sie sicher, dass Sie einem Token vertrauen, bevor Sie es importieren. Erfahren Sie, wie Sie 1$ vermeiden und die Token-Erkennung $2 aktivieren können." @@ -1025,6 +1231,12 @@ "customerSupport": { "message": "Kundensupport" }, + "customizeYourNotifications": { + "message": "Passen Sie Ihre Benachrichtigungen an" + }, + "customizeYourNotificationsText": { + "message": "Schalten Sie die Arten von Benachrichtigungen ein, die Sie empfangen möchten:" + }, "dappRequestedSpendingCap": { "message": "Von der Seite beantragte Ausgabenobergrenze" }, @@ -1108,6 +1320,18 @@ "deposit": { "message": "Einzahlung" }, + "deprecatedGoerliNtwrkMsg": { + "message": "Aufgrund von Aktualisierungen des Ethereum-Systems wird das Goerli-Testnetzwerk bald eingestellt." + }, + "deprecatedNetwork": { + "message": "Dieses Netzwerk ist veraltet" + }, + "deprecatedNetworkButtonMsg": { + "message": "Verstanden" + }, + "deprecatedNetworkDescription": { + "message": "Das Netzwerk, zu dem Sie eine Verbindung herstellen möchten, wird von Metamask nicht mehr unterstützt. $1" + }, "description": { "message": "Beschreibung" }, @@ -1115,110 +1339,20 @@ "message": "Beschreibung von $1", "description": "$1 represents the name of the snap" }, - "desktopApp": { - "message": "Desktop-App" - }, - "desktopConnectionCriticalErrorDescription": { - "message": "Dieser Fehler könnte unregelmäßig auftreten, also versuchen Sie, Ihr die Erweiterung neu zu starten oder MetaMask Desktop zu deaktivieren." - }, - "desktopConnectionCriticalErrorTitle": { - "message": "MetaMask hat Probleme beim Starten." - }, - "desktopConnectionLostErrorDescription": { - "message": "Bitte stellen Sie sicher, dass die Desktop-App ausgeführt wird oder deaktivieren Sie MetaMask Desktop." - }, - "desktopConnectionLostErrorTitle": { - "message": "MetaMask Desktop-Verbindung wurde unterbrochen" - }, - "desktopDisableButton": { - "message": "Desktop-App deaktivieren" - }, - "desktopDisableErrorCTA": { - "message": "MetaMask Desktop deaktivieren" - }, - "desktopEnableButton": { - "message": "Desktop-App aktivieren" - }, - "desktopEnableButtonDescription": { - "message": "Klicken Sie, um alle Hintergrundprozesse in der Desktop-App auszuführen." - }, - "desktopErrorNavigateSettingsCTA": { - "message": "Zurück zur Seite „Einstellungen“" - }, - "desktopErrorRestartMMCTA": { - "message": "MetaMask neu starten" - }, - "desktopNotFoundErrorCTA": { - "message": "MetaMask Desktop herunterladen" - }, - "desktopNotFoundErrorDescription1": { - "message": "Bitte stellen Sie sicher, dass die MetaMask Desktop-App ausgeführt wird." - }, - "desktopNotFoundErrorDescription2": { - "message": "Sollten Sie keine Desktop-App installiert haben, laden Sie diese bitte von der MetaMask-Webseite herunter." - }, - "desktopNotFoundErrorTitle": { - "message": "MetaMask Desktop wurde nicht gefunden" - }, - "desktopOpenOrDownloadCTA": { - "message": "MetaMask Desktop öffnen" - }, - "desktopOutdatedErrorCTA": { - "message": "MetaMask Desktop aktualisieren" - }, - "desktopOutdatedErrorDescription": { - "message": "Ihre MetaMask Desktop-App muss aktualisiert werden." - }, - "desktopOutdatedErrorTitle": { - "message": "MetaMask Desktop-App ist veraltet" - }, - "desktopOutdatedExtensionErrorCTA": { - "message": "MetaMask-Erweiterung aktualisieren" - }, - "desktopOutdatedExtensionErrorDescription": { - "message": "Ihre MetaMask-Erweiterung muss aktualisiert werden." - }, - "desktopOutdatedExtensionErrorTitle": { - "message": "MetaMask-Erweiterung ist veraltet" - }, - "desktopPageDescription": { - "message": "Bei erfolgreicher Kopplung wird die Erweiterung neu gestartet und Sie müssen Ihr Passwort erneut eingeben." - }, - "desktopPageSubTitle": { - "message": "Öffnen Sie MetaMask Desktop und geben Sie diesen Code ein." - }, - "desktopPageTitle": { - "message": "Mit Desktop koppeln" - }, - "desktopPairedWarningDeepLink": { - "message": "Gehen Sie zu den Einstellungen in MetaMask Desktop." - }, - "desktopPairedWarningDescription": { - "message": "Wenn Sie eine neue Kopplung starten möchten, entfernen Sie bitte die aktuelle Verbindung." - }, - "desktopPairedWarningTitle": { - "message": "MM Desktop ist bereits gekoppelt" - }, - "desktopPairingExpireMessage": { - "message": "Code läuft in $1 Sekunden ab" - }, - "desktopRouteNotFoundErrorDescription": { - "message": "desktopRouteNotFoundErrorDescription" - }, - "desktopRouteNotFoundErrorTitle": { - "message": "desktopRouteNotFoundErrorTitle" + "details": { + "message": "Details" }, - "desktopUnexpectedErrorCTA": { - "message": "Zur MetaMask-Startseite zurückkehren" + "developerOptions": { + "message": "Entwickler-Optionen" }, - "desktopUnexpectedErrorDescription": { - "message": "Prüfen Sie MetaMask Desktop, um die Verbindung wiederherzustellen." + "developerOptionsResetStatesAnnouncementsDescription": { + "message": "Setzt den Booleschen Wert isShown für alle Ankündigungen auf false zurück. Ankündigungen sind die Benachrichtigungen, die im Was-neu-ist-Popup-Modal angezeigt werden." }, - "desktopUnexpectedErrorTitle": { - "message": "Etwas ist schiefgelaufen ..." + "developerOptionsResetStatesOnboarding": { + "message": "Setzt verschiedene Status im Zusammenhang mit dem Onboarding zurück und leitet zur Onboarding-Seite „Sichern Sie Ihre Wallet“ weiter." }, - "details": { - "message": "Details" + "developerOptionsServiceWorkerKeepAlive": { + "message": "Führt dazu, dass ein Zeitstempel kontinuierlich in session.storage gespeichert wird." }, "disabledGasOptionToolTipMessage": { "message": "“$1” ist deaktiviert, weil es nicht das Minimum einer zehnprozentigen Erhöhung gegenüber der ursprünglichen Gasgebühr erfüllt.", @@ -1233,12 +1367,38 @@ "disconnectAllAccountsConfirmationDescription": { "message": "Sind Sie sicher, dass Sie die Verbindung trennen möchten? Die Seitenfunktionalität könnte verloren gehen." }, + "disconnectAllAccountsText": { + "message": "Konten" + }, + "disconnectAllSnapsText": { + "message": "Snaps" + }, + "disconnectAllText": { + "message": "Wenn Sie die Verbindung zwischen $1 und $2 unterbrechen, müssen Sie die Verbindung wiederherstellen, um sie erneut zu verwenden.", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`, $2 represents the website hostname" + }, + "disconnectAllTitle": { + "message": "Alle $1 trennen", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`" + }, "disconnectPrompt": { "message": "$1 trennen" }, "disconnectThisAccount": { "message": "Dieses Konto trennen" }, + "disconnectedAllAccountsToast": { + "message": "Alle Konten wurden von $1 getrennt", + "description": "$1 is name of the dapp`" + }, + "disconnectedSingleAccountToast": { + "message": "$1 wurde von $2 getrennt", + "description": "$1 is name of the name and $2 represents the dapp name`" + }, + "discoverSnaps": { + "message": "Snaps entdecken", + "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." + }, "dismiss": { "message": "Verwerfen" }, @@ -1248,9 +1408,21 @@ "dismissReminderField": { "message": "Backup-Erinnerung zur geheimen Wiederherstellungsphrase verwerfen" }, + "displayNftMedia": { + "message": "NFT-Medien anzeigen" + }, + "displayNftMediaDescription": { + "message": "Durch die Anzeige von NFT-Medien und -Daten wird Ihre IP-Adresse an OpenSea oder andere Dritte weitergegeben. Dies kann es Angreifern ermöglichen, Ihre IP-Adresse mit Ihrer Ethereum-Adresse in Verbindung zu bringen. Die automatische NFT-Erkennung basiert auf dieser Einstellung und ist nicht verfügbar, wenn diese ausgeschaltet ist." + }, + "doNotShare": { + "message": "Teilen Sie dies mit niemanden" + }, "domain": { "message": "Domain" }, + "domainNotSupportedOnNetwork": { + "message": "Netzwerk unterstützt kein Domain-Lookup" + }, "done": { "message": "Fertig" }, @@ -1269,6 +1441,9 @@ "downloadStateLogs": { "message": "Statusprotokolle herunterladen" }, + "dragAndDropBanner": { + "message": "Sie können Netzwerke ziehen, um sie neu anzuordnen." + }, "dropped": { "message": "Abgebrochen" }, @@ -1367,6 +1542,9 @@ "editSpeedUpEditGasFeeModalTitle": { "message": "Beschleunigung der Gasgebühr bearbeiten" }, + "enable": { + "message": "Aktivieren" + }, "enableAutoDetect": { "message": " Automatische Erkennung aktivieren" }, @@ -1397,6 +1575,18 @@ "enhancedTokenDetectionAlertMessage": { "message": "Erweiterte Token-Erkennung ist derzeit über $1 verfügbar. $2" }, + "ensDomainsSettingDescriptionIntroduction": { + "message": "MetaMask zeigt Ihnen ENS-Domains direkt in der Adressleiste Ihres Browsers an. So funktioniert es:" + }, + "ensDomainsSettingDescriptionOutroduction": { + "message": "Beachten Sie bitte, dass durch die Nutzung dieser Funktion Ihre IP-Adresse für IPFS-Dienste anbietende Dritte sichtbar wird." + }, + "ensDomainsSettingDescriptionPart1": { + "message": "MetaMask findet mithilfe von Ethereums ENS-Contract den mit dem ENS-Namen verbundenen Code." + }, + "ensDomainsSettingDescriptionPart2": { + "message": "Wenn der Code mit IPFS verknüpft ist, wird der dazugehörige Content (in der Regel eine Website) wiedergegeben." + }, "ensDomainsSettingTitle": { "message": "ENS-Domains in der Adresszeile anzeigen" }, @@ -1438,6 +1628,9 @@ "message": "Fehlerdetails", "description": "Title for collapsible section that displays error details for debugging purposes" }, + "errorGettingSafeChainList": { + "message": "Fehler beim Abrufen der Liste sicherer Ketten, bitte mit Vorsicht fortfahren." + }, "errorMessage": { "message": "Nachricht: $1", "description": "Displayed error message for debugging purposes. $1 is the error message" @@ -1469,6 +1662,9 @@ "message": "Fehler bei $1", "description": "$1 represents the name of the snap" }, + "estimatedFee": { + "message": "Geschätzte Gebühr" + }, "ethGasPriceFetchWarning": { "message": "Der Gas-Preis, der sich aus der Gas-Hauptschätzungsdienst ergibt, ist derzeit nicht verfügbar." }, @@ -1495,12 +1691,24 @@ "message": "Experimentell" }, "extendWalletWithSnaps": { - "message": "Erweitern Sie Ihr Wallet-Erlebnis.", + "message": "Erkunden Sie die von der Community erstellten Snaps, um Ihr web3-Erlebnis individuell zu gestalten.", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "extensionInsallCompleteDescription": { + "message": "Kehren Sie zur Produkteinführung von MetaMask Institutional zurück, um Ihre Verwahrungs- oder Selbstverwahrungskonten zu verbinden." + }, + "extensionInsallCompleteTitle": { + "message": "Installation der Erweiterung abgeschlossen" + }, "externalExtension": { "message": "Externe Erweiterung" }, + "externalNameSourcesSetting": { + "message": "Vorgeschlagene Spitznamen" + }, + "externalNameSourcesSettingDescription": { + "message": "Wir rufen die vorgeschlagenen Spitznamen für Adressen, mit denen Sie interagieren, aus Drittanbieterquellen wie Etherscan, Infura und Lens Protocol ab. Diese Anbieter sind in der Lage, die betreffenden Adressen sowie Ihre IP-Adresse einzusehen. Ihre Kontoadresse wird jedoch nicht an Drittparteien weitergegeben." + }, "failed": { "message": "Fehlgeschlagen" }, @@ -1519,6 +1727,9 @@ "feeAssociatedRequest": { "message": "Mit dieser Anfrage ist eine Gebühr verbunden." }, + "feeDetails": { + "message": "Details zur Gebühr" + }, "fiat": { "message": "FIAT", "description": "Exchange type" @@ -1551,6 +1762,9 @@ "message": "Ich akzeptiere die Risiken", "description": "this text is shown on a button, which the user presses to confirm they understand the risks of using Flask" }, + "floatAmountToken": { + "message": "Token-Betrag muss eine ganze Zahl sein" + }, "followUsOnTwitter": { "message": "Folgen Sie uns auf Twitter." }, @@ -1573,6 +1787,9 @@ "fromTokenLists": { "message": "Von Token-Liste: $1" }, + "function": { + "message": "Funktion: $1" + }, "functionApprove": { "message": "Funktion: Genehmigen" }, @@ -1582,6 +1799,13 @@ "functionType": { "message": "Funktionstyp" }, + "fundYourWallet": { + "message": "Versehen Sie Ihre Wallet mit Geldern" + }, + "fundYourWalletDescription": { + "message": "Legen Sie los, indem Sie Ihrer Wallet $1 hinzufügen.", + "description": "$1 is the token symbol" + }, "gas": { "message": "Gas" }, @@ -1592,6 +1816,9 @@ "message": "Diese Gas-Gebühr wurde von $1 vorgeschlagen. Dies kann ein Problem mit Ihrer Transaktion verursachen. Bei Fragen wenden Sie sich bitte an $1.", "description": "$1 represents the Dapp's origin" }, + "gasIsETH": { + "message": "Gas ist $1" + }, "gasLimit": { "message": "Gas-Limit" }, @@ -1636,6 +1863,9 @@ "message": "$1 Stunde", "description": "$1 represents a number of hours" }, + "gasTimingLow": { + "message": "Langsam" + }, "gasTimingMinutesShort": { "message": "Min. $1", "description": "$1 represents a number of minutes" @@ -1650,15 +1880,29 @@ "general": { "message": "Allgemein" }, - "globalTitle": { - "message": "Globales Menü" + "generalCameraError": { + "message": "Wir konnten nicht auf Ihre Kamera zugreifen. Bitte versuchen Sie es erneut." + }, + "generalCameraErrorTitle": { + "message": "Etwas ist schiefgelaufen ...." + }, + "genericExplorerView": { + "message": "Konto auf $1 ansehen" }, - "globalTourDescription": { - "message": "Sehen Sie Ihr Portfolio, verbundene Seiten, Einstellungen und mehr." + "getStartedWithNFTs": { + "message": "Erhalten Sie $1 für den Kauf von NFTs", + "description": "$1 is the token symbol" + }, + "getStartedWithNFTsDescription": { + "message": "Legen Sie mit NFTs los, indem Sie Ihrer Wallet $1 hinzufügen.", + "description": "$1 is the token symbol" }, "goBack": { "message": "Zurück" }, + "goToSite": { + "message": "Zur Seite gehen" + }, "goerli": { "message": "Goerli-Testnetzwerk" }, @@ -1700,15 +1944,24 @@ "hexData": { "message": "Hexdaten" }, + "hiddenAccounts": { + "message": "Versteckte Konten" + }, "hide": { "message": "Verbergen" }, + "hideAccount": { + "message": "Konto verbergen" + }, "hideFullTransactionDetails": { "message": "Vollständige Transaktionsdetails verbergen" }, "hideSeedPhrase": { "message": "Seed-Phrase verbergen" }, + "hideSentitiveInfo": { + "message": "Sensible Informationen verbergen" + }, "hideToken": { "message": "Token verbergen" }, @@ -1790,6 +2043,9 @@ "ignoreTokenWarning": { "message": "Wenn Sie Tokens verbergen, werden Sie nicht in Ihrer Wallet angezeigt. Sie können sie jedoch weiterhin hinzufügen, indem Sie nach ihnen suchen." }, + "imToken": { + "message": "imToken" + }, "import": { "message": "Importieren", "description": "Button to import an account from a selected file" @@ -1848,6 +2104,9 @@ "importTokensCamelCase": { "message": "Tokens importieren" }, + "importTokensError": { + "message": "Wir konnten die Tokens nicht importieren. Bitte versuchen Sie es später erneut." + }, "importWithCount": { "message": "$1 importieren", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -1866,6 +2125,9 @@ "initialTransactionConfirmed": { "message": "Ihre erste Transaktion wurde vom Netzwerk bestätigt. Klicken Sie auf „OK“, um zurückzukehren." }, + "inlineAlert": { + "message": "Warnung" + }, "inputLogicEmptyState": { "message": "Geben Sie nur eine Nummer ein, die Sie den Drittanbieter jetzt oder in Zukunft ausgeben lassen möchten. Sie können die Ausgabenobergrenze später jederzeit ändern." }, @@ -1876,6 +2138,27 @@ "inputLogicHigherNumber": { "message": "Dies erlaubt dem Drittanbieter, Ihr gesamtes Token-Guthaben auszugeben, bis die Obergrenze erreicht wurde oder Sie die Einschränkung widerrufen. Sollte dies nicht Ihre Absicht sein, ziehen Sie eine niedrigere Ausgabenobergrenze in Betracht." }, + "insightWarning": { + "message": "Warnung" + }, + "insightWarningCheckboxMessage": { + "message": "$1 die Anfrage von $2", + "description": "$1 is the action i.e. sign, confirm. $2 is the origin making the request." + }, + "insightWarningContentPlural": { + "message": "Überprüfen Sie $1 vor dem $2. Einmal getan, ist Ihre $3 unwiderruflich.", + "description": "$1 the 'insightWarnings' message (2 warnings) representing warnings, $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningContentSingular": { + "message": "Überprüfen Sie $1 vor dem $2. Einmal getan, ist Ihre $3 unwiderruflich.", + "description": "$1 is the 'insightWarning' message (1 warning), $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningHeader": { + "message": "Diese Anfrage kann riskant sein" + }, + "insightWarnings": { + "message": "Warnungen" + }, "insightsFromSnap": { "message": "Einblicke von $1", "description": "$1 represents the name of the snap" @@ -1883,9 +2166,18 @@ "install": { "message": "Installieren" }, + "installExtension": { + "message": "Erweiterung installieren" + }, + "installExtensionDescription": { + "message": "Die Institution-kompatible Version der weltweit führenden Web3-Wallet, MetaMask." + }, "installOrigin": { "message": "Origin installieren" }, + "installRequest": { + "message": "Zu MetaMask hinzufügen" + }, "installedOn": { "message": "Installiert auf $1", "description": "$1 is the date when the snap has been installed" @@ -1914,6 +2206,12 @@ "insufficientTokens": { "message": "Nicht genügend Tokens." }, + "interactingWith": { + "message": "Interaktion mit" + }, + "interactingWithTransactionDescription": { + "message": "Dies ist der Kontrakt, mit dem Sie interagieren. Schützen Sie sich vor Betrügern, indem Sie die Details überprüfen." + }, "invalidAddress": { "message": "Ungültige Adresse" }, @@ -1986,6 +2284,9 @@ "ipfsToggleModalSettings": { "message": "Einstellungen > Sicherheit und Datenschutz" }, + "isSigningOrSubmitting": { + "message": "Eine frühere Transaktion wird noch signiert oder eingereicht" + }, "jazzAndBlockies": { "message": "Jazzicons und Blockies sind zwei verschiedene Arten von einzigartigen Symbolen, mit denen Sie ein Konto auf einen Blick erkennen können." }, @@ -1999,6 +2300,24 @@ "message": "JSON Datei", "description": "format for importing an account" }, + "keyringAccountName": { + "message": "Kontoname" + }, + "keyringAccountPublicAddress": { + "message": "Öffentliche Adresse" + }, + "keyringSnapRemovalResult1": { + "message": "$1 $2entfernt", + "description": "Displays the result after removal of a keyring snap. $1 is the snap name, $2 is whether it is successful or not" + }, + "keyringSnapRemovalResultNotSuccessful": { + "message": "nicht ", + "description": "Displays the `not` word in $2." + }, + "keyringSnapRemoveConfirmation": { + "message": "„$1“ eingeben, um zu bestätigen, dass Sie diesen Snap entfernen möchten:", + "description": "Asks user to input the name nap prior to deleting the snap. $1 is the snap name" + }, "keystone": { "message": "Keystone" }, @@ -2017,9 +2336,15 @@ "lastSold": { "message": "Zuletzt verkauft" }, + "lavaDomeCopyWarning": { + "message": "Zu Ihrer Sicherheit ist die Auswahl dieses Textes im Moment nicht möglich." + }, "layer1Fees": { "message": "Layer 1 Gebühren" }, + "layer2Fees": { + "message": "Layer-2-Gebühren" + }, "learnCancelSpeeedup": { "message": "Erfahren Sie, wie Sie $1", "description": "$1 is link to cancel or speed up transactions" @@ -2037,9 +2362,21 @@ "learnMoreUpperCase": { "message": "Mehr erfahren" }, + "learnMoreUpperCaseWithDot": { + "message": "Erfahren Sie mehr." + }, "learnScamRisk": { "message": "Betrügereien und Sicherheitsrisiken." }, + "learnToBridge": { + "message": "Lernen Sie zu bridgen" + }, + "leaveMetaMask": { + "message": "MetaMask verlassen?" + }, + "leaveMetaMaskDesc": { + "message": "Sie sind im Begriff, eine Seite außerhalb von MetaMask zu besuchen. Überprüfen Sie die URL, bevor Sie fortfahren." + }, "ledgerAccountRestriction": { "message": "Sie müssen Ihr letztes Konto verwenden, ehe Sie ein neues hinzufügen können." }, @@ -2058,6 +2395,18 @@ "ledgerDeviceOpenFailureMessage": { "message": "Das Ledger-Gerät konnte nicht geöffnet werden. Ihr Ledger könnte mit anderer Software verbunden sein. Bitte schließen Sie Ledger Live oder andere Anwendungen, die mit Ihrem Ledger Gerät verbunden sind, und versuchen Sie es erneut." }, + "ledgerErrorConnectionIssue": { + "message": "Verbinden Sie Ihr Ledger nochmals, öffnen Sie die ETH-App und versuchen Sie es erneut." + }, + "ledgerErrorDevicedLocked": { + "message": "Ihr Ledger ist gesperrt. Entsperren Sie es und versuchen Sie es erneut." + }, + "ledgerErrorEthAppNotOpen": { + "message": "Um das Problem zu lösen, öffnen Sie die ETH-Anwendung auf Ihrem Gerät und versuchen Sie es erneut." + }, + "ledgerErrorTransactionDataNotPadded": { + "message": "Die Eingabedaten der Ethereum-Transaktion sind nicht ausreichend aufgefüllt." + }, "ledgerLiveApp": { "message": "Ledger Live App" }, @@ -2077,6 +2426,9 @@ "lightTheme": { "message": "Leicht" }, + "likeToImportToken": { + "message": "Möchten Sie diesen Token importieren?" + }, "likeToImportTokens": { "message": "Möchten Sie diese Tokens hinzufügen?" }, @@ -2086,6 +2438,9 @@ "lineaMainnet": { "message": "Linea Mainnet" }, + "lineaSepolia": { + "message": "Linea-Sepolia-Testnetzwerk" + }, "link": { "message": "Link" }, @@ -2098,8 +2453,11 @@ "loading": { "message": "Wird geladen ..." }, - "loadingNFTs": { - "message": "NFTs werden geladen ..." + "loadingScreenHardwareWalletMessage": { + "message": "Bitte schließen Sie die Transaktion im Hardware-Wallet ab." + }, + "loadingScreenSnapMessage": { + "message": "Bitte schließen Sie die Transaktion im Snap ab." }, "loadingTokens": { "message": "Tokens werden geladen ..." @@ -2146,6 +2504,9 @@ "message": "Stellen Sie sicher, dass niemand zuschaut.", "description": "Warning to users to be care while creating and saving their new Secret Recovery Phrase" }, + "manageInSettings": { + "message": "In Einstellungen verwalten" + }, "max": { "message": "Max." }, @@ -2180,15 +2541,34 @@ "metaMaskConnectStatusParagraphTwo": { "message": "Die Schaltfläche Verbindungsstatus zeigt an, ob die Webseite, die Sie besuchen, mit Ihrem aktuell ausgewählten Konto verbunden ist." }, + "metadataModalSourceTooltip": { + "message": "$1 wird auf npm gehostet und $2 ist die einzige Kennung dieses Snaps.", + "description": "$1 is the snap name and $2 is the snap NPM id." + }, "metamaskInstitutionalVersion": { "message": "MetaMask Institutional-Version" }, + "metamaskNotificationsAreOff": { + "message": "Wallet-Benachrichtigungen sind momentan nicht aktiv." + }, + "metamaskPortfolio": { + "message": "MetaMask Portfolio." + }, "metamaskSwapsOfflineDescription": { "message": "MetaMask Swaps wird gewartet. Bitte versuchen Sie es später erneut." }, "metamaskVersion": { "message": "MetaMask-Version" }, + "methodData": { + "message": "Methode" + }, + "methodDataTransactionDescription": { + "message": "Dies ist die konkrete Aktion, die durchgeführt wird. Diese Daten können gefälscht sein, daher sollten Sie der Website auf der anderen Seite vertrauen." + }, + "methodNotSupported": { + "message": "Bei diesem Konto nicht unterstützt." + }, "metrics": { "message": "Metriken" }, @@ -2224,11 +2604,17 @@ "mmiBuiltAroundTheWorld": { "message": "MetaMask Institutional ist weltweit konzipiert und aufgebaut." }, + "mmiNewNFTDetectedInNFTsTabMessage": { + "message": "Lassen Sie zu, dass MetaMask Institutional NFTs automatisch erkennt und anzeigt." + }, + "mmiPasswordSetupDetails": { + "message": "Dieses Passwort entsperrt nur Ihre MetaMask Institutional-Erweiterung." + }, "more": { "message": "mehr" }, "multipleSnapConnectionWarning": { - "message": "$1 möchte sich mit $2 Snaps verbinden. Fahren Sie nur fort, wenn Sie dieser Webseite vertrauen.", + "message": "$1 möchte $2 Snaps verwenden", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." }, "mustSelectOne": { @@ -2237,10 +2623,80 @@ "name": { "message": "Name" }, + "nameAddressLabel": { + "message": "Adresse", + "description": "Label above address field in name component modal." + }, + "nameInstructionsNew": { + "message": "Falls Sie diese Adresse kennen, können Sie ihr einen Spitznamen zuweisen, um sie künftig wiederzuerkennen.", + "description": "Instruction text in name component modal when value is not recognised." + }, + "nameInstructionsRecognized": { + "message": "Diese Adresse hat einen vorgegebenen Spitznamen, den Sie jedoch bearbeiten oder weitere Empfehlungen einholen können.", + "description": "Instruction text in name component modal when value is recognized but not saved." + }, + "nameInstructionsSaved": { + "message": "Sie haben bereits einen Spitznamen für diese Adresse hinzugefügt. Sie können weitere vorgeschlagene Spitznamen bearbeiten oder einsehen.", + "description": "Instruction text in name component modal when value is saved." + }, + "nameLabel": { + "message": "Spitzname", + "description": "Label above name input field in name component modal." + }, + "nameModalMaybeProposedName": { + "message": "Vielleicht: $1", + "description": "$1 is the proposed name" + }, + "nameModalTitleNew": { + "message": "Unbekannte Adresse", + "description": "Title of the modal created by the name component when value is not recognised." + }, + "nameModalTitleRecognized": { + "message": "Erkannte Adresse", + "description": "Title of the modal created by the name component when value is recognized but not saved." + }, + "nameModalTitleSaved": { + "message": "Gespeicherte Adresse", + "description": "Title of the modal created by the name component when value is saved." + }, + "nameProviderProposedBy": { + "message": "Vorgeschlagen von $1", + "description": "$1 is the name of the provider" + }, + "nameProvider_ens": { + "message": "Ethereum Name Service (ENS)" + }, + "nameProvider_etherscan": { + "message": "Etherscan" + }, + "nameProvider_lens": { + "message": "Lens Protocol" + }, + "nameProvider_token": { + "message": "MetaMask" + }, + "nameSetPlaceholder": { + "message": "Wählen Sie einen Spitznamen ...", + "description": "Placeholder text for name input field in name component modal." + }, + "nativePermissionRequestDescription": { + "message": "Möchten Sie, dass diese Website Folgendes tut?", + "description": "Description below header used on Permission Connect screen for native permissions." + }, "nativeToken": { "message": "Das native Token dieses Netzwerks ist $1. Dieses Token wird für die Gas-Gebühr verwendet.", "description": "$1 represents the name of the native token on the current network" }, + "nativeTokenScamWarningConversion": { + "message": "Netzwerkdetails bearbeiten" + }, + "nativeTokenScamWarningDescription": { + "message": "Dieses Netzwerk passt nicht zu seiner zugehörigen Chain-ID oder seinem Namen. Viele beliebte Tokens verwenden den Namen $1, was sie zu einem Ziel für Betrüger macht. Betrüger könnten Sie dazu verleiten, ihnen im Gegenzug wertvollere Währung zu schicken. Überprüfen Sie alles, bevor Sie fortfahren.", + "description": "$1 represents the currency name" + }, + "nativeTokenScamWarningTitle": { + "message": "Dies ist ein möglicher Betrug" + }, "needHelp": { "message": "Brauchen Sie Hilfe? Kontaktieren Sie $1.", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -2261,6 +2717,9 @@ "negativeETH": { "message": "Negative ETH Beträge können nicht versendet werden." }, + "negativeOrZeroAmountToken": { + "message": "Negative oder Nullbeträge von Assets können nicht gesendet werden." + }, "network": { "message": "Netzwerk:" }, @@ -2291,6 +2750,9 @@ "networkNameBSC": { "message": "BSC" }, + "networkNameBase": { + "message": "Basis" + }, "networkNameDefinition": { "message": "Der diesem Netzwerk zugeordnete Name." }, @@ -2300,12 +2762,21 @@ "networkNameGoerli": { "message": "Goerli" }, + "networkNameLinea": { + "message": "Linea" + }, + "networkNameOpMainnet": { + "message": "OP Mainnet" + }, "networkNamePolygon": { "message": "Polygon" }, "networkNameTestnet": { "message": "Testnet" }, + "networkNameZkSyncEra": { + "message": "zkSync Era" + }, "networkProvider": { "message": "Netzwerkanbieter" }, @@ -2358,6 +2829,19 @@ "newContract": { "message": "Neuer Contract" }, + "newNFTDetectedInImportNFTsMessageStrongText": { + "message": "Einstellungen > Sicherheit und Datenschutz" + }, + "newNFTDetectedInImportNFTsMsg": { + "message": "Um Opensea zu verwenden, um Ihre NFTs zu sehen, aktivieren Sie ‚NFT-Medien anzeigen‘ in $1.", + "description": "$1 is used for newNFTDetectedInImportNFTsMessageStrongText" + }, + "newNFTDetectedInNFTsTabMessage": { + "message": "Lassen Sie zu, dass MetaMask NFTs automatisch erkennt und anzeigt." + }, + "newNFTsAutodetected": { + "message": "Automatische NFT-Erkennung" + }, "newNetworkAdded": { "message": "„$1“ wurde erfolgreich hinzugefügt!" }, @@ -2367,6 +2851,12 @@ "newPassword": { "message": "Neues Passwort (min. 8 Zeichen)" }, + "newPrivacyPolicyActionButton": { + "message": "Mehr erfahren" + }, + "newPrivacyPolicyTitle": { + "message": "Wir haben unsere Datenschutzrichtlinie aktualisiert" + }, "newTokensImportedMessage": { "message": "Sie haben $1 erfolgreich importiert.", "description": "$1 is the string of symbols of all the tokens imported" @@ -2388,6 +2878,9 @@ "message": "Dieses Token ist ein NFT. Bei $1 hinzufügen.", "description": "$1 is a clickable link with text defined by the 'importNFTPage' key" }, + "nftAlreadyAdded": { + "message": "NFT wurde bereits hinzugefügt." + }, "nftDisclaimer": { "message": "Haftungsausschluss: MetaMask bezieht die Mediendatei aus der Quellen-URL. Diese URL wird manchmal vom Markt, auf dem das NFT erstellt wurde, geändert." }, @@ -2423,12 +2916,21 @@ "noAddressForName": { "message": "Für den angegebene Namen wurde keine Adresse eingegeben." }, + "noConnectedAccountDescription": { + "message": "Wählen Sie ein Konto, das Sie auf dieser Website verwenden möchten, um fortzufahren." + }, + "noConnectedAccountTitle": { + "message": "MetaMask ist nicht mit dieser Website verbunden" + }, "noConversionDateAvailable": { "message": "Kein Umrechnungskursdaten verfügbar" }, "noConversionRateAvailable": { "message": "Kein Umrechnungskurs verfügbar" }, + "noDomainResolution": { + "message": "Keine Auflösung für die Domain angegeben." + }, "noNFTs": { "message": "Noch keine NFTs" }, @@ -2447,6 +2949,9 @@ "noWebcamFoundTitle": { "message": "Webcam nicht gefunden" }, + "nonCustodialAccounts": { + "message": "MetaMask Institutional erlaubt Ihnen die Verwendung von Konten ohne Verwaltung, wenn Sie vorhaben, diese Konten als Backup für die geheime Wiederherstellungsphrase zu verwenden." + }, "nonce": { "message": "Unbekannt" }, @@ -2477,69 +2982,137 @@ "notePlaceholder": { "message": "Der Genehmiger sieht diese Notiz, wenn die Transaktion beim Verwahrer genehmigt wird." }, - "notificationTransactionFailedMessage": { - "message": "Transaktion $1 ist fehlgeschlagen! $2", - "description": "Content of the browser notification that appears when a transaction fails" + "notificationDetail": { + "message": "Details" }, - "notificationTransactionFailedMessageMMI": { - "message": "Transaktion ist fehlgeschlagen $1", - "description": "Content of the browser notification that appears when a transaction fails in MMI" + "notificationDetailBaseFee": { + "message": "Grundgebühr (GWEI)" }, - "notificationTransactionFailedTitle": { - "message": "Fehlgeschlagene Transaktion", - "description": "Title of the browser notification that appears when a transaction fails" + "notificationDetailGasLimit": { + "message": "Gas-Limit (Einheiten)" }, - "notificationTransactionSuccessMessage": { - "message": "Transaktion $1 wurde bestätigt!", - "description": "Content of the browser notification that appears when a transaction is confirmed" + "notificationDetailGasUsed": { + "message": "Verbrauchtes Gas (Einheiten)" }, - "notificationTransactionSuccessTitle": { - "message": "Bestätigte Transaktion", - "description": "Title of the browser notification that appears when a transaction is confirmed" + "notificationDetailMaxFee": { + "message": "Maximale Gebühr pro Gas" }, - "notificationTransactionSuccessView": { - "message": "Auf $1 ansehen", - "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" + "notificationDetailNetwork": { + "message": "Netzwerk" }, - "notifications": { - "message": "Benachrichtigungen" + "notificationDetailNetworkFee": { + "message": "Netzwerkgebühr" }, - "notifications20ActionText": { - "message": "Mehr erfahren", - "description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a ledger page to resolve the U2F connection issue." + "notificationDetailPriorityFee": { + "message": "Prioritätsgebühr (GWEI)" }, - "notifications20Description": { - "message": "Falls Sie die neueste Version von Firefox nutzen, könnte ein Problem auftreten, das mit der Einstellung der U2F-Unterstützung seitens Firefox in Verbindung steht.", - "description": "Description of a notification in the 'See What's New' popup. Describes the U2F support being dropped by firefox and that it affects ledger users." + "notificationItemCheckBlockExplorer": { + "message": "Überprüfen Sie den BlockExplorer" }, - "notifications20Title": { - "message": "Nutzer von Ledger und Firefox haben Verbindungsprobleme.", - "description": "Title for a notification in the 'See What's New' popup. Tells users that latest firefox users using U2F may experience connection issues." + "notificationItemCollection": { + "message": "Sammlung" }, - "notifications24ActionText": { - "message": "Verstanden" + "notificationItemConfirmed": { + "message": "Bestätigt" }, - "notifications24Description": { - "message": "Die Einstellungen für erweiterte Gasgebühren werden jetzt je nach dem von Ihnen verwendeten Netz gespeichert. Das bedeutet, dass Sie für jedes Netz spezifische erweiterte Gasgebühren festlegen und so vermeiden können, dass Sie zu viel für Gas bezahlen oder Transaktionen stecken bleiben." + "notificationItemError": { + "message": "Gebühren können derzeit nicht abgerufen werden" }, - "notifications24Title": { - "message": "Erweiterte Gas-Gebühr nach Netzwerk" + "notificationItemFrom": { + "message": "Von" + }, + "notificationItemLidoStakeReadyToBeWithdrawn": { + "message": "Auszahlung bereit" + }, + "notificationItemLidoStakeReadyToBeWithdrawnMessage": { + "message": "Sie können sich nun Ihre Unstaked $1 auszahlen lassen" + }, + "notificationItemLidoWithdrawalRequestedMessage": { + "message": "Ihre Anfrage zum Unstake von $1 wurde gesendet" + }, + "notificationItemNFTReceivedFrom": { + "message": "NFT empfangen von" + }, + "notificationItemNFTSentTo": { + "message": "NFT gesendet an" + }, + "notificationItemNetwork": { + "message": "Netzwerk" + }, + "notificationItemRate": { + "message": "Kurs (inklusive Gebühr)" + }, + "notificationItemReceived": { + "message": "Empfangen" + }, + "notificationItemReceivedFrom": { + "message": "Empfangen von" + }, + "notificationItemSent": { + "message": "Gesendet" + }, + "notificationItemSentTo": { + "message": "Gesendet an" + }, + "notificationItemStakeCompleted": { + "message": "Stake abgeschlossen" + }, + "notificationItemStaked": { + "message": "Staked" + }, + "notificationItemStakingProvider": { + "message": "Staking-Anbieter" + }, + "notificationItemStatus": { + "message": "Status" + }, + "notificationItemSwapped": { + "message": "Geswappt" + }, + "notificationItemSwappedFor": { + "message": "für" }, - "notifications8ActionText": { - "message": "Zu den erweiterten Einstellungen gehen", - "description": "Description on an action button that appears in the What's New popup. Tells the user that if they click it, they will go to our Advanced settings page." + "notificationItemTo": { + "message": "An" + }, + "notificationItemTransactionId": { + "message": "Transaktions-ID" + }, + "notificationItemUnStakeCompleted": { + "message": "UnStaking abgeschlossen" + }, + "notificationItemUnStaked": { + "message": "Unstaked" + }, + "notificationItemUnStakingRequested": { + "message": "Unstaking angefordert" + }, + "notificationTransactionFailedMessage": { + "message": "Transaktion $1 ist fehlgeschlagen! $2", + "description": "Content of the browser notification that appears when a transaction fails" + }, + "notificationTransactionFailedMessageMMI": { + "message": "Transaktion ist fehlgeschlagen $1", + "description": "Content of the browser notification that appears when a transaction fails in MMI" + }, + "notificationTransactionFailedTitle": { + "message": "Fehlgeschlagene Transaktion", + "description": "Title of the browser notification that appears when a transaction fails" + }, + "notificationTransactionSuccessMessage": { + "message": "Transaktion $1 wurde bestätigt!", + "description": "Content of the browser notification that appears when a transaction is confirmed" }, - "notifications8DescriptionOne": { - "message": "Ab MetaMask v10.4.0 benötigen Sie kein Ledger Live mehr, um Ihr Ledger-Gerät mit MetaMask zu verbinden.", - "description": "Description of a notification in the 'See What's New' popup. Describes changes for how Ledger Live is no longer needed to connect the device." + "notificationTransactionSuccessTitle": { + "message": "Bestätigte Transaktion", + "description": "Title of the browser notification that appears when a transaction is confirmed" }, - "notifications8DescriptionTwo": { - "message": "Für ein einfacheres und stabileres Ledger-Erlebnis gehen Sie zu Einstellungen > Erweitert und stellen Sie den „Bevorzugten Ledger-Verbindungstyp“ auf „WebHID“ um.", - "description": "Description of a notification in the 'See What's New' popup. Describes how the user can turn off the Ledger Live setting." + "notificationTransactionSuccessView": { + "message": "Auf $1 ansehen", + "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" }, - "notifications8Title": { - "message": "Verbesserung der Ledger-Verbindung", - "description": "Title for a notification in the 'See What's New' popup. Notifies ledger users that there is an improvement in how they can connect their device." + "notifications": { + "message": "Benachrichtigungen" }, "notificationsDropLedgerFirefoxDescription": { "message": "Firefox unterstützt U2F nicht mehr, daher wird Ledger nicht mit MetaMask auf Firefox funktionieren. Probieren Sie stattdessen MetaMask auf Google Chrome aus.", @@ -2549,33 +3122,37 @@ "message": "Einstellung der Ledger-Unterstützung für Firefox", "description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped." }, - "notificationsEmptyText": { - "message": "Hier gibt es nichts zu sehen." - }, - "notificationsHeader": { - "message": "Benachrichtigungen" + "notificationsFeatureToggle": { + "message": "Wallet-Benachrichtigungen aktivieren", + "description": "Experimental feature title" }, - "notificationsInfos": { - "message": "$1 von $2", - "description": "$1 is the date at which the notification has been dispatched and $2 is the link to the snap that dispatched the notification." + "notificationsFeatureToggleDescription": { + "message": "Dies ermöglicht Wallet-Benachrichtigungen wie das Senden/Empfangen von Geldern oder NFTs und Funktionsankündigungen.", + "description": "Description of the experimental notifications feature" }, "notificationsMarkAllAsRead": { "message": "Alle als gelesen markieren" }, - "notificationsOpenBetaSnapsActionText": { - "message": "Mehr erfahren" + "notificationsPageEmptyTitle": { + "message": "Hier gibt es nichts zu sehen" + }, + "notificationsPageErrorContent": { + "message": "Bitte versuchen Sie, diese Seite erneut zu besuchen." + }, + "notificationsPageErrorTitle": { + "message": "Ein Fehler ist aufgetreten" }, - "notificationsOpenBetaSnapsDescriptionOne": { - "message": "🎉 Wir freuen uns sehr, die Open-Beta-Version von MetaMask Snaps zu präsentieren!" + "notificationsPageNoNotificationsContent": { + "message": "Sie haben noch keine Benachrichtigungen empfangen." }, - "notificationsOpenBetaSnapsDescriptionThree": { - "message": "Personalisieren Sie Ihre Wallet mit Snaps, die von der Entwickler-Community erstellt wurden!" + "notificationsSettingsBoxError": { + "message": "Etwas ist schiefgelaufen! Bitte versuchen Sie es erneut." }, - "notificationsOpenBetaSnapsDescriptionTwo": { - "message": "Snaps helfen Ihnen dabei, mehr aus MetaMask zu machen – wie z. B. Verbindungen mit anderen Netzwerken herzustellen, Transaktionseinblicke zu erlangen und benutzerdefinierte Benachrichtigungen zu erhalten." + "notificationsSettingsPageAllowNotifications": { + "message": "Bleiben Sie mit Benachrichtigungen stets darüber auf dem Laufenden, was in Ihrer Wallet passiert. Zur Nutzung von Benachrichtigungen verwenden wir ein Profil, um bestimmte Einstellungen auf Ihren Geräten zu synchronisieren. $1" }, - "notificationsOpenBetaSnapsTitle": { - "message": "Wir stellen vor: MetaMask Snaps" + "notificationsSettingsPageAllowNotificationsLink": { + "message": "Erfahren Sie, wie wir Ihre Privatsphäre bei der Nutzung dieser Funktion schützen." }, "numberOfNewTokensDetectedPlural": { "message": "$1 neue Tokens in diesem Konto gefunden.", @@ -2599,6 +3176,9 @@ "on": { "message": "An" }, + "onboarding": { + "message": "Onboarding" + }, "onboardingAdvancedPrivacyIPFSDescription": { "message": "Das IPFS-Gateway ermöglicht es, auf von Dritten gehostete Daten zuzugreifen und diese einzusehen. Sie können ein benutzerdefiniertes IPFS-Gateway hinzufügen oder weiterhin das Standard-Gateway verwenden." }, @@ -2629,51 +3209,45 @@ "onboardingMetametricsAgree": { "message": "Ich stimme zu" }, - "onboardingMetametricsAllowOptOut": { - "message": "Erlaubt Ihnen immer die Abmeldung über Einstellungen" - }, - "onboardingMetametricsDataTerms": { - "message": "Diese Daten werden gesammelt und sind daher im Rahmen der Datenschutz-Grundverordnung (EU) 2016/679 anonym." - }, "onboardingMetametricsDescription": { - "message": "MetaMask möchte Nutzungsdaten sammeln, um ein besseres Verständnis zu erhalten, wie unsere Nutzer mit MetaMask interagieren. Diese Daten werden verwendet, um Dienste anzubieten, was auf Ihrer Nutzung basierte Dienstverbesserungen einschließt." + "message": "Wir würden gerne grundlegende Nutzungs- und Diagnosedaten sammeln, um MetaMask zu verbessern. Sie sollten wissen, dass wir die Daten, die Sie uns hier zur Verfügung stellen, niemals verkaufen." }, "onboardingMetametricsDescription2": { - "message": "MetaMask wird ..." + "message": "Wenn wir Metriken sammeln, wird es immer wie folgt sein ..." }, "onboardingMetametricsDisagree": { "message": "Nein, danke!" }, "onboardingMetametricsInfuraTerms": { - "message": "*Wenn Sie Infura als Standard-RPC-Anbieter in MetaMask vewenden, speichert Infura Ihre IP-Adresse und Ihre Etherum-Wallet-Adresse, wenn Sie eine Transaktion senden. Wir speichern diese Daten in keinster Weise in unserem System, um sie miteinander in Verbindung zu bringen. Für weitere Informationen darüber, wie MetaMask und Infura in Hinischt auf Datenspeicherung zusammenarbeiten, sehen Sie sich bitte unser Update $1 an. Für mehr Informationen bezüglich unseren allgemeinen Datenschutzpraktiken, sehen Sie sich bitte unsere $2 an.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" + "message": "Wir werden Sie informieren, wenn wir beschließen, diese Daten für andere Zwecke zu verwenden. Für weitere Informationen können Sie unsere $1 einsehen. Vergessen Sie nicht, dass Sie jederzeit zu Einstellungen gehen und sich abmelden können.", + "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, "onboardingMetametricsInfuraTermsPolicy": { - "message": "Datenschutzerklärung hier" - }, - "onboardingMetametricsInfuraTermsPolicyLink": { - "message": "hier" + "message": "Datenschutzrichtlinie" }, "onboardingMetametricsModalTitle": { "message": "Benutzerdefiniertes Netzwerk hinzufügen" }, "onboardingMetametricsNeverCollect": { - "message": "$1 speichert Daten, die wir nicht benötigen, um die Dienstleistung zur Verfügung zu stellen (wie zum Beispiel Schlüssel, Adresse, Transaktions-Hashs oder Guthaben)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 Klicks und Aufrufe der App werden gespeichert, andere Details (wie Ihre öffentliche Adresse) jedoch nicht.", + "description": "$1 represents `onboardingMetametricsNeverCollectEmphasis`" + }, + "onboardingMetametricsNeverCollectEmphasis": { + "message": "Privat:" }, "onboardingMetametricsNeverCollectIP": { - "message": "$1 speichert Ihre vollständige IP-Adresse*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 wir verwenden Ihre IP-Adresse vorübergehend, um einen allgemeinen Standort zu ermitteln (z. B. Ihr Land oder Ihre Region), aber er wird niemals gespeichert.", + "description": "$1 represents `onboardingMetametricsNeverCollectIPEmphasis`" }, - "onboardingMetametricsNeverEmphasis": { - "message": "Nie" + "onboardingMetametricsNeverCollectIPEmphasis": { + "message": "Allgemein:" }, "onboardingMetametricsNeverSellData": { - "message": "$1 Daten verkaufen. Niemals!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 Sie können jederzeit über die Einstellungen entscheiden, ob Sie Ihre Nutzungsdaten freigeben oder löschen möchten.", + "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" }, - "onboardingMetametricsSendAnonymize": { - "message": "Anonymisierte Ereignisse für Klicks und Seitenaufrufe senden" + "onboardingMetametricsNeverSellDataEmphasis": { + "message": "Optional:" }, "onboardingMetametricsTitle": { "message": "Helfen Sie uns, MetaMask zu verbessern." @@ -2714,15 +3288,26 @@ "onboardingPinExtensionTitle": { "message": "Ihre MetaMask Installation ist abgeschlossen!" }, + "onboardingPinMmiExtensionLabel": { + "message": "MetaMask Institutional pinnen" + }, "onboardingUsePhishingDetectionDescription": { "message": "Phishing-Warnungen basieren auf der Kommunikation mit $1. jsDeliver hat Zugriff auf Ihre IP-Adresse. $2 ansehen.", "description": "The $1 is the word 'jsDeliver', from key 'jsDeliver' and $2 is the words Privacy Policy from key 'privacyMsg', both separated here so that it can be wrapped as a link" }, + "onekey": { + "message": "OneKey" + }, "onlyAddTrustedNetworks": { "message": "Ein betrügerischer Netzwerkanbieter kann bezüglich des Status der Blockchain täuschen und Ihre Netzwerkaktivitäten aufzeichnen. Fügen Sie nur vertrauenswürdige Netzwerke hinzu." }, "onlyConnectTrust": { - "message": "Verbinden Sie sich nur mit Seiten, denen Sie vertrauen." + "message": "Verbinden Sie sich nur mit Websites, denen Sie vertrauen. $1", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." + }, + "openCustodianApp": { + "message": "$1 App öffnen", + "description": "The $1 is the name of the Custodian that will be open" }, "openFullScreenForLedgerWebHid": { "message": "Öffnen Sie MetaMask im Vollbildmodus, um Ihren Ledger über WebHID zu verbinden.", @@ -2734,6 +3319,15 @@ "openSeaNew": { "message": "OpenSea" }, + "openSeaToBlockaidBtnLabel": { + "message": "Snaps entdecken" + }, + "openSeaToBlockaidDescription": { + "message": "Sicherheitsbenachrichtigungen sind in diesem Netzwerk nicht mehr verfügbar. Die Installation eines Snaps kann Ihre Sicherheit erhöhen." + }, + "openSeaToBlockaidTitle": { + "message": "Vorsicht!" + }, "operationFailed": { "message": "Vorgang fehlgeschlagen" }, @@ -2777,6 +3371,9 @@ "password": { "message": "Passwort" }, + "passwordMmiTermsWarning": { + "message": "Ich verstehe, dass MetaMask Institutional dieses Passwort für mich nicht wiederherstellen kann. $1" + }, "passwordNotLongEnough": { "message": "Passwort nicht lang genug" }, @@ -2803,6 +3400,10 @@ "message": "Geben Sie hier die Zeichenfolge Ihres privaten Schlüssels ein:", "description": "For importing an account from a private key" }, + "paymasterInUse": { + "message": "Das Gas für diese Transaktion wird von einem Zahlmeister bezahlt.", + "description": "Alert shown in transaction confirmation if paymaster in use." + }, "pending": { "message": "Ausstehend" }, @@ -2816,18 +3417,26 @@ "message": "Sie haben ($1) ausstehende Transaktionen.", "description": "$1 is count of pending transactions" }, - "permissionRequest": { - "message": "Genehmigungsanfrage" + "permissionDetails": { + "message": "Genehmigungsdetails" }, - "permissionRequestCapitalized": { + "permissionRequest": { "message": "Genehmigungsanfrage" }, "permissionRequested": { "message": "Jetzt angefragt" }, + "permissionRequestedForAccounts": { + "message": "Jetzt für $1 angefordert", + "description": "Permission cell status for requested permission including accounts, rendered as AvatarGroup which is $1." + }, "permissionRevoked": { "message": "In diesem Update widerrufen" }, + "permissionRevokedForAccounts": { + "message": "In diesem Update für $1 widerrufen", + "description": "Permission cell status for revoked permission including accounts, rendered as AvatarGroup which is $1." + }, "permission_accessNamedSnap": { "message": "Mit $1 verbinden.", "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." @@ -2836,6 +3445,10 @@ "message": "Greifen Sie auf das Internet zu.", "description": "The description of the `endowment:network-access` permission." }, + "permission_accessNetworkDescription": { + "message": "Erlauben Sie $1, auf das Internet zuzugreifen. Dies kann sowohl zum Senden als auch zum Empfangen von Daten mit Servern von Drittanbietern verwendet werden.", + "description": "An extended description of the `endowment:network-access` permission. $1 is the snap name." + }, "permission_accessSnap": { "message": "Verbinden Sie sich mit dem $1-Snap.", "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." @@ -2848,10 +3461,18 @@ "message": "Regelmäßige Transaktionen planen und ausführen.", "description": "The description for the `snap_cronjob` permission" }, + "permission_cronjobDescription": { + "message": "Erlauben Sie $1, Aktionen auszuführen, die periodisch zu festen Zeiten, Daten oder Intervallen ablaufen. Dies kann verwendet werden, um zeitkritische Interaktionen oder Benachrichtigungen auszulösen.", + "description": "An extended description for the `snap_cronjob` permission. $1 is the snap name." + }, "permission_dialog": { "message": "Dialogfenster in MetaMask anzeigen.", "description": "The description for the `snap_dialog` permission" }, + "permission_dialogDescription": { + "message": "Erlauben Sie $1, MetaMask-Popups mit benutzerdefiniertem Text, Eingabefeld und Schaltflächen zur Genehmigung oder Ablehnung einer Aktion anzugeigen. Kann verwendet werden, um z. B. Warnungen, Bestätigungen und Opt-in-Flows für einen Snap zu erstellen.", + "description": "An extended description for the `snap_dialog` permission. $1 is the snap name." + }, "permission_ethereumAccounts": { "message": "Siehe Adresse, Kontostand, Aktivitäten und Vorschläge für zu genehmigende Transaktionen.", "description": "The description for the `eth_accounts` permission" @@ -2860,30 +3481,138 @@ "message": "Auf den Ethereum-Anbieter zugreifen.", "description": "The description for the `endowment:ethereum-provider` permission" }, + "permission_ethereumProviderDescription": { + "message": "Erlauben Sie $1, direkt mit MetaMask zu kommunizieren, damit es Daten aus der Blockchain lesen und Nachrichten und Transaktionen vorschlagen kann.", + "description": "An extended description for the `endowment:ethereum-provider` permission. $1 is the snap name." + }, + "permission_getEntropy": { + "message": "Leiten Sie beliebige Schlüssel ab, die nur für $1 gelten.", + "description": "The description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getEntropyDescription": { + "message": "Erlauben Sie $1, beliebige Schlüssel abzuleiten, die nur für $1 gelten, ohne sie offenzulegen. Diese Schlüssel sind von Ihrem MetaMask-Konto bzw. Ihren MetaMask-Konten getrennt und haben nichts mit Ihren privaten Schlüsseln oder Ihrer geheimen Wiederherstellungsphrase zu tun. Andere Snaps können nicht auf diese Informationen zugreifen.", + "description": "An extended description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getLocale": { + "message": "Ihre bevorzugte Sprache anzeigen.", + "description": "The description for the `snap_getLocale` permission" + }, + "permission_getLocaleDescription": { + "message": "Lassen Sie $1 über Ihre MetaMask-Einstellungen auf Ihre bevorzugte Sprache zugreifen. Dies kann verwendet werden, um den Inhalt von $1 in Ihrer Sprache zu lokalisieren und anzuzeigen.", + "description": "An extended description for the `snap_getLocale` permission. $1 is the snap name." + }, + "permission_homePage": { + "message": "Anzeige eines benutzerdefinierten Bildschirms", + "description": "The description for the `endowment:page-home` permission" + }, + "permission_homePageDescription": { + "message": "Lassen Sie $1 einen benutzerdefinierten Startbildschirm in MetaMask anzeigen. Dieser kann für Benutzeroberflächen, Konfiguration und Dashboards verwendet werden.", + "description": "An extended description for the `endowment:page-home` permission. $1 is the snap name." + }, + "permission_keyring": { + "message": "Anfragen zur Hinzufügung und Steuerung von Ethereum-Konten erlauben", + "description": "The description for the `endowment:keyring` permission" + }, + "permission_keyringDescription": { + "message": "Lassen Sie $1 Anfragen zum Hinzufügen oder Entfernen von Konten entgegennehmen sowie im Namen dieser Konten unterschreiben und Transaktionen durchführen.", + "description": "An extended description for the `endowment:keyring` permission. $1 is the snap name." + }, "permission_lifecycleHooks": { "message": "Verwenden Sie Lebenszyklus-Hooks.", "description": "The description for the `endowment:lifecycle-hooks` permission" }, + "permission_lifecycleHooksDescription": { + "message": "Erlauben Sie $1, Lebenszyklus-Hooks zu verwenden, um Code zu bestimmten Zeiten während seines Lebenszyklus auszuführen.", + "description": "An extended description for the `endowment:lifecycle-hooks` permission. $1 is the snap name." + }, "permission_manageAccounts": { "message": "Ethereum-Konten hinzufügen und kontrollieren", "description": "The description for `snap_manageAccounts` permission" }, + "permission_manageAccountsDescription": { + "message": "Erlauben Sie $1, Ethereum-Konten hinzuzufügen oder zu entfernen und dann mit diesen Konten Transaktionen durchzuführen und zu unterschreiben.", + "description": "An extended description for the `snap_manageAccounts` permission. $1 is the snap name." + }, + "permission_manageBip32Keys": { + "message": "$1-Konten verwalten.", + "description": "The description for the `snap_getBip32Entropy` permission. $1 is a derivation path, e.g. 'm/44'/0'/0' (secp256k1)'." + }, + "permission_manageBip44AndBip32KeysDescription": { + "message": "Erlauben Sie $1, Konten und Assets in dem gewünschten Netzwerk zu verwalten. Diese Konten werden unter Verwendung Ihrer geheimen Wiederherstellungsphrase abgeleitet und gesichert (ohne sie preiszugeben). Mit der Fähigkeit, Schlüssel abzuleiten, kann $1 eine Vielzahl von Blockchain-Protokollen über Ethereum (EVMs) hinaus unterstützen.", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions. $1 is the snap name." + }, + "permission_manageBip44Keys": { + "message": "$1-Konten verwalten.", + "description": "The description for the `snap_getBip44Entropy` permission. $1 is the name of a protocol, e.g. 'Filecoin'." + }, "permission_manageState": { "message": "Speichern und verwalten Sie die Daten auf Ihrem Gerät.", "description": "The description for the `snap_manageState` permission" }, + "permission_manageStateDescription": { + "message": "Erlauben Sie $1, Daten sicher und verschlüsselt zu speichern, zu aktualisieren und abzurufen. Andere Snaps können nicht auf diese Informationen zugreifen.", + "description": "An extended description for the `snap_manageState` permission. $1 is the snap name." + }, + "permission_nameLookup": { + "message": "Bereitstellung von Domain- und Adress-Lookups.", + "description": "The description for the `endowment:name-lookup` permission." + }, + "permission_nameLookupDescription": { + "message": "Erlauben Sie dem Snap, Adress- und Domain-Lookups in verschiedenen Teilen der MetaMask-Benutzeroberfläche abzurufen und anzuzeigen.", + "description": "An extended description for the `endowment:name-lookup` permission." + }, "permission_notifications": { "message": "Benachrichtigungen anzeigen.", "description": "The description for the `snap_notify` permission" }, + "permission_notificationsDescription": { + "message": "Erlauben Sie $1, Benachrichtigungen in MetaMask anzuzeigen. Ein kurzer Benachrichtigungstext kann durch einen Snap für handlungsrelevante oder zeitkritische Informationen ausgelöst werden.", + "description": "An extended description for the `snap_notify` permission. $1 is the snap name." + }, + "permission_rpc": { + "message": "Erlauben Sie $1, direkt mit $2 zu kommunizieren.", + "description": "The description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescription": { + "message": "Erlauben Sie $1, Nachrichten an $2 zu senden und eine Antwort von $2 zu erhalten.", + "description": "An extended description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescriptionOriginList": { + "message": "$1 und $2", + "description": "A list of allowed origins where $2 is the last origin of the list and $1 is the rest of the list separated by ','." + }, + "permission_signatureInsight": { + "message": "Signatureinblicke modal anzeigen.", + "description": "The description for the `endowment:signature-insight` permission" + }, + "permission_signatureInsightDescription": { + "message": "Erlauben Sie $1, ein Modal mit Einblicken in jede Signaturanfrage vor der Genehmigung anzuzeigen. Dies kann für Anti-Phishing- und Sicherheitslösungen verwendet werden.", + "description": "An extended description for the `endowment:signature-insight` permission. $1 is the snap name." + }, + "permission_signatureInsightOrigin": { + "message": "Sehen Sie sich die Herkunft der Websites ein, die eine Signaturanfrage initiieren.", + "description": "The description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission" + }, + "permission_signatureInsightOriginDescription": { + "message": "Erlauben Sie $1, die Herkunft (URI) von Websites zu sehen, die Signaturanfragen initiieren. Dies kann für Anti-Phishing- und Sicherheitslösungen verwendet werden.", + "description": "An extended description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission. $1 is the snap name." + }, "permission_transactionInsight": { "message": "Transaktions-Einsichten abrufen und anzeigen.", "description": "The description for the `endowment:transaction-insight` permission" }, + "permission_transactionInsightDescription": { + "message": "Erlauben Sie $1, Transaktionen zu dekodieren und Einblicke innerhalb der MetaMask UI zu zeigen. Dies kann für Anti-Phishing- und Sicherheitslösungen verwendet werden.", + "description": "An extended description for the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_transactionInsightOrigin": { "message": "Ursprung der Webseite anzeigen, die Transaktionen vorschlägt", "description": "The description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission" }, + "permission_transactionInsightOriginDescription": { + "message": "Erlauben Sie $1, die Herkunft (URI) von Websites einzusehen, die Transaktionen vorschlagen. Dies kann für Anti-Phishing- und Sicherheitslösungen verwendet werden.", + "description": "An extended description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_unknown": { "message": "Unbekannte Genehmigung: $1", "description": "$1 is the name of a requested permission that is not recognized." @@ -2892,29 +3621,66 @@ "message": "Öffentlichen Schlüssel für $1 ($2) anzeigen.", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a derivation path, e.g. 'm/44'/0'/0''. $2 is the elliptic curve name, e.g. 'secp256k1'." }, + "permission_viewBip32PublicKeysDescription": { + "message": "Erlauben Sie $2, Ihre öffentlichen Schlüssel (und Adressen) für $1 einzusehen. Damit wird keine Kontrolle über Konten oder Assets gewährt.", + "description": "An extended description for the `snap_getBip32PublicKey` permission. $1 is a derivation path (name). $2 is the snap name." + }, "permission_viewNamedBip32PublicKeys": { "message": "Öffentlichen Schlüssel für $1 anzeigen.", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a name for the derivation path, e.g., 'Ethereum accounts'." }, + "permission_walletSwitchEthereumChain": { + "message": "Wechseln Sie zum folgenden Netzwerk und nutzen Sie dieses", + "description": "The label for the `wallet_switchEthereumChain` permission" + }, "permission_webAssembly": { "message": "Support für WebAssembly.", "description": "The description of the `endowment:webassembly` permission." }, + "permission_webAssemblyDescription": { + "message": "Erlauben Sie $1, auf Low-Level-Ausführungsumgebungen über WebAssembly zuzugreifen.", + "description": "An extended description of the `endowment:webassembly` permission. $1 is the snap name." + }, "permissions": { "message": "Genehmigungen" }, - "permissionsTitle": { - "message": "Genehmigungen" + "permissionsPageEmptyContent": { + "message": "Nichts zu sehen hier" }, - "permissionsTourDescription": { - "message": "Hier können Sie Ihre verbundenen Konten finden und Berechtigungen verwalten." + "permissionsPageEmptySubContent": { + "message": "Hier können Sie die Genehmigungen sehen, die Sie installierten Snaps oder verbundenen Websites gegeben haben." + }, + "permissionsPageTourDescription": { + "message": "Dies ist Ihr Kontrollfeld zum Verwalten der Genehmigungen für verbundene Websites und installierte Snaps." + }, + "permissionsPageTourTitle": { + "message": "Verbundene Websites sind nun Genehmigungen" }, "personalAddressDetected": { "message": "Personalisierte Adresse identifiziert. Bitte füge die Token-Contract-Adresse ein." }, + "petnamesEnabledToggle": { + "message": "Spitznamen erlauben" + }, + "petnamesEnabledToggleDescription": { + "message": "Damit können Sie jeder Adresse einen Spitznamen zuweisen. Nach Möglichkeit werden wir Namen für Adressen vorschlagen, mit denen Sie interagieren." + }, + "pinExtensionDescription": { + "message": "Gehen Sie zum Erweiterungsmenü und heften Sie MetaMask Institutional für nahtlosen Zugriff an." + }, + "pinExtensionTitle": { + "message": "Erweiterung anheften" + }, + "pinToTop": { + "message": "Pin nach oben" + }, "pleaseConfirm": { "message": "Bitte bestätigen" }, + "plusMore": { + "message": "+ $1 mehr", + "description": "$1 is the number of additional items" + }, "plusXMore": { "message": "+ $1 mehr", "description": "$1 is a number of additional but unshown items in a list- this message will be shown in place of those items" @@ -2940,6 +3706,9 @@ "primaryCurrencySettingDescription": { "message": "Wählen Sie 'Nativ', um dem Anzeigen von Werten in der nativen Währung der Chain (z. B. ETH) Vorrang zu geben. Wählen Sie 'Fiat', um dem Anzeigen von Werten in Ihrer gewählten Fiat-Währung Vorrang zu geben." }, + "primaryType": { + "message": "Primärer Typ" + }, "priorityFee": { "message": "Prioritätsgebühr" }, @@ -2960,6 +3729,18 @@ "message": "Privater Schlüssel für $1", "description": "$1 represents the account name" }, + "privateKeyHidden": { + "message": "Der private Schlüssel ist verborgen", + "description": "Explains that the private key input is hidden" + }, + "privateKeyShow": { + "message": "Eingabe des privaten Schlüssels anzeigen/ausblenden", + "description": "Describes a toggle that is used to show or hide the private key input" + }, + "privateKeyShown": { + "message": "Dieser private Schlüssel wird angezeigt", + "description": "Explains that the private key input is being shown" + }, "privateKeyWarning": { "message": "Warnung: Geben Sie diesen Schlüssel niemals weiter. Jeder, der Ihre privaten Schlüssel hat, kann alle Assets auf Ihrem Konto stehlen." }, @@ -2969,6 +3750,21 @@ "proceedWithTransaction": { "message": "Ich möchte dennoch fortfahren." }, + "productAnnouncements": { + "message": "Produktankündigungen" + }, + "profileSync": { + "message": "Profilsynchronisation" + }, + "profileSyncConfirmation": { + "message": "Wenn Sie die Profilsynchronisierung deaktivieren, können Sie keine Benachrichtigungen empfangen." + }, + "profileSyncDescription": { + "message": "Erstellt ein Profil, über das MetaMask bestimmte Einstellungen zwischen Ihren Geräten synchronisiert. Dies ist für den Erhalt von Benachrichtigungen erforderlich. $1." + }, + "profileSyncPrivacyLink": { + "message": "Erfahren Sie, wie wir Ihre Privatsphäre schützen" + }, "proposedApprovalLimit": { "message": "Vorgeschlagenes Genehmigungslimit" }, @@ -2978,6 +3774,78 @@ "publicAddress": { "message": "Öffentliche Adresse" }, + "pushPlatformNotificationsFundsReceivedDescription": { + "message": "Sie haben $1 $2 erhalten" + }, + "pushPlatformNotificationsFundsReceivedDescriptionDefault": { + "message": "Sie haben einige Tokens erhalten" + }, + "pushPlatformNotificationsFundsReceivedTitle": { + "message": "Gelder erhalten" + }, + "pushPlatformNotificationsFundsSentDescription": { + "message": "Sie haben erfolgreich $1 $2 gesendet" + }, + "pushPlatformNotificationsFundsSentDescriptionDefault": { + "message": "Sie haben erfolgreich einige Tokens gesendet" + }, + "pushPlatformNotificationsFundsSentTitle": { + "message": "Gelder gesendet" + }, + "pushPlatformNotificationsNftReceivedDescription": { + "message": "Sie haben neue NFTs erhalten" + }, + "pushPlatformNotificationsNftReceivedTitle": { + "message": "NFT erhalten" + }, + "pushPlatformNotificationsNftSentDescription": { + "message": "Sie haben erfolgreich einen NFT gesendet" + }, + "pushPlatformNotificationsNftSentTitle": { + "message": "NFT gesendet" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedDescription": { + "message": "Ihr Lido-Stake war erfolgreich" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedTitle": { + "message": "Stake abgeschlossen" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnDescription": { + "message": "Ihr Lido-Stake kann jetzt ausgezahlt werden" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnTitle": { + "message": "Stake bereit zur Auszahlung" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedDescription": { + "message": "Ihre Lido-Auszahlung war erfolgreich" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedTitle": { + "message": "Auszahlung abgeschlossen" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedDescription": { + "message": "Ihre Lido-Auszahlungsanfrage wurde übermittelt" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedTitle": { + "message": "Auszahlung angefordert" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedDescription": { + "message": "Ihr RocketPool-Stake war erfolgreich" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedTitle": { + "message": "Stake abgeschlossen" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedDescription": { + "message": "Ihr RocketPool-Unstake war erfolgreich" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedTitle": { + "message": "Unstake abgeschlossen" + }, + "pushPlatformNotificationsSwapCompletedDescription": { + "message": "Ihr MetaMask-Swap war erfolgreich" + }, + "pushPlatformNotificationsSwapCompletedTitle": { + "message": "Swap abgeschlossen" + }, "queued": { "message": "In Warteschlange" }, @@ -2996,9 +3864,15 @@ "receive": { "message": "Empfangen" }, + "receiveTokensCamelCase": { + "message": "Tokens erhalten" + }, "recipientAddressPlaceholder": { "message": "Öffentliche Adresse (0x) oder ENS-Name eingeben" }, + "recipientAddressPlaceholderFlask": { + "message": "Öffentliche Adresse (0x) oder Domainname eingeben" + }, "recommendedGasLabel": { "message": "Empfohlen" }, @@ -3026,6 +3900,12 @@ "recoveryPhraseReminderTitle": { "message": "Schützen Sie Ihre Gelder." }, + "redesignedConfirmationsEnabledToggle": { + "message": "Verbesserte Unterschriftsanfrage" + }, + "redesignedConfirmationsToggleDescription": { + "message": "Schalten Sie dies ein, um sich Unterschriftsanfragen in einem erweiterten Format anzeigen zu lassen." + }, "refreshList": { "message": "Liste aktualisieren" }, @@ -3068,15 +3948,30 @@ "removeJWTDescription": { "message": "Sind Sie sicher, dass Sie dieses Token entfernen möchten? Alle diesem Token zugewiesenen Konten werden ebenfalls von der Erweiterung entfernt: " }, + "removeKeyringSnap": { + "message": "Das Entfernen dieses Snaps entfernt folgende Konten aus MetaMask:" + }, + "removeKeyringSnapToolTip": { + "message": "Der Snap kontrolliert die Konten und durch seine Entfernung werden diese Konten ebenfalls aus MetaMask entfernt, verbleiben jedoch in der Blockchain." + }, "removeNFT": { "message": "NFT entfernen" }, + "removeNftErrorMessage": { + "message": "Wir konnten dieses NFT nicht entfernen." + }, "removeNftMessage": { "message": "NFT wurde erfolgreich entfernt!" }, "removeSnap": { "message": "Snap entfernen" }, + "removeSnapAccountDescription": { + "message": "Wenn Sie fortfahren, wird dieses Konto nicht mehr in MetaMask verfügbar sein." + }, + "removeSnapAccountTitle": { + "message": "Konto entfernen" + }, "removeSnapConfirmation": { "message": "Sind Sie sicher, dass Sie $1 entfernen möchten?", "description": "$1 represents the name of the snap" @@ -3087,12 +3982,24 @@ "replace": { "message": "ersetzen" }, + "reportIssue": { + "message": "Ein Problem melden" + }, "requestFlaggedAsMaliciousFallbackCopyReason": { "message": "Der Sicherheitsanbieter hat keine weiteren Details zur Verfügung gestellt." }, "requestFlaggedAsMaliciousFallbackCopyReasonTitle": { "message": "Anfrage als bösartig gemeldet" }, + "requestFrom": { + "message": "Anfrage von" + }, + "requestFromInfo": { + "message": "Dies ist die Seite, auf der Sie um Ihre Unterschrift gebeten werden." + }, + "requestFromTransactionDescription": { + "message": "Dies ist die Website, die Sie um Ihre Bestätigung bittet." + }, "requestMayNotBeSafe": { "message": "Anfrage könnte nicht sicher sein" }, @@ -3114,6 +4021,9 @@ "reset": { "message": "Zurücksetzen" }, + "resetStates": { + "message": "Status zurücksetzen" + }, "resetWallet": { "message": "Wallet zurücksetzen" }, @@ -3142,7 +4052,7 @@ "message": "Benutzerdaten wiederherstellen" }, "restoreUserDataDescription": { - "message": "Sie können die Benutzereinstellungen, die bevorzugte Einstellungen und Kontoadressen umfassen, aus einer vormals gesicherten JSON-Datei wiederherstellen." + "message": "Sie können Daten wie Kontakte und Einstellungen aus einer Sicherungsdatei wiederherstellen." }, "resultPageError": { "message": "Fehler" @@ -3196,9 +4106,15 @@ "message": "Der MetaMask Support wird Sie nie danach fragen.", "description": "The bolded texted in the second part of 'revealSeedWordsWarning'" }, + "revealSensitiveContent": { + "message": "Sensible Inhalte offenlegen" + }, "revealTheSeedPhrase": { "message": "Seed-Phrase anzeigen" }, + "reviewAlerts": { + "message": "Benachrichtigungen überprüfen" + }, "revokeAllTokensTitle": { "message": "Genehmigung zum Zugriff auf alle Ihre $1 sowie deren Übertragung entziehen?", "description": "$1 is the symbol of the token for which the user is revoking approval" @@ -3249,6 +4165,9 @@ "searchAccounts": { "message": "Konten durchsuchen" }, + "searchTokens": { + "message": "Tokens suchen" + }, "secretRecoveryPhrase": { "message": "Geheime Wiederherstellungsphrase" }, @@ -3265,13 +4184,14 @@ "message": "Sicherheitsbenachrichtigungen" }, "securityAlertsDescription": { - "message": "Diese Funktion warnt Sie vor schädlichen Aktivitäten im Ethereum Mainnet, indem sie Ihre Transaktions- und Signaturanfragen aktiv überprüft und dabei ihre Privatsphäre schützt. Ihre Daten werden dazu nicht an Dritte weitergegeben, die diesen Dienst anbieten. Denken Sie immer an Ihre eigene Sorgfaltspflicht, bevor Sie Anfragen genehmigen, denn es gibt keine Garantie dafür, dass diese Funktion alle schädlichen Aktivitäten auch tatsächlich erkennt." + "message": "Diese Funktion warnt Sie vor bösartigen Aktivitäten, indem sie aktiv Transaktionen und Signaturanfragen überprüft. $1", + "description": "Link to learn more about security alerts" }, "securityAndPrivacy": { "message": "Sicherheit und Datenschutz" }, "securityProviderPoweredBy": { - "message": "Powered by $1", + "message": "Unterstützt durch $1", "description": "The security provider that is providing data" }, "seeDetails": { @@ -3355,6 +4275,9 @@ "selectAnAccountHelp": { "message": "Wählen Sie die Verwahrungskonten zur Nutzung in MetaMask Institutional aus." }, + "selectEnableDisplayMediaPrivacyPreference": { + "message": "NFT-Medien anzeigen einschalten" + }, "selectHdPath": { "message": "HD-Pfad auswählen" }, @@ -3376,18 +4299,41 @@ "send": { "message": "Senden" }, + "sendAToken": { + "message": "Token senden" + }, "sendBugReport": { "message": "Übermitteln Sie uns einen Fehlerbericht." }, + "sendNoContactsConversionText": { + "message": "klicken Sie hier" + }, + "sendNoContactsDescription": { + "message": "Kontakte ermöglich Ihnen, Transaktionen sicher und mehrfach an ein anderes Konto zu senden. Um einen Kontakt zu erstellen, $1", + "description": "$1 represents the action text 'click here'" + }, + "sendNoContactsTitle": { + "message": "Sie haben noch keine Kontakte" + }, + "sendSelectReceiveAsset": { + "message": "Wählen Sie das zu empfangende Asset" + }, + "sendSelectSendAsset": { + "message": "Wählen Sie das zu sendende Asset" + }, "sendSpecifiedTokens": { "message": "$1 senden", "description": "Symbol of the specified token" }, - "sendTo": { - "message": "Senden an" + "sendSwapSubmissionWarning": { + "message": "Wenn Sie auf diese Schaltfläche klicken, wird Ihre Swap-Transaktion sofort eingeleitet. Bevor Sie fortfahren, überprüfen Sie bitte Ihre Transaktionsdetails." + }, + "sendTokenAsToken": { + "message": "$1 als $2 senden", + "description": "Used in the transaction display list to describe a swap and send. $1 and $2 are the symbols of tokens in involved in the swap." }, - "sendTokens": { - "message": "Tokens senden" + "sendingAsset": { + "message": "Senden von $1" }, "sendingDisabled": { "message": "Das Senden von ERC-1155 NFT-Assets wird noch nicht unterstützt." @@ -3400,9 +4346,15 @@ "message": "Warnhinweis: Sie sind im Begriff, an einen Token-Contract zu senden, und dies könnte zu einem Verlust Ihrer Gelder führen. $1", "description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning" }, + "sendingZeroAmount": { + "message": "Sie senden 0 $1." + }, "sepolia": { "message": "Sepolia-Testnetzwerk" }, + "serviceWorkerKeepAlive": { + "message": "serviceWorkerKeepAlive" + }, "setAdvancedPrivacySettingsDetails": { "message": "MetaMask nutzt diese vertrauenswürdigen Dienstleistungen von Drittanbietern, um die Benutzerfreundlichkeit und Sicherheit der Produkte zu verbessern." }, @@ -3414,7 +4366,7 @@ "description": "The token symbol that is being approved" }, "settingAddSnapAccount": { - "message": "Snap-Konto hinzufügen" + "message": "Konto-Snap hinzufügen" }, "settings": { "message": "Einstellungen" @@ -3422,9 +4374,21 @@ "settingsSearchMatchingNotFound": { "message": "Keine passenden Ergebnisse gefunden." }, + "settingsSubHeadingSignaturesAndTransactions": { + "message": "Signatur- und Transaktionsanfragen" + }, "show": { "message": "Zeigen" }, + "showAccount": { + "message": "Konto anzeigen" + }, + "showExtensionInFullSizeView": { + "message": "Erweiterung in Vollbildansicht anzeigen" + }, + "showExtensionInFullSizeViewDescription": { + "message": "Schalten Sie dies ein, um die Vollbildansicht als Standard einzustellen, sobald Sie auf das Erweiterungssymbol klicken." + }, "showFiatConversionInTestnets": { "message": "Umrechnung auf Testnets anzeigen" }, @@ -3444,6 +4408,9 @@ "message": "Das hängt von $1 ab, das Zugriff auf Ihre Ethereum-Adresse und Ihre IP-Adresse hat. $2", "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" }, + "showIncomingTransactionsExplainer": { + "message": "Dies hängt bei jedem Netzwerk von unterschiedlichen APIs Dritter ab, die Ihre Ethereum- und IP-Adresse offenlegen." + }, "showMore": { "message": "Mehr anzeigen" }, @@ -3483,9 +4450,46 @@ "signin": { "message": "Anmelden" }, + "signing": { + "message": "Signieren" + }, + "simulationDetailsFailed": { + "message": "Es ist ein Fehler beim Laden Ihrer Schätzung aufgetreten." + }, + "simulationDetailsFiatNotAvailable": { + "message": "Nicht verfügbar" + }, + "simulationDetailsIncomingHeading": { + "message": "Sie erhalten" + }, + "simulationDetailsNoBalanceChanges": { + "message": "Keine Änderungen für Ihre Wallet prognostiziert." + }, + "simulationDetailsOutgoingHeading": { + "message": "Sie senden" + }, + "simulationDetailsTitle": { + "message": "Geschätzte Änderungen" + }, + "simulationDetailsTitleTooltip": { + "message": "Die geschätzten Änderungen sind das, was passieren könnte, wenn Sie diese Transaktion durchführen. Dies ist nur eine Prognostizierung, keine Garantie." + }, + "simulationDetailsTotalFiat": { + "message": "Gesamt = $1", + "description": "$1 is the total amount in fiat currency on one side of the transaction" + }, + "simulationDetailsTransactionReverted": { + "message": "Diese Transaktion wird wahrscheinlich scheitern" + }, "simulationErrorMessageV2": { "message": "Wir konnten das Gas nicht schätzen. Es könnte einen Fehler im Contract geben und diese Transaktion könnte fehlschlagen." }, + "simulationsSettingDescription": { + "message": "Schalten Sie diese Option ein, um die Saldoänderungen von Transaktionen zu schätzen, bevor Sie diese bestätigen. Dies ist keine Garantie für das endgültige Ergebnis Ihrer Transaktionen. $1" + }, + "simulationsSettingSubHeader": { + "message": "Geschätzte Saldoänderungen" + }, "skip": { "message": "Überspringen" }, @@ -3498,20 +4502,99 @@ "smartContracts": { "message": "Smart Contracts" }, - "smartSwapsAreHere": { - "message": "Die Smart Swaps sind da!" - }, - "smartSwapsDescription": { - "message": "MetaMask Swaps ist jetzt wesentlich intelligenter! Die Aktivierung von Smart Swaps wird es MetaMask erlauben, Ihre Swaps programmatisch zu optimieren, um zu helfen:" - }, "smartSwapsErrorNotEnoughFunds": { "message": "Nicht genügend Gelder für einen Smart Swap." }, "smartSwapsErrorUnavailable": { "message": "Smart Swaps sind vorrübergehend nicht verfügbar." }, + "smartTransactionCancelled": { + "message": "Ihre Transaktion wurde storniert" + }, + "smartTransactionCancelledDescription": { + "message": "Ihre Transaktion konnte nicht abgeschlossen werden und wurde daher storniert, damit Sie keine unnötigen Gas-Gebühren zahlen müssen." + }, + "smartTransactionError": { + "message": "Ihre Transaktion schlug fehl" + }, + "smartTransactionErrorDescription": { + "message": "Plötzliche Marktveränderungen können zu Ausfällen führen. Wenn das Problem weiterhin besteht, wenden Sie sich an den MetaMask-Kundensupport." + }, + "smartTransactionPending": { + "message": "Übermittlung Ihrer Transaktion" + }, + "smartTransactionSuccess": { + "message": "Ihre Transaktion ist abgeschlossen" + }, + "smartTransactionTakingTooLong": { + "message": "Entschuldigung für die Wartezeit" + }, + "smartTransactionTakingTooLongDescription": { + "message": "Wenn Ihre Transaktion nicht innerhalb von $1 abgeschlossen wird, wird sie storniert und Ihnen wird kein Gas berechnet.", + "description": "$1 is remaining time in seconds" + }, + "smartTransactions": { + "message": "Smart Transactions" + }, + "smartTransactionsBenefit1": { + "message": "Erfolgsrate: 99,5 %" + }, + "smartTransactionsBenefit2": { + "message": "Spart Ihnen Geld" + }, + "smartTransactionsBenefit3": { + "message": "Updates in Echtzeit" + }, + "smartTransactionsDescription": { + "message": "Erzielen Sie mit Smart Transactions höhere Erfolgsraten, einen Frontrunning-Schutz und eine bessere Transparenz." + }, + "smartTransactionsDescription2": { + "message": "Nur auf Ethereum verfügbar. Sie können diese Funktion jederzeit in den Einstellungen aktivieren oder deaktivieren. $1", + "description": "$1 is an external link to learn more about Smart Transactions" + }, + "smartTransactionsOptItModalTitle": { + "message": "Verbesserter Transaktionsschutz" + }, + "snapAccountCreated": { + "message": "Konto erstellt" + }, + "snapAccountCreatedDescription": { + "message": "Ihr neues Konto ist jetzt einsatzbereit!" + }, + "snapAccountCreationFailed": { + "message": "Kontoerstellung fehlgeschlagen" + }, + "snapAccountCreationFailedDescription": { + "message": "$1 hat es nicht geschafft, ein Konto für Sie zu erstellen.", + "description": "$1 is the snap name" + }, + "snapAccountRedirectFinishSigningTitle": { + "message": "Unterzeichnen beenden" + }, + "snapAccountRedirectSiteDescription": { + "message": "Befolgen Sie die Anweisungen von $1" + }, + "snapAccountRemovalFailed": { + "message": "Kontoentfernung fehlgeschlagen" + }, + "snapAccountRemovalFailedDescription": { + "message": "$1 hat es nicht geschafft, dieses Konto für Sie zu löschen.", + "description": "$1 is the snap name" + }, + "snapAccountRemoved": { + "message": "Konto wurde entfernt" + }, + "snapAccountRemovedDescription": { + "message": "Dieses Konto wird in MetaMask nicht mehr zur Nutzung zur Verfügung stehen." + }, + "snapAccounts": { + "message": "Konto-Snaps" + }, + "snapAccountsDescription": { + "message": "Von Snaps Dritter kontrollierte Konten." + }, "snapConnectionWarning": { - "message": "$1 möchte sich mit $2 verbinden. Fahren Sie nur fort, wenn Sie dieser Webseite vertrauen.", + "message": "$1 möchte $2 verwenden", "description": "$2 is the snap and $1 is the dapp requesting connection to the snap." }, "snapContent": { @@ -3522,15 +4605,35 @@ "message": "Webseite" }, "snapInstallRequest": { - "message": "Durch die Installation von $1 werden folgende Genehmigungen erteilt. Nur fortfahren, wenn Sie $1 vertrauen.", + "message": "Durch die Installation von $1 erhält es die folgenden Berechtigungen.", "description": "$1 is the snap name." }, "snapInstallSuccess": { "message": "Installation ist abgeschlossen" }, + "snapInstallWarningCheck": { + "message": "$1 möchte die Genehmigung, Folgendes zu tun:", + "description": "Warning message used in popup displayed on snap install. $1 is the snap name." + }, "snapInstallWarningHeading": { "message": "Seien Sie vorsichtig" }, + "snapInstallWarningPermissionDescriptionForBip32View": { + "message": "Erlauben Sie $1, Ihre öffentlichen Schlüssel (und Adressen) einzusehen. Damit wird keine Kontrolle über Konten oder Assets gewährt.", + "description": "An extended description for the `snap_getBip32PublicKey` permission used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionDescriptionForEntropy": { + "message": "Erlauben Sie $1 Snap, Konten und Assets in dem/den gewünschten Netzwerk(en) zu verwalten. Diese Konten werden unter Verwendung Ihrer geheimen Wiederherstellungsphrase abgeleitet und gesichert (ohne sie preiszugeben). Mit der Fähigkeit, Schlüssel abzuleiten, kann $1 eine Vielzahl von Blockchain-Protokollen über Ethereum (EVMs) hinaus unterstützen.", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionNameForEntropy": { + "message": "$1-Konten verwalten", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, + "snapInstallWarningPermissionNameForViewPublicKey": { + "message": "Sehen Sie Ihren öffentlichen Schlüssel für $1 ein", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, "snapInstallationErrorDescription": { "message": "$1 konnte nicht installiert werden.", "description": "Error description used when snap installation fails. $1 is the snap name." @@ -3548,6 +4651,10 @@ "snapResultSuccessDescription": { "message": "$1 ist einsatzbereit" }, + "snapUpdateAlertDescription": { + "message": "Holen Sie sich die neueste Version von $1\n", + "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." + }, "snapUpdateAvailable": { "message": "Update verfügbar" }, @@ -3559,22 +4666,40 @@ "message": "Update fehlgeschlagen", "description": "Error title used when snap update fails." }, + "snapUpdateRequest": { + "message": "Durch die Aktualisierung von $1 erhält es die folgenden Berechtigungen.", + "description": "$1 is the Snap name." + }, "snapUpdateSuccess": { "message": "Update abgeschlossen" }, + "snapUrlIsBlocked": { + "message": "Dieser Snap hat vor, Sie auf eine gesperrte Seite zu bringen. $1." + }, "snaps": { "message": "Snaps" }, - "snapsInvalidUIError": { - "message": "Die vom Snap spezifizierte UI ist ungültig." + "snapsConnected": { + "message": "Snaps wurden verbunden" }, "snapsNoInsight": { "message": "Der Snap brachte keine Einsicht." }, + "snapsPrivacyWarningFirstMessage": { + "message": "Sie erkennen an, dass es sich – sofern nicht anders angegeben – bei jedem von Ihnen installierten Snap um einen Drittanbieter-Service handelt, gemäß der in Consensys $1 genannten Definition. Ihre Nutzung von Drittanbieter-Services unterliegt separaten Bedingungen, die vom Anbieter des jeweiligen Drittanbieter-Service festgelegt werden. Consensys empfiehlt keiner bestimmten Person aus irgendeinem bestimmten Grund die Verwendung eines Snaps. Sie nehmen Zugriff auf, verlassen sich auf und verwenden die Dienste Dritter auf eigenes Risiko. Consensys lehnt jede Verantwortung und Haftung für Verluste ab, die sich aus Ihrer Nutzung von Drittanbieter-Diensten ergeben.", + "description": "First part of a message in popup modal displayed when installing a snap for the first time. $1 is terms of use link." + }, "snapsPrivacyWarningSecondMessage": { "message": "Alle Daten, die Sie mit Drittanbieterdiensten teilen, werden direkt von diesen Drittanbieterdiensten im Einklang mit deren Datenschutzerklärung erfasst. Für weitere Informationen lesen Sie bitte die jeweiligen Datenschutzerklärungen.", "description": "Second part of a message in popup modal displayed when installing a snap for the first time." }, + "snapsPrivacyWarningThirdMessage": { + "message": "Consensys hat keinen Zugriff auf die Informationen, die Sie an den Drittanbieter-Service weitergeben.", + "description": "Third part of a message in popup modal displayed when installing a snap for the first time." + }, + "snapsSettings": { + "message": "Snap-Einstellungen" + }, "snapsTermsOfUse": { "message": "Nutzungsbedingungen" }, @@ -3588,12 +4713,19 @@ "someNetworksMayPoseSecurity": { "message": "Einige Netzwerke können Sicherheits- und/oder Datenschutzrisiken bergen. Informieren Sie sich über die Risiken, bevor Sie ein Netzwerk hinzufügen und nutzen." }, + "somethingDoesntLookRight": { + "message": "Scheint irgendetwas nicht in Ordnung zu sein? $1", + "description": "A false positive message for users to contact support. $1 is a link to the support page." + }, "somethingIsWrong": { "message": "Etwas ist schiefgelaufen. Versuchen Sie, die Seite neu zu laden." }, "somethingWentWrong": { "message": "Hoppla! Etwas ist schiefgelaufen." }, + "source": { + "message": "Quelle" + }, "speedUp": { "message": "Beschleunigen" }, @@ -3728,6 +4860,14 @@ "stake": { "message": "Anteil" }, + "startYourJourney": { + "message": "Beginnen Sie Ihre Reise mit $1", + "description": "$1 is the token symbol" + }, + "startYourJourneyDescription": { + "message": "Legen Sie mit web3 los, indem Sie Ihrer Wallet $1 hinzufügen.", + "description": "$1 is the token symbol" + }, "stateLogError": { "message": "Fehler beim Abfragen der Statusprotokolle." }, @@ -3740,6 +4880,9 @@ "stateLogsDescription": { "message": "Die Statusprotokolle enthalten Ihre öffentlichen Kontoadressen und gesendeten Transaktionen." }, + "states": { + "message": "Status" + }, "status": { "message": "Status" }, @@ -3783,18 +4926,6 @@ "strong": { "message": "Stark" }, - "stxBenefit1": { - "message": "Transaktionskosten minimieren" - }, - "stxBenefit2": { - "message": "Transaktionsausfälle reduzieren" - }, - "stxBenefit3": { - "message": "Steckengebliebene Transaktionen eliminieren" - }, - "stxBenefit4": { - "message": "Front-Running verhindern" - }, "stxCancelled": { "message": "Swap wäre gescheitert" }, @@ -3804,6 +4935,10 @@ "stxCancelledSubDescription": { "message": "Versuchen Sie Ihren Swap erneut. Wir werden hier sein, um Sie beim nächsten Mal vor ähnlichen Risiken zu schützen." }, + "stxEstimatedCompletion": { + "message": "Geschätzter Abschluss in < $1", + "description": "$1 is remeaning time in minutes and seconds, e.g. 0:10" + }, "stxFailure": { "message": "Swap fehlgeschlagen" }, @@ -3811,6 +4946,9 @@ "message": "Plötzliche Marktveränderungen können zu Ausfällen führen. Wenn das Problem weiterhin besteht, wenden Sie sich bitte an $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInDescription": { + "message": "Schalten Sie Smart Transactions für zuverlässigere und sicherere Transaktionen im Ethereum Mainnet ein. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Ihr Swap wird privat abgesendet ..." }, @@ -3849,12 +4987,21 @@ "submitted": { "message": "Abgesendet" }, + "suggestedTokenSymbol": { + "message": "Vorgeschlagenes Tickersymbol:" + }, "support": { "message": "Support" }, "supportCenter": { "message": "Besuchen Sie unser Support Center." }, + "surveyConversion": { + "message": "Nehmen Sie an unserer Umfrage teil" + }, + "surveyTitle": { + "message": "Gestalten Sie die Zukunft von MetaMask" + }, "swap": { "message": "Swap" }, @@ -3874,6 +5021,9 @@ "swapAmountReceivedInfo": { "message": "Dies ist der Mindestbetrag, den Sie empfangen werden. Je nach Slippage können Sie auch mehr empfangen." }, + "swapAndSend": { + "message": "Swappen und Senden" + }, "swapAnyway": { "message": "Swap trotzdem ausführen" }, @@ -3989,6 +5139,10 @@ "message": "Enthält eine MetaMask-Gebühr von $1%.", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." }, + "swapIncludesMMFeeAlt": { + "message": "Angebot umfasst $1% MetaMask-Gebühr", + "description": "Provides information about the fee that metamask takes for swaps using the latest copy. $1 is a decimal number." + }, "swapIncludesMetaMaskFeeViewAllQuotes": { "message": "Enthält eine MetaMask-Gebühr von $1% bis $2.", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number and $2 is a link to view all quotes." @@ -3996,6 +5150,9 @@ "swapLearnMore": { "message": "Mehr über Swaps erfahren" }, + "swapLiquiditySourceInfo": { + "message": "Wir durchsuchen mehrere Liquiditätsquellen (Börsen, Aggregatoren und professionelle Market Maker), um Wechselkurse und Netzwerkgebühren zu vergleichen." + }, "swapLowSlippage": { "message": "Niedrige Slippage" }, @@ -4268,6 +5425,9 @@ "switchEthereumChainConfirmationTitle": { "message": "Dieser Seite das Wechseln eines Netzwerks erlauben?" }, + "switchInputCurrency": { + "message": "Eingangswährung wechseln" + }, "switchNetwork": { "message": "Netzwerk wechseln" }, @@ -4281,14 +5441,15 @@ "switchToThisAccount": { "message": "Zu diesem Konto wechseln" }, - "switchedTo": { - "message": "Sie haben gewechselt zu" + "switchedNetworkToastDecline": { + "message": "Nicht mehr anzeigen" }, - "switcherTitle": { - "message": "Netzwerkwechsler" + "switchedNetworkToastMessage": { + "message": "$1 ist jetzt aktiv bei $2", + "description": "$1 represents the account name, $2 represents the network name" }, - "switcherTourDescription": { - "message": "Klicken Sie auf das Symbol, um das Netzwerk zu wechseln oder ein neues Netzwerk hinzuzufügen." + "switchedTo": { + "message": "Sie haben gewechselt zu" }, "switchingNetworksCancelsPendingConfirmations": { "message": "Das Wechseln der Netzwerke wird alle ausstehenden Bestätigungen stornieren." @@ -4388,6 +5549,18 @@ "toggleEthSignOn": { "message": "EIN (nicht empfohlen)" }, + "toggleRequestQueueDescription": { + "message": "Dadurch können Sie ein Netzwerk für jede Website auswählen, anstatt ein einziges Netzwerk für alle Websites auszuwählen. Diese Funktion verhindert, dass Sie manuell zwischen den Netzwerken wechseln müssen, was die Benutzerfreundlichkeit auf bestimmten Websites beeinträchtigen könnte." + }, + "toggleRequestQueueField": { + "message": "Wählen Sie Netzwerke für jede Website" + }, + "toggleRequestQueueOff": { + "message": "Aus" + }, + "toggleRequestQueueOn": { + "message": "An" + }, "token": { "message": "Token" }, @@ -4404,7 +5577,7 @@ "message": "Token-Contract-Adresse" }, "tokenDecimalFetchFailed": { - "message": "Token-Dezimalzahlen erforderlich." + "message": "Tokendezimal erforderlich. Finden Sie es auf: $1" }, "tokenDecimalTitle": { "message": "Token-Dezimale:" @@ -4443,6 +5616,9 @@ "tooltipSatusConnected": { "message": "verbunden" }, + "tooltipSatusConnectedUpperCase": { + "message": "Verbunden" + }, "tooltipSatusNotConnected": { "message": "nicht verbunden" }, @@ -4583,6 +5759,39 @@ "tryAgain": { "message": "Erneut versuchen" }, + "turnOff": { + "message": "Ausschalten" + }, + "turnOffMetamaskNotificationsError": { + "message": "Beim Deaktivieren der Benachrichtigungen ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut." + }, + "turnOn": { + "message": "Einschalten" + }, + "turnOnMetamaskNotifications": { + "message": "Benachrichtigungen einschalten" + }, + "turnOnMetamaskNotificationsButton": { + "message": "Einschalten" + }, + "turnOnMetamaskNotificationsError": { + "message": "Beim Erstellen der Benachrichtigungen ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut." + }, + "turnOnMetamaskNotificationsMessageFirst": { + "message": "Bleiben Sie mit Benachrichtigungen auf dem Laufenden darüber, was in Ihrer Wallet passiert." + }, + "turnOnMetamaskNotificationsMessagePrivacyBold": { + "message": "Einstellungen > Benachrichtigungen." + }, + "turnOnMetamaskNotificationsMessagePrivacyLink": { + "message": "Erfahren Sie, wie wir Ihre Privatsphäre bei der Nutzung dieser Funktion schützen." + }, + "turnOnMetamaskNotificationsMessageSecond": { + "message": "Um Wallet-Benachrichtigungen zu nutzen, verwenden wir ein Profil, um bestimmte Einstellungen auf Ihren Geräten zu synchronisieren. $1" + }, + "turnOnMetamaskNotificationsMessageThird": { + "message": "Sie können die Benachrichtigungen jederzeit unter $1 ausschalten" + }, "turnOnTokenDetection": { "message": "Erweiterte Token-Erkennung aktivieren" }, @@ -4614,6 +5823,10 @@ "unknownNetwork": { "message": "Unbekanntes privates Netzwerk" }, + "unknownNetworkForKeyEntropy": { + "message": "Unbekanntes Netzwerk", + "description": "Displayed on places like Snap install warning when regular name is not available." + }, "unknownQrCode": { "message": "Fehler: Wir konnten diesen QR-Code nicht identifizieren." }, @@ -4626,6 +5839,9 @@ "unlockMessage": { "message": "Das dezentrale Web erwartet Sie" }, + "unpin": { + "message": "Lösen" + }, "unrecognizedChain": { "message": "Dieses benutzerdefinierte Netzwerk wird nicht erkannt.", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." @@ -4643,6 +5859,9 @@ "update": { "message": "Update" }, + "updateRequest": { + "message": "Aktualisierungsanfrage" + }, "updatedWithDate": { "message": "$1 aktualisiert" }, @@ -4667,12 +5886,25 @@ "useNftDetection": { "message": "NFTs automatisch erkennen" }, + "useNftDetectionDescriptionText": { + "message": "Lassen Sie MetaMask NFTs, die Sie besitzen, anhand von Drittanbieterdiensten (wie OpenSea) hinzufügen. Durch die automatische Erkennung von NFTs werden Ihre IP- und Kontoadresse für diese Dienste offengelegt. Durch die Aktivierung dieser Funktion können eventuell Ihre IP- und Ethereum-Adresse miteinander in Verbindung gebracht und gefälschte, von Betrügern per Airdropping abgesetzte NFTs anzeigt werden. Es ist möglich, Tokens manuell hinzufügen, um dieses Risiko zu vermeiden." + }, "usePhishingDetection": { "message": "Phishing-Erkennung verwenden" }, "usePhishingDetectionDescription": { "message": "Zeigt eine Warnung für Phishing-Domains, die Ethereum-Nutzer ansprechen." }, + "useSafeChainsListValidation": { + "message": "Überprüfung der Netzwerkangaben" + }, + "useSafeChainsListValidationDescription": { + "message": "MetaMask verwendet einen Drittanbieter-Service namens $1, um genaue und standardisierte Netzwerkangaben anzuzeigen. Dies verringert die Wahrscheinlichkeit, dass Sie mit einem bösartigen oder falschen Netzwerk in Verbindungen treten. Wenn Sie diese Funktion benutzen, wird Ihre IP-Adresse chainid.network gegenüber offengelegt." + }, + "useSafeChainsListValidationWebsite": { + "message": "chainid.network", + "description": "useSafeChainsListValidationWebsite is separated from the rest of the text so that we can bold the third party service name in the middle of them" + }, "useSiteSuggestion": { "message": "Seitenvorschlag verwenden" }, @@ -4685,6 +5917,9 @@ "userName": { "message": "Nutzername" }, + "userOpContractDeployError": { + "message": "Contract-Bereitstellung von einem Smart-Contract-Konto wird nicht unterstützt" + }, "verifyContractDetails": { "message": "Drittanbieter-Details überprüfen" }, @@ -4702,6 +5937,9 @@ "view": { "message": "Anzeigen" }, + "viewActivity": { + "message": "Aktivität anzeigen" + }, "viewAllDetails": { "message": "Alle Details anzeigen" }, @@ -4725,7 +5963,7 @@ }, "viewOnCustomBlockExplorer": { "message": "Zeige $1 bei $2", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "$1 auf Etherscan anzeigen", @@ -4737,6 +5975,9 @@ "viewOnOpensea": { "message": "Auf Opensea ansehen" }, + "viewTransaction": { + "message": "Transaktion einsehen" + }, "viewinCustodianApp": { "message": "In Verwahrungs-App anzeigen" }, @@ -4744,6 +5985,9 @@ "message": "$1 im Explorer anzeigen", "description": "$1 is the action type. e.g (Account, Transaction, Swap)" }, + "visitSite": { + "message": "Seite besuchen" + }, "visitWebSite": { "message": "Besuchen Sie unsere Webseite." }, @@ -4782,6 +6026,10 @@ "warning": { "message": "Warnung" }, + "warningFromSnap": { + "message": "Warnung von $1", + "description": "$1 represents the name of the snap" + }, "warningTooltipText": { "message": "$1 Der Dritte könnte Ihr gesamtes Token-Guthaben ohne weitere Benachrichtigung oder Zustimmung ausgeben. Schützen Sie sich, indem Sie eine niedrigere Ausgabenobergrenze festlegen.", "description": "$1 is a warning icon with text 'Be careful' in 'warning' colour" @@ -4789,6 +6037,9 @@ "weak": { "message": "Schwach" }, + "web3": { + "message": "Web3" + }, "web3ShimUsageNotification": { "message": "Wir haben festgestellt, dass die aktuelle Webseite versucht hat, die entfernte window.web3 API zu verwenden. Sollte die Seite defekt sein, klicken Sie bitte auf $1 für weitere Informationen.", "description": "$1 is a clickable link." @@ -4829,10 +6080,6 @@ "whatsThis": { "message": "Was ist das?" }, - "xOfY": { - "message": "$1 von $2", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$1 von $2 ausstehend", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" @@ -4840,6 +6087,9 @@ "yes": { "message": "Ja" }, + "you": { + "message": "Sie" + }, "youHaveAddedAll": { "message": "Sie haben alle beliebten Netzwerke hinzugefügt. Sie können weitere Netzwerke entdecken $1 oder Sie können $2", "description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'" @@ -4862,6 +6112,12 @@ "yourPrivateSeedPhrase": { "message": "Ihre geheime Wiederherstellungsphrase" }, + "yourTransactionConfirmed": { + "message": "Transaktion bereits bestätigt" + }, + "yourTransactionJustConfirmed": { + "message": "Wir waren nicht in der Lage, Ihre Transaktion zu stornieren, bevor sie in der Blockchain bestätigt wurde." + }, "zeroGasPriceOnSpeedUpError": { "message": "Keine Gas-Kosten bei Beschleunigung" } diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index aa32480036bd..cfbe0bd874dd 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -130,12 +130,21 @@ "account": { "message": "Λογαριασμός" }, + "accountActivity": { + "message": "Δραστηριότητα λογαριασμού" + }, + "accountActivityText": { + "message": "Επιλέξτε τους λογαριασμούς για τους οποίους θέλετε να λαμβάνετε ειδοποιήσεις:" + }, "accountDetails": { "message": "Στοιχεία λογαριασμού" }, "accountIdenticon": { "message": "Αναγνωριστικό Λογαριασμού" }, + "accountIsntConnectedToastText": { + "message": "Το $1 δεν συνδέεται με το $2" + }, "accountName": { "message": "Όνομα Λογαριασμού" }, @@ -153,6 +162,12 @@ "accountSelectionRequired": { "message": "Πρέπει να επιλέξετε έναν λογαριασμό!" }, + "accounts": { + "message": "Λογαριασμοί" + }, + "accountsConnected": { + "message": "Συνδεδεμένοι λογαριασμοί" + }, "active": { "message": "Ενεργό" }, @@ -243,6 +258,9 @@ "addIPFSGateway": { "message": "Προσθέστε την πύλη IPFS που προτιμάτε" }, + "addImportAccount": { + "message": "Προσθήκη λογαριασμού ή πορτοφολιού υλικού" + }, "addMemo": { "message": "Προσθήκη σημειώματος" }, @@ -256,6 +274,9 @@ "message": "Αυτή η σύνδεση δικτύου βασίζεται σε τρίτους. H σύνδεση ενδέχεται να είναι λιγότερο αξιόπιστη ή να επιτρέπει σε τρίτους να παρακολουθούν τη δραστηριότητα. $1", "description": "$1 is Learn more link" }, + "addNewAccount": { + "message": "Προσθήκη νέου λογαριασμού" + }, "addNewToken": { "message": "Προσθήκη νέου token" }, @@ -265,6 +286,12 @@ "addNfts": { "message": "Προσθήκη των NFT" }, + "addSnapAccountToggle": { + "message": "Ενεργοποίηση της λειτουργίας \"Προσθήκη λογαριασμού Snap (Beta)\"" + }, + "addSnapAccountsDescription": { + "message": "Η ενεργοποίηση αυτής της λειτουργίας θα σας δώσει τη δυνατότητα να προσθέσετε νέο λογαριασμό Snaps Beta απευθείας από τη λίστα λογαριασμών σας. Εάν εγκαταστήσετε έναν λογαριασμό Snap, να θυμάστε ότι πρόκειται για μια υπηρεσία τρίτων." + }, "addSuggestedNFTs": { "message": "Προσθήκη προτεινόμενων NFT" }, @@ -281,6 +308,9 @@ "addingCustomNetwork": { "message": "Προσθήκη δικτύου" }, + "addingTokens": { + "message": "Προσθήκη tokens" + }, "address": { "message": "Διεύθυνση" }, @@ -316,9 +346,27 @@ "airgapVault": { "message": "Θησαυροφυλάκιο AirGap" }, + "alert": { + "message": "Ειδοποίηση" + }, + "alertBannerMultipleAlertsDescription": { + "message": "Εάν εγκρίνετε αυτό το αίτημα, ένας τρίτος που είναι γνωστός για απάτες μπορεί να αποκτήσει όλα τα περιουσιακά σας στοιχεία." + }, + "alertBannerMultipleAlertsTitle": { + "message": "Πολλαπλές ειδοποιήσεις!" + }, "alertDisableTooltip": { "message": "Αυτό μπορεί να αλλάξει στις \"Ρυθμίσεις > Ειδοποιήσεις\"" }, + "alertModalAcknowledge": { + "message": "Αναγνωρίζω τον κίνδυνο και εξακολουθώ να θέλω να συνεχίσω" + }, + "alertModalDetails": { + "message": "Λεπτομέρειες ειδοποίησης" + }, + "alertModalReviewAllAlerts": { + "message": "Έλεγχος όλων των ειδοποιήσεων" + }, "alertSettingsUnconnectedAccount": { "message": "Περιήγηση σε έναν ιστότοπο με έναν μη συνδεδεμένο επιλέγμενο λογαριασμό" }, @@ -334,6 +382,9 @@ "alerts": { "message": "Ειδοποιήσεις" }, + "all": { + "message": "Όλες" + }, "allCustodianAccountsConnectedSubtitle": { "message": "Είτε έχετε ήδη συνδέσει όλους τους λογαριασμούς θεματοφύλακα είτε δεν έχετε κανέναν λογαριασμό να συνδέσετε με το MetaMask Institutional." }, @@ -344,23 +395,26 @@ "message": "Όλα σας τα $1", "description": "$1 is the symbol or name of the token that the user is approving spending" }, + "allPermissions": { + "message": "Όλες οι άδειες χρήσης" + }, "allYourNFTsOf": { "message": "Όλα τα NFT σας από το $1", "description": "$1 is a link to contract on the block explorer when we're not able to retrieve a erc721 or erc1155 name" }, - "allowExternalExtensionTo": { - "message": "Επιτρέψτε σε αυτή την εξωτερική επέκταση να:" + "allow": { + "message": "Να επιτρέπεται" + }, + "allowMmiToConnectToCustodian": { + "message": "Αυτό θα επιτρέψει στο MMI να συνδεθεί στο $1 για να εισαγάγει τους λογαριασμούς σας." + }, + "allowNotifications": { + "message": "Να επιτρέπονται οι ειδοποιήσεις" }, "allowSpendToken": { "message": "Δίνετε άδεια για να αποκτήσετε πρόσβαση στο $1;", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "Επιτρέψτε σε αυτόν τον ιστότοπο να:" - }, - "allowThisSnapTo": { - "message": "Επιτρέψτε αυτό το snap να:" - }, "allowWithdrawAndSpend": { "message": "Επιτρέψτε στο $1 να κάνει ανάληψη και να ξοδέψει μέχρι το ακόλουθο ποσό:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -368,6 +422,23 @@ "amount": { "message": "Ποσό" }, + "amountReceived": { + "message": "Ποσό που λάβατε" + }, + "amountSent": { + "message": "Ποσό που στείλατε" + }, + "andForListItems": { + "message": "$1 και $2", + "description": "$1 is the first item, $2 is the last item in a list of items. Used in Snap Install Warning modal." + }, + "andForTwoItems": { + "message": "$1 και $2", + "description": "$1 is the first item, $2 is the second item. Used in Snap Install Warning modal." + }, + "announcements": { + "message": "Ανακοινώσεις" + }, "appDescription": { "message": "Ένα Πορτοφόλι Ethereum στο Πρόγραμμα Περιήγησής σας", "description": "The description of the application" @@ -402,6 +473,10 @@ "approveButtonText": { "message": "Έγκριση" }, + "approveIncreaseAllowance": { + "message": "Αύξηση $1 του ανώτατου ορίου δαπανών", + "description": "The token symbol that is being approved" + }, "approveSpendingCap": { "message": "Έγκριση $1 ως ανώτατο όριο δαπανών", "description": "The token symbol that is being approved" @@ -427,6 +502,10 @@ "message": "Εγκρίθηκε στις $1", "description": "$1 is the approval date for a permission" }, + "approvedOnForAccounts": { + "message": "Εγκρίθηκε στο $1 για $2", + "description": "$1 is the approval date for a permission. $2 is the AvatarGroup component displaying account images." + }, "areYouSure": { "message": "Είστε σίγουροι;" }, @@ -439,12 +518,21 @@ "attemptSendingAssets": { "message": "Εάν επιχειρήσετε να στείλετε περιουσιακά στοιχεία απευθείας από ένα δίκτυο σε ένα άλλο, αυτό ενδέχεται να οδηγήσει σε μόνιμη απώλεια περιουσιακών στοιχείων. Βεβαιωθείτε ότι χρησιμοποιείτε μια διασύνδεση." }, + "attemptSendingAssetsWithPortfolio": { + "message": "Μπορεί να χάσετε τα περιουσιακά σας στοιχεία αν προσπαθήσετε να τα στείλετε από άλλο δίκτυο. Μεταφέρετε χρήματα με ασφάλεια μεταξύ δικτύων χρησιμοποιώντας μια διασύνδεση, όπως το $1" + }, + "attemptToCancelSwapForFree": { + "message": "Προσπάθεια ακύρωσης των ανταλλαγών δωρεάν" + }, "attemptingConnect": { "message": "Προσπάθεια σύνδεσης στο blockchain." }, "attributions": { "message": "Αποδόσεις" }, + "auroraRpcDeprecationMessage": { + "message": "Η διεύθυνση URL του Infura RPC δεν υποστηρίζει πλέον την Aurora." + }, "authorizedPermissions": { "message": "Έχετε εξουσιοδοτήσει τα ακόλουθα δικαιώματα" }, @@ -479,6 +567,9 @@ "backupApprovalNotice": { "message": "Δημιουργήστε αντίγραφο ασφαλείας της Μυστικής σας Φράσης Ανάκτησης για να διατηρήσετε το πορτοφόλι και τα χρήματά σας ασφαλή." }, + "backupKeyringSnapReminder": { + "message": "Βεβαιωθείτε ότι μπορείτε να έχετε πρόσβαση σε όλους τους λογαριασμούς που έχουν δημιουργηθεί από αυτό το Snap πριν το αφαιρέσετε" + }, "backupNow": { "message": "Δημιουργήστε αντίγραφο ασφαλείας τώρα" }, @@ -500,6 +591,30 @@ "basic": { "message": "Βασικά" }, + "basicConfigurationBannerCTA": { + "message": "Ενεργοποίηση βασικών λειτουργιών" + }, + "basicConfigurationBannerTitle": { + "message": "Οι βασικές λειτουργίες είναι απενεργοποιημένες" + }, + "basicConfigurationLabel": { + "message": "Βασικές λειτουργίες" + }, + "basicConfigurationModalCheckbox": { + "message": "Το κατανοώ και θέλω να συνεχίσω" + }, + "basicConfigurationModalDisclaimerOff": { + "message": "Αυτό σημαίνει ότι δεν θα αξιοποιήσετε πλήρως τον χρόνο σας στο MetaMask. Βασικές λειτουργίες (όπως λεπτομέρειες για tokens, βέλτιστες ρυθμίσεις τελών συναλλαγών και άλλα) δεν θα είναι διαθέσιμές σε εσάς." + }, + "basicConfigurationModalDisclaimerOn": { + "message": "Για να αξιοποιήσετε τον χρόνο σας στο MetaMask, θα πρέπει να ενεργοποιήσετε αυτή τη λειτουργία. Οι βασικές λειτουργίες (όπως οι λεπτομέρειες για tokens, οι βέλτιστες ρυθμίσεις τελών συναλλαγών και άλλα) είναι σημαντικές για την εμπειρία web3." + }, + "basicConfigurationModalHeadingOff": { + "message": "Απενεργοποίηση βασικών λειτουργιών" + }, + "basicConfigurationModalHeadingOn": { + "message": "Ενεργοποίηση βασικών λειτουργιών" + }, "beCareful": { "message": "Να είστε προσεκτικοί" }, @@ -571,6 +686,9 @@ "blockaidDescriptionTransferFarming": { "message": "Εάν εγκρίνετε αυτό το αίτημα, ένας τρίτος που είναι γνωστός για απάτες θα πάρει όλα τα περιουσιακά σας στοιχεία." }, + "blockaidMessage": { + "message": "Διαφύλαξη της ιδιωτικότητας - δεν κοινοποιούνται δεδομένα σε τρίτους. Διατίθεται στα Arbitrum, Avalanche, BNB chain, Ethereum Mainnet, Linea, Optimism, Polygon, Base και Sepolia." + }, "blockaidTitleDeceptive": { "message": "Αυτό είναι ένα παραπλανητικό αίτημα" }, @@ -586,6 +704,9 @@ "bridge": { "message": "Διασύνδεση" }, + "bridgeDontSend": { + "message": "Μην στείλετε χωρίς διασύνδεση" + }, "browserNotSupported": { "message": "Το Πρόγραμμα Περιήγησής σας δεν υποστηρίζεται..." }, @@ -598,6 +719,9 @@ "busy": { "message": "Απασχολημένο" }, + "buyAndSell": { + "message": "Αγορά & Πώληση" + }, "buyAsset": { "message": "Αγορά $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -609,6 +733,10 @@ "buyNow": { "message": "Αγοράστε Τώρα" }, + "buyToken": { + "message": "Αγορά $1", + "description": "$1 is the token symbol" + }, "bytes": { "message": "Bytes" }, @@ -618,9 +746,6 @@ "cancel": { "message": "Άκυρο" }, - "cancelEdit": { - "message": "Ακύρωση επεξεργασίας" - }, "cancelPopoverTitle": { "message": "Ακύρωση συναλλαγής" }, @@ -647,6 +772,9 @@ "chainIdExistsErrorMsg": { "message": "Αυτό το αναγνωριστικό αλυσίδας χρησιμοποιείται επί του παρόντος από το δίκτυο $1." }, + "chainListReturnedDifferentTickerSymbol": { + "message": "Αυτό το σύμβολο token δεν ταιριάζει με το όνομα δικτύου ή το αναγνωριστικό αλυσίδας που καταχωρίσατε. Πολλά δημοφιλή token χρησιμοποιούν παρόμοια σύμβολα, τα οποία μπορούν να χρησιμοποιήσουν οι απατεώνες για να σας εξαπατήσουν ώστε να τους στείλετε ένα πιο πολύτιμο token σε αντάλλαγμα. Επαληθεύστε τα πάντα πριν συνεχίσετε." + }, "chooseYourNetwork": { "message": "Επιλέξτε το δίκτυό σας" }, @@ -682,9 +810,19 @@ "close": { "message": "Κλείσιμο" }, + "closeExtension": { + "message": "Κλείσιμο επέκτασης" + }, + "closeWindowAnytime": { + "message": "Μπορείτε να κλείσετε αυτό το παράθυρο ανά πάσα στιγμή." + }, "coingecko": { "message": "CoinGecko" }, + "comboNoOptions": { + "message": "Δεν βρέθηκαν επιλογές", + "description": "Default text shown in the combo field dropdown if no options." + }, "configureSnapPopupDescription": { "message": "Τώρα αποχωρείτε από το MetaMask για να ρυθμίσετε αυτό το snap." }, @@ -703,12 +841,42 @@ "confirm": { "message": "Επιβεβαίωση" }, + "confirmAlertModalAcknowledge": { + "message": "Έχω ενημερωθεί για τις ειδοποιήσεις και εξακολουθώ να θέλω να συνεχίσω" + }, + "confirmAlertModalDetails": { + "message": "Εάν συνδεθείτε, ένας τρίτος που είναι γνωστός για απάτες μπορεί να αποκτήσει όλα τα περιουσιακά σας στοιχεία. Ελέγξτε τις ειδοποιήσεις πριν συνεχίσετε." + }, + "confirmAlertModalTitle": { + "message": "Τα περιουσιακά σας στοιχεία μπορεί να κινδυνεύουν" + }, + "confirmConnectCustodianRedirect": { + "message": "Θα σας ανακατευθύνουμε στο $1 όταν κάνετε κλικ για να συνεχίσετε." + }, + "confirmConnectCustodianText": { + "message": "Για να συνδέσετε τους λογαριασμούς σας εισέλθετε στον λογαριασμό σας στο $1 και κάντε κλικ στο κουμπί «σύνδεση με το MMI»." + }, + "confirmConnectionTitle": { + "message": "Επιβεβαίωση σύνδεσης με το $1" + }, "confirmPassword": { "message": "Επιβεβαίωση Κωδικού Πρόσβασης" }, "confirmRecoveryPhrase": { "message": "Επιβεβαιώστε τη Μυστική Φράση Ανάκτησης" }, + "confirmTitleDescContractInteractionTransaction": { + "message": "Επιβεβαιώστε αυτή τη συναλλαγή μόνο εάν κατανοείτε πλήρως το περιεχόμενο και εμπιστεύεστε τον ιστότοπο που τη ζητάει." + }, + "confirmTitleDescSignature": { + "message": "Επιβεβαιώστε αυτό το μήνυμα μόνο εάν εγκρίνετε το περιεχόμενο και εμπιστεύεστε τον ιστότοπο που το ζητάει." + }, + "confirmTitleSignature": { + "message": "Αίτημα υπογραφής" + }, + "confirmTitleTransaction": { + "message": "Αίτημα συναλλαγής" + }, "confirmed": { "message": "Επιβεβαιωμένο" }, @@ -724,9 +892,15 @@ "connect": { "message": "Σύνδεση" }, + "connectAccount": { + "message": "Σύνδεση λογαριασμού" + }, "connectAccountOrCreate": { "message": "Σύνδεση λογαριασμού ή δημιουργία νέου" }, + "connectAccounts": { + "message": "Σύνδεση λογαριασμών" + }, "connectCustodialAccountMenu": { "message": "Σύνδεση λογαριασμού θεματοφύλακα" }, @@ -736,36 +910,25 @@ "connectCustodialAccountTitle": { "message": "Λογαριασμοί θεματοφύλακα" }, + "connectCustodianAccounts": { + "message": "Σύνδεση των $1 λογαριασμών" + }, "connectManually": { "message": "Χειροκίνητη σύνδεση στον τρέχοντα ιστότοπο" }, + "connectMoreAccounts": { + "message": "Σύνδεση περισσότερων λογαριασμών" + }, "connectSnap": { "message": "Σύνδεση $1", "description": "$1 is the snap for which a connection is being requested." }, - "connectTo": { - "message": "Σύνδεση με $1", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "Συνδεθείτε σε όλα τα $1 σας", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "λογαριασμοί", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "Σύνδεση με $1", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1 λογαριασμοί", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "Σύνδεση με το MetaMask" }, + "connectedAccounts": { + "message": "Συνδεδεμένοι λογαριασμοί" + }, "connectedAccountsDescriptionPlural": { "message": "Έχετε $1 λογαριασμούς συνδεδεμένους με αυτόν τον ιστότοπο.", "description": "$1 is the number of accounts" @@ -776,6 +939,13 @@ "connectedAccountsEmptyDescription": { "message": "To MetaMask δεν είναι συνδεδεμένo σε αυτόν τον ιστότοπο. Για να συνδεθείτε σε έναν ιστότοπο web3, βρείτε και κάντε κλικ στο κουμπί σύνδεσης." }, + "connectedAccountsListTooltip": { + "message": "Το $1 μπορεί να δει το υπόλοιπο του λογαριασμού, τη διεύθυνση, τη δραστηριότητα και να προτείνει συναλλαγές προς έγκριση για συνδεδεμένους λογαριασμούς.", + "description": "$1 is the origin name" + }, + "connectedAccountsToast": { + "message": "Οι συνδεδεμένοι λογαριασμοί ενημερώθηκαν" + }, "connectedSites": { "message": "Συνδεδεμένοι ιστότοποι" }, @@ -787,12 +957,21 @@ "message": "Το $1 δεν είναι συνδεδεμένο με καμία τοποθεσία.", "description": "$1 is the account name" }, + "connectedSnapAndNoAccountDescription": { + "message": "Το MetaMask είναι συνδεδεμένο σε αυτόν τον ιστότοπο, αλλά δεν έχουν συνδεθεί ακόμα λογαριασμοί" + }, + "connectedWith": { + "message": "Συνδέεται με" + }, "connecting": { "message": "Σύνδεση..." }, "connectingTo": { "message": "Σύνδεση με $1" }, + "connectingToDeprecatedNetwork": { + "message": "Το '$1' καταργείται σταδιακά και μπορεί να μην λειτουργεί. Δοκιμάστε ένα άλλο δίκτυο." + }, "connectingToGoerli": { "message": "Σύνδεση στο δίκτυο δοκιμών Goerli" }, @@ -802,6 +981,9 @@ "connectingToLineaMainnet": { "message": "Σύνδεση στο Linea Mainnet" }, + "connectingToLineaSepolia": { + "message": "Γίνεται σύνδεση στο δίκτυο δοκιμών Linea Sepolia" + }, "connectingToMainnet": { "message": "Σύνδεση στο Ethereum Mainnet" }, @@ -831,6 +1013,12 @@ "continue": { "message": "Συνέχεια" }, + "continueMmiOnboarding": { + "message": "Συνεχίστε στο περιβάλλον του MetaMask Institutional" + }, + "continueToWallet": { + "message": "Συνεχίστε στο πορτοφόλι" + }, "contract": { "message": "Συμβόλαιο" }, @@ -882,6 +1070,9 @@ "copyAddress": { "message": "Αντιγραφή διεύθυνσης στο πρόχειρο" }, + "copyPrivateKey": { + "message": "Αντιγραφή ιδιωτικού κλειδιού" + }, "copyRawTransactionData": { "message": "Αντιγραφή ακατέργαστων δεδομένων συναλλαγών" }, @@ -900,6 +1091,15 @@ "createPassword": { "message": "Δημιουργία κωδικού πρόσβασης" }, + "createSnapAccountDescription": { + "message": "Το $1 θέλει να προσθέσει έναν νέο λογαριασμό στο MetaMask." + }, + "createSnapAccountTitle": { + "message": "Δημιουργία λογαριασμού" + }, + "crossChainSwapsLink": { + "message": "Εναλλαγή σε διάφορα δίκτυα με το MetaMask Portfolio" + }, "cryptoCompare": { "message": "CryptoCompare" }, @@ -955,6 +1155,12 @@ "custodianAccountAddedTitle": { "message": "Έχουν προστεθεί επιλεγμένοι λογαριασμοί θεματοφύλακα." }, + "custodianQRCodeScan": { + "message": "Σαρώστε τον κωδικό QR με την εφαρμογή $1 για κινητά" + }, + "custodianQRCodeScanDescription": { + "message": "Ή συνδεθείτε στον λογαριασμό σας $1 και κάντε κλικ στο κουμπί 'Σύνδεση στο MMI'" + }, "custodianReplaceRefreshTokenChangedFailed": { "message": "Παρακαλούμε μεταβείτε στο $1 και κάντε κλικ στο κουμπί «Σύνδεση με το MMI» στο περιβάλλον εργασίας χρήστη για να συνδέσετε ξανά τους λογαριασμούς σας με το MMI." }, @@ -1025,6 +1231,12 @@ "customerSupport": { "message": "υποστήριξη πελατών" }, + "customizeYourNotifications": { + "message": "Προσαρμόστε τις ειδοποιήσεις σας" + }, + "customizeYourNotificationsText": { + "message": "Ενεργοποιήστε τους τύπους ειδοποιήσεων που θέλετε να λαμβάνετε:" + }, "dappRequestedSpendingCap": { "message": "Αιτούμενο ανώτατο όριο δαπανών του ιστότοπου" }, @@ -1108,6 +1320,18 @@ "deposit": { "message": "Κατάθεση" }, + "deprecatedGoerliNtwrkMsg": { + "message": "Εξαιτίας των ενημερώσεων στο σύστημα Ethereum, το δίκτυο δοκιμών Goerli θα καταργηθεί σύντομα." + }, + "deprecatedNetwork": { + "message": "Αυτό το δίκτυο έχει καταργηθεί" + }, + "deprecatedNetworkButtonMsg": { + "message": "Κατανοητό" + }, + "deprecatedNetworkDescription": { + "message": "Το δίκτυο στο οποίο προσπαθείτε να συνδεθείτε δεν υποστηρίζεται πλέον από το Metamask. $1" + }, "description": { "message": "Περιγραφή" }, @@ -1115,110 +1339,20 @@ "message": "Περιγραφή από $1", "description": "$1 represents the name of the snap" }, - "desktopApp": { - "message": "Εφαρμογή για υπολογιστές" - }, - "desktopConnectionCriticalErrorDescription": { - "message": "Αυτό το σφάλμα μπορεί να είναι περιστασιακό, οπότε δοκιμάστε να επανεκκινήσετε την επέκταση ή απενεργοποιήστε το MetaMask Desktop." - }, - "desktopConnectionCriticalErrorTitle": { - "message": "Το MetaMask είχε πρόβλημα κατά την εκκίνηση" - }, - "desktopConnectionLostErrorDescription": { - "message": "Βεβαιωθείτε ότι έχετε την εφαρμογή για την επιφάνεια εργασίας σε λειτουργία ή απενεργοποιήστε το MetaMask Desktop." - }, - "desktopConnectionLostErrorTitle": { - "message": "Η σύνδεση με το MetaMask Desktop χάθηκε" - }, - "desktopDisableButton": { - "message": "Απενεργοποιήστε την εφαρμογή για την επιφάνεια εργασίας" - }, - "desktopDisableErrorCTA": { - "message": "Απενεργοποιήστε το MetaMask Desktop" - }, - "desktopEnableButton": { - "message": "Ενεργοποιήστε την εφαρμογή για την επιφάνεια εργασίας" - }, - "desktopEnableButtonDescription": { - "message": "Κάντε κλικ για να εκτελέσετε όλες τις διεργασίες παρασκηνίου στην εφαρμογή επιφάνειας εργασίας." - }, - "desktopErrorNavigateSettingsCTA": { - "message": "Επιστροφή στη σελίδα Ρυθμίσεις" - }, - "desktopErrorRestartMMCTA": { - "message": "Επανεκκίνηση του MetaMask" - }, - "desktopNotFoundErrorCTA": { - "message": "Λήψη του MetaMask Desktop" - }, - "desktopNotFoundErrorDescription1": { - "message": "Βεβαιωθείτε ότι έχετε ενεργοποιήσει και εκτελείτε την εφαρμογή για την επιφάνεια εργασίας." - }, - "desktopNotFoundErrorDescription2": { - "message": "Αν δεν έχετε εγκαταστήσει την εφαρμογή για την επιφάνεια εργασίας, κατεβάστε την από τον ιστότοπο του MetaMask." - }, - "desktopNotFoundErrorTitle": { - "message": "Το MetaMask Desktop δεν βρέθηκε" - }, - "desktopOpenOrDownloadCTA": { - "message": "Άνοιγμα του MetaMask Desktop" - }, - "desktopOutdatedErrorCTA": { - "message": "Ενημέρωση του MetaMask Desktop" - }, - "desktopOutdatedErrorDescription": { - "message": "Η εφαρμογή MetaMask Desktop πρέπει να αναβαθμιστεί." - }, - "desktopOutdatedErrorTitle": { - "message": "Το MetaMask Desktop είναι ξεπερασμένο" - }, - "desktopOutdatedExtensionErrorCTA": { - "message": "Ενημέρωση της επέκτασης MetaMask" - }, - "desktopOutdatedExtensionErrorDescription": { - "message": "Η επέκταση του MetaMask πρέπει να αναβαθμιστεί." - }, - "desktopOutdatedExtensionErrorTitle": { - "message": "Η επέκταση του MetaMask είναι ξεπερασμένη" - }, - "desktopPageDescription": { - "message": "Εάν η ζεύξη είναι επιτυχής, η επέκταση θα επανεκκινηθεί και θα πρέπει να εισαγάγετε εκ νέου τον κωδικό πρόσβασής σας." - }, - "desktopPageSubTitle": { - "message": "Ανοίξτε το MetaMask Desktop και πληκτρολογήστε αυτόν τον κωδικό" - }, - "desktopPageTitle": { - "message": "Ζεύξη με το Desktop" - }, - "desktopPairedWarningDeepLink": { - "message": "Μεταβείτε στις Ρυθμίσεις στο MetaMask Desktop" - }, - "desktopPairedWarningDescription": { - "message": "Αν θέλετε να ξεκινήσετε μια νέα ζεύξη, αφαιρέστε την τρέχουσα σύνδεση." - }, - "desktopPairedWarningTitle": { - "message": "Το MM Desktop είναι ήδη συνδεδεμένο" - }, - "desktopPairingExpireMessage": { - "message": "Ο κωδικός λήγει σε $1 δευτερόλεπτα" - }, - "desktopRouteNotFoundErrorDescription": { - "message": "desktopRouteNotFoundErrorDescription" + "details": { + "message": "Λεπτομέρειες" }, - "desktopRouteNotFoundErrorTitle": { - "message": "desktopRouteNotFoundErrorTitle" + "developerOptions": { + "message": "Επιλογές προγραμματιστών" }, - "desktopUnexpectedErrorCTA": { - "message": "Επιστροφή στην αρχική σελίδα του MetaMask" + "developerOptionsResetStatesAnnouncementsDescription": { + "message": "Επαναφέρει το δυαδικό isShown σε ψευδές για όλες τις ανακοινώσεις. Οι ανακοινώσεις είναι οι ειδοποιήσεις που εμφανίζονται στο αναδυόμενο παράθυρο \"Τι νέο υπάρχει\"." }, - "desktopUnexpectedErrorDescription": { - "message": "Ελέγξτε το MetaMask Desktop για να επαναφέρετε τη σύνδεση" + "developerOptionsResetStatesOnboarding": { + "message": "Επαναφέρει διάφορες καταστάσεις που σχετίζονται με την ενσωμάτωση και ανακατευθύνει στη σελίδα ενσωμάτωσης \"Ασφαλίστε το πορτοφόλι σας\"." }, - "desktopUnexpectedErrorTitle": { - "message": "Κάτι πήγε στραβά..." - }, - "details": { - "message": "Λεπτομέρειες" + "developerOptionsServiceWorkerKeepAlive": { + "message": "Αυτό έχει ως αποτέλεσμα τη συνεχή αποθήκευση μιας χρονοσφραγίδας στο session.storage" }, "disabledGasOptionToolTipMessage": { "message": "Το \"1$\" είναι απενεργοποιημένο επειδή δεν πληροί την ελάχιστη αύξηση 10% σε σχέση με τα αρχικά τέλη συναλλαγής.", @@ -1233,12 +1367,38 @@ "disconnectAllAccountsConfirmationDescription": { "message": "Είστε βέβαιοι ότι θέλετε να αποσυνδεθείτε; Μπορεί να χάσετε τη λειτουργικότητα της ιστοσελίδας." }, + "disconnectAllAccountsText": { + "message": "λογαριασμοί" + }, + "disconnectAllSnapsText": { + "message": "Snaps" + }, + "disconnectAllText": { + "message": "Αν αποσυνδέσετε τo $1 από τo $2, θα πρέπει να επανασυνδεθείτε για να τα χρησιμοποιήσετε ξανά.", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`, $2 represents the website hostname" + }, + "disconnectAllTitle": { + "message": "Αποσύνδεση όλων των $1", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`" + }, "disconnectPrompt": { "message": "Αποσύνδεση $1" }, "disconnectThisAccount": { "message": "Αποσύνδεση αυτού του λογαριασμού" }, + "disconnectedAllAccountsToast": { + "message": "Όλοι οι λογαριασμοί αποσυνδέθηκαν από το $1", + "description": "$1 is name of the dapp`" + }, + "disconnectedSingleAccountToast": { + "message": "Το $1 αποσυνδέθηκε από το $2", + "description": "$1 is name of the name and $2 represents the dapp name`" + }, + "discoverSnaps": { + "message": "Ανακαλύψτε τα Snaps", + "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." + }, "dismiss": { "message": "Παράβλεψη" }, @@ -1248,9 +1408,21 @@ "dismissReminderField": { "message": "Απορρίψτε την υπενθύμιση δημιουργίας αντιγράφων ασφαλείας της Μυστικής Φράσης Ανάκτησης" }, + "displayNftMedia": { + "message": "Προβολή μέσων NFT" + }, + "displayNftMediaDescription": { + "message": "Η προβολή μέσων και δεδομένων NFT εκθέτει τη διεύθυνση IP σας στo OpenSea ή σε άλλους τρίτους. Αυτό μπορεί να επιτρέψει στους εισβολείς να συσχετίσουν τη διεύθυνση IP σας με τη διεύθυνση σας στο Ethereum. Η αυτόματη ανίχνευση NFT βασίζεται σε αυτή τη ρύθμιση και δεν θα είναι διαθέσιμη όταν είναι απενεργοποιημένη." + }, + "doNotShare": { + "message": "Μην το μοιραστείτε με κανέναν" + }, "domain": { "message": "Τομέας" }, + "domainNotSupportedOnNetwork": { + "message": "Το δίκτυο δεν υποστηρίζει αναζήτηση τομέα" + }, "done": { "message": "Τέλος" }, @@ -1269,6 +1441,9 @@ "downloadStateLogs": { "message": "Λήψη Αρχείων Καταγραφής Κατάστασης" }, + "dragAndDropBanner": { + "message": "Μπορείτε να σύρετε τα δίκτυα για να τα επαναδιατάξετε. " + }, "dropped": { "message": "Απορρίφθηκε" }, @@ -1367,6 +1542,9 @@ "editSpeedUpEditGasFeeModalTitle": { "message": "Επεξεργασία τελών επίσπευσης συναλλαγής" }, + "enable": { + "message": "Ενεργοποίηση" + }, "enableAutoDetect": { "message": " Ενεργοποίηση αυτόματου εντοπισμού" }, @@ -1397,6 +1575,18 @@ "enhancedTokenDetectionAlertMessage": { "message": "Ο βελτιωμένος εντοπισμός για token είναι επί του παρόντος διαθέσιμος στο $1. $2" }, + "ensDomainsSettingDescriptionIntroduction": { + "message": "Το MetaMask σας επιτρέπει να βλέπετε τους τομείς ENS ακριβώς στη γραμμή διευθύνσεων του προγράμματος περιήγησής σας. Δείτε πώς λειτουργεί:" + }, + "ensDomainsSettingDescriptionOutroduction": { + "message": "Να έχετε υπόψη ότι η χρήση αυτής της λειτουργίας εκθέτει τη διεύθυνση IP σας σε υπηρεσίες τρίτων με IPFS." + }, + "ensDomainsSettingDescriptionPart1": { + "message": "Το MetaMask ελέγχει το συμβόλαιο ENS του Ethereum για να βρει τον κωδικό που συνδέεται με το όνομα ENS." + }, + "ensDomainsSettingDescriptionPart2": { + "message": "Εάν ο κωδικός παραπέμπει σε IPFS, μπορείτε να δείτε το περιεχόμενο που σχετίζεται με αυτόν (συνήθως έναν ιστότοπο)." + }, "ensDomainsSettingTitle": { "message": "Εμφάνιση τομέων ENS στη γραμμή διευθύνσεων" }, @@ -1438,6 +1628,9 @@ "message": "Λεπτομέρειες σφάλματος", "description": "Title for collapsible section that displays error details for debugging purposes" }, + "errorGettingSafeChainList": { + "message": "Σφάλμα κατά τη λήψη της λίστας ασφαλών αλυσίδων, συνεχίστε με προσοχή." + }, "errorMessage": { "message": "Μήνυμα: $1", "description": "Displayed error message for debugging purposes. $1 is the error message" @@ -1469,6 +1662,9 @@ "message": "Σφάλμα με $1", "description": "$1 represents the name of the snap" }, + "estimatedFee": { + "message": "Εκτιμώμενη χρέωση" + }, "ethGasPriceFetchWarning": { "message": "Η εφεδρική τιμή του τέλους συναλλαγής παρέχεται καθώς η κύρια υπηρεσία εκτίμησης τελών συναλλαγής, δεν είναι διαθέσιμη αυτή τη στιγμή." }, @@ -1498,9 +1694,21 @@ "message": "Προσαρμόστε την εμπειρία του πορτοφολιού σας.", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "extensionInsallCompleteDescription": { + "message": "Επιστρέψτε στο περιβάλλον προϊόντος του MetaMask Institutional για να συνδέσετε τους λογαριασμούς θεματοφύλακα ή αυτο-θεματοφύλακά σας." + }, + "extensionInsallCompleteTitle": { + "message": "Η εγκατάσταση της επέκτασης ολοκληρώθηκε" + }, "externalExtension": { "message": "Εξωτερική επέκταση" }, + "externalNameSourcesSetting": { + "message": "Προτεινόμενα ψευδώνυμα" + }, + "externalNameSourcesSettingDescription": { + "message": "Θα παρέχουμε προτεινόμενα ψευδώνυμα για διευθύνσεις με τις οποίες αλληλεπιδράτε από πηγές τρίτων, όπως τα Etherscan, Infura και Lens Protocol. Αυτές οι πηγές θα είναι σε θέση να δουν τις εν λόγω διευθύνσεις και τη διεύθυνση IP σας. Η διεύθυνση του λογαριασμού σας δεν θα εκτεθεί σε τρίτους." + }, "failed": { "message": "Απέτυχε" }, @@ -1519,6 +1727,9 @@ "feeAssociatedRequest": { "message": "Ένα τέλος σχετίζεται με αυτό το αίτημα." }, + "feeDetails": { + "message": "Λεπτομέρειες χρεώσεων" + }, "fiat": { "message": "Εντολή", "description": "Exchange type" @@ -1551,6 +1762,9 @@ "message": "Αποδέχομαι τον κίνδυνο", "description": "this text is shown on a button, which the user presses to confirm they understand the risks of using Flask" }, + "floatAmountToken": { + "message": "Η ποσότητα των Τokens πρέπει να είναι ακέραιος αριθμός" + }, "followUsOnTwitter": { "message": "Ακολουθήστε μας στο Twitter" }, @@ -1573,6 +1787,9 @@ "fromTokenLists": { "message": "Από λίστες token: $1" }, + "function": { + "message": "Λειτουργία: $1" + }, "functionApprove": { "message": "Λειτουργία: Έγκριση" }, @@ -1582,6 +1799,13 @@ "functionType": { "message": "Τύπος λειτουργίας" }, + "fundYourWallet": { + "message": "Χρηματοδοτήστε το πορτοφόλι σας" + }, + "fundYourWalletDescription": { + "message": "Ξεκινήστε προσθέτοντας περίπου $1 στο πορτοφόλι σας.", + "description": "$1 is the token symbol" + }, "gas": { "message": "Τέλος συναλλαγής" }, @@ -1592,6 +1816,9 @@ "message": "Αυτό το τέλος συναλλαγής έχει προταθεί από το $1. Η παράκαμψη μπορεί να προκαλέσει προβλήματα με τη συναλλαγή σας. Εάν έχετε απορίες, επικοινωνήστε με $1.", "description": "$1 represents the Dapp's origin" }, + "gasIsETH": { + "message": "Τέλη συναλλαγής $1 " + }, "gasLimit": { "message": "Όριο τέλους συναλλαγής" }, @@ -1636,6 +1863,9 @@ "message": "$1 ώρες", "description": "$1 represents a number of hours" }, + "gasTimingLow": { + "message": "Με αργό ρυθμό" + }, "gasTimingMinutesShort": { "message": "$1 λεπτά", "description": "$1 represents a number of minutes" @@ -1650,15 +1880,29 @@ "general": { "message": "Γενικά" }, - "globalTitle": { - "message": "Γενικό μενού" + "generalCameraError": { + "message": "Δεν μπορέσαμε να έχουμε πρόσβαση στην κάμερά σας. Προσπαθήστε ξανά." + }, + "generalCameraErrorTitle": { + "message": "Κάτι πήγε στραβά...." + }, + "genericExplorerView": { + "message": "Προβολή λογαριασμού σε $1" }, - "globalTourDescription": { - "message": "Δείτε το χαρτοφυλάκιό σας, τις συνδεδεμένες ιστοσελίδες, τις ρυθμίσεις και πολλά άλλα" + "getStartedWithNFTs": { + "message": "Λάβετε $1 για να αγοράσετε NFT", + "description": "$1 is the token symbol" + }, + "getStartedWithNFTsDescription": { + "message": "Ξεκινήστε με NFT προσθέτοντας περίπου $1 στο πορτοφόλι σας.", + "description": "$1 is the token symbol" }, "goBack": { "message": "Πηγαίνετε πίσω" }, + "goToSite": { + "message": "Μετάβαση στον ιστότοπο" + }, "goerli": { "message": "Δοκιμαστικό δίκτυο Goerli" }, @@ -1700,15 +1944,24 @@ "hexData": { "message": "Δεκαεξαδικά δεδομένα" }, + "hiddenAccounts": { + "message": "Κρυφοί λογαριασμοί" + }, "hide": { "message": "Απόκρυψη" }, + "hideAccount": { + "message": "Απόκρυψη λογαριασμού" + }, "hideFullTransactionDetails": { "message": "Απόκρυψη αναλυτικών στοιχείων συναλλαγών" }, "hideSeedPhrase": { "message": "Απόκρυψη φράσης ανάκτησης" }, + "hideSentitiveInfo": { + "message": "Απόκρυψη ευαίσθητων πληροφοριών" + }, "hideToken": { "message": "Απόκρυψη token" }, @@ -1790,6 +2043,9 @@ "ignoreTokenWarning": { "message": "Εάν αποκρύψετε τα tokens, δεν θα εμφανίζονται στο πορτοφόλι σας. Ωστόσο, μπορείτε να τα προσθέσετε, αναζητώντας τα." }, + "imToken": { + "message": "imToken" + }, "import": { "message": "Εισαγωγή", "description": "Button to import an account from a selected file" @@ -1848,6 +2104,9 @@ "importTokensCamelCase": { "message": "Εισαγωγή tokens" }, + "importTokensError": { + "message": "Δεν μπορέσαμε να εισάγουμε τα tokens. Προσπαθήστε ξανά αργότερα." + }, "importWithCount": { "message": "Εισαγωγή $1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -1866,6 +2125,9 @@ "initialTransactionConfirmed": { "message": "Η αρχική σας συναλλαγή επιβεβαιώθηκε από το δίκτυο. Κάντε κλικ στο OK για να επιστρέψετε." }, + "inlineAlert": { + "message": "Ειδοποίηση" + }, "inputLogicEmptyState": { "message": "Πληκτρολογήστε μόνο έναν αριθμό που σας βολεύει να ξοδέψει ο τρίτος τώρα ή στο μέλλον. Μπορείτε πάντα να αυξήσετε το ανώτατο όριο δαπανών αργότερα." }, @@ -1876,6 +2138,27 @@ "inputLogicHigherNumber": { "message": "Αυτό επιτρέπει στον τρίτο να ξοδέψει όλο το υπόλοιπο των tokens σας μέχρι να φτάσει στο ανώτατο όριο ή να ανακαλέσετε το ανώτατο όριο δαπανών. Εάν δεν το θέλετε αυτό, εξετάστε το ενδεχόμενο να ορίσετε χαμηλότερο όριο δαπανών." }, + "insightWarning": { + "message": "προειδοποίηση" + }, + "insightWarningCheckboxMessage": { + "message": "$1 το αίτημα από $2", + "description": "$1 is the action i.e. sign, confirm. $2 is the origin making the request." + }, + "insightWarningContentPlural": { + "message": "Ελέγξτε το $1 πριν από το $2. Μόλις ολοκληρωθεί, το $3 είναι μη αναστρέψιμο.", + "description": "$1 the 'insightWarnings' message (2 warnings) representing warnings, $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningContentSingular": { + "message": "Ελέγξτε το $1 πριν από το $2. Μόλις γίνει, το $3 είναι μη αναστρέψιμο.", + "description": "$1 is the 'insightWarning' message (1 warning), $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningHeader": { + "message": "Το αίτημα αυτό μπορεί να είναι επικίνδυνο" + }, + "insightWarnings": { + "message": "προειδοποιήσεις" + }, "insightsFromSnap": { "message": "Απόψεις για το $1", "description": "$1 represents the name of the snap" @@ -1883,9 +2166,18 @@ "install": { "message": "Εγκατάσταση" }, + "installExtension": { + "message": "Εγκατάσταση επέκτασης" + }, + "installExtensionDescription": { + "message": "Η συμβατή με την θεσμική έκδοση του κορυφαίου web3 πορτοφολιού στον κόσμο, MetaMask." + }, "installOrigin": { "message": "Προέλευση εγκατάστασης" }, + "installRequest": { + "message": "Προσθήκη στο MetaMask" + }, "installedOn": { "message": "Εγκαταστάθηκε στο $1", "description": "$1 is the date when the snap has been installed" @@ -1914,6 +2206,12 @@ "insufficientTokens": { "message": "Ανεπαρκή tokens." }, + "interactingWith": { + "message": "Αλληλεπίδραση με" + }, + "interactingWithTransactionDescription": { + "message": "Αυτή είναι το συμβόλαιο με το οποίο αλληλεπιδράτε. Προστατευτείτε από τους απατεώνες επαληθεύοντας τις λεπτομέρειες." + }, "invalidAddress": { "message": "Μη έγκυρη διεύθυνση" }, @@ -1986,6 +2284,9 @@ "ipfsToggleModalSettings": { "message": "Ρυθμίσεις > Ασφάλεια και απόρρητο" }, + "isSigningOrSubmitting": { + "message": "Μια προηγούμενη συναλλαγή εξακολουθεί να είναι σε διαδικασία υπογραφής ή υποβολής" + }, "jazzAndBlockies": { "message": "Τα Jazzicons και τα Blockies είναι δύο διαφορετικά στυλ μοναδικών εικονιδίων που σας βοηθούν να αναγνωρίζετε έναν λογαριασμό με μια ματιά." }, @@ -1999,6 +2300,24 @@ "message": "Αρχείο JSON", "description": "format for importing an account" }, + "keyringAccountName": { + "message": "Όνομα λογαριασμού" + }, + "keyringAccountPublicAddress": { + "message": "Δημόσια διεύθυνση" + }, + "keyringSnapRemovalResult1": { + "message": "$1 $2αφαιρέθηκαν", + "description": "Displays the result after removal of a keyring snap. $1 is the snap name, $2 is whether it is successful or not" + }, + "keyringSnapRemovalResultNotSuccessful": { + "message": "όχι ", + "description": "Displays the `not` word in $2." + }, + "keyringSnapRemoveConfirmation": { + "message": "Πληκτρολογήστε $1 για να επιβεβαιώσετε ότι θέλετε να καταργήσετε αυτό το snap:", + "description": "Asks user to input the name nap prior to deleting the snap. $1 is the snap name" + }, "keystone": { "message": "Keystone" }, @@ -2017,9 +2336,15 @@ "lastSold": { "message": "Τελευταία πώληση" }, + "lavaDomeCopyWarning": { + "message": "Για την ασφάλειά σας, η επιλογή αυτού του κειμένου δεν είναι διαθέσιμη αυτή τη στιγμή." + }, "layer1Fees": { "message": "Τέλη επιπέδου 1" }, + "layer2Fees": { + "message": "Τέλη επιπέδου 2" + }, "learnCancelSpeeedup": { "message": "Μάθετε πώς να $1", "description": "$1 is link to cancel or speed up transactions" @@ -2037,9 +2362,21 @@ "learnMoreUpperCase": { "message": "Μάθετε περισσότερα" }, + "learnMoreUpperCaseWithDot": { + "message": "Μάθετε περισσότερα." + }, "learnScamRisk": { "message": "απάτες και κίνδυνοι ασφάλειας." }, + "learnToBridge": { + "message": "Μάθετε για την διασύνδεση" + }, + "leaveMetaMask": { + "message": "Αποχώρηση από το MetaMask;" + }, + "leaveMetaMaskDesc": { + "message": "Πρόκειται να επισκεφθείτε έναν ιστότοπο εκτός του MetaMask. Ελέγξτε ξανά τη διεύθυνση URL προτού συνεχίσετε." + }, "ledgerAccountRestriction": { "message": "Πρέπει να κάνετε χρήση του τελευταίου σας λογαριασμού πριν προσθέσετε έναν νέο." }, @@ -2058,6 +2395,18 @@ "ledgerDeviceOpenFailureMessage": { "message": "Η συσκευή Ledger απέτυχε να ανοίξει. Το Ledger σας μπορεί να είναι συνδεδεμένο με άλλο λογισμικό. Παρακαλούμε κλείστε το Ledger Live ή άλλες εφαρμογές που είναι συνδεδεμένες με τη συσκευή Ledger και προσπαθήστε να συνδεθείτε ξανά." }, + "ledgerErrorConnectionIssue": { + "message": "Επανασυνδέστε το Ledger σας, ανοίξτε την εφαρμογή ETH και δοκιμάστε ξανά." + }, + "ledgerErrorDevicedLocked": { + "message": "Το Ledger σας είναι κλειδωμένο. Ξεκλειδώστε το και δοκιμάστε ξανά." + }, + "ledgerErrorEthAppNotOpen": { + "message": "Για να επιλύσετε το πρόβλημα, ανοίξτε την εφαρμογή ETH στη συσκευή σας και προσπαθήστε ξανά." + }, + "ledgerErrorTransactionDataNotPadded": { + "message": "Η εισαγωγή δεδομένων στις συναλλαγές με Ethereum δεν έχει πραγματοποιηθεί επαρκώς." + }, "ledgerLiveApp": { "message": "Εφαρμογή Ledger Live" }, @@ -2077,6 +2426,9 @@ "lightTheme": { "message": "Ανοιχτόχρωμο" }, + "likeToImportToken": { + "message": "Θέλετε να εισαγάγετε αυτό το token;" + }, "likeToImportTokens": { "message": "Θέλετε να εισαγάγετε αυτά τα tokens;" }, @@ -2086,6 +2438,9 @@ "lineaMainnet": { "message": "Linea Mainnet" }, + "lineaSepolia": { + "message": "Δίκτυο δοκιμών Linea Sepolia" + }, "link": { "message": "Σύνδεσμος" }, @@ -2098,8 +2453,11 @@ "loading": { "message": "Φόρτωση..." }, - "loadingNFTs": { - "message": "Φόρτωση των NFT..." + "loadingScreenHardwareWalletMessage": { + "message": "Ολοκληρώστε τη συναλλαγή στο πορτοφόλι υλικού." + }, + "loadingScreenSnapMessage": { + "message": "Ολοκληρώστε τη συναλλαγή στο Snap." }, "loadingTokens": { "message": "Φόρτωση των tokens..." @@ -2146,6 +2504,9 @@ "message": "Βεβαιωθείτε ότι κανείς δεν κοιτάει", "description": "Warning to users to be care while creating and saving their new Secret Recovery Phrase" }, + "manageInSettings": { + "message": "Διαχείριση των ρυθμίσεων" + }, "max": { "message": "Μέγ." }, @@ -2180,15 +2541,34 @@ "metaMaskConnectStatusParagraphTwo": { "message": "Το κουμπί Κατάστασης Σύνδεσης δείχνει αν ο ιστότοπος που επισκέπτεστε είναι συνδεδεμένος με τον τρέχοντα επιλεγμένο λογαριασμό σας." }, + "metadataModalSourceTooltip": { + "message": "Το $1 φιλοξενείται στο npm και το $2 είναι το μοναδικό αναγνωριστικό αυτού του Snap.", + "description": "$1 is the snap name and $2 is the snap NPM id." + }, "metamaskInstitutionalVersion": { "message": "Έκδοση του MetaMask Institutional" }, + "metamaskNotificationsAreOff": { + "message": "Οι ειδοποιήσεις του πορτοφολιού δεν είναι προς το παρόν ενεργές." + }, + "metamaskPortfolio": { + "message": "MetaMask Portfolio." + }, "metamaskSwapsOfflineDescription": { "message": "Το MetaMask Swaps είναι υπό συντήρηση. Παρακαλείστε να επιστρέψετε αργότερα." }, "metamaskVersion": { "message": "Έκδοση του MetaMask" }, + "methodData": { + "message": "Μέθοδος" + }, + "methodDataTransactionDescription": { + "message": "Αυτή είναι η συγκεκριμένη ενέργεια που θα γίνει. Αυτά τα δεδομένα μπορεί να είναι ψεύτικα, οπότε βεβαιωθείτε ότι εμπιστεύεστε τον ιστότοπο στην άλλη πλευρά." + }, + "methodNotSupported": { + "message": "Δεν υποστηρίζεται με αυτόν τον λογαριασμό." + }, "metrics": { "message": "Μετρήσεις" }, @@ -2224,11 +2604,17 @@ "mmiBuiltAroundTheWorld": { "message": "Το MetaMask Institutional έχει σχεδιαστεί και λειτουργεί σε όλο τον κόσμο." }, + "mmiNewNFTDetectedInNFTsTabMessage": { + "message": "Επιτρέψτε στο MetaMask Institutional να ανιχνεύει και να εμφανίζει αυτόματα τα NFT στο πορτοφόλι σας." + }, + "mmiPasswordSetupDetails": { + "message": "Αυτός ο κωδικός πρόσβασης θα ξεκλειδώσει μόνο την επέκταση του MetaMask Institutional." + }, "more": { "message": "περισσότερα" }, "multipleSnapConnectionWarning": { - "message": "Το $1 θέλει να συνδεθεί με τα snaps $2. Προχωρήστε μόνο αν εμπιστεύεστε αυτόν τον ιστότοπο.", + "message": "Το $1 θέλει να χρησιμοποιήσει $2 Snaps", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." }, "mustSelectOne": { @@ -2237,10 +2623,80 @@ "name": { "message": "Όνομα" }, + "nameAddressLabel": { + "message": "Διεύθυνση", + "description": "Label above address field in name component modal." + }, + "nameInstructionsNew": { + "message": "Εάν γνωρίζετε αυτή τη διεύθυνση, δώστε της ένα ψευδώνυμο για να την αναγνωρίζετε και στο μέλλον.", + "description": "Instruction text in name component modal when value is not recognised." + }, + "nameInstructionsRecognized": { + "message": "Αυτή η διεύθυνση έχει ένα προεπιλεγμένο ψευδώνυμο, αλλά μπορείτε να το επεξεργαστείτε ή να εξετάσετε άλλες προτάσεις.", + "description": "Instruction text in name component modal when value is recognized but not saved." + }, + "nameInstructionsSaved": { + "message": "Έχετε ήδη προσθέσει ένα ψευδώνυμο για αυτή τη διεύθυνση. Μπορείτε να το επεξεργαστείτε ή να δείτε άλλα προτεινόμενα ψευδώνυμα.", + "description": "Instruction text in name component modal when value is saved." + }, + "nameLabel": { + "message": "Ψευδώνυμο", + "description": "Label above name input field in name component modal." + }, + "nameModalMaybeProposedName": { + "message": "Ίσως: $1", + "description": "$1 is the proposed name" + }, + "nameModalTitleNew": { + "message": "Άγνωστη διεύθυνση", + "description": "Title of the modal created by the name component when value is not recognised." + }, + "nameModalTitleRecognized": { + "message": "Αναγνωρισμένη διεύθυνση", + "description": "Title of the modal created by the name component when value is recognized but not saved." + }, + "nameModalTitleSaved": { + "message": "Αποθηκευμένη διεύθυνση", + "description": "Title of the modal created by the name component when value is saved." + }, + "nameProviderProposedBy": { + "message": "Προτείνεται από $1", + "description": "$1 is the name of the provider" + }, + "nameProvider_ens": { + "message": "Ethereum Name Service (ENS)" + }, + "nameProvider_etherscan": { + "message": "Etherscan" + }, + "nameProvider_lens": { + "message": "Lens Protocol" + }, + "nameProvider_token": { + "message": "MetaMask" + }, + "nameSetPlaceholder": { + "message": "Επιλέξτε ένα ψευδώνυμο...", + "description": "Placeholder text for name input field in name component modal." + }, + "nativePermissionRequestDescription": { + "message": "Θέλετε αυτός ο ιστότοπος να κάνει τα εξής;", + "description": "Description below header used on Permission Connect screen for native permissions." + }, "nativeToken": { "message": "Το αρχικό token σε αυτό το δίκτυο είναι το $1. Είναι το token που χρησιμοποιείται για τα τέλη συναλλαγών.", "description": "$1 represents the name of the native token on the current network" }, + "nativeTokenScamWarningConversion": { + "message": "Επεξεργασία λεπτομερειών δικτύου" + }, + "nativeTokenScamWarningDescription": { + "message": "Αυτό το δίκτυο δεν ταιριάζει με το αναγνωριστικό ή το όνομα της σχετικής αλυσίδας. Πολλά δημοφιλή tokens χρησιμοποιούν το όνομα $1, καθιστώντας το στόχο για απάτες. Οι απατεώνες μπορεί να σας ξεγελάσουν για να τους στείλετε πιο πολύτιμα νομίσματα σε αντάλλαγμα. Επαληθεύστε τα πάντα προτού συνεχίσετε.", + "description": "$1 represents the currency name" + }, + "nativeTokenScamWarningTitle": { + "message": "Πρόκειται για πιθανή απάτη" + }, "needHelp": { "message": "Χρειάζεστε βοήθεια; Επικοινωνήστε με $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -2261,6 +2717,9 @@ "negativeETH": { "message": "Δεν μπορεί να γίνει αποστολή αρνητικών ποσών στο ETH." }, + "negativeOrZeroAmountToken": { + "message": "Δεν είναι δυνατή η αποστολή αρνητικών ή μηδενικών ποσών περιουσιακών στοιχείων." + }, "network": { "message": "Δίκτυο:" }, @@ -2291,6 +2750,9 @@ "networkNameBSC": { "message": "BSC" }, + "networkNameBase": { + "message": "Βάση" + }, "networkNameDefinition": { "message": "Το όνομα που συνδέεται με αυτό το δίκτυο." }, @@ -2300,12 +2762,21 @@ "networkNameGoerli": { "message": "Goerli" }, + "networkNameLinea": { + "message": "Linea" + }, + "networkNameOpMainnet": { + "message": "Κύριο δίκτυο OP" + }, "networkNamePolygon": { "message": "Polygon" }, "networkNameTestnet": { "message": "Testnet" }, + "networkNameZkSyncEra": { + "message": "zkSync Era" + }, "networkProvider": { "message": "Πάροχος δικτύου" }, @@ -2358,6 +2829,19 @@ "newContract": { "message": "Νέο συμβόλαιο" }, + "newNFTDetectedInImportNFTsMessageStrongText": { + "message": "Ρυθμίσεις > Ασφάλεια και απόρρητο" + }, + "newNFTDetectedInImportNFTsMsg": { + "message": "Για να χρησιμοποιήσετε το Opensea για να δείτε τα NFT, ενεργοποιήστε την επιλογή 'Προβολή NFT μέσων' στο $1.", + "description": "$1 is used for newNFTDetectedInImportNFTsMessageStrongText" + }, + "newNFTDetectedInNFTsTabMessage": { + "message": "Επιτρέψτε στο MetaMask να ανιχνεύει και να εμφανίζει αυτόματα τα NFT στο πορτοφόλι σας." + }, + "newNFTsAutodetected": { + "message": "Αυτόματη ανίχνευση NFT" + }, "newNetworkAdded": { "message": "Το “$1” προστέθηκε με επιτυχία!" }, @@ -2367,6 +2851,12 @@ "newPassword": { "message": "Νέος κωδικός πρόσβασης (τουλάχιστον 8 χαρακτήρες)" }, + "newPrivacyPolicyActionButton": { + "message": "Διαβάστε περισσότερα" + }, + "newPrivacyPolicyTitle": { + "message": "Ενημερώσαμε την πολιτική απορρήτου μας" + }, "newTokensImportedMessage": { "message": "Έχετε εισάγει με επιτυχία το $1.", "description": "$1 is the string of symbols of all the tokens imported" @@ -2388,6 +2878,9 @@ "message": "Αυτό το token είναι NFT. Προσθήκη στο $1", "description": "$1 is a clickable link with text defined by the 'importNFTPage' key" }, + "nftAlreadyAdded": { + "message": "Το NFT έχει ήδη προστεθεί." + }, "nftDisclaimer": { "message": "Αποποίηση ευθυνών: Το MetaMask αντλεί το αρχείο πολυμέσων από το url της πηγής. Αυτό το url μερικές φορές αλλάζει ανάλογα με την αγορά στην οποία εκδόθηκε το NFT." }, @@ -2423,12 +2916,21 @@ "noAddressForName": { "message": "Δεν έχει οριστεί διεύθυνση για αυτό το όνομα." }, + "noConnectedAccountDescription": { + "message": "Επιλέξτε έναν λογαριασμό που θέλετε να χρησιμοποιήσετε σε αυτόν τον ιστότοπο για να συνεχίσετε." + }, + "noConnectedAccountTitle": { + "message": "Το MetaMask δεν συνδέεται με αυτόν τον ιστότοπο" + }, "noConversionDateAvailable": { "message": "Δεν υπάρχει διαθέσιμη ημερομηνία μετατροπής νομίσματος" }, "noConversionRateAvailable": { "message": "Δεν υπάρχει διαθέσιμη ισοτιμία μετατροπής" }, + "noDomainResolution": { + "message": "Δεν παρέχεται ανάλυση για τον τομέα." + }, "noNFTs": { "message": "Δεν υπάρχουν NFT ακόμα" }, @@ -2447,6 +2949,9 @@ "noWebcamFoundTitle": { "message": "Η διαδικτυακή κάμερα δεν βρέθηκε" }, + "nonCustodialAccounts": { + "message": "Το MetaMask Institutional σάς επιτρέπει να χρησιμοποιείτε λογαριασμούς μη θεματοφυλακής, αν σκοπεύετε να χρησιμοποιήσετε αυτούς τους λογαριασμούς για την δημιουργία αντιγράφων ασφαλείας μέσω της Μυστικής Φράσης Ανάκτησης." + }, "nonce": { "message": "Αριθμολέξημα" }, @@ -2477,6 +2982,111 @@ "notePlaceholder": { "message": "Ο υπεύθυνος έγκρισης θα δει αυτήν τη σημείωση όταν εγκρίνει τη συναλλαγή ως θεματοφύλακας." }, + "notificationDetail": { + "message": "Λεπτομέρειες" + }, + "notificationDetailBaseFee": { + "message": "Βασικό τέλος (GWEI)" + }, + "notificationDetailGasLimit": { + "message": "Όριο τελών συναλλαγών (μονάδες)" + }, + "notificationDetailGasUsed": { + "message": "Τέλη συναλλαγών που χρησιμοποιήθηκαν (μονάδες)" + }, + "notificationDetailMaxFee": { + "message": "Μέγιστη χρέωση ανά τέλος συναλλαγής" + }, + "notificationDetailNetwork": { + "message": "Δίκτυο" + }, + "notificationDetailNetworkFee": { + "message": "Τέλη δικτύου" + }, + "notificationDetailPriorityFee": { + "message": "Τέλος προτεραιότητας (GWEI)" + }, + "notificationItemCheckBlockExplorer": { + "message": "Έλεγχος στο BlockExplorer" + }, + "notificationItemCollection": { + "message": "Συλλογή" + }, + "notificationItemConfirmed": { + "message": "Επιβεβαιωμένο" + }, + "notificationItemError": { + "message": "Δεν είναι δυνατή η ανάκτηση χρεώσεων προς το παρόν" + }, + "notificationItemFrom": { + "message": "Από" + }, + "notificationItemLidoStakeReadyToBeWithdrawn": { + "message": "Έτοιμη για ανάληψη" + }, + "notificationItemLidoStakeReadyToBeWithdrawnMessage": { + "message": "Μπορείτε τώρα να αποσύρετε τα $1 που δεν έχετε ποντάρει" + }, + "notificationItemLidoWithdrawalRequestedMessage": { + "message": "Το αίτημά σας για ακύρωση του πονταρίσματος των $1 έχει σταλεί" + }, + "notificationItemNFTReceivedFrom": { + "message": "Λάβατε NFT από" + }, + "notificationItemNFTSentTo": { + "message": "Στείλατε NFT σε" + }, + "notificationItemNetwork": { + "message": "Δίκτυο" + }, + "notificationItemRate": { + "message": "Ποσό (περιλαμβάνονται οι χρεώσεις)" + }, + "notificationItemReceived": { + "message": "Ελήφθη" + }, + "notificationItemReceivedFrom": { + "message": "Ελήφθη από" + }, + "notificationItemSent": { + "message": "Εστάλη" + }, + "notificationItemSentTo": { + "message": "Εστάλη σε" + }, + "notificationItemStakeCompleted": { + "message": "Ολοκλήρωση του πονταρίσματος" + }, + "notificationItemStaked": { + "message": "Ποντάρισμα" + }, + "notificationItemStakingProvider": { + "message": "Πάροχος πονταρίσματος" + }, + "notificationItemStatus": { + "message": "Κατάσταση" + }, + "notificationItemSwapped": { + "message": "Ανταλλαγή" + }, + "notificationItemSwappedFor": { + "message": "για" + }, + "notificationItemTo": { + "message": "Προς" + }, + "notificationItemTransactionId": { + "message": "Αναγνωριστικό συναλλαγής" + }, + "notificationItemUnStakeCompleted": { + "message": "Ολοκλήρωση ακύρωσης πονταρίσματός" + }, + "notificationItemUnStaked": { + "message": "Ακύρωση πονταρίσματος" + }, + "notificationItemUnStakingRequested": { + "message": "Αίτημα ακύρωσης πονταρίσματος" + }, "notificationTransactionFailedMessage": { "message": "Η συναλλαγή $1 απέτυχε! $2", "description": "Content of the browser notification that appears when a transaction fails" @@ -2494,52 +3104,15 @@ "description": "Content of the browser notification that appears when a transaction is confirmed" }, "notificationTransactionSuccessTitle": { - "message": "Επιβεβαιωμένη συναλλαγή", - "description": "Title of the browser notification that appears when a transaction is confirmed" - }, - "notificationTransactionSuccessView": { - "message": "Προβολή σε $1", - "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" - }, - "notifications": { - "message": "Ειδοποιήσεις" - }, - "notifications20ActionText": { - "message": "Μάθετε περισσότερα", - "description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a ledger page to resolve the U2F connection issue." - }, - "notifications20Description": { - "message": "Αν χρησιμοποιείτε την τελευταία έκδοση του Firefox, ίσως αντιμετωπίζετε ένα πρόβλημα που σχετίζεται με την κατάργηση της υποστήριξης U2F από τον Firefox.", - "description": "Description of a notification in the 'See What's New' popup. Describes the U2F support being dropped by firefox and that it affects ledger users." - }, - "notifications20Title": { - "message": "Οι χρήστες του Ledger και του Firefox αντιμετωπίζουν προβλήματα σύνδεσης", - "description": "Title for a notification in the 'See What's New' popup. Tells users that latest firefox users using U2F may experience connection issues." - }, - "notifications24ActionText": { - "message": "Κατάλαβα" - }, - "notifications24Description": { - "message": "Οι προηγμένες ρυθμίσεις τελών συναλλαγών καταχωρούνται τώρα με βάση το δίκτυο που χρησιμοποιείτε. Αυτό σημαίνει ότι μπορείτε να ορίσετε συγκεκριμένα προηγμένα τέλη συναλλαγών για κάθε δίκτυο και να αποφύγετε την υπερπληρωμή για τα τέλη ή την καθυστέρηση των συναλλαγών." - }, - "notifications24Title": { - "message": "Προηγμένα τέλη συναλλαγών ανά δίκτυο" - }, - "notifications8ActionText": { - "message": "Μεταβείτε στις Ρυθμίσεις > Για Προχωρημένους", - "description": "Description on an action button that appears in the What's New popup. Tells the user that if they click it, they will go to our Advanced settings page." - }, - "notifications8DescriptionOne": { - "message": "Από το MetaMask v10.4.0, δεν χρειάζεστε πλέον το Ledger Live για να συνδέσετε τη συσκευή Ledger με το MetaMask.", - "description": "Description of a notification in the 'See What's New' popup. Describes changes for how Ledger Live is no longer needed to connect the device." + "message": "Επιβεβαιωμένη συναλλαγή", + "description": "Title of the browser notification that appears when a transaction is confirmed" }, - "notifications8DescriptionTwo": { - "message": "Για μια ευκολότερη και πιο σταθερή εμπειρία με το Ledger, μεταβείτε στις Ρυθμίσεις > Για προχωρημένους και αλλάξτε τον \"Προτιμώμενο τύπο σύνδεσης στο Ledger\" σε \"WebHID\".", - "description": "Description of a notification in the 'See What's New' popup. Describes how the user can turn off the Ledger Live setting." + "notificationTransactionSuccessView": { + "message": "Προβολή σε $1", + "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" }, - "notifications8Title": { - "message": "Βελτίωση της σύνδεσης στο Ledger", - "description": "Title for a notification in the 'See What's New' popup. Notifies ledger users that there is an improvement in how they can connect their device." + "notifications": { + "message": "Ειδοποιήσεις" }, "notificationsDropLedgerFirefoxDescription": { "message": "Ο Firefox δεν υποστηρίζει πλέον το U2F, οπότε το Ledger δεν θα λειτουργεί με το MetaMask στον Firefox. Δοκιμάστε αντ' αυτού το MetaMask στο Google Chrome.", @@ -2549,33 +3122,37 @@ "message": "Διακοπή της υποστήριξης του Ledger για τον Firefox", "description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped." }, - "notificationsEmptyText": { - "message": "Εδώ μπορείτε να βρείτε ειδοποιήσεις από τα εγκατεστημένα snaps." - }, - "notificationsHeader": { - "message": "Ειδοποιήσεις" + "notificationsFeatureToggle": { + "message": "Ενεργοποίηση ειδοποιήσεων για το πορτοφόλι", + "description": "Experimental feature title" }, - "notificationsInfos": { - "message": "$1 από $2", - "description": "$1 is the date at which the notification has been dispatched and $2 is the link to the snap that dispatched the notification." + "notificationsFeatureToggleDescription": { + "message": "Αυτό επιτρέπει ειδοποιήσεις για το πορτοφόλι, όπως αποστολή/λήψη κεφαλαίων ή NFT και ανακοινώσεις λειτουργιών.", + "description": "Description of the experimental notifications feature" }, "notificationsMarkAllAsRead": { "message": "Επισήμανση όλων ως αναγνωσμένων" }, - "notificationsOpenBetaSnapsActionText": { - "message": "Μάθετε περισσότερα" + "notificationsPageEmptyTitle": { + "message": "Τίποτα το ιδιαίτερο εδώ" + }, + "notificationsPageErrorContent": { + "message": "Προσπαθήστε να επισκεφθείτε ξανά αυτή τη σελίδα." }, - "notificationsOpenBetaSnapsDescriptionOne": { - "message": "🎉 Είμαστε ενθουσιασμένοι που ανακοινώνουμε την δοκιμαστική έναρξη του MetaMask Snaps!" + "notificationsPageErrorTitle": { + "message": "Παρουσιάστηκε ένα σφάλμα" }, - "notificationsOpenBetaSnapsDescriptionThree": { - "message": "Εξατομικεύστε το πορτοφόλι σας με snaps που δημιουργήθηκαν από την κοινότητα προγραμματιστών!" + "notificationsPageNoNotificationsContent": { + "message": "Δεν έχετε λάβει καμία ειδοποίηση ακόμα." }, - "notificationsOpenBetaSnapsDescriptionTwo": { - "message": "Τα Snaps σάς βοηθούν να κάνετε περισσότερα με το MetaMask — όπως τη σύνδεση σε περισσότερα δίκτυα, τη προβολή πληροφοριών συναλλαγών και τη λήψη προσαρμοσμένων ειδοποιήσεων." + "notificationsSettingsBoxError": { + "message": "Κάτι πήγε στραβά. Προσπαθήστε ξανά." }, - "notificationsOpenBetaSnapsTitle": { - "message": "Παρουσιάζουμε τα MetaMask Snaps" + "notificationsSettingsPageAllowNotifications": { + "message": "Μείνετε ενήμεροι για ό,τι συμβαίνει στο πορτοφόλι σας με τις ειδοποιήσεις. Για να χρησιμοποιήσετε τις ειδοποιήσεις, χρησιμοποιούμε ένα προφίλ για να συγχρονίσουμε ορισμένες ρυθμίσεις στις συσκευές σας. $1" + }, + "notificationsSettingsPageAllowNotificationsLink": { + "message": "Μάθετε πώς προστατεύουμε το απόρρητό σας κατά τη χρήση αυτής της λειτουργίας." }, "numberOfNewTokensDetectedPlural": { "message": "$1 νέα tokens βρέθηκαν σε αυτόν τον λογαριασμό", @@ -2599,6 +3176,9 @@ "on": { "message": "Ενεργό" }, + "onboarding": { + "message": "Ενσωμάτωση" + }, "onboardingAdvancedPrivacyIPFSDescription": { "message": "Η πύλη IPFS επιτρέπει την πρόσβαση και την προβολή δεδομένων που φιλοξενούνται από τρίτους. Μπορείτε να προσθέσετε μια προσαρμοσμένη πύλη IPFS ή να συνεχίσετε να χρησιμοποιείτε την προεπιλεγμένη." }, @@ -2629,51 +3209,45 @@ "onboardingMetametricsAgree": { "message": "Συμφωνώ" }, - "onboardingMetametricsAllowOptOut": { - "message": "Σας επιτρέπεται πάντα να εξαιρεθείτε μέσω των Ρυθμίσεων" - }, - "onboardingMetametricsDataTerms": { - "message": "Τα δεδομένα αυτά είναι συγκεντρωτικά και συνεπώς ανώνυμα για τους σκοπούς του Γενικού Κανονισμού για την Προστασία Δεδομένων (ΕΕ) 2016/679." - }, "onboardingMetametricsDescription": { - "message": "Το MetaMask θα ήθελε να συλλέγει δεδομένα χρήσης για να κατανοήσει καλύτερα τον τρόπο με τον οποίο οι χρήστες μας αλληλεπιδρούν με το MetaMask. Τα δεδομένα αυτά θα χρησιμοποιηθούν για την παροχή της υπηρεσίας, η οποία περιλαμβάνει τη βελτίωση της υπηρεσίας με βάση τη χρήση σας." + "message": "Θέλουμε να συλλέξουμε βασικά δεδομένα χρήσης και διάγνωσης για να βελτιώσουμε το MetaMask. Λάβετε υπόψη ότι δεν πουλάμε ποτέ τα δεδομένα που μας παρέχετε εδώ." }, "onboardingMetametricsDescription2": { - "message": "Το MetaMask θα..." + "message": "Όταν συγκεντρώνουμε μετρήσεις, θα είναι πάντα..." }, "onboardingMetametricsDisagree": { "message": "Όχι, ευχαριστώ" }, "onboardingMetametricsInfuraTerms": { - "message": "* Όταν χρησιμοποιείτε την Infura ως τον προεπιλεγμένο πάροχο RPC στο MetaMask, η Infura θα συλλέγει τη διεύθυνση IP σας και τη διεύθυνση του πορτοφολιού σας στο Ethereum όταν αποστέλλετε μια συναλλαγή. Δεν αποθηκεύουμε αυτές τις πληροφορίες με τρόπο που να επιτρέπει στα συστήματά μας να συσχετίζουν αυτά τα δύο δεδομένα. Για περισσότερες πληροφορίες σχετικά με τον τρόπο με τον οποίο αλληλεπιδρούν το MetaMask και η Infura από την πλευρά της συλλογής δεδομένων, δείτε την ενημέρωσή μας $1. Για περισσότερες πληροφορίες σχετικά με τις πρακτικές απορρήτου μας γενικά, δείτε την ενημέρωσή μας $2.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" + "message": "Θα σας ενημερώσουμε εάν αποφασίσουμε να χρησιμοποιήσουμε αυτά τα δεδομένα για άλλους σκοπούς. Για περισσότερες πληροφορίες, μπορείτε να ανατρέξετε στην $1. Να θυμάστε ότι μπορείτε να μεταβείτε στις ρυθμίσεις και να εξαιρεθείτε ανά πάσα στιγμή.", + "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, "onboardingMetametricsInfuraTermsPolicy": { - "message": "Πολιτική Απορρήτου εδώ" - }, - "onboardingMetametricsInfuraTermsPolicyLink": { - "message": "εδώ" + "message": "Πολιτική Απορρήτου" }, "onboardingMetametricsModalTitle": { "message": "Προσθήκη προσαρμοσμένου δικτύου" }, "onboardingMetametricsNeverCollect": { - "message": "To $1 συλλέγει πληροφορίες που δεν χρειαζόμαστε για την παροχή της υπηρεσίας (όπως κλειδιά, διευθύνσεις, αναλύσεις συναλλαγών ή υπόλοιπα)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 τα κλικ και οι προβολές στην εφαρμογή αποθηκεύονται, ωστόσο άλλα στοιχεία (όπως η δημόσια διεύθυνσή σας) όχι.", + "description": "$1 represents `onboardingMetametricsNeverCollectEmphasis`" + }, + "onboardingMetametricsNeverCollectEmphasis": { + "message": "Ιδιωτικές:" }, "onboardingMetametricsNeverCollectIP": { - "message": "To $1 συλλέγει την πλήρη διεύθυνση IP σας*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 χρησιμοποιούμε προσωρινά τη διεύθυνση IP σας για να εντοπίσουμε τη γενική τοποθεσία (όπως η χώρα ή η περιοχή σας), αλλά δεν αποθηκεύεται ποτέ.", + "description": "$1 represents `onboardingMetametricsNeverCollectIPEmphasis`" }, - "onboardingMetametricsNeverEmphasis": { - "message": "Ποτέ" + "onboardingMetametricsNeverCollectIPEmphasis": { + "message": "Γενικές:" }, "onboardingMetametricsNeverSellData": { - "message": "To $1 πουλάει δεδομένα. Ποτέ!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 εσείς αποφασίζετε αν θέλετε να κοινοποιήσετε ή να διαγράψετε τα δεδομένα χρήσης σας μέσω των ρυθμίσεων ανά πάσα στιγμή.", + "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" }, - "onboardingMetametricsSendAnonymize": { - "message": "Αποστολή ανώνυμων συμβάντων κλικ και προβολής ιστοσελίδων" + "onboardingMetametricsNeverSellDataEmphasis": { + "message": "Προαιρετικές:" }, "onboardingMetametricsTitle": { "message": "Βοηθήστε μας να βελτιώσουμε το MetaMask" @@ -2714,15 +3288,26 @@ "onboardingPinExtensionTitle": { "message": "Η εγκατάσταση του MetaMask ολοκληρώθηκε!" }, + "onboardingPinMmiExtensionLabel": { + "message": "Καρφιτσώστε το MetaMask Institutional" + }, "onboardingUsePhishingDetectionDescription": { "message": "Οι ειδοποιήσεις ανίχνευσης για phishing βασίζονται στην επικοινωνία με το $1. Το jsDeliver θα έχει πρόσβαση στη διεύθυνση IP σας. Δείτε $2.", "description": "The $1 is the word 'jsDeliver', from key 'jsDeliver' and $2 is the words Privacy Policy from key 'privacyMsg', both separated here so that it can be wrapped as a link" }, + "onekey": { + "message": "OneKey" + }, "onlyAddTrustedNetworks": { "message": "Ένας κακόβουλος πάροχος δικτύου μπορεί να πει ψέματα σχετικά με την κατάσταση του blockchain και να καταγράψει τη δραστηριότητα του δικτύου σας. Προσθέστε μόνο προσαρμοσμένα δίκτυα που εμπιστεύεστε." }, "onlyConnectTrust": { - "message": "Συνδεθείτε μόνο με ιστότοπους που εμπιστεύεστε." + "message": "Συνδεθείτε μόνο με ιστότοπους που εμπιστεύεστε. $1", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." + }, + "openCustodianApp": { + "message": "Ανοίξτε την εφαρμογή $1", + "description": "The $1 is the name of the Custodian that will be open" }, "openFullScreenForLedgerWebHid": { "message": "Μεταβείτε σε πλήρη οθόνη για να συνδέσετε το Ledger σας.", @@ -2734,6 +3319,15 @@ "openSeaNew": { "message": "OpenSea" }, + "openSeaToBlockaidBtnLabel": { + "message": "Εξερευνήστε τα Snaps" + }, + "openSeaToBlockaidDescription": { + "message": "Οι ειδοποιήσεις ασφαλείας δεν είναι πλέον διαθέσιμες σε αυτό το δίκτυο. Η εγκατάσταση ενός Snap μπορεί να βελτιώσει την ασφάλειά σας." + }, + "openSeaToBlockaidTitle": { + "message": "Προσοχή!" + }, "operationFailed": { "message": "Η λειτουργία απέτυχε" }, @@ -2777,6 +3371,9 @@ "password": { "message": "Κωδικός πρόσβασης" }, + "passwordMmiTermsWarning": { + "message": "Κατανοώ ότι το MetaMask Institutional δεν μπορεί να ανακτήσει αυτόν τον κωδικό πρόσβασης για μένα. $1" + }, "passwordNotLongEnough": { "message": "Ο κωδικός πρόσβασης δεν είναι αρκετά μεγάλος" }, @@ -2803,6 +3400,10 @@ "message": "Εισάγετε τη συμβολοσειρά του ιδιωτικού σας κλειδιού εδώ:", "description": "For importing an account from a private key" }, + "paymasterInUse": { + "message": "Το τέλη για αυτή τη συναλλαγή θα καταβληθούν από τον πληρωτή.", + "description": "Alert shown in transaction confirmation if paymaster in use." + }, "pending": { "message": "Σε εκκρεμότητα" }, @@ -2816,18 +3417,26 @@ "message": "Έχετε (1) εκκρεμή συναλλαγή.", "description": "$1 is count of pending transactions" }, - "permissionRequest": { - "message": "Αίτημα άδειας" + "permissionDetails": { + "message": "Λεπτομέρειες άδειας χρήσης" }, - "permissionRequestCapitalized": { + "permissionRequest": { "message": "Αίτημα άδειας" }, "permissionRequested": { "message": "Ζητήθηκε τώρα" }, + "permissionRequestedForAccounts": { + "message": "Ζητείται τώρα για $1", + "description": "Permission cell status for requested permission including accounts, rendered as AvatarGroup which is $1." + }, "permissionRevoked": { "message": "Ανακλήθηκε σε αυτήν την ενημέρωση" }, + "permissionRevokedForAccounts": { + "message": "Ανακλήθηκε σε αυτή την ενημέρωση για $1", + "description": "Permission cell status for revoked permission including accounts, rendered as AvatarGroup which is $1." + }, "permission_accessNamedSnap": { "message": "Σύνδεση με $1.", "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." @@ -2836,6 +3445,10 @@ "message": "Πρόσβαση στο διαδίκτυο.", "description": "The description of the `endowment:network-access` permission." }, + "permission_accessNetworkDescription": { + "message": "Επιτρέψτε στο $1 να έχει πρόσβαση στο διαδίκτυο. Αυτό μπορεί να χρησιμοποιηθεί για αποστολή και λήψη δεδομένων με διακομιστές τρίτων.", + "description": "An extended description of the `endowment:network-access` permission. $1 is the snap name." + }, "permission_accessSnap": { "message": "Συνδεθείτε στο snap $1.", "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." @@ -2848,10 +3461,18 @@ "message": "Προγραμματισμός και εκτέλεση περιοδικών ενεργειών.", "description": "The description for the `snap_cronjob` permission" }, + "permission_cronjobDescription": { + "message": "Επιτρέψτε στο $1 να εκτελεί ενέργειες που εκτελούνται περιοδικά σε σταθερές ώρες, ημερομηνίες ή διαστήματα. Αυτό μπορεί να χρησιμοποιηθεί για την ενεργοποίηση αλληλεπιδράσεων ή ειδοποιήσεων ευαίσθητων στο χρόνο.", + "description": "An extended description for the `snap_cronjob` permission. $1 is the snap name." + }, "permission_dialog": { "message": "Εμφάνιση παραθύρων διαλόγου στο MetaMask.", "description": "The description for the `snap_dialog` permission" }, + "permission_dialogDescription": { + "message": "Επιτρέψτε στο $1 να εμφανίζει αναδυόμενα παράθυρα του MetaMask με προσαρμοσμένο κείμενο, πεδίο εισαγωγής και κουμπιά για την έγκριση ή την απόρριψη μιας ενέργειας.\nΜπορεί να χρησιμοποιηθεί για τη δημιουργία π.χ. ειδοποιήσεων, επιβεβαιώσεων και ροών επιλογής για το snap.", + "description": "An extended description for the `snap_dialog` permission. $1 is the snap name." + }, "permission_ethereumAccounts": { "message": "Δείτε τη διεύθυνση, το υπόλοιπο του λογαριασμού, τη δραστηριότητα και προτείνετε συναλλαγές προς έγκριση.", "description": "The description for the `eth_accounts` permission" @@ -2860,30 +3481,138 @@ "message": "Πρόσβαση στον πάροχο του Ethereum.", "description": "The description for the `endowment:ethereum-provider` permission" }, + "permission_ethereumProviderDescription": { + "message": "Επιτρέψτε στο $1 να επικοινωνεί απευθείας με το MetaMask, προκειμένου να διαβάζει δεδομένα από το blockchain και να προτείνει μηνύματα και συναλλαγές.", + "description": "An extended description for the `endowment:ethereum-provider` permission. $1 is the snap name." + }, + "permission_getEntropy": { + "message": "Δημιουργία τυχαίων κλειδιών μοναδικών σε αυτό το $1.", + "description": "The description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getEntropyDescription": { + "message": "Επιτρέψτε στο $1 να παράγει τυχαία κλειδιά μοναδικά για αυτό το $1, χωρίς να τα εκθέτει. Αυτά τα κλειδιά είναι ξεχωριστά από τον λογαριασμό (-ους) σας στο MetaMask και δεν σχετίζονται με τα ιδιωτικά σας κλειδιά ή τη Μυστική Φράση Ανάκτησης. Άλλα snaps δεν μπορούν να έχουν πρόσβαση σε αυτές τις πληροφορίες.", + "description": "An extended description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getLocale": { + "message": "Προβολή της γλώσσας προτίμησής σας.", + "description": "The description for the `snap_getLocale` permission" + }, + "permission_getLocaleDescription": { + "message": "Επιτρέψτε στο $1 να έχει πρόσβαση στη γλώσσα προτίμησής σας από τις ρυθμίσεις του MetaMask. Αυτό μπορεί να χρησιμεύει για την τοπική προσαρμογή και την εμφάνιση του περιεχομένου του $1 στη γλώσσα σας.", + "description": "An extended description for the `snap_getLocale` permission. $1 is the snap name." + }, + "permission_homePage": { + "message": "Εμφάνιση προσαρμοσμένης οθόνης", + "description": "The description for the `endowment:page-home` permission" + }, + "permission_homePageDescription": { + "message": "Επιτρέψτε στο $1 να εμφανίσει μια προσαρμοσμένη αρχική οθόνη στο MetaMask. Αυτή μπορεί να χρησιμοποιηθεί για διεπαφές χρήστη, διαμόρφωση και πίνακες οργάνων.", + "description": "An extended description for the `endowment:page-home` permission. $1 is the snap name." + }, + "permission_keyring": { + "message": "Να επιτρέπονται αιτήματα για την προσθήκη και τον έλεγχο λογαριασμών Ethereum", + "description": "The description for the `endowment:keyring` permission" + }, + "permission_keyringDescription": { + "message": "Επιτρέψτε σε αυτό το $1 να λαμβάνει αιτήματα προσθήκης ή αφαίρεσης λογαριασμών, καθώς και να υπογράφει και να πραγματοποιεί συναλλαγές εκ μέρους αυτών των λογαριασμών.", + "description": "An extended description for the `endowment:keyring` permission. $1 is the snap name." + }, "permission_lifecycleHooks": { "message": "Χρησιμοποιήστε επιχειρηματικά μοντέλα.", "description": "The description for the `endowment:lifecycle-hooks` permission" }, + "permission_lifecycleHooksDescription": { + "message": "Επιτρέψτε στο $1 να χρησιμοποιεί επιχειρηματικά μοντέλα για την εκτέλεση κώδικα σε συγκεκριμένες χρονικές στιγμές κατά τη διάρκεια του κύκλου ζωής του.", + "description": "An extended description for the `endowment:lifecycle-hooks` permission. $1 is the snap name." + }, "permission_manageAccounts": { "message": "Προσθήκη και έλεγχος λογαριασμών στο Ethereum", "description": "The description for `snap_manageAccounts` permission" }, + "permission_manageAccountsDescription": { + "message": "Επιτρέψτε σε αυτό το $1 να προσθέτει ή να αφαιρεί λογαριασμούς Ethereum και, στη συνέχεια, να πραγματοποιεί συναλλαγές και να υπογράφει με αυτούς τους λογαριασμούς.", + "description": "An extended description for the `snap_manageAccounts` permission. $1 is the snap name." + }, + "permission_manageBip32Keys": { + "message": "Διαχειριστείτε λογαριασμούς $1.", + "description": "The description for the `snap_getBip32Entropy` permission. $1 is a derivation path, e.g. 'm/44'/0'/0' (secp256k1)'." + }, + "permission_manageBip44AndBip32KeysDescription": { + "message": "Επιτρέψτε στο $1 να διαχειρίζεται λογαριασμούς και στοιχεία στο ζητούμενο δίκτυο. Αυτοί οι λογαριασμοί προέρχονται από τη μυστική φράση ανάκτησης και δημιουργούν αντίγραφα ασφαλείας από αυτήν (χωρίς να την αποκαλύπτουν). Με τη δυνατότητα εξαγωγής κλειδιών, το $1 μπορεί να υποστηρίξει μια ποικιλία πρωτοκόλλων blockchain πέρα από το Ethereum (EVM).", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions. $1 is the snap name." + }, + "permission_manageBip44Keys": { + "message": "Διαχειριστείτε λογαριασμούς $1.", + "description": "The description for the `snap_getBip44Entropy` permission. $1 is the name of a protocol, e.g. 'Filecoin'." + }, "permission_manageState": { "message": "Αποθηκεύστε και διαχειριστείτε τα δεδομένα του στη συσκευή σας.", "description": "The description for the `snap_manageState` permission" }, + "permission_manageStateDescription": { + "message": "Επιτρέψτε στο $1 να αποθηκεύει, να ενημερώνει και να ανακτά δεδομένα με ασφάλεια και με κρυπτογράφηση. Άλλα snaps δεν μπορούν να έχουν πρόσβαση σε αυτές τις πληροφορίες.", + "description": "An extended description for the `snap_manageState` permission. $1 is the snap name." + }, + "permission_nameLookup": { + "message": "Παροχή αναζήτησης τομέων και διευθύνσεων.", + "description": "The description for the `endowment:name-lookup` permission." + }, + "permission_nameLookupDescription": { + "message": "Επιτρέψτε στο snap να αντλεί και να εμφανίζει αναζητήσεις διευθύνσεων και τομέων σε διαφορετικά μέρη του MetaMask UI.", + "description": "An extended description for the `endowment:name-lookup` permission." + }, "permission_notifications": { "message": "Εμφάνιση ειδοποιήσεων.", "description": "The description for the `snap_notify` permission" }, + "permission_notificationsDescription": { + "message": "Επιτρέψτε στο $1 να εμφανίζει ειδοποιήσεις εντός του MetaMask. Ένα σύντομο κείμενο ειδοποίησης μπορεί να ενεργοποιηθεί από το snap για πληροφορίες που μπορούν να ληφθούν υπόψη ή σχετίζονται με το χρόνο.", + "description": "An extended description for the `snap_notify` permission. $1 is the snap name." + }, + "permission_rpc": { + "message": "Επιτρέψτε στο $1 να επικοινωνήσει απευθείας με αυτό το $2.", + "description": "The description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescription": { + "message": "Επιτρέψτε στο $1 να στέλνει μηνύματα στο $2 και να λαμβάνει απάντηση από το $2.", + "description": "An extended description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescriptionOriginList": { + "message": "$1 και $2", + "description": "A list of allowed origins where $2 is the last origin of the list and $1 is the rest of the list separated by ','." + }, + "permission_signatureInsight": { + "message": "Εμφάνιση του πλαισίου των στοιχείων της υπογραφής.", + "description": "The description for the `endowment:signature-insight` permission" + }, + "permission_signatureInsightDescription": { + "message": "Επιτρέψτε στο $1 να εμφανίζει ένα πλαίσιο με στοιχεία για κάθε αίτημα υπογραφής πριν από την έγκριση. Αυτό μπορεί να χρησιμοποιηθεί ως λύση κατά του phishing και της ασφάλειας.", + "description": "An extended description for the `endowment:signature-insight` permission. $1 is the snap name." + }, + "permission_signatureInsightOrigin": { + "message": "Δείτε την προέλευση των ιστότοπων που δρομολογούν ένα αίτημα υπογραφής", + "description": "The description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission" + }, + "permission_signatureInsightOriginDescription": { + "message": "Επιτρέψτε στο $1 να βλέπει την προέλευση (URI) των ιστότοπων που δρομολογούν αιτήματα υπογραφής. Αυτό μπορεί να χρησιμοποιηθεί ως λύση κατά του phishing και της ασφάλειας.", + "description": "An extended description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission. $1 is the snap name." + }, "permission_transactionInsight": { "message": "Λήψη και εμφάνιση πληροφοριών σχετικά με τις συναλλαγές.", "description": "The description for the `endowment:transaction-insight` permission" }, + "permission_transactionInsightDescription": { + "message": "Επιτρέψτε στο $1 να αποκωδικοποιεί τις συναλλαγές και να εμφανίζει πληροφορίες εντός του MetaMask UI. Αυτό μπορεί να χρησιμοποιηθεί για λύσεις προστασίας κατά της εξαπάτησης και της ασφάλειας.", + "description": "An extended description for the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_transactionInsightOrigin": { "message": "Δείτε την προέλευση των ιστότοπων που προτείνουν συναλλαγές", "description": "The description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission" }, + "permission_transactionInsightOriginDescription": { + "message": "Επιτρέψτε στο $1 να βλέπει την προέλευση (URI) των ιστότοπων που προτείνουν συναλλαγές. Αυτό μπορεί να χρησιμοποιηθεί για λύσεις προστασίας κατά της εξαπάτησης και της ασφάλειας.", + "description": "An extended description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_unknown": { "message": "Άγνωστη άδεια: $1", "description": "$1 is the name of a requested permission that is not recognized." @@ -2892,29 +3621,66 @@ "message": "Δείτε το δημόσιο κλειδί σας για το $1 ($2).", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a derivation path, e.g. 'm/44'/0'/0''. $2 is the elliptic curve name, e.g. 'secp256k1'." }, + "permission_viewBip32PublicKeysDescription": { + "message": "Επιτρέψτε στο $2 να δει τα δημόσια κλειδιά (και τις διευθύνσεις) σας για το $1. Αυτό δεν παραχωρεί κανέναν έλεγχο λογαριασμών ή περιουσιακών στοιχείων.", + "description": "An extended description for the `snap_getBip32PublicKey` permission. $1 is a derivation path (name). $2 is the snap name." + }, "permission_viewNamedBip32PublicKeys": { "message": "Δείτε το δημόσιο κλειδί σας για το $1.", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a name for the derivation path, e.g., 'Ethereum accounts'." }, + "permission_walletSwitchEthereumChain": { + "message": "Μεταβείτε και χρησιμοποιήστε το ακόλουθο δίκτυο", + "description": "The label for the `wallet_switchEthereumChain` permission" + }, "permission_webAssembly": { "message": "Υποστήριξη για το WebAssembly.", "description": "The description of the `endowment:webassembly` permission." }, + "permission_webAssemblyDescription": { + "message": "Επιτρέψτε στο $1 να έχει πρόσβαση σε περιβάλλοντα εκτέλεσης χαμηλού επιπέδου μέσω του WebAssembly.", + "description": "An extended description of the `endowment:webassembly` permission. $1 is the snap name." + }, "permissions": { "message": "Άδειες" }, - "permissionsTitle": { - "message": "Άδειες" + "permissionsPageEmptyContent": { + "message": "Δεν υπάρχει τίποτα εδώ" + }, + "permissionsPageEmptySubContent": { + "message": "Εδώ μπορείτε να δείτε τις άδειες χρήσης που έχετε δώσει στα εγκατεστημένα Snaps ή στους συνδεδεμένους ιστότοπους." + }, + "permissionsPageTourDescription": { + "message": "Αυτός είναι ο πίνακας ελέγχου για τη διαχείριση των αδειών χρήσης που έχετε δώσει στους συνδεδεμένους ιστότοπους και στα εγκατεστημένα Snaps." }, - "permissionsTourDescription": { - "message": "Βρείτε τους συνδεδεμένους λογαριασμούς σας και διαχειριστείτε τις άδειες εδώ" + "permissionsPageTourTitle": { + "message": "Οι συνδεδεμένοι ιστότοποι είναι τώρα με άδειες χρήσης" }, "personalAddressDetected": { "message": "Η προσωπική διεύθυνση εντοπίστηκε. Καταχωρίστε τη διεύθυνση συμβολαίου του token." }, + "petnamesEnabledToggle": { + "message": "Επιτρέψτε τα ψευδώνυμα" + }, + "petnamesEnabledToggleDescription": { + "message": "Αυτό σας επιτρέπει να εκχωρήσετε ένα ψευδώνυμο σε οποιαδήποτε διεύθυνση. Θα σας προτείνουμε ονόματα για διευθύνσεις με τις οποίες αλληλεπιδράτε, όπου είναι δυνατόν." + }, + "pinExtensionDescription": { + "message": "Περιηγηθείτε στο μενού επέκτασης και καρφιτσώστε το MetaMask Institutional για απρόσκοπτη πρόσβαση." + }, + "pinExtensionTitle": { + "message": "Καρφιτσώστε την επέκταση" + }, + "pinToTop": { + "message": "Καρφίτσωμα στην κορυφή" + }, "pleaseConfirm": { "message": "Επιβεβαιώστε" }, + "plusMore": { + "message": "+ $1 ακόμη", + "description": "$1 is the number of additional items" + }, "plusXMore": { "message": "+ $1 ακόμη", "description": "$1 is a number of additional but unshown items in a list- this message will be shown in place of those items" @@ -2940,6 +3706,9 @@ "primaryCurrencySettingDescription": { "message": "Επιλέξτε εγχώριο για να δώσετε προτεραιότητα στην εμφάνιση των τιμών στο νόμισμα της αλυσίδας (π.χ. ETH). Επιλέξτε Παραστατικό για να δώσετε προτεραιότητα στην εμφάνιση τιμών στο επιλεγμένο παραστατικό νόμισμα." }, + "primaryType": { + "message": "Βασικός τύπος" + }, "priorityFee": { "message": "Τέλος προτεραιότητας" }, @@ -2960,6 +3729,18 @@ "message": "Ιδιωτικό κλειδί για $1", "description": "$1 represents the account name" }, + "privateKeyHidden": { + "message": "Το ιδιωτικό κλειδί είναι κρυφό", + "description": "Explains that the private key input is hidden" + }, + "privateKeyShow": { + "message": "Εμφάνιση/απόκρυψη της εισαγωγής του ιδιωτικού κλειδιού", + "description": "Describes a toggle that is used to show or hide the private key input" + }, + "privateKeyShown": { + "message": "Αυτό το ιδιωτικό κλειδί είναι ορατό", + "description": "Explains that the private key input is being shown" + }, "privateKeyWarning": { "message": "Προειδοποίηση: Ποτέ μην αποκαλύπτετε αυτό το κλειδί. Οποιοσδήποτε έχει τα ιδιωτικά σας κλειδιά μπορεί να κλέψει όλα τα περιουσιακά στοιχεία που βρίσκονται στον λογαριασμό σας." }, @@ -2969,6 +3750,21 @@ "proceedWithTransaction": { "message": "Θέλω να προχωρήσω έτσι κι αλλιώς" }, + "productAnnouncements": { + "message": "Ανακοινώσεις προϊόντων" + }, + "profileSync": { + "message": "Συγχρονισμός του προφίλ" + }, + "profileSyncConfirmation": { + "message": "Εάν απενεργοποιήσετε τον συγχρονισμό του προφίλ, δεν θα μπορείτε να λαμβάνετε ειδοποιήσεις." + }, + "profileSyncDescription": { + "message": "Δημιουργεί ένα προφίλ που χρησιμοποιεί το MetaMask για να συγχρονίσει ορισμένες ρυθμίσεις μεταξύ των συσκευών σας. Αυτό είναι απαραίτητο για να λαμβάνετε ειδοποιήσεις. $1." + }, + "profileSyncPrivacyLink": { + "message": "Μάθετε πώς προστατεύουμε το απόρρητό σας" + }, "proposedApprovalLimit": { "message": "Προτεινόμενο όριο έγκρισης" }, @@ -2978,6 +3774,78 @@ "publicAddress": { "message": "Δημόσια διεύθυνση" }, + "pushPlatformNotificationsFundsReceivedDescription": { + "message": "Λάβατε $1 $2" + }, + "pushPlatformNotificationsFundsReceivedDescriptionDefault": { + "message": "Λάβατε μερικά tokens" + }, + "pushPlatformNotificationsFundsReceivedTitle": { + "message": "Λάβατε κεφάλαια" + }, + "pushPlatformNotificationsFundsSentDescription": { + "message": "Στείλατε με επιτυχία $1 $2" + }, + "pushPlatformNotificationsFundsSentDescriptionDefault": { + "message": "Στείλατε με επιτυχία μερικά tokens" + }, + "pushPlatformNotificationsFundsSentTitle": { + "message": "Έγινε αποστολή κεφαλαίων" + }, + "pushPlatformNotificationsNftReceivedDescription": { + "message": "Λάβατε νέα NFT" + }, + "pushPlatformNotificationsNftReceivedTitle": { + "message": "Λάβατε NFT" + }, + "pushPlatformNotificationsNftSentDescription": { + "message": "Στείλατε με επιτυχία ένα NFT" + }, + "pushPlatformNotificationsNftSentTitle": { + "message": "Το NFT στάλθηκε" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedDescription": { + "message": "Το ποντάρισμά σας στο Lido ήταν επιτυχές" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedTitle": { + "message": "Ολοκλήρωση πονταρίσματος" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnDescription": { + "message": "Το ποντάρισμά σας στο Lido είναι τώρα έτοιμο για ανάληψη" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnTitle": { + "message": "Ποντάρισμα έτοιμο για ανάληψη" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedDescription": { + "message": "Η ανάληψή σας από το Lido ήταν επιτυχής" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedTitle": { + "message": "Ολοκλήρωση ανάληψης" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedDescription": { + "message": "Το αίτημά σας για ανάληψη από το Lido υποβλήθηκε" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedTitle": { + "message": "Αίτημα ανάληψης" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedDescription": { + "message": "Το ποντάρισμά σας στο RocketPool ήταν επιτυχές" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedTitle": { + "message": "Ολοκλήρωση πονταρίσματος" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedDescription": { + "message": "Η ακύρωση πονταρίσματός σας στο RocketPool ήταν επιτυχής" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedTitle": { + "message": "Ολοκλήρωση ακύρωσης πονταρίσματός" + }, + "pushPlatformNotificationsSwapCompletedDescription": { + "message": "Η ανταλλαγή σας στο MetaMask ήταν επιτυχής" + }, + "pushPlatformNotificationsSwapCompletedTitle": { + "message": "Ολοκλήρωση ανταλλαγής" + }, "queued": { "message": "Σε Αναμονή" }, @@ -2996,9 +3864,15 @@ "receive": { "message": "Λήψη" }, + "receiveTokensCamelCase": { + "message": "Λάβετε tokens" + }, "recipientAddressPlaceholder": { "message": "Εισάγετε τη δημόσια διεύθυνση (0x) ή το όνομα ENS" }, + "recipientAddressPlaceholderFlask": { + "message": "Εισαγάγετε τη δημόσια διεύθυνση (0x) ή το όνομα τομέα" + }, "recommendedGasLabel": { "message": "Προτεινόμενο" }, @@ -3026,6 +3900,12 @@ "recoveryPhraseReminderTitle": { "message": "Προστατέψτε τα κεφάλαιά σας" }, + "redesignedConfirmationsEnabledToggle": { + "message": "Αιτήματα βελτιωμένων υπογραφών" + }, + "redesignedConfirmationsToggleDescription": { + "message": "Ενεργοποιήστε το για να δείτε αιτήματα υπογραφών σε βελτιωμένη μορφή." + }, "refreshList": { "message": "Ανανέωση λίστας" }, @@ -3068,15 +3948,30 @@ "removeJWTDescription": { "message": "Είστε σίγουροι ότι θέλετε να αφαιρέσετε αυτό το token; Όλοι οι λογαριασμοί που αντιστοιχούν σε αυτό το token θα αφαιρεθούν και από την επέκταση: " }, + "removeKeyringSnap": { + "message": "Η αφαίρεση αυτού του Snap αφαιρεί αυτούς τους λογαριασμούς από το MetaMask:" + }, + "removeKeyringSnapToolTip": { + "message": "Το snap ελέγχει τους λογαριασμούς και με την αφαίρεσή του, οι λογαριασμοί θα αφαιρεθούν και από το MetaMask, αλλά θα παραμείνουν στην αλυσίδα συστοιχιών (blockchain)." + }, "removeNFT": { "message": "Αφαίρεση του NFT" }, + "removeNftErrorMessage": { + "message": "Δεν μπορέσαμε να αφαιρέσουμε αυτό το NFT." + }, "removeNftMessage": { "message": "Το NFT αφαιρέθηκε με επιτυχία!" }, "removeSnap": { "message": "Αφαίρεση του snap" }, + "removeSnapAccountDescription": { + "message": "Εάν προχωρήσετε, αυτός ο λογαριασμός δεν θα είναι πλέον διαθέσιμος στο MetaMask." + }, + "removeSnapAccountTitle": { + "message": "Κατάργηση λογαριασμού" + }, "removeSnapConfirmation": { "message": "Είστε σίγουροι ότι θέλετε να αφαιρέσετε το $1;", "description": "$1 represents the name of the snap" @@ -3087,12 +3982,24 @@ "replace": { "message": "αντικατάσταση" }, + "reportIssue": { + "message": "Αναφορά ενός προβλήματος" + }, "requestFlaggedAsMaliciousFallbackCopyReason": { "message": "Ο πάροχος ασφάλειας δεν έχει μοιραστεί πρόσθετες λεπτομέρειες" }, "requestFlaggedAsMaliciousFallbackCopyReasonTitle": { "message": "Το αίτημα χαρακτηρίστηκε ως κακόβουλο" }, + "requestFrom": { + "message": "Αίτημα από" + }, + "requestFromInfo": { + "message": "Αυτός είναι ο ιστότοπος που ζητά την υπογραφή σας." + }, + "requestFromTransactionDescription": { + "message": "Αυτός είναι ο ιστότοπος που ζητά την επιβεβαίωσή σας." + }, "requestMayNotBeSafe": { "message": "Το αίτημα μπορεί να μην είναι ασφαλές" }, @@ -3114,6 +4021,9 @@ "reset": { "message": "Επαναφορά" }, + "resetStates": { + "message": "Επαναφορά καταστάσεων" + }, "resetWallet": { "message": "Επαναφορά πορτοφολιού" }, @@ -3196,9 +4106,15 @@ "message": "Η Υποστήριξη του MetaMask δεν θα σας τη ζητήσει ποτέ.", "description": "The bolded texted in the second part of 'revealSeedWordsWarning'" }, + "revealSensitiveContent": { + "message": "Αποκάλυψη ευαίσθητου περιεχομένου" + }, "revealTheSeedPhrase": { "message": "Αποκάλυψη φράσης ανάκτησης" }, + "reviewAlerts": { + "message": "Έλεγχος ειδοποιήσεων" + }, "revokeAllTokensTitle": { "message": "Ανάκληση της άδειας πρόσβασης και μεταφοράς όλων των $1;", "description": "$1 is the symbol of the token for which the user is revoking approval" @@ -3249,6 +4165,9 @@ "searchAccounts": { "message": "Αναζήτηση λογαριασμών" }, + "searchTokens": { + "message": "Αναζήτηση tokens" + }, "secretRecoveryPhrase": { "message": "Μυστική Φράση Ανάκτησης" }, @@ -3265,7 +4184,8 @@ "message": "Ειδοποιήσεις ασφαλείας" }, "securityAlertsDescription": { - "message": "Αυτή η λειτουργία σας ειδοποιεί για κακόβουλη δραστηριότητα στο Κύριο Δίκτυο του Ethereum, ελέγχοντας ενεργά τα αιτήματα συναλλαγών και υπογραφών, διατηρώντας παράλληλα το απόρρητό σας. Τα δεδομένα σας δεν κοινοποιούνται στους τρίτους που παρέχουν αυτή την υπηρεσία. Να κάνετε πάντα τη δική σας επιμελή έρευνα προτού εγκρίνετε οποιαδήποτε αιτήματα. Δεν υπάρχει καμία εγγύηση ότι αυτή η λειτουργία θα εντοπίσει όλες τις κακόβουλες δραστηριότητες." + "message": "Αυτή η λειτουργία σας προειδοποιεί για κακόβουλη δραστηριότητα, καθώς ελέγχει ενεργά τα αιτήματα συναλλαγών και υπογραφών. $1", + "description": "Link to learn more about security alerts" }, "securityAndPrivacy": { "message": "Ασφάλεια και απόρρητο" @@ -3355,6 +4275,9 @@ "selectAnAccountHelp": { "message": "Επιλέξτε τους λογαριασμούς θεματοφύλακα που θα χρησιμοποιηθούν στο MetaMask Institutional." }, + "selectEnableDisplayMediaPrivacyPreference": { + "message": "Ενεργοποίηση της \"Προβολής μέσων NFT\"" + }, "selectHdPath": { "message": "Επιλέξτε τη διαδρομή HD" }, @@ -3376,18 +4299,41 @@ "send": { "message": "Αποστολή" }, + "sendAToken": { + "message": "Στείλτε ένα token" + }, "sendBugReport": { "message": "Στείλτε μας μια αναφορά σφάλματος." }, + "sendNoContactsConversionText": { + "message": "κάντε κλικ εδώ" + }, + "sendNoContactsDescription": { + "message": "Οι επαφές σας επιτρέπουν να στέλνετε με ασφάλεια συναλλαγές σε άλλο λογαριασμό πολλές φορές. Για να δημιουργήσετε μια επαφή, $1", + "description": "$1 represents the action text 'click here'" + }, + "sendNoContactsTitle": { + "message": "Δεν έχετε ακόμα επαφές" + }, + "sendSelectReceiveAsset": { + "message": "Επιλέξτε περιουσιακό στοιχείο για λήψη" + }, + "sendSelectSendAsset": { + "message": "Επιλέξτε περιουσιακό στοιχείο για αποστολή" + }, "sendSpecifiedTokens": { "message": "Αποστολή $1", "description": "Symbol of the specified token" }, - "sendTo": { - "message": "Αποστολή σε" + "sendSwapSubmissionWarning": { + "message": "Κάνοντας κλικ σε αυτό το κουμπί θα ξεκινήσει αμέσως η συναλλαγή ανταλλαγής. Ελέγξτε τις λεπτομέρειες της συναλλαγής σας πριν συνεχίσετε." }, - "sendTokens": { - "message": "Στείλτε tokens" + "sendTokenAsToken": { + "message": "Στείλατε $1 ως $2", + "description": "Used in the transaction display list to describe a swap and send. $1 and $2 are the symbols of tokens in involved in the swap." + }, + "sendingAsset": { + "message": "Αποστολή $1" }, "sendingDisabled": { "message": "Η αποστολή περιουσιακών στοιχείων ERC-1155 NFT δεν υποστηρίζεται ακόμη." @@ -3400,9 +4346,15 @@ "message": "Προειδοποίηση: πρόκειται να στείλετε ένα συμβόλαιο token το οποίο ίσως καταλήξει σε απώλεια χρημάτων. $1", "description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning" }, + "sendingZeroAmount": { + "message": "Στέλνετε 0 $1." + }, "sepolia": { "message": "Δίκτυο δοκιμών Sepolia" }, + "serviceWorkerKeepAlive": { + "message": "Διατηρήστε το Service Worker" + }, "setAdvancedPrivacySettingsDetails": { "message": "Το MetaMask χρησιμοποιεί αυτές τις αξιόπιστες υπηρεσίες τρίτων για να ενισχύσει τη χρηστικότητα και την ασφάλεια των προϊόντων." }, @@ -3422,9 +4374,21 @@ "settingsSearchMatchingNotFound": { "message": "Δε βρέθηκαν αποτελέσματα που να ταιριάζουν." }, + "settingsSubHeadingSignaturesAndTransactions": { + "message": "Αιτήματα υπογραφών και συναλλαγών" + }, "show": { "message": "Εμφάνιση" }, + "showAccount": { + "message": "Προβολή λογαριασμού" + }, + "showExtensionInFullSizeView": { + "message": "Εμφάνιση της επέκτασης σε προβολή πλήρους μεγέθους" + }, + "showExtensionInFullSizeViewDescription": { + "message": "Ενεργοποιήστε το για να κάνετε την προβολή πλήρους μεγέθους ως προεπιλογή όταν κάνετε κλικ στο εικονίδιο της επέκτασης." + }, "showFiatConversionInTestnets": { "message": "Εμφάνιση μετατροπής σε δοκιμαστικά δίκτυα" }, @@ -3444,6 +4408,9 @@ "message": "Αυτό βασίζεται στο $1, το οποίο θα έχει πρόσβαση στη διεύθυνση Ethereum και τη διεύθυνση IP σας. $2", "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" }, + "showIncomingTransactionsExplainer": { + "message": "Αυτό βασίζεται σε διαφορετικά API τρίτων για κάθε δίκτυο, τα οποία εκθέτουν τη διεύθυνση Ethereum και τη διεύθυνση IP σας." + }, "showMore": { "message": "Εμφάνιση περισσότερων" }, @@ -3483,9 +4450,46 @@ "signin": { "message": "Σύνδεση" }, + "signing": { + "message": "Υπογραφή" + }, + "simulationDetailsFailed": { + "message": "Υπήρξε σφάλμα στη φόρτωση της εκτίμησής σας." + }, + "simulationDetailsFiatNotAvailable": { + "message": "Μη διαθέσιμο" + }, + "simulationDetailsIncomingHeading": { + "message": "Λαμβάνετε" + }, + "simulationDetailsNoBalanceChanges": { + "message": "Δεν προβλέπονται αλλαγές για το πορτοφόλι σας" + }, + "simulationDetailsOutgoingHeading": { + "message": "Στέλνετε" + }, + "simulationDetailsTitle": { + "message": "Εκτιμώμενες αλλαγές" + }, + "simulationDetailsTitleTooltip": { + "message": "Οι εκτιμώμενες αλλαγές είναι αυτό που μπορεί να συμβεί αν προχωρήσετε σε αυτή τη συναλλαγή. Πρόκειται απλώς για μια πρόβλεψη, όχι για εγγύηση." + }, + "simulationDetailsTotalFiat": { + "message": "Σύνολο = $1", + "description": "$1 is the total amount in fiat currency on one side of the transaction" + }, + "simulationDetailsTransactionReverted": { + "message": "Αυτή η συναλλαγή είναι πιθανό να αποτύχει" + }, "simulationErrorMessageV2": { "message": "Δεν ήμασταν σε θέση να εκτιμήσουμε το τέλος συναλλαγής. Μπορεί να υπάρχει σφάλμα στο συμβόλαιο και η συναλλαγή αυτή να αποτύχει." }, + "simulationsSettingDescription": { + "message": "Ενεργοποιήστε το για να εκτιμήσετε τις αλλαγές στο υπόλοιπο των συναλλαγών πριν τις επιβεβαιώσετε. Αυτό δεν εγγυάται το τελικό αποτέλεσμα στις συναλλαγές σας. $1" + }, + "simulationsSettingSubHeader": { + "message": "Εκτίμηση μεταβολών υπολοίπου" + }, "skip": { "message": "Παράλειψη" }, @@ -3498,20 +4502,99 @@ "smartContracts": { "message": "Έξυπνα συμβόλαια" }, - "smartSwapsAreHere": { - "message": "Οι Έξυπνες Ανταλλαγές είναι εδώ!" - }, - "smartSwapsDescription": { - "message": "Οι Ανταλλαγές στο MetaMask μόλις έγιναν πολύ πιο έξυπνες! Η ενεργοποίηση των Έξυπνων Ανταλλαγών θα επιτρέψει στο MetaMask να βελτιστοποιήσει προγραμματιστικά τις Ανταλλαγές σας, ώστε να σας βοηθήσει:" - }, "smartSwapsErrorNotEnoughFunds": { "message": "Δεν υπάρχουν αρκετά κεφάλαια για έξυπνες ανταλλαγές." }, "smartSwapsErrorUnavailable": { "message": "Οι Έξυπνες Ανταλλαγές είναι προσωρινά μη διαθέσιμες." }, + "smartTransactionCancelled": { + "message": "Η συναλλαγή σας ακυρώθηκε" + }, + "smartTransactionCancelledDescription": { + "message": "Η συναλλαγή σας δεν ήταν δυνατόν να ολοκληρωθεί, οπότε ακυρώθηκε για να μην πληρώσετε περιττά τέλη συναλλαγών." + }, + "smartTransactionError": { + "message": "Η συναλλαγή σας απέτυχε" + }, + "smartTransactionErrorDescription": { + "message": "Οι ξαφνικές αλλαγές στην αγορά μπορεί να προκαλέσουν αποτυχίες. Εάν το πρόβλημα συνεχίζεται, επικοινωνήστε με την υποστήριξη πελατών του MetaMask." + }, + "smartTransactionPending": { + "message": "Υποβολή των συναλλαγών σας" + }, + "smartTransactionSuccess": { + "message": "Η συναλλαγή σας ολοκληρώθηκε" + }, + "smartTransactionTakingTooLong": { + "message": "Συγγνώμη για την αναμονή" + }, + "smartTransactionTakingTooLongDescription": { + "message": "Εάν η συναλλαγή σας δεν ολοκληρωθεί εντός $1, θα ακυρωθεί και δεν θα χρεωθείτε με τέλη συναλλαγών.", + "description": "$1 is remaining time in seconds" + }, + "smartTransactions": { + "message": "Έξυπνες συναλλαγές" + }, + "smartTransactionsBenefit1": { + "message": "Ποσοστό επιτυχίας 99,5%" + }, + "smartTransactionsBenefit2": { + "message": "Σας εξοικονομεί χρήματα" + }, + "smartTransactionsBenefit3": { + "message": "Ενημερώσεις σε πραγματικό χρόνο" + }, + "smartTransactionsDescription": { + "message": "Ξεκλειδώστε υψηλότερα ποσοστά επιτυχίας, προστασία σε \"προπορευόμενες συναλλαγές\" και καλύτερη ορατότητα με τις Έξυπνες Συναλλαγές." + }, + "smartTransactionsDescription2": { + "message": "Διατίθεται μόνο στο Ethereum. Ενεργοποιήστε ή απενεργοποιήστε το ανά πάσα στιγμή στις ρυθμίσεις. $1", + "description": "$1 is an external link to learn more about Smart Transactions" + }, + "smartTransactionsOptItModalTitle": { + "message": "Ενισχυμένη Προστασία Συναλλαγών" + }, + "snapAccountCreated": { + "message": "Ο λογαριασμός δημιουργήθηκε" + }, + "snapAccountCreatedDescription": { + "message": "Ο νέος σας λογαριασμός είναι έτοιμος για χρήση!" + }, + "snapAccountCreationFailed": { + "message": "Αποτυχία δημιουργίας λογαριασμού" + }, + "snapAccountCreationFailedDescription": { + "message": "Το $1 δεν κατάφερε να δημιουργήσει έναν λογαριασμό για εσάς.", + "description": "$1 is the snap name" + }, + "snapAccountRedirectFinishSigningTitle": { + "message": "Ολοκλήρωση υπογραφής" + }, + "snapAccountRedirectSiteDescription": { + "message": "Ακολουθήστε τις οδηγίες από το $1" + }, + "snapAccountRemovalFailed": { + "message": "Αποτυχία διαγραφής λογαριασμού" + }, + "snapAccountRemovalFailedDescription": { + "message": "Το $1 δεν κατάφερε να διαγράψει αυτόν τον λογαριασμό για εσάς.", + "description": "$1 is the snap name" + }, + "snapAccountRemoved": { + "message": "Ο λογαριασμός αφαιρέθηκε" + }, + "snapAccountRemovedDescription": { + "message": "Αυτός ο λογαριασμός δεν θα είναι πλέον διαθέσιμος για χρήση στο MetaMask." + }, + "snapAccounts": { + "message": "Λογαριασμός Snaps" + }, + "snapAccountsDescription": { + "message": "Λογαριασμοί που ελέγχονται από Snaps τρίτων." + }, "snapConnectionWarning": { - "message": "Το $1 θέλει να συνδεθεί με το $2. Συνεχίστε μόνο αν εμπιστεύεστε αυτόν τον ιστότοπο.", + "message": "Το $1 θέλει να χρησιμοποιήσει $2", "description": "$2 is the snap and $1 is the dapp requesting connection to the snap." }, "snapContent": { @@ -3522,15 +4605,35 @@ "message": "Ιστότοπος" }, "snapInstallRequest": { - "message": "Με την εγκατάσταση, εκχωρούνται στο $1 οι ακόλουθες άδειες. Συνεχίστε μόνο αν εμπιστεύεστε το $1.", + "message": "Η εγκατάσταση του $1 του δίνει τις ακόλουθες άδειες.", "description": "$1 is the snap name." }, "snapInstallSuccess": { "message": "Η εγκατάσταση ολοκληρώθηκε" }, + "snapInstallWarningCheck": { + "message": "Το $1 θέλει άδεια για να κάνει τα εξής:", + "description": "Warning message used in popup displayed on snap install. $1 is the snap name." + }, "snapInstallWarningHeading": { "message": "Προχωρήστε με προσοχή" }, + "snapInstallWarningPermissionDescriptionForBip32View": { + "message": "Επιτρέψτε στο $1 να δει τα δημόσια κλειδιά (και τις διευθύνσεις) σας. Αυτό δεν παραχωρεί κανέναν έλεγχο λογαριασμών ή περιουσιακών στοιχείων.", + "description": "An extended description for the `snap_getBip32PublicKey` permission used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionDescriptionForEntropy": { + "message": "Επιτρέψτε στο Snap $1 να διαχειρίζεται λογαριασμούς και στοιχεία στο ζητούμενο δίκτυο(-α). Αυτοί οι λογαριασμοί προέρχονται από τη μυστική φράση ανάκτησης και δημιουργούν αντίγραφα ασφαλείας από αυτήν (χωρίς να την αποκαλύπτουν). Με τη δυνατότητα εξαγωγής κλειδιών, το $1 μπορεί να υποστηρίξει μια ποικιλία πρωτοκόλλων blockchain πέρα από το Ethereum (EVM).", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionNameForEntropy": { + "message": "Διαχειριστείτε λογαριασμούς $1", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, + "snapInstallWarningPermissionNameForViewPublicKey": { + "message": "Δείτε το δημόσιο κλειδί σας για το $1", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, "snapInstallationErrorDescription": { "message": "Το $1 δεν μπόρεσε να εγκατασταθεί.", "description": "Error description used when snap installation fails. $1 is the snap name." @@ -3548,6 +4651,10 @@ "snapResultSuccessDescription": { "message": "Το $1 είναι έτοιμο για χρήση" }, + "snapUpdateAlertDescription": { + "message": "Αποκτήστε την τελευταία έκδοση του $1", + "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." + }, "snapUpdateAvailable": { "message": "Διαθέσιμη ενημέρωση" }, @@ -3559,22 +4666,40 @@ "message": "Η ενημέρωση απέτυχε", "description": "Error title used when snap update fails." }, + "snapUpdateRequest": { + "message": "Η ενημέρωση του $1 του δίνει τις ακόλουθες άδειες.", + "description": "$1 is the Snap name." + }, "snapUpdateSuccess": { "message": "Η ενημέρωση ολοκληρώθηκε" }, + "snapUrlIsBlocked": { + "message": "Αυτό το Snap θέλει να σας μεταφέρει σε μια μπλοκαρισμένη ιστοσελίδα. $1." + }, "snaps": { "message": "Snaps" }, - "snapsInvalidUIError": { - "message": "Το UI που καθορίζεται από το snap δεν είναι έγκυρο." + "snapsConnected": { + "message": "Συνδεδεμένα Snaps" }, "snapsNoInsight": { "message": "Το snap δεν επέστρεψε καμία πληροφορία" }, + "snapsPrivacyWarningFirstMessage": { + "message": "Αναγνωρίζετε ότι κάθε Snap που εγκαθιστάτε είναι μια Υπηρεσία Τρίτων, εφόσον δεν δηλώνεται διαφορετικά, όπως ορίζεται στην ιστοσελίδα της Consensys $1. Η χρήση των Υπηρεσιών Τρίτων διέπεται από ξεχωριστούς όρους και προϋποθέσεις που καθορίζονται από τον πάροχο των Υπηρεσιών Τρίτων. Η Consensys δεν συνιστά τη χρήση οποιουδήποτε Snap από κάποιο συγκεκριμένο άτομο για κάποιο συγκεκριμένο λόγο. Αποκτάτε πρόσβαση, εμπιστεύεστε ή χρησιμοποιείτε την Υπηρεσία Τρίτων με δική σας ευθύνη. Η Consensys αποποιείται κάθε είδους ευθύνη και υποχρέωση για τυχόν απώλειες λόγω της χρήσης των Υπηρεσιών Τρίτων.", + "description": "First part of a message in popup modal displayed when installing a snap for the first time. $1 is terms of use link." + }, "snapsPrivacyWarningSecondMessage": { "message": "Οποιεσδήποτε πληροφορίες μοιράζεστε με τις Υπηρεσίες Τρίτων θα συλλέγονται απευθείας από τις εν λόγω Υπηρεσίες Τρίτων σύμφωνα με τις πολιτικές απορρήτου τους. Ανατρέξτε στις πολιτικές απορρήτου τους για περισσότερες πληροφορίες.", "description": "Second part of a message in popup modal displayed when installing a snap for the first time." }, + "snapsPrivacyWarningThirdMessage": { + "message": "Η Consensys δεν έχει πρόσβαση στις πληροφορίες που μοιράζεστε με τις Υπηρεσίες Τρίτων.", + "description": "Third part of a message in popup modal displayed when installing a snap for the first time." + }, + "snapsSettings": { + "message": "Ρυθμίσεις για τα Snaps" + }, "snapsTermsOfUse": { "message": "Όροι Χρήσης" }, @@ -3588,12 +4713,19 @@ "someNetworksMayPoseSecurity": { "message": "Ορισμένα δίκτυα ενδέχεται να ενέχουν κινδύνους για την ασφάλεια ή/και το απόρρητο. Ενημερωθείτε για τους κινδύνους πριν προσθέσετε και χρησιμοποιήσετε ένα δίκτυο." }, + "somethingDoesntLookRight": { + "message": "Κάτι δεν φαίνεται σωστό; $1", + "description": "A false positive message for users to contact support. $1 is a link to the support page." + }, "somethingIsWrong": { "message": "Κάτι πήγε στραβά. Δοκιμάστε να φορτώσετε ξανά τη σελίδα." }, "somethingWentWrong": { "message": "Ουπς! Κάτι πήγε στραβά." }, + "source": { + "message": "Πηγή" + }, "speedUp": { "message": "Επιτάχυνση" }, @@ -3728,6 +4860,14 @@ "stake": { "message": "Stake" }, + "startYourJourney": { + "message": "Ξεκινήστε το ταξίδι σας με $1", + "description": "$1 is the token symbol" + }, + "startYourJourneyDescription": { + "message": "Ξεκινήστε με Web3 προσθέτοντας περίπου $1 στο πορτοφόλι σας.", + "description": "$1 is the token symbol" + }, "stateLogError": { "message": "Σφάλμα κατά την ανάκτηση αρχείων καταγραφής κατάστασης." }, @@ -3740,6 +4880,9 @@ "stateLogsDescription": { "message": "Τα αρχεία καταγραφής κατάστασης περιέχουν τις διευθύνσεις του δημόσιου λογαριασμού σας και τις συναλλαγές οι οποίες έχουν αποσταλεί." }, + "states": { + "message": "Καταστάσεις" + }, "status": { "message": "Κατάσταση" }, @@ -3783,18 +4926,6 @@ "strong": { "message": "Ισχυρό" }, - "stxBenefit1": { - "message": "Ελαχιστοποίηση του κόστους συναλλαγών" - }, - "stxBenefit2": { - "message": "Μείωση των αποτυχημένων συναλλαγών" - }, - "stxBenefit3": { - "message": "Εξάλειψη των εμπλοκών στις συναλλαγές" - }, - "stxBenefit4": { - "message": "Αποτροπή των προπορευόμενων συναλλαγών (front-running)" - }, "stxCancelled": { "message": "Η ανταλλαγή θα είχε αποτύχει" }, @@ -3804,6 +4935,10 @@ "stxCancelledSubDescription": { "message": "Προσπαθήστε ξανά να κάνετε ανταλλαγή. Θα είμαστε εδώ για να σας προστατεύσουμε από παρόμοιους κινδύνους και την επόμενη φορά." }, + "stxEstimatedCompletion": { + "message": "Εκτιμώμενη ολοκλήρωση σε < $1", + "description": "$1 is remeaning time in minutes and seconds, e.g. 0:10" + }, "stxFailure": { "message": "Η ανταλλαγή απέτυχε" }, @@ -3811,6 +4946,9 @@ "message": "Οι ξαφνικές αλλαγές στην αγορά μπορεί να προκαλέσουν αποτυχίες. Εάν το πρόβλημα επιμένει, παρακαλούμε επικοινωνήστε με το $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInDescription": { + "message": "Ενεργοποιήστε τις Έξυπνες Συναλλαγές για πιο αξιόπιστες και ασφαλείς συναλλαγές στο Ethereum Mainnet. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Ιδιωτική υποβολή της Ανταλλαγής σας..." }, @@ -3849,12 +4987,21 @@ "submitted": { "message": "Υποβλήθηκε" }, + "suggestedTokenSymbol": { + "message": "Προτεινόμενο σύμβολο μετοχής:" + }, "support": { "message": "Υποστήριξη" }, "supportCenter": { "message": "Επισκεφθείτε το Κέντρο Υποστήριξής μας" }, + "surveyConversion": { + "message": "Πάρτε μέρος στην έρευνά μας" + }, + "surveyTitle": { + "message": "Διαμορφώστε το μέλλον του MetaMask" + }, "swap": { "message": "Ανταλλαγή" }, @@ -3874,6 +5021,9 @@ "swapAmountReceivedInfo": { "message": "Αυτό είναι το ελάχιστο ποσό που θα λάβετε. Ενδέχεται να λάβετε περισσότερα ανάλογα με την ολίσθηση." }, + "swapAndSend": { + "message": "Ανταλλαγή & Αποστολή" + }, "swapAnyway": { "message": "Ανταλλαγή ούτως ή άλλως" }, @@ -3989,6 +5139,10 @@ "message": "Περιλαμβάνει μια χρέωση $1% στο MetaMask.", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." }, + "swapIncludesMMFeeAlt": { + "message": "Η παράθεση αντικατοπτρίζει την χρέωση τελών $1% στο MetaMask", + "description": "Provides information about the fee that metamask takes for swaps using the latest copy. $1 is a decimal number." + }, "swapIncludesMetaMaskFeeViewAllQuotes": { "message": "Περιλαμβάνει μια χρέωση $1% στο MetaMask - $2", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number and $2 is a link to view all quotes." @@ -3996,6 +5150,9 @@ "swapLearnMore": { "message": "Μάθετε περισσότερα για τις Ανταλλαγές" }, + "swapLiquiditySourceInfo": { + "message": "Αναζητούμε πολλαπλές πηγές ρευστότητας (χρηματιστήρια, συσσωρευτές και επαγγελματίες διαπραγματευτές αγοράς) για να συγκρίνουμε τις ισοτιμίες ανταλλαγής και τα τέλη δικτύου." + }, "swapLowSlippage": { "message": "Χαμηλή ολίσθηση" }, @@ -4268,6 +5425,9 @@ "switchEthereumChainConfirmationTitle": { "message": "Επιτρέπετε σε αυτόν τον ιστότοπο να αλλάξει το δίκτυο;" }, + "switchInputCurrency": { + "message": "Εναλλαγή νομίσματος εισόδου" + }, "switchNetwork": { "message": "Αλλαγή δικτύου" }, @@ -4281,14 +5441,15 @@ "switchToThisAccount": { "message": "Αλλαγή σε αυτόν τον λογαριασμό" }, - "switchedTo": { - "message": "Έχετε αλλάξει σε" + "switchedNetworkToastDecline": { + "message": "Να μην εμφανιστεί ξανά" }, - "switcherTitle": { - "message": "Επιλογέας δικτύου" + "switchedNetworkToastMessage": { + "message": "Το $1 είναι τώρα ενεργό στο $2", + "description": "$1 represents the account name, $2 represents the network name" }, - "switcherTourDescription": { - "message": "Κάντε κλικ στο εικονίδιο για να αλλάξετε δίκτυο ή να προσθέσετε ένα νέο δίκτυο" + "switchedTo": { + "message": "Έχετε αλλάξει σε" }, "switchingNetworksCancelsPendingConfirmations": { "message": "Η αλλαγή δικτύων θα ακυρώσει όλες τις εκκρεμείς επιβεβαιώσεις" @@ -4388,6 +5549,18 @@ "toggleEthSignOn": { "message": "ΕΝΕΡΓΟ (δεν συνιστάται)" }, + "toggleRequestQueueDescription": { + "message": "Αυτό σας επιτρέπει να επιλέξετε ένα δίκτυο για κάθε ιστότοπο αντί για ένα μόνο επιλεγμένο δίκτυο για όλους τους ιστότοπους. Αυτή η λειτουργία θα σας αποτρέψει από το να αλλάζετε δίκτυα χειροκίνητα, το οποίο μπορεί να διαταράξει την εμπειρία του χρήστη σε ορισμένους ιστότοπους." + }, + "toggleRequestQueueField": { + "message": "Επιλογή δικτύων για κάθε ιστότοπο" + }, + "toggleRequestQueueOff": { + "message": "Απενεργοποίηση" + }, + "toggleRequestQueueOn": { + "message": "Ενεργοποίηση" + }, "token": { "message": "Token" }, @@ -4404,7 +5577,7 @@ "message": "Διεύθυνση συμβολαίου του token" }, "tokenDecimalFetchFailed": { - "message": "Απαιτείται δεκαδικό token." + "message": "Απαιτείται δεκαδικό token. Βρείτε το σε: $1" }, "tokenDecimalTitle": { "message": "Δεκαδικά Ψηφία του token:" @@ -4443,6 +5616,9 @@ "tooltipSatusConnected": { "message": "συνδεδεμένο" }, + "tooltipSatusConnectedUpperCase": { + "message": "Συνδεδεμένο" + }, "tooltipSatusNotConnected": { "message": "μη συνδεδεμένο" }, @@ -4583,6 +5759,39 @@ "tryAgain": { "message": "Προσπαθήστε ξανά" }, + "turnOff": { + "message": "Απενεργοποίηση" + }, + "turnOffMetamaskNotificationsError": { + "message": "Προέκυψε σφάλμα κατά την απενεργοποίηση των ειδοποιήσεων. Προσπαθήστε ξανά αργότερα." + }, + "turnOn": { + "message": "Ενεργοποίηση" + }, + "turnOnMetamaskNotifications": { + "message": "Ενεργοποίηση των ειδοποιήσεων" + }, + "turnOnMetamaskNotificationsButton": { + "message": "Ενεργοποίηση" + }, + "turnOnMetamaskNotificationsError": { + "message": "Προέκυψε σφάλμα κατά τη δημιουργία των ειδοποιήσεων. Προσπαθήστε ξανά αργότερα." + }, + "turnOnMetamaskNotificationsMessageFirst": { + "message": "Μείνετε ενήμεροι για ό,τι συμβαίνει στο πορτοφόλι σας με τις ειδοποιήσεις." + }, + "turnOnMetamaskNotificationsMessagePrivacyBold": { + "message": "Ρυθμίσεις > Ειδοποιήσεις." + }, + "turnOnMetamaskNotificationsMessagePrivacyLink": { + "message": "Μάθετε πώς προστατεύουμε το απόρρητό σας κατά τη χρήση αυτής της λειτουργίας." + }, + "turnOnMetamaskNotificationsMessageSecond": { + "message": "Για να χρησιμοποιήσετε τις ειδοποιήσεις στο πορτοφόλι σας χρησιμοποιούμε ένα προφίλ για να συγχρονίσουμε ορισμένες ρυθμίσεις στις συσκευές σας. $1" + }, + "turnOnMetamaskNotificationsMessageThird": { + "message": "Μπορείτε να απενεργοποιήσετε τις ειδοποιήσεις ανά πάσα στιγμή στις $1" + }, "turnOnTokenDetection": { "message": "Ενεργοποίηση της ενισχυμένης ανίχνευσης των token" }, @@ -4614,6 +5823,10 @@ "unknownNetwork": { "message": "Άγνωστο ιδιωτικό δίκτυο" }, + "unknownNetworkForKeyEntropy": { + "message": "Άγνωστο δίκτυο", + "description": "Displayed on places like Snap install warning when regular name is not available." + }, "unknownQrCode": { "message": "Σφάλμα: Δεν μπορέσαμε να αναγνωρίσουμε αυτόν τον κωδικό QR" }, @@ -4626,6 +5839,9 @@ "unlockMessage": { "message": "Το αποκεντρωμένο διαδίκτυο αναμένει" }, + "unpin": { + "message": "Ξεκαρφίτσωμα" + }, "unrecognizedChain": { "message": "Αυτό το προσαρμοσμένο δίκτυο δεν αναγνωρίζεται", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." @@ -4643,6 +5859,9 @@ "update": { "message": "Ενημέρωση" }, + "updateRequest": { + "message": "Αίτημα ενημέρωσης" + }, "updatedWithDate": { "message": "Ενημερώθηκε $1" }, @@ -4667,12 +5886,25 @@ "useNftDetection": { "message": "Αυτόματη ανίχνευση των NFT" }, + "useNftDetectionDescriptionText": { + "message": "Επιτρέψτε στο MetaMask να προσθέτει NFT που σας ανήκουν χρησιμοποιώντας υπηρεσίες τρίτων (όπως το OpenSea). Ο αυτόματος εντοπισμός NFT εκθέτει τη διεύθυνση IP και τον λογαριασμό σας σε αυτές τις υπηρεσίες. Η ενεργοποίηση αυτής της λειτουργίας θα μπορούσε να συσχετίσει τη διεύθυνση IP σας με τη διεύθυνση Ethereum σας και να εμφανίσει ψεύτικα NFT που διοχετεύουν οι απατεώνες. Μπορείτε να προσθέσετε tokens χειροκίνητα για να αποφύγετε αυτόν τον κίνδυνο." + }, "usePhishingDetection": { "message": "Χρήση ανίχνευσης phishing" }, "usePhishingDetectionDescription": { "message": "Εμφάνιση προειδοποίησης για τομείς phishing που στοχεύουν χρήστες του Ethereum" }, + "useSafeChainsListValidation": { + "message": "Έλεγχος λεπτομερειών δικτύου" + }, + "useSafeChainsListValidationDescription": { + "message": "Το MetaMask χρησιμοποιεί μια υπηρεσία τρίτων που ονομάζεται $1 για να εμφανίζει ακριβείς και τυποποιημένες λεπτομέρειες δικτύου. Αυτό μειώνει τις πιθανότητες σύνδεσής σας με κακόβουλο ή λανθασμένο δίκτυο. Όταν χρησιμοποιείτε αυτή τη λειτουργία, η διεύθυνση IP σας εκτίθεται στο chainid.network." + }, + "useSafeChainsListValidationWebsite": { + "message": "chainid.network", + "description": "useSafeChainsListValidationWebsite is separated from the rest of the text so that we can bold the third party service name in the middle of them" + }, "useSiteSuggestion": { "message": "Χρήση προτεινόμενου ιστότοπου" }, @@ -4685,6 +5917,9 @@ "userName": { "message": "Όνομα χρήστη" }, + "userOpContractDeployError": { + "message": "Δεν υποστηρίζεται η ανάπτυξη συμβολαίου από λογαριασμό έξυπνου συμβολαίου" + }, "verifyContractDetails": { "message": "Επαλήθευση στοιχείων τρίτων" }, @@ -4702,6 +5937,9 @@ "view": { "message": "Προβολή" }, + "viewActivity": { + "message": "Προβολή δραστηριότητας" + }, "viewAllDetails": { "message": "Προβολή όλων των λεπτομερειών" }, @@ -4725,7 +5963,7 @@ }, "viewOnCustomBlockExplorer": { "message": "Προβολή $1 στο $2", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "Προβολή $1 στο Etherscan", @@ -4737,6 +5975,9 @@ "viewOnOpensea": { "message": "Προβολή στο Opensea" }, + "viewTransaction": { + "message": "Προβολή συναλλαγών" + }, "viewinCustodianApp": { "message": "Προβολή στην εφαρμογή θεματοφύλακα" }, @@ -4744,6 +5985,9 @@ "message": "Προβολή $1 στον explorer", "description": "$1 is the action type. e.g (Account, Transaction, Swap)" }, + "visitSite": { + "message": "Επισκεφθείτε τον ιστότοπο" + }, "visitWebSite": { "message": "Επισκεφθείτε τον ιστότοπό μας" }, @@ -4782,6 +6026,10 @@ "warning": { "message": "Προειδοποίηση" }, + "warningFromSnap": { + "message": "Προειδοποίηση από $1", + "description": "$1 represents the name of the snap" + }, "warningTooltipText": { "message": "$1 Ο τρίτος θα μπορούσε να ξοδέψει ολόκληρο το υπόλοιπο των tokens σας χωρίς περαιτέρω ειδοποίηση ή συγκατάθεση. Προστατέψτε τον εαυτό σας προσαρμόζοντας ένα χαμηλότερο όριο δαπανών.", "description": "$1 is a warning icon with text 'Be careful' in 'warning' colour" @@ -4789,6 +6037,9 @@ "weak": { "message": "Αδύναμο" }, + "web3": { + "message": "Web3" + }, "web3ShimUsageNotification": { "message": "Παρατηρήσαμε ότι ο τρέχων ιστότοπος προσπάθησε να χρησιμοποιήσει το καταργημένο API window.web3. Εάν ο ιστότοπος φαίνεται να έχει παραβιαστεί, κάντε κλικ στο $1 για περισσότερες πληροφορίες.", "description": "$1 is a clickable link." @@ -4829,10 +6080,6 @@ "whatsThis": { "message": "Τι είναι αυτό;" }, - "xOfY": { - "message": "$1 από $2", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$1 από $2 σε εκκρεμότητα", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" @@ -4840,6 +6087,9 @@ "yes": { "message": "Ναι" }, + "you": { + "message": "Εσείς" + }, "youHaveAddedAll": { "message": "Προσθέσατε όλα τα δημοφιλή δίκτυα. Μπορείτε να ανακαλύψετε περισσότερα δίκτυα $1 Ή μπορείτε να $2", "description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'" @@ -4862,6 +6112,12 @@ "yourPrivateSeedPhrase": { "message": "Η Μυστική Φράση Ανάκτησής σας" }, + "yourTransactionConfirmed": { + "message": "Η συναλλαγή έχει ήδη επιβεβαιωθεί" + }, + "yourTransactionJustConfirmed": { + "message": "Δεν μπορέσαμε να ακυρώσουμε τη συναλλαγή σας πριν επιβεβαιωθεί από το blockchain." + }, "zeroGasPriceOnSpeedUpError": { "message": "Μηδενική τιμή συναλλαγών για επίσπευση" } diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index afac52e67f93..a7573e179ef3 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -130,6 +130,12 @@ "account": { "message": "Account" }, + "accountActivity": { + "message": "Account activity" + }, + "accountActivityText": { + "message": "Select the accounts you want to be notified about:" + }, "accountDetails": { "message": "Account details" }, @@ -156,6 +162,12 @@ "accountSelectionRequired": { "message": "You need to select an account!" }, + "accountTypeNotSupported": { + "message": "Account type not supported" + }, + "accounts": { + "message": "Accounts" + }, "accountsConnected": { "message": "Accounts connected" }, @@ -277,6 +289,9 @@ "addNfts": { "message": "Add NFTs" }, + "addRpcUrl": { + "message": "Add RPC URL" + }, "addSnapAccountToggle": { "message": "Enable \"Add account Snap (Beta)\"" }, @@ -299,6 +314,12 @@ "addingCustomNetwork": { "message": "Adding Network" }, + "addingTokens": { + "message": "Adding tokens" + }, + "additionalNetworks": { + "message": "Additional networks" + }, "address": { "message": "Address" }, @@ -314,6 +335,18 @@ "advancedConfiguration": { "message": "Advanced configuration" }, + "advancedDetailsDataDesc": { + "message": "Data" + }, + "advancedDetailsHexDesc": { + "message": "Hex" + }, + "advancedDetailsNonceDesc": { + "message": "Nonce" + }, + "advancedDetailsNonceTooltip": { + "message": "This is the transaction number of an account. Nonce for the first transaction is 0 and it increases in sequential order." + }, "advancedGasFeeDefaultOptIn": { "message": "Save these values as my default for the $1 network.", "description": "$1 is the current network name." @@ -334,9 +367,84 @@ "airgapVault": { "message": "AirGap Vault" }, + "alert": { + "message": "Alert" + }, + "alertActionBuy": { + "message": "Buy ETH" + }, + "alertActionUpdateGas": { + "message": "Update gas limit" + }, + "alertActionUpdateGasFee": { + "message": "Update fee" + }, + "alertActionUpdateGasFeeLevel": { + "message": "Update gas options" + }, + "alertBannerMultipleAlertsDescription": { + "message": "If you approve this request, a third party known for scams might take all your assets." + }, + "alertBannerMultipleAlertsTitle": { + "message": "Multiple alerts!" + }, "alertDisableTooltip": { "message": "This can be changed in \"Settings > Alerts\"" }, + "alertMessageGasEstimateFailed": { + "message": "We’re unable to provide an accurate fee and this estimate might be high. We suggest you to input a custom gas limit, but there’s a risk the transaction will still fail." + }, + "alertMessageGasFeeLow": { + "message": "When choosing a low fee, expect slower transactions and longer wait times. For faster transactions, choose Market or Aggressive fee options." + }, + "alertMessageGasTooLow": { + "message": "To continue with this transaction, you’ll need to increase the gas limit to 21000 or higher." + }, + "alertMessageInsufficientBalance": { + "message": "You do not have enough ETH in your account to pay for transaction fees." + }, + "alertMessageNetworkBusy": { + "message": "Gas prices are high and estimates are less accurate." + }, + "alertMessageNoGasPrice": { + "message": "We can’t move forward with this transaction until you manually update the fee." + }, + "alertMessagePendingTransactions": { + "message": "This transaction won’t go through until a previous transaction is complete. Learn how to cancel or speed up a transaction." + }, + "alertMessageSigningOrSubmitting": { + "message": "This transaction will only go through once your previous transaction is complete." + }, + "alertModalAcknowledge": { + "message": "I have acknowledged the risk and still want to proceed" + }, + "alertModalDetails": { + "message": "Alert Details" + }, + "alertModalReviewAllAlerts": { + "message": "Review all alerts" + }, + "alertReasonGasEstimateFailed": { + "message": "Inaccurate fee" + }, + "alertReasonGasFeeLow": { + "message": "Slow speed" + }, + "alertReasonGasTooLow": { + "message": "Low gas limit" + }, + "alertReasonInsufficientBalance": { + "message": "Insufficient funds" + }, + "alertReasonNetworkBusy": { + "message": "Network is busy" + }, + "alertReasonNoGasPrice": { + "message": "Fee estimate unavailable" + }, + "alertReasonPendingTransactions": { + "message": "Pending transaction" + }, "alertSettingsUnconnectedAccount": { "message": "Browsing a website with an unconnected account selected" }, @@ -353,7 +461,7 @@ "message": "Alerts" }, "all": { - "message": "ALL" + "message": "All" }, "allCustodianAccountsConnectedSubtitle": { "message": "You have either already connected all your custodian accounts or don’t have any account to connect to MetaMask Institutional." @@ -381,22 +489,22 @@ "allow": { "message": "Allow" }, - "allowExternalExtensionTo": { - "message": "Allow this external extension to:" + "allowMetaMaskToDetectNFTs": { + "message": "Allow MetaMask to detect and display your NFTs with autodetection. You’ll be able to:" + }, + "allowMetaMaskToDetectTokens": { + "message": "Allow MetaMask to detect and display your tokens with autodetection. You’ll be able to:" }, "allowMmiToConnectToCustodian": { "message": "This will allow MMI to connect to $1 to import your accounts." }, + "allowNotifications": { + "message": "Allow notifications" + }, "allowSpendToken": { "message": "Give permission to access your $1?", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "Allow this site to:" - }, - "allowThisSnapTo": { - "message": "Allow this snap to:" - }, "allowWithdrawAndSpend": { "message": "Allow $1 to withdraw and spend up to the following amount:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -404,6 +512,12 @@ "amount": { "message": "Amount" }, + "amountReceived": { + "message": "Amount Received" + }, + "amountSent": { + "message": "Amount Sent" + }, "andForListItems": { "message": "$1, and $2", "description": "$1 is the first item, $2 is the last item in a list of items. Used in Snap Install Warning modal." @@ -412,6 +526,9 @@ "message": "$1 and $2", "description": "$1 is the first item, $2 is the second item. Used in Snap Install Warning modal." }, + "announcements": { + "message": "Announcements" + }, "appDescription": { "message": "An Ethereum Wallet in your Browser", "description": "The description of the application" @@ -446,6 +563,10 @@ "approveButtonText": { "message": "Approve" }, + "approveIncreaseAllowance": { + "message": "Increase $1 spending cap", + "description": "The token symbol that is being approved" + }, "approveSpendingCap": { "message": "Approve $1 spending cap", "description": "The token symbol that is being approved" @@ -471,6 +592,10 @@ "message": "Approved on $1", "description": "$1 is the approval date for a permission" }, + "approvedOnForAccounts": { + "message": "Approved on $1 for $2", + "description": "$1 is the approval date for a permission. $2 is the AvatarGroup component displaying account images." + }, "areYouSure": { "message": "Are you sure?" }, @@ -481,7 +606,10 @@ "message": "Asset options" }, "attemptSendingAssets": { - "message": "If you attempt to send assets directly from one network to another, this may result in permanent asset loss. Make sure to use a bridge." + "message": "You may lose your assets if you try to send them from another network. Transfer funds safely between networks by using a bridge." + }, + "attemptSendingAssetsWithPortfolio": { + "message": "You may lose your assets if you try to send them from another network. Transfer funds safely between networks by using a bridge, like $1" }, "attemptToCancelSwapForFree": { "message": "Attempt to cancel swap for free" @@ -492,9 +620,8 @@ "attributions": { "message": "Attributions" }, - "auroraDeprecationWarning": { - "message": "MetaMask will be deprecating support for $1 network", - "description": "$1 is name of deprecated network" + "auroraRpcDeprecationMessage": { + "message": "The Infura RPC URL is no longer supporting Aurora." }, "authorizedPermissions": { "message": "You have authorized the following permissions" @@ -554,6 +681,34 @@ "basic": { "message": "Basic" }, + "basicConfigurationBannerCTA": { + "message": "Turn on basic functionality" + }, + "basicConfigurationBannerTitle": { + "message": "Basic functionality is off" + }, + "basicConfigurationDescription": { + "message": "MetaMask offers basic features like token details and gas settings through internet services. When you use internet services, your IP address is shared, in this case with MetaMask. This is just like when you visit any website. MetaMask uses this data temporarily and never sells your data. You can use a VPN or turn off these services, but it may affect your MetaMask experience. To learn more read our $1.", + "description": "$1 is to be replaced by the message for privacyMsg, and will link to https://consensys.io/privacy-policy" + }, + "basicConfigurationLabel": { + "message": "Basic functionality" + }, + "basicConfigurationModalCheckbox": { + "message": "I understand and want to continue" + }, + "basicConfigurationModalDisclaimerOff": { + "message": "This means you won't fully optimize your time on MetaMask. Basic features (like token details, optimal gas settings, and others) won't be available to you." + }, + "basicConfigurationModalDisclaimerOn": { + "message": "To optimize your time on MetaMask, you’ll need to turn on this feature. Basic functions (like token details, optimal gas settings, and others) are important to the web3 experience." + }, + "basicConfigurationModalHeadingOff": { + "message": "Turn off basic functionality" + }, + "basicConfigurationModalHeadingOn": { + "message": "Turn on basic functionality" + }, "beCareful": { "message": "Be careful" }, @@ -608,6 +763,9 @@ "blockaid": { "message": "Blockaid" }, + "blockaidAlertInfo": { + "message": "We don't recommend proceeding with this request." + }, "blockaidDescriptionApproveFarming": { "message": "If you approve this request, a third party known for scams might take all your assets." }, @@ -615,7 +773,7 @@ "message": "If you approve this request, someone can steal your assets listed on Blur." }, "blockaidDescriptionErrored": { - "message": "Because of an error, this request was not verified by the security provider. Proceed with caution." + "message": "Because of an error, we couldn't check for security alerts. Only continue if you trust every address involved." }, "blockaidDescriptionMaliciousDomain": { "message": "You're interacting with a malicious domain. If you approve this request, you might lose your assets." @@ -629,6 +787,9 @@ "blockaidDescriptionTransferFarming": { "message": "If you approve this request, a third party known for scams will take all your assets." }, + "blockaidDescriptionWarning": { + "message": "This could be a deceptive request. Only continue if you trust every address involved." + }, "blockaidMessage": { "message": "Privacy preserving - no data is shared with third parties. Available on Arbitrum, Avalanche, BNB chain, Ethereum Mainnet, Linea, Optimism, Polygon, Base and Sepolia." }, @@ -636,7 +797,7 @@ "message": "This is a deceptive request" }, "blockaidTitleMayNotBeSafe": { - "message": "Request may not be safe" + "message": "Be careful" }, "blockaidTitleSuspicious": { "message": "This is a suspicious request" @@ -647,6 +808,9 @@ "bridge": { "message": "Bridge" }, + "bridgeDontSend": { + "message": "Bridge, don't send" + }, "browserNotSupported": { "message": "Your browser is not supported..." }, @@ -659,9 +823,6 @@ "busy": { "message": "Busy" }, - "buy": { - "message": "Buy" - }, "buyAndSell": { "message": "Buy & Sell" }, @@ -676,6 +837,10 @@ "buyNow": { "message": "Buy Now" }, + "buyToken": { + "message": "Buy $1", + "description": "$1 is the token symbol" + }, "bytes": { "message": "Bytes" }, @@ -685,9 +850,6 @@ "cancel": { "message": "Cancel" }, - "cancelEdit": { - "message": "Cancel edit" - }, "cancelPopoverTitle": { "message": "Cancel transaction" }, @@ -750,11 +912,17 @@ "description": "Text that can be clicked to open a browser popup for connecting the ledger device via webhid" }, "clickToManuallyAdd": { - "message": "Click here to manually add the tokens." + "message": "You can always add tokens manually." }, "close": { "message": "Close" }, + "closeExtension": { + "message": "Close extension" + }, + "closeWindowAnytime": { + "message": "You may close this window anytime." + }, "coingecko": { "message": "CoinGecko" }, @@ -780,6 +948,18 @@ "confirm": { "message": "Confirm" }, + "confirmAlertModalAcknowledge": { + "message": "I have acknowledged the alerts and still want to proceed" + }, + "confirmAlertModalAcknowledgeBlockaid": { + "message": "I have acknowledged the alert and still want to proceed" + }, + "confirmAlertModalDetails": { + "message": "If you sign in, a third party known for scams might take all your assets. Please review the alerts before you proceed." + }, + "confirmAlertModalTitle": { + "message": "Your assets may be at risk" + }, "confirmConnectCustodianRedirect": { "message": "We will redirect you to $1 upon clicking continue." }, @@ -789,18 +969,42 @@ "confirmConnectionTitle": { "message": "Confirm connection to $1" }, + "confirmFieldPaymaster": { + "message": "Fee paid by" + }, + "confirmFieldTooltipPaymaster": { + "message": "The fee for this transaction will be paid by the paymaster smart contract." + }, "confirmPassword": { "message": "Confirm password" }, "confirmRecoveryPhrase": { "message": "Confirm Secret Recovery Phrase" }, + "confirmTitleDescContractInteractionTransaction": { + "message": "Only confirm this transaction if you fully understand the content and trust the requesting site." + }, + "confirmTitleDescPermitSignature": { + "message": "This site wants permission to spend your tokens." + }, + "confirmTitleDescSIWESignature": { + "message": "A site wants you to sign in to prove you own this account." + }, "confirmTitleDescSignature": { - "message": "Only sign this message if you fully understand the content and trust the requesting site" + "message": "Only confirm this message if you approve the content and trust the requesting site." + }, + "confirmTitlePermitSignature": { + "message": "Spending cap request" + }, + "confirmTitleSIWESignature": { + "message": "Sign-in request" }, "confirmTitleSignature": { "message": "Signature request" }, + "confirmTitleTransaction": { + "message": "Transaction request" + }, "confirmed": { "message": "Confirmed" }, @@ -847,26 +1051,6 @@ "message": "Connect $1", "description": "$1 is the snap for which a connection is being requested." }, - "connectTo": { - "message": "Connect to $1", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "Connect to all your $1", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "accounts", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "Connect to $1", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1 accounts", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "Connect with MetaMask" }, @@ -887,6 +1071,9 @@ "message": "$1 can see the account balance, address, activity, and suggest transactions to approve for connected accounts.", "description": "$1 is the origin name" }, + "connectedAccountsToast": { + "message": "Connected accounts updated" + }, "connectedSites": { "message": "Connected sites" }, @@ -904,11 +1091,8 @@ "connectedWith": { "message": "Connected with" }, - "connectedaccountsTabKey": { - "message": "Connected accounts" - }, "connecting": { - "message": "Connecting..." + "message": "Connecting" }, "connectingTo": { "message": "Connecting to $1" @@ -925,6 +1109,9 @@ "connectingToLineaMainnet": { "message": "Connecting to Linea Mainnet" }, + "connectingToLineaSepolia": { + "message": "Connecting to Linea Sepolia test network" + }, "connectingToMainnet": { "message": "Connecting to Ethereum Mainnet" }, @@ -1096,6 +1283,12 @@ "custodianAccountAddedTitle": { "message": "Selected $1 accounts have been added." }, + "custodianQRCodeScan": { + "message": "Scan QR code with your $1 mobile app" + }, + "custodianQRCodeScanDescription": { + "message": "Or log into your $1 account and click on the 'Connect to MMI' button" + }, "custodianReplaceRefreshTokenChangedFailed": { "message": "Please go to $1 and click the 'Connect to MMI' button within their user interface to connect your accounts to MMI again." }, @@ -1166,6 +1359,12 @@ "customerSupport": { "message": "customer support" }, + "customizeYourNotifications": { + "message": "Customize your notifications" + }, + "customizeYourNotificationsText": { + "message": "Turn on the types of notifications you want to receive:" + }, "dappRequestedSpendingCap": { "message": "Site requested spending cap" }, @@ -1198,6 +1397,18 @@ "dataBackupSeemsCorrupt": { "message": "Can not restore your data. The file appears to be corrupt." }, + "dataCollectionForMarketing": { + "message": "Data collection for marketing" + }, + "dataCollectionForMarketingDescription": { + "message": "We'll use MetaMetrics to learn how you interact with our marketing communications. We may share relevant news (like product features and other materials)." + }, + "dataCollectionWarningPopoverButton": { + "message": "Okay" + }, + "dataCollectionWarningPopoverDescription": { + "message": "You turned off data collection for our marketing purposes. This only applies to this device. If you use MetaMask on other devices, make sure to opt out there as well." + }, "dataHex": { "message": "Hex" }, @@ -1230,6 +1441,9 @@ "decryptRequest": { "message": "Decrypt request" }, + "defaultRpcUrl": { + "message": "Default RPC URL" + }, "delete": { "message": "Delete" }, @@ -1249,9 +1463,6 @@ "deposit": { "message": "Deposit" }, - "deprecatedAuroraNetworkMsg": { - "message": "MetaMask will be deprecating support for Aurora network. Please add it as a custom network if you want to continue to use it" - }, "deprecatedGoerliNtwrkMsg": { "message": "Because of updates to the Ethereum system, the Goerli test network will be phased out soon." }, @@ -1271,110 +1482,26 @@ "message": "Description from $1", "description": "$1 represents the name of the snap" }, - "desktopApp": { - "message": "Desktop App" - }, - "desktopConnectionCriticalErrorDescription": { - "message": "This error could be intermittent, so try restarting the extension or disable MetaMask Desktop." - }, - "desktopConnectionCriticalErrorTitle": { - "message": "MetaMask had trouble starting" - }, - "desktopConnectionLostErrorDescription": { - "message": "Please make sure you have the desktop app up and running or disable MetaMask Desktop." - }, - "desktopConnectionLostErrorTitle": { - "message": "MetaMask Desktop connection was lost" - }, - "desktopDisableButton": { - "message": "Disable Desktop App" - }, - "desktopDisableErrorCTA": { - "message": "Disable MetaMask Desktop" - }, - "desktopEnableButton": { - "message": "Enable Desktop App" - }, - "desktopEnableButtonDescription": { - "message": "Click to run all background processes in the desktop app." - }, - "desktopErrorNavigateSettingsCTA": { - "message": "Return to Settings Page" - }, - "desktopErrorRestartMMCTA": { - "message": "Restart MetaMask" - }, - "desktopNotFoundErrorCTA": { - "message": "Download MetaMask Desktop" - }, - "desktopNotFoundErrorDescription1": { - "message": "Please make sure you have the desktop app up and running." - }, - "desktopNotFoundErrorDescription2": { - "message": "If you have no desktop app installed, please download it on the MetaMask website." - }, - "desktopNotFoundErrorTitle": { - "message": "MetaMask Desktop was not found" - }, - "desktopOpenOrDownloadCTA": { - "message": "Open MetaMask Desktop" - }, - "desktopOutdatedErrorCTA": { - "message": "Update MetaMask Desktop" - }, - "desktopOutdatedErrorDescription": { - "message": "Your MetaMask desktop app needs to be upgraded." - }, - "desktopOutdatedErrorTitle": { - "message": "MetaMask Desktop is outdated" - }, - "desktopOutdatedExtensionErrorCTA": { - "message": "Update MetaMask Extension" - }, - "desktopOutdatedExtensionErrorDescription": { - "message": "Your MetaMask extension needs to be upgraded." - }, - "desktopOutdatedExtensionErrorTitle": { - "message": "MetaMask Extension is outdated" - }, - "desktopPageDescription": { - "message": "If the pairing is successful, extension will restart and you'll have to re-enter your password." - }, - "desktopPageSubTitle": { - "message": "Open your MetaMask Desktop and type this code" - }, - "desktopPageTitle": { - "message": "Pair with Desktop" - }, - "desktopPairedWarningDeepLink": { - "message": "Go to Settings in MetaMask Desktop" - }, - "desktopPairedWarningDescription": { - "message": "If you want to start a new pairing, please remove the current connection." - }, - "desktopPairedWarningTitle": { - "message": "MM Desktop is already paired" - }, - "desktopPairingExpireMessage": { - "message": "Code expires in $1 seconds" + "details": { + "message": "Details" }, - "desktopRouteNotFoundErrorDescription": { - "message": "desktopRouteNotFoundErrorDescription" + "developerOptions": { + "message": "Developer Options" }, - "desktopRouteNotFoundErrorTitle": { - "message": "desktopRouteNotFoundErrorTitle" + "developerOptionsNetworkMenuRedesignDescription": { + "message": "Toggles the new design of the Networks menu" }, - "desktopUnexpectedErrorCTA": { - "message": "Return MetaMask Home" + "developerOptionsNetworkMenuRedesignTitle": { + "message": "Network Menu Redesign" }, - "desktopUnexpectedErrorDescription": { - "message": "Check your MetaMask Desktop to restore connection" + "developerOptionsResetStatesAnnouncementsDescription": { + "message": "Resets isShown boolean to false for all announcements. Announcements are the notifications shown in the What's New popup modal." }, - "desktopUnexpectedErrorTitle": { - "message": "Something went wrong..." + "developerOptionsResetStatesOnboarding": { + "message": "Resets various states related to onboarding and redirects to the \"Secure Your Wallet\" onboarding page." }, - "details": { - "message": "Details" + "developerOptionsServiceWorkerKeepAlive": { + "message": "Results in a timestamp being continuously saved to session.storage" }, "disabledGasOptionToolTipMessage": { "message": "“$1” is disabled because it does not meet the minimum of a 10% increase from the original gas fee.", @@ -1409,6 +1536,14 @@ "disconnectThisAccount": { "message": "Disconnect this account" }, + "disconnectedAllAccountsToast": { + "message": "All accounts disconnected from $1", + "description": "$1 is name of the dapp`" + }, + "disconnectedSingleAccountToast": { + "message": "$1 disconnected from $2", + "description": "$1 is name of the name and $2 represents the dapp name`" + }, "discoverSnaps": { "message": "Discover Snaps", "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." @@ -1428,6 +1563,12 @@ "displayNftMediaDescription": { "message": "Displaying NFT media and data exposes your IP address to OpenSea or other third parties. This can allow attackers to associate your IP address with your Ethereum address. NFT autodetection relies on this setting, and won't be available when this is turned off." }, + "diveStraightIntoUsingYourNFTs": { + "message": "Dive straight into using your NFTs" + }, + "diveStraightIntoUsingYourTokens": { + "message": "Dive straight into using your tokens" + }, "doNotShare": { "message": "Do not share this with anyone" }, @@ -1556,14 +1697,20 @@ "editSpeedUpEditGasFeeModalTitle": { "message": "Edit speed up gas fee" }, + "effortlesslyNavigateYourDigitalAssets": { + "message": "Effortlessly navigate your digital assets" + }, + "enable": { + "message": "Enable" + }, "enableAutoDetect": { "message": " Enable autodetect" }, "enableFromSettings": { "message": " Enable it from Settings." }, - "enableSmartSwaps": { - "message": "Enable Smart Swaps" + "enableNftAutoDetection": { + "message": "Enable NFT autodetection" }, "enableSnap": { "message": "Enable" @@ -1572,9 +1719,15 @@ "message": "enable $1", "description": "$1 is a token symbol, e.g. ETH" }, + "enableTokenAutoDetection": { + "message": "Enable token autodetection" + }, "enabled": { "message": "Enabled" }, + "enabledNetworks": { + "message": "Enabled networks" + }, "encryptionPublicKeyNotice": { "message": "$1 would like your public encryption key. By consenting, this site will be able to compose encrypted messages to you.", "description": "$1 is the web3 site name" @@ -1721,7 +1874,7 @@ "message": "Proposed nicknames" }, "externalNameSourcesSettingDescription": { - "message": "We’ll fetch proposed nicknames for addresses you interact with from third-party sources like Etherscan, Infura, and Lens Protocol. These sources will be able to see the those addresses and your IP address. Your account address won’t be exposed to third parties." + "message": "We’ll fetch proposed nicknames for addresses you interact with from third-party sources like Etherscan, Infura, and Lens Protocol. These sources will be able to see those addresses and your IP address. Your account address won’t be exposed to third parties." }, "failed": { "message": "Failed" @@ -1735,9 +1888,6 @@ "failureMessage": { "message": "Something went wrong, and we were unable to complete the action" }, - "faqAndRiskDisclosures": { - "message": "FAQ and Risk Disclosures" - }, "fast": { "message": "Fast" }, @@ -1804,6 +1954,9 @@ "fromTokenLists": { "message": "From token lists: $1" }, + "function": { + "message": "Function: $1" + }, "functionApprove": { "message": "Function: Approve" }, @@ -1813,6 +1966,13 @@ "functionType": { "message": "Function type" }, + "fundYourWallet": { + "message": "Fund your wallet" + }, + "fundYourWalletDescription": { + "message": "Get started by adding some $1 to your wallet.", + "description": "$1 is the token symbol" + }, "gas": { "message": "Gas" }, @@ -1823,6 +1983,9 @@ "message": "This gas fee has been suggested by $1. Overriding this may cause a problem with your transaction. Please reach out to $1 if you have questions.", "description": "$1 represents the Dapp's origin" }, + "gasIsETH": { + "message": "Gas is $1 " + }, "gasLimit": { "message": "Gas limit" }, @@ -1893,11 +2056,13 @@ "genericExplorerView": { "message": "View account on $1" }, - "globalTitle": { - "message": "Global menu" + "getStartedWithNFTs": { + "message": "Get $1 to buy NFTs", + "description": "$1 is the token symbol" }, - "globalTourDescription": { - "message": "See your portfolio, connected sites, settings, and more" + "getStartedWithNFTsDescription": { + "message": "Get started with NFTs by adding some $1 to your wallet.", + "description": "$1 is the token symbol" }, "goBack": { "message": "Go back" @@ -1987,9 +2152,6 @@ "highLowercase": { "message": "high" }, - "historicalPricesWereNotFound": { - "message": "Historical prices were not found" - }, "history": { "message": "History" }, @@ -2051,6 +2213,12 @@ "imToken": { "message": "imToken" }, + "immediateAccessToYourNFTs": { + "message": "Immediately access your NFTs" + }, + "immediateAccessToYourTokens": { + "message": "Immediate access to your tokens" + }, "import": { "message": "Import", "description": "Button to import an account from a selected file" @@ -2130,6 +2298,9 @@ "initialTransactionConfirmed": { "message": "Your initial transaction was confirmed by the network. Click OK to go back." }, + "inlineAlert": { + "message": "Alert" + }, "inputLogicEmptyState": { "message": "Only enter a number that you're comfortable with the third party spending now or in the future. You can always increase the spending cap later." }, @@ -2178,7 +2349,7 @@ "message": "Install origin" }, "installRequest": { - "message": "Installation request" + "message": "Add to MetaMask" }, "installedOn": { "message": "Installed on $1", @@ -2208,6 +2379,12 @@ "insufficientTokens": { "message": "Insufficient tokens." }, + "interactingWith": { + "message": "Interacting with" + }, + "interactingWithTransactionDescription": { + "message": "This is the contract you're interacting with. Protect yourself from scammers by verifying the details." + }, "invalidAddress": { "message": "Invalid address" }, @@ -2338,6 +2515,9 @@ "layer1Fees": { "message": "Layer 1 fees" }, + "layer2Fees": { + "message": "Layer 2 fees" + }, "learnCancelSpeeedup": { "message": "Learn how to $1", "description": "$1 is link to cancel or speed up transactions" @@ -2355,9 +2535,15 @@ "learnMoreUpperCase": { "message": "Learn more" }, + "learnMoreUpperCaseWithDot": { + "message": "Learn more." + }, "learnScamRisk": { "message": "scams and security risks." }, + "learnToBridge": { + "message": "Learn to bridge" + }, "leaveMetaMask": { "message": "Leave MetaMask?" }, @@ -2425,6 +2611,9 @@ "lineaMainnet": { "message": "Linea Mainnet" }, + "lineaSepolia": { + "message": "Linea Sepolia test network" + }, "link": { "message": "Link" }, @@ -2437,9 +2626,6 @@ "loading": { "message": "Loading..." }, - "loadingNFTs": { - "message": "Loading NFTs..." - }, "loadingScreenHardwareWalletMessage": { "message": "Please complete the transaction on the hardware wallet." }, @@ -2541,12 +2727,24 @@ "metamaskInstitutionalVersion": { "message": "MetaMask Institutional Version" }, + "metamaskNotificationsAreOff": { + "message": "Wallet notifications are currently not active." + }, + "metamaskPortfolio": { + "message": "MetaMask Portfolio." + }, "metamaskSwapsOfflineDescription": { "message": "MetaMask Swaps is undergoing maintenance. Please check back later." }, "metamaskVersion": { "message": "MetaMask Version" }, + "methodData": { + "message": "Method" + }, + "methodDataTransactionDescription": { + "message": "This is the specific action that will be taken. This data can be faked, so be sure you trust the site on the other end." + }, "methodNotSupported": { "message": "Not supported with this account." }, @@ -2599,7 +2797,7 @@ "message": "more" }, "multipleSnapConnectionWarning": { - "message": "$1 wants to connect with $2 snaps. Only proceed if you trust this website.", + "message": "$1 wants to use $2 Snaps", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." }, "mustSelectOne": { @@ -2664,8 +2862,12 @@ "message": "Choose a nickname...", "description": "Placeholder text for name input field in name component modal." }, + "nativePermissionRequestDescription": { + "message": "Do you want this site to do the following?", + "description": "Description below header used on Permission Connect screen for native permissions." + }, "nativeToken": { - "message": "The native token on this network is $1. It is the token used for gas fees.", + "message": "The native token on this network is $1. It is the token used for gas fees. ", "description": "$1 represents the name of the native token on the current network" }, "nativeTokenScamWarningConversion": { @@ -2699,7 +2901,7 @@ "message": "Can not send negative amounts of ETH." }, "negativeOrZeroAmountToken": { - "message": "Cannot send negative or zero amounts of Tokens" + "message": "Cannot send negative or zero amounts of asset." }, "network": { "message": "Network:" @@ -2731,6 +2933,9 @@ "networkNameBSC": { "message": "BSC" }, + "networkNameBase": { + "message": "Base" + }, "networkNameDefinition": { "message": "The name associated with this network." }, @@ -2755,6 +2960,9 @@ "networkNameZkSyncEra": { "message": "zkSync Era" }, + "networkOptions": { + "message": "Network options" + }, "networkProvider": { "message": "Network provider" }, @@ -2823,12 +3031,21 @@ "newNetworkAdded": { "message": "“$1” was successfully added!" }, + "newNetworkEdited": { + "message": "“$1” was successfully edited!" + }, "newNftAddedMessage": { "message": "NFT was successfully added!" }, "newPassword": { "message": "New password (8 characters min)" }, + "newPrivacyPolicyActionButton": { + "message": "Read more" + }, + "newPrivacyPolicyTitle": { + "message": "We’ve updated our privacy policy" + }, "newTokensImportedMessage": { "message": "You’ve successfully imported $1.", "description": "$1 is the string of symbols of all the tokens imported" @@ -2853,12 +3070,12 @@ "nftAlreadyAdded": { "message": "NFT has already been added." }, + "nftAutoDetectionEnabled": { + "message": "NFT autodetection enabled" + }, "nftDisclaimer": { "message": "Disclaimer: MetaMask pulls the media file from the source url. This url sometimes gets changed by the marketplace on which the NFT was minted." }, - "nftLearnMore": { - "message": "Learn more about NFTs" - }, "nftOptions": { "message": "NFT Options" }, @@ -2903,6 +3120,12 @@ "noConversionRateAvailable": { "message": "No conversion rate available" }, + "noDomainResolution": { + "message": "No resolution for domain provided." + }, + "noHardwareWalletOrSnapsSupport": { + "message": "Snaps, and most hardware wallets, will not work with your current browser version." + }, "noNFTs": { "message": "No NFTs yet" }, @@ -2921,6 +3144,9 @@ "noWebcamFoundTitle": { "message": "Webcam not found" }, + "nonCustodialAccounts": { + "message": "MetaMask Institutional allows you to use non-custodial accounts, if you plan to use these accounts backup the Secret Recovery Phrase." + }, "nonce": { "message": "Nonce" }, @@ -2945,179 +3171,186 @@ "notEnoughGas": { "message": "Not enough gas" }, + "notRightNow": { + "message": "Not right now" + }, "note": { "message": "Note" }, "notePlaceholder": { "message": "The approver will see this note when approving the transaction at the custodian." }, - "notificationTransactionFailedMessage": { - "message": "Transaction $1 failed! $2", - "description": "Content of the browser notification that appears when a transaction fails" + "notificationDetail": { + "message": "Details" }, - "notificationTransactionFailedMessageMMI": { - "message": "Transaction failed! $1", - "description": "Content of the browser notification that appears when a transaction fails in MMI" + "notificationDetailBaseFee": { + "message": "Base fee (GWEI)" }, - "notificationTransactionFailedTitle": { - "message": "Failed transaction", - "description": "Title of the browser notification that appears when a transaction fails" + "notificationDetailGasLimit": { + "message": "Gas limit (units)" }, - "notificationTransactionSuccessMessage": { - "message": "Transaction $1 confirmed!", - "description": "Content of the browser notification that appears when a transaction is confirmed" + "notificationDetailGasUsed": { + "message": "Gas used (units)" }, - "notificationTransactionSuccessTitle": { - "message": "Confirmed transaction", - "description": "Title of the browser notification that appears when a transaction is confirmed" + "notificationDetailMaxFee": { + "message": "Max fee per gas" }, - "notificationTransactionSuccessView": { - "message": "View on $1", - "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" + "notificationDetailNetwork": { + "message": "Network" }, - "notifications": { - "message": "Notifications" + "notificationDetailNetworkFee": { + "message": "Network fee" }, - "notifications20ActionText": { - "message": "Learn more", - "description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a ledger page to resolve the U2F connection issue." + "notificationDetailPriorityFee": { + "message": "Priority fee (GWEI)" }, - "notifications20Description": { - "message": "If you're on the latest version of Firefox, you might be experiencing an issue related to Firefox dropping U2F support.", - "description": "Description of a notification in the 'See What's New' popup. Describes the U2F support being dropped by firefox and that it affects ledger users." + "notificationItemCheckBlockExplorer": { + "message": "Check on the Block Explorer" }, - "notifications20Title": { - "message": "Ledger and Firefox Users Experiencing Connection Issues", - "description": "Title for a notification in the 'See What's New' popup. Tells users that latest firefox users using U2F may experience connection issues." + "notificationItemCollection": { + "message": "Collection" }, - "notifications24ActionText": { - "message": "Got it" + "notificationItemConfirmed": { + "message": "Confirmed" }, - "notifications24Description": { - "message": "Advanced gas fee settings are now remembered based on the network you're using. This means you can set specific advanced gas fees for each network and avoid overpaying for gas or stuck transactions." + "notificationItemError": { + "message": "Unable to retrieve fees currently" }, - "notifications24Title": { - "message": "Advanced gas fees by network" + "notificationItemFrom": { + "message": "From" }, - "notifications8ActionText": { - "message": "Go to Settings > Advanced", - "description": "Description on an action button that appears in the What's New popup. Tells the user that if they click it, they will go to our Advanced settings page." + "notificationItemLidoStakeReadyToBeWithdrawn": { + "message": "Withdrawal Ready" }, - "notifications8DescriptionOne": { - "message": "As of MetaMask v10.4.0, you no longer need Ledger Live to connect your Ledger device to MetaMask.", - "description": "Description of a notification in the 'See What's New' popup. Describes changes for how Ledger Live is no longer needed to connect the device." + "notificationItemLidoStakeReadyToBeWithdrawnMessage": { + "message": "You can now withdraw your unstaked $1" }, - "notifications8DescriptionTwo": { - "message": "For an easier and more stable ledger experience, go to Settings > Advanced and switch the 'Preferred Ledger Connection Type' to 'WebHID'.", - "description": "Description of a notification in the 'See What's New' popup. Describes how the user can turn off the Ledger Live setting." + "notificationItemLidoWithdrawalRequestedMessage": { + "message": "Your request to unstake $1 has been sent" }, - "notifications8Title": { - "message": "Ledger connection improvement", - "description": "Title for a notification in the 'See What's New' popup. Notifies ledger users that there is an improvement in how they can connect their device." + "notificationItemNFTReceivedFrom": { + "message": "Received NFT from" }, - "notificationsBlockaidDefaultDescriptionActionText": { - "message": "Got it" + "notificationItemNFTSentTo": { + "message": "Sent NFT to" }, - "notificationsBlockaidDefaultDescriptionOne": { - "message": "Steer clear of known scams while still preserving your privacy with security alerts powered by Blockaid. This feature is available on Arbitrum, Avalanche, BNB chain, Ethereum Mainnet, Linea, Optimism, Polygon, Base and Sepolia." + "notificationItemNetwork": { + "message": "Network" }, - "notificationsBlockaidDefaultDescriptionTwo": { - "message": "Always do your own due diligence before approving requests." + "notificationItemRate": { + "message": "Rate (fee included)" }, - "notificationsBlockaidDefaultTitle": { - "message": "Stay safe with security alerts" + "notificationItemReceived": { + "message": "Received" }, - "notificationsBuySellActionText": { - "message": "Try it on MetaMask Portfolio" + "notificationItemReceivedFrom": { + "message": "Received from" }, - "notificationsBuySellDescription": { - "message": "Introducing the ‘Buy & Sell’ button, giving you easy access to our latest feature: Sell. When clicked, you’ll be redirected to MetaMask Portfolio, where you’ll be able to convert your crypto to cash in a flash. Initially available for ETH on mainnet in the US (state restrictions apply), UK, and parts of Europe." + "notificationItemSent": { + "message": "Sent" }, - "notificationsBuySellTitle": { - "message": "Sell your crypto, get cash" + "notificationItemSentTo": { + "message": "Sent to" }, - "notificationsDropLedgerFirefoxDescription": { - "message": "Firefox no longer supports U2F, so Ledger won't work with MetaMask on Firefox. Try MetaMask on Google Chrome instead.", - "description": "Description of a notification in the 'See What's New' popup. Describes that ledger will not longer be supported for firefox users and they should use MetaMask on chrome for ledger support instead." + "notificationItemStakeCompleted": { + "message": "Stake completed" }, - "notificationsDropLedgerFirefoxTitle": { - "message": "Dropping Ledger Support for Firefox", - "description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped." + "notificationItemStaked": { + "message": "Staked" }, - "notificationsEmptyText": { - "message": "This is where you can find notifications from your installed snaps." + "notificationItemStakingProvider": { + "message": "Staking Provider" }, - "notificationsHeader": { - "message": "Notifications" + "notificationItemStatus": { + "message": "Status" }, - "notificationsInfos": { - "message": "$1 from $2", - "description": "$1 is the date at which the notification has been dispatched and $2 is the link to the snap that dispatched the notification." + "notificationItemSwapped": { + "message": "Swapped" }, - "notificationsMarkAllAsRead": { - "message": "Mark all as read" + "notificationItemSwappedFor": { + "message": "for" }, - "notificationsOpenBetaSnapsActionText": { - "message": "Learn more" + "notificationItemTo": { + "message": "To" }, - "notificationsOpenBetaSnapsDescriptionOne": { - "message": "🎉 We're excited to announce the Open Beta of MetaMask Snaps!" + "notificationItemTransactionId": { + "message": "Transaction ID" }, - "notificationsOpenBetaSnapsDescriptionThree": { - "message": "Personalize your wallet with snaps built by the developer community!" + "notificationItemUnStakeCompleted": { + "message": "UnStaking complete" }, - "notificationsOpenBetaSnapsDescriptionTwo": { - "message": "Snaps help you do more with MetaMask — like connect to more networks, see transaction insights, and get custom notifications." + "notificationItemUnStaked": { + "message": "Unstaked" }, - "notificationsOpenBetaSnapsTitle": { - "message": "Introducing MetaMask Snaps" + "notificationItemUnStakingRequested": { + "message": "Unstaking requested" }, - "notificationsPetnamesActionText": { - "message": "Got it" + "notificationTransactionFailedMessage": { + "message": "Transaction $1 failed! $2", + "description": "Content of the browser notification that appears when a transaction fails" }, - "notificationsPetnamesDescriptionOne": { - "message": "When you click on an address during a transaction, you can see suggested nicknames from third-party sources such as ENS, Lens, and Etherscan." + "notificationTransactionFailedMessageMMI": { + "message": "Transaction failed! $1", + "description": "Content of the browser notification that appears when a transaction fails in MMI" }, - "notificationsPetnamesDescriptionTwo": { - "message": "This will make it easier for you to recognize addresses in the future, so be sure to give a nickname to addresses you trust." + "notificationTransactionFailedTitle": { + "message": "Failed transaction", + "description": "Title of the browser notification that appears when a transaction fails" }, - "notificationsPetnamesTitle": { - "message": "Suggested nicknames are here!" + "notificationTransactionSuccessMessage": { + "message": "Transaction $1 confirmed!", + "description": "Content of the browser notification that appears when a transaction is confirmed" }, - "notificationsPortfolioV2ActionText": { - "message": "See Portfolio" + "notificationTransactionSuccessTitle": { + "message": "Confirmed transaction", + "description": "Title of the browser notification that appears when a transaction is confirmed" }, - "notificationsPortfolioV2DescriptionOne": { - "message": "Still missing out on MetaMask Portfolio?" + "notificationTransactionSuccessView": { + "message": "View on $1", + "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" }, - "notificationsPortfolioV2DescriptionThree": { - "message": "Your Portfolio is waiting." + "notifications": { + "message": "Notifications" }, - "notificationsPortfolioV2DescriptionTwo": { - "message": "Manage your web3 assets across different networks and accounts in one powerful dashboard. Swap, Buy, Sell, Bridge, and Stake in a secure, convenient, and easy to use dapp. Stay up to speed with the pulse of the cryptoverse, see your DeFi positions, manage your NFT collection, and more. All in one place." + "notificationsDropLedgerFirefoxDescription": { + "message": "Firefox no longer supports U2F, so Ledger won't work with MetaMask on Firefox. Try MetaMask on Google Chrome instead.", + "description": "Description of a notification in the 'See What's New' popup. Describes that ledger will not longer be supported for firefox users and they should use MetaMask on chrome for ledger support instead." + }, + "notificationsDropLedgerFirefoxTitle": { + "message": "Dropping Ledger Support for Firefox", + "description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped." + }, + "notificationsFeatureToggle": { + "message": "Enable Wallet Notifications", + "description": "Experimental feature title" + }, + "notificationsFeatureToggleDescription": { + "message": "This enables wallet notifications like send/receive funds or nfts and feature announcements.", + "description": "Description of the experimental notifications feature" }, - "notificationsPortfolioV2Title": { - "message": "MetaMask Portfolio - join millions" + "notificationsMarkAllAsRead": { + "message": "Mark all as read" }, - "notificationsStakingPortfolioActionText": { - "message": "Got it", - "description": "Action text for a notification in the 'See What's New' popup. Tells users that staking is now available in the portfolio app." + "notificationsPageEmptyTitle": { + "message": "Nothing to see here" }, - "notificationsStakingPortfolioDescription": { - "message": "Now you can stake ETH and manage your rewards all in one place.", - "description": "Description for a notification in the 'See What's New' popup. Tells users that staking is now available in the portfolio app." + "notificationsPageErrorContent": { + "message": "Please, try to visit this page again." }, - "notificationsStakingPortfolioTitle": { - "message": "Stake smarter in Portfolio", - "description": "Title for a notification in the 'See What's New' popup. Tells users that staking is now available in the portfolio app." + "notificationsPageErrorTitle": { + "message": "There has been an error" }, - "notificationsU2FLedgerLiveDescription": { - "message": "U2F and Ledger Live are no longer available on Chrome. You can still connect Ledger devices on Chrome using Webhid.", - "description": "Description of a notification in the 'See What's New' popup. Describes the U2F and Ledger Live connection modes are now deprecated" + "notificationsPageNoNotificationsContent": { + "message": "You have not received any notifications yet." }, - "notificationsU2FLedgerLiveTitle": { - "message": "U2F and Ledger Live deprecation", - "description": "Title for a notification in the 'See What's New' popup. Tells ledger and chrome users that U2F and Ledger Live options are now deprecated." + "notificationsSettingsBoxError": { + "message": "Something went wrong. Please try again." + }, + "notificationsSettingsPageAllowNotifications": { + "message": "Stay in the loop on what’s happening in your wallet with notifications. To use notifications, we use a profile to sync some settings across your devices. $1" + }, + "notificationsSettingsPageAllowNotificationsLink": { + "message": "Learn how we protect your privacy while using this feature." }, "numberOfNewTokensDetectedPlural": { "message": "$1 new tokens found in this account", @@ -3141,6 +3374,40 @@ "on": { "message": "On" }, + "onboardedMetametricsAccept": { + "message": "I agree" + }, + "onboardedMetametricsDisagree": { + "message": "No thanks" + }, + "onboardedMetametricsKey1": { + "message": "Latest developments" + }, + "onboardedMetametricsKey2": { + "message": "Product features" + }, + "onboardedMetametricsKey3": { + "message": "Other relevant promotional materials" + }, + "onboardedMetametricsLink": { + "message": "MetaMetrics" + }, + "onboardedMetametricsParagraph1": { + "message": "In addition to $1, we'd like to use data to understand how you interact with marketing communications.", + "description": "$1 represents the 'onboardedMetametricsLink' locale string" + }, + "onboardedMetametricsParagraph2": { + "message": "This helps us personalize what we share with you, like:" + }, + "onboardedMetametricsParagraph3": { + "message": "Remember, we never sell the data you provide and you can opt out any time." + }, + "onboardedMetametricsTitle": { + "message": "Help us enhance your experience" + }, + "onboarding": { + "message": "Onboarding" + }, "onboardingAdvancedPrivacyIPFSDescription": { "message": "The IPFS gateway makes it possible to access and view data hosted by third parties. You can add a custom IPFS gateway or continue using the default." }, @@ -3171,55 +3438,52 @@ "onboardingMetametricsAgree": { "message": "I agree" }, - "onboardingMetametricsAllowOptOut": { - "message": "Always allow you to opt-out via Settings" - }, - "onboardingMetametricsDataTerms": { - "message": "This data is aggregated and is therefore anonymous for the purposes of General Data Protection Regulation (EU) 2016/679." - }, "onboardingMetametricsDescription": { - "message": "MetaMask would like to gather usage data to better understand how our users interact with MetaMask. This data will be used to provide the service, which includes improving the service based on your use." + "message": "We’d like to gather basic usage and diagnostics data to improve MetaMask. Know that we never sell the data you provide here." }, "onboardingMetametricsDescription2": { - "message": "MetaMask will..." + "message": "When we gather metrics, it will always be..." }, "onboardingMetametricsDisagree": { "message": "No thanks" }, "onboardingMetametricsInfuraTerms": { - "message": "* When you use Infura as your default RPC provider in MetaMask, Infura will collect your IP address and your Ethereum wallet address when you send a transaction. We don’t store this information in a way that allows our systems to associate those two pieces of data. For more information on how MetaMask and Infura interact from a data collection perspective, see our update $1. For more information on our privacy practices in general, see our $2.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" + "message": "We’ll let you know if we decide to use this data for other purposes. You can review our $1 for more information. Remember, you can go to settings and opt out at any time.", + "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, "onboardingMetametricsInfuraTermsPolicy": { - "message": "Privacy Policy here" - }, - "onboardingMetametricsInfuraTermsPolicyLink": { - "message": "here" + "message": "Privacy Policy" }, "onboardingMetametricsModalTitle": { "message": "Add custom network" }, "onboardingMetametricsNeverCollect": { - "message": "$1 collect information we don’t need to provide the service (such as keys, addresses, transaction hashes, or balances)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 clicks and views on the app are stored, but other details (like your public address) are not.", + "description": "$1 represents `onboardingMetametricsNeverCollectEmphasis`" + }, + "onboardingMetametricsNeverCollectEmphasis": { + "message": "Private:" }, "onboardingMetametricsNeverCollectIP": { - "message": "$1 collect your full IP address*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 we temporarily use your IP address to detect a general location (like your country or region), but it's never stored.", + "description": "$1 represents `onboardingMetametricsNeverCollectIPEmphasis`" }, - "onboardingMetametricsNeverEmphasis": { - "message": "Never" + "onboardingMetametricsNeverCollectIPEmphasis": { + "message": "General:" }, "onboardingMetametricsNeverSellData": { - "message": "$1 sell data. Ever!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 you decide if you want to share or delete your usage data via settings any time.", + "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" }, - "onboardingMetametricsSendAnonymize": { - "message": "Send anonymized click and pageview events" + "onboardingMetametricsNeverSellDataEmphasis": { + "message": "Optional:" }, "onboardingMetametricsTitle": { "message": "Help us improve MetaMask" }, + "onboardingMetametricsUseDataCheckbox": { + "message": "We’ll use this data to learn how you interact with our marketing communications. We may share relevant news (like product features)." + }, "onboardingPinExtensionBillboardAccess": { "message": "Full access" }, @@ -3279,11 +3543,15 @@ "message": "1Y", "description": "Shortened form of '1 year'" }, + "onekey": { + "message": "OneKey" + }, "onlyAddTrustedNetworks": { "message": "A malicious network provider can lie about the state of the blockchain and record your network activity. Only add custom networks you trust." }, "onlyConnectTrust": { - "message": "Only connect with sites you trust." + "message": "Only connect with sites you trust. $1", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." }, "openCustodianApp": { "message": "Open $1 app", @@ -3296,21 +3564,21 @@ "openInBlockExplorer": { "message": "Open in block explorer" }, - "openSeaLabel": { - "message": "OpenSea + Blockaid" - }, - "openSeaMessage": { - "message": "Data is shared with third parties. Security providers will receive your unsigned transactions and signature requests. $1" - }, "openSeaNew": { "message": "OpenSea" }, + "openSeaToBlockaidBtnLabel": { + "message": "Explore Snaps" + }, + "openSeaToBlockaidDescription": { + "message": "Security alerts are no longer available on this network. Installing a Snap may improve your security." + }, + "openSeaToBlockaidTitle": { + "message": "Heads up!" + }, "operationFailed": { "message": "Operation Failed" }, - "optimismFees": { - "message": "Optimism fees" - }, "optional": { "message": "Optional" }, @@ -3403,15 +3671,20 @@ "permissionRequest": { "message": "Permission request" }, - "permissionRequestCapitalized": { - "message": "Permission request" - }, "permissionRequested": { "message": "Requested now" }, + "permissionRequestedForAccounts": { + "message": "Requested now for $1", + "description": "Permission cell status for requested permission including accounts, rendered as AvatarGroup which is $1." + }, "permissionRevoked": { "message": "Revoked in this update" }, + "permissionRevokedForAccounts": { + "message": "Revoked in this update for $1", + "description": "Permission cell status for revoked permission including accounts, rendered as AvatarGroup which is $1." + }, "permission_accessNamedSnap": { "message": "Connect to $1.", "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." @@ -3604,6 +3877,10 @@ "message": "View your public key for $1.", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a name for the derivation path, e.g., 'Ethereum accounts'." }, + "permission_walletSwitchEthereumChain": { + "message": "Switch to and use the following network", + "description": "The label for the `wallet_switchEthereumChain` permission" + }, "permission_webAssembly": { "message": "Support for WebAssembly.", "description": "The description of the `endowment:webassembly` permission." @@ -3627,11 +3904,8 @@ "permissionsPageTourTitle": { "message": "Connected sites are now permissions" }, - "permissionsTitle": { - "message": "Permissions" - }, - "permissionsTourDescription": { - "message": "Find your connected accounts and manage permissions here" + "permitSimulationDetailInfo": { + "message": "You're giving the spender permission to spend this many tokens from your account." }, "personalAddressDetected": { "message": "Personal address detected. Input the token contract address." @@ -3665,24 +3939,22 @@ "popularCustomNetworks": { "message": "Popular custom networks" }, + "popularNetworkAddToolTip": { + "message": "Some of these networks rely on third parties. The connections may be less reliable or enable third-parties to track activity. $1", + "description": "$1 is Learn more link" + }, "portfolio": { "message": "Portfolio" }, "portfolioDashboard": { "message": "Portfolio Dashboard" }, - "preferredProvider": { - "message": "Select your preferred provider" - }, "preparingSwap": { "message": "Preparing swap..." }, "prev": { "message": "Prev" }, - "pricingIsNotSupportedOnThisNetwork": { - "message": "Pricing is not supported on this network" - }, "primaryCurrencySetting": { "message": "Primary currency" }, @@ -3733,6 +4005,21 @@ "proceedWithTransaction": { "message": "I want to proceed anyway" }, + "productAnnouncements": { + "message": "Product announcements" + }, + "profileSync": { + "message": "Profile Sync" + }, + "profileSyncConfirmation": { + "message": "If you turn off profile sync, you won’t be able to receive notifications." + }, + "profileSyncDescription": { + "message": "Creates a profile that MetaMask uses to sync some settings among your devices. This is required to get notifications. $1." + }, + "profileSyncPrivacyLink": { + "message": "Learn how we protect your privacy" + }, "proposedApprovalLimit": { "message": "Proposed approval limit" }, @@ -3742,6 +4029,78 @@ "publicAddress": { "message": "Public address" }, + "pushPlatformNotificationsFundsReceivedDescription": { + "message": "You received $1 $2" + }, + "pushPlatformNotificationsFundsReceivedDescriptionDefault": { + "message": "You received some tokens" + }, + "pushPlatformNotificationsFundsReceivedTitle": { + "message": "Funds received" + }, + "pushPlatformNotificationsFundsSentDescription": { + "message": "You successfully sent $1 $2" + }, + "pushPlatformNotificationsFundsSentDescriptionDefault": { + "message": "You successfully sent some tokens" + }, + "pushPlatformNotificationsFundsSentTitle": { + "message": "Funds sent" + }, + "pushPlatformNotificationsNftReceivedDescription": { + "message": "You received new NFTs" + }, + "pushPlatformNotificationsNftReceivedTitle": { + "message": "NFT received" + }, + "pushPlatformNotificationsNftSentDescription": { + "message": "You have successfully sent an NFT" + }, + "pushPlatformNotificationsNftSentTitle": { + "message": "NFT sent" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedDescription": { + "message": "Your Lido stake was successful" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedTitle": { + "message": "Stake complete" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnDescription": { + "message": "Your Lido stake is now ready to be withdrawn" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnTitle": { + "message": "Stake ready for withdrawal" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedDescription": { + "message": "Your Lido withdrawal was successful" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedTitle": { + "message": "Withdrawal completed" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedDescription": { + "message": "Your Lido withdrawal request was submitted" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedTitle": { + "message": "Withdrawal requested" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedDescription": { + "message": "Your RocketPool stake was successful" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedTitle": { + "message": "Stake complete" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedDescription": { + "message": "Your RocketPool unstake was successful" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedTitle": { + "message": "Unstake complete" + }, + "pushPlatformNotificationsSwapCompletedDescription": { + "message": "Your MetaMask Swap was successful" + }, + "pushPlatformNotificationsSwapCompletedTitle": { + "message": "Swap completed" + }, "queued": { "message": "Queued" }, @@ -3760,6 +4119,9 @@ "receive": { "message": "Receive" }, + "receiveTokensCamelCase": { + "message": "Receive tokens" + }, "recipientAddressPlaceholder": { "message": "Enter public address (0x) or ENS name" }, @@ -3793,6 +4155,12 @@ "recoveryPhraseReminderTitle": { "message": "Protect your funds" }, + "redesignedConfirmationsEnabledToggle": { + "message": "Improved signature requests" + }, + "redesignedConfirmationsToggleDescription": { + "message": "Turn this on to see signature requests in an enhanced format." + }, "refreshList": { "message": "Refresh list" }, @@ -3844,6 +4212,9 @@ "removeNFT": { "message": "Remove NFT" }, + "removeNftErrorMessage": { + "message": "We could not remove this NFT." + }, "removeNftMessage": { "message": "NFT was successfully removed!" }, @@ -3881,6 +4252,9 @@ "requestFromInfo": { "message": "This is the site asking for your signature." }, + "requestFromTransactionDescription": { + "message": "This is the site asking for your confirmation." + }, "requestMayNotBeSafe": { "message": "Request may not be safe" }, @@ -3902,6 +4276,9 @@ "reset": { "message": "Reset" }, + "resetStates": { + "message": "Reset States" + }, "resetWallet": { "message": "Reset wallet" }, @@ -3990,6 +4367,9 @@ "revealTheSeedPhrase": { "message": "Reveal seed phrase" }, + "reviewAlerts": { + "message": "Review alerts" + }, "revokeAllTokensTitle": { "message": "Revoke permission to access and transfer all of your $1?", "description": "$1 is the symbol of the token for which the user is revoking approval" @@ -4040,8 +4420,8 @@ "searchAccounts": { "message": "Search accounts" }, - "searchTokenOrNFT": { - "message": "Search token or NFT" + "searchNfts": { + "message": "Search NFTs" }, "searchTokens": { "message": "Search tokens" @@ -4062,7 +4442,8 @@ "message": "Security alerts" }, "securityAlertsDescription": { - "message": "This feature alerts you to malicious activity by actively reviewing transaction and signature requests. Always do your own due diligence before approving any requests. There's no guarantee that this feature will detect all malicious activity. By enabling this feature you agree to the provider's terms of use." + "message": "This feature alerts you to malicious activity by actively reviewing transaction and signature requests. $1", + "description": "Link to learn more about security alerts" }, "securityAndPrivacy": { "message": "Security & privacy" @@ -4131,9 +4512,6 @@ "select": { "message": "Select" }, - "selectAToken": { - "message": "Select a token" - }, "selectAccounts": { "message": "Select the account(s) to use on this site" }, @@ -4165,7 +4543,7 @@ "message": "Select token" }, "selectNFTPrivacyPreference": { - "message": "Turn on NFT detection in Settings" + "message": "Enable NFT Autodetection" }, "selectPathHelp": { "message": "If you don't see the accounts you expect, try switching the HD path or current selected network." @@ -4195,15 +4573,25 @@ "sendNoContactsTitle": { "message": "You don't have any contacts yet" }, + "sendSelectReceiveAsset": { + "message": "Select asset to receive" + }, + "sendSelectSendAsset": { + "message": "Select asset to send" + }, "sendSpecifiedTokens": { "message": "Send $1", "description": "Symbol of the specified token" }, - "sendTo": { - "message": "Send to" + "sendSwapSubmissionWarning": { + "message": "Clicking this button will immediately initiate your swap transaction. Please review your transaction details before proceeding." }, - "sendTokens": { - "message": "Send tokens" + "sendTokenAsToken": { + "message": "Send $1 as $2", + "description": "Used in the transaction display list to describe a swap and send. $1 and $2 are the symbols of tokens in involved in the swap." + }, + "sendingAsset": { + "message": "Sending $1" }, "sendingDisabled": { "message": "Sending of ERC-1155 NFT assets is not yet supported." @@ -4222,6 +4610,9 @@ "sepolia": { "message": "Sepolia test network" }, + "serviceWorkerKeepAlive": { + "message": "Service Worker Keep Alive" + }, "setAdvancedPrivacySettingsDetails": { "message": "MetaMask uses these trusted third-party services to enhance product usability and safety." }, @@ -4320,14 +4711,63 @@ "signing": { "message": "Signing" }, + "signingInWith": { + "message": "Signing in with" + }, + "simulationDetailsFailed": { + "message": "There was an error loading your estimation." + }, + "simulationDetailsFiatNotAvailable": { + "message": "Not Available" + }, + "simulationDetailsIncomingHeading": { + "message": "You receive" + }, + "simulationDetailsNoBalanceChanges": { + "message": "No changes predicted for your wallet" + }, + "simulationDetailsOutgoingHeading": { + "message": "You send" + }, + "simulationDetailsTitle": { + "message": "Estimated changes" + }, + "simulationDetailsTitleTooltip": { + "message": "Estimated changes are what might happen if you go through with this transaction. This is just a prediction, not a guarantee." + }, + "simulationDetailsTotalFiat": { + "message": "Total = $1", + "description": "$1 is the total amount in fiat currency on one side of the transaction" + }, + "simulationDetailsTransactionReverted": { + "message": "This transaction is likely to fail" + }, "simulationErrorMessageV2": { "message": "We were not able to estimate gas. There might be an error in the contract and this transaction may fail." }, - "siteConnections": { - "message": "Site Connections" + "simulationsSettingDescription": { + "message": "Turn this on to estimate balance changes of transactions before you confirm them. This doesn't guarantee the final outcome of your transactions. $1" + }, + "simulationsSettingSubHeader": { + "message": "Estimate balance changes" + }, + "siweIssued": { + "message": "Issued" + }, + "siweNetwork": { + "message": "Network" + }, + "siweRequestId": { + "message": "Request ID" + }, + "siweResources": { + "message": "Resources" }, - "sites": { - "message": "Sites" + "siweSignatureSimulationDetailInfo": { + "message": "You’re signing into a site and there are no predicted changes to your account." + }, + "siweURI": { + "message": "URL" }, "skip": { "message": "Skip" @@ -4341,28 +4781,58 @@ "smartContracts": { "message": "Smart contracts" }, - "smartSwaps": { - "message": "Smart Swaps" - }, - "smartSwapsAreHere": { - "message": "Smart Swaps are here!" - }, - "smartSwapsDescription": { - "message": "MetaMask Swaps just got a whole lot smarter! Enabling Smart Swaps will allow MetaMask to programmatically optimize your Swap to help:" - }, - "smartSwapsDescription2": { - "message": "*Smart Swaps will submit your transaction privately. You can opt-out in advanced settings at any time. To learn more about Smart Swaps, read our $1.", - "description": "$1 is an external link to FAQ and Risk Disclosures" - }, "smartSwapsErrorNotEnoughFunds": { "message": "Not enough funds for a smart swap." }, "smartSwapsErrorUnavailable": { "message": "Smart Swaps are temporarily unavailable." }, - "smartSwapsTooltip": { - "message": "Simulate transactions before submitting to decrease transaction costs and reduce failures. To learn more, read our $1", - "description": "$1 is an external link to FAQ and Risk Disclosures" + "smartTransactionCancelled": { + "message": "Your transaction was canceled" + }, + "smartTransactionCancelledDescription": { + "message": "Your transaction couldn't be completed, so it was canceled to save you from paying unnecessary gas fees." + }, + "smartTransactionError": { + "message": "Your transaction failed" + }, + "smartTransactionErrorDescription": { + "message": "Sudden market changes can cause failures. If the problem continues, reach out to MetaMask customer support." + }, + "smartTransactionPending": { + "message": "Submitting your transaction" + }, + "smartTransactionSuccess": { + "message": "Your transaction is complete" + }, + "smartTransactionTakingTooLong": { + "message": "Sorry for the wait" + }, + "smartTransactionTakingTooLongDescription": { + "message": "If your transaction is not finalized within $1, it will be canceled and you will not be charged for gas.", + "description": "$1 is remaining time in seconds" + }, + "smartTransactions": { + "message": "Smart Transactions" + }, + "smartTransactionsBenefit1": { + "message": "99.5% success rate" + }, + "smartTransactionsBenefit2": { + "message": "Saves you money" + }, + "smartTransactionsBenefit3": { + "message": "Real-time updates" + }, + "smartTransactionsDescription": { + "message": "Unlock higher success rates, frontrunning protection, and better visibility with Smart Transactions." + }, + "smartTransactionsDescription2": { + "message": "Only available on Ethereum. Enable or disable any time in settings. $1", + "description": "$1 is an external link to learn more about Smart Transactions" + }, + "smartTransactionsOptItModalTitle": { + "message": "Enhanced Transaction Protection" }, "snapAccountCreated": { "message": "Account created" @@ -4402,13 +4872,18 @@ "snapAccountsDescription": { "message": "Accounts controlled by third-party Snaps." }, + "snapConnectTo": { + "message": "Connect to $1", + "description": "$1 is the website URL or a Snap name. Used for Snaps pre-approved connections." + }, + "snapConnectionPermissionDescription": { + "message": "Let $1 automatically connect to $2 without your approval.", + "description": "Used for Snap pre-approved connections. $1 is the Snap name, $2 is a website URL." + }, "snapConnectionWarning": { - "message": "$1 wants to connect to $2. Only continue if you trust this website.", + "message": "$1 wants to use $2", "description": "$2 is the snap and $1 is the dapp requesting connection to the snap." }, - "snapConnections": { - "message": "Snap Connections" - }, "snapContent": { "message": "This content is coming from $1", "description": "This is shown when a snap shows transaction insight information in the confirmation UI. $1 is a link to the snap's settings page with the link text being the name of the snap." @@ -4417,7 +4892,7 @@ "message": "Website" }, "snapInstallRequest": { - "message": "Installing $1 gives it the following permissions. Only continue if you trust $1.", + "message": "Installing $1 gives it the following permissions.", "description": "$1 is the snap name." }, "snapInstallSuccess": { @@ -4479,8 +4954,8 @@ "description": "Error title used when snap update fails." }, "snapUpdateRequest": { - "message": "Updating $1 to $2 gives it the following permissions. Only continue if you trust $1.", - "description": "$1 is the snap name and $2 is the snap version." + "message": "Updating $1 gives it the following permissions.", + "description": "$1 is the Snap name." }, "snapUpdateSuccess": { "message": "Update complete" @@ -4494,9 +4969,6 @@ "snapsConnected": { "message": "Snaps connected" }, - "snapsInvalidUIError": { - "message": "The UI specified by the snap is invalid." - }, "snapsNoInsight": { "message": "The snap didn't return any insight" }, @@ -4575,6 +5047,9 @@ "spendLimitTooLarge": { "message": "Spend limit too large" }, + "spender": { + "message": "Spender" + }, "spendingCap": { "message": "Spending cap" }, @@ -4675,6 +5150,14 @@ "stake": { "message": "Stake" }, + "startYourJourney": { + "message": "Start your journey with $1", + "description": "$1 is the token symbol" + }, + "startYourJourneyDescription": { + "message": "Get started with web3 by adding some $1 to your wallet.", + "description": "$1 is the token symbol" + }, "stateLogError": { "message": "Error in retrieving state logs." }, @@ -4687,6 +5170,9 @@ "stateLogsDescription": { "message": "State logs contain your public account addresses and sent transactions." }, + "states": { + "message": "States" + }, "status": { "message": "Status" }, @@ -4730,18 +5216,6 @@ "strong": { "message": "Strong" }, - "stxBenefit1": { - "message": "Minimize transaction costs" - }, - "stxBenefit2": { - "message": "Reduce transaction failures" - }, - "stxBenefit3": { - "message": "Eliminate stuck transactions" - }, - "stxBenefit4": { - "message": "Prevent front-running" - }, "stxCancelled": { "message": "Swap would have failed" }, @@ -4751,6 +5225,10 @@ "stxCancelledSubDescription": { "message": "Try your swap again. We’ll be here to protect you against similar risks next time." }, + "stxEstimatedCompletion": { + "message": "Estimated completion in < $1", + "description": "$1 is remeaning time in minutes and seconds, e.g. 0:10" + }, "stxFailure": { "message": "Swap failed" }, @@ -4758,6 +5236,9 @@ "message": "Sudden market changes can cause failures. If the problem persists, please reach out to $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInDescription": { + "message": "Turn on Smart Transactions for more reliable and secure transactions on Ethereum Mainnet. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Privately submitting your Swap..." }, @@ -4796,8 +5277,12 @@ "submitted": { "message": "Submitted" }, - "suggestedBy": { - "message": "Suggested by" + "suggestedBySnap": { + "message": "Suggested by $1", + "description": "$1 is the snap name" + }, + "suggestedTokenName": { + "message": "Suggested name:" }, "suggestedTokenSymbol": { "message": "Suggested ticker symbol:" @@ -4833,6 +5318,9 @@ "swapAmountReceivedInfo": { "message": "This is the minimum amount you will receive. You may receive more depending on slippage." }, + "swapAndSend": { + "message": "Swap & Send" + }, "swapAnyway": { "message": "Swap anyway" }, @@ -4910,7 +5398,7 @@ "description": "A count of possible quotes shown to the user while they are waiting for quotes to be fetched. $1 is the number of quotes already loaded, and $2 is the total number of resources that we check for quotes. Keep in mind that not all resources will have a quote for a particular swap." }, "swapFetchingQuotes": { - "message": "Fetching quotes" + "message": "Fetching quotes..." }, "swapFetchingQuotesErrorDescription": { "message": "Hmmm... something went wrong. Try again, or if errors persist, contact customer support." @@ -4948,6 +5436,10 @@ "message": "Includes a $1% MetaMask fee.", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." }, + "swapIncludesMMFeeAlt": { + "message": "Quote reflects $1% MetaMask fee", + "description": "Provides information about the fee that metamask takes for swaps using the latest copy. $1 is a decimal number." + }, "swapIncludesMetaMaskFeeViewAllQuotes": { "message": "Includes a $1% MetaMask fee – $2", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number and $2 is a link to view all quotes." @@ -5246,14 +5738,15 @@ "switchToThisAccount": { "message": "Switch to this account" }, - "switchedTo": { - "message": "You have switched to" + "switchedNetworkToastDecline": { + "message": "Don't show again" }, - "switcherTitle": { - "message": "Network switcher" + "switchedNetworkToastMessage": { + "message": "$1 is now active on $2", + "description": "$1 represents the account name, $2 represents the network name" }, - "switcherTourDescription": { - "message": "Click the icon to switch networks or add a new network" + "switchedTo": { + "message": "You're now using" }, "switchingNetworksCancelsPendingConfirmations": { "message": "Switching networks will cancel all pending confirmations" @@ -5292,7 +5785,7 @@ "message": "Choose your preferred MetaMask theme." }, "thingsToKeep": { - "message": "Things to keep in mind:" + "message": "Keep in mind:" }, "thirdPartySoftware": { "message": "Third-party software notice", @@ -5409,7 +5902,7 @@ "message": "token scams and security risks" }, "tokenShowUp": { - "message": "Your tokens may not automatically show up in your wallet." + "message": "Your tokens may not automatically show up in your wallet. " }, "tokenSymbol": { "message": "Token symbol" @@ -5577,6 +6070,39 @@ "tryAgain": { "message": "Try again" }, + "turnOff": { + "message": "Turn off" + }, + "turnOffMetamaskNotificationsError": { + "message": "There was an error in disabling the notifications. Please try again later." + }, + "turnOn": { + "message": "Turn on" + }, + "turnOnMetamaskNotifications": { + "message": "Turn on notifications" + }, + "turnOnMetamaskNotificationsButton": { + "message": "Turn on" + }, + "turnOnMetamaskNotificationsError": { + "message": "There was an error in creating the notifications. Please try again later." + }, + "turnOnMetamaskNotificationsMessageFirst": { + "message": "Stay in the loop on what's happening in your wallet with notifications." + }, + "turnOnMetamaskNotificationsMessagePrivacyBold": { + "message": "Settings > Notifications." + }, + "turnOnMetamaskNotificationsMessagePrivacyLink": { + "message": "Learn how we protect your privacy while using this feature." + }, + "turnOnMetamaskNotificationsMessageSecond": { + "message": "To use wallet notifications, we use a profile to sync some settings across your devices. $1" + }, + "turnOnMetamaskNotificationsMessageThird": { + "message": "You can turn off notifications at any time in $1" + }, "turnOnTokenDetection": { "message": "Turn on enhanced token detection" }, @@ -5722,6 +6248,9 @@ "view": { "message": "View" }, + "viewActivity": { + "message": "View activity" + }, "viewAllDetails": { "message": "View all details" }, @@ -5745,7 +6274,7 @@ }, "viewOnCustomBlockExplorer": { "message": "View $1 at $2", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "View $1 on Etherscan", @@ -5757,6 +6286,9 @@ "viewOnOpensea": { "message": "View on Opensea" }, + "viewTransaction": { + "message": "View transaction" + }, "viewinCustodianApp": { "message": "View in custodian app" }, @@ -5816,6 +6348,9 @@ "weak": { "message": "Weak" }, + "web3": { + "message": "Web3" + }, "web3ShimUsageNotification": { "message": "We noticed that the current website tried to use the removed window.web3 API. If the site appears to be broken, please click $1 for more information.", "description": "$1 is a clickable link." @@ -5856,9 +6391,8 @@ "whatsThis": { "message": "What's this?" }, - "xOfY": { - "message": "$1 of $2", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" + "wrongNetworkName": { + "message": "According to our records, the network name may not correctly match this chain ID." }, "xOfYPending": { "message": "$1 of $2 pending", @@ -5867,6 +6401,9 @@ "yes": { "message": "Yes" }, + "you": { + "message": "You" + }, "youHaveAddedAll": { "message": "You've added all the popular networks. You can discover more networks $1 Or you can $2", "description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'" diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index b53d55eff620..f49efdbc7218 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -130,12 +130,21 @@ "account": { "message": "Cuenta" }, + "accountActivity": { + "message": "Actividad de la cuenta" + }, + "accountActivityText": { + "message": "Seleccione las cuentas sobre las que desea recibir notificaciones:" + }, "accountDetails": { "message": "Detalles de la cuenta" }, "accountIdenticon": { "message": "Identicon de cuenta" }, + "accountIsntConnectedToastText": { + "message": "$1 no está conectado a $2" + }, "accountName": { "message": "Nombre de la cuenta" }, @@ -153,6 +162,12 @@ "accountSelectionRequired": { "message": "Debe seleccionar una cuenta." }, + "accounts": { + "message": "Cuentas" + }, + "accountsConnected": { + "message": "Cuentas conectadas" + }, "active": { "message": "Activo" }, @@ -243,6 +258,9 @@ "addIPFSGateway": { "message": "Agregue su puerta de enlace de IPFS preferida" }, + "addImportAccount": { + "message": "Añadir una cuenta o un monedero físico" + }, "addMemo": { "message": "Añadir memo" }, @@ -256,6 +274,9 @@ "message": "Esta conexión de red depende de terceros. Y puede ser menos confiable o permite que terceros rastreen la actividad. $1", "description": "$1 is Learn more link" }, + "addNewAccount": { + "message": "Añadir una cuenta nueva" + }, "addNewToken": { "message": "Agregar nuevo token" }, @@ -265,6 +286,12 @@ "addNfts": { "message": "Añadir NFT" }, + "addSnapAccountToggle": { + "message": "Activar \"Añadir una cuenta Snap (Beta)\"" + }, + "addSnapAccountsDescription": { + "message": "Activar esta función le dará la opción de agregar los nuevos Snaps de la cuenta Beta directamente desde su lista de cuentas. Si instala una cuenta Snap, recuerde que es un servicio de terceros." + }, "addSuggestedNFTs": { "message": "Añadir NFT sugeridos" }, @@ -281,6 +308,9 @@ "addingCustomNetwork": { "message": "Agregando red" }, + "addingTokens": { + "message": "Agregando tokens" + }, "address": { "message": "Dirección" }, @@ -316,9 +346,27 @@ "airgapVault": { "message": "Bóveda AirGap" }, + "alert": { + "message": "Alerta" + }, + "alertBannerMultipleAlertsDescription": { + "message": "Si aprueba esta solicitud, un tercero conocido por estafas podría quedarse con todos sus activos." + }, + "alertBannerMultipleAlertsTitle": { + "message": "¡Alertas múltiples!" + }, "alertDisableTooltip": { "message": "Esto se puede modificar en \"Configuración > Alertas\"" }, + "alertModalAcknowledge": { + "message": "Soy consciente del riesgo y aun así deseo continuar" + }, + "alertModalDetails": { + "message": "Detalles de la alerta" + }, + "alertModalReviewAllAlerts": { + "message": "Revisar todas las alertas" + }, "alertSettingsUnconnectedAccount": { "message": "Explorando un sitio web con una cuenta no conectada seleccionada" }, @@ -334,6 +382,9 @@ "alerts": { "message": "Alertas" }, + "all": { + "message": "Todo" + }, "allCustodianAccountsConnectedSubtitle": { "message": "Ya ha conectado todas sus cuentas custodiadas o no tiene ninguna cuenta para conectarse a MetaMask Institutional." }, @@ -344,23 +395,26 @@ "message": "Todo su $1", "description": "$1 is the symbol or name of the token that the user is approving spending" }, + "allPermissions": { + "message": "Todos los permisos" + }, "allYourNFTsOf": { "message": "Todos sus NFT de $1", "description": "$1 is a link to contract on the block explorer when we're not able to retrieve a erc721 or erc1155 name" }, - "allowExternalExtensionTo": { - "message": "Permitir que esta extensión externa haga lo siguiente:" + "allow": { + "message": "Permitir" + }, + "allowMmiToConnectToCustodian": { + "message": "Esto permitirá que MMI se conecte a $1 para importar sus cuentas." + }, + "allowNotifications": { + "message": "Permitir notificaciones" }, "allowSpendToken": { "message": "¿Dar permiso para acceder a su $1?", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "Permitir que este sitio haga lo siguiente:" - }, - "allowThisSnapTo": { - "message": "Permitir que este snap haga:" - }, "allowWithdrawAndSpend": { "message": "Permitir que se retire $1 y gastar hasta el siguiente importe:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -368,6 +422,23 @@ "amount": { "message": "Importe" }, + "amountReceived": { + "message": "Monto recibido" + }, + "amountSent": { + "message": "Monto enviado" + }, + "andForListItems": { + "message": "$1, y $2", + "description": "$1 is the first item, $2 is the last item in a list of items. Used in Snap Install Warning modal." + }, + "andForTwoItems": { + "message": "$1 y $2", + "description": "$1 is the first item, $2 is the second item. Used in Snap Install Warning modal." + }, + "announcements": { + "message": "Anuncios" + }, "appDescription": { "message": "Un monedero de Ethereum en el explorador", "description": "The description of the application" @@ -402,6 +473,10 @@ "approveButtonText": { "message": "Aprobar" }, + "approveIncreaseAllowance": { + "message": "Aumentar el límite de gasto de $1", + "description": "The token symbol that is being approved" + }, "approveSpendingCap": { "message": "Aprobar límite de gasto $1", "description": "The token symbol that is being approved" @@ -427,6 +502,10 @@ "message": "Aprobado el $1", "description": "$1 is the approval date for a permission" }, + "approvedOnForAccounts": { + "message": "Aprobado el $1 por $2", + "description": "$1 is the approval date for a permission. $2 is the AvatarGroup component displaying account images." + }, "areYouSure": { "message": "¿Está seguro?" }, @@ -439,6 +518,12 @@ "attemptSendingAssets": { "message": "Si intenta enviar activos directamente de una red a otra, esto puede provocar la pérdida permanente de activos. Asegúrese de utilizar un puente." }, + "attemptSendingAssetsWithPortfolio": { + "message": "Puede perder sus activos si intenta enviarlos desde otra red. Transfiera fondos de forma segura entre redes usando un puente, como $1" + }, + "attemptToCancelSwapForFree": { + "message": "Intente cancelar el intercambio de forma gratuita" + }, "attemptingConnect": { "message": "Intentando una conexión a la cadena de bloques." }, @@ -479,14 +564,17 @@ "backupApprovalNotice": { "message": "Cree una copia de seguridad de su frase secreta de recuperación para mantener protegidos sus fondos y su monedero." }, + "backupKeyringSnapReminder": { + "message": "Asegúrese de poder acceder a cualquier cuenta creada por este Snap por si mismo antes de eliminarlo" + }, "backupNow": { - "message": "Crear copia de seguridad ahora" + "message": "Respaldar ahora" }, "backupUserData": { "message": "Respalde sus datos" }, "backupUserDataDescription": { - "message": "Puede respaldar la configuración del usuario que contiene preferencias y direcciones de cuenta en un archivo JSON." + "message": "Puede hacer una copia de seguridad de datos tal y como sus contactos y preferencias." }, "balance": { "message": "Saldo" @@ -500,6 +588,30 @@ "basic": { "message": "Básico" }, + "basicConfigurationBannerCTA": { + "message": "Activar la funcionalidad básica" + }, + "basicConfigurationBannerTitle": { + "message": "La funcionalidad básica está desactivada" + }, + "basicConfigurationLabel": { + "message": "Funcionalidad básica" + }, + "basicConfigurationModalCheckbox": { + "message": "Entiendo y deseo continuar" + }, + "basicConfigurationModalDisclaimerOff": { + "message": "Esto significa que no optimizará completamente su tiempo en MetaMask. Las funciones básicas (como los detalles de los tokens, la configuración óptima de gas y otras) no estarán disponibles para usted." + }, + "basicConfigurationModalDisclaimerOn": { + "message": "Para optimizar su tiempo en MetaMask, tendrá que activar esta función. Las funciones básicas (como los detalles de los tokens, la configuración óptima de gas y otras) son importantes para la experiencia Web3." + }, + "basicConfigurationModalHeadingOff": { + "message": "Desactivar la funcionalidad básica" + }, + "basicConfigurationModalHeadingOn": { + "message": "Activar la funcionalidad básica" + }, "beCareful": { "message": "Sea cuidadoso" }, @@ -571,6 +683,9 @@ "blockaidDescriptionTransferFarming": { "message": "Si aprueba esta solicitud, un tercero conocido por estafas tomará todos sus activos." }, + "blockaidMessage": { + "message": "Preservación de la privacidad: no se comparten datos con terceros. Disponible en Arbitrum, Avalanche, BNB Chain, la red principal de Ethereum, Linea, Optimism, Polygon, Base y Sepolia." + }, "blockaidTitleDeceptive": { "message": "Esta es una solicitud engañosa" }, @@ -586,6 +701,9 @@ "bridge": { "message": "Puente" }, + "bridgeDontSend": { + "message": "Puente, no enviar" + }, "browserNotSupported": { "message": "Su explorador no es compatible..." }, @@ -598,6 +716,9 @@ "busy": { "message": "Ocupado" }, + "buyAndSell": { + "message": "Comprar y vender" + }, "buyAsset": { "message": "Comprar $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -609,6 +730,10 @@ "buyNow": { "message": "Comprar ahora" }, + "buyToken": { + "message": "Comprar $1", + "description": "$1 is the token symbol" + }, "bytes": { "message": "Bytes" }, @@ -618,9 +743,6 @@ "cancel": { "message": "Cancelar" }, - "cancelEdit": { - "message": "Cancelar Editar" - }, "cancelPopoverTitle": { "message": "Cancelar transacción" }, @@ -647,6 +769,9 @@ "chainIdExistsErrorMsg": { "message": "En este momento, la red $1 está utilizando este identificador de cadena." }, + "chainListReturnedDifferentTickerSymbol": { + "message": "Este símbolo de token no coincide con el nombre de la red o el ID de cadena ingresados. Muchos tokens populares usan símbolos similares, que los estafadores pueden usar para engañarlo y enviarles a cambio un token más valioso. Verifique todo antes de continuar." + }, "chooseYourNetwork": { "message": "Elija su red" }, @@ -682,9 +807,19 @@ "close": { "message": "Cerrar" }, + "closeExtension": { + "message": "Cerrar extensión" + }, + "closeWindowAnytime": { + "message": "Puede cerrar esta ventana en cualquier momento." + }, "coingecko": { "message": "CoinGecko" }, + "comboNoOptions": { + "message": "No se encontraron opciones", + "description": "Default text shown in the combo field dropdown if no options." + }, "configureSnapPopupDescription": { "message": "Ahora está saliendo de MetaMask para configurar este snap." }, @@ -703,12 +838,42 @@ "confirm": { "message": "Confirmar" }, + "confirmAlertModalAcknowledge": { + "message": "Soy consciente de las alertas y aun así deseo continuar" + }, + "confirmAlertModalDetails": { + "message": "Si inicia sesión, un tercero conocido por estafas podría quedarse con todos sus activos. Revise las alertas antes de continuar." + }, + "confirmAlertModalTitle": { + "message": "Sus activos podrían estar en riesgo" + }, + "confirmConnectCustodianRedirect": { + "message": "Lo redirigiremos a $1 al hacer clic en continuar." + }, + "confirmConnectCustodianText": { + "message": "Para conectar sus cuentas, inicie sesión en su cuenta de $1 y haga clic en el botón 'conectar a MMI'." + }, + "confirmConnectionTitle": { + "message": "Confirmar conexión a $1" + }, "confirmPassword": { "message": "Confirmar contraseña" }, "confirmRecoveryPhrase": { "message": "Confirmar frase secreta de recuperación" }, + "confirmTitleDescContractInteractionTransaction": { + "message": "Solo confirme esta transacción si entiende completamente el contenido y confía en el sitio solicitante." + }, + "confirmTitleDescSignature": { + "message": "Solo confirme este mensaje si aprueba el contenido y confía en el sitio solicitante." + }, + "confirmTitleSignature": { + "message": "Solicitud de firma" + }, + "confirmTitleTransaction": { + "message": "Solicitud de transacción" + }, "confirmed": { "message": "Confirmado" }, @@ -724,9 +889,15 @@ "connect": { "message": "Conectar" }, + "connectAccount": { + "message": "Conectar cuenta" + }, "connectAccountOrCreate": { "message": "Conectar cuenta o crear nueva" }, + "connectAccounts": { + "message": "Conectar cuentas" + }, "connectCustodialAccountMenu": { "message": "Conectar cuenta custodiada" }, @@ -736,36 +907,25 @@ "connectCustodialAccountTitle": { "message": "Cuentas custodiadas" }, + "connectCustodianAccounts": { + "message": "Conectar a cuentas de $1" + }, "connectManually": { "message": "Conectarse manualmente al sitio actual" }, + "connectMoreAccounts": { + "message": "Conectar más cuentas" + }, "connectSnap": { "message": "Conectar $1", "description": "$1 is the snap for which a connection is being requested." }, - "connectTo": { - "message": "Conectarse a $1", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "Conectarse a todas sus $1", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "cuentas", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "Conectarse a $1", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1 cuentas", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "Conectarse con MetaMask" }, + "connectedAccounts": { + "message": "Cuentas conectadas" + }, "connectedAccountsDescriptionPlural": { "message": "Tiene $1 cuentas conectadas a este sitio.", "description": "$1 is the number of accounts" @@ -776,6 +936,13 @@ "connectedAccountsEmptyDescription": { "message": "MetaMask no está conectado a este sitio. Para conectarse a un sitio de Web3, busque el botón de conexión en su sitio." }, + "connectedAccountsListTooltip": { + "message": "$1 puede ver el saldo de la cuenta, la dirección, la actividad y sugerir transacciones para aprobar para las cuentas conectadas.", + "description": "$1 is the origin name" + }, + "connectedAccountsToast": { + "message": "Se actualizaron las cuentas conectadas" + }, "connectedSites": { "message": "Sitios conectados" }, @@ -787,12 +954,21 @@ "message": "$1 no está conectado a ningún sitio.", "description": "$1 is the account name" }, + "connectedSnapAndNoAccountDescription": { + "message": "MetaMask está conectado a este sitio, pero aún no hay cuentas conectadas" + }, + "connectedWith": { + "message": "Conectado con" + }, "connecting": { "message": "Estableciendo conexión…" }, "connectingTo": { "message": "Estableciendo conexión a $1" }, + "connectingToDeprecatedNetwork": { + "message": "'$1' se está eliminando gradualmente y es posible que no funcione. Pruebe con otra red." + }, "connectingToGoerli": { "message": "Estableciendo conexión a la red de prueba Goerli" }, @@ -802,6 +978,9 @@ "connectingToLineaMainnet": { "message": "Estableciendo conexión a la red principal de Linea" }, + "connectingToLineaSepolia": { + "message": "Estableciendo conexión a la red de prueba Linea Sepolia" + }, "connectingToMainnet": { "message": "Estableciendo conexión a la red principal de Ethereum" }, @@ -831,6 +1010,12 @@ "continue": { "message": "Continuar" }, + "continueMmiOnboarding": { + "message": "Continuar con la incorporación de MetaMask Institutional" + }, + "continueToWallet": { + "message": "Continuar al monedero" + }, "contract": { "message": "Contrato" }, @@ -882,6 +1067,9 @@ "copyAddress": { "message": "Copiar dirección al Portapapeles" }, + "copyPrivateKey": { + "message": "Copiar clave privada" + }, "copyRawTransactionData": { "message": "Copiar los datos de las transacciones en bruto" }, @@ -900,6 +1088,15 @@ "createPassword": { "message": "Crear contraseña" }, + "createSnapAccountDescription": { + "message": "$1 quiere agregar una nueva cuenta a MetaMask." + }, + "createSnapAccountTitle": { + "message": "Crear cuenta" + }, + "crossChainSwapsLink": { + "message": "Intercambie entre redes con MetaMask Portfolio" + }, "cryptoCompare": { "message": "CryptoCompare" }, @@ -950,10 +1147,16 @@ "message": "Custodio" }, "custodianAccountAddedDesc": { - "message": "Ahora ya puede usar sus cuentas custodiadas en MetaMask Institutional." + "message": "Ahora puede utilizar sus cuentas en MetaMask Institutional." }, "custodianAccountAddedTitle": { - "message": "Se agregaron cuentas de custodia seleccionadas." + "message": "Se agregaron cuentas seleccionadas de $1." + }, + "custodianQRCodeScan": { + "message": "Escanee el código QR con su aplicación móvil $1" + }, + "custodianQRCodeScanDescription": { + "message": "O inicie sesión en su cuenta de $1 y haga clic en el botón \"Conectar a MMI\"" }, "custodianReplaceRefreshTokenChangedFailed": { "message": "Por favor, vaya a $1 y haga clic en el botón 'Conectar a MMI' dentro de su interfaz de usuario para volver a conectar sus cuentas a MMI." @@ -1017,7 +1220,7 @@ "message": "La detección de token aún no está disponible en esta red. Importe el token de forma manual y asegúrese de que confía en él. Más información sobre $1" }, "customTokenWarningInTokenDetectionNetwork": { - "message": "Antes de importar un token de forma manual, asegúrese de que confía en él. Más información acerca de $1" + "message": "Cualquiera puede crear un token, incluida la creación de versiones falsas de tokens existentes. Aprenda más sobre $1" }, "customTokenWarningInTokenDetectionNetworkWithTDOFF": { "message": "Asegúrese de confiar en un token antes de agregarlo. Aprenda cómo evitar $1. También puede habilitar la detección de tokens $2." @@ -1025,6 +1228,12 @@ "customerSupport": { "message": "atención al cliente" }, + "customizeYourNotifications": { + "message": "Personalice sus notificaciones" + }, + "customizeYourNotificationsText": { + "message": "Active los tipos de notificaciones que desea recibir:" + }, "dappRequestedSpendingCap": { "message": "Límite de gasto solicitado por el sitio" }, @@ -1108,6 +1317,18 @@ "deposit": { "message": "Depositar" }, + "deprecatedGoerliNtwrkMsg": { + "message": "Debido a las actualizaciones del sistema Ethereum, la red de prueba Goerli se eliminará pronto." + }, + "deprecatedNetwork": { + "message": "Esta red está en desuso" + }, + "deprecatedNetworkButtonMsg": { + "message": "Entendido" + }, + "deprecatedNetworkDescription": { + "message": "La red a la que está intentando conectarse ya no es compatible con Metamask. $1" + }, "description": { "message": "Descripción" }, @@ -1115,110 +1336,20 @@ "message": "Descripción de $1", "description": "$1 represents the name of the snap" }, - "desktopApp": { - "message": "App de escritorio" - }, - "desktopConnectionCriticalErrorDescription": { - "message": "Este error podría ser intermitente, así que intente reiniciar la extensión o desactive MetaMask Desktop." - }, - "desktopConnectionCriticalErrorTitle": { - "message": "MetaMask tuvo problemas al iniciar" - }, - "desktopConnectionLostErrorDescription": { - "message": "Asegúrese de tener la aplicación de escritorio en funcionamiento o deshabilite MetaMask Desktop." - }, - "desktopConnectionLostErrorTitle": { - "message": "Se perdió la conexión de MetaMask Desktop" - }, - "desktopDisableButton": { - "message": "Deshabilitar la aplicación Desktop" - }, - "desktopDisableErrorCTA": { - "message": "Deshabilitar MetaMask Desktop" - }, - "desktopEnableButton": { - "message": "Habilitar la aplicación Desktop" - }, - "desktopEnableButtonDescription": { - "message": "Haga clic para ejecutar todos los procesos en segundo plano en la aplicación de escritorio." - }, - "desktopErrorNavigateSettingsCTA": { - "message": "Volver a la página de configuración" - }, - "desktopErrorRestartMMCTA": { - "message": "Reiniciar MetaMask" - }, - "desktopNotFoundErrorCTA": { - "message": "Descargar MetaMask Desktop" - }, - "desktopNotFoundErrorDescription1": { - "message": "Asegúrese de tener la aplicación de escritorio en funcionamiento." - }, - "desktopNotFoundErrorDescription2": { - "message": "Si no tiene una aplicación de escritorio instalada, descárguela desde el sitio web de MetaMask." - }, - "desktopNotFoundErrorTitle": { - "message": "No se encontró MetaMask Desktop" - }, - "desktopOpenOrDownloadCTA": { - "message": "Abrir MetaMask Desktop" - }, - "desktopOutdatedErrorCTA": { - "message": "Actualizar MetaMask Desktop" - }, - "desktopOutdatedErrorDescription": { - "message": "Su aplicación de escritorio MetaMask debe actualizarse." - }, - "desktopOutdatedErrorTitle": { - "message": "MetaMask Desktop está desactualizada" - }, - "desktopOutdatedExtensionErrorCTA": { - "message": "Actualizar la extensión MetaMask" - }, - "desktopOutdatedExtensionErrorDescription": { - "message": "Su extensión MetaMask debe actualizarse." - }, - "desktopOutdatedExtensionErrorTitle": { - "message": "La extensión MetaMask está desactualizada" - }, - "desktopPageDescription": { - "message": "Si el emparejamiento es exitoso, la extensión se reiniciará y deberá volver a ingresar su contraseña." - }, - "desktopPageSubTitle": { - "message": "Abra su MetaMask Desktop y escriba este código" - }, - "desktopPageTitle": { - "message": "Emparejar con Desktop" - }, - "desktopPairedWarningDeepLink": { - "message": "Vaya a Configuración en MetaMask Desktop" - }, - "desktopPairedWarningDescription": { - "message": "Si desea iniciar un nuevo emparejamiento, elimine la conexión actual." - }, - "desktopPairedWarningTitle": { - "message": "MM Desktop ya está emparejada" - }, - "desktopPairingExpireMessage": { - "message": "El código caduca en $1 segundos" - }, - "desktopRouteNotFoundErrorDescription": { - "message": "desktopRouteNotFoundErrorDescription" + "details": { + "message": "Detalles" }, - "desktopRouteNotFoundErrorTitle": { - "message": "desktopRouteNotFoundErrorTitle" + "developerOptions": { + "message": "Opciones de desarrollador" }, - "desktopUnexpectedErrorCTA": { - "message": "Volver a MetaMask Inicio" + "developerOptionsResetStatesAnnouncementsDescription": { + "message": "Restablece el valor booleano isShown a falso para todos los anuncios. Los anuncios son las notificaciones que se muestran en la ventana emergente Novedades." }, - "desktopUnexpectedErrorDescription": { - "message": "Verifique su MetaMask Desktop para restaurar la conexión" + "developerOptionsResetStatesOnboarding": { + "message": "Restablece varios estados relacionados con la incorporación y redirige a la página de incorporación \"Asegure su monedero\"." }, - "desktopUnexpectedErrorTitle": { - "message": "Algo salió mal..." - }, - "details": { - "message": "Detalles" + "developerOptionsServiceWorkerKeepAlive": { + "message": "El resultado es una marca de tiempo que se guarda continuamente en session.storage" }, "disabledGasOptionToolTipMessage": { "message": "“$1” está desactivado porque no cumple el mínimo de un aumento del 10 % respecto a la tarifa de gas original.", @@ -1233,12 +1364,38 @@ "disconnectAllAccountsConfirmationDescription": { "message": "¿Está seguro de que se quiere desconectar? Podría perder la funcionalidad del sitio." }, + "disconnectAllAccountsText": { + "message": "cuentas" + }, + "disconnectAllSnapsText": { + "message": "Snaps" + }, + "disconnectAllText": { + "message": "Si desconecta su $1 de su $2, tendrá que volver a conectarlos para usarlos nuevamente.", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`, $2 represents the website hostname" + }, + "disconnectAllTitle": { + "message": "Desconectar todos/as $1", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`" + }, "disconnectPrompt": { "message": "Desconectar $1" }, "disconnectThisAccount": { "message": "Desconectar esta cuenta" }, + "disconnectedAllAccountsToast": { + "message": "Todas las cuentas desconectadas de $1", + "description": "$1 is name of the dapp`" + }, + "disconnectedSingleAccountToast": { + "message": "$1 desconectada de $2", + "description": "$1 is name of the name and $2 represents the dapp name`" + }, + "discoverSnaps": { + "message": "Descubrir Snaps", + "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." + }, "dismiss": { "message": "Ignorar" }, @@ -1248,9 +1405,21 @@ "dismissReminderField": { "message": "Ignorar el recordatorio de respaldo de la frase de recuperación" }, + "displayNftMedia": { + "message": "Mostrar medios NFT" + }, + "displayNftMediaDescription": { + "message": "Mostrar los medios y datos NFT expone su dirección IP a OpenSea u otros terceros. Esto puede permitir que los atacantes asocien su dirección IP con su dirección Ethereum. La detección automática de NFT se basa en esta configuración y no estará disponible cuando esté desactivada." + }, + "doNotShare": { + "message": "No comparta esto con nadie" + }, "domain": { "message": "Dominio" }, + "domainNotSupportedOnNetwork": { + "message": "La red no admite la búsqueda de dominios" + }, "done": { "message": "Hecho" }, @@ -1269,6 +1438,9 @@ "downloadStateLogs": { "message": "Descargar registros de estado" }, + "dragAndDropBanner": { + "message": "Puede arrastrar redes para reordenarlas. " + }, "dropped": { "message": "Abandonado" }, @@ -1367,6 +1539,9 @@ "editSpeedUpEditGasFeeModalTitle": { "message": "Editar la tarifa de aceleración de gas" }, + "enable": { + "message": "Habilitar" + }, "enableAutoDetect": { "message": " Activar autodetección" }, @@ -1397,6 +1572,18 @@ "enhancedTokenDetectionAlertMessage": { "message": "Actualmente, la detección mejorada de token se encuentra disponible en $1. $2" }, + "ensDomainsSettingDescriptionIntroduction": { + "message": "MetaMask le permite ver los dominios de ENS directamente en la barra de direcciones de su navegador. Así es como funciona:" + }, + "ensDomainsSettingDescriptionOutroduction": { + "message": "Tenga en cuenta que el uso de esta función expone su dirección IP a servicios de terceros de IPFS." + }, + "ensDomainsSettingDescriptionPart1": { + "message": "MetaMask consulta el contrato ENS de Ethereum para encontrar el código conectado al nombre de ENS." + }, + "ensDomainsSettingDescriptionPart2": { + "message": "Si el código se vincula a IPFS, puede ver el contenido asociado a él (generalmente un sitio web)." + }, "ensDomainsSettingTitle": { "message": "Mostrar dominios ENS en la barra de direcciones" }, @@ -1438,6 +1625,9 @@ "message": "Detalles del error", "description": "Title for collapsible section that displays error details for debugging purposes" }, + "errorGettingSafeChainList": { + "message": "Error al obtener la lista de cadenas seguras, por favor continúe con precaución." + }, "errorMessage": { "message": "Mensaje: $1", "description": "Displayed error message for debugging purposes. $1 is the error message" @@ -1469,6 +1659,9 @@ "message": "Error con $1", "description": "$1 represents the name of the snap" }, + "estimatedFee": { + "message": "Tarifa estimada" + }, "ethGasPriceFetchWarning": { "message": "Se muestra el precio del gas de respaldo, ya que el servicio para calcular el precio del gas principal no se encuentra disponible en este momento." }, @@ -1495,12 +1688,24 @@ "message": "Experimental" }, "extendWalletWithSnaps": { - "message": "Amplíe la experiencia de uso de su monedero.", + "message": "Explore los Snaps creados por la comunidad para personalizar su experiencia web3", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "extensionInsallCompleteDescription": { + "message": "Regrese a la incorporación del producto MetaMask Institutional para conectar sus cuentas de custodia o de autocustodia." + }, + "extensionInsallCompleteTitle": { + "message": "Instalación de extensión completa" + }, "externalExtension": { "message": "Extensión externa" }, + "externalNameSourcesSetting": { + "message": "Apodos propuestos" + }, + "externalNameSourcesSettingDescription": { + "message": "Obtendremos apodos propuestos para las direcciones con las que interactúa de fuentes de terceros como Etherscan, Infura y Lens Protocol. Estas fuentes podrán ver esas direcciones y su dirección IP. La dirección de su cuenta no estará expuesta a terceros." + }, "failed": { "message": "Con errores" }, @@ -1519,6 +1724,9 @@ "feeAssociatedRequest": { "message": "Esta solicitud tiene asociada una tarifa." }, + "feeDetails": { + "message": "Detalles de la tarifa" + }, "fiat": { "message": "Fiduciaria", "description": "Exchange type" @@ -1551,6 +1759,9 @@ "message": "Acepto los riesgos", "description": "this text is shown on a button, which the user presses to confirm they understand the risks of using Flask" }, + "floatAmountToken": { + "message": "La cantidad de tokens debe ser un número entero" + }, "followUsOnTwitter": { "message": "Síganos en Twitter" }, @@ -1573,6 +1784,9 @@ "fromTokenLists": { "message": "De las listas de tóken: $1" }, + "function": { + "message": "Función: $1" + }, "functionApprove": { "message": "Función: Aprobar" }, @@ -1582,6 +1796,13 @@ "functionType": { "message": "Tipo de función" }, + "fundYourWallet": { + "message": "Agregar fondos a su monedero" + }, + "fundYourWalletDescription": { + "message": "Comience agregando $1 a su monedero.", + "description": "$1 is the token symbol" + }, "gas": { "message": "Gas" }, @@ -1592,6 +1813,9 @@ "message": "Esta tarifa de gas ha sido sugerida por $1. Anularla puede causar un problema con su transacción. Comuníquese con $1 si tiene preguntas.", "description": "$1 represents the Dapp's origin" }, + "gasIsETH": { + "message": "El gas es $1 " + }, "gasLimit": { "message": "Límite de gas" }, @@ -1636,6 +1860,9 @@ "message": "$1 horas", "description": "$1 represents a number of hours" }, + "gasTimingLow": { + "message": "Lento" + }, "gasTimingMinutesShort": { "message": "$1 min", "description": "$1 represents a number of minutes" @@ -1650,15 +1877,29 @@ "general": { "message": "General" }, - "globalTitle": { - "message": "Menú global" + "generalCameraError": { + "message": "No hemos podido acceder a su cámara. Por favor, inténtelo de nuevo." + }, + "generalCameraErrorTitle": { + "message": "Algo salió mal..." + }, + "genericExplorerView": { + "message": "Ver cuenta en $1" + }, + "getStartedWithNFTs": { + "message": "Obtenga $1 para comprar NFT", + "description": "$1 is the token symbol" }, - "globalTourDescription": { - "message": "Vea su portafolio, sitios conectados, configuraciones y más" + "getStartedWithNFTsDescription": { + "message": "Comience con los NFT agregando $1 a su monedero.", + "description": "$1 is the token symbol" }, "goBack": { "message": "Volver" }, + "goToSite": { + "message": "Ir al sitio" + }, "goerli": { "message": "Red de prueba Goerli" }, @@ -1700,15 +1941,24 @@ "hexData": { "message": "Datos hexadecimales" }, + "hiddenAccounts": { + "message": "Cuentas ocultas" + }, "hide": { "message": "Ocultar" }, + "hideAccount": { + "message": "Ocultar cuenta" + }, "hideFullTransactionDetails": { "message": "Esconder los detalles completos de la transacción" }, "hideSeedPhrase": { "message": "Ocultar frase inicial" }, + "hideSentitiveInfo": { + "message": "Ocultar información confidencial" + }, "hideToken": { "message": "Ocultar token" }, @@ -1782,7 +2032,7 @@ "message": "mantenga presionado para revelar el círculo desbloqueado" }, "id": { - "message": "Id." + "message": "ID" }, "ignoreAll": { "message": "Ignorar todo" @@ -1790,6 +2040,9 @@ "ignoreTokenWarning": { "message": "Si oculta tokens, estos no se mostrarán en su monedero. Sin embargo, aún puede agregarlos buscándolos." }, + "imToken": { + "message": "imToken" + }, "import": { "message": "Importar", "description": "Button to import an account from a selected file" @@ -1848,6 +2101,9 @@ "importTokensCamelCase": { "message": "Importar tokens" }, + "importTokensError": { + "message": "No pudimos importar los tokens. Por favor, inténtelo de nuevo más tarde." + }, "importWithCount": { "message": "Importar $1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -1866,6 +2122,9 @@ "initialTransactionConfirmed": { "message": "La red confirmó la transacción inicial. Haga clic en Aceptar para volver." }, + "inlineAlert": { + "message": "Alerta" + }, "inputLogicEmptyState": { "message": "Ingrese solo una cantidad que esté dispuesto a gastar en el tercero ahora o en el futuro. Siempre puede aumentar el límite de gastos más adelante." }, @@ -1876,6 +2135,27 @@ "inputLogicHigherNumber": { "message": "Esto permite que el tercero gaste todo su saldo de tokens hasta que alcance el límite o usted revoque el límite de gasto. Si esta no es su intención, considere establecer un límite de gasto más bajo." }, + "insightWarning": { + "message": "advertencia" + }, + "insightWarningCheckboxMessage": { + "message": "$1 la solicitud por $2", + "description": "$1 is the action i.e. sign, confirm. $2 is the origin making the request." + }, + "insightWarningContentPlural": { + "message": "Revise $1 antes de $2. Una vez realizada, la $3 es irreversible.", + "description": "$1 the 'insightWarnings' message (2 warnings) representing warnings, $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningContentSingular": { + "message": "Revise $1 antes de $2. Una vez realizada, la $3 es irreversible.", + "description": "$1 is the 'insightWarning' message (1 warning), $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningHeader": { + "message": "Esta solicitud puede ser riesgosa" + }, + "insightWarnings": { + "message": "advertencias" + }, "insightsFromSnap": { "message": "Perspectivas de $1", "description": "$1 represents the name of the snap" @@ -1883,9 +2163,18 @@ "install": { "message": "Instalar" }, + "installExtension": { + "message": "Instalar extensión" + }, + "installExtensionDescription": { + "message": "La versión compatible con instituciones de la billetera web3 líder en el mundo, MetaMask." + }, "installOrigin": { "message": "Instalar origen" }, + "installRequest": { + "message": "Añadir a MetaMask" + }, "installedOn": { "message": "Instalado en $1", "description": "$1 is the date when the snap has been installed" @@ -1914,6 +2203,12 @@ "insufficientTokens": { "message": "Tokens insuficientes." }, + "interactingWith": { + "message": "Interactuando con" + }, + "interactingWithTransactionDescription": { + "message": "Este es el contrato con el que está interactuando. Protéjase de los estafadores verificando los detalles." + }, "invalidAddress": { "message": "Dirección no válida" }, @@ -1986,6 +2281,9 @@ "ipfsToggleModalSettings": { "message": "Configuración > Seguridad y privacidad" }, + "isSigningOrSubmitting": { + "message": "Aún se está firmando o enviando una transacción anterior" + }, "jazzAndBlockies": { "message": "Jazzicons y Blockies son dos estilos distintos de íconos únicos que pueden ayudarlo a identificar rápidamente una cuenta." }, @@ -1999,6 +2297,24 @@ "message": "Archivo JSON", "description": "format for importing an account" }, + "keyringAccountName": { + "message": "Nombre de la cuenta" + }, + "keyringAccountPublicAddress": { + "message": "Dirección pública" + }, + "keyringSnapRemovalResult1": { + "message": "$1 eliminado $2", + "description": "Displays the result after removal of a keyring snap. $1 is the snap name, $2 is whether it is successful or not" + }, + "keyringSnapRemovalResultNotSuccessful": { + "message": "no ", + "description": "Displays the `not` word in $2." + }, + "keyringSnapRemoveConfirmation": { + "message": "Ingrese $1 para confirmar que desea eliminar este snap:", + "description": "Asks user to input the name nap prior to deleting the snap. $1 is the snap name" + }, "keystone": { "message": "Keystone" }, @@ -2017,9 +2333,15 @@ "lastSold": { "message": "Última venta" }, + "lavaDomeCopyWarning": { + "message": "Por su seguridad, seleccionar este texto no está disponible en este momento." + }, "layer1Fees": { "message": "Tarifas de la capa 1" }, + "layer2Fees": { + "message": "Tarifas de la capa 2" + }, "learnCancelSpeeedup": { "message": "Aprenda cómo $1", "description": "$1 is link to cancel or speed up transactions" @@ -2037,9 +2359,21 @@ "learnMoreUpperCase": { "message": "Más información" }, + "learnMoreUpperCaseWithDot": { + "message": "Más información." + }, "learnScamRisk": { "message": "estafas y riesgos en seguridad." }, + "learnToBridge": { + "message": "Aprenda a puentear" + }, + "leaveMetaMask": { + "message": "¿Dejar MetaMask?" + }, + "leaveMetaMaskDesc": { + "message": "Está a punto de visitar un sitio fuera de MetaMask. Vuelva a verificar la URL antes de continuar." + }, "ledgerAccountRestriction": { "message": "Debe usar su última cuenta antes de poder agregar una nueva." }, @@ -2058,6 +2392,18 @@ "ledgerDeviceOpenFailureMessage": { "message": "El dispositivo Ledger no pudo abrirse. Su Ledger podría estar conectado a otro software. Cierre Ledger Live u otras aplicaciones conectadas a su dispositivo Ledger, e intente conectarse de nuevo." }, + "ledgerErrorConnectionIssue": { + "message": "Vuelva a conectar su Ledger, abra la aplicación ETH e inténtelo nuevamente." + }, + "ledgerErrorDevicedLocked": { + "message": "Su Ledger está bloqueado. Desbloquéelo y vuelve a intentarlo." + }, + "ledgerErrorEthAppNotOpen": { + "message": "Para resolver el problema, abra la aplicación ETH en su dispositivo y vuelva a intentarlo." + }, + "ledgerErrorTransactionDataNotPadded": { + "message": "Los datos de entrada de la transacción de Ethereum no están lo suficientemente completos." + }, "ledgerLiveApp": { "message": "Aplicación de Ledger Live" }, @@ -2077,6 +2423,9 @@ "lightTheme": { "message": "Claro" }, + "likeToImportToken": { + "message": "¿Le gustaría importar este token?" + }, "likeToImportTokens": { "message": "¿Le gustaría agregar estos tokens?" }, @@ -2086,6 +2435,9 @@ "lineaMainnet": { "message": "Red principal de Linea" }, + "lineaSepolia": { + "message": "Red de prueba Linea Sepolia" + }, "link": { "message": "Vínculo" }, @@ -2098,8 +2450,11 @@ "loading": { "message": "Cargando…" }, - "loadingNFTs": { - "message": "Cargando NFT..." + "loadingScreenHardwareWalletMessage": { + "message": "Por favor, complete la transacción en el monedero físico." + }, + "loadingScreenSnapMessage": { + "message": "Por favor, complete la transacción en el Snap." }, "loadingTokens": { "message": "Cargando tokens..." @@ -2146,6 +2501,9 @@ "message": "Asegúrese de que nadie esté mirando", "description": "Warning to users to be care while creating and saving their new Secret Recovery Phrase" }, + "manageInSettings": { + "message": "Administrar en configuración" + }, "max": { "message": "Máx." }, @@ -2180,15 +2538,34 @@ "metaMaskConnectStatusParagraphTwo": { "message": "El botón de estado de la conexión muestra si el sitio web que visita está conectado a la cuenta seleccionada actualmente." }, + "metadataModalSourceTooltip": { + "message": "$1 está alojado en npm y $2 es el identificador único de este Snap.", + "description": "$1 is the snap name and $2 is the snap NPM id." + }, "metamaskInstitutionalVersion": { "message": "MetaMask Institutional" }, + "metamaskNotificationsAreOff": { + "message": "Las notificaciones del monedero no están activas actualmente." + }, + "metamaskPortfolio": { + "message": "MetaMask Portfolio." + }, "metamaskSwapsOfflineDescription": { "message": "MetaMask Swaps está en mantenimiento. Vuelva a comprobarlo más tarde." }, "metamaskVersion": { "message": "Versión de MetaMask" }, + "methodData": { + "message": "Método" + }, + "methodDataTransactionDescription": { + "message": "Esta es la acción específica que se llevará a cabo. Estos datos pueden falsificarse, así que asegúrese de que confía en el otro sitio." + }, + "methodNotSupported": { + "message": "No compatible con esta cuenta." + }, "metrics": { "message": "Indicadores" }, @@ -2224,11 +2601,17 @@ "mmiBuiltAroundTheWorld": { "message": "MetaMask Institutional está diseñado y construido en todo el mundo." }, + "mmiNewNFTDetectedInNFTsTabMessage": { + "message": "Deje que MetaMask Institutional detecte y muestre automáticamente NFT en su monedero." + }, + "mmiPasswordSetupDetails": { + "message": "Esta contraseña desbloqueará únicamente su extensión MetaMask Institutional." + }, "more": { "message": "más" }, "multipleSnapConnectionWarning": { - "message": "$1 quiere conectarse con $2 snaps. Continúe solo si confía en este sitio web.", + "message": "$1 quiere conectarse a $2", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." }, "mustSelectOne": { @@ -2237,10 +2620,80 @@ "name": { "message": "Nombre" }, + "nameAddressLabel": { + "message": "Dirección", + "description": "Label above address field in name component modal." + }, + "nameInstructionsNew": { + "message": "Si conoce esta dirección, asígnele un apodo para reconocerla en el futuro.", + "description": "Instruction text in name component modal when value is not recognised." + }, + "nameInstructionsRecognized": { + "message": "Esta dirección tiene un apodo predeterminado, pero puede editarlo o explorar otras sugerencias.", + "description": "Instruction text in name component modal when value is recognized but not saved." + }, + "nameInstructionsSaved": { + "message": "Ya agregó un apodo para esta dirección anteriormente. Puede editar o ver otros apodos sugeridos.", + "description": "Instruction text in name component modal when value is saved." + }, + "nameLabel": { + "message": "Apodo", + "description": "Label above name input field in name component modal." + }, + "nameModalMaybeProposedName": { + "message": "Quizás: $1", + "description": "$1 is the proposed name" + }, + "nameModalTitleNew": { + "message": "Dirección desconocida", + "description": "Title of the modal created by the name component when value is not recognised." + }, + "nameModalTitleRecognized": { + "message": "Dirección reconocida", + "description": "Title of the modal created by the name component when value is recognized but not saved." + }, + "nameModalTitleSaved": { + "message": "Dirección guardada", + "description": "Title of the modal created by the name component when value is saved." + }, + "nameProviderProposedBy": { + "message": "Propuesto por $1", + "description": "$1 is the name of the provider" + }, + "nameProvider_ens": { + "message": "Servicio de nombres de Ethereum (ENS)" + }, + "nameProvider_etherscan": { + "message": "Etherscan" + }, + "nameProvider_lens": { + "message": "Lens Protocol" + }, + "nameProvider_token": { + "message": "MetaMask" + }, + "nameSetPlaceholder": { + "message": "Elija un apodo...", + "description": "Placeholder text for name input field in name component modal." + }, + "nativePermissionRequestDescription": { + "message": "¿Desea que este sitio haga lo siguiente?", + "description": "Description below header used on Permission Connect screen for native permissions." + }, "nativeToken": { "message": "El token nativo en esta red es de $1. Es el token utilizado para las tarifas de gas.", "description": "$1 represents the name of the native token on the current network" }, + "nativeTokenScamWarningConversion": { + "message": "Editar detalles de la red" + }, + "nativeTokenScamWarningDescription": { + "message": "Esta red no coincide con su ID de cadena o nombre asociado. Muchos tokens populares usan el nombre $1, lo que los convierte en blanco de estafas. Los estafadores pueden engañarlo para que les envíe dinero más valioso a cambio. Verifique todo antes de continuar.", + "description": "$1 represents the currency name" + }, + "nativeTokenScamWarningTitle": { + "message": "Esto es una estafa potencial" + }, "needHelp": { "message": "¿Necesita ayuda? Comuníquese con $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -2261,6 +2714,9 @@ "negativeETH": { "message": "No se pueden enviar cantidades negativas de ETH." }, + "negativeOrZeroAmountToken": { + "message": "No se pueden enviar montos negativos o nulos de activos." + }, "network": { "message": "Red:" }, @@ -2291,6 +2747,9 @@ "networkNameBSC": { "message": "BSC" }, + "networkNameBase": { + "message": "Base" + }, "networkNameDefinition": { "message": "El nombre asociado a esta red." }, @@ -2300,12 +2759,21 @@ "networkNameGoerli": { "message": "Goerli" }, + "networkNameLinea": { + "message": "Linea" + }, + "networkNameOpMainnet": { + "message": "Red principal OP" + }, "networkNamePolygon": { "message": "Polygon" }, "networkNameTestnet": { "message": "Red de prueba" }, + "networkNameZkSyncEra": { + "message": "zkSync Era" + }, "networkProvider": { "message": "Proveedor de red" }, @@ -2358,6 +2826,19 @@ "newContract": { "message": "Contrato nuevo" }, + "newNFTDetectedInImportNFTsMessageStrongText": { + "message": "Configuración > Seguridad y privacidad" + }, + "newNFTDetectedInImportNFTsMsg": { + "message": "Para usar Opensea, para ver sus NFT, active 'Mostrar medios NFT' en $1.", + "description": "$1 is used for newNFTDetectedInImportNFTsMessageStrongText" + }, + "newNFTDetectedInNFTsTabMessage": { + "message": "Deje que MetaMask detecte y muestre automáticamente los NFT en su monedero." + }, + "newNFTsAutodetected": { + "message": "Autodetección de NFT" + }, "newNetworkAdded": { "message": "¡\"$1\" se añadió con éxito!" }, @@ -2367,6 +2848,12 @@ "newPassword": { "message": "Contraseña nueva (mín. de 8 caracteres)" }, + "newPrivacyPolicyActionButton": { + "message": "Leer más" + }, + "newPrivacyPolicyTitle": { + "message": "Hemos actualizado nuestra política de privacidad" + }, "newTokensImportedMessage": { "message": "Ha importado $1 exitosamente.", "description": "$1 is the string of symbols of all the tokens imported" @@ -2388,6 +2875,9 @@ "message": "Este token es un NFT. Añadir a $1", "description": "$1 is a clickable link with text defined by the 'importNFTPage' key" }, + "nftAlreadyAdded": { + "message": "NFT ya ha sido añadido." + }, "nftDisclaimer": { "message": "Descargo de responsabilidad: MetaMask extrae el archivo multimedia de la URL de origen. Esta URL a veces es modificada por el mercado en el que se acuñó el NFT." }, @@ -2423,12 +2913,21 @@ "noAddressForName": { "message": "No se estableció ninguna dirección para este nombre." }, + "noConnectedAccountDescription": { + "message": "Seleccione una cuenta que desee utilizar en este sitio para continuar." + }, + "noConnectedAccountTitle": { + "message": "MetaMask no está conectado a este sitio" + }, "noConversionDateAvailable": { "message": "No hay fecha de conversión de moneda disponible" }, "noConversionRateAvailable": { "message": "No hay tasa de conversión disponible" }, + "noDomainResolution": { + "message": "No se proporcionó resolución para el dominio." + }, "noNFTs": { "message": "No hay ningún NFT aún" }, @@ -2447,8 +2946,11 @@ "noWebcamFoundTitle": { "message": "No se encontró cámara web" }, + "nonCustodialAccounts": { + "message": "MetaMask Institutional le permite usar cuentas no custodiadas, si tiene previsto usar estas cuentas como respaldo de la frase secreta de recuperación." + }, "nonce": { - "message": "Mientras tanto" + "message": "Nonce" }, "nonceField": { "message": "Personalizar nonce de transacción" @@ -2477,69 +2979,137 @@ "notePlaceholder": { "message": "El verificador verá esta nota cuando apruebe la transacción en la cuenta custodiada." }, - "notificationTransactionFailedMessage": { - "message": "¡La transacción $1 fallida! $2", - "description": "Content of the browser notification that appears when a transaction fails" + "notificationDetail": { + "message": "Detalles" }, - "notificationTransactionFailedMessageMMI": { - "message": "¡Transacción fallida! $1", - "description": "Content of the browser notification that appears when a transaction fails in MMI" + "notificationDetailBaseFee": { + "message": "Tarifa base (GWEI)" }, - "notificationTransactionFailedTitle": { - "message": "Transacción fallida", - "description": "Title of the browser notification that appears when a transaction fails" + "notificationDetailGasLimit": { + "message": "Límite de gas (unidades)" }, - "notificationTransactionSuccessMessage": { - "message": "¡Transacción $1 confirmada!", - "description": "Content of the browser notification that appears when a transaction is confirmed" + "notificationDetailGasUsed": { + "message": "Gas usado (unidades)" }, - "notificationTransactionSuccessTitle": { - "message": "Transacción confirmada", - "description": "Title of the browser notification that appears when a transaction is confirmed" + "notificationDetailMaxFee": { + "message": "Tarifa máxima por gas" }, - "notificationTransactionSuccessView": { - "message": "Ver en $1", - "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" + "notificationDetailNetwork": { + "message": "Red" }, - "notifications": { - "message": "Notificaciones" + "notificationDetailNetworkFee": { + "message": "Tarifa de red" }, - "notifications20ActionText": { - "message": "Más información", - "description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a ledger page to resolve the U2F connection issue." + "notificationDetailPriorityFee": { + "message": "Tarifa de prioridad (GWEI)" }, - "notifications20Description": { - "message": "Si tiene la última versión de Firefox, es posible que experimente un problema relacionado con la eliminación de la compatibilidad con U2F de Firefox.", - "description": "Description of a notification in the 'See What's New' popup. Describes the U2F support being dropped by firefox and that it affects ledger users." + "notificationItemCheckBlockExplorer": { + "message": "Verifique en el BlockExplorer" }, - "notifications20Title": { - "message": "Usuarios de Ledger y Firefox están experimentando problemas de conexión", - "description": "Title for a notification in the 'See What's New' popup. Tells users that latest firefox users using U2F may experience connection issues." + "notificationItemCollection": { + "message": "Colección" }, - "notifications24ActionText": { - "message": "Entendido" + "notificationItemConfirmed": { + "message": "Confirmado" }, - "notifications24Description": { - "message": "Las configuraciones avanzadas de tarifas de gas ahora se recuerdan según la red que esté utilizando. Esto significa que puede establecer tarifas de gas avanzadas específicas para cada red y evitar pagar de más por el gas o transacciones estancadas." + "notificationItemError": { + "message": "No se pueden obtener las tarifas en este momento" }, - "notifications24Title": { - "message": "Tarifas avanzadas de gas por red" + "notificationItemFrom": { + "message": "De" + }, + "notificationItemLidoStakeReadyToBeWithdrawn": { + "message": "Retiro listo" + }, + "notificationItemLidoStakeReadyToBeWithdrawnMessage": { + "message": "Ahora puede retirar sus $1 sin staking" + }, + "notificationItemLidoWithdrawalRequestedMessage": { + "message": "Se envió su solicitud para hacer unstaking de $1" + }, + "notificationItemNFTReceivedFrom": { + "message": "NFT recibido de" + }, + "notificationItemNFTSentTo": { + "message": "NFT enviado a" + }, + "notificationItemNetwork": { + "message": "Red" + }, + "notificationItemRate": { + "message": "Tasa (tarifa incluida)" + }, + "notificationItemReceived": { + "message": "Recibido" + }, + "notificationItemReceivedFrom": { + "message": "Recibido de" + }, + "notificationItemSent": { + "message": "Enviado" + }, + "notificationItemSentTo": { + "message": "Enviado a" + }, + "notificationItemStakeCompleted": { + "message": "Staking finalizado" + }, + "notificationItemStaked": { + "message": "Con staking" + }, + "notificationItemStakingProvider": { + "message": "Proveedor de staking" + }, + "notificationItemStatus": { + "message": "Estado" + }, + "notificationItemSwapped": { + "message": "Canjeado" + }, + "notificationItemSwappedFor": { + "message": "por" }, - "notifications8ActionText": { - "message": "Ir a Configuración > Avanzado", - "description": "Description on an action button that appears in the What's New popup. Tells the user that if they click it, they will go to our Advanced settings page." + "notificationItemTo": { + "message": "Para" + }, + "notificationItemTransactionId": { + "message": "ID de transacción" + }, + "notificationItemUnStakeCompleted": { + "message": "Unstaking finalizado" + }, + "notificationItemUnStaked": { + "message": "Sin staking" + }, + "notificationItemUnStakingRequested": { + "message": "Unstaking solicitado" + }, + "notificationTransactionFailedMessage": { + "message": "¡La transacción $1 fallida! $2", + "description": "Content of the browser notification that appears when a transaction fails" + }, + "notificationTransactionFailedMessageMMI": { + "message": "¡Transacción fallida! $1", + "description": "Content of the browser notification that appears when a transaction fails in MMI" + }, + "notificationTransactionFailedTitle": { + "message": "Transacción fallida", + "description": "Title of the browser notification that appears when a transaction fails" + }, + "notificationTransactionSuccessMessage": { + "message": "¡Transacción $1 confirmada!", + "description": "Content of the browser notification that appears when a transaction is confirmed" }, - "notifications8DescriptionOne": { - "message": "A partir de MetaMask v10.4.0, ya no necesita Ledger Live para conectar su dispositivo Ledger a MetaMask.", - "description": "Description of a notification in the 'See What's New' popup. Describes changes for how Ledger Live is no longer needed to connect the device." + "notificationTransactionSuccessTitle": { + "message": "Transacción confirmada", + "description": "Title of the browser notification that appears when a transaction is confirmed" }, - "notifications8DescriptionTwo": { - "message": "Para una experiencia más fácil y estable, vaya a la pestaña de Configuración > Avanzado y cambie el 'Tipo de conexión a Ledger preferida' a 'WebHID'.", - "description": "Description of a notification in the 'See What's New' popup. Describes how the user can turn off the Ledger Live setting." + "notificationTransactionSuccessView": { + "message": "Ver en $1", + "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" }, - "notifications8Title": { - "message": "Mejora de la conexión de Ledger", - "description": "Title for a notification in the 'See What's New' popup. Notifies ledger users that there is an improvement in how they can connect their device." + "notifications": { + "message": "Notificaciones" }, "notificationsDropLedgerFirefoxDescription": { "message": "Firefox ya no es compatible con U2F, por lo que Ledger no funcionará con MetaMask en Firefox. En su lugar, pruebe MetaMask en Google Chrome.", @@ -2549,33 +3119,37 @@ "message": "Eliminación de la compatibilidad de Ledger para Firefox", "description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped." }, - "notificationsEmptyText": { - "message": "Aquí es donde puede encontrar las notificaciones de sus snaps instalados." - }, - "notificationsHeader": { - "message": "Notificaciones" + "notificationsFeatureToggle": { + "message": "Habilitar notificaciones del monedero", + "description": "Experimental feature title" }, - "notificationsInfos": { - "message": "$1 de $2", - "description": "$1 is the date at which the notification has been dispatched and $2 is the link to the snap that dispatched the notification." + "notificationsFeatureToggleDescription": { + "message": "Esto permite activar notificaciones del monedero como enviar/recibir fondos o NTF y anuncios de funciones.", + "description": "Description of the experimental notifications feature" }, "notificationsMarkAllAsRead": { "message": "Marcar todo como leído" }, - "notificationsOpenBetaSnapsActionText": { - "message": "Conozca más" + "notificationsPageEmptyTitle": { + "message": "No hay nada que ver aquí" + }, + "notificationsPageErrorContent": { + "message": "Intente volver a visitar esta página." }, - "notificationsOpenBetaSnapsDescriptionOne": { - "message": "🎉 ¡Nos complace anunciar la versión Beta abierta de MetaMask Snaps!" + "notificationsPageErrorTitle": { + "message": "Hubo un error" }, - "notificationsOpenBetaSnapsDescriptionThree": { - "message": "¡Personalice su monedero con snaps creados por la comunidad de desarrolladores!" + "notificationsPageNoNotificationsContent": { + "message": "Aún no ha recibido ninguna notificación." }, - "notificationsOpenBetaSnapsDescriptionTwo": { - "message": "Los snaps lo ayudan a hacer más con MetaMask, como conectarlo a más redes, ver información sobre transacciones y recibir notificaciones personalizadas." + "notificationsSettingsBoxError": { + "message": "Se produjo un error. Vuelva a intentarlo." }, - "notificationsOpenBetaSnapsTitle": { - "message": "Presentamos MetaMask Snaps" + "notificationsSettingsPageAllowNotifications": { + "message": "Manténgase informado sobre lo que sucede en su monedero con notificaciones. Para usar notificaciones, utilizamos un perfil para sincronizar algunas configuraciones en sus dispositivos. $1" + }, + "notificationsSettingsPageAllowNotificationsLink": { + "message": "Obtenga más información sobre cómo protegemos su privacidad mientras utiliza esta función." }, "numberOfNewTokensDetectedPlural": { "message": "$1 nuevos tokens encontrados en esta cuenta", @@ -2599,6 +3173,9 @@ "on": { "message": "Activado" }, + "onboarding": { + "message": "Incorporación" + }, "onboardingAdvancedPrivacyIPFSDescription": { "message": "La puerta de enlace de IPFS permite acceder y visualizar datos alojados por terceros. Puede agregar una puerta de enlace de IPFS personalizada o continuar usando la predeterminada." }, @@ -2629,51 +3206,45 @@ "onboardingMetametricsAgree": { "message": "Acepto" }, - "onboardingMetametricsAllowOptOut": { - "message": "Siempre le permitirá excluirse a través de la Configuración" - }, - "onboardingMetametricsDataTerms": { - "message": "Estos datos se agrupan y, por lo tanto, son anónimos a los efectos del Reglamento general de protección de datos (UE) 2016/679." - }, "onboardingMetametricsDescription": { - "message": "MetaMask quisiera recopilar datos de uso para comprender mejor cómo nuestros usuarios interactúan con MetaMask. Estos datos se utilizarán para proporcionar el servicio, lo que incluye mejorarlo en función de su uso." + "message": "Nos gustaría recopilar datos básicos de uso y diagnóstico para mejorar MetaMask. Tenga presente que nunca venderemos los datos que nos proporcione aquí." }, "onboardingMetametricsDescription2": { - "message": "MetaMask..." + "message": "Al recopilar métricas, siempre será..." }, "onboardingMetametricsDisagree": { "message": "No, gracias" }, "onboardingMetametricsInfuraTerms": { - "message": "*Al utilizar Infura como su proveedor de RPC predeterminado en MetaMask, Infura recopilará su dirección IP y la dirección de su monedero de Ethereum cuando envíe una transacción. No almacenamos esta información de una manera que permita qie nuestros sistemas asocien esos dos datos. Para obtener más información sobre cómo interactúan MetaMask e Infura desde la perspectiva de la recopilación de datos, consulte nuestra actualización $1. Para obtener más información sobre nuestras prácticas de privacidad en general, consulte nuestra $2.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" + "message": "Le informaremos si decidimos usar estos datos para otros fines. Puede consultar $1 para obtener más información. Recuerde que puede acceder a la configuración y excluirse en cualquier momento.", + "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, "onboardingMetametricsInfuraTermsPolicy": { - "message": "Política de privacidad aquí" - }, - "onboardingMetametricsInfuraTermsPolicyLink": { - "message": "aquí" + "message": "Política de privacidad" }, "onboardingMetametricsModalTitle": { "message": "Agregar red personalizada" }, "onboardingMetametricsNeverCollect": { - "message": "$1 recopilará información que no necesitamos para brindar el servicio (como claves, direcciones, hashes de transacciones o saldos)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "Se almacenan los clics y las visualizaciones de $1 en la aplicación, pero no otros detalles (como su dirección pública).", + "description": "$1 represents `onboardingMetametricsNeverCollectEmphasis`" + }, + "onboardingMetametricsNeverCollectEmphasis": { + "message": "Privadas:" }, "onboardingMetametricsNeverCollectIP": { - "message": "$1 recopilará su dirección IP completa*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 usamos su dirección IP temporalmente para detectar una ubicación general (como su país o región), pero no la guardamos nunca.", + "description": "$1 represents `onboardingMetametricsNeverCollectIPEmphasis`" }, - "onboardingMetametricsNeverEmphasis": { - "message": "Nunca" + "onboardingMetametricsNeverCollectIPEmphasis": { + "message": "Generales:" }, "onboardingMetametricsNeverSellData": { - "message": "$1 venderá datos. ¡Jamás!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 usted decide si desea compartir o eliminar sus datos de uso a través de la configuración en cualquier momento.", + "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" }, - "onboardingMetametricsSendAnonymize": { - "message": "Enviará eventos de vistas de página y clics anónimos" + "onboardingMetametricsNeverSellDataEmphasis": { + "message": "Opcionales:" }, "onboardingMetametricsTitle": { "message": "Ayúdenos a mejorar MetaMask" @@ -2714,15 +3285,26 @@ "onboardingPinExtensionTitle": { "message": "¡Su instalación de MetaMask ha finalizado!" }, + "onboardingPinMmiExtensionLabel": { + "message": "Fijar MetaMask Institutional" + }, "onboardingUsePhishingDetectionDescription": { "message": "Las alertas de detección de phishing se basan en la comunicación con $1. jsDeliver tendrá acceso a su dirección IP. Ver 2$.", "description": "The $1 is the word 'jsDeliver', from key 'jsDeliver' and $2 is the words Privacy Policy from key 'privacyMsg', both separated here so that it can be wrapped as a link" }, + "onekey": { + "message": "OneKey" + }, "onlyAddTrustedNetworks": { "message": "Un proveedor de red malintencionado puede mentir sobre el estado de la cadena de bloques y registrar su actividad de red. Agregue solo redes personalizadas de confianza." }, "onlyConnectTrust": { - "message": "Conéctese solo con sitios de confianza." + "message": "Conéctese solo con sitios de confianza. $1", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." + }, + "openCustodianApp": { + "message": "Abrir aplicación de $1", + "description": "The $1 is the name of the Custodian that will be open" }, "openFullScreenForLedgerWebHid": { "message": "Pase al modo de pantalla completa para conectar su Ledger.", @@ -2734,6 +3316,15 @@ "openSeaNew": { "message": "OpenSea" }, + "openSeaToBlockaidBtnLabel": { + "message": "Explorar Snaps" + }, + "openSeaToBlockaidDescription": { + "message": "Las alertas de seguridad ya no están disponibles en esta red. Instalar un Snap podría mejorar su seguridad." + }, + "openSeaToBlockaidTitle": { + "message": "¡Atención!" + }, "operationFailed": { "message": "Operación fallida" }, @@ -2777,6 +3368,9 @@ "password": { "message": "Contraseña" }, + "passwordMmiTermsWarning": { + "message": "Entiendo que MetaMask Institutional no puede recuperar esta contraseña por mí. $1" + }, "passwordNotLongEnough": { "message": "La contraseña no es suficientemente larga" }, @@ -2803,6 +3397,10 @@ "message": "Pegue aquí la cadena de clave privada:", "description": "For importing an account from a private key" }, + "paymasterInUse": { + "message": "El gas para esta transacción será cubierto por un pagador.", + "description": "Alert shown in transaction confirmation if paymaster in use." + }, "pending": { "message": "Pendiente" }, @@ -2816,18 +3414,26 @@ "message": "Tiene (1) transacción pendiente.", "description": "$1 is count of pending transactions" }, - "permissionRequest": { - "message": "Solicitud de permiso" + "permissionDetails": { + "message": "Detalles del permiso" }, - "permissionRequestCapitalized": { + "permissionRequest": { "message": "Solicitud de permiso" }, "permissionRequested": { "message": "Solicitado ahora" }, + "permissionRequestedForAccounts": { + "message": "Solicitado ahora por $1", + "description": "Permission cell status for requested permission including accounts, rendered as AvatarGroup which is $1." + }, "permissionRevoked": { "message": "Revocado en esta actualización" }, + "permissionRevokedForAccounts": { + "message": "Revocado en esta actualización por $1", + "description": "Permission cell status for revoked permission including accounts, rendered as AvatarGroup which is $1." + }, "permission_accessNamedSnap": { "message": "Conectarse a $1.", "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." @@ -2836,6 +3442,10 @@ "message": "Acceso a internet.", "description": "The description of the `endowment:network-access` permission." }, + "permission_accessNetworkDescription": { + "message": "Permita que $1 tenga acceso a Internet. Esto se puede usar tanto para enviar como para recibir datos con servidores de terceros.", + "description": "An extended description of the `endowment:network-access` permission. $1 is the snap name." + }, "permission_accessSnap": { "message": "Conéctese al snap de $1.", "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." @@ -2848,10 +3458,18 @@ "message": "Programar y ejecutar acciones periódicas.", "description": "The description for the `snap_cronjob` permission" }, + "permission_cronjobDescription": { + "message": "Permita que $1 realice acciones que se ejecutan periódicamente en horas, fechas o intervalos fijos. Esto se puede usar para activar interacciones o notificaciones sensibles al tiempo.", + "description": "An extended description for the `snap_cronjob` permission. $1 is the snap name." + }, "permission_dialog": { "message": "Mostrar ventanas de diálogo en MetaMask.", "description": "The description for the `snap_dialog` permission" }, + "permission_dialogDescription": { + "message": "Permita que $1 muestre ventanas emergentes de MetaMask con texto personalizado, campo de entrada y botones para aprobar o rechazar una acción.\nSe puede usar para crear, p. ej. alertas, confirmaciones y flujos de suscripción para un snap.", + "description": "An extended description for the `snap_dialog` permission. $1 is the snap name." + }, "permission_ethereumAccounts": { "message": "Ver las direcciones de las cuentas permitidas (requerido)", "description": "The description for the `eth_accounts` permission" @@ -2860,30 +3478,138 @@ "message": "Acceda al proveedor de Ethereum.", "description": "The description for the `endowment:ethereum-provider` permission" }, + "permission_ethereumProviderDescription": { + "message": "Permita que $1 se comunique directamente con MetaMask para que lea datos de la cadena de bloques y sugiera mensajes y transacciones.", + "description": "An extended description for the `endowment:ethereum-provider` permission. $1 is the snap name." + }, + "permission_getEntropy": { + "message": "Obtenga claves arbitrarias únicas para $1.", + "description": "The description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getEntropyDescription": { + "message": "Permita que $1 obtenga claves arbitrarias únicas para $1, sin exponerlas. Estas claves son independientes de su(s) cuenta(s) de MetaMask y no están relacionadas con sus claves privadas ni su frase secreta de recuperación. Otros snaps no pueden acceder a esta información.", + "description": "An extended description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getLocale": { + "message": "Vea su idioma preferido.", + "description": "The description for the `snap_getLocale` permission" + }, + "permission_getLocaleDescription": { + "message": "Permita que $1 acceda a su idioma preferido desde la configuración de MetaMask. Esto se puede usar para localizar y mostrar el contenido de $1 usando su idioma.", + "description": "An extended description for the `snap_getLocale` permission. $1 is the snap name." + }, + "permission_homePage": { + "message": "Mostrar una pantalla personalizada", + "description": "The description for the `endowment:page-home` permission" + }, + "permission_homePageDescription": { + "message": "Permita que $1 muestre una pantalla de inicio personalizada en MetaMask. Esto se puede utilizar para interfaces de usuario, configuración y paneles.", + "description": "An extended description for the `endowment:page-home` permission. $1 is the snap name." + }, + "permission_keyring": { + "message": "Permitir solicitudes para agregar y controlar cuentas Ethereum", + "description": "The description for the `endowment:keyring` permission" + }, + "permission_keyringDescription": { + "message": "Permita que $1 reciba solicitudes para agregar o eliminar cuentas, además de firmar y realizar transacciones en nombre de estas cuentas.", + "description": "An extended description for the `endowment:keyring` permission. $1 is the snap name." + }, "permission_lifecycleHooks": { "message": "Utilice ganchos de ciclo de vida.", "description": "The description for the `endowment:lifecycle-hooks` permission" }, + "permission_lifecycleHooksDescription": { + "message": "Permita que $1 use ganchos de ciclo de vida para ejecutar código en momentos específicos durante su ciclo de vida.", + "description": "An extended description for the `endowment:lifecycle-hooks` permission. $1 is the snap name." + }, "permission_manageAccounts": { "message": "Agregar y controlar cuentas de Ethereum", "description": "The description for `snap_manageAccounts` permission" }, + "permission_manageAccountsDescription": { + "message": "Permita que $1 agregue o elimine cuentas de Ethereum, luego realice transacciones y firme con estas cuentas.", + "description": "An extended description for the `snap_manageAccounts` permission. $1 is the snap name." + }, + "permission_manageBip32Keys": { + "message": "Administrar cuentas de $1.", + "description": "The description for the `snap_getBip32Entropy` permission. $1 is a derivation path, e.g. 'm/44'/0'/0' (secp256k1)'." + }, + "permission_manageBip44AndBip32KeysDescription": { + "message": "Permita a $1 para administrar cuentas y activos en la red solicitada. Estas cuentas se derivan y se respaldan utilizando su frase de recuperación secreta (sin revelarla). Con el poder de derivar claves, $1 puede admitir una variedad de protocolos de cadenas de bloques más allá de Ethereum (EVM).", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions. $1 is the snap name." + }, + "permission_manageBip44Keys": { + "message": "Administrar cuentas de $1.", + "description": "The description for the `snap_getBip44Entropy` permission. $1 is the name of a protocol, e.g. 'Filecoin'." + }, "permission_manageState": { "message": "Almacene y administre sus datos en su dispositivo.", "description": "The description for the `snap_manageState` permission" }, + "permission_manageStateDescription": { + "message": "Permita que $1 almacene, actualice y recupere datos de forma segura con cifrado. Otros snaps no pueden acceder a esta información.", + "description": "An extended description for the `snap_manageState` permission. $1 is the snap name." + }, + "permission_nameLookup": { + "message": "Proporcionar búsquedas de dominios y direcciones.", + "description": "The description for the `endowment:name-lookup` permission." + }, + "permission_nameLookupDescription": { + "message": "Permita que el snap obtenga y muestre búsquedas de direcciones y dominios en diferentes partes de la interfaz de usuario de MetaMask.", + "description": "An extended description for the `endowment:name-lookup` permission." + }, "permission_notifications": { "message": "Mostrar notificaciones.", "description": "The description for the `snap_notify` permission" }, + "permission_notificationsDescription": { + "message": "Permita que $1 muestre notificaciones dentro de MetaMask. Se puede activar un breve texto de notificación con un snap para obtener información procesable o sensible al tiempo.", + "description": "An extended description for the `snap_notify` permission. $1 is the snap name." + }, + "permission_rpc": { + "message": "Permitir que $1 se comunique directamente con $2.", + "description": "The description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescription": { + "message": "Permita que $1 envíe mensajes a $2 y reciba una respuesta de $2.", + "description": "An extended description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescriptionOriginList": { + "message": "$1 y $2", + "description": "A list of allowed origins where $2 is the last origin of the list and $1 is the rest of the list separated by ','." + }, + "permission_signatureInsight": { + "message": "Mostrar modo de información de firma.", + "description": "The description for the `endowment:signature-insight` permission" + }, + "permission_signatureInsightDescription": { + "message": "Permita que $1 muestre un modo con información sobre cualquier solicitud de firma antes de su aprobación. Esto se puede utilizar para soluciones de seguridad y antiphishing.", + "description": "An extended description for the `endowment:signature-insight` permission. $1 is the snap name." + }, + "permission_signatureInsightOrigin": { + "message": "Vea los orígenes de los sitios web que inician una solicitud de firma", + "description": "The description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission" + }, + "permission_signatureInsightOriginDescription": { + "message": "Permita que $1 vea el origen (URI) de los sitios web que inician solicitudes de firma. Esto se puede utilizar para soluciones antiphishing y de seguridad.", + "description": "An extended description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission. $1 is the snap name." + }, "permission_transactionInsight": { "message": "Obtenga y muestre información de transacciones.", "description": "The description for the `endowment:transaction-insight` permission" }, + "permission_transactionInsightDescription": { + "message": "Permita que $1 decodifique transacciones y muestre información dentro de la interfaz de usuario de MetaMask. Esto se puede utilizar para soluciones antiphishing y de seguridad.", + "description": "An extended description for the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_transactionInsightOrigin": { "message": "Ver los orígenes de los sitios web que sugieren transacciones", "description": "The description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission" }, + "permission_transactionInsightOriginDescription": { + "message": "Permita que $1 vea el origen (URI) de los sitios web que sugieren transacciones. Esto se puede utilizar para soluciones antiphishing y de seguridad.", + "description": "An extended description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_unknown": { "message": "Permiso desconocido: $1", "description": "$1 is the name of a requested permission that is not recognized." @@ -2892,29 +3618,66 @@ "message": "Ver su clave pública para $1 ($2).", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a derivation path, e.g. 'm/44'/0'/0''. $2 is the elliptic curve name, e.g. 'secp256k1'." }, + "permission_viewBip32PublicKeysDescription": { + "message": "Permita que $2 vea sus claves (y direcciones) públicas para $1. Esto no otorga ningún control de cuentas o activos.", + "description": "An extended description for the `snap_getBip32PublicKey` permission. $1 is a derivation path (name). $2 is the snap name." + }, "permission_viewNamedBip32PublicKeys": { "message": "Vea su clave pública para $1.", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a name for the derivation path, e.g., 'Ethereum accounts'." }, + "permission_walletSwitchEthereumChain": { + "message": "Cambie a la siguiente red y utilícela", + "description": "The label for the `wallet_switchEthereumChain` permission" + }, "permission_webAssembly": { "message": "Soporte para WebAssembly.", "description": "The description of the `endowment:webassembly` permission." }, + "permission_webAssemblyDescription": { + "message": "Permita que $1 acceda a entornos de ejecución de bajo nivel a través de WebAssembly.", + "description": "An extended description of the `endowment:webassembly` permission. $1 is the snap name." + }, "permissions": { "message": "Permisos" }, - "permissionsTitle": { - "message": "Permisos" + "permissionsPageEmptyContent": { + "message": "Nada que ver aquí" }, - "permissionsTourDescription": { - "message": "Encuentre sus cuentas conectadas y administre los permisos aquí" + "permissionsPageEmptySubContent": { + "message": "Aquí es donde puedes ver los permisos que has otorgado a los Snaps instalados o a los sitios conectados." + }, + "permissionsPageTourDescription": { + "message": "Este es su panel de control para administrar los permisos otorgados a los sitios conectados y los Snaps instalados." + }, + "permissionsPageTourTitle": { + "message": "Los sitios conectados ahora tienen permisos" }, "personalAddressDetected": { "message": "Se detectó una dirección personal. Ingrese la dirección de contrato del token." }, + "petnamesEnabledToggle": { + "message": "Permitir apodos" + }, + "petnamesEnabledToggleDescription": { + "message": "Esto le permite asignar un apodo a cualquier dirección. Le sugeriremos nombres para las direcciones con las que interactúa cuando sea posible." + }, + "pinExtensionDescription": { + "message": "Navegue hasta el menú de extensión y fije MetaMask Institutional para un acceso perfecto." + }, + "pinExtensionTitle": { + "message": "Fije la extensión" + }, + "pinToTop": { + "message": "Anclar arriba" + }, "pleaseConfirm": { "message": "Confirmar" }, + "plusMore": { + "message": "+ $1 más", + "description": "$1 is the number of additional items" + }, "plusXMore": { "message": "+ $1 más", "description": "$1 is a number of additional but unshown items in a list- this message will be shown in place of those items" @@ -2940,6 +3703,9 @@ "primaryCurrencySettingDescription": { "message": "Seleccione Nativa para dar prioridad a mostrar los valores en la moneda nativa de la cadena (p. ej., ETH). Seleccione Fiduciaria para dar prioridad a mostrar los valores en la moneda fiduciaria seleccionada." }, + "primaryType": { + "message": "Tipo principal" + }, "priorityFee": { "message": "Tarifa de prioridad" }, @@ -2960,6 +3726,18 @@ "message": "Clave privada para $1", "description": "$1 represents the account name" }, + "privateKeyHidden": { + "message": "La clave privada está oculta", + "description": "Explains that the private key input is hidden" + }, + "privateKeyShow": { + "message": "Mostrar/ocultar la entrada de clave privada", + "description": "Describes a toggle that is used to show or hide the private key input" + }, + "privateKeyShown": { + "message": "Esta clave privada se está mostrando", + "description": "Explains that the private key input is being shown" + }, "privateKeyWarning": { "message": "Advertencia: No revele esta clave. Cualquier persona que tenga sus claves privadas podría robar los activos de su cuenta." }, @@ -2969,6 +3747,21 @@ "proceedWithTransaction": { "message": "Quiero continuar de todos modos" }, + "productAnnouncements": { + "message": "Anuncios de productos" + }, + "profileSync": { + "message": "Sincronización del perfil" + }, + "profileSyncConfirmation": { + "message": "Si desactiva la sincronización del perfil, no podrá recibir notificaciones." + }, + "profileSyncDescription": { + "message": "Crea un perfil que MetaMask utiliza para sincronizar algunas configuraciones entre sus dispositivos. Esto es necesario para recibir notificaciones. $1." + }, + "profileSyncPrivacyLink": { + "message": "Obtenga información sobre cómo protegemos su privacidad" + }, "proposedApprovalLimit": { "message": "Límite de aprobación propuesto" }, @@ -2978,6 +3771,78 @@ "publicAddress": { "message": "Dirección pública" }, + "pushPlatformNotificationsFundsReceivedDescription": { + "message": "Recibió $1 $2" + }, + "pushPlatformNotificationsFundsReceivedDescriptionDefault": { + "message": "Recibió algunos tokens" + }, + "pushPlatformNotificationsFundsReceivedTitle": { + "message": "Fondos recibidos" + }, + "pushPlatformNotificationsFundsSentDescription": { + "message": "Envió correctamente $1 $2" + }, + "pushPlatformNotificationsFundsSentDescriptionDefault": { + "message": "Envió correctamente algunos tokens" + }, + "pushPlatformNotificationsFundsSentTitle": { + "message": "Fondos enviados" + }, + "pushPlatformNotificationsNftReceivedDescription": { + "message": "Recibió nuevos NFT" + }, + "pushPlatformNotificationsNftReceivedTitle": { + "message": "NFT recibido" + }, + "pushPlatformNotificationsNftSentDescription": { + "message": "Envió correctamente un NFT" + }, + "pushPlatformNotificationsNftSentTitle": { + "message": "NFT enviado" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedDescription": { + "message": "Su staking en Lido se realizó correctamente" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedTitle": { + "message": "Staking finalizado" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnDescription": { + "message": "Su staking en Lido ya está listo para retirarse" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnTitle": { + "message": "Staking listo para retirarse" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedDescription": { + "message": "Su retiro en Lido se realizó correctamente" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedTitle": { + "message": "Retiro finalizado" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedDescription": { + "message": "Se envió su solicitud de retiro en Lido" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedTitle": { + "message": "Retiro solicitado" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedDescription": { + "message": "Su staking en RocketPool se realizó correctamente" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedTitle": { + "message": "Staking finalizado" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedDescription": { + "message": "Su unstaking en RocketPool se realizó correctamente" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedTitle": { + "message": "Unstaking finalizado" + }, + "pushPlatformNotificationsSwapCompletedDescription": { + "message": "Su intercambio en MetaMask se realizó correctamente" + }, + "pushPlatformNotificationsSwapCompletedTitle": { + "message": "Intercambio finalizado" + }, "queued": { "message": "En cola" }, @@ -2996,9 +3861,15 @@ "receive": { "message": "Recibir" }, + "receiveTokensCamelCase": { + "message": "Recibir tokens" + }, "recipientAddressPlaceholder": { "message": "Ingrese la dirección pública (0x) o el nombre de ENS" }, + "recipientAddressPlaceholderFlask": { + "message": "Ingrese la dirección pública (0x) o el nombre de dominio" + }, "recommendedGasLabel": { "message": "Recomendado" }, @@ -3026,6 +3897,12 @@ "recoveryPhraseReminderTitle": { "message": "Proteja sus fondos." }, + "redesignedConfirmationsEnabledToggle": { + "message": "Solicitudes de firma mejoradas" + }, + "redesignedConfirmationsToggleDescription": { + "message": "Active esta opción para ver las solicitudes de firma en un formato mejorado." + }, "refreshList": { "message": "Actualizar lista" }, @@ -3068,15 +3945,30 @@ "removeJWTDescription": { "message": "¿Está seguro de que desea eliminar este token? Todas las cuentas asignadas a este token también se eliminarán de la extensión: " }, + "removeKeyringSnap": { + "message": "Al eliminar este Snap, se eliminan estas cuentas de MetaMask:" + }, + "removeKeyringSnapToolTip": { + "message": "El snap controla las cuentas y, al eliminarlo, las cuentas también se eliminarán de MetaMask, pero permanecerán en la cadena de bloques." + }, "removeNFT": { "message": "Eliminar NFT" }, + "removeNftErrorMessage": { + "message": "No pudimos eliminar este NFT." + }, "removeNftMessage": { "message": "¡El NFT se eliminó con éxito!" }, "removeSnap": { "message": "Eliminar snap" }, + "removeSnapAccountDescription": { + "message": "Si continúa, esta cuenta ya no estará disponible en MetaMask." + }, + "removeSnapAccountTitle": { + "message": "Eliminar cuenta" + }, "removeSnapConfirmation": { "message": "¿Está seguro de que desea eliminar $1?", "description": "$1 represents the name of the snap" @@ -3087,12 +3979,24 @@ "replace": { "message": "reemplazar" }, + "reportIssue": { + "message": "Reportar un problema" + }, "requestFlaggedAsMaliciousFallbackCopyReason": { "message": "El proveedor de seguridad no ha compartido detalles adicionales" }, "requestFlaggedAsMaliciousFallbackCopyReasonTitle": { "message": "Solicitud marcada como maliciosa" }, + "requestFrom": { + "message": "Solicitud de" + }, + "requestFromInfo": { + "message": "Este es el sitio que solicita su firma." + }, + "requestFromTransactionDescription": { + "message": "Este es el sitio que le pide su confirmación." + }, "requestMayNotBeSafe": { "message": "Es posible que la solicitud no sea segura" }, @@ -3114,6 +4018,9 @@ "reset": { "message": "Restablecer" }, + "resetStates": { + "message": "Restablecer estados" + }, "resetWallet": { "message": "Restablecer monedero" }, @@ -3142,7 +4049,7 @@ "message": "Restaure sus datos de usuario" }, "restoreUserDataDescription": { - "message": "Puede restaurar la configuración del usuario que contiene preferencias y direcciones de cuenta desde en un archivo JSON previamente respaldado." + "message": "Puede restaurar datos tal y como contactos y preferencias desde un archivo de copia de seguridad." }, "resultPageError": { "message": "Error" @@ -3196,9 +4103,15 @@ "message": "El soporte técnico de MetaMask nunca se lo solicitará.", "description": "The bolded texted in the second part of 'revealSeedWordsWarning'" }, + "revealSensitiveContent": { + "message": "Revelar contenido sensible" + }, "revealTheSeedPhrase": { "message": "Revelar frase semilla" }, + "reviewAlerts": { + "message": "Revisar alertas" + }, "revokeAllTokensTitle": { "message": "¿Revocar el permiso para acceder y transferir todos sus $1?", "description": "$1 is the symbol of the token for which the user is revoking approval" @@ -3249,6 +4162,9 @@ "searchAccounts": { "message": "Buscar cuentas" }, + "searchTokens": { + "message": "Buscar tokens" + }, "secretRecoveryPhrase": { "message": "Frase secreta de recuperación" }, @@ -3265,7 +4181,8 @@ "message": "Alertas de seguridad" }, "securityAlertsDescription": { - "message": "Esta función le alerta sobre actividad maliciosa en la red principal de Ethereum al revisar activamente las solicitudes de transacciones y firmas mientras preserva su privacidad. Sus datos no se comparten con el tercero que proporciona este servicio. Haga siempre su propia diligencia debida antes de aprobar cualquier solicitud. No hay garantía de que esta función detecte toda la actividad maliciosa." + "message": "Esta función le alerta sobre actividades maliciosas al revisar activamente las solicitudes de transacciones y firmas. $1", + "description": "Link to learn more about security alerts" }, "securityAndPrivacy": { "message": "Seguridad y privacidad" @@ -3355,6 +4272,9 @@ "selectAnAccountHelp": { "message": "Seleccione las cuentas custodiadas para usar en MetaMask Institutional." }, + "selectEnableDisplayMediaPrivacyPreference": { + "message": "Activar Mostrar medios NFT" + }, "selectHdPath": { "message": "Seleccione la ruta de acceso al disco duro" }, @@ -3376,18 +4296,41 @@ "send": { "message": "Enviar" }, + "sendAToken": { + "message": "Enviar un token" + }, "sendBugReport": { "message": "Envíenos un informe de error." }, + "sendNoContactsConversionText": { + "message": "haga clic aquí" + }, + "sendNoContactsDescription": { + "message": "Los contactos le permiten enviar transacciones de forma segura a otra cuenta múltiples veces. Para crear un contacto, $1", + "description": "$1 represents the action text 'click here'" + }, + "sendNoContactsTitle": { + "message": "Aún no tiene ningún contacto" + }, + "sendSelectReceiveAsset": { + "message": "Seleccione el activo a recibir" + }, + "sendSelectSendAsset": { + "message": "Seleccione el activo a enviar" + }, "sendSpecifiedTokens": { "message": "Enviar $1", "description": "Symbol of the specified token" }, - "sendTo": { - "message": "Enviar a" + "sendSwapSubmissionWarning": { + "message": "Al hacer clic en este botón se iniciará inmediatamente su transacción de canje. Revise los detalles de la transacción antes de continuar." }, - "sendTokens": { - "message": "Enviar tokens" + "sendTokenAsToken": { + "message": "Enviar $1 como $2", + "description": "Used in the transaction display list to describe a swap and send. $1 and $2 are the symbols of tokens in involved in the swap." + }, + "sendingAsset": { + "message": "Enviando $1" }, "sendingDisabled": { "message": "Todavía no se admite el envío de activos NFT ERC-1155." @@ -3400,9 +4343,15 @@ "message": "Advertencia: está a punto de enviar un contrato de token que podría dar lugar a una pérdida de fondos. $1", "description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning" }, + "sendingZeroAmount": { + "message": "Estás enviando 0 $1." + }, "sepolia": { "message": "Red de prueba Sepolia" }, + "serviceWorkerKeepAlive": { + "message": "Mantener activo el Service Worker" + }, "setAdvancedPrivacySettingsDetails": { "message": "MetaMask utiliza estos servicios de terceros de confianza para mejorar la usabilidad y la seguridad de los productos." }, @@ -3414,7 +4363,7 @@ "description": "The token symbol that is being approved" }, "settingAddSnapAccount": { - "message": "Añadir una cuenta snap" + "message": "Añadir una cuenta Snap" }, "settings": { "message": "Configuración" @@ -3422,9 +4371,21 @@ "settingsSearchMatchingNotFound": { "message": "No se encontraron resultados coincidentes." }, + "settingsSubHeadingSignaturesAndTransactions": { + "message": "Solicitudes de firmas y transacciones" + }, "show": { "message": "Mostrar" }, + "showAccount": { + "message": "Mostrar cuenta" + }, + "showExtensionInFullSizeView": { + "message": "Mostrar extensión en vista de tamaño completo" + }, + "showExtensionInFullSizeViewDescription": { + "message": "Active esto para que la vista en tamaño completo sea por defecto cuando haga clic en el icono de extensión." + }, "showFiatConversionInTestnets": { "message": "Mostrar conversión en redes de prueba" }, @@ -3444,6 +4405,9 @@ "message": "Seleccione esta opción para usar Etherscan para mostrar las transacciones entrantes en la lista de transacciones", "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" }, + "showIncomingTransactionsExplainer": { + "message": "Esto se basa en diferentes API de terceros para cada red, que exponen su dirección Ethereum y su dirección IP." + }, "showMore": { "message": "Mostrar más" }, @@ -3483,9 +4447,46 @@ "signin": { "message": "Iniciar sesión" }, + "signing": { + "message": "Firmando" + }, + "simulationDetailsFailed": { + "message": "Se produjo un error al cargar su estimación." + }, + "simulationDetailsFiatNotAvailable": { + "message": "No disponible" + }, + "simulationDetailsIncomingHeading": { + "message": "Usted recibe" + }, + "simulationDetailsNoBalanceChanges": { + "message": "No se prevén cambios para su monedero" + }, + "simulationDetailsOutgoingHeading": { + "message": "Envía" + }, + "simulationDetailsTitle": { + "message": "Cambios estimados" + }, + "simulationDetailsTitleTooltip": { + "message": "Los cambios estimados son los que podrían producirse si sigue adelante con esta transacción. Esto es solo una predicción, no una garantía." + }, + "simulationDetailsTotalFiat": { + "message": "Total = $1", + "description": "$1 is the total amount in fiat currency on one side of the transaction" + }, + "simulationDetailsTransactionReverted": { + "message": "Es probable que esta transacción falle" + }, "simulationErrorMessageV2": { "message": "No pudimos estimar el gas. Podría haber un error en el contrato y esta transacción podría fallar." }, + "simulationsSettingDescription": { + "message": "Active esta opción para estimar los cambios de saldo de las transacciones antes de confirmarlas. Esto no garantiza el resultado final de sus transacciones. $1" + }, + "simulationsSettingSubHeader": { + "message": "Estimar cambios de saldo" + }, "skip": { "message": "Omitir" }, @@ -3498,20 +4499,99 @@ "smartContracts": { "message": "Contratos inteligentes" }, - "smartSwapsAreHere": { - "message": "¡Los intercambios inteligentes ya están aquí!" - }, - "smartSwapsDescription": { - "message": "¡La función Intercambios de MetaMask ahora es mucho más inteligente! Habilitar Intercambios inteligentes permitirá que MetaMask optimice mediante programación su intercambio para ayudar a:" - }, "smartSwapsErrorNotEnoughFunds": { "message": "No hay suficientes fondos para un intercambio inteligente." }, "smartSwapsErrorUnavailable": { "message": "Los intercambios inteligentes no están disponibles temporalmente." }, + "smartTransactionCancelled": { + "message": "Su transacción se canceló" + }, + "smartTransactionCancelledDescription": { + "message": "Su transacción no se pudo completa, así que se canceló para ahorrarle el pago de comisiones de gas innecesarias." + }, + "smartTransactionError": { + "message": "Su transacción falló" + }, + "smartTransactionErrorDescription": { + "message": "Los cambios repentinos en el mercado pueden causar fallos. Si el problema continúa, póngase en contacto con el soporte al cliente de MetaMask." + }, + "smartTransactionPending": { + "message": "Enviando su transacción" + }, + "smartTransactionSuccess": { + "message": "Su transacción está completa" + }, + "smartTransactionTakingTooLong": { + "message": "Disculpe la espera" + }, + "smartTransactionTakingTooLongDescription": { + "message": "Si su transacción no finaliza en $1, se cancelará y no se le cobrará el gas.", + "description": "$1 is remaining time in seconds" + }, + "smartTransactions": { + "message": "Transacciones inteligentes" + }, + "smartTransactionsBenefit1": { + "message": "Índice de éxito del 99.5%" + }, + "smartTransactionsBenefit2": { + "message": "Le permite ahorrar dinero" + }, + "smartTransactionsBenefit3": { + "message": "Actualizaciones en tiempo real" + }, + "smartTransactionsDescription": { + "message": "Desbloquee índices de éxito más altos, protección contra frontrunning y mejor visibilidad con transacciones inteligentes." + }, + "smartTransactionsDescription2": { + "message": "Solo disponible en Ethereum. Active o desactive en cualquier momento en la configuración. $1", + "description": "$1 is an external link to learn more about Smart Transactions" + }, + "smartTransactionsOptItModalTitle": { + "message": "Protección mejorada de transacciones" + }, + "snapAccountCreated": { + "message": "Cuenta creada" + }, + "snapAccountCreatedDescription": { + "message": "¡Su nueva cuenta está lista para usar!" + }, + "snapAccountCreationFailed": { + "message": "Error al crear la cuenta" + }, + "snapAccountCreationFailedDescription": { + "message": "$1 no logró crear una cuenta para usted.", + "description": "$1 is the snap name" + }, + "snapAccountRedirectFinishSigningTitle": { + "message": "Terminar de firmar" + }, + "snapAccountRedirectSiteDescription": { + "message": "Siga las instrucciones desde $1" + }, + "snapAccountRemovalFailed": { + "message": "Error al eliminar la cuenta" + }, + "snapAccountRemovalFailedDescription": { + "message": "$1 no logró eliminar esta cuenta para usted.", + "description": "$1 is the snap name" + }, + "snapAccountRemoved": { + "message": "Cuenta eliminada" + }, + "snapAccountRemovedDescription": { + "message": "Esta cuenta ya no estará disponible para su uso en MetaMask." + }, + "snapAccounts": { + "message": "Cuenta de Snaps" + }, + "snapAccountsDescription": { + "message": "Cuentas controladas por Snaps de terceros." + }, "snapConnectionWarning": { - "message": "$1 quiere conectarse a $2. Continúe solo si confía en este sitio web.", + "message": "$1 quiere conectarse a $2", "description": "$2 is the snap and $1 is the dapp requesting connection to the snap." }, "snapContent": { @@ -3522,15 +4602,35 @@ "message": "Sitio web" }, "snapInstallRequest": { - "message": "La instalación de $1 otorga los siguientes permisos. Solo continúe si confía en $1.", + "message": "Instalar $1 le otorga los siguientes permisos.", "description": "$1 is the snap name." }, "snapInstallSuccess": { "message": "Instalación completa" }, + "snapInstallWarningCheck": { + "message": "$1 quiere permiso para hacer lo siguiente:", + "description": "Warning message used in popup displayed on snap install. $1 is the snap name." + }, "snapInstallWarningHeading": { "message": "Proceda con precaución" }, + "snapInstallWarningPermissionDescriptionForBip32View": { + "message": "Permita que $1 vea sus claves (y direcciones) públicas. Esto no otorga ningún control de cuentas o activos.", + "description": "An extended description for the `snap_getBip32PublicKey` permission used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionDescriptionForEntropy": { + "message": "Permita que Snap $1 administre cuentas y activos en las red(es) solicitada(s). Estas cuentas se derivan y se respaldan utilizando su frase de recuperación secreta (sin revelarla). Con el poder de derivar claves, $1 puede admitir una variedad de protocolos blockchain más allá de Ethereum (EVM).", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionNameForEntropy": { + "message": "Administrar cuentas de $1", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, + "snapInstallWarningPermissionNameForViewPublicKey": { + "message": "Ver su clave pública para $1", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, "snapInstallationErrorDescription": { "message": "$1 no se pudo instalar.", "description": "Error description used when snap installation fails. $1 is the snap name." @@ -3548,6 +4648,10 @@ "snapResultSuccessDescription": { "message": "$1 está listo para usar" }, + "snapUpdateAlertDescription": { + "message": "Obtenga la última versión de $1", + "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." + }, "snapUpdateAvailable": { "message": "Actualización disponible" }, @@ -3559,22 +4663,40 @@ "message": "Actualización fallida", "description": "Error title used when snap update fails." }, + "snapUpdateRequest": { + "message": "Actualizar $1 le otorga los siguientes permisos.", + "description": "$1 is the Snap name." + }, "snapUpdateSuccess": { "message": "Actualización completa" }, + "snapUrlIsBlocked": { + "message": "Este Snap quiere llevarlo a un sitio bloqueado. $1." + }, "snaps": { "message": "Snaps" }, - "snapsInvalidUIError": { - "message": "La IU especificada por el snap no es válida." + "snapsConnected": { + "message": "Snaps conectados" }, "snapsNoInsight": { "message": "El snap no devolvió ninguna información" }, + "snapsPrivacyWarningFirstMessage": { + "message": "Usted reconoce que el snap que está a punto de instalar es un Servicio de terceros, menos que se identifique de otro modo, según se define en Consensys $1. El uso que haga de los Servicios de terceros se rige por términos y condiciones independientes establecidos por el proveedor de Servicios de terceros. Consensys no recomienda el uso de ningún snap a ninguna persona en particular por ningún motivo en particular. Usted accede, confía o utiliza el Servicio de terceros bajo su propio riesgo. Consensys se exime de toda responsabilidad por cualquier pérdida a causa del uso de los Servicios de terceros.", + "description": "First part of a message in popup modal displayed when installing a snap for the first time. $1 is terms of use link." + }, "snapsPrivacyWarningSecondMessage": { "message": "Cualquier información que comparta con Servicios de terceros será recopilada directamente por dichos Servicios de terceros de acuerdo con sus políticas de privacidad. Consulte sus políticas de privacidad para obtener más información.", "description": "Second part of a message in popup modal displayed when installing a snap for the first time." }, + "snapsPrivacyWarningThirdMessage": { + "message": "Consensys no tiene acceso a la información que usted comparte con servicios de terceros.", + "description": "Third part of a message in popup modal displayed when installing a snap for the first time." + }, + "snapsSettings": { + "message": "Configuración de Snap" + }, "snapsTermsOfUse": { "message": "Términos de uso" }, @@ -3588,12 +4710,19 @@ "someNetworksMayPoseSecurity": { "message": "Algunas redes pueden presentar riesgos de seguridad y/o privacidad. Comprenda los riesgos antes de agregar y utilizar una red." }, + "somethingDoesntLookRight": { + "message": "Algo no se ve bien, ¿cierto? $1", + "description": "A false positive message for users to contact support. $1 is a link to the support page." + }, "somethingIsWrong": { "message": "Algo salió mal. Intente volver a cargar la página." }, "somethingWentWrong": { "message": "Lo lamentamos, se produjo un error." }, + "source": { + "message": "Fuente" + }, "speedUp": { "message": "Acelerar" }, @@ -3728,6 +4857,14 @@ "stake": { "message": "Staking" }, + "startYourJourney": { + "message": "Comience su recorrido con $1", + "description": "$1 is the token symbol" + }, + "startYourJourneyDescription": { + "message": "Comience con la web3 agregando $1 a su monedero.", + "description": "$1 is the token symbol" + }, "stateLogError": { "message": "Error al recuperar los registros de estado." }, @@ -3740,6 +4877,9 @@ "stateLogsDescription": { "message": "Los registros de estado contienen sus direcciones de cuentas públicas y las transacciones enviadas." }, + "states": { + "message": "Estados" + }, "status": { "message": "Estado" }, @@ -3783,18 +4923,6 @@ "strong": { "message": "Fuerte" }, - "stxBenefit1": { - "message": "Minimizar los costos de transacción" - }, - "stxBenefit2": { - "message": "Reducir las fallas en las transacciones" - }, - "stxBenefit3": { - "message": "Eliminar las transacciones atascadas" - }, - "stxBenefit4": { - "message": "Prevenir la inversión ventajista" - }, "stxCancelled": { "message": "El intercambio habría fallado" }, @@ -3804,6 +4932,10 @@ "stxCancelledSubDescription": { "message": "Intente su swap nuevamente. Estaremos aquí para protegerlo contra riesgos similares la próxima vez." }, + "stxEstimatedCompletion": { + "message": "Finalización estimada en < $1", + "description": "$1 is remeaning time in minutes and seconds, e.g. 0:10" + }, "stxFailure": { "message": "Error al intercambiar" }, @@ -3811,6 +4943,9 @@ "message": "Los cambios repentinos del mercado pueden causar fallas. Si el problema persiste, comuníquese con $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInDescription": { + "message": "Active las transacciones inteligentes para realizar transacciones más confiables y seguras en la red principal de Ethereum. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Enviando su intercambio de forma privada..." }, @@ -3849,12 +4984,21 @@ "submitted": { "message": "Enviado" }, + "suggestedTokenSymbol": { + "message": "Símbolo de cotización sugerido:" + }, "support": { "message": "Soporte técnico" }, "supportCenter": { "message": "Visite nuestro Centro de soporte técnico" }, + "surveyConversion": { + "message": "Responda a nuestra encuesta" + }, + "surveyTitle": { + "message": "Dé forma al futuro de MetaMask" + }, "swap": { "message": "Intercambiar" }, @@ -3874,6 +5018,9 @@ "swapAmountReceivedInfo": { "message": "Se refiere al monto mínimo que recibirá. Puede recibir más en función del deslizamiento." }, + "swapAndSend": { + "message": "Canjear y enviar" + }, "swapAnyway": { "message": "Intercambiar de todos modos" }, @@ -3989,6 +5136,10 @@ "message": "Incluye una tasa de MetaMask del $1%.", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." }, + "swapIncludesMMFeeAlt": { + "message": "La cotización refleja la tarifa de MetaMask del $1 %", + "description": "Provides information about the fee that metamask takes for swaps using the latest copy. $1 is a decimal number." + }, "swapIncludesMetaMaskFeeViewAllQuotes": { "message": "Incluye una tarifa MetaMask de $1% - $2", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number and $2 is a link to view all quotes." @@ -3996,6 +5147,9 @@ "swapLearnMore": { "message": "Más información sobre los intercambios" }, + "swapLiquiditySourceInfo": { + "message": "Buscamos varias fuentes de liquidez (sitios de cambio, agregadores y creadores de mercado profesionales) para comparar las mejores tasas de cambio y las tarifas de red." + }, "swapLowSlippage": { "message": "Deslizamiento bajo" }, @@ -4268,6 +5422,9 @@ "switchEthereumChainConfirmationTitle": { "message": "¿Le permite a este sitio cambiar la red?" }, + "switchInputCurrency": { + "message": "Cambiar moneda de entrada" + }, "switchNetwork": { "message": "Cambiar red" }, @@ -4281,14 +5438,15 @@ "switchToThisAccount": { "message": "Cambiar a esta cuenta" }, - "switchedTo": { - "message": "Ha cambiado a" + "switchedNetworkToastDecline": { + "message": "No volver a mostrar" }, - "switcherTitle": { - "message": "Selector de red" + "switchedNetworkToastMessage": { + "message": "$1 ahora está activo en $2", + "description": "$1 represents the account name, $2 represents the network name" }, - "switcherTourDescription": { - "message": "Haga clic en el icono para cambiar de red o agregar una nueva red" + "switchedTo": { + "message": "Ha cambiado a" }, "switchingNetworksCancelsPendingConfirmations": { "message": "Cambiar de red cancelará todas las confirmaciones pendientes" @@ -4388,6 +5546,18 @@ "toggleEthSignOn": { "message": "ACTIVADO (No recomendado)" }, + "toggleRequestQueueDescription": { + "message": "Esto le permite seleccionar una red para cada sitio en lugar de una única red seleccionada para todos los sitios. Esta función evitará que cambie de red manualmente, lo que puede afectar su experiencia de usuario en ciertos sitios." + }, + "toggleRequestQueueField": { + "message": "Seleccionar redes para cada sitio" + }, + "toggleRequestQueueOff": { + "message": "Desactivado" + }, + "toggleRequestQueueOn": { + "message": "Activado" + }, "token": { "message": "Token" }, @@ -4404,7 +5574,7 @@ "message": "Dirección de contrato de token" }, "tokenDecimalFetchFailed": { - "message": "Se requieren los decimales del token." + "message": "Se requiere decimal del token. Encuéntrelo en: $1" }, "tokenDecimalTitle": { "message": "Decimales del token:" @@ -4443,6 +5613,9 @@ "tooltipSatusConnected": { "message": "conectado" }, + "tooltipSatusConnectedUpperCase": { + "message": "Conectado" + }, "tooltipSatusNotConnected": { "message": "no conectado" }, @@ -4583,6 +5756,39 @@ "tryAgain": { "message": "Vuelva a intentarlo" }, + "turnOff": { + "message": "Desactivar" + }, + "turnOffMetamaskNotificationsError": { + "message": "Hubo un error al desactivar las notificaciones. Vuelva a intentarlo más tarde." + }, + "turnOn": { + "message": "Activar" + }, + "turnOnMetamaskNotifications": { + "message": "Activar las notificaciones" + }, + "turnOnMetamaskNotificationsButton": { + "message": "Activar" + }, + "turnOnMetamaskNotificationsError": { + "message": "Hubo un error al crear las notificaciones. Vuelva a intentarlo más tarde." + }, + "turnOnMetamaskNotificationsMessageFirst": { + "message": "Manténgase informado sobre lo que sucede en su monedero con notificaciones." + }, + "turnOnMetamaskNotificationsMessagePrivacyBold": { + "message": "Configuración > Notificaciones." + }, + "turnOnMetamaskNotificationsMessagePrivacyLink": { + "message": "Obtenga más información sobre cómo protegemos su privacidad mientras utiliza esta función." + }, + "turnOnMetamaskNotificationsMessageSecond": { + "message": "Para usar las notificaciones del monedero, utilizamos un perfil para sincronizar algunas configuraciones en sus dispositivos. $1" + }, + "turnOnMetamaskNotificationsMessageThird": { + "message": "Puede desactivar las notificaciones en cualquier momento en $1" + }, "turnOnTokenDetection": { "message": "Activar la detección mejorada de tokens" }, @@ -4614,6 +5820,10 @@ "unknownNetwork": { "message": "Red privada desconocida" }, + "unknownNetworkForKeyEntropy": { + "message": "Red desconocida", + "description": "Displayed on places like Snap install warning when regular name is not available." + }, "unknownQrCode": { "message": "Error: No se pudo identificar ese código QR" }, @@ -4626,6 +5836,9 @@ "unlockMessage": { "message": "La Web descentralizada espera" }, + "unpin": { + "message": "Desanclar" + }, "unrecognizedChain": { "message": "No se reconoce esta red personalizada", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." @@ -4643,6 +5856,9 @@ "update": { "message": "Actualizar" }, + "updateRequest": { + "message": "Solicitud de actualización" + }, "updatedWithDate": { "message": "$1 actualizado" }, @@ -4667,12 +5883,25 @@ "useNftDetection": { "message": "Detección automática de NFT" }, + "useNftDetectionDescriptionText": { + "message": "Permita que MetaMask agregue NFT de su propiedad mediante servicios de terceros (como OpenSea). La detección automática de NFT expone su IP y dirección de cuenta a estos servicios. Habilitar esta función podría asociar su dirección IP con su dirección de Ethereum y mostrar NFT enviados mediante airdrop por estafadores. Puede agregar tokens manualmente para evitar este riesgo." + }, "usePhishingDetection": { "message": "Usar detección de phishing" }, "usePhishingDetectionDescription": { "message": "Mostrar una advertencia respecto de los dominios de phishing dirigidos a los usuarios de Ethereum" }, + "useSafeChainsListValidation": { + "message": "Verificación de detalles de la red" + }, + "useSafeChainsListValidationDescription": { + "message": "MetaMask utiliza un servicio de terceros llamado $1 para mostrar detalles de red precisos y estandarizados. Esto reduce las posibilidades de conectarse a una red maliciosa o incorrecta. Al utilizar esta función, su dirección IP queda expuesta a chainid.network." + }, + "useSafeChainsListValidationWebsite": { + "message": "chainid.network", + "description": "useSafeChainsListValidationWebsite is separated from the rest of the text so that we can bold the third party service name in the middle of them" + }, "useSiteSuggestion": { "message": "Usar sugerencia del sitio" }, @@ -4685,6 +5914,9 @@ "userName": { "message": "Nombre de usuario" }, + "userOpContractDeployError": { + "message": "La implementación de contratos desde una cuenta de contrato inteligente no es compatible" + }, "verifyContractDetails": { "message": "Verificar detalles de terceros" }, @@ -4702,6 +5934,9 @@ "view": { "message": "Ver" }, + "viewActivity": { + "message": "Ver actividad" + }, "viewAllDetails": { "message": "Ver todos los detalles" }, @@ -4725,7 +5960,7 @@ }, "viewOnCustomBlockExplorer": { "message": "Ver $1 en $2", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "Ver $1 en Etherscan", @@ -4737,6 +5972,9 @@ "viewOnOpensea": { "message": "Ver en Opensea" }, + "viewTransaction": { + "message": "Ver transacción" + }, "viewinCustodianApp": { "message": "Ver en la aplicación de custodia" }, @@ -4744,6 +5982,9 @@ "message": "Ver $1 en el explorador", "description": "$1 is the action type. e.g (Account, Transaction, Swap)" }, + "visitSite": { + "message": "Visitar sitio" + }, "visitWebSite": { "message": "Visite nuestro sitio web" }, @@ -4782,6 +6023,10 @@ "warning": { "message": "Advertencia" }, + "warningFromSnap": { + "message": "Advertencia de $1", + "description": "$1 represents the name of the snap" + }, "warningTooltipText": { "message": "$1 El tercero podría gastar todo su saldo de tokens sin previo aviso o consentimiento. Protéjase personalizando un límite de gasto más bajo.", "description": "$1 is a warning icon with text 'Be careful' in 'warning' colour" @@ -4789,6 +6034,9 @@ "weak": { "message": "Débil" }, + "web3": { + "message": "Web3" + }, "web3ShimUsageNotification": { "message": "Parece que el sitio web actual intentó utilizar la API de window.web3 que se eliminó. Si el sitio no funciona, haga clic en $1 para obtener más información.", "description": "$1 is a clickable link." @@ -4829,10 +6077,6 @@ "whatsThis": { "message": "¿Qué es esto?" }, - "xOfY": { - "message": "$1 de $2", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$1 de $2 están pendientes", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" @@ -4840,6 +6084,9 @@ "yes": { "message": "Sí" }, + "you": { + "message": "Usted" + }, "youHaveAddedAll": { "message": "Ha agregado todas las redes populares. Puede descubrir más redes $1 o puede $2", "description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'" @@ -4862,6 +6109,12 @@ "yourPrivateSeedPhrase": { "message": "Su frase secreta de recuperación" }, + "yourTransactionConfirmed": { + "message": "Transacción ya confirmada" + }, + "yourTransactionJustConfirmed": { + "message": "No pudimos cancelar su transacción antes de que se confirmara en la cadena de bloques." + }, "zeroGasPriceOnSpeedUpError": { "message": "No hay entradas sobre el precio del gas al acelerar la transacción" } diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index 370c94563e9d..b2f763ced384 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -172,16 +172,10 @@ "alerts": { "message": "Alertas" }, - "allowExternalExtensionTo": { - "message": "Permitir que esta extensión externa haga lo siguiente:" - }, "allowSpendToken": { "message": "¿Dar permiso para acceder a su $1?", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "Permitir que este sitio haga lo siguiente:" - }, "allowWithdrawAndSpend": { "message": "Permitir que se retire $1 y gastar hasta el siguiente importe:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -308,9 +302,6 @@ "cancel": { "message": "Cancelar" }, - "cancelEdit": { - "message": "Cancelar Editar" - }, "cancelPopoverTitle": { "message": "Cancelar transacción" }, @@ -377,26 +368,6 @@ "connectManually": { "message": "Conectarse manualmente al sitio actual" }, - "connectTo": { - "message": "Conectarse a $1", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "Conectarse a todas sus $1", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "cuentas", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "Conectarse a $1", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1 cuentas", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "Conectarse con MetaMask" }, @@ -1410,22 +1381,6 @@ "notEnoughGas": { "message": "No hay gas suficiente" }, - "notifications8ActionText": { - "message": "Ir a Configuración Avanzada", - "description": "Description on an action button that appears in the What's New popup. Tells the user that if they click it, they will go to our Advanced settings page." - }, - "notifications8DescriptionOne": { - "message": "A partir de MetaMask v10.4.0, ya no necesita Ledger Live para conectar su dispositivo Ledger a MetaMask.", - "description": "Description of a notification in the 'See What's New' popup. Describes changes for how Ledger Live is no longer needed to connect the device." - }, - "notifications8DescriptionTwo": { - "message": "Para una experiencia más fácil y estable, vaya a la pestaña de Configuración Avanzada y cambie el 'Tipo de Conexión de Ledger Preferida' a 'WebHID'.", - "description": "Description of a notification in the 'See What's New' popup. Describes how the user can turn off the Ledger Live setting." - }, - "notifications8Title": { - "message": "Mejora de la conexión de Ledger", - "description": "Title for a notification in the 'See What's New' popup. Notifies ledger users that there is an improvement in how they can connect their device." - }, "ofTextNofM": { "message": "de" }, @@ -1487,7 +1442,8 @@ "message": "Un proveedor de red malintencionado puede mentir sobre el estado de la cadena de bloques y registrar su actividad de red. Agregue solo redes personalizadas de confianza." }, "onlyConnectTrust": { - "message": "Conéctese solo con sitios de confianza." + "message": "Conéctese solo con sitios de confianza.", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." }, "openFullScreenForLedgerWebHid": { "message": "Abra MetaMask en pantalla completa para conectar su Ledger a través de WebHID.", @@ -1821,12 +1777,6 @@ "message": "Enviar $1", "description": "Symbol of the specified token" }, - "sendTo": { - "message": "Enviar a" - }, - "sendTokens": { - "message": "Enviar tokens" - }, "sendingDisabled": { "message": "Todavía no se admite el envío de activos ERC-1155 NFT." }, @@ -2543,7 +2493,7 @@ }, "viewOnCustomBlockExplorer": { "message": "Ver $1 en $2", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "Ver $1 en Etherscan", @@ -2618,10 +2568,6 @@ "whatsThis": { "message": "¿Qué es esto?" }, - "xOfY": { - "message": "$1 de $2", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$1 de $2 están pendientes", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" diff --git a/app/_locales/et/messages.json b/app/_locales/et/messages.json index 97d874b47fd8..cba62eb1d7d9 100644 --- a/app/_locales/et/messages.json +++ b/app/_locales/et/messages.json @@ -620,9 +620,6 @@ "send": { "message": "Saada" }, - "sendTokens": { - "message": "Saada lube" - }, "settings": { "message": "Seaded" }, diff --git a/app/_locales/fa/messages.json b/app/_locales/fa/messages.json index 31b99eacb93c..3f2e3a703f01 100644 --- a/app/_locales/fa/messages.json +++ b/app/_locales/fa/messages.json @@ -630,9 +630,6 @@ "send": { "message": "ارسال" }, - "sendTokens": { - "message": "رمزیاب ها را ارسال کنید" - }, "settings": { "message": "تنظیمات" }, diff --git a/app/_locales/fi/messages.json b/app/_locales/fi/messages.json index d3d20b627f20..a907aeedbd9e 100644 --- a/app/_locales/fi/messages.json +++ b/app/_locales/fi/messages.json @@ -627,9 +627,6 @@ "send": { "message": "Lähetä" }, - "sendTokens": { - "message": "Lähetä tietueita" - }, "settings": { "message": "Asetukset" }, diff --git a/app/_locales/fil/messages.json b/app/_locales/fil/messages.json index 7377ecc1b87e..040a687f7633 100644 --- a/app/_locales/fil/messages.json +++ b/app/_locales/fil/messages.json @@ -554,9 +554,6 @@ "send": { "message": "Ipadala" }, - "sendTokens": { - "message": "Magpadala ng Mga Token" - }, "settings": { "message": "Mga Setting" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index d477599060dd..c44d687aeaf6 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -130,12 +130,21 @@ "account": { "message": "Compte" }, + "accountActivity": { + "message": "Activité du compte" + }, + "accountActivityText": { + "message": "Sélectionnez les comptes pour lesquels vous souhaitez recevoir des notifications :" + }, "accountDetails": { "message": "Détails du compte" }, "accountIdenticon": { "message": "Identicon de compte" }, + "accountIsntConnectedToastText": { + "message": "$1 n’est pas connecté à $2" + }, "accountName": { "message": "Nom du compte" }, @@ -153,6 +162,12 @@ "accountSelectionRequired": { "message": "Vous devez sélectionner un compte !" }, + "accounts": { + "message": "Comptes" + }, + "accountsConnected": { + "message": "Comptes connectés" + }, "active": { "message": "Actif" }, @@ -243,6 +258,9 @@ "addIPFSGateway": { "message": "Ajoutez votre passerelle IPFS préférée" }, + "addImportAccount": { + "message": "Ajouter un compte ou un portefeuille matériel" + }, "addMemo": { "message": "Ajouter un mémo" }, @@ -256,6 +274,9 @@ "message": "Cette connexion réseau repose sur des tiers. Elle peut être moins fiable ou permettre à des tiers de suivre l’activité des utilisateurs. $1", "description": "$1 is Learn more link" }, + "addNewAccount": { + "message": "Ajouter un nouveau compte" + }, "addNewToken": { "message": "Ajouter un nouveau jeton" }, @@ -265,6 +286,12 @@ "addNfts": { "message": "Ajouter des NFT" }, + "addSnapAccountToggle": { + "message": "Activer « Ajouter un Snap de compte (bêta) »" + }, + "addSnapAccountsDescription": { + "message": "En activant cette fonctionnalité, vous aurez la possibilité d’ajouter les nouveaux Snaps de compte bêta directement à partir de votre liste de comptes. Veuillez noter que les Snaps de compte sont des services fournis par des tiers." + }, "addSuggestedNFTs": { "message": "Ajouter les NFT suggérés" }, @@ -281,6 +308,9 @@ "addingCustomNetwork": { "message": "Ajout de réseau" }, + "addingTokens": { + "message": "Ajouter des jetons" + }, "address": { "message": "Adresse" }, @@ -316,9 +346,27 @@ "airgapVault": { "message": "Coffre-fort AirGap" }, + "alert": { + "message": "Alerte" + }, + "alertBannerMultipleAlertsDescription": { + "message": "Si vous approuvez cette demande, un tiers connu pour ses activités frauduleuses pourrait s’emparer de tous vos actifs." + }, + "alertBannerMultipleAlertsTitle": { + "message": "Plusieurs alertes !" + }, "alertDisableTooltip": { "message": "Vous pouvez modifier ceci dans « Paramètres > Alertes »" }, + "alertModalAcknowledge": { + "message": "Je suis conscient du risque et je souhaite quand même continuer" + }, + "alertModalDetails": { + "message": "Détails de l’alerte" + }, + "alertModalReviewAllAlerts": { + "message": "Examiner toutes les alertes" + }, "alertSettingsUnconnectedAccount": { "message": "Navigation sur un site Web avec un compte non connecté sélectionné" }, @@ -334,6 +382,9 @@ "alerts": { "message": "Alertes" }, + "all": { + "message": "Tout" + }, "allCustodianAccountsConnectedSubtitle": { "message": "Soit vous avez déjà connecté tous vos comptes dépositaires, soit vous n’avez aucun compte à connecter à MetaMask Institutional." }, @@ -344,23 +395,26 @@ "message": "Tous vos $1", "description": "$1 is the symbol or name of the token that the user is approving spending" }, + "allPermissions": { + "message": "Toutes les autorisations" + }, "allYourNFTsOf": { "message": "Tous vos NFT via $1", "description": "$1 is a link to contract on the block explorer when we're not able to retrieve a erc721 or erc1155 name" }, - "allowExternalExtensionTo": { - "message": "Autoriser cette extension externe à :" + "allow": { + "message": "Autoriser" + }, + "allowMmiToConnectToCustodian": { + "message": "Cela permettra à MMI de se connecter à $1 pour importer vos comptes." + }, + "allowNotifications": { + "message": "Autoriser les notifications" }, "allowSpendToken": { "message": "Donner l’autorisation d’accéder à votre $1 ?", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "Autoriser ce site à :" - }, - "allowThisSnapTo": { - "message": "Autoriser ce snap à :" - }, "allowWithdrawAndSpend": { "message": "Permettre à $1 de retirer et de dépenser jusqu’au montant suivant :", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -368,6 +422,23 @@ "amount": { "message": "Montant" }, + "amountReceived": { + "message": "Montant reçu" + }, + "amountSent": { + "message": "Montant envoyé" + }, + "andForListItems": { + "message": "$1, et $2", + "description": "$1 is the first item, $2 is the last item in a list of items. Used in Snap Install Warning modal." + }, + "andForTwoItems": { + "message": "$1 et $2", + "description": "$1 is the first item, $2 is the second item. Used in Snap Install Warning modal." + }, + "announcements": { + "message": "Annonces" + }, "appDescription": { "message": "Extension Ethereum pour navigateur", "description": "The description of the application" @@ -402,6 +473,10 @@ "approveButtonText": { "message": "Approuver" }, + "approveIncreaseAllowance": { + "message": "Augmenter le plafond des dépenses de $1", + "description": "The token symbol that is being approved" + }, "approveSpendingCap": { "message": "Approuver le plafond de dépenses de $1", "description": "The token symbol that is being approved" @@ -427,6 +502,10 @@ "message": "Approuver le $1", "description": "$1 is the approval date for a permission" }, + "approvedOnForAccounts": { + "message": "Approuvé le $1 pour $2", + "description": "$1 is the approval date for a permission. $2 is the AvatarGroup component displaying account images." + }, "areYouSure": { "message": "En êtes-vous sûr(e) ?" }, @@ -439,12 +518,21 @@ "attemptSendingAssets": { "message": "Si vous essayez d’envoyer des actifs directement d’un réseau à un autre, une perte permanente des actifs pourrait en résulter. Assurez-vous d’utiliser une passerelle." }, + "attemptSendingAssetsWithPortfolio": { + "message": "Si vous essayez d’envoyer des actifs directement d’un réseau à un autre, vous pourriez les perdre définitivement. Utilisez une passerelle comme $1 pour transférer en toute sécurité des fonds d’un réseau à un autre" + }, + "attemptToCancelSwapForFree": { + "message": "Tentative d’annuler gratuitement le swap" + }, "attemptingConnect": { "message": "Tentative de connexion au réseau" }, "attributions": { "message": "Attributions" }, + "auroraRpcDeprecationMessage": { + "message": "L’URL Infura RPC ne prend plus en charge Aurora." + }, "authorizedPermissions": { "message": "Vous avez accordé les autorisations suivantes" }, @@ -477,7 +565,10 @@ "message": "Ce code secret est requis pour récupérer votre portefeuille si jamais vous perdez votre appareil, oubliez votre mot de passe, devez réinstaller MetaMask ou souhaitez accéder à votre portefeuille depuis un autre appareil." }, "backupApprovalNotice": { - "message": "Sauvegardez votre phrase de récupération secret pour garder votre portefeuille et vos fonds en sécurité." + "message": "Sauvegardez votre phrase secrète de récupération pour garder votre portefeuille et vos fonds en sécurité." + }, + "backupKeyringSnapReminder": { + "message": "Assurez-vous que vous pouvez accéder à tous les comptes créés par ce snap avant de le supprimer" }, "backupNow": { "message": "Sauvegarder maintenant" @@ -486,7 +577,7 @@ "message": "Sauvegardez vos données" }, "backupUserDataDescription": { - "message": "Vous pouvez sauvegarder les paramètres de l’utilisateur qui contiennent les préférences et les adresses de compte dans un fichier JSON." + "message": "Vous pouvez sauvegarder des paramètres tels que vos contacts et vos préférences." }, "balance": { "message": "Solde" @@ -500,6 +591,30 @@ "basic": { "message": "Général" }, + "basicConfigurationBannerCTA": { + "message": "Activer la fonctionnalité de base" + }, + "basicConfigurationBannerTitle": { + "message": "La fonctionnalité de base est désactivée" + }, + "basicConfigurationLabel": { + "message": "Fonctionnalité de base" + }, + "basicConfigurationModalCheckbox": { + "message": "Je comprends et je veux continuer" + }, + "basicConfigurationModalDisclaimerOff": { + "message": "Cela signifie que vous n’optimiserez pas complètement votre temps sur MetaMask. Vous n’aurez pas accès aux fonctions de base (comme les détails des jetons, les réglages optimaux du gaz, et autres)." + }, + "basicConfigurationModalDisclaimerOn": { + "message": "Pour optimiser votre temps sur MetaMask, vous devez activer cette fonction. Les fonctions de base (comme les détails des jetons, les réglages optimaux du gaz, et autres) améliorent votre expérience Web3." + }, + "basicConfigurationModalHeadingOff": { + "message": "Désactiver la fonctionnalité de base" + }, + "basicConfigurationModalHeadingOn": { + "message": "Activer la fonctionnalité de base" + }, "beCareful": { "message": "Soyez prudent" }, @@ -571,6 +686,9 @@ "blockaidDescriptionTransferFarming": { "message": "Si vous approuvez cette demande, un tiers connu pour ses activités frauduleuses pourrait s’emparer de tous vos actifs." }, + "blockaidMessage": { + "message": "Protection de la vie privée : aucune donnée n’est partagée avec des tiers. Disponible sur Arbitrum, Avalanche, BNB chain, Linea, Optimism, Polygon, Base, Sepolia et le réseau principal Ethereum." + }, "blockaidTitleDeceptive": { "message": "Cette demande trompeuse" }, @@ -586,6 +704,9 @@ "bridge": { "message": "Pont" }, + "bridgeDontSend": { + "message": "Passerelle, ne pas envoyer" + }, "browserNotSupported": { "message": "Votre navigateur internet n’est pas compatible..." }, @@ -598,6 +719,9 @@ "busy": { "message": "Occupé" }, + "buyAndSell": { + "message": "Acheter et vendre" + }, "buyAsset": { "message": "Acheter $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -609,6 +733,10 @@ "buyNow": { "message": "Achetez maintenant" }, + "buyToken": { + "message": "Acheter des $1", + "description": "$1 is the token symbol" + }, "bytes": { "message": "Octets" }, @@ -618,9 +746,6 @@ "cancel": { "message": "Annuler" }, - "cancelEdit": { - "message": "Annuler la modification" - }, "cancelPopoverTitle": { "message": "Annuler la transaction" }, @@ -647,6 +772,9 @@ "chainIdExistsErrorMsg": { "message": "Cet ID de chaîne est actuellement utilisé par le réseau $1." }, + "chainListReturnedDifferentTickerSymbol": { + "message": "Le symbole de ce jeton ne correspond pas au nom du réseau ou à l’ID de chaîne saisi. De nombreux jetons populaires utilisent des symboles similaires que les escrocs peuvent utiliser pour vous amener à leur envoyer un jeton de plus grande valeur en retour. Veuillez vérifier toutes les informations avant de continuer." + }, "chooseYourNetwork": { "message": "Choisissez votre réseau" }, @@ -682,9 +810,19 @@ "close": { "message": "Fermer" }, + "closeExtension": { + "message": "Fermer l’extension" + }, + "closeWindowAnytime": { + "message": "Vous pouvez fermer cette fenêtre à tout moment." + }, "coingecko": { "message": "CoinGecko" }, + "comboNoOptions": { + "message": "Aucune option trouvée", + "description": "Default text shown in the combo field dropdown if no options." + }, "configureSnapPopupDescription": { "message": "Vous devez maintenant quitter MetaMask pour configurer ce snap." }, @@ -703,12 +841,42 @@ "confirm": { "message": "Confirmer" }, + "confirmAlertModalAcknowledge": { + "message": "J’ai pris connaissance des alertes, mais je souhaite quand même continuer" + }, + "confirmAlertModalDetails": { + "message": "Si vous vous connectez, un tiers connu pour ses activités frauduleuses pourrait s’emparer de tous vos actifs. Veuillez examiner les alertes avant de continuer." + }, + "confirmAlertModalTitle": { + "message": "Vous risquez de perdre tout ou partie de vos actifs" + }, + "confirmConnectCustodianRedirect": { + "message": "Nous vous redirigerons vers $1 une fois que vous cliquerez sur « Continuer »." + }, + "confirmConnectCustodianText": { + "message": "Pour associer vos comptes, connectez-vous à votre compte $1 et cliquez sur le bouton « Se connecter à MMI »." + }, + "confirmConnectionTitle": { + "message": "Confirmer la connexion à $1" + }, "confirmPassword": { "message": "Confirmer le mot de passe" }, "confirmRecoveryPhrase": { "message": "Confirmer la phrase secrète de récupération" }, + "confirmTitleDescContractInteractionTransaction": { + "message": "Ne confirmez cette transaction que si vous comprenez parfaitement son contenu et si vous faites confiance au site demandeur." + }, + "confirmTitleDescSignature": { + "message": "Ne confirmez ce message que si vous approuvez son contenu et faites confiance au site demandeur." + }, + "confirmTitleSignature": { + "message": "Demande de signature" + }, + "confirmTitleTransaction": { + "message": "Demande de transaction" + }, "confirmed": { "message": "Confirmé" }, @@ -724,9 +892,15 @@ "connect": { "message": "Connecter" }, + "connectAccount": { + "message": "Connecter le compte" + }, "connectAccountOrCreate": { "message": "Connecter un compte ou en créer un nouveau" }, + "connectAccounts": { + "message": "Connecter les comptes" + }, "connectCustodialAccountMenu": { "message": "Connexion au compte de dépôt" }, @@ -736,36 +910,25 @@ "connectCustodialAccountTitle": { "message": "Comptes de dépôt" }, + "connectCustodianAccounts": { + "message": "Associer $1 comptes" + }, "connectManually": { "message": "Se connecter manuellement au site actuel" }, + "connectMoreAccounts": { + "message": "Connecter d’autres comptes" + }, "connectSnap": { "message": "Connecter $1", "description": "$1 is the snap for which a connection is being requested." }, - "connectTo": { - "message": "Connectez-vous à $1", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "Connectez-vous à vos $1", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "comptes", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "Connectez-vous à $1", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1 comptes", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "Connectez-vous avec MetaMask" }, + "connectedAccounts": { + "message": "Comptes connectés" + }, "connectedAccountsDescriptionPlural": { "message": "Vous avez $1 comptes connectés à ce site.", "description": "$1 is the number of accounts" @@ -776,6 +939,13 @@ "connectedAccountsEmptyDescription": { "message": "MetaMask n’est pas connecté à ce site. Pour vous connecter à un site web3, cliquez sur le bouton de connexion." }, + "connectedAccountsListTooltip": { + "message": "$1 peut voir le solde, l’adresse et l’activité du compte, et suggérer des transactions à approuver pour les comptes connectés.", + "description": "$1 is the origin name" + }, + "connectedAccountsToast": { + "message": "Les comptes connectés ont été mis à jour" + }, "connectedSites": { "message": "Sites connectés" }, @@ -787,12 +957,21 @@ "message": "$1 n’est connecté à aucun site.", "description": "$1 is the account name" }, + "connectedSnapAndNoAccountDescription": { + "message": "MetaMask est connecté à ce site, mais aucun compte n’est encore connecté" + }, + "connectedWith": { + "message": "Connecté avec" + }, "connecting": { "message": "Connexion…" }, "connectingTo": { "message": "Connexion à $1" }, + "connectingToDeprecatedNetwork": { + "message": "Le réseau « $1 » sera bientôt abandonné et pourrait ne plus fonctionner. Essayez-en un autre." + }, "connectingToGoerli": { "message": "Connexion au testnet Goerli" }, @@ -802,6 +981,9 @@ "connectingToLineaMainnet": { "message": "Connexion au réseau principal de Linea" }, + "connectingToLineaSepolia": { + "message": "Connexion au réseau de test Linea Sepolia" + }, "connectingToMainnet": { "message": "Connexion au réseau principal Ethereum" }, @@ -831,6 +1013,12 @@ "continue": { "message": "Continuer" }, + "continueMmiOnboarding": { + "message": "Poursuivre le processus d’intégration de MetaMask Institutional" + }, + "continueToWallet": { + "message": "Accéder au portefeuille" + }, "contract": { "message": "Contrat" }, @@ -882,6 +1070,9 @@ "copyAddress": { "message": "Copier l’addresse dans le presse-papier" }, + "copyPrivateKey": { + "message": "Copier la clé privée" + }, "copyRawTransactionData": { "message": "Copier les données brutes de la transaction" }, @@ -900,6 +1091,15 @@ "createPassword": { "message": "Créer un mot de passe" }, + "createSnapAccountDescription": { + "message": "$1 veut ajouter un nouveau compte à MetaMask." + }, + "createSnapAccountTitle": { + "message": "Créer un compte" + }, + "crossChainSwapsLink": { + "message": "Échanges inter-réseaux avec MetaMask Portfolio" + }, "cryptoCompare": { "message": "CryptoCompare" }, @@ -953,7 +1153,13 @@ "message": "Vous pouvez maintenant utiliser vos comptes de dépôt dans MetaMask Institutional." }, "custodianAccountAddedTitle": { - "message": "Les comptes de dépôt sélectionnés ont été ajoutés." + "message": "Les comptes de dépôt $1 sélectionnés ont été ajoutés." + }, + "custodianQRCodeScan": { + "message": "Scannez le code QR avec votre application mobile $1" + }, + "custodianQRCodeScanDescription": { + "message": "Ou connectez-vous à votre compte $1 et cliquez sur le bouton « Se connecter à MMI »" }, "custodianReplaceRefreshTokenChangedFailed": { "message": "Accédez à $1 et cliquez sur le bouton « Se connecter à MMI » dans l’interface utilisateur pour reconnecter vos comptes à MMI." @@ -1017,7 +1223,7 @@ "message": "La détection de token n’est pas encore disponible sur ce réseau. Veuillez importer le token manuellement et vous assurer que vous lui faites bien confiance. En savoir plus sur $1" }, "customTokenWarningInTokenDetectionNetwork": { - "message": "Veuillez vous assurer que le jeton est authentique avant de l’importer. En savoir plus sur $1" + "message": "Tout un chacun peut créer un jeton, y compris créer de fausses copies de jetons existants. En savoir plus sur $1" }, "customTokenWarningInTokenDetectionNetworkWithTDOFF": { "message": "Veuillez vous assurer que le jeton est authentique avant de l’importer. Apprenez à éviter $1. Vous pouvez également activer la détection des jetons $2." @@ -1025,6 +1231,12 @@ "customerSupport": { "message": "service client" }, + "customizeYourNotifications": { + "message": "Personnalisez vos notifications" + }, + "customizeYourNotificationsText": { + "message": "Activez les types de notifications que vous souhaitez recevoir :" + }, "dappRequestedSpendingCap": { "message": "Plafond de dépenses demandé par le site" }, @@ -1108,6 +1320,18 @@ "deposit": { "message": "Effectuez un dépôt" }, + "deprecatedGoerliNtwrkMsg": { + "message": "Les mises à jour du système Ethereum rendront bientôt le testnet Goerli obsolète." + }, + "deprecatedNetwork": { + "message": "Ce réseau est obsolète" + }, + "deprecatedNetworkButtonMsg": { + "message": "J’ai compris" + }, + "deprecatedNetworkDescription": { + "message": "Le réseau auquel vous essayez de vous connecter n’est plus pris en charge par Metamask. $1" + }, "description": { "message": "Description" }, @@ -1115,110 +1339,20 @@ "message": "Description provenant de $1", "description": "$1 represents the name of the snap" }, - "desktopApp": { - "message": "Application de bureau" - }, - "desktopConnectionCriticalErrorDescription": { - "message": "Cette erreur peut être passagère – essayez de redémarrer l’extension ou de désactiver MetaMask Desktop." - }, - "desktopConnectionCriticalErrorTitle": { - "message": "MetaMask a rencontré des difficultés à démarrer" - }, - "desktopConnectionLostErrorDescription": { - "message": "Veuillez vérifier que l’application de bureau est opérationnelle ou désactivez MetaMask Desktop." - }, - "desktopConnectionLostErrorTitle": { - "message": "La connexion à MetaMask Desktop a été perdue" - }, - "desktopDisableButton": { - "message": "Désactiver l’application Desktop" - }, - "desktopDisableErrorCTA": { - "message": "Désactiver MetaMask Desktop" - }, - "desktopEnableButton": { - "message": "Activer l’application Desktop" - }, - "desktopEnableButtonDescription": { - "message": "Cliquez pour exécuter tous les processus d’arrière-plan dans l’application de bureau." - }, - "desktopErrorNavigateSettingsCTA": { - "message": "Retour à la page des paramètres (« Settings »)" - }, - "desktopErrorRestartMMCTA": { - "message": "Redémarrer MetaMask" - }, - "desktopNotFoundErrorCTA": { - "message": "Télécharger MetaMask Desktop" - }, - "desktopNotFoundErrorDescription1": { - "message": "Veuillez vous assurer que l’application de bureau est installée et qu’elle fonctionne." - }, - "desktopNotFoundErrorDescription2": { - "message": "Si vous n’avez pas installé l’application de bureau, veuillez la télécharger sur le site Web de MetaMask." - }, - "desktopNotFoundErrorTitle": { - "message": "MetaMask Desktop est introuvable" - }, - "desktopOpenOrDownloadCTA": { - "message": "Ouvrir MetaMask Desktop" - }, - "desktopOutdatedErrorCTA": { - "message": "Mettre à jour MetaMask Desktop" - }, - "desktopOutdatedErrorDescription": { - "message": "Votre application MetaMask Desktop doit être mise à jour." - }, - "desktopOutdatedErrorTitle": { - "message": "MetaMask Desktop est obsolète" - }, - "desktopOutdatedExtensionErrorCTA": { - "message": "Mettre à jour l’extension MetaMask" - }, - "desktopOutdatedExtensionErrorDescription": { - "message": "Votre extension MetaMask doit être mise à jour." - }, - "desktopOutdatedExtensionErrorTitle": { - "message": "L’extension MetaMask est obsolète" - }, - "desktopPageDescription": { - "message": "Si le couplage est réussi, l’extension redémarrera et vous devrez saisir à nouveau votre mot de passe." - }, - "desktopPageSubTitle": { - "message": "Ouvrez votre application MetaMask Desktop et saisissez ce code" - }, - "desktopPageTitle": { - "message": "Couplage avec Desktop" - }, - "desktopPairedWarningDeepLink": { - "message": "Allez dans les paramètres (« Settings ») de MetaMask Desktop" - }, - "desktopPairedWarningDescription": { - "message": "Si vous souhaitez lancer un nouveau couplage, veuillez supprimer la connexion actuelle." - }, - "desktopPairedWarningTitle": { - "message": "MM Desktop est déjà couplée" - }, - "desktopPairingExpireMessage": { - "message": "Le code expire dans $1 secondes" - }, - "desktopRouteNotFoundErrorDescription": { - "message": "desktopRouteNotFoundErrorDescription" - }, - "desktopRouteNotFoundErrorTitle": { - "message": "desktopRouteNotFoundErrorTitle" + "details": { + "message": "Détails" }, - "desktopUnexpectedErrorCTA": { - "message": "Retour à la page d’accueil (« Home ») de MetaMask" + "developerOptions": { + "message": "Options pour les développeurs" }, - "desktopUnexpectedErrorDescription": { - "message": "Vérifiez votre application MetaMask Desktop pour rétablir la connexion" + "developerOptionsResetStatesAnnouncementsDescription": { + "message": "Règle la valeur de « isShown boolean » sur faux (false) pour toutes les annonces. Les annonces sont les notifications affichées dans la fenêtre contextuelle « Nouveautés »." }, - "desktopUnexpectedErrorTitle": { - "message": "Nous avons eu un problème…" + "developerOptionsResetStatesOnboarding": { + "message": "Réinitialise divers états liés au processus d’intégration et redirige vers la page d’accueil « Sécuriser votre portefeuille »." }, - "details": { - "message": "Détails" + "developerOptionsServiceWorkerKeepAlive": { + "message": "Les résultats d’un horodatage sont continuellement sauvegardés dans « session.storage »" }, "disabledGasOptionToolTipMessage": { "message": "« $1 » est désactivé parce qu’il ne correspond pas au minimum d’augmentation de 10 % par rapport aux gas fees initiaux.", @@ -1233,12 +1367,38 @@ "disconnectAllAccountsConfirmationDescription": { "message": "Souhaitez-vous vraiment vous déconnecter ? Vous risquez de perdre certaines fonctionnalités du site." }, + "disconnectAllAccountsText": { + "message": "comptes" + }, + "disconnectAllSnapsText": { + "message": "Snaps" + }, + "disconnectAllText": { + "message": "Si vous déconnectez vos $1 de $2, vous devrez vous reconnecter pour les utiliser à nouveau.", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`, $2 represents the website hostname" + }, + "disconnectAllTitle": { + "message": "Déconnecter tous les $1", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`" + }, "disconnectPrompt": { "message": "Déconnecter $1" }, "disconnectThisAccount": { "message": "Déconnecter ce compte" }, + "disconnectedAllAccountsToast": { + "message": "Tous les comptes ont été déconnectés de $1", + "description": "$1 is name of the dapp`" + }, + "disconnectedSingleAccountToast": { + "message": "$1 déconnecté de $2", + "description": "$1 is name of the name and $2 represents the dapp name`" + }, + "discoverSnaps": { + "message": "Découvrir des Snaps", + "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." + }, "dismiss": { "message": "Annuler" }, @@ -1248,9 +1408,21 @@ "dismissReminderField": { "message": "Annuler le rappel de sauvegarde de la phrase secrète de récupération" }, + "displayNftMedia": { + "message": "Afficher les médias NFT" + }, + "displayNftMediaDescription": { + "message": "L’affichage des médias et des données NFT expose votre adresse IP à OpenSea ou à d’autres fournisseurs de services tiers. Cela permet à des hackers d’associer votre adresse IP à votre adresse Ethereum. La détection automatique des NFT dépend de ce paramètre et ne sera pas disponible lorsque celui-ci est désactivé." + }, + "doNotShare": { + "message": "Ne partagez ceci avec personne" + }, "domain": { "message": "Domaine" }, + "domainNotSupportedOnNetwork": { + "message": "Le réseau ne prend pas en charge la recherche de noms de domaine" + }, "done": { "message": "Terminé" }, @@ -1269,6 +1441,9 @@ "downloadStateLogs": { "message": "Télécharger les journaux d’événements" }, + "dragAndDropBanner": { + "message": "Vous pouvez faire glisser les réseaux pour les réorganiser. " + }, "dropped": { "message": "Déconnecté" }, @@ -1367,6 +1542,9 @@ "editSpeedUpEditGasFeeModalTitle": { "message": "Modifier les gas fees d’accélération" }, + "enable": { + "message": "Activer" + }, "enableAutoDetect": { "message": " Activer la détection automatique" }, @@ -1397,6 +1575,18 @@ "enhancedTokenDetectionAlertMessage": { "message": "La détection améliorée des jetons est actuellement disponible sur $1. $2" }, + "ensDomainsSettingDescriptionIntroduction": { + "message": "MetaMask vous permet de voir les domaines ENS dans la barre d’adresse de votre navigateur. Voici comment cela fonctionne :" + }, + "ensDomainsSettingDescriptionOutroduction": { + "message": "Veuillez noter que l’utilisation de cette fonctionnalité expose votre adresse IP à des services tiers IPFS." + }, + "ensDomainsSettingDescriptionPart1": { + "message": "MetaMask vérifie le contrat ENS d’Ethereum pour trouver le code lié au nom de domaine ENS." + }, + "ensDomainsSettingDescriptionPart2": { + "message": "Si le code renvoie à un IPFS, vous pouvez voir le contenu qui y est associé (généralement un site web)." + }, "ensDomainsSettingTitle": { "message": "Afficher les domaines ENS dans la barre d’adresse" }, @@ -1438,6 +1628,9 @@ "message": "Détails de l’erreur", "description": "Title for collapsible section that displays error details for debugging purposes" }, + "errorGettingSafeChainList": { + "message": "Erreur lors de l’obtention de la liste des chaînes sécurisées, veuillez continuer avec précaution." + }, "errorMessage": { "message": "Message : $1", "description": "Displayed error message for debugging purposes. $1 is the error message" @@ -1469,6 +1662,9 @@ "message": "Erreur avec $1", "description": "$1 represents the name of the snap" }, + "estimatedFee": { + "message": "Frais estimés" + }, "ethGasPriceFetchWarning": { "message": "Le prix de carburant de sauvegarde est fourni, car le service principal d’estimation du carburant est momentanément indisponible." }, @@ -1495,12 +1691,24 @@ "message": "Expérimental" }, "extendWalletWithSnaps": { - "message": "Personnalisez votre expérience de portefeuille.", + "message": "Explorez les Snaps créés par la communauté pour personnaliser votre expérience web3", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "extensionInsallCompleteDescription": { + "message": "Retournez à la page d’intégration des produits MetaMask Institutional pour connecter vos compte-titres ou vos comptes de dépôt." + }, + "extensionInsallCompleteTitle": { + "message": "L’extension a été installée avec succès" + }, "externalExtension": { "message": "Extension externe" }, + "externalNameSourcesSetting": { + "message": "Pseudonymes proposés" + }, + "externalNameSourcesSettingDescription": { + "message": "Nous récupérons les pseudonymes proposés pour les adresses avec lesquelles vous interagissez auprès de sources tierces telles que Etherscan, Infura et Lens Protocol. Ces sources pourront voir ces adresses et votre adresse IP. L’adresse de votre compte ne sera pas divulguée à des tiers." + }, "failed": { "message": "Échec" }, @@ -1519,6 +1727,9 @@ "feeAssociatedRequest": { "message": "Des frais sont associés à cette demande." }, + "feeDetails": { + "message": "Détails des frais" + }, "fiat": { "message": "FIAT", "description": "Exchange type" @@ -1551,6 +1762,9 @@ "message": "J’accepte les risques", "description": "this text is shown on a button, which the user presses to confirm they understand the risks of using Flask" }, + "floatAmountToken": { + "message": "Le nombre de jetons doit être un nombre entier" + }, "followUsOnTwitter": { "message": "Suivez-nous sur Twitter" }, @@ -1573,6 +1787,9 @@ "fromTokenLists": { "message": "À partir des listes de tokens : $1" }, + "function": { + "message": "Fonction : $1" + }, "functionApprove": { "message": "Fonction : approuver" }, @@ -1582,6 +1799,13 @@ "functionType": { "message": "Type de fonction" }, + "fundYourWallet": { + "message": "Approvisionnez votre portefeuille" + }, + "fundYourWalletDescription": { + "message": "Commencez par ajouter quelques $1 à votre portefeuille.", + "description": "$1 is the token symbol" + }, "gas": { "message": "Carburant" }, @@ -1592,6 +1816,9 @@ "message": "Ce prix de carburant a été suggéré par $1. Si vous n’en tenez pas compte, vous risquez de rencontrer des difficultés lors de votre transaction. Veuillez contacter $1 pour toute question.", "description": "$1 represents the Dapp's origin" }, + "gasIsETH": { + "message": "Le gaz est $1 " + }, "gasLimit": { "message": "Montant maximal des frais de transaction" }, @@ -1636,6 +1863,9 @@ "message": "$1 h", "description": "$1 represents a number of hours" }, + "gasTimingLow": { + "message": "Lente" + }, "gasTimingMinutesShort": { "message": "$1 min", "description": "$1 represents a number of minutes" @@ -1650,18 +1880,29 @@ "general": { "message": "Général" }, + "generalCameraError": { + "message": "Impossible d’accéder à votre appareil photo. Veuillez réessayer." + }, + "generalCameraErrorTitle": { + "message": "Quelque chose a mal tourné…" + }, "genericExplorerView": { "message": "Afficher le compte sur $1" }, - "globalTitle": { - "message": "Menu global" + "getStartedWithNFTs": { + "message": "Obtenez des $1 pour acheter des NFT", + "description": "$1 is the token symbol" }, - "globalTourDescription": { - "message": "Voyez votre portfolio, vos sites connectés, vos paramètres, et bien plus encore" + "getStartedWithNFTsDescription": { + "message": "Débutez avec les NFT en ajoutant quelques $1 à votre portefeuille.", + "description": "$1 is the token symbol" }, "goBack": { "message": "Retour" }, + "goToSite": { + "message": "Accéder au site" + }, "goerli": { "message": "Testnet Goerli" }, @@ -1703,15 +1944,24 @@ "hexData": { "message": "Données Hex" }, + "hiddenAccounts": { + "message": "Comptes cachés" + }, "hide": { "message": "Masquer" }, + "hideAccount": { + "message": "Compte caché" + }, "hideFullTransactionDetails": { "message": "Masquer tous les détails de la transaction" }, "hideSeedPhrase": { "message": "Masquer la phrase mnémonique" }, + "hideSentitiveInfo": { + "message": "Masquer les informations sensibles" + }, "hideToken": { "message": "Masquer le token" }, @@ -1785,7 +2035,7 @@ "message": "appuyez longuement pour révéler le cercle déverrouillé" }, "id": { - "message": "Identifiant" + "message": "ID" }, "ignoreAll": { "message": "Ignorer tout" @@ -1793,6 +2043,9 @@ "ignoreTokenWarning": { "message": "Si vous masquez des jetons, ils n’apparaîtront pas dans votre portefeuille. Cependant, vous pouvez toujours les ajouter en les recherchant." }, + "imToken": { + "message": "imToken" + }, "import": { "message": "Importer", "description": "Button to import an account from a selected file" @@ -1851,6 +2104,9 @@ "importTokensCamelCase": { "message": "Importer des jetons" }, + "importTokensError": { + "message": "Impossible d’importer les jetons. Veuillez ressayer plus tard." + }, "importWithCount": { "message": "Importer $1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -1869,6 +2125,9 @@ "initialTransactionConfirmed": { "message": "Votre transaction initiale a été confirmée par le réseau. Cliquez sur OK pour retourner à l’écran précédent." }, + "inlineAlert": { + "message": "Alerte" + }, "inputLogicEmptyState": { "message": "N'entrez qu'une somme que vous pouvez accepter que le tiers dépense aujourd'hui ou à l'avenir. Vous pourrez toujours augmenter le plafond de dépenses ultérieurement." }, @@ -1879,6 +2138,27 @@ "inputLogicHigherNumber": { "message": "Cela permet au tiers de dépenser tout votre solde de jetons jusqu'à ce qu'il atteigne le plafond ou que vous révoquiez le plafond de dépenses. Si ce n'est pas votre intention, envisagez de fixer un plafond de dépenses plus bas." }, + "insightWarning": { + "message": "avertissement" + }, + "insightWarningCheckboxMessage": { + "message": "$1 la demande de $2", + "description": "$1 is the action i.e. sign, confirm. $2 is the origin making the request." + }, + "insightWarningContentPlural": { + "message": "Vérifiez les $1 avant de $2. Vous ne pouvez retirer votre consentement, une fois la $3 validée.", + "description": "$1 the 'insightWarnings' message (2 warnings) representing warnings, $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningContentSingular": { + "message": "Vérifiez les $1 avant de $2. Vous ne pouvez retirer votre consentement, une fois la $3 validée.", + "description": "$1 is the 'insightWarning' message (1 warning), $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningHeader": { + "message": "Cette demande peut être dangereuse" + }, + "insightWarnings": { + "message": "avertissements" + }, "insightsFromSnap": { "message": "Aperçus $1", "description": "$1 represents the name of the snap" @@ -1886,9 +2166,18 @@ "install": { "message": "Installez" }, + "installExtension": { + "message": "Installer l’extension" + }, + "installExtensionDescription": { + "message": "La version est conforme aux normes institutionnelles du principal fournisseur de portefeuilles Web3 au monde, MetaMask." + }, "installOrigin": { "message": "Installer Origin" }, + "installRequest": { + "message": "Ajouter à MetaMask" + }, "installedOn": { "message": "Installé le $1", "description": "$1 is the date when the snap has been installed" @@ -1917,6 +2206,12 @@ "insufficientTokens": { "message": "Jetons insuffisants." }, + "interactingWith": { + "message": "Interagir avec" + }, + "interactingWithTransactionDescription": { + "message": "Ceci est le contrat avec lequel vous interagissez. Vérifiez les détails pour éviter les arnaques." + }, "invalidAddress": { "message": "Adresse invalide" }, @@ -1989,6 +2284,9 @@ "ipfsToggleModalSettings": { "message": "Paramètres > Sécurité et confidentialité" }, + "isSigningOrSubmitting": { + "message": "Une transaction antérieure est toujours en cours de signature ou d’envoi" + }, "jazzAndBlockies": { "message": "Les Jazzicons et les Blockies sont deux styles différents d’icônes uniques qui vous aident à identifier un compte en un coup d’œil." }, @@ -2002,6 +2300,24 @@ "message": "Fichier JSON", "description": "format for importing an account" }, + "keyringAccountName": { + "message": "Nom du compte" + }, + "keyringAccountPublicAddress": { + "message": "Adresse publique" + }, + "keyringSnapRemovalResult1": { + "message": "$1 $2 supprimé", + "description": "Displays the result after removal of a keyring snap. $1 is the snap name, $2 is whether it is successful or not" + }, + "keyringSnapRemovalResultNotSuccessful": { + "message": "pas ", + "description": "Displays the `not` word in $2." + }, + "keyringSnapRemoveConfirmation": { + "message": "Saisissez $1 pour confirmer que vous souhaitez supprimer ce snap :", + "description": "Asks user to input the name nap prior to deleting the snap. $1 is the snap name" + }, "keystone": { "message": "Keystone" }, @@ -2020,9 +2336,15 @@ "lastSold": { "message": "Dernière vente" }, + "lavaDomeCopyWarning": { + "message": "Pour votre sécurité, vous ne pouvez pas sélectionner ce texte actuellement." + }, "layer1Fees": { "message": "Frais de couche 1 (L1)" }, + "layer2Fees": { + "message": "Frais de couche 2" + }, "learnCancelSpeeedup": { "message": "Découvrir comment $1", "description": "$1 is link to cancel or speed up transactions" @@ -2040,9 +2362,21 @@ "learnMoreUpperCase": { "message": "En savoir plus" }, + "learnMoreUpperCaseWithDot": { + "message": "En savoir plus." + }, "learnScamRisk": { "message": "hameçonnages et risques de sécurité." }, + "learnToBridge": { + "message": "Apprenez à établir une passerelle" + }, + "leaveMetaMask": { + "message": "Voulez-vous quitter MetaMask ?" + }, + "leaveMetaMaskDesc": { + "message": "Vous allez visiter un site externe à MetaMask. Vérifiez l’URL avant de continuer." + }, "ledgerAccountRestriction": { "message": "Vous devez d’abord utiliser le dernier compte que vous avez créé avant de pouvoir en ajouter un nouveau." }, @@ -2061,6 +2395,18 @@ "ledgerDeviceOpenFailureMessage": { "message": "Le dispositif Ledger n’a pas pu s’ouvrir. Il est peut-être connecté à d’autres logiciels. Veuillez fermer Ledger Live ou toute autre application déjà connectée à celui-ci, puis essayez de vous reconnecter." }, + "ledgerErrorConnectionIssue": { + "message": "Reconnectez votre Ledger, ouvrez l’application ETH et réessayez." + }, + "ledgerErrorDevicedLocked": { + "message": "Votre Ledger est verrouillé. Déverrouillez-le et réessayez." + }, + "ledgerErrorEthAppNotOpen": { + "message": "Pour résoudre le problème, ouvrez l’application ETH sur votre appareil et réessayez." + }, + "ledgerErrorTransactionDataNotPadded": { + "message": "Les données d’entrée de la transaction Ethereum ne sont pas suffisamment étoffées." + }, "ledgerLiveApp": { "message": "Appli Ledger Live" }, @@ -2080,6 +2426,9 @@ "lightTheme": { "message": "Clair" }, + "likeToImportToken": { + "message": "Voulez-vous importer ce jeton ?" + }, "likeToImportTokens": { "message": "Souhaitez-vous ajouter ces jetons ?" }, @@ -2089,6 +2438,9 @@ "lineaMainnet": { "message": "Le réseau principal de Linea" }, + "lineaSepolia": { + "message": "Réseau de test Linea Sepolia" + }, "link": { "message": "Associer" }, @@ -2101,8 +2453,11 @@ "loading": { "message": "Chargement..." }, - "loadingNFTs": { - "message": "Chargement des NFT..." + "loadingScreenHardwareWalletMessage": { + "message": "Veuillez conclure la transaction sur le portefeuille matériel." + }, + "loadingScreenSnapMessage": { + "message": "Veuillez conclure la transaction sur le snap." }, "loadingTokens": { "message": "Chargement des jetons..." @@ -2149,6 +2504,9 @@ "message": "Assurez-vous que personne ne regarde votre écran", "description": "Warning to users to be care while creating and saving their new Secret Recovery Phrase" }, + "manageInSettings": { + "message": "Gérer dans les paramètres" + }, "max": { "message": "Max." }, @@ -2183,15 +2541,34 @@ "metaMaskConnectStatusParagraphTwo": { "message": "Le bouton d’état de connexion indique si le site Web que vous visitez est connecté à votre compte actuellement sélectionné." }, + "metadataModalSourceTooltip": { + "message": "$1 est hébergé sur npm et $2 est l’identifiant unique de ce Snap.", + "description": "$1 is the snap name and $2 is the snap NPM id." + }, "metamaskInstitutionalVersion": { "message": "Version MetaMask Institutional" }, + "metamaskNotificationsAreOff": { + "message": "Les notifications du portefeuille ne sont actuellement pas activées." + }, + "metamaskPortfolio": { + "message": "Portfolio MetaMask." + }, "metamaskSwapsOfflineDescription": { "message": "MetaMask Swaps est en cours de maintenance. Nous vous invitons à revenir plus tard." }, "metamaskVersion": { "message": "Version de MetaMask" }, + "methodData": { + "message": "Méthode" + }, + "methodDataTransactionDescription": { + "message": "Il s’agit de l’action spécifique qui sera entreprise. Ces données peuvent être falsifiées. Alors veillez à ce que le site qui se trouve à l’autre bout soit digne de confiance." + }, + "methodNotSupported": { + "message": "Non pris en charge par ce compte." + }, "metrics": { "message": "Indicateurs" }, @@ -2227,11 +2604,17 @@ "mmiBuiltAroundTheWorld": { "message": "MetaMask Institutional est conçu et établi dans le monde entier." }, + "mmiNewNFTDetectedInNFTsTabMessage": { + "message": "Laissez MetaMask Institutional détecter et afficher automatiquement les NFT dans votre portefeuille." + }, + "mmiPasswordSetupDetails": { + "message": "Ce mot de passe déverrouillera uniquement votre extension MetaMask Institutional." + }, "more": { "message": "plus" }, "multipleSnapConnectionWarning": { - "message": "$1 veut se connecter avec $2 snaps. Ne procédez que si vous avez confiance dans ce site web.", + "message": "$1 veut utiliser $2 Snaps", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." }, "mustSelectOne": { @@ -2240,10 +2623,80 @@ "name": { "message": "Nom" }, + "nameAddressLabel": { + "message": "Adresse", + "description": "Label above address field in name component modal." + }, + "nameInstructionsNew": { + "message": "Si vous connaissez cette adresse, donnez-lui un pseudonyme pour l’identifier plus facilement à l’avenir.", + "description": "Instruction text in name component modal when value is not recognised." + }, + "nameInstructionsRecognized": { + "message": "Cette adresse a un pseudonyme par défaut, mais vous pouvez le modifier ou consulter la liste des pseudonymes proposés.", + "description": "Instruction text in name component modal when value is recognized but not saved." + }, + "nameInstructionsSaved": { + "message": "Vous avez déjà choisi un pseudonyme pour cette adresse. Vous pouvez le modifier ou consulter la liste des pseudonymes proposés.", + "description": "Instruction text in name component modal when value is saved." + }, + "nameLabel": { + "message": "Pseudonyme", + "description": "Label above name input field in name component modal." + }, + "nameModalMaybeProposedName": { + "message": "Peut-être : $1", + "description": "$1 is the proposed name" + }, + "nameModalTitleNew": { + "message": "Adresse inconnue", + "description": "Title of the modal created by the name component when value is not recognised." + }, + "nameModalTitleRecognized": { + "message": "Adresse reconnue", + "description": "Title of the modal created by the name component when value is recognized but not saved." + }, + "nameModalTitleSaved": { + "message": "Adresse enregistrée", + "description": "Title of the modal created by the name component when value is saved." + }, + "nameProviderProposedBy": { + "message": "Proposé par $1", + "description": "$1 is the name of the provider" + }, + "nameProvider_ens": { + "message": "Service de noms Ethereum (ENS)" + }, + "nameProvider_etherscan": { + "message": "Etherscan" + }, + "nameProvider_lens": { + "message": "Lens Protocol" + }, + "nameProvider_token": { + "message": "MetaMask" + }, + "nameSetPlaceholder": { + "message": "Choisissez un pseudonyme…", + "description": "Placeholder text for name input field in name component modal." + }, + "nativePermissionRequestDescription": { + "message": "Voulez-vous que ce site fasse ce qui suit ?", + "description": "Description below header used on Permission Connect screen for native permissions." + }, "nativeToken": { "message": "Le jeton natif de ce réseau est $1. C’est le jeton utilisé pour les frais de gaz.\n", "description": "$1 represents the name of the native token on the current network" }, + "nativeTokenScamWarningConversion": { + "message": "Modifier les détails du réseau" + }, + "nativeTokenScamWarningDescription": { + "message": "L’ID ou le nom de la chaîne associée à ce réseau n’est pas correct. De nombreux jetons populaires utilisent le nom $1, ce qui en fait une cible pour les escrocs. Vérifiez tout avant de continuer, car vous risquez de vous faire arnaquer.", + "description": "$1 represents the currency name" + }, + "nativeTokenScamWarningTitle": { + "message": "Il pourrait s’agir d’une arnaque" + }, "needHelp": { "message": "Vous avez besoin d’aide ? Contactez $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -2264,6 +2717,9 @@ "negativeETH": { "message": "Vous ne pouvez envoyer des montants négatifs d’ETH." }, + "negativeOrZeroAmountToken": { + "message": "Impossible d’envoyer des montants négatifs ou nuls." + }, "network": { "message": "Réseau :" }, @@ -2294,6 +2750,9 @@ "networkNameBSC": { "message": "BSC" }, + "networkNameBase": { + "message": "Base" + }, "networkNameDefinition": { "message": "Le nom associé à ce réseau." }, @@ -2303,12 +2762,21 @@ "networkNameGoerli": { "message": "Goerli" }, + "networkNameLinea": { + "message": "Linea" + }, + "networkNameOpMainnet": { + "message": "Réseau principal OP" + }, "networkNamePolygon": { "message": "Polygon" }, "networkNameTestnet": { "message": "Testnet" }, + "networkNameZkSyncEra": { + "message": "zkSync Era" + }, "networkProvider": { "message": "Fournisseur de réseau" }, @@ -2361,6 +2829,19 @@ "newContract": { "message": "Nouveau contrat" }, + "newNFTDetectedInImportNFTsMessageStrongText": { + "message": "Paramètres > Sécurité et confidentialité" + }, + "newNFTDetectedInImportNFTsMsg": { + "message": "Pour afficher vos NFT en utilisant Opensea, activez l’option « Afficher les supports NFT » dans $1.", + "description": "$1 is used for newNFTDetectedInImportNFTsMessageStrongText" + }, + "newNFTDetectedInNFTsTabMessage": { + "message": "Laissez MetaMask détecter et afficher automatiquement les NFT dans votre portefeuille." + }, + "newNFTsAutodetected": { + "message": "Détection automatique des NFT" + }, "newNetworkAdded": { "message": "« $1 » a été ajouté avec succès !" }, @@ -2370,6 +2851,12 @@ "newPassword": { "message": "Nouveau mot de passe (min 8 caractères)" }, + "newPrivacyPolicyActionButton": { + "message": "En savoir plus" + }, + "newPrivacyPolicyTitle": { + "message": "Nous avons mis à jour notre politique de confidentialité" + }, "newTokensImportedMessage": { "message": "Vous avez importé avec succès $1.", "description": "$1 is the string of symbols of all the tokens imported" @@ -2391,6 +2878,9 @@ "message": "Ce token est un NFT. Ajouter sur la $1", "description": "$1 is a clickable link with text defined by the 'importNFTPage' key" }, + "nftAlreadyAdded": { + "message": "Le NFT a déjà été ajouté." + }, "nftDisclaimer": { "message": "Avertissement : MetaMask importe le fichier multimédia de l'URL source. Cette URL est parfois modifiée par la place de marché sur laquelle le NFT a été frappé." }, @@ -2426,12 +2916,21 @@ "noAddressForName": { "message": "Aucune adresse n’a été définie pour ce nom." }, + "noConnectedAccountDescription": { + "message": "Sélectionnez un compte que vous souhaitez utiliser sur ce site pour continuer." + }, + "noConnectedAccountTitle": { + "message": "MetaMask n’est pas connecté à ce site" + }, "noConversionDateAvailable": { "message": "Aucune date de conversion des devises n’est disponible" }, "noConversionRateAvailable": { "message": "Aucun taux de conversion disponible" }, + "noDomainResolution": { + "message": "Aucune résolution n’a été fournie pour le domaine." + }, "noNFTs": { "message": "Aucun NFT pour le moment" }, @@ -2450,6 +2949,9 @@ "noWebcamFoundTitle": { "message": "Webcam introuvable" }, + "nonCustodialAccounts": { + "message": "MetaMask Institutional vous permet d’utiliser des comptes de détention en propre pour sauvegarder la phrase secrète de récupération." + }, "nonce": { "message": "Nonce" }, @@ -2480,6 +2982,111 @@ "notePlaceholder": { "message": "L’approbateur verra cette note lorsqu’il approuvera la transaction auprès du dépositaire." }, + "notificationDetail": { + "message": "Détails" + }, + "notificationDetailBaseFee": { + "message": "Frais de base (GWEI)" + }, + "notificationDetailGasLimit": { + "message": "Limite de gaz (unités)" + }, + "notificationDetailGasUsed": { + "message": "Gaz utilisé (unités)" + }, + "notificationDetailMaxFee": { + "message": "Frais maximaux par unité de gaz" + }, + "notificationDetailNetwork": { + "message": "Réseau" + }, + "notificationDetailNetworkFee": { + "message": "Frais de réseau" + }, + "notificationDetailPriorityFee": { + "message": "Frais de priorité (GWEI)" + }, + "notificationItemCheckBlockExplorer": { + "message": "Vérifier sur l’explorateur de blocs" + }, + "notificationItemCollection": { + "message": "Collection" + }, + "notificationItemConfirmed": { + "message": "Confirmé" + }, + "notificationItemError": { + "message": "Impossible de consulter la liste des frais pour l’instant" + }, + "notificationItemFrom": { + "message": "De la part de" + }, + "notificationItemLidoStakeReadyToBeWithdrawn": { + "message": "Retrait prêt à être effectué" + }, + "notificationItemLidoStakeReadyToBeWithdrawnMessage": { + "message": "Vous pouvez maintenant retirer vos $1 non stakés" + }, + "notificationItemLidoWithdrawalRequestedMessage": { + "message": "La demande que vous avez soumise pour déstaker vos $1 a été envoyée" + }, + "notificationItemNFTReceivedFrom": { + "message": "A reçu un NFT de" + }, + "notificationItemNFTSentTo": { + "message": "A envoyé un NFT à" + }, + "notificationItemNetwork": { + "message": "Réseau" + }, + "notificationItemRate": { + "message": "Taux (frais inclus)" + }, + "notificationItemReceived": { + "message": "Reçu" + }, + "notificationItemReceivedFrom": { + "message": "Reçu de la part de" + }, + "notificationItemSent": { + "message": "Envoyé" + }, + "notificationItemSentTo": { + "message": "Envoyé à" + }, + "notificationItemStakeCompleted": { + "message": "Staking terminé" + }, + "notificationItemStaked": { + "message": "Staké" + }, + "notificationItemStakingProvider": { + "message": "Fournisseur de services de staking" + }, + "notificationItemStatus": { + "message": "Statut" + }, + "notificationItemSwapped": { + "message": "Échangé" + }, + "notificationItemSwappedFor": { + "message": "contre" + }, + "notificationItemTo": { + "message": "Destinataire" + }, + "notificationItemTransactionId": { + "message": "ID de transaction" + }, + "notificationItemUnStakeCompleted": { + "message": "Annulation du staking terminée" + }, + "notificationItemUnStaked": { + "message": "Déstaké" + }, + "notificationItemUnStakingRequested": { + "message": "Demande d’annulation du staking" + }, "notificationTransactionFailedMessage": { "message": "La transaction $1 a échoué ! $2", "description": "Content of the browser notification that appears when a transaction fails" @@ -2507,43 +3114,6 @@ "notifications": { "message": "Notifications" }, - "notifications20ActionText": { - "message": "En savoir plus", - "description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a ledger page to resolve the U2F connection issue." - }, - "notifications20Description": { - "message": "Si vous utilisez la dernière version de Firefox, il se peut que vous rencontriez un problème, car Firefox ne prend plus en charge la norme d’authentification U2F.", - "description": "Description of a notification in the 'See What's New' popup. Describes the U2F support being dropped by firefox and that it affects ledger users." - }, - "notifications20Title": { - "message": "Les utilisateurs de Ledger et de Firefox rencontrent des problèmes de connexion", - "description": "Title for a notification in the 'See What's New' popup. Tells users that latest firefox users using U2F may experience connection issues." - }, - "notifications24ActionText": { - "message": "J’ai compris" - }, - "notifications24Description": { - "message": "Les paramètres des frais de gaz avancés sont désormais ajustés en fonction du réseau que vous utilisez. Cela signifie que vous pouvez définir des frais de gaz avancés pour chaque réseau et éviter de payer trop cher pour le gaz ou le blocage des transactions." - }, - "notifications24Title": { - "message": "Frais de gaz avancés pour chaque réseau" - }, - "notifications8ActionText": { - "message": "Allez dans Paramètres > Avancés", - "description": "Description on an action button that appears in the What's New popup. Tells the user that if they click it, they will go to our Advanced settings page." - }, - "notifications8DescriptionOne": { - "message": "Depuis MetaMask v10.4.0, vous n’avez plus besoin de Ledger Live pour connecter votre appareil Ledger à MetaMask.", - "description": "Description of a notification in the 'See What's New' popup. Describes changes for how Ledger Live is no longer needed to connect the device." - }, - "notifications8DescriptionTwo": { - "message": "Pour améliorer votre expérience utilisateur, allez dans Paramètres > Avancés et changez le « Type de connexion préférée au Ledger » en « WebHID ».", - "description": "Description of a notification in the 'See What's New' popup. Describes how the user can turn off the Ledger Live setting." - }, - "notifications8Title": { - "message": "Amélioration de la connexion Ledger", - "description": "Title for a notification in the 'See What's New' popup. Notifies ledger users that there is an improvement in how they can connect their device." - }, "notificationsDropLedgerFirefoxDescription": { "message": "Firefox ne prend plus en charge la norme d’authentification U2F, donc Ledger ne fonctionnera pas avec MetaMask sur Firefox. Essayez plutôt d’utiliser MetaMask sur Google Chrome.", "description": "Description of a notification in the 'See What's New' popup. Describes that ledger will not longer be supported for firefox users and they should use MetaMask on chrome for ledger support instead." @@ -2552,33 +3122,37 @@ "message": "La prise en charge de Ledger ne sera plus assurée sur Firefox", "description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped." }, - "notificationsEmptyText": { - "message": "Ici, vous pouvez trouver des notifications de vos snaps installés." - }, - "notificationsHeader": { - "message": "Notifications" + "notificationsFeatureToggle": { + "message": "Activer les notifications du portefeuille", + "description": "Experimental feature title" }, - "notificationsInfos": { - "message": "Le $1 de $2", - "description": "$1 is the date at which the notification has been dispatched and $2 is the link to the snap that dispatched the notification." + "notificationsFeatureToggleDescription": { + "message": "Cette option permet d’activer les notifications du portefeuille telles que l’envoi/la réception de fonds ou de NFT et les annonces liées aux fonctionnalités.", + "description": "Description of the experimental notifications feature" }, "notificationsMarkAllAsRead": { "message": "Marquer tout comme lu" }, - "notificationsOpenBetaSnapsActionText": { - "message": "En savoir plus" + "notificationsPageEmptyTitle": { + "message": "Rien à voir ici" + }, + "notificationsPageErrorContent": { + "message": "Essayez de visiter à nouveau cette page." + }, + "notificationsPageErrorTitle": { + "message": "Une erreur s’est produite" }, - "notificationsOpenBetaSnapsDescriptionOne": { - "message": "🎉 Nous sommes ravis d’annoncer le lancement de la version bêta publique de MetaMask Snaps !" + "notificationsPageNoNotificationsContent": { + "message": "Vous n’avez pas encore reçu de notifications." }, - "notificationsOpenBetaSnapsDescriptionThree": { - "message": "Personnalisez votre portefeuille avec des snaps conçus par la communauté de développeurs !" + "notificationsSettingsBoxError": { + "message": "Un problème est survenu, veuillez réessayer." }, - "notificationsOpenBetaSnapsDescriptionTwo": { - "message": "Les snaps vous aident à profiter pleinement de MetaMask, par exemple vous connecter à plus de réseaux, voir un aperçu des transactions et recevoir des notifications personnalisées." + "notificationsSettingsPageAllowNotifications": { + "message": "Restez au courant de ce qui se passe dans votre portefeuille grâce aux notifications. Pour activer les notifications, nous utilisons un profil pour synchroniser certains paramètres entre vos appareils. $1" }, - "notificationsOpenBetaSnapsTitle": { - "message": "Présentation de MetaMask Snaps" + "notificationsSettingsPageAllowNotificationsLink": { + "message": "Découvrez comment nous protégeons vos données personnelles lorsque vous utilisez cette fonctionnalité." }, "numberOfNewTokensDetectedPlural": { "message": "$1 nouveaux jetons trouvés dans ce compte", @@ -2602,6 +3176,9 @@ "on": { "message": "Activé" }, + "onboarding": { + "message": "Intégration" + }, "onboardingAdvancedPrivacyIPFSDescription": { "message": "La passerelle IPFS vous permet d’accéder aux données hébergées par des tiers et de les visualiser. Vous pouvez ajouter une passerelle IPFS personnalisée ou continuer à utiliser la passerelle par défaut." }, @@ -2632,51 +3209,45 @@ "onboardingMetametricsAgree": { "message": "J’accepte" }, - "onboardingMetametricsAllowOptOut": { - "message": "Vous pourrez toujours vous désinscrire depuis les Paramètres" - }, - "onboardingMetametricsDataTerms": { - "message": "Conformément au règlement général sur la protection des données (UE) 2016/679, ces données sont agrégées pour préserver l’anonymat des utilisateurs." - }, "onboardingMetametricsDescription": { - "message": "MetaMask souhaite recueillir des données d’utilisation afin de mieux comprendre comment les utilisateurs interagissent avec MetaMask. Ces données seront utilisées pour améliorer les services que nous proposons ainsi que l’expérience utilisateur." + "message": "Nous aimerions recueillir des données d’utilisation et de diagnostic de base afin d’améliorer MetaMask. Sachez que nous ne vendons jamais les données que vous nous fournissez ici." }, "onboardingMetametricsDescription2": { - "message": "MetaMask..." + "message": "Lorsque nous recueillons des données, elles sont toujours…" }, "onboardingMetametricsDisagree": { "message": "Non merci" }, "onboardingMetametricsInfuraTerms": { - "message": "* Sachez que lorsque vous définissez Infura comme fournisseur de RPC par défaut dans MetaMask, votre adresse IP et l’adresse de votre portefeuille Ethereum seront communiquées à Infura pour valider les transactions. Ces données sont stockées séparément sur nos systèmes pour préserver l’anonymat des utilisateurs. Pour plus d’informations sur la façon dont MetaMask et Infura collectent les données, consultez nos dernières mises à jour $1. Pour plus d’informations, consultez notre $2.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" + "message": "Nous vous informerons si nous décidons d’utiliser ces données à d’autres fins. Pour plus d’informations, vous pouvez consulter notre $1. N’oubliez pas que vous pouvez aller dans les paramètres et vous désinscrire à tout moment.", + "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, "onboardingMetametricsInfuraTermsPolicy": { - "message": "Politique de confidentialité ici" - }, - "onboardingMetametricsInfuraTermsPolicyLink": { - "message": "ici" + "message": "Politique de confidentialité" }, "onboardingMetametricsModalTitle": { "message": "Ajouter un réseau personnalisé" }, "onboardingMetametricsNeverCollect": { - "message": "Nous ne collectons $1 d’informations dont nous n’avons pas besoin pour fournir nos services (comme les clés, les adresses, les hachages de transactions ou les soldes)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 les clics et les contenus visualisés sur l’application sont enregistrés, mais d’autres renseignements (comme votre adresse publique) ne le sont pas.", + "description": "$1 represents `onboardingMetametricsNeverCollectEmphasis`" + }, + "onboardingMetametricsNeverCollectEmphasis": { + "message": "Privé :" }, "onboardingMetametricsNeverCollectIP": { - "message": "Nous ne collectons $1 l’intégralité de votre adresse IP*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 nous utilisons votre adresse IP de temps en temps pour détecter votre emplacement général (comme votre pays ou votre région), mais nous ne l’enregistrons pas.", + "description": "$1 represents `onboardingMetametricsNeverCollectIPEmphasis`" }, - "onboardingMetametricsNeverEmphasis": { - "message": "Jamais" + "onboardingMetametricsNeverCollectIPEmphasis": { + "message": "Général :" }, "onboardingMetametricsNeverSellData": { - "message": "Nous ne vendons $1 vos données !", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 vous pouvez décider à tout moment de partager ou de supprimer vos données d’utilisation dans les paramètres.", + "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" }, - "onboardingMetametricsSendAnonymize": { - "message": "Envoyer des données anonymisées sur les clics effectués et les pages vues" + "onboardingMetametricsNeverSellDataEmphasis": { + "message": "Facultatif :" }, "onboardingMetametricsTitle": { "message": "Aidez-nous à améliorer MetaMask" @@ -2717,15 +3288,26 @@ "onboardingPinExtensionTitle": { "message": "Votre installation de MetaMask est terminée !" }, + "onboardingPinMmiExtensionLabel": { + "message": "Épingler MetaMask Institutional" + }, "onboardingUsePhishingDetectionDescription": { "message": "Les alertes de détection d’hameçonnage reposent sur la communication avec $1. jsDeliver aura accès à votre adresse IP. Voir $2.", "description": "The $1 is the word 'jsDeliver', from key 'jsDeliver' and $2 is the words Privacy Policy from key 'privacyMsg', both separated here so that it can be wrapped as a link" }, + "onekey": { + "message": "OneKey" + }, "onlyAddTrustedNetworks": { "message": "Un fournisseur de réseau malveillant peut mentir quant à l’état de la blockchain et enregistrer votre activité réseau. N’ajoutez que des réseaux personnalisés auxquels vous faites confiance." }, "onlyConnectTrust": { - "message": "Ne vous connectez qu’aux sites auxquels vous faites confiance." + "message": "Ne vous connectez qu’aux sites auxquels vous faites confiance. $1", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." + }, + "openCustodianApp": { + "message": "Ouvrir l’application $1", + "description": "The $1 is the name of the Custodian that will be open" }, "openFullScreenForLedgerWebHid": { "message": "Passez en plein écran pour connecter votre Ledger.", @@ -2737,6 +3319,15 @@ "openSeaNew": { "message": "OpenSea" }, + "openSeaToBlockaidBtnLabel": { + "message": "Explorer les Snaps" + }, + "openSeaToBlockaidDescription": { + "message": "Les alertes de sécurité ne sont plus disponibles sur ce réseau. L’installation d’un Snap peut améliorer la sécurité." + }, + "openSeaToBlockaidTitle": { + "message": "Attention !" + }, "operationFailed": { "message": "L’opération a échoué" }, @@ -2780,6 +3371,9 @@ "password": { "message": "Mot de passe" }, + "passwordMmiTermsWarning": { + "message": "Je comprends que MetaMask Institutional ne pourra pas m’aider à récupérer ce mot de passe. $1" + }, "passwordNotLongEnough": { "message": "Mot de passe trop court" }, @@ -2806,6 +3400,10 @@ "message": "Collez votre clé privée ici:", "description": "For importing an account from a private key" }, + "paymasterInUse": { + "message": "Le gaz pour cette transaction sera payé par un payeur.", + "description": "Alert shown in transaction confirmation if paymaster in use." + }, "pending": { "message": "En attente" }, @@ -2819,18 +3417,26 @@ "message": "Vous avez (1) transaction en attente.", "description": "$1 is count of pending transactions" }, - "permissionRequest": { - "message": "Demande d’autorisation" + "permissionDetails": { + "message": "Informations sur les autorisations" }, - "permissionRequestCapitalized": { + "permissionRequest": { "message": "Demande d’autorisation" }, "permissionRequested": { "message": "Demandé maintenant" }, + "permissionRequestedForAccounts": { + "message": "Demandée maintenant pour $1", + "description": "Permission cell status for requested permission including accounts, rendered as AvatarGroup which is $1." + }, "permissionRevoked": { "message": "Révoqué dans cette mise à jour" }, + "permissionRevokedForAccounts": { + "message": "Révoquée dans cette mise à jour pour $1", + "description": "Permission cell status for revoked permission including accounts, rendered as AvatarGroup which is $1." + }, "permission_accessNamedSnap": { "message": "Se connecter à $1.", "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." @@ -2839,6 +3445,10 @@ "message": "Accéder à internet.", "description": "The description of the `endowment:network-access` permission." }, + "permission_accessNetworkDescription": { + "message": "Autoriser le Snap $1 à accéder à l’internet. Cela permet d’effectuer des transferts de données avec des serveurs tiers.", + "description": "An extended description of the `endowment:network-access` permission. $1 is the snap name." + }, "permission_accessSnap": { "message": "Connexion au Snap $1.", "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." @@ -2851,10 +3461,18 @@ "message": "Planifiez et exécutez des actions périodiques.", "description": "The description for the `snap_cronjob` permission" }, + "permission_cronjobDescription": { + "message": "Autoriser le Snap $1 à effectuer des actions qui s’exécutent périodiquement à des heures, des dates ou des intervalles fixes. Cela permet d’envoyer des messages ou des notifications urgentes.", + "description": "An extended description for the `snap_cronjob` permission. $1 is the snap name." + }, "permission_dialog": { "message": "Afficher les boîtes de dialogue dans MetaMask.", "description": "The description for the `snap_dialog` permission" }, + "permission_dialogDescription": { + "message": "Autoriser le Snap $1 à afficher des fenêtres contextuelles MetaMask contenant du texte personnalisé, un champ de saisie et des boutons pour approuver ou rejeter une action.\nCela permet de créer par exemple des alertes, des confirmations et des flux d'adhésion pour un snap.", + "description": "An extended description for the `snap_dialog` permission. $1 is the snap name." + }, "permission_ethereumAccounts": { "message": "Consultez l’adresse, le solde du compte et l’activité, et lancez des transactions", "description": "The description for the `eth_accounts` permission" @@ -2863,30 +3481,138 @@ "message": "Accéder au fournisseur d’Ethereum.", "description": "The description for the `endowment:ethereum-provider` permission" }, + "permission_ethereumProviderDescription": { + "message": "Autorisez le Snap $1 à communiquer directement avec MetaMask, afin qu'il puisse lire les données de la blockchain et suggérer des messages et des transactions.", + "description": "An extended description for the `endowment:ethereum-provider` permission. $1 is the snap name." + }, + "permission_getEntropy": { + "message": "Dériver des clés arbitraires uniques au Snap $1.", + "description": "The description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getEntropyDescription": { + "message": "Autoriser le Snap $1 à dériver des clés arbitraires uniques au Snap $1, sans les divulguer. Ces clés sont distinctes de votre ou vos comptes MetaMask et ne sont pas liées à vos clés privées ou à votre phrase secrète de récupération. Les autres snaps ne peuvent pas accéder à ces informations.", + "description": "An extended description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getLocale": { + "message": "Afficher votre langue préférée.", + "description": "The description for the `snap_getLocale` permission" + }, + "permission_getLocaleDescription": { + "message": "Autoriser le Snap $1 à accéder à vos paramètres MetaMask pour qu’il puisse identifier votre langue préférée. Cela permet de localiser et d’afficher le contenu du Snap $1 dans votre langue.", + "description": "An extended description for the `snap_getLocale` permission. $1 is the snap name." + }, + "permission_homePage": { + "message": "Afficher un écran personnalisé", + "description": "The description for the `endowment:page-home` permission" + }, + "permission_homePageDescription": { + "message": "Laissez $1 afficher un écran d’accueil personnalisé dans MetaMask. Celui-ci peut être utilisé pour les interfaces utilisateur, la configuration et les tableaux de bord.", + "description": "An extended description for the `endowment:page-home` permission. $1 is the snap name." + }, + "permission_keyring": { + "message": "Autoriser les demandes d’ajout et de gestion de comptes Ethereum", + "description": "The description for the `endowment:keyring` permission" + }, + "permission_keyringDescription": { + "message": "Autoriser le Snap $1 à recevoir des demandes d’ajout ou de suppression de comptes et à signer des documents et effectuer des transactions au nom des détenteurs de ces comptes.", + "description": "An extended description for the `endowment:keyring` permission. $1 is the snap name." + }, "permission_lifecycleHooks": { "message": "Utilisez les hooks de cycle de vie.", "description": "The description for the `endowment:lifecycle-hooks` permission" }, + "permission_lifecycleHooksDescription": { + "message": "Autoriser le Snap $1 à utiliser des hooks de cycle de vie pour exécuter des codes à des moments spécifiques de son cycle de vie.", + "description": "An extended description for the `endowment:lifecycle-hooks` permission. $1 is the snap name." + }, "permission_manageAccounts": { "message": "Ajouter et gérer des comptes Ethereum", "description": "The description for `snap_manageAccounts` permission" }, + "permission_manageAccountsDescription": { + "message": "Autoriser le Snap $1 à ajouter ou supprimer des comptes Ethereum qui peuvent être utilisés pour effectuer des transactions et signer des documents.", + "description": "An extended description for the `snap_manageAccounts` permission. $1 is the snap name." + }, + "permission_manageBip32Keys": { + "message": "Gérer les comptes du chemin $1.", + "description": "The description for the `snap_getBip32Entropy` permission. $1 is a derivation path, e.g. 'm/44'/0'/0' (secp256k1)'." + }, + "permission_manageBip44AndBip32KeysDescription": { + "message": "Autoriser le Snap $1 à gérer des comptes et des actifs sur le réseau demandé. Ces comptes sont dérivés et sauvegardés à l’aide de votre phrase secrète de récupération (sans la divulguer). Grâce à sa capacité à dériver des clés, le Snap $1 peut prendre en charge des protocoles blockchain autres que les protocoles de la blockchain Ethereum (EVM).", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions. $1 is the snap name." + }, + "permission_manageBip44Keys": { + "message": "Gérer les comptes du protocole $1.", + "description": "The description for the `snap_getBip44Entropy` permission. $1 is the name of a protocol, e.g. 'Filecoin'." + }, "permission_manageState": { "message": "Stockez et gérez ses données sur votre appareil.", "description": "The description for the `snap_manageState` permission" }, + "permission_manageStateDescription": { + "message": "Autoriser le Snap $1 à stocker, mettre à jour et récupérer des données en toute sécurité en les chiffrant. Les autres snaps ne peuvent pas accéder à ces informations.", + "description": "An extended description for the `snap_manageState` permission. $1 is the snap name." + }, + "permission_nameLookup": { + "message": "Permet de rechercher les noms de domaine et les adresses.", + "description": "The description for the `endowment:name-lookup` permission." + }, + "permission_nameLookupDescription": { + "message": "Autorisez le Snap à récupérer et à afficher les adresses et les noms de domaine dans différentes parties de l’interface utilisateur de MetaMask.", + "description": "An extended description for the `endowment:name-lookup` permission." + }, "permission_notifications": { "message": "Afficher les notifications.", "description": "The description for the `snap_notify` permission" }, + "permission_notificationsDescription": { + "message": "Autoriser le Snap $1 à afficher des notifications dans MetaMask. Un court texte de notification peut être déclenché par un snap pour fournir des informations exploitables ou sensibles au facteur temps.", + "description": "An extended description for the `snap_notify` permission. $1 is the snap name." + }, + "permission_rpc": { + "message": "Autoriser $1 à communiquer directement avec le Snap $2.", + "description": "The description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescription": { + "message": "Autoriser $1 à envoyer des messages au Snap $2 et à recevoir une réponse du Snap $2.", + "description": "An extended description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescriptionOriginList": { + "message": "$1 et $2", + "description": "A list of allowed origins where $2 is the last origin of the list and $1 is the rest of the list separated by ','." + }, + "permission_signatureInsight": { + "message": "Afficher la fenêtre modale contenant des informations sur les demandes de signature.", + "description": "The description for the `endowment:signature-insight` permission" + }, + "permission_signatureInsightDescription": { + "message": "Autoriser $1 à afficher une fenêtre modale contenant des informations sur toute demande de signature avant son approbation. Cela peut être utilisé pour mettre en place des mesures de sécurité et de lutte contre l’hameçonnage.", + "description": "An extended description for the `endowment:signature-insight` permission. $1 is the snap name." + }, + "permission_signatureInsightOrigin": { + "message": "Voir l’origine des sites web qui soumettent une demande de signature", + "description": "The description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission" + }, + "permission_signatureInsightOriginDescription": { + "message": "Autoriser $1 à voir l’origine (URI) des sites web qui soumettent des demandes de signature. Cela peut être utilisé pour mettre en place des mesures de sécurité et de lutte contre l’hameçonnage.", + "description": "An extended description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission. $1 is the snap name." + }, "permission_transactionInsight": { "message": "Récupérez et affichez les aperçus de transaction.", "description": "The description for the `endowment:transaction-insight` permission" }, + "permission_transactionInsightDescription": { + "message": "Autoriser le Snap $1 à décoder les transactions et à afficher des informations dans l'interface utilisateur de MetaMask. Cela peut être utilisé pour des solutions de sécurité et de lutte contre l'hameçonnage.", + "description": "An extended description for the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_transactionInsightOrigin": { "message": "Voir les sites web à l’origine des demandes de transaction", "description": "The description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission" }, + "permission_transactionInsightOriginDescription": { + "message": "Autoriser le Snap $1 à voir l'origine (URI) des sites Web qui suggèrent des transactions. Cela permet de développer des solutions de sécurité et de lutte contre l'hameçonnage.", + "description": "An extended description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_unknown": { "message": "Autorisation inconnue : $1", "description": "$1 is the name of a requested permission that is not recognized." @@ -2895,29 +3621,66 @@ "message": "Consultez votre clé publique pour $1 ($2).", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a derivation path, e.g. 'm/44'/0'/0''. $2 is the elliptic curve name, e.g. 'secp256k1'." }, + "permission_viewBip32PublicKeysDescription": { + "message": "Autoriser le Snap $2 à consulter vos clés publiques (et vos adresses) pour $1. Cela n’accorde pas l’autorisation de gérer les comptes ou les actifs.", + "description": "An extended description for the `snap_getBip32PublicKey` permission. $1 is a derivation path (name). $2 is the snap name." + }, "permission_viewNamedBip32PublicKeys": { "message": "Afficher votre clé publique pour $1.", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a name for the derivation path, e.g., 'Ethereum accounts'." }, + "permission_walletSwitchEthereumChain": { + "message": "Passer au réseau suivant et l’utiliser", + "description": "The label for the `wallet_switchEthereumChain` permission" + }, "permission_webAssembly": { "message": "Prise en charge de WebAssembly.", "description": "The description of the `endowment:webassembly` permission." }, + "permission_webAssemblyDescription": { + "message": "Autoriser le Snap $1 à accéder à des environnements d’exécution de faible niveau via WebAssembly.", + "description": "An extended description of the `endowment:webassembly` permission. $1 is the snap name." + }, "permissions": { "message": "Autorisations" }, - "permissionsTitle": { - "message": "Autorisations" + "permissionsPageEmptyContent": { + "message": "Rien à voir ici" + }, + "permissionsPageEmptySubContent": { + "message": "Ici, vous pouvez voir les autorisations que vous avez accordées aux Snaps installés ou aux sites connectés." }, - "permissionsTourDescription": { - "message": "Trouvez vos comptes connectés et gérez les autorisations ici" + "permissionsPageTourDescription": { + "message": "C’’est votre panneau de configuration pour gérer les autorisations accordées aux sites connectés et aux Snaps installés." + }, + "permissionsPageTourTitle": { + "message": "Les sites connectés sont maintenant des autorisations" }, "personalAddressDetected": { "message": "Votre adresse personnelle a été détectée. Veuillez saisir à la place l’adresse du contrat du jeton." }, + "petnamesEnabledToggle": { + "message": "Autoriser les pseudonymes" + }, + "petnamesEnabledToggleDescription": { + "message": "Cette option vous permet d’attribuer un pseudonyme à n’importe quelle adresse. Nous vous suggérerons, si possible, des pseudonymes que vous pourrez attribuer aux adresses avec lesquelles vous interagissez." + }, + "pinExtensionDescription": { + "message": "Allez dans le menu de l’extension et épinglez MetaMask Institutional pour y faciliter l’accès." + }, + "pinExtensionTitle": { + "message": "Épingler l’extension" + }, + "pinToTop": { + "message": "Épingler en haut de la page" + }, "pleaseConfirm": { "message": "Veuillez confirmer" }, + "plusMore": { + "message": "+ $1 de plus", + "description": "$1 is the number of additional items" + }, "plusXMore": { "message": "+ $1 de plus", "description": "$1 is a number of additional but unshown items in a list- this message will be shown in place of those items" @@ -2943,6 +3706,9 @@ "primaryCurrencySettingDescription": { "message": "Sélectionnez « natif » pour donner la priorité à l’affichage des valeurs dans la devise native de la chaîne (par ex. ETH). Sélectionnez « fiduciaire » pour donner la priorité à l’affichage des valeurs dans la devise de votre choix." }, + "primaryType": { + "message": "Type principal" + }, "priorityFee": { "message": "Frais de priorité" }, @@ -2963,6 +3729,18 @@ "message": "Clé privée pour $1", "description": "$1 represents the account name" }, + "privateKeyHidden": { + "message": "La clé privée est masquée", + "description": "Explains that the private key input is hidden" + }, + "privateKeyShow": { + "message": "Afficher/masquer le champ de saisie de la clé privée", + "description": "Describes a toggle that is used to show or hide the private key input" + }, + "privateKeyShown": { + "message": "Cette clé privée est affichée", + "description": "Explains that the private key input is being shown" + }, "privateKeyWarning": { "message": "Avertissement : ne divulguez jamais cette clé, quiconque possède vos clés privées peut voler tous les actifs de votre compte." }, @@ -2972,6 +3750,21 @@ "proceedWithTransaction": { "message": "Je veux tout de même continuer" }, + "productAnnouncements": { + "message": "Annonces de produits" + }, + "profileSync": { + "message": "Synchronisation du profil" + }, + "profileSyncConfirmation": { + "message": "Si vous désactivez la synchronisation du profil, vous ne pourrez plus recevoir de notifications." + }, + "profileSyncDescription": { + "message": "Crée un profil que MetaMask utilise pour synchroniser certains paramètres entre vos appareils. Ceci est nécessaire pour activer des notifications. $1." + }, + "profileSyncPrivacyLink": { + "message": "Découvrez comment nous protégeons vos données personnelles" + }, "proposedApprovalLimit": { "message": "Limite d’approbation proposée" }, @@ -2981,6 +3774,78 @@ "publicAddress": { "message": "Adresse publique" }, + "pushPlatformNotificationsFundsReceivedDescription": { + "message": "Vous avez reçu $1 $2" + }, + "pushPlatformNotificationsFundsReceivedDescriptionDefault": { + "message": "Vous avez reçu des jetons" + }, + "pushPlatformNotificationsFundsReceivedTitle": { + "message": "Fonds reçus" + }, + "pushPlatformNotificationsFundsSentDescription": { + "message": "Vous avez envoyé avec succès $1 $2" + }, + "pushPlatformNotificationsFundsSentDescriptionDefault": { + "message": "Vous avez envoyé avec succès des jetons" + }, + "pushPlatformNotificationsFundsSentTitle": { + "message": "Fonds envoyés" + }, + "pushPlatformNotificationsNftReceivedDescription": { + "message": "Vous avez reçu de nouveaux NFT" + }, + "pushPlatformNotificationsNftReceivedTitle": { + "message": "NFT reçu" + }, + "pushPlatformNotificationsNftSentDescription": { + "message": "Vous avez envoyé avec succès un NFT" + }, + "pushPlatformNotificationsNftSentTitle": { + "message": "NFT envoyé" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedDescription": { + "message": "Votre staking Lido a été effectué avec succès" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedTitle": { + "message": "Staking terminé" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnDescription": { + "message": "Vous pouvez désormais retirer vos récompenses de staking Lido" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnTitle": { + "message": "Retirer les récompenses de staking Lido" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedDescription": { + "message": "Votre retrait Lido a été effectué avec succès" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedTitle": { + "message": "Retrait effectué" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedDescription": { + "message": "Votre demande de retrait Lido a été envoyée" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedTitle": { + "message": "La demande de retrait a été envoyée" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedDescription": { + "message": "Votre staking RocketPool a été effectué avec succès" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedTitle": { + "message": "Staking terminé" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedDescription": { + "message": "L’annulation du staking RocketPool a été effectuée avec succès" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedTitle": { + "message": "Annulation du staking terminée" + }, + "pushPlatformNotificationsSwapCompletedDescription": { + "message": "Votre swap MetaMask a été effectué avec succès" + }, + "pushPlatformNotificationsSwapCompletedTitle": { + "message": "Swap terminé" + }, "queued": { "message": "En attente" }, @@ -2999,9 +3864,15 @@ "receive": { "message": "Recevoir" }, + "receiveTokensCamelCase": { + "message": "Recevez des jetons" + }, "recipientAddressPlaceholder": { "message": "Saisissez l’adresse publique (0x) ou le nom de domaine ENS" }, + "recipientAddressPlaceholderFlask": { + "message": "Saisissez l’adresse publique (0x) ou le nom de domaine" + }, "recommendedGasLabel": { "message": "Recommandé" }, @@ -3029,6 +3900,12 @@ "recoveryPhraseReminderTitle": { "message": "Protégez vos fonds" }, + "redesignedConfirmationsEnabledToggle": { + "message": "Demandes de signature améliorées" + }, + "redesignedConfirmationsToggleDescription": { + "message": "Activez cette option pour afficher les demandes de signature dans un format amélioré." + }, "refreshList": { "message": "Rafraîchir la liste" }, @@ -3071,14 +3948,29 @@ "removeJWTDescription": { "message": "Êtes-vous sûr de vouloir supprimer ce jeton ? Tous les comptes attribués à ce jeton seront également supprimés de l’extension : " }, + "removeKeyringSnap": { + "message": "En supprimant ce snap, vous supprimerez ces comptes de MetaMask :" + }, + "removeKeyringSnapToolTip": { + "message": "Les comptes sont gérés par ce snap. Si vous le supprimez, les comptes seront supprimés de MetaMask, mais pas de la blockchain." + }, "removeNFT": { "message": "Supprimer le NFT" }, + "removeNftErrorMessage": { + "message": "Nous n’avons pas pu supprimer ce NFT." + }, "removeNftMessage": { "message": "Le NFT a été supprimé avec succès !" }, "removeSnap": { - "message": "Supprimer Snap" + "message": "Supprimer le Snap" + }, + "removeSnapAccountDescription": { + "message": "Si vous continuez, ce compte ne sera plus disponible dans MetaMask." + }, + "removeSnapAccountTitle": { + "message": "Supprimer le compte" }, "removeSnapConfirmation": { "message": "Voulez-vous vraiment supprimer $1 ?", @@ -3090,12 +3982,24 @@ "replace": { "message": "remplacer" }, + "reportIssue": { + "message": "Signaler un problème" + }, "requestFlaggedAsMaliciousFallbackCopyReason": { "message": "Le fournisseur de sécurité n’a pas partagé d’autres détails" }, "requestFlaggedAsMaliciousFallbackCopyReasonTitle": { "message": "Demande signalée comme malveillante" }, + "requestFrom": { + "message": "Demande de" + }, + "requestFromInfo": { + "message": "C'est le site qui vous demande votre signature." + }, + "requestFromTransactionDescription": { + "message": "Il s’agit du site qui demande votre confirmation." + }, "requestMayNotBeSafe": { "message": "Cette demande peut présenter des risques" }, @@ -3117,6 +4021,9 @@ "reset": { "message": "Reinitialiser" }, + "resetStates": { + "message": "Réinitialiser les états" + }, "resetWallet": { "message": "Réinitialiser le portefeuille" }, @@ -3145,7 +4052,7 @@ "message": "Restaurer les données de l’utilisateur" }, "restoreUserDataDescription": { - "message": "Vous pouvez restaurer les paramètres de l’utilisateur qui contiennent les préférences et les adresses de compte à partir d’un fichier JSON précédemment sauvegardé." + "message": "Vous pouvez restaurer des données telles que des contacts et des préférences à partir d’un fichier de sauvegarde." }, "resultPageError": { "message": "Erreur" @@ -3199,9 +4106,15 @@ "message": "Le service d’assistance de MetaMask ne vous la demandera jamais.", "description": "The bolded texted in the second part of 'revealSeedWordsWarning'" }, + "revealSensitiveContent": { + "message": "Révéler les contenus sensibles" + }, "revealTheSeedPhrase": { "message": "Révéler la phrase mnémonique" }, + "reviewAlerts": { + "message": "Examiner les alertes" + }, "revokeAllTokensTitle": { "message": "Révoquer l’autorisation d’accès et de transfert de tous vos $1 ?", "description": "$1 is the symbol of the token for which the user is revoking approval" @@ -3252,6 +4165,9 @@ "searchAccounts": { "message": "Rechercher des comptes" }, + "searchTokens": { + "message": "Rechercher des jetons" + }, "secretRecoveryPhrase": { "message": "Phrase secrète de récupération" }, @@ -3268,7 +4184,8 @@ "message": "Alertes de sécurité" }, "securityAlertsDescription": { - "message": "Cette fonctionnalité vous avertit de toute activité malveillante sur le réseau principal Ethereum en examinant activement les transactions et les demandes de signature tout en protégeant vos données personnelles. Vos données ne sont pas partagées avec la tierce partie qui fournit ce service. Vous devez faire preuve de diligence raisonnable avant d’approuver toute demande. Rien ne garantit que toutes les activités malveillantes seront détectées par cette fonctionnalité." + "message": "Cette fonctionnalité vous alerte en cas d’activité malveillante en examinant activement les demandes de transaction et de signature. $1", + "description": "Link to learn more about security alerts" }, "securityAndPrivacy": { "message": "Sécurité et confidentialité" @@ -3358,6 +4275,9 @@ "selectAnAccountHelp": { "message": "Sélectionnez les comptes de dépôt que vous voulez utiliser dans MetaMask Institutional." }, + "selectEnableDisplayMediaPrivacyPreference": { + "message": "Activer l’option « Afficher les supports NFT »" + }, "selectHdPath": { "message": "Sélectionner le chemin HD" }, @@ -3379,18 +4299,41 @@ "send": { "message": "Envoyer" }, + "sendAToken": { + "message": "Envoyer un jeton" + }, "sendBugReport": { "message": "Envoyez-nous un rapport de bogue." }, + "sendNoContactsConversionText": { + "message": "cliquez ici" + }, + "sendNoContactsDescription": { + "message": "Les contacts vous permettent d’envoyer en toute sécurité plusieurs transactions vers un autre compte. Pour créer un contact, $1", + "description": "$1 represents the action text 'click here'" + }, + "sendNoContactsTitle": { + "message": "Vous n’avez aucun contact" + }, + "sendSelectReceiveAsset": { + "message": "Sélectionnez l’actif que vous recevrez" + }, + "sendSelectSendAsset": { + "message": "Sélectionnez l’actif que vous voulez envoyer" + }, "sendSpecifiedTokens": { "message": "Envoyer $1", "description": "Symbol of the specified token" }, - "sendTo": { - "message": "Envoyer à" + "sendSwapSubmissionWarning": { + "message": "En cliquant sur ce bouton, vous entamez immédiatement l’opération d’échange. Veuillez vérifier les détails de votre transaction avant de continuer." }, - "sendTokens": { - "message": "Envoyer des jetons" + "sendTokenAsToken": { + "message": "Échanger des $1 contre des $2 et les envoyer", + "description": "Used in the transaction display list to describe a swap and send. $1 and $2 are the symbols of tokens in involved in the swap." + }, + "sendingAsset": { + "message": "Envoi de $1" }, "sendingDisabled": { "message": "L’envoi d’actifs ERC-1155 NFT n’est pas encore pris en charge." @@ -3403,9 +4346,15 @@ "message": "Attention : vous êtes sur le point d’envoyer des jetons à l’adresse d’un contrat de jetons qui pourrait entraîner une perte de fonds. $1", "description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning" }, + "sendingZeroAmount": { + "message": "Vous envoyez 0 $1." + }, "sepolia": { "message": "Réseau de test Sepolia" }, + "serviceWorkerKeepAlive": { + "message": "Garder le « Service Worker » activé" + }, "setAdvancedPrivacySettingsDetails": { "message": "MetaMask utilise ces services tiers de confiance pour améliorer la convivialité et la sécurité des produits." }, @@ -3417,7 +4366,7 @@ "description": "The token symbol that is being approved" }, "settingAddSnapAccount": { - "message": "Ajouter un compte snap" + "message": "Ajouter un compte Snap" }, "settings": { "message": "Paramètres" @@ -3425,9 +4374,21 @@ "settingsSearchMatchingNotFound": { "message": "Aucun résultat correspondant trouvé." }, + "settingsSubHeadingSignaturesAndTransactions": { + "message": "Demandes de signature et de transaction" + }, "show": { "message": "Afficher" }, + "showAccount": { + "message": "Afficher le compte" + }, + "showExtensionInFullSizeView": { + "message": "Afficher l’extension en taille réelle" + }, + "showExtensionInFullSizeViewDescription": { + "message": "Activez cette option si vous voulez que l’extension s’affiche en taille réelle lorsque vous cliquez sur l’icône de l’extension." + }, "showFiatConversionInTestnets": { "message": "Afficher la conversion sur les testnets" }, @@ -3447,6 +4408,9 @@ "message": "Sélectionnez ceci pour utiliser Etherscan afin d’afficher les transactions entrantes dans la liste des transactions", "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" }, + "showIncomingTransactionsExplainer": { + "message": "Ce processus fait appel à différentes API tierces pour chaque réseau et expose ainsi votre adresse Ethereum et votre adresse IP." + }, "showMore": { "message": "Afficher plus" }, @@ -3486,9 +4450,46 @@ "signin": { "message": "Connexion" }, + "signing": { + "message": "Signature" + }, + "simulationDetailsFailed": { + "message": "Une erreur s’est produite lors du chargement de l’estimation." + }, + "simulationDetailsFiatNotAvailable": { + "message": "Non disponible" + }, + "simulationDetailsIncomingHeading": { + "message": "Vous recevez" + }, + "simulationDetailsNoBalanceChanges": { + "message": "Aucun changement prévu pour votre portefeuille" + }, + "simulationDetailsOutgoingHeading": { + "message": "Vous envoyez" + }, + "simulationDetailsTitle": { + "message": "Changements estimés" + }, + "simulationDetailsTitleTooltip": { + "message": "Les changements estimés représentent ce qui pourrait se produire si vous effectuez cette transaction. Il s’agit juste d’une estimation fournie à des fins d’information." + }, + "simulationDetailsTotalFiat": { + "message": "Total = $1", + "description": "$1 is the total amount in fiat currency on one side of the transaction" + }, + "simulationDetailsTransactionReverted": { + "message": "Cette transaction va probablement échouer" + }, "simulationErrorMessageV2": { "message": "Nous n’avons pas pu estimer le prix de carburant. Par conséquent, il se peut qu’il y ait une erreur dans le contrat et que cette transaction échoue." }, + "simulationsSettingDescription": { + "message": "Activez cette option pour estimer les changements de solde des transactions avant de les confirmer. Cela ne garantit pas le résultat final de vos transactions. $1" + }, + "simulationsSettingSubHeader": { + "message": "Estimer les changements de solde" + }, "skip": { "message": "Ignorer" }, @@ -3501,20 +4502,99 @@ "smartContracts": { "message": "Contrats intelligents" }, - "smartSwapsAreHere": { - "message": "Les contrats de swap intelligents sont enfin arrivés !" - }, - "smartSwapsDescription": { - "message": "Les swaps sont devenus beaucoup plus intelligents sur MetaMask ! L’activation des contrats de swap intelligents permettra à MetaMask d’optimiser programmatiquement le processus contractuel pour vous aider à :" - }, "smartSwapsErrorNotEnoughFunds": { "message": "Fonds insuffisants pour souscrire un contrat de swap intelligent." }, "smartSwapsErrorUnavailable": { "message": "Les contrats de swap intelligents sont temporairement indisponibles." }, + "smartTransactionCancelled": { + "message": "Votre transaction a été annulée" + }, + "smartTransactionCancelledDescription": { + "message": "Votre transaction n’a pas pu être effectuée, elle a donc été annulée pour vous éviter de payer inutilement des frais de gaz." + }, + "smartTransactionError": { + "message": "Votre transaction a échoué" + }, + "smartTransactionErrorDescription": { + "message": "Des changements soudains sur le marché peuvent entraîner des échecs de transaction. Si le problème persiste, contactez le service d’assistance à la clientèle de MetaMask." + }, + "smartTransactionPending": { + "message": "Soumettre votre transaction" + }, + "smartTransactionSuccess": { + "message": "Votre transaction est terminée" + }, + "smartTransactionTakingTooLong": { + "message": "Désolé de vous avoir fait attendre" + }, + "smartTransactionTakingTooLongDescription": { + "message": "Si votre transaction n’est pas finalisée dans un délai de $1, elle sera annulée et les frais de gaz ne vous seront pas facturés.", + "description": "$1 is remaining time in seconds" + }, + "smartTransactions": { + "message": "Transactions intelligentes" + }, + "smartTransactionsBenefit1": { + "message": "Taux de réussite de 99,5 %" + }, + "smartTransactionsBenefit2": { + "message": "Cela vous permet d’économiser de l’argent" + }, + "smartTransactionsBenefit3": { + "message": "Mises à jour en temps réel" + }, + "smartTransactionsDescription": { + "message": "Bénéficiez de taux de réussite plus élevés, d’une protection contre le « front running » et d’une meilleure visibilité grâce aux transactions intelligentes." + }, + "smartTransactionsDescription2": { + "message": "Disponible uniquement sur Ethereum. Vous pouvez activer ou désactiver cette option à tout moment dans les paramètres. $1", + "description": "$1 is an external link to learn more about Smart Transactions" + }, + "smartTransactionsOptItModalTitle": { + "message": "Protection renforcée des transactions" + }, + "snapAccountCreated": { + "message": "Le compte a été créé" + }, + "snapAccountCreatedDescription": { + "message": "Votre nouveau compte est prêt à être utilisé !" + }, + "snapAccountCreationFailed": { + "message": "La création du compte a échoué" + }, + "snapAccountCreationFailedDescription": { + "message": "$1 n’a pas réussi à créer un compte pour vous.", + "description": "$1 is the snap name" + }, + "snapAccountRedirectFinishSigningTitle": { + "message": "Finaliser la signature" + }, + "snapAccountRedirectSiteDescription": { + "message": "Suivez les instructions de $1" + }, + "snapAccountRemovalFailed": { + "message": "La suppression du compte a échoué" + }, + "snapAccountRemovalFailedDescription": { + "message": "$1 n’a pas réussi à supprimer ce compte pour vous.", + "description": "$1 is the snap name" + }, + "snapAccountRemoved": { + "message": "Compte supprimé" + }, + "snapAccountRemovedDescription": { + "message": "Ce compte ne pourra plus être utilisé dans MetaMask." + }, + "snapAccounts": { + "message": "Snaps de compte" + }, + "snapAccountsDescription": { + "message": "Comptes contrôlés par des Snaps tiers." + }, "snapConnectionWarning": { - "message": "$1 veut se connecter à $2. Ne continuez que si vous avez confiance en ce site web.", + "message": "$1 veut utiliser $2", "description": "$2 is the snap and $1 is the dapp requesting connection to the snap." }, "snapContent": { @@ -3525,15 +4605,35 @@ "message": "Site web" }, "snapInstallRequest": { - "message": "L’installation de $1 lui donne les autorisations suivantes. Ne continuez que si vous faites confiance à $1.", + "message": "L’installation de $1 lui accorde les autorisations suivantes.", "description": "$1 is the snap name." }, "snapInstallSuccess": { "message": "Installation terminée" }, + "snapInstallWarningCheck": { + "message": "Le Snap $1 demande l’autorisation de faire ce qui suit :", + "description": "Warning message used in popup displayed on snap install. $1 is the snap name." + }, "snapInstallWarningHeading": { "message": "Agissez avec prudence" }, + "snapInstallWarningPermissionDescriptionForBip32View": { + "message": "Autoriser le Snap $1 à consulter vos clés publiques (et vos adresses). Cela n’accorde pas l’autorisation de gérer les comptes ou les actifs.", + "description": "An extended description for the `snap_getBip32PublicKey` permission used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionDescriptionForEntropy": { + "message": "Autoriser le Snap $1 à gérer des comptes et des actifs sur le(s) réseau(x) demandé(s). Ces comptes sont dérivés et sauvegardés à l'aide de votre phrase secrète de récupération (sans la divulguer). Grâce à sa capacité à dériver des clés, le Snap $1 peut prendre en charge des protocoles blockchain autres que les protocoles de la blockchain Ethereum (EVM).", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionNameForEntropy": { + "message": "Gérer les comptes $1", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, + "snapInstallWarningPermissionNameForViewPublicKey": { + "message": "Afficher la clé publique pour $1", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, "snapInstallationErrorDescription": { "message": "$1 n’a pas pu être installé.", "description": "Error description used when snap installation fails. $1 is the snap name." @@ -3551,6 +4651,10 @@ "snapResultSuccessDescription": { "message": "$1 est prêt à être utilisé" }, + "snapUpdateAlertDescription": { + "message": "Obtenez la dernière version de $1", + "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." + }, "snapUpdateAvailable": { "message": "Une mise à jour est disponible" }, @@ -3562,22 +4666,40 @@ "message": "La mise à jour a échoué", "description": "Error title used when snap update fails." }, + "snapUpdateRequest": { + "message": "La mise à jour de $1 lui accorde les autorisations suivantes.", + "description": "$1 is the Snap name." + }, "snapUpdateSuccess": { "message": "Mise à jour terminée" }, + "snapUrlIsBlocked": { + "message": "Ce Snap veut vous emmener sur un site bloqué. $1." + }, "snaps": { "message": "Snaps" }, - "snapsInvalidUIError": { - "message": "L’interface utilisateur (IU) spécifiée par le snap n’est pas valide." + "snapsConnected": { + "message": "Snaps connectés" }, "snapsNoInsight": { "message": "Le snap n’a renvoyé aucun aperçu" }, + "snapsPrivacyWarningFirstMessage": { + "message": "Vous reconnaissez que tout Snap que vous installez (sauf indication contraire) est un « Service tiers » tel que défini dans les $1 de Consensys. L’utilisation des services tiers est régie par des conditions distinctes définies par les fournisseurs de services tiers. Consensys ne recommande pas à des personnes particulières d’utiliser un Snap pour des raisons particulières. Si vous décidez d’utiliser un service tiers, vous le faites à vos propres risques. Consensys décline toute responsabilité pour toute perte liée à l’utilisation des services tiers.", + "description": "First part of a message in popup modal displayed when installing a snap for the first time. $1 is terms of use link." + }, "snapsPrivacyWarningSecondMessage": { "message": "Toute information que vous partagez avec des services tiers sera collectée directement par ces services tiers conformément à leur politique de confidentialité. Pour plus d’informations, veuillez consulter leur politique de confidentialité.", "description": "Second part of a message in popup modal displayed when installing a snap for the first time." }, + "snapsPrivacyWarningThirdMessage": { + "message": "Consensys n’a pas accès aux informations que vous partagez avec les fournisseurs de services tiers.", + "description": "Third part of a message in popup modal displayed when installing a snap for the first time." + }, + "snapsSettings": { + "message": "Paramètres du Snap" + }, "snapsTermsOfUse": { "message": "Conditions d’utilisation" }, @@ -3591,12 +4713,19 @@ "someNetworksMayPoseSecurity": { "message": "Certains réseaux peuvent présenter des risques pour la sécurité et/ou la vie privée. Informez-vous sur les risques avant d’ajouter et d’utiliser un réseau." }, + "somethingDoesntLookRight": { + "message": "On dirait que quelque chose ne va pas ? $1", + "description": "A false positive message for users to contact support. $1 is a link to the support page." + }, "somethingIsWrong": { "message": "Un problème est survenu. Essayez de recharger la page." }, "somethingWentWrong": { "message": "Oups ! Quelque chose a mal tourné. " }, + "source": { + "message": "Source" + }, "speedUp": { "message": "Accélérer" }, @@ -3731,6 +4860,14 @@ "stake": { "message": "Staker" }, + "startYourJourney": { + "message": "Lancez-vous dans les $1", + "description": "$1 is the token symbol" + }, + "startYourJourneyDescription": { + "message": "Lancez-vous dans le Web3 en ajoutant quelques $1 à votre portefeuille.", + "description": "$1 is the token symbol" + }, "stateLogError": { "message": "Erreur lors du chargement des journaux d’état." }, @@ -3743,6 +4880,9 @@ "stateLogsDescription": { "message": "Les journaux d’état contiennent les adresses publiques de vos comptes et vos transactions envoyées." }, + "states": { + "message": "États" + }, "status": { "message": "État" }, @@ -3786,18 +4926,6 @@ "strong": { "message": "Robuste" }, - "stxBenefit1": { - "message": "Minimise les frais de transaction" - }, - "stxBenefit2": { - "message": "Réduit les échecs de transaction" - }, - "stxBenefit3": { - "message": "Élimine les blocages de transaction" - }, - "stxBenefit4": { - "message": "Empêcher le favoritisme" - }, "stxCancelled": { "message": "Le swap aurait échoué" }, @@ -3807,6 +4935,10 @@ "stxCancelledSubDescription": { "message": "Réessayez le swap. Nous serons là pour vous protéger contre des risques similaires la prochaine fois." }, + "stxEstimatedCompletion": { + "message": "Délai estimé < $1", + "description": "$1 is remeaning time in minutes and seconds, e.g. 0:10" + }, "stxFailure": { "message": "Échec du swap" }, @@ -3814,6 +4946,9 @@ "message": "Les fluctuations soudaines du marché peuvent provoquer des échecs. Si le problème persiste, veuillez contacter $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInDescription": { + "message": "Activez les transactions intelligentes pour profiter de transactions plus fiables et plus sûres sur le réseau principal Ethereum. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Soumission privée de votre Swap..." }, @@ -3852,12 +4987,21 @@ "submitted": { "message": "Envoyé" }, + "suggestedTokenSymbol": { + "message": "Symbole boursier suggéré :" + }, "support": { "message": "Assistance" }, "supportCenter": { "message": "Visitez notre centre d’aide" }, + "surveyConversion": { + "message": "Répondez à notre sondage" + }, + "surveyTitle": { + "message": "Façonnez l’avenir de MetaMask" + }, "swap": { "message": "Swap" }, @@ -3877,6 +5021,9 @@ "swapAmountReceivedInfo": { "message": "Il s’agit du montant minimal que vous recevrez. Vous pouvez recevoir plus en fonction du glissement." }, + "swapAndSend": { + "message": "Échanger et envoyer" + }, "swapAnyway": { "message": "Procéder de toute façon au swap" }, @@ -3992,6 +5139,10 @@ "message": "Comprend des frais MetaMask à hauteur de $1 %.", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." }, + "swapIncludesMMFeeAlt": { + "message": "La cotation inclut les frais de change de MetaMask qui s’élèvent à $1 %", + "description": "Provides information about the fee that metamask takes for swaps using the latest copy. $1 is a decimal number." + }, "swapIncludesMetaMaskFeeViewAllQuotes": { "message": "Comprend des frais MetaMask à hauteur de $1 % – $2", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number and $2 is a link to view all quotes." @@ -3999,6 +5150,9 @@ "swapLearnMore": { "message": "En savoir plus sur les swaps" }, + "swapLiquiditySourceInfo": { + "message": "Nous consultons différentes sources de liquidité (bourses, agrégateurs et teneurs de marché professionnels) pour comparer les taux de change et les frais de réseau." + }, "swapLowSlippage": { "message": "Faible effet de glissement" }, @@ -4139,7 +5293,7 @@ "message": "La tolérance au slippage doit être inférieure ou égale à 15 %. Une tolérance plus élevée peut se traduire par un taux de change désavantageux." }, "swapSlippageOverLimitTitle": { - "message": "Réduisez le slippage pour continuer" + "message": "Slippage très élevé" }, "swapSlippagePercent": { "message": "$1 %", @@ -4271,6 +5425,9 @@ "switchEthereumChainConfirmationTitle": { "message": "Autoriser ce site à changer de réseau ?" }, + "switchInputCurrency": { + "message": "Changer la devise" + }, "switchNetwork": { "message": "Changer de réseau" }, @@ -4284,14 +5441,15 @@ "switchToThisAccount": { "message": "Basculer vers ce compte" }, - "switchedTo": { - "message": "Vous êtes passé à" + "switchedNetworkToastDecline": { + "message": "Ne plus afficher" }, - "switcherTitle": { - "message": "Commutateur réseau" + "switchedNetworkToastMessage": { + "message": "$1 est maintenant actif sur $2", + "description": "$1 represents the account name, $2 represents the network name" }, - "switcherTourDescription": { - "message": "Cliquez sur l’icône pour changer de réseau ou ajouter un nouveau réseau" + "switchedTo": { + "message": "Vous êtes passé à" }, "switchingNetworksCancelsPendingConfirmations": { "message": "Le changement de réseau annulera toutes les confirmations en attente" @@ -4391,6 +5549,18 @@ "toggleEthSignOn": { "message": "Activer (recommandé)" }, + "toggleRequestQueueDescription": { + "message": "Cette fonction vous permet de sélectionner un réseau pour chaque site au lieu d’un seul réseau pour tous les sites. Vous n’aurez donc pas à changer manuellement de réseau, ce qui pourrait nuire à l’expérience utilisateur sur certains sites." + }, + "toggleRequestQueueField": { + "message": "Sélectionnez les réseaux pour chaque site" + }, + "toggleRequestQueueOff": { + "message": "Désactiver" + }, + "toggleRequestQueueOn": { + "message": "Activer" + }, "token": { "message": "Jeton" }, @@ -4407,7 +5577,7 @@ "message": "Adresse du contrat de jeton" }, "tokenDecimalFetchFailed": { - "message": "Décimale de jeton requise." + "message": "La décimale du jeton est requise. Trouvez-la sur : $1" }, "tokenDecimalTitle": { "message": "Nombre de décimales du token :" @@ -4446,6 +5616,9 @@ "tooltipSatusConnected": { "message": "connecté" }, + "tooltipSatusConnectedUpperCase": { + "message": "Connecté" + }, "tooltipSatusNotConnected": { "message": "non connecté" }, @@ -4586,6 +5759,39 @@ "tryAgain": { "message": "Réessayez" }, + "turnOff": { + "message": "Désactiver" + }, + "turnOffMetamaskNotificationsError": { + "message": "Une erreur s’est produite lors de la désactivation des notifications. Veuillez réessayer plus tard." + }, + "turnOn": { + "message": "Activer" + }, + "turnOnMetamaskNotifications": { + "message": "Activer les notifications" + }, + "turnOnMetamaskNotificationsButton": { + "message": "Activer" + }, + "turnOnMetamaskNotificationsError": { + "message": "Une erreur s’est produite lors de la création des notifications. Veuillez réessayer plus tard." + }, + "turnOnMetamaskNotificationsMessageFirst": { + "message": "Restez au courant de ce qui se passe dans votre portefeuille grâce aux notifications." + }, + "turnOnMetamaskNotificationsMessagePrivacyBold": { + "message": "Paramètres > Notifications." + }, + "turnOnMetamaskNotificationsMessagePrivacyLink": { + "message": "Découvrez comment nous protégeons vos données personnelles lorsque vous utilisez cette fonctionnalité." + }, + "turnOnMetamaskNotificationsMessageSecond": { + "message": "Pour activer les notifications du portefeuille, nous utilisons un profil pour synchroniser certains paramètres entre vos appareils. $1" + }, + "turnOnMetamaskNotificationsMessageThird": { + "message": "Vous pouvez désactiver les notifications à tout moment dans $1" + }, "turnOnTokenDetection": { "message": "Activer la détection améliorée des jetons" }, @@ -4617,6 +5823,10 @@ "unknownNetwork": { "message": "Réseau privé inconnu" }, + "unknownNetworkForKeyEntropy": { + "message": "Réseau inconnu", + "description": "Displayed on places like Snap install warning when regular name is not available." + }, "unknownQrCode": { "message": "Erreur : nous n’avons pas pu identifier le code QR" }, @@ -4629,6 +5839,9 @@ "unlockMessage": { "message": "Le web décentralisé vous attend" }, + "unpin": { + "message": "Détacher" + }, "unrecognizedChain": { "message": "Ce réseau personnalisé n’est pas reconnu", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." @@ -4646,6 +5859,9 @@ "update": { "message": "Mise à jour" }, + "updateRequest": { + "message": "Demande de mise à jour" + }, "updatedWithDate": { "message": "Mis à jour $1" }, @@ -4670,12 +5886,25 @@ "useNftDetection": { "message": "Détection automatique des NFT" }, + "useNftDetectionDescriptionText": { + "message": "Laissez MetaMask ajouter les NFT que vous possédez en utilisant des services tiers (comme OpenSea). La détection automatique des NFT expose votre adresse IP et l’adresse de votre compte à ces services. Si vous activez cette fonctionnalité, un lien pourrait être établi entre votre adresse IP et votre adresse Ethereum, et entrainer l’affichage de faux NFT distribués par des escrocs. Vous pouvez ajouter des jetons manuellement pour éviter ce risque." + }, "usePhishingDetection": { "message": "Utiliser la fonction anti-hameçonnage" }, "usePhishingDetectionDescription": { "message": "Cela permet d’afficher un avertissement pour les domaines d’hameçonnage ciblant les utilisateurs d’Ethereum" }, + "useSafeChainsListValidation": { + "message": "Vérification des détails du réseau" + }, + "useSafeChainsListValidationDescription": { + "message": "MetaMask utilise un service tiers appelé $1 pour afficher des détails précis et standardisés concernant les réseaux. Vous limitez ainsi les risques de vous connecter à un réseau malveillant ou au mauvais réseau. En utilisant cette fonctionnalité, vous exposez votre adresse IP à chainid.network." + }, + "useSafeChainsListValidationWebsite": { + "message": "chainid.network", + "description": "useSafeChainsListValidationWebsite is separated from the rest of the text so that we can bold the third party service name in the middle of them" + }, "useSiteSuggestion": { "message": "Utiliser la suggestion du site" }, @@ -4688,6 +5917,9 @@ "userName": { "message": "Nom d’utilisateur" }, + "userOpContractDeployError": { + "message": "Le déploiement de contrats à partir d’un compte de contrat intelligent n’est pas pris en charge" + }, "verifyContractDetails": { "message": "Vérifier les informations relatives aux tiers" }, @@ -4705,6 +5937,9 @@ "view": { "message": "Affichez" }, + "viewActivity": { + "message": "Voir l’activité" + }, "viewAllDetails": { "message": "Afficher tous les détails" }, @@ -4728,7 +5963,7 @@ }, "viewOnCustomBlockExplorer": { "message": "Afficher $1 à $2", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "Afficher $1 sur Etherscan", @@ -4740,6 +5975,9 @@ "viewOnOpensea": { "message": "Afficher sur Opensea" }, + "viewTransaction": { + "message": "Voir la transaction" + }, "viewinCustodianApp": { "message": "Afficher dans l’application dépositaire" }, @@ -4747,6 +5985,9 @@ "message": "Voir $1 dans l’explorateur", "description": "$1 is the action type. e.g (Account, Transaction, Swap)" }, + "visitSite": { + "message": "Visiter le site" + }, "visitWebSite": { "message": "Visitez notre site web" }, @@ -4785,6 +6026,10 @@ "warning": { "message": "Avertissement" }, + "warningFromSnap": { + "message": "Avertissement provenant de $1", + "description": "$1 represents the name of the snap" + }, "warningTooltipText": { "message": "$1 L’autre partie au contrat peut dépenser la totalité de votre solde de jetons sans préavis et sans demander votre consentement. Protégez-vous en abaissant le plafond des dépenses.", "description": "$1 is a warning icon with text 'Be careful' in 'warning' colour" @@ -4792,6 +6037,9 @@ "weak": { "message": "Faible" }, + "web3": { + "message": "Web3" + }, "web3ShimUsageNotification": { "message": "Nous avons remarqué que ce site Web a essayé d’utiliser l’API window.web3 supprimée. Si le site semble être défectueux, veuillez cliquer sur $1 pour plus d’informations.", "description": "$1 is a clickable link." @@ -4832,10 +6080,6 @@ "whatsThis": { "message": "Qu’est-ce que c’est ?" }, - "xOfY": { - "message": "$1 sur $2", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$1 sur $2 en attente", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" @@ -4843,6 +6087,9 @@ "yes": { "message": "Oui" }, + "you": { + "message": "Vous" + }, "youHaveAddedAll": { "message": "Vous avez ajouté tous les réseaux populaires. Vous pouvez découvrir d’autres réseaux $1 ou $2", "description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'" @@ -4865,6 +6112,12 @@ "yourPrivateSeedPhrase": { "message": "Votre phrase secrète de récupération privée" }, + "yourTransactionConfirmed": { + "message": "Transaction déjà confirmée" + }, + "yourTransactionJustConfirmed": { + "message": "Nous n'avons pas pu annuler votre transaction avant qu'elle ne soit confirmée sur la blockchain." + }, "zeroGasPriceOnSpeedUpError": { "message": "Prix de carburant zéro sur l’accélération" } diff --git a/app/_locales/he/messages.json b/app/_locales/he/messages.json index bfc0eb50541b..22f5ac53511e 100644 --- a/app/_locales/he/messages.json +++ b/app/_locales/he/messages.json @@ -627,9 +627,6 @@ "send": { "message": "שלח" }, - "sendTokens": { - "message": "שלח טוקנים" - }, "settings": { "message": "הגדרות" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 50027209b4f5..7ebd3e958736 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -130,12 +130,21 @@ "account": { "message": "अकाउंट" }, + "accountActivity": { + "message": "अकाउंट एक्टिविटी" + }, + "accountActivityText": { + "message": "वे अकाउंट चुनें जिनके बारे में आप सूचित होना चाहते हैं:" + }, "accountDetails": { "message": "अकाउंट की जानकारी" }, "accountIdenticon": { "message": "अकाउंट आइडेंटिकॉन" }, + "accountIsntConnectedToastText": { + "message": "$2 से $1 कनेक्टेड नहीं है" + }, "accountName": { "message": "अकाउंट का नाम" }, @@ -153,6 +162,12 @@ "accountSelectionRequired": { "message": "आपको एक अकाउंट चुनना होगा!" }, + "accounts": { + "message": "अकाउंट्स" + }, + "accountsConnected": { + "message": "अकाउंट्स कनेक्ट किए गए।" + }, "active": { "message": "एक्टिव है" }, @@ -220,7 +235,7 @@ "message": "यह महत्वपूर्ण है कि आपका प्रोवाइडर विश्वसनीय हो, क्योंकि उसके पास निम्नलिखित अधिकार हैं:" }, "addEthereumChainWarningModalListPointOne": { - "message": "आपके एकाउंट्स और आईपी एड्रेस देखने की, और उन्हें एक साथ जोड़ने की" + "message": "आपके एकाउंट्स और आईपी ​​एड्रेस देखने की, और उन्हें एक साथ जोड़ने की" }, "addEthereumChainWarningModalListPointThree": { "message": "अकाउंट बैलेंस और अन्य ऑन-चेन स्टेट दिखाने की" @@ -243,6 +258,9 @@ "addIPFSGateway": { "message": "अपना पसंदीदा IPFS गेटवे जोड़ें" }, + "addImportAccount": { + "message": "अकाउंट या हार्डवेयर वॉलेट जोड़ें" + }, "addMemo": { "message": "मेमो जोड़ें" }, @@ -256,6 +274,9 @@ "message": "यह नेटवर्क कनेक्शन थर्ड पार्टियों पर निर्भर करता है। यह कनेक्शन संभवतः कम विश्वसनीय है या थर्ड-पार्टियों को एक्टिविटी को ट्रैक करने के लिए इनेबल कर सकता है। $1", "description": "$1 is Learn more link" }, + "addNewAccount": { + "message": "एक नया अकाउंट जोड़ें" + }, "addNewToken": { "message": "नया टोकन जोड़ें" }, @@ -265,6 +286,12 @@ "addNfts": { "message": "NFTs जोड़ें" }, + "addSnapAccountToggle": { + "message": "\"अकाउंट Snap जोड़ें (बीटा)\" को चालू करें" + }, + "addSnapAccountsDescription": { + "message": "इस फीचर को चालू करने से आपको सीधे अपनी अकाउंट लिस्ट से नया बीटा अकाउंट Snap जोड़ने का विकल्प मिलेगा। अगर आप Snap अकाउंट इनस्टॉल करते हैं, तो याद रखें कि यह एक थर्ड-पार्टी सर्विस है।" + }, "addSuggestedNFTs": { "message": "सुझाए गए NFTs जोड़ें" }, @@ -281,6 +308,9 @@ "addingCustomNetwork": { "message": "नेटवर्क जोड़ रहे हैं" }, + "addingTokens": { + "message": "टोकन जोड़ना" + }, "address": { "message": "एड्रेस" }, @@ -316,9 +346,27 @@ "airgapVault": { "message": "AirGap Vault" }, + "alert": { + "message": "एलर्ट" + }, + "alertBannerMultipleAlertsDescription": { + "message": "यदि आप इस रिक्वेस्ट को एप्रूव करते हैं, तो स्कैम के लिए मशहूर कोई थर्ड पार्टी आपके सारे एसेट चुरा सकती है।" + }, + "alertBannerMultipleAlertsTitle": { + "message": "एकाधिक एलर्ट!" + }, "alertDisableTooltip": { "message": "इसे \"सेटिंग > अलर्ट\" में बदला जा सकता है" }, + "alertModalAcknowledge": { + "message": "मैंने जोखिम को स्वीकार कर लिया है और इसके बावजूद आगे बढ़ना चाहता/चाहती हूं" + }, + "alertModalDetails": { + "message": "एलर्ट का विवरण" + }, + "alertModalReviewAllAlerts": { + "message": "सभी एलर्ट की समीक्षा करें" + }, "alertSettingsUnconnectedAccount": { "message": "जो कनेक्टेड नहीं है वह अकाउंट चुनकर कोई वेबसाइट ब्राउज़ करना" }, @@ -334,6 +382,9 @@ "alerts": { "message": "चेतावनियां" }, + "all": { + "message": "सभी" + }, "allCustodianAccountsConnectedSubtitle": { "message": "आपने या तो अपने सभी कस्टोडियन एकाउंट्स को पहले ही जोड़ लिया है या MetaMask इंस्टीट्यूशनल से जुड़ने के लिए कोई अकाउंट नहीं है।" }, @@ -344,23 +395,26 @@ "message": "आपके सभी $1", "description": "$1 is the symbol or name of the token that the user is approving spending" }, + "allPermissions": { + "message": "सभी अनुमतियां" + }, "allYourNFTsOf": { "message": "आपके सभी NFTs $1 से शुरू", "description": "$1 is a link to contract on the block explorer when we're not able to retrieve a erc721 or erc1155 name" }, - "allowExternalExtensionTo": { - "message": "इस बाहरी एक्सटेंशन को इसकी अनुमति दें:" + "allow": { + "message": "अनुमति दें" + }, + "allowMmiToConnectToCustodian": { + "message": "यह आपके एकाउंट्स को इम्पोर्ट करने के लिए MMI को $1 से कनेक्ट करने की अनुमति देगा।" + }, + "allowNotifications": { + "message": "नोटिफिकेशंस की अनुमति दें" }, "allowSpendToken": { "message": "आपके $1 को एक्सेस करने की अनुमति दें?", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "इस साइट को इसकी अनुमति दें:" - }, - "allowThisSnapTo": { - "message": "इस Snap को इसकी अनुमति दें:" - }, "allowWithdrawAndSpend": { "message": "$1 को निम्नलिखित तक अमाउंट निकालने और खर्च करने की अनुमति दें:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -368,6 +422,23 @@ "amount": { "message": "अमाउंट" }, + "amountReceived": { + "message": "प्राप्त किया गया राशि" + }, + "amountSent": { + "message": "भेजा गया राशि" + }, + "andForListItems": { + "message": "$1, और $2", + "description": "$1 is the first item, $2 is the last item in a list of items. Used in Snap Install Warning modal." + }, + "andForTwoItems": { + "message": "$1 और $2", + "description": "$1 is the first item, $2 is the second item. Used in Snap Install Warning modal." + }, + "announcements": { + "message": "घोषणाएं" + }, "appDescription": { "message": "आपके ब्राउज़र में एक Ethereum वॉलेट", "description": "The description of the application" @@ -402,6 +473,10 @@ "approveButtonText": { "message": "एप्रूव करें" }, + "approveIncreaseAllowance": { + "message": "$1 खर्च करने की लिमिट को बढ़ाएं", + "description": "The token symbol that is being approved" + }, "approveSpendingCap": { "message": "खर्च करने की लिमिट $1 को एप्रूव करें", "description": "The token symbol that is being approved" @@ -427,6 +502,10 @@ "message": "$1 पर एप्रूव किया गया", "description": "$1 is the approval date for a permission" }, + "approvedOnForAccounts": { + "message": "$1 पर $2 के लिए एप्रूव किया गया", + "description": "$1 is the approval date for a permission. $2 is the AvatarGroup component displaying account images." + }, "areYouSure": { "message": "क्या आप वाकई ऐसा करना चाहते हैं?" }, @@ -437,7 +516,13 @@ "message": "एसेट के विकल्प" }, "attemptSendingAssets": { - "message": "यदि आप एसेट्स को सीधे एक नेटवर्क से दूसरे नेटवर्क पर भेजने की कोशिश करते हैं, तो इस वजह से स्थायी एसेट्स का नुकसान हो सकता है। ब्रिज का इस्तेमाल करना पक्का करें।" + "message": "अगर आप एसेट्स को सीधे एक नेटवर्क से दूसरे नेटवर्क पर भेजने की कोशिश करते हैं, तो ऐसा करने से आपको एसेट्स का नुकसान हो सकता है। ब्रिज का इस्तेमाल करके नेटवर्कों के बीच फंड्स को सुरक्षित तरीके से ट्रांसफ़र करें।" + }, + "attemptSendingAssetsWithPortfolio": { + "message": "अगर आप एसेट्स को सीधे एक नेटवर्क से दूसरे नेटवर्क पर भेजने की कोशिश करते हैं, तो ऐसा करने से आपको एसेट्स का नुकसान हो सकता है। ब्रिज, जैसे like $1, का इस्तेमाल करके नेटवर्कों के बीच फंड्स को सुरक्षित तरीके से ट्रांसफ़र करें।" + }, + "attemptToCancelSwapForFree": { + "message": "स्वैप को मुफ्त में कैंसिल करने की कोशिश करें" }, "attemptingConnect": { "message": "ब्लॉकचेन से कनेक्ट करने की कोशिश कर रहे हैं।" @@ -477,7 +562,10 @@ "message": "यदि आप अपना डिवाइस खो देते हैं, अपना पासवर्ड भूल जाते हैं, MetaMask को फिर से इनस्टॉल करना हो या दूसरे डिवाइस पर अपने वॉलेट को एक्सेस करना चाहते हों, तो आपके वॉलेट को रिकवर करने के लिए यह सीक्रेट कोड आवश्यक है।" }, "backupApprovalNotice": { - "message": "अपने वॉलेट और पैसे को सुरक्षित रखने के लिए अपने सीक्रेट रिकवरी फ्रेज़ का बैकअप लें।" + "message": "अपने वॉलेट और फंड्स को सुरक्षित रखने के लिए अपने सीक्रेट रिकवरी फ्रेज़ का बैकअप लें।" + }, + "backupKeyringSnapReminder": { + "message": "इस अकाउंट को हटाने से पहले यह पक्का कर लें कि इस Snap द्वारा बनाए गए सभी एकाउंट्स को आप खुद एक्सेस कर पा रहे हैं" }, "backupNow": { "message": "अभी बैकअप लें" @@ -486,7 +574,7 @@ "message": "अपने डेटा का बैकअप लें" }, "backupUserDataDescription": { - "message": "आप एक JSON फाइल में अपनी पसंद (प्रेफेरेंस) और अकाउंट एड्रेस वाली यूज़र सेटिंग्स का बैकअप ले सकते हैं।" + "message": "आप अपने डेटा, जैसे कि अपने कॉन्टेक्ट्स और अपनी प्रेफेरेंस, का बैकअप ले सकते हैं।" }, "balance": { "message": "बैलेंस" @@ -500,6 +588,30 @@ "basic": { "message": "बेसिक" }, + "basicConfigurationBannerCTA": { + "message": "बेसिक फंक्शनलिटी को चालू करें" + }, + "basicConfigurationBannerTitle": { + "message": "बेसिक फंक्शनलिटी बंद है" + }, + "basicConfigurationLabel": { + "message": "बेसिक फंक्शनलिटी" + }, + "basicConfigurationModalCheckbox": { + "message": "मैं समझता/समझती हूं और जारी रखना चाहता/चाहती हूं" + }, + "basicConfigurationModalDisclaimerOff": { + "message": "इसका मतलब यह है कि आप MetaMask पर अपना समय सबसे अच्छे तरीके से इस्तेमाल नहीं कर पाएंगे। बेसिक फीचर्स (जैसे टोकन विवरण, ऑप्टीमल गैस सेटिंग्स और अन्य) आपके लिए उपलब्ध नहीं होंगे।" + }, + "basicConfigurationModalDisclaimerOn": { + "message": "MetaMask पर अपना समय अच्छे तरीके से इस्तेमाल करने के लिए, आपको इस फीचर को चालू करना होगा। बुनियादी कार्य (जैसे टोकन विवरण, ऑप्टीमल गैस सेटिंग्स और अन्य) Web3 अनुभव के लिए महत्वपूर्ण हैं।" + }, + "basicConfigurationModalHeadingOff": { + "message": "बेसिक फंक्शनलिटी को बंद करें" + }, + "basicConfigurationModalHeadingOn": { + "message": "बेसिक फंक्शनलिटी को चालू करें" + }, "beCareful": { "message": "सावधान रहें" }, @@ -557,7 +669,7 @@ "message": "यदि आप इस रिक्वेस्ट को स्वीकार करते हैं, तो कोई Blur पर लिस्टेड आपके सारे एसेट चुरा सकता है।" }, "blockaidDescriptionErrored": { - "message": "कोई समस्या होने के कारण, इस रिक्वेस्ट को सिक्यूरिटी प्रोवाइडर द्वारा वेरीफ़ाई नहीं किया गया। सावधानी से आगे बढ़ें।" + "message": "किसी समस्या के कारण, हम सुरक्षा अलर्ट की जाँच नहीं कर सके। केवल तभी जारी रखें जब आपको इसमें शामिल प्रत्येक पते पर भरोसा हो।" }, "blockaidDescriptionMaliciousDomain": { "message": "आप एक बुरी नीयत वाले डोमेन से इंटरैक्ट कर रहे हैं। यदि आप इस रिक्वेस्ट को एप्रूव करते हैं, तो आप अपने सारे एसेट गंवा सकते हैं।" @@ -571,11 +683,14 @@ "blockaidDescriptionTransferFarming": { "message": "यदि आप इस रिक्वेस्ट को स्वीकार करते हैं, तो स्कैम के लिए मशहूर कोई थर्ड पार्टी आपके सारे एसेट चुरा सकती है।" }, + "blockaidMessage": { + "message": "गोपनीयता को सुरक्षित रखना - कोई भी डेटा थर्ड पार्टी के साथ साझा नहीं किया जाता है। Arbitrum, Avalanche, BNB chain, Ethereum Mainnet, Linea, Optimism, Polygon, Base और Sepolia पर उपलब्ध है।" + }, "blockaidTitleDeceptive": { "message": "इस रिक्वेस्ट को धोखेबाज़ी के उद्देश्य से भेजा गया है" }, "blockaidTitleMayNotBeSafe": { - "message": "हो सकता है कि रिक्वेस्ट सुरक्षित न हो" + "message": "सावधान रहें" }, "blockaidTitleSuspicious": { "message": "इस रिक्वेस्ट पर एकदम से भरोसा नहीं किया जा सकता" @@ -586,6 +701,9 @@ "bridge": { "message": "ब्रिज" }, + "bridgeDontSend": { + "message": "ब्रिज, न भेजें" + }, "browserNotSupported": { "message": "आपका ब्राउज़र सपोर्टेड नहीं है..." }, @@ -598,6 +716,9 @@ "busy": { "message": "बिज़ी" }, + "buyAndSell": { + "message": "खरीदें और बेचें" + }, "buyAsset": { "message": "$1 खरीदें", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -609,6 +730,10 @@ "buyNow": { "message": "अभी खरीदें" }, + "buyToken": { + "message": "$1 खरीदें", + "description": "$1 is the token symbol" + }, "bytes": { "message": "बाइट" }, @@ -618,9 +743,6 @@ "cancel": { "message": "कैंसिल करें" }, - "cancelEdit": { - "message": "बदलाव करना कैंसिल करें" - }, "cancelPopoverTitle": { "message": "ट्रांसेक्शन कैंसिल करें" }, @@ -647,6 +769,9 @@ "chainIdExistsErrorMsg": { "message": "यह चेन ID वर्तमान में $1 नेटवर्क द्वारा इस्तेमाल की जाती है।" }, + "chainListReturnedDifferentTickerSymbol": { + "message": "यह टोकन सिंबल आपके द्वारा डाले गए नेटवर्क नाम या चेन ID से मेल नहीं खाता है। कई लोकप्रिय टोकन इसी तरह के सिंबल का उपयोग करते हैं, जिनका उपयोग स्कैमर्स आपको बदले में ज़्यादा कीमती टोकन भेजने का झांसा देने के लिए कर सकते हैं। आगे बढ़ने से पहले हर चीज़ अच्छे से वेरीफाई कर लें।" + }, "chooseYourNetwork": { "message": "अपना नेटवर्क चुनें" }, @@ -677,14 +802,24 @@ "description": "Text that can be clicked to open a browser popup for connecting the ledger device via webhid" }, "clickToManuallyAdd": { - "message": "मैन्युअल रूप से टोकन जोड़ने के लिए यहां क्लिक करें" + "message": "आप कभी भी मैन्युअल रूप से टोकन जोड़ सकते हैं।" }, "close": { "message": "बंद करें" }, + "closeExtension": { + "message": "एक्सटेंशन को बंद करें" + }, + "closeWindowAnytime": { + "message": "आप इस विंडो को कभी भी बंद कर सकते हैं।" + }, "coingecko": { "message": "CoinGecko" }, + "comboNoOptions": { + "message": "कोई विकल्प नहीं मिला", + "description": "Default text shown in the combo field dropdown if no options." + }, "configureSnapPopupDescription": { "message": "अब आप इस Snap को कॉन्फिगर करने के लिए MetaMask से बाहर जा रहे हैं।" }, @@ -703,12 +838,42 @@ "confirm": { "message": "कन्फर्म करें" }, + "confirmAlertModalAcknowledge": { + "message": "मैंने एलर्ट को स्वीकार कर लिया है और इसके बावजूद आगे बढ़ना चाहता/चाहती हूं" + }, + "confirmAlertModalDetails": { + "message": "यदि आप साइन इन करते हैं, तो स्कैम के लिए मशहूर कोई थर्ड पार्टी आपके सारे एसेट चुरा सकती है। कृपया आगे बढ़ने से पहले एलर्ट की समीक्षा करें।" + }, + "confirmAlertModalTitle": { + "message": "आपके एसेट खतरे में हो सकते हैं" + }, + "confirmConnectCustodianRedirect": { + "message": "'जारी रखें' पर क्लिक करने पर हम आपको $1 पर रीडायरेक्ट कर देंगे।" + }, + "confirmConnectCustodianText": { + "message": "अपने एकाउंट्स को कनेक्ट करने के लिए, अपने $1 अकाउंट में लॉग इन करें और 'MMI से कनेक्ट करें' बटन पर क्लिक करें।" + }, + "confirmConnectionTitle": { + "message": "$1 से कनेक्शन को कन्फर्म करें" + }, "confirmPassword": { "message": "पासवर्ड कन्फर्म करें" }, "confirmRecoveryPhrase": { "message": "सीक्रेट रिकवरी फ्रेज कन्फर्म करें" }, + "confirmTitleDescContractInteractionTransaction": { + "message": "यदि आप कंटेंट को पूरी तरह से समझते हैं और अनुरोध करने वाली साइट पर भरोसा करते हैं तो ही इस ट्रांसेक्शन को कन्फर्म करें" + }, + "confirmTitleDescSignature": { + "message": "इस संदेश को केवल तभी कन्फर्म करें जब आप कंटेंट को एप्रूव करते हैं और अनुरोध करने वाली साइट पर भरोसा करते हैं।" + }, + "confirmTitleSignature": { + "message": "सिग्नेचर अनुरोध" + }, + "confirmTitleTransaction": { + "message": "ट्रांसेक्शन अनुरोध" + }, "confirmed": { "message": "कन्फर्म किया गया" }, @@ -724,9 +889,15 @@ "connect": { "message": "कनेक्ट करें" }, + "connectAccount": { + "message": "खाता कनेक्ट करें" + }, "connectAccountOrCreate": { "message": "अकाउंट कनेक्ट करें या नया बनाएं" }, + "connectAccounts": { + "message": "एकाउंट्स को कनेक्ट करें" + }, "connectCustodialAccountMenu": { "message": "कस्टोडियल अकाउंट कनेक्ट करें" }, @@ -736,36 +907,25 @@ "connectCustodialAccountTitle": { "message": "कस्टोडियल अकाउंट" }, + "connectCustodianAccounts": { + "message": "$1 एकाउंट्स को कनेक्ट करें" + }, "connectManually": { "message": "वर्तमान साइट से मैन्युअल रूप से कनेक्ट करें" }, + "connectMoreAccounts": { + "message": "ज़्यादा एकाउंट्स को कनेक्ट करें" + }, "connectSnap": { "message": "$1 को कनेक्ट करें", "description": "$1 is the snap for which a connection is being requested." }, - "connectTo": { - "message": "$1 से कनेक्ट करें", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "अपने सभी $1 से कनेक्ट करें", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "एकाउंट्स", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "$1 से कनेक्ट करें", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1 एकाउंट्स", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "MetaMask के साथ कनेक्ट करें" }, + "connectedAccounts": { + "message": "कनेक्ट किए हुए एकाउंट्स" + }, "connectedAccountsDescriptionPlural": { "message": "आपके पास इस साइट से कनेक्ट किए गए $1 एकाउंट्स हैं।", "description": "$1 is the number of accounts" @@ -776,6 +936,13 @@ "connectedAccountsEmptyDescription": { "message": "MetaMask इस साइट से कनेक्ट नहीं है। किसी web3 साइट से कनेक्ट करने के लिए, उनकी साइट पर कनेक्ट बटन खोजें।" }, + "connectedAccountsListTooltip": { + "message": "$1, अकाउंट का बैलेंस, एड्रेस, एक्टिविटी देख सकता है और कनेक्टेड अकाउंट्स के लिए एप्रूवल देने के लिए ट्रांसेक्शन का सुझाव दे सकता है।", + "description": "$1 is the origin name" + }, + "connectedAccountsToast": { + "message": "कनेक्टेड अकाउंट अपडेट किए गए" + }, "connectedSites": { "message": "कनेक्ट की गई साइटें" }, @@ -787,12 +954,21 @@ "message": "$1 किसी भी साइट से कनेक्ट नहीं है।", "description": "$1 is the account name" }, + "connectedSnapAndNoAccountDescription": { + "message": "MetaMask इस साइट से कनेक्टेड है, लेकिन अभी तक कोई अकाउंट कनेक्ट नहीं किया गया है" + }, + "connectedWith": { + "message": "से कनेक्ट किया गया" + }, "connecting": { - "message": "कनेक्ट किया जा रहा है..." + "message": "कनेक्ट किया जा रहा है" }, "connectingTo": { "message": "$1 से कनेक्ट किया जा रहा है" }, + "connectingToDeprecatedNetwork": { + "message": "'$1' को चरणबद्ध तरीके से हटाया जा रहा है और हो सकता है कि यह काम न करे। कोई और नेटवर्क इस्तेमाल करके देखें।" + }, "connectingToGoerli": { "message": "Goerli टेस्ट नेटवर्क से कनेक्ट हो रहा है" }, @@ -802,6 +978,9 @@ "connectingToLineaMainnet": { "message": "Linea Mainnet से कनेक्ट हो रहा है" }, + "connectingToLineaSepolia": { + "message": "Linea Sepolia टेस्ट नेटवर्क से कनेक्ट हो रहा है" + }, "connectingToMainnet": { "message": " Ethereum Mainnet से कनेक्ट हो रहा है" }, @@ -831,6 +1010,12 @@ "continue": { "message": "जारी रखें" }, + "continueMmiOnboarding": { + "message": "MetaMask Institutional ऑनबोर्डिंग जारी रखें" + }, + "continueToWallet": { + "message": "वॉलेट जारी रखें" + }, "contract": { "message": "कॉन्ट्रैक्ट" }, @@ -882,6 +1067,9 @@ "copyAddress": { "message": "क्लिपबोर्ड पर एड्रेस कॉपी करें" }, + "copyPrivateKey": { + "message": "प्राइवेट की (key) को कॉपी करें" + }, "copyRawTransactionData": { "message": "रॉ ट्रांसेक्शन डेटा कॉपी करें" }, @@ -900,6 +1088,15 @@ "createPassword": { "message": "पासवर्ड बनाएं" }, + "createSnapAccountDescription": { + "message": "$1 MetaMask में एक नया अकाउंट जोड़ना चाहता है।" + }, + "createSnapAccountTitle": { + "message": "अकाउंट बनाएं" + }, + "crossChainSwapsLink": { + "message": "MetaMask पोर्टफोलियो के साथ पूरे नेटवर्क में कहीं भी स्वैप करें" + }, "cryptoCompare": { "message": "CryptoCompare" }, @@ -950,10 +1147,16 @@ "message": "कस्टोडियन" }, "custodianAccountAddedDesc": { - "message": "अब आप MetaMask Institutional में अपने कस्टोडियन एकाउंट्स का इस्तेमाल कर सकते हैं।" + "message": "अब आप MetaMask Institutional में अपने एकाउंट्स का इस्तेमाल कर सकते हैं।" }, "custodianAccountAddedTitle": { - "message": "चुने गए कस्टोडियन अकाउंट जोड़ दिए गए हैं।" + "message": "चुने गए $1 एकाउंट्स जोड़ दिए गए हैं।" + }, + "custodianQRCodeScan": { + "message": "QR कोड को अपने $1 मोबाइल ऐप से स्कैन करें" + }, + "custodianQRCodeScanDescription": { + "message": "या अपने $1 अकाउंट में लॉग इन करें और 'Connect to MMI' बटन पर क्लिक करें" }, "custodianReplaceRefreshTokenChangedFailed": { "message": "कृपया $1 पर जाएं और अपने एकाउंट्स को फिर से MMI से जोड़ने के लिए उनके यूज़र इंटरफेस के भीतर 'MMI से कनेक्ट करें' बटन पर क्लिक करें।" @@ -1017,7 +1220,7 @@ "message": "इस नेटवर्क पर अभी टोकन डिटेक्शन उपलब्ध नहीं है। कृपया टोकन को मैन्युअल रूप से इंपोर्ट करें और ये पक्का करें कि आपको उसपर भरोसा हो। $1 के बारे में जानें" }, "customTokenWarningInTokenDetectionNetwork": { - "message": "टोकन को मैन्युअल रूप से इंपोर्ट करने से पहले, पक्का करें कि आपको उसपर भरोसा हो। $1 के बारे में जानें" + "message": "कोई भी टोकन बना सकता है, जिसमें मौजूदा टोकन के नकली वर्शन को बनाना शामिल है। $1 के बारे में जानें" }, "customTokenWarningInTokenDetectionNetworkWithTDOFF": { "message": "पक्का करें कि आप किसी टोकन को इम्पोर्ट करने से पहले उस पर भरोसा करते हैं। $1 को टालने का तरीका जानें। आप टोकन डिटेक्शन $2 भी इनेबल कर सकते हैं।" @@ -1025,6 +1228,12 @@ "customerSupport": { "message": "कस्टमर सपोर्ट" }, + "customizeYourNotifications": { + "message": "अपने नोटिफिकेशंस कस्टमाइज़ करें" + }, + "customizeYourNotificationsText": { + "message": "आप जिस प्रकार के नोटिफिकेशंस प्राप्त करना चाहते हैं, उन्हें चालू करें:" + }, "dappRequestedSpendingCap": { "message": "साइट ने खर्च करने की लिमिट का रिक्वेस्ट किया" }, @@ -1108,6 +1317,18 @@ "deposit": { "message": "डिपॉज़िट करें" }, + "deprecatedGoerliNtwrkMsg": { + "message": "Ethereum सिस्टम में हुए अपडेट के कारण, Goerli टेस्ट नेटवर्क को जल्द ही चरणबद्ध तरीके से हटा दिया जाएगा।" + }, + "deprecatedNetwork": { + "message": "इस नेटवर्क को हटा दिया गया है" + }, + "deprecatedNetworkButtonMsg": { + "message": "समझ गए" + }, + "deprecatedNetworkDescription": { + "message": "जिस नेटवर्क से आप कनेक्ट करने का प्रयास कर रहे हैं उसे अब MetaMask सपोर्ट नहीं करता। $1" + }, "description": { "message": "जानकारी" }, @@ -1115,110 +1336,20 @@ "message": "$1 से जानकारी", "description": "$1 represents the name of the snap" }, - "desktopApp": { - "message": "डेस्कटॉप ऐप" - }, - "desktopConnectionCriticalErrorDescription": { - "message": "यह गड़बड़ी रुक-रुक कर हो सकती है, इसलिए एक्सटेंशन को फिर से शुरू करने की कोशिश करें या MetaMask डेस्कटॉप को डिसेबल करें।" - }, - "desktopConnectionCriticalErrorTitle": { - "message": "MetaMask को शुरू करने में परेशानी हुई" - }, - "desktopConnectionLostErrorDescription": { - "message": "कृपया पक्का करें कि आपके पास डेस्कटॉप ऐप चालू है और चल रहा है या MetaMask डेस्कटॉप को डिसेबल करें।" - }, - "desktopConnectionLostErrorTitle": { - "message": "MetaMask डेस्कटॉप कनेक्शन टूट हो गया था" - }, - "desktopDisableButton": { - "message": "डेस्कटॉप ऐप को डिसेबल करें" - }, - "desktopDisableErrorCTA": { - "message": "MetaMask डेस्कटॉप को डिसेबल करें" - }, - "desktopEnableButton": { - "message": "डेस्कटॉप ऐप को इनेबल करें" - }, - "desktopEnableButtonDescription": { - "message": "डेस्कटॉप ऐप में सभी बैकग्राउंड प्रक्रियाओं को चलाने के लिए क्लिक करें।" - }, - "desktopErrorNavigateSettingsCTA": { - "message": "सेटिंग्स पेज पर वापस लौटें" - }, - "desktopErrorRestartMMCTA": { - "message": "MetaMask को फिर से शुरू करें" - }, - "desktopNotFoundErrorCTA": { - "message": "MetaMask डेस्कटॉप डाउनलोड करें" - }, - "desktopNotFoundErrorDescription1": { - "message": "कृपया पक्का करें कि आपके पास डेस्कटॉप ऐप चालू है और चल रहा है।" - }, - "desktopNotFoundErrorDescription2": { - "message": "अगर आपके पास कोई डेस्कटॉप ऐप इंस्टॉल नहीं है, तो कृपया इसे MetaMask वेबसाइट पर डाउनलोड करें।" - }, - "desktopNotFoundErrorTitle": { - "message": "MetaMask डेस्कटॉप नहीं पाया गया" - }, - "desktopOpenOrDownloadCTA": { - "message": "MetaMask डेस्कटॉप को खोलें" - }, - "desktopOutdatedErrorCTA": { - "message": "MetaMask डेस्कटॉप अपडेट करें" - }, - "desktopOutdatedErrorDescription": { - "message": "आपके MetaMask डेस्कटॉप ऐप को अपग्रेड करने की आवश्यकता है।" - }, - "desktopOutdatedErrorTitle": { - "message": "MetaMask डेस्कटॉप पुराना हो चुका है" - }, - "desktopOutdatedExtensionErrorCTA": { - "message": "MetaMask एक्सटेंशन का अपडेट करें" - }, - "desktopOutdatedExtensionErrorDescription": { - "message": "आपके MetaMask एक्सटेंशन को अपग्रेड करने की आवश्यकता है।" - }, - "desktopOutdatedExtensionErrorTitle": { - "message": "MetaMask एक्सटेंशन पुराना हो चुका है" - }, - "desktopPageDescription": { - "message": "यदि पेयरिंग सफल होती है, तो एक्सटेंशन फिर से शुरू हो जाएगा और आपको अपना पासवर्ड फिर से डालना होगा।" - }, - "desktopPageSubTitle": { - "message": "अपना MetaMask डेस्कटॉप खोलें और इस कोड को टाइप करें" - }, - "desktopPageTitle": { - "message": "डेस्कटॉप के साथ पेयर करें" - }, - "desktopPairedWarningDeepLink": { - "message": "MetaMask डेस्कटॉप में सेटिंग्स में जाएं" - }, - "desktopPairedWarningDescription": { - "message": "यदि आप एक नई पेयरिंग शुरू करना चाहते हैं, तो कृपया वर्तमान कनेक्शन को हटा दें।" - }, - "desktopPairedWarningTitle": { - "message": "MM डेस्कटॉप पहले से पेयर हो चुका है" - }, - "desktopPairingExpireMessage": { - "message": "कोड $1 सेकंड में समाप्त हो रहा है" - }, - "desktopRouteNotFoundErrorDescription": { - "message": "desktopRouteNotFoundErrorDescription" - }, - "desktopRouteNotFoundErrorTitle": { - "message": "desktopRouteNotFoundErrorTitle" + "details": { + "message": "विस्तृत जानकारी" }, - "desktopUnexpectedErrorCTA": { - "message": "MetaMask होम को लौटें" + "developerOptions": { + "message": "डेवलपर विकल्प" }, - "desktopUnexpectedErrorDescription": { - "message": "कनेक्शन को रीस्टोर करने के लिए अपने MetaMask डेस्कटॉप की जाँच करें" + "developerOptionsResetStatesAnnouncementsDescription": { + "message": "सभी घोषणाओं के लिए isShown boolean को गलत पर रीसेट करता है। घोषणाएं व्हाट्स न्यू पॉपअप मोडल में दिखाई जाने वाली सूचनाएं हैं।" }, - "desktopUnexpectedErrorTitle": { - "message": "कुछ गलत हो गया..." + "developerOptionsResetStatesOnboarding": { + "message": "ऑनबोर्डिंग से संबंधित विभिन्न स्टेट को रीसेट करता है और \"सिक्योर योर वॉलेट\" ऑनबोर्डिंग पेज पर रीडायरेक्ट करता है।" }, - "details": { - "message": "विस्तृत जानकारी" + "developerOptionsServiceWorkerKeepAlive": { + "message": "हर टाइमस्टैम्प के परिणाम को लगातार session.storage में सेव किया जा रहा है" }, "disabledGasOptionToolTipMessage": { "message": "\"$1\" डिसेबल किया गया है क्योंकि यह ओरिजिनल गैस फ़ीस से कम-से-कम 10% वृद्धि को पूरा नहीं करता है।", @@ -1233,12 +1364,38 @@ "disconnectAllAccountsConfirmationDescription": { "message": "क्या आप वाकई डिस्कनेक्ट करना चाहते हैं? आप साइट की फंक्शनलिटी खो सकते हैं।" }, + "disconnectAllAccountsText": { + "message": "अकाउंट्स" + }, + "disconnectAllSnapsText": { + "message": "Snaps" + }, + "disconnectAllText": { + "message": "अगर आप अपने $1 को $2 से डिस्कनेक्ट करते हैं, तो आपको उन्हें दोबारा इस्तेमाल करने के लिए रिकनेक्ट करना होगा।", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`, $2 represents the website hostname" + }, + "disconnectAllTitle": { + "message": "सभी $1 को डिस्कनेक्ट करें", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`" + }, "disconnectPrompt": { "message": "$1 डिस्कनेक्ट करें" }, "disconnectThisAccount": { "message": "इस अकाउंट को डिस्कनेक्ट करें" }, + "disconnectedAllAccountsToast": { + "message": "सभी अकाउंट्स $1 से डिसकनेक्ट किए गए।", + "description": "$1 is name of the dapp`" + }, + "disconnectedSingleAccountToast": { + "message": "$1, $2 से डिसकनेक्ट हो गया", + "description": "$1 is name of the name and $2 represents the dapp name`" + }, + "discoverSnaps": { + "message": "Snaps के बारे में और जानें", + "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." + }, "dismiss": { "message": "खारिज करें" }, @@ -1248,9 +1405,21 @@ "dismissReminderField": { "message": "सीक्रेट रिकवरी फ्रेज़ बैकअप रिमाइंडर खारिज करें" }, + "displayNftMedia": { + "message": "NFT मीडिया को दिखाएं" + }, + "displayNftMediaDescription": { + "message": "NFT मीडिया और डेटा दिखाने से आपका IP एड्रेस OpenSea या अन्य थर्ड पार्टियों के सामने आ जाता है। ऐसा होने पर, हमला करने वाले आपके IP एड्रेस को आपके Ethereum एड्रेस के साथ जोड़ पाते हैं। NFT ऑटोडिटेक्शन की सुविधा इस सेटिंग पर निर्भर करती है, और इस सेटिंग को बंद किए जाने पर उपलब्ध नहीं रहेगी।" + }, + "doNotShare": { + "message": "इसे किसी के साथ शेयर न करें।" + }, "domain": { "message": "डोमेन" }, + "domainNotSupportedOnNetwork": { + "message": "नेटवर्क, डोमेन लुकअप का सपोर्ट नहीं करता" + }, "done": { "message": "हो गया" }, @@ -1269,6 +1438,9 @@ "downloadStateLogs": { "message": "स्टेट लॉग डाउनलोड करें" }, + "dragAndDropBanner": { + "message": "आप नेटवर्कों को फिर से व्यवस्थित करने के लिए उन्हें खींचकर इधर से उधर ले जा सकते हैं।" + }, "dropped": { "message": "ड्रॉप किया गया" }, @@ -1367,6 +1539,9 @@ "editSpeedUpEditGasFeeModalTitle": { "message": "गैस फ़ीस स्पीड अप को बदलें" }, + "enable": { + "message": "चालू करें" + }, "enableAutoDetect": { "message": " ऑटो डिटेक्ट इनेबल करें" }, @@ -1397,6 +1572,18 @@ "enhancedTokenDetectionAlertMessage": { "message": "एडवांस्ड टोकन डिटेक्शन वर्तमान में $1 पर उपलब्ध है। $2" }, + "ensDomainsSettingDescriptionIntroduction": { + "message": "MetaMask आपको सीधे आपके ब्राउज़़र के एड्रेस बार में ENS डोमेन देखने की सुविधा देता है। यह ऐसे काम करता है:" + }, + "ensDomainsSettingDescriptionOutroduction": { + "message": "ध्यान रखें कि इस फ़ीचर का इस्तेमाल करने से आपका आईपी एड्रेस IPFS थर्ड-पार्टी सर्विसेज़ के सामने आ जाता है।" + }, + "ensDomainsSettingDescriptionPart1": { + "message": "ENS नाम से जुड़े कोड को खोजने के लिए MetaMask, Ethereum के ENS कॉन्ट्रैक्ट की जांच करता है।" + }, + "ensDomainsSettingDescriptionPart2": { + "message": "अगर कोड IPFS से लिंक होता है, तो आप उससे जुड़े कंटेंट (आमतौर पर एक वेबसाइट) को देख सकते हैं।" + }, "ensDomainsSettingTitle": { "message": "एड्रेस बार में ENS डोमेन दिखाएँ" }, @@ -1438,6 +1625,9 @@ "message": "गड़बड़ी की जानकारी", "description": "Title for collapsible section that displays error details for debugging purposes" }, + "errorGettingSafeChainList": { + "message": "सेफ चेन लिस्ट पाते समय गड़बड़ी हुई, कृपया सावधानी के साथ जारी रखें।" + }, "errorMessage": { "message": "मैसेज: $1", "description": "Displayed error message for debugging purposes. $1 is the error message" @@ -1469,6 +1659,9 @@ "message": "$1 के साथ गड़बड़ी", "description": "$1 represents the name of the snap" }, + "estimatedFee": { + "message": "अनुमानित फ़ीस" + }, "ethGasPriceFetchWarning": { "message": "बैकअप गैस प्राइस दिया गया है क्योंकि मेन गैस एस्टीमेशन सर्विस अभी उपलब्ध नहीं है।" }, @@ -1495,12 +1688,24 @@ "message": "एक्सपेरिमेंटल" }, "extendWalletWithSnaps": { - "message": "वॉलेट एक्सपीरियंस को कस्टमाइज़ करें।", + "message": "अपने Web3 एक्सपीरियंस को कस्टमाइज़ करने के लिए कम्युनिटी-बिल्ट Snaps को एक्सप्लोर करें।", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "extensionInsallCompleteDescription": { + "message": "अपने कस्टोडियल या सेल्फ-कस्टोडियल एकाउंट्स को जोड़ने के लिए MetaMask Institutional प्रोडक्ट ऑनबोर्डिंग पर वापस आएं।" + }, + "extensionInsallCompleteTitle": { + "message": "एक्सटेंशन इनस्टॉल पूरा हो गया" + }, "externalExtension": { "message": "बाहरी एक्स्टेन्शन" }, + "externalNameSourcesSetting": { + "message": "प्रस्तावित उपनाम" + }, + "externalNameSourcesSettingDescription": { + "message": "हम Etherscan, Infura और लेंस प्रोटोकॉल जैसे थर्ड पार्टी स्रोतों से उन एड्रेसों के लिए प्रस्तावित उपनाम लाएंगे जिनके साथ आप इंटरैक्ट करते हैं। ये स्रोत उन एड्रेसों और आपके आईपी एड्रेस को देख सकेंगे। आपके अकाउंट का एड्रेस थर्ड पार्टी के सामने नहीं आएगा।" + }, "failed": { "message": "नहीं हो पाया" }, @@ -1519,6 +1724,9 @@ "feeAssociatedRequest": { "message": "इस रिक्वेस्ट के साथ एक फ़ीस जुड़ी हुई है।" }, + "feeDetails": { + "message": "फ़ीस का ब्यौरा" + }, "fiat": { "message": "फिएट", "description": "Exchange type" @@ -1551,6 +1759,9 @@ "message": "जोख़िमों को मैं स्वीकर करता हूं।", "description": "this text is shown on a button, which the user presses to confirm they understand the risks of using Flask" }, + "floatAmountToken": { + "message": "टोकन अमाउंट एक पूर्णांक होना चाहिए" + }, "followUsOnTwitter": { "message": "हमें Twitter पर फॉलो करें" }, @@ -1573,6 +1784,9 @@ "fromTokenLists": { "message": "टोकन लिस्टों से: $1" }, + "function": { + "message": "फंक्शन: $1" + }, "functionApprove": { "message": "फंक्शन: एप्रूव करें" }, @@ -1582,6 +1796,13 @@ "functionType": { "message": "फ़ंक्शन का प्रकार" }, + "fundYourWallet": { + "message": "अपने वॉलेट को फंड करें" + }, + "fundYourWalletDescription": { + "message": "अपने वॉलेट में कुछ $1 जोड़कर शुरुआत करें।", + "description": "$1 is the token symbol" + }, "gas": { "message": "गैस" }, @@ -1592,6 +1813,9 @@ "message": "यह गैस फ़ीस $1 द्वारा सुझाया गया है। इसे ओवरराइड करने से आपके ट्रांसेक्शन में समस्या हो सकती है। यदि आपके पास कोई सवाल हैं तो कृपया $1 से इंटरैक्ट करें।", "description": "$1 represents the Dapp's origin" }, + "gasIsETH": { + "message": "गैस $1 है " + }, "gasLimit": { "message": "गैस लिमिट" }, @@ -1636,6 +1860,9 @@ "message": "$1 घंटे", "description": "$1 represents a number of hours" }, + "gasTimingLow": { + "message": "धीमा" + }, "gasTimingMinutesShort": { "message": "$1मिनट", "description": "$1 represents a number of minutes" @@ -1650,15 +1877,29 @@ "general": { "message": "सामान्य" }, - "globalTitle": { - "message": "वैश्विक मेन्यू" + "generalCameraError": { + "message": "हम आपके कैमरे को ऐक्सेस नहीं कर पाए। कृपया दोबारा कोशिश करें।" + }, + "generalCameraErrorTitle": { + "message": "कुछ गलत हो गया..." + }, + "genericExplorerView": { + "message": "$1 पर अकाउंट देखें" + }, + "getStartedWithNFTs": { + "message": "NFTs खरीदने के लिए $1 प्राप्त करें", + "description": "$1 is the token symbol" }, - "globalTourDescription": { - "message": "अपना पोर्टफ़ोलियो, जुड़ी हुई साइटें, सेटिंग्स आदि देखें" + "getStartedWithNFTsDescription": { + "message": "अपने वॉलेट में कुछ $1 जोड़कर NFTs से शुरुआत करें।", + "description": "$1 is the token symbol" }, "goBack": { "message": "वापस जाएं" }, + "goToSite": { + "message": "साइट पर जाएं" + }, "goerli": { "message": "Goerli टेस्ट नेटवर्क" }, @@ -1700,15 +1941,24 @@ "hexData": { "message": "हेक्स डेटा" }, + "hiddenAccounts": { + "message": "छिपाए गए अकाउंट" + }, "hide": { "message": "छिपाएं" }, + "hideAccount": { + "message": "अकाउंट छिपाएं" + }, "hideFullTransactionDetails": { "message": "ट्रांसेक्शन की पूरी जानकारी छिपा कर रखें" }, "hideSeedPhrase": { "message": "सीड फ्रेज़ छुपा दें" }, + "hideSentitiveInfo": { + "message": "संवेदनशील जानकारी छिपाएं" + }, "hideToken": { "message": "टोकन छुपा दें" }, @@ -1790,6 +2040,9 @@ "ignoreTokenWarning": { "message": "यदि आप टोकन छिपाते हैं, तो वे आपके वॉलेट में नहीं दिखाए जाएंगे। हालांकि, आप अभी भी उन्हें खोज कर जोड़ सकते हैं।" }, + "imToken": { + "message": "imToken" + }, "import": { "message": "इम्पोर्ट करें", "description": "Button to import an account from a selected file" @@ -1848,6 +2101,9 @@ "importTokensCamelCase": { "message": "टोकन इम्पोर्ट करें" }, + "importTokensError": { + "message": "हम टोकनों को इंपोर्ट नहीं कर सके। कृपया बाद में फिर से कोशिश करें।" + }, "importWithCount": { "message": "$1 इम्पोर्ट करें", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -1866,6 +2122,9 @@ "initialTransactionConfirmed": { "message": "नेटवर्क द्वारा आपके प्रारंभिक ट्रांसेक्शन को कन्फर्म किया गया था। वापस जाने के लिए ठीक पर क्लिक करें।" }, + "inlineAlert": { + "message": "एलर्ट" + }, "inputLogicEmptyState": { "message": "केवल वही संख्या डालें जो आप अभी या भविष्य में थर्ड पार्टी खर्च के साथ सहज महसूस करते हैं। आप बाद में कभी भी खर्च करने की लिमिट बढ़ा सकते हैं।" }, @@ -1876,6 +2135,27 @@ "inputLogicHigherNumber": { "message": "यह आपको अपने सभी टोकन बैलेंस को तब तक खर्च करने की अनुमति देता है जब तक कि यह सीमा तक नहीं पहुंच जाता या आप खर्च करने की लिमिट को कैंसिल नहीं कर देते। यदि आपका वह इरादा नहीं है, तो कम खर्च करने की लिमिट सेट करने पर विचार करें।" }, + "insightWarning": { + "message": "चेतावनी" + }, + "insightWarningCheckboxMessage": { + "message": "$2 द्वारा किए अनुरोध को $1", + "description": "$1 is the action i.e. sign, confirm. $2 is the origin making the request." + }, + "insightWarningContentPlural": { + "message": "$2 से पहले $1 को रिव्यु करें। एक बार बन जाने के बाद, $3 पहले जैसा नहीं किया जा सकता।", + "description": "$1 the 'insightWarnings' message (2 warnings) representing warnings, $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningContentSingular": { + "message": "$2 से पहले $1 को रिव्यु करें। एक बार बन जाने के बाद, $3 पहले जैसा नहीं किया जा सकता।", + "description": "$1 is the 'insightWarning' message (1 warning), $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningHeader": { + "message": "यह अनुरोध जोखिम भरा हो सकता है" + }, + "insightWarnings": { + "message": "चेतावनियाँ" + }, "insightsFromSnap": { "message": "$1 से इनसाइट्स", "description": "$1 represents the name of the snap" @@ -1883,9 +2163,18 @@ "install": { "message": "इंस्टॉल करें" }, + "installExtension": { + "message": "एक्सटेंशन इनस्टॉल करें" + }, + "installExtensionDescription": { + "message": "दुनिया में तेज़ी से अपना पाँव जमाने वाले Web3 वॉलेट, MetaMask का इंस्टीट्यूशन-कंप्लायंट संस्करण।" + }, "installOrigin": { "message": "ओरिजिन इंस्टॉल करें" }, + "installRequest": { + "message": "MetaMask में जोड़ें" + }, "installedOn": { "message": "$1 पर इंस्टॉल किया गया", "description": "$1 is the date when the snap has been installed" @@ -1914,6 +2203,12 @@ "insufficientTokens": { "message": "कम टोकन।" }, + "interactingWith": { + "message": "के साथ इंटरैक्ट कर रहा है" + }, + "interactingWithTransactionDescription": { + "message": "यह वही कॉन्ट्रैक्ट है जिसके साथ आप इंटरैक्ट कर रहे हैं। विवरण वेरीफाई करके स्कैमर्स से स्वयं को सुरक्षित रखें।" + }, "invalidAddress": { "message": "ग़लत एड्रेस" }, @@ -1986,6 +2281,9 @@ "ipfsToggleModalSettings": { "message": "सेटिंग्स > सुरक्षा और गोपनीयता" }, + "isSigningOrSubmitting": { + "message": "पिछला ट्रांसेक्शन अभी भी साइन या सबमिट किया जा रहा है" + }, "jazzAndBlockies": { "message": "जैज़आइकन्स और ब्लॉकीज़ यूनीक आइकनों की दो अलग-अलग शैलियां हैं जो आपको एक नज़र में किसी अकाउंट की पहचान करने में मदद करती हैं।" }, @@ -1999,6 +2297,24 @@ "message": "JSON फाइल", "description": "format for importing an account" }, + "keyringAccountName": { + "message": "अकाउंट का नाम" + }, + "keyringAccountPublicAddress": { + "message": "पब्लिक एड्रेस" + }, + "keyringSnapRemovalResult1": { + "message": "$1 $2हटाया गया", + "description": "Displays the result after removal of a keyring snap. $1 is the snap name, $2 is whether it is successful or not" + }, + "keyringSnapRemovalResultNotSuccessful": { + "message": "नहीं ", + "description": "Displays the `not` word in $2." + }, + "keyringSnapRemoveConfirmation": { + "message": "अगर आप इस Snap को हटाना चाहते हैं तो इस बात को कन्फर्म करने के लिए $1 टाइप करें:", + "description": "Asks user to input the name nap prior to deleting the snap. $1 is the snap name" + }, "keystone": { "message": "Keystone" }, @@ -2017,9 +2333,15 @@ "lastSold": { "message": "पिछली बार बेचा गया" }, + "lavaDomeCopyWarning": { + "message": "सुरक्षा कारणों से, इस टेक्स्ट को चुनने का विकल्प अभी उपलब्ध नहीं है।" + }, "layer1Fees": { "message": "परत 1 फ़ीस" }, + "layer2Fees": { + "message": "लेयर 2 शुल्क" + }, "learnCancelSpeeedup": { "message": "$1 करने का तरीका जानें", "description": "$1 is link to cancel or speed up transactions" @@ -2037,9 +2359,21 @@ "learnMoreUpperCase": { "message": "अधिक जानें" }, + "learnMoreUpperCaseWithDot": { + "message": "ज़्यादा जानें।" + }, "learnScamRisk": { "message": "घोटाले और सुरक्षा जोखिम।" }, + "learnToBridge": { + "message": "ब्रिज करना सीखें" + }, + "leaveMetaMask": { + "message": "MetaMask से बाहर निकलें?" + }, + "leaveMetaMaskDesc": { + "message": "आप MetaMask के बाहर किसी साइट पर जाने वाले हैं। जारी रखने से पहले URL को दोबारा जांचें।" + }, "ledgerAccountRestriction": { "message": "नया अकाउंट जोड़ने से पहले आपको अपने पिछले अकाउंट का इस्तेमाल करना होगा।" }, @@ -2058,6 +2392,18 @@ "ledgerDeviceOpenFailureMessage": { "message": "Ledger डिवाइस खोलने में नहीं हो पाया। आपका Ledger अन्य सॉफ्टवेयर से कनेक्ट हो सकता है। कृपया Ledger लाइव या अपने Ledger डिवाइस से जुड़े अन्य ऐप्लिकेशन को बंद करें, और फिर से कनेक्ट करने की कोशिश करें।" }, + "ledgerErrorConnectionIssue": { + "message": "अपने Ledger को फिर से कनेक्ट करें, ETH ऐप खोलें और फिर से प्रयास करें।" + }, + "ledgerErrorDevicedLocked": { + "message": "आपका Ledger लॉक हुआ पड़ा है। इसे अनलॉक करें और फिर से प्रयास करें।" + }, + "ledgerErrorEthAppNotOpen": { + "message": "समस्या को हल करने के लिए, अपने डिवाइस पर ETH एप्लिकेशन खोलें और फिर से प्रयास करें।" + }, + "ledgerErrorTransactionDataNotPadded": { + "message": "Ethereum ट्रांसेक्शन का इनपुट डेटा पर्याप्त रूप से पैडेड नहीं है।" + }, "ledgerLiveApp": { "message": "Ledger Live ऐप" }, @@ -2077,6 +2423,9 @@ "lightTheme": { "message": "हल्की" }, + "likeToImportToken": { + "message": "क्या आप इस टोकन को इंपोर्ट करना चाहेंगे?" + }, "likeToImportTokens": { "message": "क्या आप इन टोकन को इंपोर्ट करना चाहते हैं?" }, @@ -2086,6 +2435,9 @@ "lineaMainnet": { "message": "Linea Mainnet" }, + "lineaSepolia": { + "message": "Linea Sepolia टेस्ट नेटवर्क" + }, "link": { "message": "लिंक" }, @@ -2098,8 +2450,11 @@ "loading": { "message": "लोड हो रहा है..." }, - "loadingNFTs": { - "message": "NFTज़ लोड कर रहा है..." + "loadingScreenHardwareWalletMessage": { + "message": "कृपया hardware wallet पर ट्रांजेक्शन पूरा करें।" + }, + "loadingScreenSnapMessage": { + "message": "कृपया Snap पर ट्रांजेक्शन पूरा करें।" }, "loadingTokens": { "message": "टोकन लोड हो रहे हैं..." @@ -2146,6 +2501,9 @@ "message": "पक्का करें कि इसे कोई भी नहीं देख रहा है", "description": "Warning to users to be care while creating and saving their new Secret Recovery Phrase" }, + "manageInSettings": { + "message": "सेटिंग्स में मैनेज करें" + }, "max": { "message": "अधिकतम" }, @@ -2180,15 +2538,34 @@ "metaMaskConnectStatusParagraphTwo": { "message": "कनेक्शन स्थिति बटन दिखाता है कि आप जिस वेबसाइट पर जा रहे हैं, वह आपके वर्तमान में चुना गया अकाउंट से कनेक्ट है।" }, + "metadataModalSourceTooltip": { + "message": "$1 को npm पर होस्ट किया गया है और $2 इस Snap का यूनीक आइडेंटिफायर है।", + "description": "$1 is the snap name and $2 is the snap NPM id." + }, "metamaskInstitutionalVersion": { "message": "MetaMask Institutional वर्शन" }, + "metamaskNotificationsAreOff": { + "message": "वॉलेट नोटिफिकेशंस वर्तमान में सक्रिय नहीं हैं।" + }, + "metamaskPortfolio": { + "message": "MetaMask Portfolio." + }, "metamaskSwapsOfflineDescription": { "message": "MetaMask स्वैप का रखरखाव किया जा रहा है। कृपया बाद में वापस देखें।" }, "metamaskVersion": { "message": "MetaMask वर्शन" }, + "methodData": { + "message": "तरीका" + }, + "methodDataTransactionDescription": { + "message": "यह विशिष्ट कार्रवाई की जाएगी। इस डेटा को जाली बनाया जा सकता है, इसलिए तभी आगे बढ़ें जब आप दूसरी तरफ की साइट पर भरोसा करते हों।" + }, + "methodNotSupported": { + "message": "इस अकाउंट के साथ सपोर्ट नहीं करता है।" + }, "metrics": { "message": "मेट्रिक्स" }, @@ -2224,11 +2601,17 @@ "mmiBuiltAroundTheWorld": { "message": "MetaMask Institutional को दुनिया भर में डिजाइन किया और बनाया गया है।" }, + "mmiNewNFTDetectedInNFTsTabMessage": { + "message": "MetaMask Institutional को ऑटोमेटिक तरीके से NFTs का पता लगाने और आपके वॉलेट में दिखाने के लिए अनुमति दें।" + }, + "mmiPasswordSetupDetails": { + "message": "यह पासवर्ड केवल आपके MetaMask Institutional एक्सटेंशन को ही अनलॉक करेगा।" + }, "more": { "message": "अधिक" }, "multipleSnapConnectionWarning": { - "message": "$1 चाहता है कि $2 Snaps के साथ जुड़े। तभी आगे बढ़ें अगर आप इस वेबसाइट पर भरोसा करते हैं।", + "message": "$1 $2 Snaps का उपयोग करना चाहता है", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." }, "mustSelectOne": { @@ -2237,10 +2620,80 @@ "name": { "message": "नाम" }, + "nameAddressLabel": { + "message": "एड्रेस", + "description": "Label above address field in name component modal." + }, + "nameInstructionsNew": { + "message": "यदि आप इस एड्रेस को जानते हैं, तो भविष्य में इसे पहचानने के लिए इसे एक उपनाम दें।", + "description": "Instruction text in name component modal when value is not recognised." + }, + "nameInstructionsRecognized": { + "message": "इस एड्रेस का एक डिफ़ॉल्ट उपनाम है, लेकिन आप इसे एडिट कर सकते हैं या अन्य सुझाव तलाश सकते हैं।", + "description": "Instruction text in name component modal when value is recognized but not saved." + }, + "nameInstructionsSaved": { + "message": "आपने पहले इस एड्रेस के लिए एक उपनाम जोड़ा है। आप अन्य सुझाए गए उपनामों को एडिट कर या देख सकते हैं।", + "description": "Instruction text in name component modal when value is saved." + }, + "nameLabel": { + "message": "उपनाम", + "description": "Label above name input field in name component modal." + }, + "nameModalMaybeProposedName": { + "message": "शायद: $1", + "description": "$1 is the proposed name" + }, + "nameModalTitleNew": { + "message": "अज्ञात एड्रेस", + "description": "Title of the modal created by the name component when value is not recognised." + }, + "nameModalTitleRecognized": { + "message": "पहचाना गया एड्रेस", + "description": "Title of the modal created by the name component when value is recognized but not saved." + }, + "nameModalTitleSaved": { + "message": "सहेजा गया एड्रेस", + "description": "Title of the modal created by the name component when value is saved." + }, + "nameProviderProposedBy": { + "message": "$1 द्वारा प्रस्तावित", + "description": "$1 is the name of the provider" + }, + "nameProvider_ens": { + "message": "एथेरियम नेम सर्विस (ENS)" + }, + "nameProvider_etherscan": { + "message": "Etherscan" + }, + "nameProvider_lens": { + "message": "लेंस प्रोटोकॉल" + }, + "nameProvider_token": { + "message": "MetaMask" + }, + "nameSetPlaceholder": { + "message": "एक उपनाम चुनें...", + "description": "Placeholder text for name input field in name component modal." + }, + "nativePermissionRequestDescription": { + "message": "क्या आप चाहते हैं कि यह साइट निम्नलिखित कार्य करे?", + "description": "Description below header used on Permission Connect screen for native permissions." + }, "nativeToken": { "message": "इस नेटवर्क पर ओरिजिनल टोकन $1 है। यह गैस फ़ीस के लिए इस्तेमाल किया जाने वाला टोकन है।", "description": "$1 represents the name of the native token on the current network" }, + "nativeTokenScamWarningConversion": { + "message": "नेटवर्क का ब्यौरा बदलें" + }, + "nativeTokenScamWarningDescription": { + "message": "यह नेटवर्क अपनी एसोसिएटेड चेन ID या नाम से मेल नहीं खाता है। कई लोकप्रिय टोकन $1 नाम का उपयोग करते हैं, जिससे इसमें स्कैम किया जा सकता है। स्कैम करने वाले आपको बदले में ज़्यादा कीमती करेंसी भेजने का झांसा दे सकते हैं। आगे बढ़ने से पहले सब कुछ वेरीफाई करें।", + "description": "$1 represents the currency name" + }, + "nativeTokenScamWarningTitle": { + "message": "यह एक बड़ा स्कैम हो सकता है" + }, "needHelp": { "message": "मदद चाहिए? $1 से कॉन्टेक्ट करें", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -2261,6 +2714,9 @@ "negativeETH": { "message": "ETH के नेगेटिव अमाउंट नहीं भेज सकते।" }, + "negativeOrZeroAmountToken": { + "message": "नेगेटिव या ज़ीरो वैल्यू के एसेट नहीं भेज सकते।" + }, "network": { "message": "नेटवर्क:" }, @@ -2291,6 +2747,9 @@ "networkNameBSC": { "message": "BSC" }, + "networkNameBase": { + "message": "बेस" + }, "networkNameDefinition": { "message": "इस नेटवर्क के साथ जुड़ा नाम।" }, @@ -2300,12 +2759,21 @@ "networkNameGoerli": { "message": "गोएर्ली" }, + "networkNameLinea": { + "message": "Linea" + }, + "networkNameOpMainnet": { + "message": "OP मेननेट (mainnet)" + }, "networkNamePolygon": { "message": "बहुभुज" }, "networkNameTestnet": { "message": "Testnet" }, + "networkNameZkSyncEra": { + "message": "zkSync Era" + }, "networkProvider": { "message": "नेटवर्क प्रोवाइडर" }, @@ -2358,6 +2826,19 @@ "newContract": { "message": "नया कॉन्ट्रैक्ट" }, + "newNFTDetectedInImportNFTsMessageStrongText": { + "message": "सेटिंग्स > सुरक्षा और गोपनीयता" + }, + "newNFTDetectedInImportNFTsMsg": { + "message": "अपने NFTs देखने के लिए OpenSea का उपयोग करने के लिए, $1 में 'NFT मीडिया दिखाएं' चालू करें।", + "description": "$1 is used for newNFTDetectedInImportNFTsMessageStrongText" + }, + "newNFTDetectedInNFTsTabMessage": { + "message": "MetaMask को ऑटोमेटिक तरीके से NFTs का पता लगाने और आपके वॉलेट में दिखाने के लिए अनुमति दें।" + }, + "newNFTsAutodetected": { + "message": "NFT ऑटोडिटेक्शन" + }, "newNetworkAdded": { "message": "\"$1\" सफलतापूर्वक जोड़ा गया था!" }, @@ -2367,6 +2848,12 @@ "newPassword": { "message": "नया पासवर्ड (कम-से-कम 8 करैक्टर)" }, + "newPrivacyPolicyActionButton": { + "message": "और पढ़ें" + }, + "newPrivacyPolicyTitle": { + "message": "हमने अपनी गोपनीयता नीति अपडेट कर दी है" + }, "newTokensImportedMessage": { "message": "आपने सफलतापूर्वक $1 इम्पोर्ट कर लिया है।", "description": "$1 is the string of symbols of all the tokens imported" @@ -2388,8 +2875,11 @@ "message": "ये टोकन एक NFT है। $1 जोड़ें", "description": "$1 is a clickable link with text defined by the 'importNFTPage' key" }, + "nftAlreadyAdded": { + "message": "NFT पहले ही जोड़ा जा चुका है।" + }, "nftDisclaimer": { - "message": "अस्वीकरण: MetaMask मीडिया फ़ाइल को स्रोत url से खींचता है। यह url कभी-कभी मार्केटप्लेस द्वारा बदल दिया जाता है जिस पर NFT को मिंट किया गया था।" + "message": "अस्वीकरण: MetaMask मीडिया फ़ाइल को सोर्स url से खींचता है। यह url कभी-कभी मार्केटप्लेस द्वारा बदल दिया जाता है जिस पर NFT को मिंट किया गया था।" }, "nftOptions": { "message": "NFT विकल्प" @@ -2423,12 +2913,21 @@ "noAddressForName": { "message": "इस नाम के लिए कोई एड्रेस नहीं सेट किया गया है।" }, + "noConnectedAccountDescription": { + "message": "जारी रखने के लिए जिस अकाउंट को आप इस साइट पर उपयोग करना चाहते हैं वह अकाउंट चुनें।" + }, + "noConnectedAccountTitle": { + "message": "MetaMask इस साइट से कनेक्टेड नहीं है।" + }, "noConversionDateAvailable": { "message": "कोई करेंसी कन्वर्शन तारीख उपलब्ध नहीं है" }, "noConversionRateAvailable": { "message": "कोई भी कन्वर्शन दर उपलब्ध नहीं है" }, + "noDomainResolution": { + "message": "डोमेन के लिए कोई रिज़ॉल्यूशन प्रदान नहीं किया गया।" + }, "noNFTs": { "message": "अभी तक कोई NFT नहीं" }, @@ -2447,6 +2946,9 @@ "noWebcamFoundTitle": { "message": "वेबकैम नहीं मिला" }, + "nonCustodialAccounts": { + "message": "MetaMask इंस्टीट्यूशनल आपको नॉन-कस्टोडियल अकाउंट का उपयोग करने की अनुमति देता है, यदि आप इन अकाउंट का उपयोग करने की योजना बना रहे हैं, तो सीक्रेट रिकवरी फ्रेज़ का बैकअप लें।" + }, "nonce": { "message": "Nonce" }, @@ -2474,8 +2976,113 @@ "note": { "message": "टिप्पणी" }, - "notePlaceholder": { - "message": "अनुमोदक इस टिप्पणी को कस्टोडियन के पास ट्रांसेक्शन का एप्रूवल करते समय देखेगा।" + "notePlaceholder": { + "message": "अनुमोदक इस टिप्पणी को कस्टोडियन के पास ट्रांसेक्शन का एप्रूवल करते समय देखेगा।" + }, + "notificationDetail": { + "message": "विवरण" + }, + "notificationDetailBaseFee": { + "message": "बेस फी (GWEI)" + }, + "notificationDetailGasLimit": { + "message": "गैस लिमिट (इकाई)" + }, + "notificationDetailGasUsed": { + "message": "इस्तेमाल की गई गैस (इकाई)" + }, + "notificationDetailMaxFee": { + "message": "प्रति गैस अधिकतम फीस" + }, + "notificationDetailNetwork": { + "message": "नेटवर्क" + }, + "notificationDetailNetworkFee": { + "message": "नेटवर्क फी" + }, + "notificationDetailPriorityFee": { + "message": "प्रायोरिटी फी (GWEI)" + }, + "notificationItemCheckBlockExplorer": { + "message": "BlockExplorer पर चेक करें" + }, + "notificationItemCollection": { + "message": "संग्रह" + }, + "notificationItemConfirmed": { + "message": "कन्फर्म किया गया" + }, + "notificationItemError": { + "message": "फ़िलहाल फ़ीस फिर से र्प्राप्त करने में असमर्थ" + }, + "notificationItemFrom": { + "message": "प्रेषक" + }, + "notificationItemLidoStakeReadyToBeWithdrawn": { + "message": "विदड्रॉवल तैयार है" + }, + "notificationItemLidoStakeReadyToBeWithdrawnMessage": { + "message": "अब आप अपना अनस्टेक्ड $1 वापस ले सकते हैं" + }, + "notificationItemLidoWithdrawalRequestedMessage": { + "message": "$1 को अनस्टेक करने का आपका अनुरोध भेज दिया गया है" + }, + "notificationItemNFTReceivedFrom": { + "message": "से NFT को प्राप्त किया गया" + }, + "notificationItemNFTSentTo": { + "message": "को NFT भेजा गया" + }, + "notificationItemNetwork": { + "message": "नेटवर्क" + }, + "notificationItemRate": { + "message": "दर (शुल्क शामिल है)" + }, + "notificationItemReceived": { + "message": "प्राप्त किया गया" + }, + "notificationItemReceivedFrom": { + "message": "से प्राप्त किया गया" + }, + "notificationItemSent": { + "message": "भेजा गया" + }, + "notificationItemSentTo": { + "message": "को भेजा गया" + }, + "notificationItemStakeCompleted": { + "message": "स्टेक पूरा हुआ" + }, + "notificationItemStaked": { + "message": "स्टेक किया गया" + }, + "notificationItemStakingProvider": { + "message": "स्टेकिंग प्रदाता" + }, + "notificationItemStatus": { + "message": "स्टेटस" + }, + "notificationItemSwapped": { + "message": "स्वैप किया गया" + }, + "notificationItemSwappedFor": { + "message": "के लिए" + }, + "notificationItemTo": { + "message": "प्रति" + }, + "notificationItemTransactionId": { + "message": "ट्रांसेक्शन आईडी" + }, + "notificationItemUnStakeCompleted": { + "message": "अनस्टेकिंग पूरा हुआ" + }, + "notificationItemUnStaked": { + "message": "अनस्टेक किया गया" + }, + "notificationItemUnStakingRequested": { + "message": "अनस्टेकिंग का अनुरोध किया गया" }, "notificationTransactionFailedMessage": { "message": "ट्रांसेक्शन $1 नहीं हो पाया! $2", @@ -2504,43 +3111,6 @@ "notifications": { "message": "सूचनाएं" }, - "notifications20ActionText": { - "message": "और अधिक जानें", - "description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a ledger page to resolve the U2F connection issue." - }, - "notifications20Description": { - "message": "यदि आप फायरफॉक्स के लेटेस्ट वर्शन का इस्तेमाल कर रहे हैं, तो आप फायरफॉक्स से U2F सपोर्ट छोड़ने से संबंधित समस्या का अनुभव कर सकते हैं।", - "description": "Description of a notification in the 'See What's New' popup. Describes the U2F support being dropped by firefox and that it affects ledger users." - }, - "notifications20Title": { - "message": "Ledger और फायरफॉक्स यूज़र कनेक्शन संबंधी समस्याओं का सामना कर रहे हैं", - "description": "Title for a notification in the 'See What's New' popup. Tells users that latest firefox users using U2F may experience connection issues." - }, - "notifications24ActionText": { - "message": "समझ गए" - }, - "notifications24Description": { - "message": "आपके द्वारा उपयोग किए जा रहे नेटवर्क के आधार पर एडवांस्ड गैस फीस सेटिंग्स अब याद रखी जाती हैं। इसका मतलब है कि आप हरेक नेटवर्क के लिए खास एडवांस्ड गैस फीस तय कर सकते हैं और गैस के लिए ज़्यादा पेमेंट करने से या ट्रांजेक्शन अटकने की समस्या से बच सकते हैं।" - }, - "notifications24Title": { - "message": "नेटवर्क द्वारा एडवांस्ड गैस फीस" - }, - "notifications8ActionText": { - "message": "सेटिंग्स पर जाएं > एडवांस्ड", - "description": "Description on an action button that appears in the What's New popup. Tells the user that if they click it, they will go to our Advanced settings page." - }, - "notifications8DescriptionOne": { - "message": "MetaMask v10.4.0 के अनुसार, अब आपको अपने Ledger डिवाइस को MetaMask से कनेक्ट करने के लिए Ledger लाइव की आवश्यकता नहीं है।", - "description": "Description of a notification in the 'See What's New' popup. Describes changes for how Ledger Live is no longer needed to connect the device." - }, - "notifications8DescriptionTwo": { - "message": "एक आसान और अधिक स्थिर Ledger अनुभव के लिए, सेटिंग्स के एडवांस्ड टैब पर जाएं और 'पसंदीदा Ledger कनेक्शन प्रकार' को 'WebHID' पर स्विच करें।", - "description": "Description of a notification in the 'See What's New' popup. Describes how the user can turn off the Ledger Live setting." - }, - "notifications8Title": { - "message": "Ledger कनेक्शन में सुधार", - "description": "Title for a notification in the 'See What's New' popup. Notifies ledger users that there is an improvement in how they can connect their device." - }, "notificationsDropLedgerFirefoxDescription": { "message": "Firefox अब U2F का सपोर्ट नहीं करता है, इसलिए Firefox पर MetaMask के साथ Ledger काम नहीं करेगा। इसके बजाय, Google Chrome पर MetaMask इस्तेमाल करके देखें।", "description": "Description of a notification in the 'See What's New' popup. Describes that ledger will not longer be supported for firefox users and they should use MetaMask on chrome for ledger support instead." @@ -2549,33 +3119,37 @@ "message": "Firefox के लिए Ledger को मिलने वाला सपोर्ट खत्म किया जा रहा है", "description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped." }, - "notificationsEmptyText": { - "message": "यहाँ देखने के लिए कुछ नहीं है।" - }, - "notificationsHeader": { - "message": "सूचनाएं" + "notificationsFeatureToggle": { + "message": "वॉलेट नोटिफिकेशन को चालू करें", + "description": "Experimental feature title" }, - "notificationsInfos": { - "message": "$1 को $2 से", - "description": "$1 is the date at which the notification has been dispatched and $2 is the link to the snap that dispatched the notification." + "notificationsFeatureToggleDescription": { + "message": "इससे फंड भेजने/प्राप्त करने या nfts और फ़ीचर से संबंधित घोषणाओं जैसे वॉलेट नोटिफिकेशन चालू हो जाते हैं।", + "description": "Description of the experimental notifications feature" }, "notificationsMarkAllAsRead": { "message": "सभी को पढ़ा हुआ चिन्हित करें" }, - "notificationsOpenBetaSnapsActionText": { - "message": "ज्यादा जानें।" + "notificationsPageEmptyTitle": { + "message": "यहाँ देखने के लिए कुछ नहीं है।" + }, + "notificationsPageErrorContent": { + "message": "कृपया, इस पेज पर दोबारा आने का प्रयास करें।" + }, + "notificationsPageErrorTitle": { + "message": "एक गड़बड़ी हुई है" }, - "notificationsOpenBetaSnapsDescriptionOne": { - "message": "🎉 MetaMask Snaps के Open Beta की घोषणा करते हुए हमें खुशी का अनुभव हो रहा है!" + "notificationsPageNoNotificationsContent": { + "message": "आपको अभी तक कोई नोटिफिकेशंस नहीं मिली है।" }, - "notificationsOpenBetaSnapsDescriptionThree": { - "message": "डेवलेपर कम्युनिटी द्वारा तैयार किए गए Snaps के साथ अपने वॉलेट को निजीकृत करें!" + "notificationsSettingsBoxError": { + "message": "कुछ गलत हो गया। कृपया फिर से कोशिश करें" }, - "notificationsOpenBetaSnapsDescriptionTwo": { - "message": "Snaps की मदद से आप MetaMask के साथ और भी बहुत कुछ कर सकते हैं - जैसे, ज़्यादा नेटवर्कों से जुड़ना, ट्रांजेक्शन से संबंधित जानकारी देखना और कस्टम नोटिफ़िकेशन्स पाना।" + "notificationsSettingsPageAllowNotifications": { + "message": "नोटिफिकेशंस के साथ आपके वॉलेट में क्या हो रहा है, इसकी जानकारी रखें। नोटिफिकेशंस का उपयोग करने के लिए, हम आपके डिवाइस में कुछ सेटिंग्स को सिंक करने के लिए एक प्रोफ़ाइल का उपयोग करते हैं। $1" }, - "notificationsOpenBetaSnapsTitle": { - "message": "पेश हैं MetaMask Snaps" + "notificationsSettingsPageAllowNotificationsLink": { + "message": "जानें कि इस फीचर का उपयोग करते समय हम आपकी गोपनीयता की सुरक्षा कैसे करते हैं।" }, "numberOfNewTokensDetectedPlural": { "message": "इस अकाउंट में $1 के नए टोकन पाए गए", @@ -2599,6 +3173,9 @@ "on": { "message": "चालू" }, + "onboarding": { + "message": "ऑनबोर्ड हो रहा है" + }, "onboardingAdvancedPrivacyIPFSDescription": { "message": "IPFS (आईपीएफएस) गेटवे थर्ड पार्टियों द्वारा होस्ट किए गए डेटा को एक्सेस करना और देखना संभव बनाता है। आप एक कस्टम IPFS गेटवे जोड़ सकते हैं या डिफॉल्ट का इस्तेमाल जारी रख सकते हैं।" }, @@ -2629,51 +3206,45 @@ "onboardingMetametricsAgree": { "message": "मैं सहमत हूं" }, - "onboardingMetametricsAllowOptOut": { - "message": "सेटिंग के माध्यम से आपको हमेशा ऑप्ट-आउट करने की अनुमति देता है" - }, - "onboardingMetametricsDataTerms": { - "message": "यह डेटा एकत्र किया गया है और इसलिए सामान्य डेटा संरक्षण विनियम (EU) 2016/679 के उद्देश्यों के लिए अज्ञात है।" - }, "onboardingMetametricsDescription": { - "message": "MetaMask यह समझने के लिए इस्तेमाल डेटा एकत्र करना चाहता है कि हमारे यूज़र MetaMask से कैसे इंटरैक्ट करते हैं। इस डेटा का इस्तेमाल सर्विस प्रदान करने के लिए किया जाएगा, जिसमें आपके इस्तेमाल के आधार पर सर्विस में सुधार करना शामिल है।" + "message": "हम MetaMask को बेहतर बनाने के लिए बुनियादी यूसेज और डाएगोनोस्टिक्स डेटा कलेक्ट करना चाहेंगे। जान लें कि हम आपके द्वारा यहां उपलब्ध कराया गया डेटा कभी नहीं बेचते हैं।" }, "onboardingMetametricsDescription2": { - "message": "MetaMask करेगा..." + "message": "जब हम मेट्रिक्स इकट्ठा करते हैं, तो यह हमेशा... रहेगा" }, "onboardingMetametricsDisagree": { "message": "जी नहीं, धन्यवाद" }, "onboardingMetametricsInfuraTerms": { - "message": "* जब आप MetaMask में अपने डिफॉल्ट RPC प्रोवाइडर के रूप में Infura का इस्तेमाल करते हैं, तो जब आप ट्रांसेक्शन भेजते हैं तो Infura आपका IP एड्रेस और आपके Ethereum वॉलेट का एड्रेस एकत्र कर लेगा। हम इस जानकारी को इस तरह से संगृहीत नहीं करते हैं जिससे हमारे सिस्टम डेटा के उन दो टुकड़ों को जोड़ सकें। डेटा संग्रह के दृष्टिकोण से MetaMask और Infura कैसे इंटरैक्ट करते हैं, इस बारे में अधिक जानकारी के लिए, हमारा अपडेट $1 देखें। सामान्य तौर पर हमारे गोपनीयता के कार्यप्रणाली के बारे में अधिक जानकारी के लिए, हमारा $2 देखें।", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" + "message": "यदि हम इस डेटा का उपयोग अन्य उद्देश्यों के लिए करने का निर्णय लेते हैं तो हम आपको बताएंगे। अधिक जानकारी के लिए आप हमारे $1 की समीक्षा कर सकते हैं। याद रखें, आप किसी भी समय सेटिंग्स में जाकर ऑप्ट आउट कर सकते हैं।", + "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, "onboardingMetametricsInfuraTermsPolicy": { - "message": "यहां गोपनीयता नीति" - }, - "onboardingMetametricsInfuraTermsPolicyLink": { - "message": "यहां" + "message": "गोपनीयता नीति" }, "onboardingMetametricsModalTitle": { "message": "कस्टम नेटवर्क जोड़ें" }, "onboardingMetametricsNeverCollect": { - "message": "$1 ऐसी जानकारी एकत्र करते हैं जिसे हमें सर्विस प्रदान करने की आवश्यकता नहीं है (जैसे कुंजियां, एड्रेस, ट्रांसेक्शन के उलझन, या बैलेंस)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "ऐप पर $1 क्लिक और व्यूज़ स्टोर किए जाते हैं, लेकिन अन्य विवरण (जैसे आपका पब्लिक एड्रेस) स्टोर नहीं होते।", + "description": "$1 represents `onboardingMetametricsNeverCollectEmphasis`" + }, + "onboardingMetametricsNeverCollectEmphasis": { + "message": "निजी:" }, "onboardingMetametricsNeverCollectIP": { - "message": "$1 आपका पूरा IP एड्रेस एकत्र करते हैं*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 हम किसी सामान्य स्थान (जैसे आपका देश या क्षेत्र) का पता लगाने के लिए अस्थायी रूप से आपके आईपी ​​एड्रेस का उपयोग करते हैं, लेकिन इसे कभी स्टोर नहीं किया जाता है।", + "description": "$1 represents `onboardingMetametricsNeverCollectIPEmphasis`" }, - "onboardingMetametricsNeverEmphasis": { - "message": "कभी नहीं" + "onboardingMetametricsNeverCollectIPEmphasis": { + "message": "सामान्य:" }, "onboardingMetametricsNeverSellData": { - "message": "$1 डेटा बेचते हैं। कभी!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 आप तय करते हैं कि आप किसी भी समय सेटिंग्स के माध्यम से अपना यूसेज डेटा शेयर करना चाहते हैं या हटाना चाहते हैं।", + "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" }, - "onboardingMetametricsSendAnonymize": { - "message": "अज्ञात क्लिक और पेजव्यू इवेंट भेजें" + "onboardingMetametricsNeverSellDataEmphasis": { + "message": "वैकल्पिक:" }, "onboardingMetametricsTitle": { "message": "MetaMask को बेहतर बनाने में हमारी मदद करें" @@ -2714,15 +3285,26 @@ "onboardingPinExtensionTitle": { "message": "आपका MetaMask इंस्टॉल पूरा हो गया है!" }, + "onboardingPinMmiExtensionLabel": { + "message": "MetaMask Institutional को पिन करें" + }, "onboardingUsePhishingDetectionDescription": { "message": "फिशिंग डिटेक्शन अलर्ट $1 के साथ संचार पर निर्भर करते हैं। jsDeliver की पहुंच आपके IP एड्रेस तक होगी। $2 देखें।", "description": "The $1 is the word 'jsDeliver', from key 'jsDeliver' and $2 is the words Privacy Policy from key 'privacyMsg', both separated here so that it can be wrapped as a link" }, + "onekey": { + "message": "OneKey" + }, "onlyAddTrustedNetworks": { "message": "एक बुरी नीयत वाला नेटवर्क प्रोवाइडर ब्लॉकचेन की स्थिति के बारे में झूठ बोल सकता है और आपकी नेटवर्क एक्टिविटी को रिकॉर्ड कर सकता है। केवल उन कस्टम नेटवर्क को जोड़ें, जिन पर आप भरोसा करते हैं।" }, "onlyConnectTrust": { - "message": "केवल उन साइटों से कनेक्ट करें, जिन पर आप भरोसा करते हैं।" + "message": "केवल उन साइटों से कनेक्ट करें, जिन पर आप भरोसा करते हैं। $1", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." + }, + "openCustodianApp": { + "message": "$1 ऐप खोलें", + "description": "The $1 is the name of the Custodian that will be open" }, "openFullScreenForLedgerWebHid": { "message": "अपने Ledger को कनेक्ट करने के लिए फुल स्क्रीन पर जाएं।", @@ -2734,6 +3316,15 @@ "openSeaNew": { "message": "ओपनसी" }, + "openSeaToBlockaidBtnLabel": { + "message": "Snaps को एक्सप्लोर करें" + }, + "openSeaToBlockaidDescription": { + "message": "सुरक्षा एलर्ट अब इस नेटवर्क पर उपलब्ध नहीं हैं। Snap इंस्टॉल करने से आपकी सुरक्षा में सुधार हो सकता है।" + }, + "openSeaToBlockaidTitle": { + "message": "सतर्क रहें!" + }, "operationFailed": { "message": "प्रचालन नहीं हो पाया" }, @@ -2777,6 +3368,9 @@ "password": { "message": "पासवर्ड" }, + "passwordMmiTermsWarning": { + "message": "मैं समझता हूं कि MetaMask Institutional मेरे लिए इस पासवर्ड को रिकवर नहीं कर सकता। $1" + }, "passwordNotLongEnough": { "message": "पासवर्ड की लंबाई पर्याप्त नहीं है" }, @@ -2803,6 +3397,10 @@ "message": "अपनी प्राइवेट की (key) स्ट्रिंग यहाँ पेस्ट करें:", "description": "For importing an account from a private key" }, + "paymasterInUse": { + "message": "इस ट्रांसेक्शन के लिए गैस का पेमेंट पेमास्टर द्वारा किया जाएगा।", + "description": "Alert shown in transaction confirmation if paymaster in use." + }, "pending": { "message": "लंबित" }, @@ -2816,18 +3414,26 @@ "message": "आपके पास (1) लंबित ट्रांसेक्शन है।", "description": "$1 is count of pending transactions" }, + "permissionDetails": { + "message": "अनुमति का ब्यौरा" + }, "permissionRequest": { "message": "अनुमति अनुरोध" }, - "permissionRequestCapitalized": { - "message": "अनुमति के लिए अनुरोध" - }, "permissionRequested": { "message": "अब रिक्वेस्ट किया गया" }, + "permissionRequestedForAccounts": { + "message": "अभी $1 के लिए अनुरोध किया गया", + "description": "Permission cell status for requested permission including accounts, rendered as AvatarGroup which is $1." + }, "permissionRevoked": { "message": "इस अपडेट में कैंसिल किया गया" }, + "permissionRevokedForAccounts": { + "message": "$1 के लिए इस अपडेट में हटाया गया", + "description": "Permission cell status for revoked permission including accounts, rendered as AvatarGroup which is $1." + }, "permission_accessNamedSnap": { "message": "$1 से कनेक्ट करें।", "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." @@ -2836,6 +3442,10 @@ "message": "इंटरनेट एक्सेस करें।", "description": "The description of the `endowment:network-access` permission." }, + "permission_accessNetworkDescription": { + "message": "$1 को इंटरनेट एक्सेस करने दें। इसका इस्तेमाल थर्ड-पार्टी सर्वर के साथ डेटा भेजने और प्राप्त करने दोनों के लिए किया जा सकता है।", + "description": "An extended description of the `endowment:network-access` permission. $1 is the snap name." + }, "permission_accessSnap": { "message": "$1 Snap से कनेक्ट करें।", "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." @@ -2848,10 +3458,18 @@ "message": "समय-समय पर आने वाले क्रियाओं को शेड्यूल और निष्पादित करें।", "description": "The description for the `snap_cronjob` permission" }, + "permission_cronjobDescription": { + "message": "$1 को अनुमति दें ताकि वह तय समय, तारीख या इंटरवल पर किए जाने वाले एक्शन कर सके। इसका इस्तेमाल टाइम-सेंसिटिव इंटरैक्शन या नोटिफिकेशन्स को ट्रिगर करने के लिए किया जा सकता है।", + "description": "An extended description for the `snap_cronjob` permission. $1 is the snap name." + }, "permission_dialog": { "message": "MetaMask में डायलॉग विंडो प्रदर्शित करें।", "description": "The description for the `snap_dialog` permission" }, + "permission_dialogDescription": { + "message": "$1 को MetaMask पॉपअप को कस्टम टेक्स्ट, इनपुट फील्ड और किसी एक्शन को एप्रूव या रिजेक्ट करने के बटन दिखाने की अनुमति दें।\nउदाहरण के लिए, Snap के लिए एलर्ट, कन्फर्मेशन और ऑप्ट-इन फ्लो क्रिएट करने के लिए इसका इस्तेमाल किया जा सकता है।", + "description": "An extended description for the `snap_dialog` permission. $1 is the snap name." + }, "permission_ethereumAccounts": { "message": "एड्रेस, अकाउंट का बैलेंस, एक्टिविटी देखें और ट्रांसेक्शन शुरू करें", "description": "The description for the `eth_accounts` permission" @@ -2860,30 +3478,138 @@ "message": "Ethereum प्रोवाइडर को ऐक्सेस करें।", "description": "The description for the `endowment:ethereum-provider` permission" }, + "permission_ethereumProviderDescription": { + "message": "$1 को MetaMask के साथ सीधे कम्यूनिकेट करने की अनुमति दें, ताकि वह ब्लॉकचेन से डेटा पढ़ सके और मैसेज और ट्रांसेक्शन का सुझाव दे सके।", + "description": "An extended description for the `endowment:ethereum-provider` permission. $1 is the snap name." + }, + "permission_getEntropy": { + "message": "$1 के लिए unique arbitrary कीज़ डिराइव करें।", + "description": "The description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getEntropyDescription": { + "message": "सबके सामने लाए बिना, $1 को $1 के लिए unique arbitrary कीज़ डिराइव करने की अनुमति दें। ये कीज़ आपके MetaMask अकाउंट (एकाउंट्स) से अलग हैं और आपकी प्राइवेट कीज़ (keys) या सीक्रेट रिकवरी फ्रेज़ से संबंधित नहीं हैं। अन्य Snaps इस जानकारी को एक्सेस नहीं कर सकते।", + "description": "An extended description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getLocale": { + "message": "अपनी पसंदीदा भाषा देखें।", + "description": "The description for the `snap_getLocale` permission" + }, + "permission_getLocaleDescription": { + "message": "$1 को आपकी MetaMask सेटिंग्स से आपकी पसंदीदा भाषा ऐक्सेस करने दें। इसे आपकी भाषा का उपयोग करके $1 के कंटेंट का स्थानीय भाषा में अनुवाद करने और उसे दिखाने के लिए इस्तेमाल किया जा सकता है।", + "description": "An extended description for the `snap_getLocale` permission. $1 is the snap name." + }, + "permission_homePage": { + "message": "एक कस्टम स्क्रीन दिखाएं", + "description": "The description for the `endowment:page-home` permission" + }, + "permission_homePageDescription": { + "message": "$1 को MetaMask में एक कस्टम होम स्क्रीन प्रदर्शित करने दें। इसका उपयोग यूजर इंटरफेस, कॉन्फ़िगरेशन और डैशबोर्ड के लिए किया जा सकता है।", + "description": "An extended description for the `endowment:page-home` permission. $1 is the snap name." + }, + "permission_keyring": { + "message": "Ethereum एकाउंट्स को जोड़ने और नियंत्रित करने की अनुरोध को अनुमति दें", + "description": "The description for the `endowment:keyring` permission" + }, + "permission_keyringDescription": { + "message": "$1 को एकाउंट्स जोड़ने या हटाने की रिक्वेस्ट रिसीव करने दें। साथ ही, इन एकाउंट्स की ओर से साइन करने और ट्रांसेक्शन करने दें।", + "description": "An extended description for the `endowment:keyring` permission. $1 is the snap name." + }, "permission_lifecycleHooks": { "message": "लाइफसाइकल हुक्स का इस्तेमाल करें।", "description": "The description for the `endowment:lifecycle-hooks` permission" }, + "permission_lifecycleHooksDescription": { + "message": "$1 को उसके लाइफसाइकल के दौरान खास समयों पर कोड चलाने के लिए लाइफसाइकल हुक का इस्तेमाल करने की अनुमति दें।", + "description": "An extended description for the `endowment:lifecycle-hooks` permission. $1 is the snap name." + }, "permission_manageAccounts": { "message": "Ethereum अकाउंट जोड़ें और नियंत्रित करें", "description": "The description for `snap_manageAccounts` permission" }, + "permission_manageAccountsDescription": { + "message": "$1 को Ethereum अकाउंट जोड़ने या हटाने, फिर इन एकाउंट्स से ट्रांसेक्ट करने और साइन करने की अनुमति दें।", + "description": "An extended description for the `snap_manageAccounts` permission. $1 is the snap name." + }, + "permission_manageBip32Keys": { + "message": "$1 एकाउंट्स को मैनेज करें।", + "description": "The description for the `snap_getBip32Entropy` permission. $1 is a derivation path, e.g. 'm/44'/0'/0' (secp256k1)'." + }, + "permission_manageBip44AndBip32KeysDescription": { + "message": "$1 को, रिक्वेस्ट किए गए नेटवर्क पर एकाउंट्स और एसेट्स को मैनेज करने की अनुमति दें। ये एकाउंट्स, आपके सीक्रेट रिकवरी फ्रेज़ (इसे सामने लाए बिना) का उपयोग करके डिराइव और बैकअप किए जाते हैं। $1 में Keys डिराइव करने की पावर होती है जिसके माध्यम से वह Ethereum (EVMs) के अलावा भी कई प्रकार के ब्लॉकचेन प्रोटोकॉल को सपोर्ट कर सकता है।", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions. $1 is the snap name." + }, + "permission_manageBip44Keys": { + "message": "$1 एकाउंट्स को मैनेज करें।", + "description": "The description for the `snap_getBip44Entropy` permission. $1 is the name of a protocol, e.g. 'Filecoin'." + }, "permission_manageState": { "message": "उसके डेटा को अपने डिवाइस पर स्टोर करें और प्रबंधित करें।", "description": "The description for the `snap_manageState` permission" }, + "permission_manageStateDescription": { + "message": "$1 को एन्क्रिप्शन के साथ सुरक्षित रूप से डेटा को स्टोर करने, अपडेट करने और फिर से पाने की अनुमति दें। अन्य Snaps इस जानकारी को एक्सेस नहीं कर सकते।", + "description": "An extended description for the `snap_manageState` permission. $1 is the snap name." + }, + "permission_nameLookup": { + "message": "डोमेन और एड्रेस लुकअप उपलब्ध कराएं।", + "description": "The description for the `endowment:name-lookup` permission." + }, + "permission_nameLookupDescription": { + "message": "Snap को MetaMask यूआई के विभिन्न हिस्सों में एड्रेस और डोमेन लुकअप को पाने और दिखाने की अनुमति दें।", + "description": "An extended description for the `endowment:name-lookup` permission." + }, "permission_notifications": { "message": "नोटीफिकेशंस दिखाएं।", "description": "The description for the `snap_notify` permission" }, + "permission_notificationsDescription": { + "message": "$1 को MetaMask के भीतर नोटिफिकेशन दिखाने की अनुमति दें। Snap के माध्यम से एक्शनेबल या टाइम-सेंसिटिव जानकारी के लिए एक शॉर्ट नोटिफिकेशन टेक्स्ट को ट्रिगर किया जा सकता है।", + "description": "An extended description for the `snap_notify` permission. $1 is the snap name." + }, + "permission_rpc": { + "message": "$1 को $2 से सीधे कम्यूनिकेट करने की अनुमति दें।", + "description": "The description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescription": { + "message": "$1 को अनुमति दें कि वह $2 को मैसेज भेज सके और $2 से जवाब पा सके।", + "description": "An extended description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescriptionOriginList": { + "message": "$1 और $2", + "description": "A list of allowed origins where $2 is the last origin of the list and $1 is the rest of the list separated by ','." + }, + "permission_signatureInsight": { + "message": "सिग्नेचर इनसाइट्स मोडल दिखाएं।", + "description": "The description for the `endowment:signature-insight` permission" + }, + "permission_signatureInsightDescription": { + "message": "एप्रूव करने से पहले $1 को किसी भी सिग्नेचर रिक्वेस्ट पर इनसाइट्स के साथ एक मोडल दिखाने की अनुमति दें। इसका उपयोग एंटी-फ़िशिंग और सिक्योरटी सॉल्यूशंस के लिए किया जा सकता है।", + "description": "An extended description for the `endowment:signature-insight` permission. $1 is the snap name." + }, + "permission_signatureInsightOrigin": { + "message": "उन वेबसाइटों के ओरिजिन देखें जो सिग्नेचर रिक्वेस्ट शुरू करती हैं", + "description": "The description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission" + }, + "permission_signatureInsightOriginDescription": { + "message": "सिग्नेचर रिक्वेस्ट शुरू करने वाली वेबसाइटों का ओरिजिन (URI) देखने के लिए $1 को अनुमति दें। इसका उपयोग एंटी-फ़िशिंग और सिक्योरटी सॉल्यूशंस के लिए किया जा सकता है।", + "description": "An extended description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission. $1 is the snap name." + }, "permission_transactionInsight": { "message": "ट्रांजैक्शन इनसाइट्स प्राप्त करें और प्रदर्शित करें।", "description": "The description for the `endowment:transaction-insight` permission" }, + "permission_transactionInsightDescription": { + "message": "$1 को ट्रांसेक्शन को डिकोड करने और MetaMask UI के भीतर इनसाइट्स दिखाने की अनुमति दें। इसका इस्तेमाल एंटी-फिशिंग और सिक्यूरिटी सॉल्युशन्स के लिए किया जा सकता है।", + "description": "An extended description for the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_transactionInsightOrigin": { "message": "ट्रांसेक्शन का सुझाव देने वाली वेबसाइटों की स्रोत देखें", "description": "The description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission" }, + "permission_transactionInsightOriginDescription": { + "message": "$1 को ट्रांसेक्शन का सुझाव देने वाली वेबसाइटों के ओरिजिन (URI) को देखने की अनुमति दें। इसका इस्तेमाल एंटी-फिशिंग और सिक्यूरिटी सॉल्युशन्स के लिए किया जा सकता है।", + "description": "An extended description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_unknown": { "message": "अज्ञात अनुमति: $1", "description": "$1 is the name of a requested permission that is not recognized." @@ -2892,29 +3618,66 @@ "message": "$1 ($2) के लिए अपनी पब्लिक की को देखें।", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a derivation path, e.g. 'm/44'/0'/0''. $2 is the elliptic curve name, e.g. 'secp256k1'." }, + "permission_viewBip32PublicKeysDescription": { + "message": "$2 को यह अनुमति दें कि वह $1 के लिए आपकी पब्लिक कीज़ (keys) (और एड्रेसों) को देख सके। इस अनुमति से आपके एकाउंट्स या एसेट्स पर कोई कंट्रोल नहीं मिलता है।", + "description": "An extended description for the `snap_getBip32PublicKey` permission. $1 is a derivation path (name). $2 is the snap name." + }, "permission_viewNamedBip32PublicKeys": { "message": "$1 के लिए अपनी पब्लिक की को देखें", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a name for the derivation path, e.g., 'Ethereum accounts'." }, + "permission_walletSwitchEthereumChain": { + "message": "निम्न नेटवर्क पर स्विच करें और उसका उपयोग करें", + "description": "The label for the `wallet_switchEthereumChain` permission" + }, "permission_webAssembly": { "message": "वेब असेंबली के लिए सपोर्ट।", "description": "The description of the `endowment:webassembly` permission." }, + "permission_webAssemblyDescription": { + "message": "$1 को यह अनुमति दें कि वह WebAssembly के माध्यम से लो-लेवल एक्सीक्यूशन वाले एनवायरनमेंट को एक्सेस कर सके।", + "description": "An extended description of the `endowment:webassembly` permission. $1 is the snap name." + }, "permissions": { "message": "अनुमतियाँ" }, - "permissionsTitle": { - "message": "अनुमतियां" + "permissionsPageEmptyContent": { + "message": "यहाँ देखने के लिए कुछ नहीं है।" + }, + "permissionsPageEmptySubContent": { + "message": "यहां पर आप इंस्टॉल किए गए Snaps या कनेक्टेड साइटों को दी गई अनुमतियां देख सकते हैं।" + }, + "permissionsPageTourDescription": { + "message": "कनेक्टेड साइटों और इंस्टॉल किए गए Snaps को दी गई अनुमतियों को मैनेज करने के लिए यह आपका कंट्रोल पैनल है।" }, - "permissionsTourDescription": { - "message": "अपने जुड़े हुए अकाउंट ढूंढें और अनुमतियां यहां प्रबंधित करें" + "permissionsPageTourTitle": { + "message": "कनेक्टेड साइटें अब अनुमतियां हैं" }, "personalAddressDetected": { "message": "व्यक्तिगत एड्रेस का एड्रेस चला। टोकन कॉन्ट्रैक्ट एड्रेस डालें।" }, + "petnamesEnabledToggle": { + "message": "उपनामों की अनुमति दें" + }, + "petnamesEnabledToggleDescription": { + "message": "यह आपको किसी भी एड्रेस पर एक उपनाम देने की सुविधा देता है। जब भी संभव होगा हम उन एड्रेसों के लिए नाम सुझाएंगे जिनसे आप इंटरैक्ट करते हैं।" + }, + "pinExtensionDescription": { + "message": "बिना रोक-टोक एक्सेस के लिए एक्सटेंशन मेनू पर जाएं और MetaMask Institutional को पिन करें।" + }, + "pinExtensionTitle": { + "message": "एक्सटेंशन को पिन करें" + }, + "pinToTop": { + "message": "सबसे ऊपर ले जाएं" + }, "pleaseConfirm": { "message": "कृपया कन्फर्म करें" }, + "plusMore": { + "message": "+ $1 और", + "description": "$1 is the number of additional items" + }, "plusXMore": { "message": "+ $1 अधिक", "description": "$1 is a number of additional but unshown items in a list- this message will be shown in place of those items" @@ -2940,6 +3703,9 @@ "primaryCurrencySettingDescription": { "message": "चेन की ओरिजिनल करेंसी (जैसे ETH) में प्रदर्शित वैल्यूज़ को प्राथमिकता देने के लिए ओरिजिनल को चुनें। अपनी चुना गया फिएट करेंसी में प्रदर्शित वैल्यूज़ को प्राथमिकता देने के लिए फिएट को चुनें।" }, + "primaryType": { + "message": "प्राइमरी टाइप" + }, "priorityFee": { "message": "प्रायोरिटी फी" }, @@ -2960,6 +3726,18 @@ "message": "$1 के लिए प्राइवेट की (key)", "description": "$1 represents the account name" }, + "privateKeyHidden": { + "message": "प्राइवेट की (key) छिपी हुई है", + "description": "Explains that the private key input is hidden" + }, + "privateKeyShow": { + "message": "प्राइवेट की (key) इनपुट को दिखाएं/छिपाएं", + "description": "Describes a toggle that is used to show or hide the private key input" + }, + "privateKeyShown": { + "message": "प्राइवेट की (key) दिखाई जा रही है", + "description": "Explains that the private key input is being shown" + }, "privateKeyWarning": { "message": "चेतावनी: इस कुंजी का खुलासा कभी न करें। आपकी निजी कुंजियों के साथ कोई भी व्यक्ति आपके अकाउंट में रखी कोई भी एसेट चुरा सकता है।" }, @@ -2969,6 +3747,21 @@ "proceedWithTransaction": { "message": "मैं फिर भी आगे बढ़ना चाहता हूं" }, + "productAnnouncements": { + "message": "प्रॉडक्ट घोषणाएं" + }, + "profileSync": { + "message": "प्रोफ़ाइल सिंक" + }, + "profileSyncConfirmation": { + "message": "यदि आप प्रोफ़ाइल सिंक बंद कर देते हैं, तो आप नोटिफिकेशंस प्राप्त नहीं कर पाएंगे।" + }, + "profileSyncDescription": { + "message": "एक प्रोफ़ाइल बनाता है जिसका उपयोग MetaMask आपके डिवाइसों के बीच कुछ सेटिंग्स को सिंक करने के लिए करता है। नोटिफिकेशंस प्राप्त करने के लिए यह आवश्यक है। $1." + }, + "profileSyncPrivacyLink": { + "message": "जानें कि हम आपकी गोपनीयता की सुरक्षा कैसे करते हैं" + }, "proposedApprovalLimit": { "message": "प्रस्तावित एप्रूवल सीमा" }, @@ -2978,6 +3771,78 @@ "publicAddress": { "message": "सार्वजनिक एड्रेस" }, + "pushPlatformNotificationsFundsReceivedDescription": { + "message": "आपको $1 $2 प्राप्त हुए" + }, + "pushPlatformNotificationsFundsReceivedDescriptionDefault": { + "message": "आपको कुछ टोकन प्राप्त हुए" + }, + "pushPlatformNotificationsFundsReceivedTitle": { + "message": "फंड प्राप्त हुए" + }, + "pushPlatformNotificationsFundsSentDescription": { + "message": "आपने सफलतापूर्वक $1 $2 भेज दिया" + }, + "pushPlatformNotificationsFundsSentDescriptionDefault": { + "message": "आपने कुछ टोकन सफलतापूर्वक भेज दिए" + }, + "pushPlatformNotificationsFundsSentTitle": { + "message": "फंड भेजे गए" + }, + "pushPlatformNotificationsNftReceivedDescription": { + "message": "आपको नए NFT प्राप्त हुए" + }, + "pushPlatformNotificationsNftReceivedTitle": { + "message": "NFT प्राप्त हुआ" + }, + "pushPlatformNotificationsNftSentDescription": { + "message": "आपने सफलतापूर्वक NFT भेज दिया है" + }, + "pushPlatformNotificationsNftSentTitle": { + "message": "NFT भेजा गया" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedDescription": { + "message": "आपका Lido स्टेक सफल रहा" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedTitle": { + "message": "स्टेक पूरा हुआ" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnDescription": { + "message": "आपका Lido स्टेक अब विदड्रॉ करने के लिए तैयार है" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnTitle": { + "message": "स्टेक विदड्रॉ करने के लिए तैयार है" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedDescription": { + "message": "आपका Lido विदड्रॉवल सफल रहा" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedTitle": { + "message": "विदड्रॉवल पूरा हुआ" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedDescription": { + "message": "आपका Lido विदड्रॉवल अनुरोध सबमिट कर दिया गया था" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedTitle": { + "message": "विदड्रॉवल का अनुरोध किया गया" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedDescription": { + "message": "आपका RocketPool स्टेक सफल रहा" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedTitle": { + "message": "स्टेक पूरा हुआ" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedDescription": { + "message": "आपका RocketPool अनस्टेक सफल रहा" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedTitle": { + "message": "अनस्टेक पूरा हुआ" + }, + "pushPlatformNotificationsSwapCompletedDescription": { + "message": "आपका MetaMask स्वैप सफल रहा" + }, + "pushPlatformNotificationsSwapCompletedTitle": { + "message": "स्वैप पूरा हुआ" + }, "queued": { "message": "कतारबद्ध" }, @@ -2996,9 +3861,15 @@ "receive": { "message": "प्राप्त करें" }, + "receiveTokensCamelCase": { + "message": "टोकन प्राप्त करें" + }, "recipientAddressPlaceholder": { "message": "सार्वजनिक एड्रेस (0x) या ENS नाम डालें" }, + "recipientAddressPlaceholderFlask": { + "message": "पब्लिक एड्रेस (0x) या डोमेन नाम एंटर करें" + }, "recommendedGasLabel": { "message": "अनुशंसित" }, @@ -3026,6 +3897,12 @@ "recoveryPhraseReminderTitle": { "message": "अपने धन को सुरक्षित रखें" }, + "redesignedConfirmationsEnabledToggle": { + "message": "बेहतर सिग्नेचर अनुरोध" + }, + "redesignedConfirmationsToggleDescription": { + "message": "उन्नत फॉर्मेट में सिग्नेचर अनुरोध देखने के लिए इसे चालू करें।" + }, "refreshList": { "message": "लिस्ट रिफ्रेश करें" }, @@ -3068,15 +3945,30 @@ "removeJWTDescription": { "message": "क्या आप सुनिश्चित हैं कि आप इस टोकन को हटाना चाहते हैं? इस टोकन को सौंपे गए सभी एकाउंट्स को एक्सटेंशन से भी हटा दिया जाएगा: " }, + "removeKeyringSnap": { + "message": "इस Snap को हटाने पर ये एकाउंट्स MetaMask से हट जाते हैं:" + }, + "removeKeyringSnapToolTip": { + "message": "Snap इन एकाउंट्स को कंट्रोल करता है और अगर इसे हटा दिया जाता है तो एकाउंट्स MetaMask से भी हटा दिए जाएंगे। हालांकि, वे एकाउंट्स ब्लॉकचेन में बने रहेंगे।" + }, "removeNFT": { "message": "NFT हटाएं" }, + "removeNftErrorMessage": { + "message": "हम इस NFT को नहीं हटा पाए।" + }, "removeNftMessage": { "message": "NET सफलतापूर्वक हटा दिया गया!" }, "removeSnap": { "message": "Snap हटाएं" }, + "removeSnapAccountDescription": { + "message": "यदि आप आगे बढ़ते हैं, तो यह अकाउंट अब MetaMask में उपलब्ध नहीं होगा।" + }, + "removeSnapAccountTitle": { + "message": "अकाउंट हटाएं" + }, "removeSnapConfirmation": { "message": "क्या आप वाकई $1 को हटाना चाहते हैं?", "description": "$1 represents the name of the snap" @@ -3087,12 +3979,24 @@ "replace": { "message": "बदलें" }, + "reportIssue": { + "message": "किसी समस्या की रिपोर्ट करें" + }, "requestFlaggedAsMaliciousFallbackCopyReason": { "message": "सुरक्षा प्रोवाइडर ने अतिरिक्त जानकारी शेयर नहीं की है" }, "requestFlaggedAsMaliciousFallbackCopyReasonTitle": { "message": "रिक्वेस्ट बुरी नीयत वाला के रूप में फ़्लैग किया गया" }, + "requestFrom": { + "message": "इनसे मिली रिक्वेस्ट" + }, + "requestFromInfo": { + "message": "यह वह साइट है जो आपका सिग्नेचर मांग रही है।" + }, + "requestFromTransactionDescription": { + "message": "यह वही साइट है जो आपका कन्फर्मेशन मांग रही है।" + }, "requestMayNotBeSafe": { "message": "रिक्वेस्ट सुरक्षित नहीं हो सकता है" }, @@ -3114,6 +4018,9 @@ "reset": { "message": "रीसेट करें" }, + "resetStates": { + "message": "स्टेट रीसेट करें" + }, "resetWallet": { "message": "वॉलेट रीसेट करें" }, @@ -3142,7 +4049,7 @@ "message": "यूज़र डेटा रीस्टोर करें" }, "restoreUserDataDescription": { - "message": "वरीयताएं और अकाउंट एड्रेस से युक्त यूज़र सेटिंग्स को आप पहले से बैकअप की गई JSON फाइल से रीस्टोर सकते हैं।" + "message": "एक बैकअप फाइल की मदद से आप अपने डेटा, जैसे कि अपने कॉन्टेक्ट्स और अपनी प्रेफेरेंस, को रिस्टोर कर सकते हैं।" }, "resultPageError": { "message": "गड़बड़ी" @@ -3196,9 +4103,15 @@ "message": "MetaMask सपोर्ट कभी इसका रिक्वेस्ट नहीं करेगा।", "description": "The bolded texted in the second part of 'revealSeedWordsWarning'" }, + "revealSensitiveContent": { + "message": "संवेदनशील कंटेंट दिखाएं" + }, "revealTheSeedPhrase": { "message": "सीड फ़्रेज़ दिखाएं" }, + "reviewAlerts": { + "message": "एलर्ट की समीक्षा करें" + }, "revokeAllTokensTitle": { "message": "आपके सभी $1 को एक्सेस और ट्रांसफ़र करने की अनुमति निरस्त करें?", "description": "$1 is the symbol of the token for which the user is revoking approval" @@ -3249,6 +4162,9 @@ "searchAccounts": { "message": "अकाउंट्स खोजें" }, + "searchTokens": { + "message": "टोकनों को ढूंढें" + }, "secretRecoveryPhrase": { "message": "सीक्रेट रिकवरी फ्रेज" }, @@ -3265,7 +4181,8 @@ "message": "सुरक्षा चेतावनी" }, "securityAlertsDescription": { - "message": "यह फ़ीचर आपकी प्राइवेसी को सुरक्षित रखते हुए, ट्रांसेक्शन और सिग्नेचर रिक्वेस्ट का ध्यान से रिव्यु करके आपको Ethereum Mainnet पर बुरी नीयत वाली गतिविधि के प्रति अलर्ट करता है। जो थर्ड पार्टी यह सर्विस देते हैं उनके साथ आपका डेटा शेयर नहीं किया जाता है। किसी भी रिक्वेस्ट को मंज़ूरी देने से पहले हमेशा पूरी जांच-पड़ताल ज़रूर करें। इस बात की कोई गारंटी नहीं है कि इस फ़ीचर के माध्यम से बुरी नीयत से की गई सभी गतिविधियों का पता लगाया जा सकेगा।" + "message": "यह फीचर सक्रिय रूप से ट्रांसेक्शन और सिग्नेचर अनुरोधों की समीक्षा करके आपको बुरी नीयत वाली गतिविधि के प्रति एलर्ट करती है। $1", + "description": "Link to learn more about security alerts" }, "securityAndPrivacy": { "message": "सुरक्षा और गोपनीयता" @@ -3355,6 +4272,9 @@ "selectAnAccountHelp": { "message": "MetaMask Institutional में इस्तेमाल करने के लिए कस्टोडियन एकाउंट्स को चुनें।" }, + "selectEnableDisplayMediaPrivacyPreference": { + "message": "डिस्प्ले NFT मीडिया चालू करें" + }, "selectHdPath": { "message": "HD पथ को चुनें" }, @@ -3365,7 +4285,7 @@ "message": "सेटिंग्स में NFT डिटेक्शन चालू करें" }, "selectPathHelp": { - "message": "यदि आपको अपेक्षित अकाउंट दिखाई नहीं देते हैं, तो HD पथ बदलने की कोशिश करें।" + "message": "यदि आपको अपनी पसंद के हिसाब से अकाउंट दिखाई नहीं देते हैं, तो HD पाथ या मौजूदा चुना गया नेटवर्क बदलने की कोशिश करें।" }, "selectType": { "message": "प्रकार को चुनें" @@ -3376,18 +4296,41 @@ "send": { "message": "भेजें" }, + "sendAToken": { + "message": "एक टोकन भेजें" + }, "sendBugReport": { "message": "हमें एक बग रिपोर्ट भेजें।" }, + "sendNoContactsConversionText": { + "message": "यहां क्लिक करें" + }, + "sendNoContactsDescription": { + "message": "कॉन्टेक्ट्स आपको कई बार ट्रांसेक्शन को दूसरे अकाउंट में सुरक्षित रूप से भेजने की अनुमति देते हैं। एक कॉन्टेक्ट बनाने के लिए, $1", + "description": "$1 represents the action text 'click here'" + }, + "sendNoContactsTitle": { + "message": "आपके पास अभी तक कोई कॉन्टेक्ट्स नहीं हैं" + }, + "sendSelectReceiveAsset": { + "message": "प्राप्त करने के लिए एसेट को चुनें" + }, + "sendSelectSendAsset": { + "message": "भेजने के लिए एसेट को चुनें" + }, "sendSpecifiedTokens": { "message": "$1 भेजें", "description": "Symbol of the specified token" }, - "sendTo": { - "message": "को भेजें" + "sendSwapSubmissionWarning": { + "message": "इस बटन पर क्लिक करने से आपका स्वैप ट्रांसेक्शन तुरंत शुरू हो जाएगा। कृपया आगे बढ़ने से पहले अपने ट्रांसेक्शन विवरण की समीक्षा करें।" + }, + "sendTokenAsToken": { + "message": "$1 को $2 के रूप में भेजें", + "description": "Used in the transaction display list to describe a swap and send. $1 and $2 are the symbols of tokens in involved in the swap." }, - "sendTokens": { - "message": "टोकन भेजें" + "sendingAsset": { + "message": "$1 भेजा जा रहा है" }, "sendingDisabled": { "message": "ERC-1155 NFT एसेट्स भेजने को अभी सपोर्ट नहीं किया जाता।" @@ -3400,9 +4343,15 @@ "message": "चेतावनी: आप एक टोकन कॉन्ट्रैक्ट को भेजने वाले हैं जिसके परिणामस्वरूप धन की हानि हो सकती है। $1", "description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning" }, + "sendingZeroAmount": { + "message": "आप 0 $1 भेज रहे हैं।" + }, "sepolia": { "message": "Sepolia टेस्ट नेटवर्क" }, + "serviceWorkerKeepAlive": { + "message": "सेवाकर्मी जीवित रहें" + }, "setAdvancedPrivacySettingsDetails": { "message": "MetaMask उत्पाद की उपयोगिता और सुरक्षा को बढ़ाने के लिए इन विश्वसनीय तीसरे-पक्ष की सेवाओं का इस्तेमाल करता है।" }, @@ -3414,7 +4363,7 @@ "description": "The token symbol that is being approved" }, "settingAddSnapAccount": { - "message": "Snap अकाउंट जोड़ें" + "message": "अकाउंट Snap जोड़ें" }, "settings": { "message": "सेटिंग" @@ -3422,9 +4371,21 @@ "settingsSearchMatchingNotFound": { "message": "कोई मेल खाने वाला परिणाम नहीं मिला।" }, + "settingsSubHeadingSignaturesAndTransactions": { + "message": "सिग्नेचर्स और ट्रांसेक्शन रिक्वेस्ट्स" + }, "show": { "message": "दिखाएं" }, + "showAccount": { + "message": "अकाउंट दिखाएं" + }, + "showExtensionInFullSizeView": { + "message": "एक्सटेंशन को पूर्ण आकार दृश्य में दिखाएं" + }, + "showExtensionInFullSizeViewDescription": { + "message": "जब आप एक्सटेंशन आइकन पर क्लिक करते हैं तो पूर्ण आकार दृश्य को अपना डिफॉल्ट बनाने के लिए इसे चालू करें।" + }, "showFiatConversionInTestnets": { "message": "टेस्ट नेटवर्क पर कन्वर्शन दिखाएं" }, @@ -3444,6 +4405,9 @@ "message": "लेनदेन सूची में आने वाले लेनदेन को दिखाने के लिए Etherscan का उपयोग करने के लिए इसका चयन करें", "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" }, + "showIncomingTransactionsExplainer": { + "message": "यह हरेक नेटवर्क के लिए अलग-अलग थर्ड-पार्टी API पर निर्भर करता है, जो आपके Ethereum एड्रेस और आपके आईपी ​​एड्रेस को एक्स्पोज़ करता है।" + }, "showMore": { "message": "अधिक दिखाएं" }, @@ -3483,9 +4447,46 @@ "signin": { "message": "साइन-इन करें" }, + "signing": { + "message": "साइन हो रहा है" + }, + "simulationDetailsFailed": { + "message": "आपका एस्टीमेशन लोड करने में गड़बड़ी हुई।" + }, + "simulationDetailsFiatNotAvailable": { + "message": "उपलब्ध नहीं है" + }, + "simulationDetailsIncomingHeading": { + "message": "आप पाते हैं" + }, + "simulationDetailsNoBalanceChanges": { + "message": "आपके वॉलेट के लिए किसी बदलाव का प्रेडिक्शन नहीं किया गया है" + }, + "simulationDetailsOutgoingHeading": { + "message": "आप भेजते हैं" + }, + "simulationDetailsTitle": { + "message": "अनुमानित बदलाव" + }, + "simulationDetailsTitleTooltip": { + "message": "अगर आप यह ट्रांसेक्शन करते हैं तो अनुमानित परिवर्तन हो सकते हैं। यह सिर्फ एक प्रेडिक्शन है, कोई गारंटी नहीं।" + }, + "simulationDetailsTotalFiat": { + "message": "टोटल = $1", + "description": "$1 is the total amount in fiat currency on one side of the transaction" + }, + "simulationDetailsTransactionReverted": { + "message": "ये ट्रांसेक्शन विफल हो सकता है" + }, "simulationErrorMessageV2": { "message": "हम गैस का अनुमान नहीं लगा पाए। कॉन्ट्रैक्ट में कोई गड़बड़ी हो सकती है और यह ट्रांसेक्शन विफल हो सकता है।" }, + "simulationsSettingDescription": { + "message": "ट्रांसेक्शन को कन्फर्म करने से पहले बैलेंस अमाउंट में बदलाव का अनुमान लगाने के लिए इसे चालू करें। यह आपके ट्रांसेक्शन के फाइनल आउटकम की गारंटी नहीं देता है।$1" + }, + "simulationsSettingSubHeader": { + "message": "बैलेंस अमाउंट में बदलावों का अनुमान लगाएं" + }, "skip": { "message": "छोड़ें" }, @@ -3498,20 +4499,99 @@ "smartContracts": { "message": "स्मार्ट कॉन्ट्रैक्ट्स" }, - "smartSwapsAreHere": { - "message": "स्मार्ट स्वैप यहां हैं!" - }, - "smartSwapsDescription": { - "message": "MetaMask के स्वैप अब और अधिक स्मार्ट हो गए हैं! इन हेतु सहायता के लिए स्मार्ट स्वैप को इनेबल करने से MetaMask आपके स्वैप को प्रोग्रामेटिक रूप से ऑप्टिमाइज कर पाएगा:" - }, "smartSwapsErrorNotEnoughFunds": { "message": "स्मार्ट स्वैप के लिए पर्याप्त फंड नहीं है।" }, "smartSwapsErrorUnavailable": { "message": "स्मार्ट स्वैप अस्थायी रूप से अनुपलब्ध हैं।" }, + "smartTransactionCancelled": { + "message": "आपका ट्रांसेक्शन कैंसिल कर दिया गया था" + }, + "smartTransactionCancelledDescription": { + "message": "आपका ट्रांसेक्शन पूरा नहीं हो सका, इसलिए आपको अनावश्यक गैस फीस भरने से बचाने के लिए इसे कैंसिल कर दिया गया।" + }, + "smartTransactionError": { + "message": "आपका ट्रांसेक्शन नहीं हो पाया" + }, + "smartTransactionErrorDescription": { + "message": "बाज़ार में अचानक हुए परिवर्तन विफलताओं का कारण बन सकते हैं। यदि समस्या बनी रहती है, तो MetaMask कस्टमर सपोर्ट से संपर्क करें।" + }, + "smartTransactionPending": { + "message": "आपका ट्रांसेक्शन सबमिट कर रहे हैं" + }, + "smartTransactionSuccess": { + "message": "आपका ट्रांसेक्शन पूरा हो गया है" + }, + "smartTransactionTakingTooLong": { + "message": "माफ़ी चाहते हैं कि आपको इंतज़ार करना पड़ा" + }, + "smartTransactionTakingTooLongDescription": { + "message": "यदि आपका ट्रांसेक्शन $1 के भीतर फाइनलाइज़ नहीं होता है, तो इसे कैंसिल कर दिया जाएगा और आपसे गैस फ़ीस नहीं ली जाएगी।", + "description": "$1 is remaining time in seconds" + }, + "smartTransactions": { + "message": "स्मार्ट ट्रांसेक्शन" + }, + "smartTransactionsBenefit1": { + "message": "99.5% सफलता दर" + }, + "smartTransactionsBenefit2": { + "message": "आपका पैसा बचाता है" + }, + "smartTransactionsBenefit3": { + "message": "रियल-टाइम अपडेट" + }, + "smartTransactionsDescription": { + "message": "स्मार्ट ट्रांसेक्शन के साथ उच्च सफलता दर, फ्रंटरनिंग सुरक्षा और बेहतर दृश्यता अनलॉक करें।" + }, + "smartTransactionsDescription2": { + "message": "केवल Ethereum पर उपलब्ध है। सेटिंग्स में किसी भी समय चालू करें या बंद करें। $1", + "description": "$1 is an external link to learn more about Smart Transactions" + }, + "smartTransactionsOptItModalTitle": { + "message": "एनहांस्ड ट्रांसेक्शन प्रोटेक्शन" + }, + "snapAccountCreated": { + "message": "अकाउंट बनाया गया" + }, + "snapAccountCreatedDescription": { + "message": "आपका नया अकाउंट उपयोग के लिए तैयार है!" + }, + "snapAccountCreationFailed": { + "message": "अकाउंट बनाने की प्रक्रिया विफल हो गई" + }, + "snapAccountCreationFailedDescription": { + "message": "$1 आपके लिए अकाउंट नहीं बना पाया।", + "description": "$1 is the snap name" + }, + "snapAccountRedirectFinishSigningTitle": { + "message": "साइन करने का काम पूरा करें" + }, + "snapAccountRedirectSiteDescription": { + "message": "$1 के निर्देशों का पालन करें" + }, + "snapAccountRemovalFailed": { + "message": "अकाउंट हटाने की प्रक्रिया विफल हो गई" + }, + "snapAccountRemovalFailedDescription": { + "message": "$1 आपके लिए अकाउंट नहीं हटा पाया।", + "description": "$1 is the snap name" + }, + "snapAccountRemoved": { + "message": "अकाउंट हटाया गया" + }, + "snapAccountRemovedDescription": { + "message": "यह अकाउंट अब MetaMask में उपयोग के लिए उपलब्ध नहीं होगा।" + }, + "snapAccounts": { + "message": "अकाउंट Snaps" + }, + "snapAccountsDescription": { + "message": "थर्ड-पार्टी Snaps द्वारा कंट्रोल किए गए अकाउंट।" + }, "snapConnectionWarning": { - "message": "$1 चाहता है कि $2 के साथ जुड़े. तभी आगे बढ़ें अगर आप इस वेबसाइट पर भरोसा करते हैं।", + "message": "$1 $2 का उपयोग करना चाहता है", "description": "$2 is the snap and $1 is the dapp requesting connection to the snap." }, "snapContent": { @@ -3522,15 +4602,35 @@ "message": "वेबसाइट" }, "snapInstallRequest": { - "message": "$1 इंस्टॉल करने से इसे निम्नलिखित अनुमतियां मिलती हैं। अगर आप $1 पर भरोसा करते हैं तो ही जारी रखें।", + "message": "$1 इंस्टॉल करने से इसे निम्नलिखित अनुमतियां मिलती हैं।", "description": "$1 is the snap name." }, "snapInstallSuccess": { "message": "इंस्टॉलेशन समाप्त" }, + "snapInstallWarningCheck": { + "message": "$1 यह अनुमति चाहता है कि:", + "description": "Warning message used in popup displayed on snap install. $1 is the snap name." + }, "snapInstallWarningHeading": { "message": "सावधानी से आगे बढ़ें" }, + "snapInstallWarningPermissionDescriptionForBip32View": { + "message": "$1 को यह अनुमति दी जाए कि वह आपकी पब्लिक कीज़ (keys) (और एड्रेसों) को देख सके। इस अनुमति से आपके एकाउंट्स या एसेट्स पर कोई कंट्रोल नहीं मिलता है।", + "description": "An extended description for the `snap_getBip32PublicKey` permission used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionDescriptionForEntropy": { + "message": "$1 Snap को, रिक्वेस्ट किए गए नेटवर्क पर एकाउंट्स और एसेट्स को मैनेज करने की अनुमति दी जाए। ये एकाउंट्स, आपके सीक्रेट रिकवरी फ्रेज़ (इसे सामने लाए बिना) का उपयोग करके डिराइव और बैकअप किए जाते हैं। $1 में Keys डिराइव करने की पावर होती है जिसके माध्यम से वह Ethereum (EVMs) के अलावा भी कई प्रकार के ब्लॉकचेन प्रोटोकॉल को सपोर्ट कर सकता है।", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionNameForEntropy": { + "message": "$1 एकाउंट्स को मैनेज करें।", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, + "snapInstallWarningPermissionNameForViewPublicKey": { + "message": "$1 के लिए अपनी पब्लिक की (key) को देखें", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, "snapInstallationErrorDescription": { "message": "$1 इंस्टॉल नहीं किया जा सका.", "description": "Error description used when snap installation fails. $1 is the snap name." @@ -3548,6 +4648,10 @@ "snapResultSuccessDescription": { "message": "$1 इस्तेमाल के लिए तैयार है" }, + "snapUpdateAlertDescription": { + "message": "$1 का लेटेस्ट वर्ज़न पाएं", + "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." + }, "snapUpdateAvailable": { "message": "अपडेट उपलब्ध है" }, @@ -3559,22 +4663,40 @@ "message": "अपडेट नहीं हो पाया", "description": "Error title used when snap update fails." }, + "snapUpdateRequest": { + "message": "$1 को अपडेट करने से इसे निम्नलिखित अनुमतियां मिलती हैं।", + "description": "$1 is the Snap name." + }, "snapUpdateSuccess": { "message": "अपडेट समाप्त" }, + "snapUrlIsBlocked": { + "message": "यह Snap आपको एक ब्लॉक्ड साइट पर ले जाना चाहता है। $1." + }, "snaps": { "message": "Snaps" }, - "snapsInvalidUIError": { - "message": "Snap द्वारा निर्दिष्ट किया गया UI ग़लत है।" + "snapsConnected": { + "message": "Snaps कनेक्ट किए गए" }, "snapsNoInsight": { "message": "Snap ने कोई इनसाइट नहीं लौटाई" }, + "snapsPrivacyWarningFirstMessage": { + "message": "आप स्वीकार करते हैं कि आपके द्वारा इंस्टॉल किया गया कोई भी Snap एक तृतीय पक्ष सेवा है, जब तक कि अन्यथा पहचाना न जाए, जैसा कि Consensys $1 में परिभाषित किया गया है। आपके द्वारा तृतीय पक्ष सेवाओं का उपयोग तृतीय पक्ष सेवा प्रदाता द्वारा निर्धारित अलग-अलग नियमों और शर्तों द्वारा नियंत्रित होता है। Consensys किसी विशेष कारण से किसी भी व्यक्ति द्वारा किसी भी Snap के उपयोग की सुझाव नहीं देता है। आप अपने जोखिम पर तृतीय पक्ष के सेवा की ऐक्सेस पाते हैं, उस पर भरोसा करते हैं या उसका उपयोग करते हैं। आपके द्वारा तृतीय पक्ष की सेवाओं के उपयोग के कारण होने वाले किसी भी नुकसान के लिए Consensys सभी जिम्मेदारी और उत्तरदायित्व से इनकार करता है।", + "description": "First part of a message in popup modal displayed when installing a snap for the first time. $1 is terms of use link." + }, "snapsPrivacyWarningSecondMessage": { "message": "थर्ड पार्टी सेवाओं के साथ आप जो भी सूचना शेयर करते हैं, उसे उन थर्ड पार्टी सेवाओं द्वारा उनकी अपनी गोपनीयता नीतियों के अनुसार सीधे एकत्र की जाएगी। अधिक जानकारी के लिए कृपया उनकी गोपनीयता नीतियां देखें।", "description": "Second part of a message in popup modal displayed when installing a snap for the first time." }, + "snapsPrivacyWarningThirdMessage": { + "message": "Consensys के पास तृतीय पक्ष की सेवाओं के साथ आपके द्वारा साझा की गई जानकारी की कोई ऐक्सेस नहीं है।", + "description": "Third part of a message in popup modal displayed when installing a snap for the first time." + }, + "snapsSettings": { + "message": "Snap सेटिंग्स" + }, "snapsTermsOfUse": { "message": "इस्तेमाल की शर्तें" }, @@ -3588,12 +4710,19 @@ "someNetworksMayPoseSecurity": { "message": "कुछ नेटवर्क सुरक्षा और/या गोपनीयता संबंधी जोखिम पैदा कर सकते हैं। नेटवर्क जोड़ने और इस्तेमाल करने से पहले जोखिमों को समझें।" }, + "somethingDoesntLookRight": { + "message": "कुछ तो गड़बड़ है? $1", + "description": "A false positive message for users to contact support. $1 is a link to the support page." + }, "somethingIsWrong": { "message": "कुछ गड़बड़ हो गया है। पेज को फिर से लोड करने की कोशिश करें।" }, "somethingWentWrong": { "message": "ओह! कुछ गलत हो गया।" }, + "source": { + "message": "स्त्रोत" + }, "speedUp": { "message": "जल्दी करें" }, @@ -3728,6 +4857,14 @@ "stake": { "message": "हिस्सेदारी" }, + "startYourJourney": { + "message": "$1 से अपनी यात्रा शुरू करें", + "description": "$1 is the token symbol" + }, + "startYourJourneyDescription": { + "message": "अपने वॉलेट में कुछ $1 जोड़कर Web3 से शुरुआत करें।", + "description": "$1 is the token symbol" + }, "stateLogError": { "message": "स्टेट लॉग को पुनर्प्राप्त करने में गड़बड़ी।" }, @@ -3740,6 +4877,9 @@ "stateLogsDescription": { "message": "स्टेट लॉग में आपके सार्वजनिक अकाउंट के एड्रेस और भेजे गए ट्रांसेक्शन शामिल होते हैं।" }, + "states": { + "message": "स्टेट" + }, "status": { "message": "स्टेटस" }, @@ -3783,18 +4923,6 @@ "strong": { "message": "मजबूत" }, - "stxBenefit1": { - "message": "ट्रांसेक्शन लागतें मिनिमाइज़ करें" - }, - "stxBenefit2": { - "message": "ट्रांसेक्शन विफलताएं कम करें" - }, - "stxBenefit3": { - "message": "अटके हुए ट्रांसेक्शन को हटा दें" - }, - "stxBenefit4": { - "message": "फ़्रंट-रनिंग को रोकें" - }, "stxCancelled": { "message": "स्वैप विफल हो सकता था" }, @@ -3804,6 +4932,10 @@ "stxCancelledSubDescription": { "message": "अपना स्वैप फिर से कोशिश करें। अगली बार भी इस तरह के जोखिमों से आपको बचाने के लिए हम यहां होंगे।" }, + "stxEstimatedCompletion": { + "message": "<$1 में पूरा होने का अनुमान", + "description": "$1 is remeaning time in minutes and seconds, e.g. 0:10" + }, "stxFailure": { "message": "स्वैप नहीं हो पाया" }, @@ -3811,6 +4943,9 @@ "message": "मार्केट के आकस्मिक बदलावों के कारण विफलताएं हो सकती हैं। अगर समस्या जारी रहती है, तो कृपया $1 से कॉन्टेक्ट करें।", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInDescription": { + "message": "Ethereum Mainnet पर अधिक विश्वसनीय और सुरक्षित ट्रांसेक्शन के लिए स्मार्ट ट्रांसेक्शन चालू करें। $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "आपका स्वैप निजी रूप से सबमिट किया जा रहा है..." }, @@ -3849,12 +4984,21 @@ "submitted": { "message": "सबमिट किया गया" }, + "suggestedTokenSymbol": { + "message": "सुझाया गया टिकर सिंबल:" + }, "support": { "message": "सहायता" }, "supportCenter": { "message": "हमारे सहायता केंद्र पर जाएं" }, + "surveyConversion": { + "message": "हमारे सर्वे में भाग लें" + }, + "surveyTitle": { + "message": "MetaMask के भविष्य को आकार दें" + }, "swap": { "message": "स्वैप करें" }, @@ -3874,6 +5018,9 @@ "swapAmountReceivedInfo": { "message": "यह आपको प्राप्त होने वाली कम-से-कम अमाउंट है। आप स्लिपेज के आधार पर अधिक प्राप्त कर सकते हैं।" }, + "swapAndSend": { + "message": "स्वैप करें और भेजें" + }, "swapAnyway": { "message": "कैसे भी स्वैप करें" }, @@ -3989,6 +5136,10 @@ "message": "$1% MetaMask फ़ीस शामिल है।", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." }, + "swapIncludesMMFeeAlt": { + "message": "उद्धरण $1% MetaMask शुल्क दर्शाता है", + "description": "Provides information about the fee that metamask takes for swaps using the latest copy. $1 is a decimal number." + }, "swapIncludesMetaMaskFeeViewAllQuotes": { "message": "$1% MetaMask फ़ीस शामिल है - $2", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number and $2 is a link to view all quotes." @@ -3996,6 +5147,9 @@ "swapLearnMore": { "message": "स्वैप के बारे में ज्यादा जानें" }, + "swapLiquiditySourceInfo": { + "message": "एक्सचेंज रेट्स और नेटवर्क फ़ीस की तुलना करने के लिए, हम कई लिक्विडिटी सोर्सेज़ (एक्सचेंज, एग्रीगेटर्स और प्रोफेशनल मार्किट मेकर्स) ढूंढते हैं।" + }, "swapLowSlippage": { "message": "कम स्लिपेज" }, @@ -4268,6 +5422,9 @@ "switchEthereumChainConfirmationTitle": { "message": "इस साइट को नेटवर्क स्विच करने की अनुमति दें?" }, + "switchInputCurrency": { + "message": "इनपुट करेंसी को स्विच करें" + }, "switchNetwork": { "message": "नेटवर्क स्विच करें" }, @@ -4281,14 +5438,15 @@ "switchToThisAccount": { "message": "इस अकाउंट पर स्विच करें" }, - "switchedTo": { - "message": "आपने स्विच कर लिया है" + "switchedNetworkToastDecline": { + "message": "इसे दोबारा न दिखाएं" }, - "switcherTitle": { - "message": "नेटवर्क स्विचर" + "switchedNetworkToastMessage": { + "message": "$1 अब $2 पर एक्टिव है", + "description": "$1 represents the account name, $2 represents the network name" }, - "switcherTourDescription": { - "message": "नेटवर्क स्विच करने या नया नेटवर्क जोड़ने के लिए आइकन पर क्लिक करें" + "switchedTo": { + "message": "आप अब इस्तेमाल कर रहे हैं" }, "switchingNetworksCancelsPendingConfirmations": { "message": "नेटवर्क स्विच करने से सभी लंबित कन्फर्मेशन कैंसिल हो जाएंगे" @@ -4327,7 +5485,7 @@ "message": "अपनी पसंदीदा MetaMask थीम चुन लें" }, "thingsToKeep": { - "message": "ध्यान रखने योग्य बातें" + "message": "ध्यान रखने योग्य बातें:" }, "thirdPartySoftware": { "message": "थर्ड-पार्टी सॉफ्टवेयर नोटिस", @@ -4388,6 +5546,18 @@ "toggleEthSignOn": { "message": "चालू (अनुशंसित नहीं)" }, + "toggleRequestQueueDescription": { + "message": "ऐसा करके, आप सभी साइटों के लिए कोई सिंगल नेटवर्क चुनने के बजाय हरेक साइट के लिए एक नेटवर्क चुन सकते हैं। यह फीचर आपको मैन्युअल तरीके से नेटवर्क स्विच करने से रोकता है, इस वजह से कुछ साइटों पर आपका यूज़र अनुभव ख़राब हो सकता है।" + }, + "toggleRequestQueueField": { + "message": "हरेक साइट के लिए नेटवर्क चुनें" + }, + "toggleRequestQueueOff": { + "message": "बंद करें" + }, + "toggleRequestQueueOn": { + "message": "चालू करें" + }, "token": { "message": "टोकन" }, @@ -4404,7 +5574,7 @@ "message": "टोकन कॉन्ट्रैक्ट एड्रेस" }, "tokenDecimalFetchFailed": { - "message": "टोकन डेसीमल आवश्यक है।" + "message": "टोकन डेसीमल की आवश्यकता है। इसे: $1 पर पाएं" }, "tokenDecimalTitle": { "message": "टोकन डेसीमल:" @@ -4419,13 +5589,13 @@ "message": "टोकन आइडी" }, "tokenList": { - "message": "टोकन सूचियां:" + "message": "टोकन लिस्ट्स:" }, "tokenScamSecurityRisk": { "message": "टोकन घोटाले और सुरक्षा जोखिम" }, "tokenShowUp": { - "message": "हो सकता है आपके वॉलेट में आपके टोकन स्वतः दिखाई नहीं दें।" + "message": "हो सकता है आपके वॉलेट में आपके टोकन ऑटोमेटिकली दिखाई नहीं दें। " }, "tokenSymbol": { "message": "टोकन का प्रतीक" @@ -4443,6 +5613,9 @@ "tooltipSatusConnected": { "message": "जुड़े हुए" }, + "tooltipSatusConnectedUpperCase": { + "message": "कनेक्ट किया गया" + }, "tooltipSatusNotConnected": { "message": "जुड़े नहीं हैं" }, @@ -4583,6 +5756,39 @@ "tryAgain": { "message": "फिर से कोशिश करें" }, + "turnOff": { + "message": "बंद करें" + }, + "turnOffMetamaskNotificationsError": { + "message": "नोटिफिकेशंस अक्षम करने में गड़बड़ी हुई। कृपया बाद में फिर से प्रयास करें।" + }, + "turnOn": { + "message": "चालू करें" + }, + "turnOnMetamaskNotifications": { + "message": "नोटिफिकेशंस चालू करें" + }, + "turnOnMetamaskNotificationsButton": { + "message": "चालू करें" + }, + "turnOnMetamaskNotificationsError": { + "message": "नोटिफिकेशंस बनाने में गड़बड़ी हुई। कृपया बाद में फिर से प्रयास करें।" + }, + "turnOnMetamaskNotificationsMessageFirst": { + "message": "नोटिफिकेशंस के साथ आपके वॉलेट में क्या हो रहा है, इसकी जानकारी रखें।" + }, + "turnOnMetamaskNotificationsMessagePrivacyBold": { + "message": "सेटिंग्स > नोटिफिकेशंस।" + }, + "turnOnMetamaskNotificationsMessagePrivacyLink": { + "message": "जानें कि इस फीचर का उपयोग करते समय हम आपकी गोपनीयता की सुरक्षा कैसे करते हैं।" + }, + "turnOnMetamaskNotificationsMessageSecond": { + "message": "वॉलेट नोटिफिकेशंस का उपयोग करने के लिए, हम आपके डिवाइस में कुछ सेटिंग्स को सिंक करने के लिए एक प्रोफ़ाइल का उपयोग करते हैं। $1" + }, + "turnOnMetamaskNotificationsMessageThird": { + "message": "आप किसी भी समय नोटिफिकेशंस बंद कर सकते हैं $1" + }, "turnOnTokenDetection": { "message": "एडवांस्ड टोकन डिटेक्शन चालू करें" }, @@ -4614,6 +5820,10 @@ "unknownNetwork": { "message": "अज्ञात निजी नेटवर्क" }, + "unknownNetworkForKeyEntropy": { + "message": "अज्ञात नेटवर्क", + "description": "Displayed on places like Snap install warning when regular name is not available." + }, "unknownQrCode": { "message": "गड़बड़ी: हम उस QR कोड की पहचान नहीं कर पाए" }, @@ -4626,6 +5836,9 @@ "unlockMessage": { "message": "विकेंद्रीकृत वेब प्रतीक्षारत है" }, + "unpin": { + "message": "अनपिन करें" + }, "unrecognizedChain": { "message": "यह कस्टम नेटवर्क पहचाना नहीं गया है", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." @@ -4643,6 +5856,9 @@ "update": { "message": "अपडेट करें" }, + "updateRequest": { + "message": "अपडेट का अनुरोध" + }, "updatedWithDate": { "message": "अपडेट किया गया $1" }, @@ -4667,12 +5883,25 @@ "useNftDetection": { "message": "NFT को ऑटो-डिटेक्ट करें" }, + "useNftDetectionDescriptionText": { + "message": "MetaMask को थर्ड पार्टी सर्विसेज़ (जैसे OpenSea) का उपयोग करके आपके NFTs जोड़ने दें। NFTs को ऑटोडिटेक्ट करने से आपका आईपी और अकाउंट एड्रेस इन सेवाओं के सामने आ जाता है। इस फ़ीचर को चालू करने से आपका आईपी ​​एड्रेस आपके Ethereum एड्रेस के साथ जुड़ सकता है और धोखाधड़ी करने वाले लोगों द्वारा एयरड्रॉप किए गए नकली NFTs दिख सकते हैं। आप मैन्युअल तरीके से टोकन जोड़कर इस ख़तरे से बच सकते हैं।" + }, "usePhishingDetection": { "message": "फिशिंग डिटेक्शन का इस्तेमाल करें" }, "usePhishingDetectionDescription": { "message": "Ethereum यूज़र्स को लक्षित करने वाले फिशिंग डोमेन के लिए एक चेतावनी प्रदर्शित करें" }, + "useSafeChainsListValidation": { + "message": "नेटवर्क डिटेल्स की जांच" + }, + "useSafeChainsListValidationDescription": { + "message": "MetaMask, सटीक और स्टैंडर्डाइज़्ड नेटवर्क डिटेल्स दिखाने के लिए, $1 नाम की थर्ड-पार्टी सर्विस इस्तेमाल करता है। इससे बुरी नीयत वाले या गलत नेटवर्क से आपके जुड़ने की संभावना कम हो जाती है। इस फ़ीचर को इस्तेमाल करते समय आपका आईपी एड्रेस, chainid.network के सामने आ जाता है।" + }, + "useSafeChainsListValidationWebsite": { + "message": "chainid.network", + "description": "useSafeChainsListValidationWebsite is separated from the rest of the text so that we can bold the third party service name in the middle of them" + }, "useSiteSuggestion": { "message": "साइट के सुझाव का प्रयोग करें" }, @@ -4685,6 +5914,9 @@ "userName": { "message": "यूज़र" }, + "userOpContractDeployError": { + "message": "स्मार्ट कॉन्ट्रैक्ट अकाउंट से कॉन्ट्रैक्ट डीप्लॉयमेंट को सपोर्ट नहीं करता" + }, "verifyContractDetails": { "message": "थर्ड-पार्टी विवरण वेरीफ़ाई करें" }, @@ -4702,6 +5934,9 @@ "view": { "message": "देखें" }, + "viewActivity": { + "message": "एक्टिविटी देखें" + }, "viewAllDetails": { "message": "सभी विवरण देखें" }, @@ -4725,7 +5960,7 @@ }, "viewOnCustomBlockExplorer": { "message": "$1 को $2 पर देखें", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "Etherscan पर $1 देखें", @@ -4737,6 +5972,9 @@ "viewOnOpensea": { "message": "Opensea पर देखें" }, + "viewTransaction": { + "message": "ट्रांसेक्शन देखें" + }, "viewinCustodianApp": { "message": "Custodian ऐप में देखें" }, @@ -4744,6 +5982,9 @@ "message": "एक्सप्लोरर में $1 देखें", "description": "$1 is the action type. e.g (Account, Transaction, Swap)" }, + "visitSite": { + "message": "साइट पर जाएं" + }, "visitWebSite": { "message": "हमारी वेबसाइट पर जाएं" }, @@ -4782,6 +6023,10 @@ "warning": { "message": "चेतावनी" }, + "warningFromSnap": { + "message": "$1 से चेतावनी", + "description": "$1 represents the name of the snap" + }, "warningTooltipText": { "message": "$1 थर्ड पार्टी आपकी संपूर्ण टोकन बैलेंस को बिना किसी सूचना या सहमति के खर्च कर सकता है। खर्च की कम सीमा को कस्टमाइज़ करके खुद को सुरक्षित रखें।", "description": "$1 is a warning icon with text 'Be careful' in 'warning' colour" @@ -4789,6 +6034,9 @@ "weak": { "message": "कमज़ोर" }, + "web3": { + "message": "Web3" + }, "web3ShimUsageNotification": { "message": "हमने देखा है कि वर्तमान वेबसाइट ने हटाए गए window.web3 API का इस्तेमाल करने की कोशिश की। यदि साइट में गड़बड़ी लगती है, तो कृपया अधिक जानकारी के लिए $1 पर क्लिक करें।", "description": "$1 is a clickable link." @@ -4829,10 +6077,6 @@ "whatsThis": { "message": "यह क्या है?" }, - "xOfY": { - "message": "$2 में से $1", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$2 में से $1 लंबित", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" @@ -4840,6 +6084,9 @@ "yes": { "message": "हां" }, + "you": { + "message": "आप" + }, "youHaveAddedAll": { "message": "आपने सभी पॉपुलर नेटवर्क जोड़ लिए हैं। आप अधिक नेटवर्क खोज सकते हैं $1 या आप $2 कर सकते हैं", "description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'" @@ -4862,6 +6109,12 @@ "yourPrivateSeedPhrase": { "message": "आपका सीक्रेट रिकवरी फ्रेज" }, + "yourTransactionConfirmed": { + "message": "ट्रांसेक्शन पहले ही कन्फर्म हो चुका है" + }, + "yourTransactionJustConfirmed": { + "message": "हम आपके ट्रांसेक्शन को रद्द नहीं कर सके क्योंकि ब्लॉकचेन पर यह पहले ही कन्फर्म हो चुका है।" + }, "zeroGasPriceOnSpeedUpError": { "message": "जीरो गैस प्राइस में तेज़ी" } diff --git a/app/_locales/hn/messages.json b/app/_locales/hn/messages.json index cb0a6795bb3f..8dc338db6dc1 100644 --- a/app/_locales/hn/messages.json +++ b/app/_locales/hn/messages.json @@ -266,9 +266,6 @@ "send": { "message": "भेजें" }, - "sendTokens": { - "message": "भेजें टोकन" - }, "settings": { "message": "सेटिंग्स" }, diff --git a/app/_locales/hr/messages.json b/app/_locales/hr/messages.json index bc1046bcce54..3d259868534a 100644 --- a/app/_locales/hr/messages.json +++ b/app/_locales/hr/messages.json @@ -623,9 +623,6 @@ "send": { "message": "Pošalji" }, - "sendTokens": { - "message": "Pošalji tokene" - }, "settings": { "message": "Postavke" }, diff --git a/app/_locales/ht/messages.json b/app/_locales/ht/messages.json index 03f1fed3b0be..94bad1913fe6 100644 --- a/app/_locales/ht/messages.json +++ b/app/_locales/ht/messages.json @@ -458,9 +458,6 @@ "send": { "message": "Voye" }, - "sendTokens": { - "message": "Voye Tokens" - }, "settings": { "message": "Paramèt" }, diff --git a/app/_locales/hu/messages.json b/app/_locales/hu/messages.json index 68994953741d..21d413aa64a3 100644 --- a/app/_locales/hu/messages.json +++ b/app/_locales/hu/messages.json @@ -623,9 +623,6 @@ "send": { "message": "Küldés" }, - "sendTokens": { - "message": "Token küldése" - }, "settings": { "message": "Beállítások" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index fdbd48de0e55..45bc8912c676 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -130,12 +130,21 @@ "account": { "message": "Akun" }, + "accountActivity": { + "message": "Aktivitas akun" + }, + "accountActivityText": { + "message": "Pilih akun yang ingin mendapatkan notifikasi:" + }, "accountDetails": { "message": "Detail akun" }, "accountIdenticon": { "message": "Identikon akun" }, + "accountIsntConnectedToastText": { + "message": "$1 tidak terhubung ke $2" + }, "accountName": { "message": "Nama akun" }, @@ -153,6 +162,12 @@ "accountSelectionRequired": { "message": "Anda harus memilih satu akun!" }, + "accounts": { + "message": "Akun" + }, + "accountsConnected": { + "message": "Akun terhubung" + }, "active": { "message": "Aktif" }, @@ -243,6 +258,9 @@ "addIPFSGateway": { "message": "Tambahkan gateway IPFS pilihan Anda" }, + "addImportAccount": { + "message": "Tambahkan akun atau dompet perangkat keras" + }, "addMemo": { "message": "Tambahkan memo" }, @@ -256,6 +274,9 @@ "message": "Koneksi jaringan ini mengandalkan pihak ketiga. Koneksi ini mungkin kurang bisa diandalkan atau memungkinkan pihak ketiga melacak aktivitas. $1", "description": "$1 is Learn more link" }, + "addNewAccount": { + "message": "Tambahkan akun baru" + }, "addNewToken": { "message": "Tambahkan token baru" }, @@ -265,6 +286,12 @@ "addNfts": { "message": "Tambahkan NFT" }, + "addSnapAccountToggle": { + "message": "Aktifkan \"Tambahkan akun Snap (Beta)\"" + }, + "addSnapAccountsDescription": { + "message": "Mengaktifkan fitur ini akan memberi opsi untuk menambahkan akun Snap Beta baru langsung dari daftar akun Anda. Jika Anda menginstal akun Snap, harap diingat bahwa ini adalah layanan pihak ketiga." + }, "addSuggestedNFTs": { "message": "Tambahkan NFT yang disarankan" }, @@ -281,6 +308,9 @@ "addingCustomNetwork": { "message": "Menambahkan Jaringan" }, + "addingTokens": { + "message": "Menambahkan token" + }, "address": { "message": "Alamat" }, @@ -316,9 +346,27 @@ "airgapVault": { "message": "AirGap Vault" }, + "alert": { + "message": "Peringatan" + }, + "alertBannerMultipleAlertsDescription": { + "message": "Jika Anda menyetujui permintaan ini, pihak ketiga yang terdeteksi melakukan penipuan dapat mengambil semua aset Anda." + }, + "alertBannerMultipleAlertsTitle": { + "message": "Beberapa peringatan!" + }, "alertDisableTooltip": { "message": "Ini dapat diubah dalam \"Pengaturan > Peringatan\"" }, + "alertModalAcknowledge": { + "message": "Saya telah mengetahui risikonya dan tetap ingin melanjutkan" + }, + "alertModalDetails": { + "message": "Detail Peringatan" + }, + "alertModalReviewAllAlerts": { + "message": "Tinjau semua peringatan" + }, "alertSettingsUnconnectedAccount": { "message": "Memilih untuk menjelajahi situs web dengan akun yang tidak terhubung" }, @@ -334,6 +382,9 @@ "alerts": { "message": "Peringatan" }, + "all": { + "message": "Semua" + }, "allCustodianAccountsConnectedSubtitle": { "message": "Anda telah menghubungkan semua akun kustodian atau tidak memiliki akun untuk terhubung ke MetaMask Institutional." }, @@ -344,23 +395,26 @@ "message": "Seluruh $1 Anda", "description": "$1 is the symbol or name of the token that the user is approving spending" }, + "allPermissions": { + "message": "Semua Izin" + }, "allYourNFTsOf": { "message": "Seluruh NFT Anda dari $1 ", "description": "$1 is a link to contract on the block explorer when we're not able to retrieve a erc721 or erc1155 name" }, - "allowExternalExtensionTo": { - "message": "Izinkan ekstensi eksternal ini untuk:" + "allow": { + "message": "Izinkan" + }, + "allowMmiToConnectToCustodian": { + "message": "Ini akan memungkinkan MMI terhubung ke $1 untuk mengimpor akun Anda." + }, + "allowNotifications": { + "message": "Izinkan notifikasi" }, "allowSpendToken": { "message": "Berikan izin untuk mengakses $1 Anda?", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "Izinkan situs ini untuk:" - }, - "allowThisSnapTo": { - "message": "Izinkan snap ini untuk:" - }, "allowWithdrawAndSpend": { "message": "Izinkan $1 untuk menarik dan menggunakan hingga jumlah berikut:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -368,6 +422,23 @@ "amount": { "message": "Jumlah" }, + "amountReceived": { + "message": "Jumlah yang Diterima" + }, + "amountSent": { + "message": "Jumlah yang Dikirim" + }, + "andForListItems": { + "message": "$1, dan $2", + "description": "$1 is the first item, $2 is the last item in a list of items. Used in Snap Install Warning modal." + }, + "andForTwoItems": { + "message": "$1 dan $2", + "description": "$1 is the first item, $2 is the second item. Used in Snap Install Warning modal." + }, + "announcements": { + "message": "Pengumuman" + }, "appDescription": { "message": "Dompet Ethereum pada Browser Anda", "description": "The description of the application" @@ -402,6 +473,10 @@ "approveButtonText": { "message": "Setujui" }, + "approveIncreaseAllowance": { + "message": "Tingkatkan batas penggunaan $1", + "description": "The token symbol that is being approved" + }, "approveSpendingCap": { "message": "Setujui batas penggunaan $1", "description": "The token symbol that is being approved" @@ -427,6 +502,10 @@ "message": "Disetujui pada $1", "description": "$1 is the approval date for a permission" }, + "approvedOnForAccounts": { + "message": "Disetujui pada $1 untuk $2", + "description": "$1 is the approval date for a permission. $2 is the AvatarGroup component displaying account images." + }, "areYouSure": { "message": "Anda yakin?" }, @@ -439,12 +518,21 @@ "attemptSendingAssets": { "message": "Jika Anda mencoba untuk mengirim aset secara langsung dari satu jaringan ke jaringan lain, aset Anda berpotensi hilang secara permanen. Pastikan untuk menggunakan bridge." }, + "attemptSendingAssetsWithPortfolio": { + "message": "Aset Anda berpotensi hilang jika mencoba mengirimnya melalui jaringan lain. Transfer dana antar jaringan dengan aman menggunakan bridge, seperti $1" + }, + "attemptToCancelSwapForFree": { + "message": "Mencoba membatalkan pertukaran secara gratis" + }, "attemptingConnect": { "message": "Mencoba terhubung ke blockchain." }, "attributions": { "message": "Atribusi" }, + "auroraRpcDeprecationMessage": { + "message": "URL RPC Infura tidak lagi mendukung Aurora." + }, "authorizedPermissions": { "message": "Anda telah mengotorisasi izin berikut" }, @@ -471,13 +559,16 @@ "message": "Kembali" }, "backup": { - "message": "Pencadangan" + "message": "Cadangkan" }, "backupApprovalInfo": { "message": "Kode rahasia ini diperlukan untuk memulihkan dompet seandainya perangkat Anda hilang, lupa kata sandi, harus memasang kembali MetaMask, atau ingin mengakses dompet Anda di perangkat lain." }, "backupApprovalNotice": { - "message": "Cadangkan Frasa Pemulihan Rahasia Anda untuk menjaga keamanan dompet dan dana Anda." + "message": "Cadangkan Frasa Pemulihan Rahasia untuk menjaga keamanan dompet dan dana Anda." + }, + "backupKeyringSnapReminder": { + "message": "Pastikan Anda dapat mengakses sendiri akun yang dibuat oleh Snap ini sebelum menghapusnya" }, "backupNow": { "message": "Cadangkan sekarang" @@ -486,7 +577,7 @@ "message": "Cadangkan data Anda" }, "backupUserDataDescription": { - "message": "Anda dapat mencadangkan pengaturan pengguna yang berisi preferensi dan alamat akun ke dalam file JSON." + "message": "Anda dapat mencadangkan data seperti kontak dan preferensi Anda." }, "balance": { "message": "Saldo" @@ -500,6 +591,30 @@ "basic": { "message": "Dasar" }, + "basicConfigurationBannerCTA": { + "message": "Aktifkan fungsionalitas dasar" + }, + "basicConfigurationBannerTitle": { + "message": "Fungsionalitas dasar tidak aktif" + }, + "basicConfigurationLabel": { + "message": "Fungsionalitas dasar" + }, + "basicConfigurationModalCheckbox": { + "message": "Saya memahami dan ingin melanjutkan" + }, + "basicConfigurationModalDisclaimerOff": { + "message": "Artinya, Anda tidak akan benar-benar mengoptimalkan waktu di MetaMask. Fitur dasar (seperti detail token, pengaturan gas optimal, dan lainnya) tidak akan tersedia untuk Anda." + }, + "basicConfigurationModalDisclaimerOn": { + "message": "Untuk mengoptimalkan waktu di MetaMask, Anda perlu mengaktifkan fitur ini. Fungsi dasar (seperti detail token, pengaturan gas optimal, dan lainnya) penting untuk pengalaman web3." + }, + "basicConfigurationModalHeadingOff": { + "message": "Nonaktifkan fungsionalitas dasar" + }, + "basicConfigurationModalHeadingOn": { + "message": "Aktifkan fungsionalitas dasar" + }, "beCareful": { "message": "Berhati-hatilah" }, @@ -571,6 +686,9 @@ "blockaidDescriptionTransferFarming": { "message": "Jika Anda menyetujui permintaan ini, pihak ketiga yang terdeteksi melakukan penipuan akan mengambil semua aset Anda." }, + "blockaidMessage": { + "message": "Menjaga privasi - tidak ada data yang dibagikan kepada pihak ketiga. Tersedia di Arbitrum, Avalanche, BNB chain, Mainnet Ethereum, Linea, Optimism, Polygon, Base, dan Sepolia." + }, "blockaidTitleDeceptive": { "message": "Ini adalah permintaan tipuan" }, @@ -586,6 +704,9 @@ "bridge": { "message": "Bridge" }, + "bridgeDontSend": { + "message": "Bridge, jangan kirim" + }, "browserNotSupported": { "message": "Browser Anda tidak didukung..." }, @@ -598,6 +719,9 @@ "busy": { "message": "Sibuk" }, + "buyAndSell": { + "message": "Jual & Beli" + }, "buyAsset": { "message": "Beli $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -609,6 +733,10 @@ "buyNow": { "message": "Beli Sekarang" }, + "buyToken": { + "message": "Beli $1", + "description": "$1 is the token symbol" + }, "bytes": { "message": "Byte" }, @@ -618,9 +746,6 @@ "cancel": { "message": "Batal" }, - "cancelEdit": { - "message": "Batalkan pengeditan" - }, "cancelPopoverTitle": { "message": "Batalkan transaksi" }, @@ -647,6 +772,9 @@ "chainIdExistsErrorMsg": { "message": "ID chain ini saat ini digunakan oleh jaringan $1." }, + "chainListReturnedDifferentTickerSymbol": { + "message": "Simbol token ini tidak cocok dengan nama jaringan atau ID chain yang dimasukkan. Banyak token populer menggunakan simbol serupa, yang dapat digunakan penipu untuk mengelabui Anda agar mengirimkan token yang lebih berharga sebagai gantinya. Pastikan untuk memverifikasi semuanya sebelum melanjutkan." + }, "chooseYourNetwork": { "message": "Pilih jaringan Anda" }, @@ -682,9 +810,19 @@ "close": { "message": "Tutup" }, + "closeExtension": { + "message": "Tutup ekstensi" + }, + "closeWindowAnytime": { + "message": "Anda dapat menutup jendela ini setiap saat." + }, "coingecko": { "message": "CoinGecko" }, + "comboNoOptions": { + "message": "Opsi tidak ditemukan", + "description": "Default text shown in the combo field dropdown if no options." + }, "configureSnapPopupDescription": { "message": "Sekarang, Anda akan meninggalkan MetaMask untuk mengonfigurasi snap ini." }, @@ -703,12 +841,42 @@ "confirm": { "message": "Konfirmasikan" }, + "confirmAlertModalAcknowledge": { + "message": "Saya telah mengetahui peringatannya dan tetap ingin melanjutkan" + }, + "confirmAlertModalDetails": { + "message": "Jika masuk, pihak ketiga yang terdeteksi melakukan penipuan dapat mengambil semua aset Anda. Tinjau peringatannya sebelum melanjutkan." + }, + "confirmAlertModalTitle": { + "message": "Aset Anda mungkin berisiko" + }, + "confirmConnectCustodianRedirect": { + "message": "Kami akan mengarahkan Anda ke $1 setelah mengeklik lanjutkan." + }, + "confirmConnectCustodianText": { + "message": "Untuk menghubungkan akun, masuk ke akun $1 dan klik tombol 'hubungkan ke MMI'." + }, + "confirmConnectionTitle": { + "message": "Konfirmasikan koneksi ke $1" + }, "confirmPassword": { "message": "Konfirmasikan kata sandi" }, "confirmRecoveryPhrase": { "message": "Konfirmasikan Frasa Pemulihan Rahasia" }, + "confirmTitleDescContractInteractionTransaction": { + "message": "Konfirmasikan transaksi ini hanya jika Anda benar-benar memahami isinya dan memercayai situs yang memintanya." + }, + "confirmTitleDescSignature": { + "message": "Konfirmasikan pesan ini hanya jika Anda menyetujui isinya dan memercayai situs yang memintanya." + }, + "confirmTitleSignature": { + "message": "Permintaan tanda tangan" + }, + "confirmTitleTransaction": { + "message": "Permintaan transaksi" + }, "confirmed": { "message": "Dikonfirmasikan" }, @@ -724,9 +892,15 @@ "connect": { "message": "Hubungkan" }, + "connectAccount": { + "message": "Hubungkan akun" + }, "connectAccountOrCreate": { "message": "Hubungkan akun atau buat baru" }, + "connectAccounts": { + "message": "Hubungkan akun" + }, "connectCustodialAccountMenu": { "message": "Hubungkan Akun Kustodian" }, @@ -736,36 +910,25 @@ "connectCustodialAccountTitle": { "message": "Akun Kustodian" }, + "connectCustodianAccounts": { + "message": "Hubungkan akun $1" + }, "connectManually": { "message": "Hubungkan ke situs saat ini secara manual" }, + "connectMoreAccounts": { + "message": "Hubungkan akun lain" + }, "connectSnap": { "message": "Hubungkan $1", "description": "$1 is the snap for which a connection is being requested." }, - "connectTo": { - "message": "Hubungkan ke $1", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "Hubungkan ke semua $1 Anda", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "akun", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "Hubungkan ke $1", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1 akun", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "Hubungkan dengan MetaMask" }, + "connectedAccounts": { + "message": "Akun yang terhubung" + }, "connectedAccountsDescriptionPlural": { "message": "Anda memiliki $1 akun yang terhubung ke situs ini.", "description": "$1 is the number of accounts" @@ -776,6 +939,13 @@ "connectedAccountsEmptyDescription": { "message": "MetaMask tidak terhubung ke situs ini. Untuk terhubung ke situs web3, cari dan klik tombol hubungkan." }, + "connectedAccountsListTooltip": { + "message": "$1 dapat melihat saldo akun, alamat, aktivitas, dan menyarankan transaksi yang akan disetujui untuk akun terhubung.", + "description": "$1 is the origin name" + }, + "connectedAccountsToast": { + "message": "Akun yang terhubung diperbarui" + }, "connectedSites": { "message": "Situs yang terhubung" }, @@ -787,12 +957,21 @@ "message": "$1 tidak terhubung ke situs mana pun.", "description": "$1 is the account name" }, + "connectedSnapAndNoAccountDescription": { + "message": "MetaMask terhubung ke situs ini, tetapi belum ada akun yang terhubung" + }, + "connectedWith": { + "message": "Terhubung dengan" + }, "connecting": { "message": "Menghubungkan..." }, "connectingTo": { "message": "Menghubungkan ke $1" }, + "connectingToDeprecatedNetwork": { + "message": "'$1' sedang dihentikan dan mungkin tidak dapat beroperasi. Coba jaringan lainnya." + }, "connectingToGoerli": { "message": "Menghubungkan ke jaringan uji Goerli" }, @@ -802,6 +981,9 @@ "connectingToLineaMainnet": { "message": "Menghubungkan ke Linea Mainnet" }, + "connectingToLineaSepolia": { + "message": "Menghubungkan ke jaringan uji Linea Sepolia" + }, "connectingToMainnet": { "message": "Menghubungkan ke Ethereum Mainnet" }, @@ -831,6 +1013,12 @@ "continue": { "message": "Lanjutkan" }, + "continueMmiOnboarding": { + "message": "Lanjutkan orientasi MetaMask Institutional" + }, + "continueToWallet": { + "message": "Lanjutkan ke dompet" + }, "contract": { "message": "Kontrak" }, @@ -882,6 +1070,9 @@ "copyAddress": { "message": "Salin alamat ke papan klip" }, + "copyPrivateKey": { + "message": "Salin kunci pribadi" + }, "copyRawTransactionData": { "message": "Salin data transaksi mentah" }, @@ -900,6 +1091,15 @@ "createPassword": { "message": "Buat kata sandi" }, + "createSnapAccountDescription": { + "message": "$1 ingin menambahkan akun baru ke MetaMask." + }, + "createSnapAccountTitle": { + "message": "Buat akun" + }, + "crossChainSwapsLink": { + "message": "Bertukar antar jaringan dengan Portfolio MetaMask" + }, "cryptoCompare": { "message": "CryptoCompare" }, @@ -950,10 +1150,16 @@ "message": "Kustodian" }, "custodianAccountAddedDesc": { - "message": "Saat ini Anda dapat menggunakan akun kustodian di MetaMask Institutional." + "message": "Kini Anda dapat menggunakan akun Anda di MetaMask Institutional." }, "custodianAccountAddedTitle": { - "message": "Akun kustodian terpilih telah ditambahkan." + "message": "Akun $1 terpilih telah ditambahkan." + }, + "custodianQRCodeScan": { + "message": "Pindai kode QR dengan aplikasi seluler $1" + }, + "custodianQRCodeScanDescription": { + "message": "Atau masuk ke akun $1 dan klik tombol 'Hubungkan ke MMI'" }, "custodianReplaceRefreshTokenChangedFailed": { "message": "Buka $1 dan klik tombol 'Hubungkan ke MMI' di antarmuka pengguna untuk menghubungkan kembali akun Anda ke MMI." @@ -1017,7 +1223,7 @@ "message": "Deteksi token belum tersedia di jaringan ini. Harap impor token secara manual dan pastikan keamanannya. Pelajari seputar $1" }, "customTokenWarningInTokenDetectionNetwork": { - "message": "Sebelum mengimpor token secara manual, pastikan keamanannya. Pelajari seputar $1" + "message": "Siapa pun dapat membuat token, termasuk membuat versi palsu dari token yang ada. Pelajari tentang $1" }, "customTokenWarningInTokenDetectionNetworkWithTDOFF": { "message": "Pastikan keamanan token sebelum mengimpornya. Pelajari cara menghindari $1. Anda juga dapat mengaktifkan deteksi token $2." @@ -1025,6 +1231,12 @@ "customerSupport": { "message": "dukungan pelanggan" }, + "customizeYourNotifications": { + "message": "Sesuaikan notifikasi" + }, + "customizeYourNotificationsText": { + "message": "Aktifkan jenis notifikasi yang ingin diterima:" + }, "dappRequestedSpendingCap": { "message": "Batas penggunaan yang diminta situs" }, @@ -1108,6 +1320,18 @@ "deposit": { "message": "Deposit" }, + "deprecatedGoerliNtwrkMsg": { + "message": "Karena pembaruan pada sistem Ethereum, jaringan uji Goerli akan segera dihentikan." + }, + "deprecatedNetwork": { + "message": "Jaringan ini tidak digunakan lagi" + }, + "deprecatedNetworkButtonMsg": { + "message": "Mengerti" + }, + "deprecatedNetworkDescription": { + "message": "Jaringan yang Anda coba hubungkan tidak lagi didukung oleh Metamask. $1" + }, "description": { "message": "Deskripsi" }, @@ -1115,110 +1339,20 @@ "message": "Deskripsi dari $1", "description": "$1 represents the name of the snap" }, - "desktopApp": { - "message": "Aplikasi Desktop" - }, - "desktopConnectionCriticalErrorDescription": { - "message": "Kesalahan ini dapat terjadi secara berkala, jadi coba mulai ulang ekstensi atau nonaktifkan MetaMask Desktop." - }, - "desktopConnectionCriticalErrorTitle": { - "message": "MetaMask mengalami masalah untuk memulai" - }, - "desktopConnectionLostErrorDescription": { - "message": "Pastikan Anda memiliki aplikasi desktop serta menjalankan atau menonaktifkan MetaMask Desktop." - }, - "desktopConnectionLostErrorTitle": { - "message": "Koneksi MetaMask Desktop terputus" - }, - "desktopDisableButton": { - "message": "Nonaktifkan Aplikasi Desktop" - }, - "desktopDisableErrorCTA": { - "message": "Nonaktifkan MetaMask Desktop" - }, - "desktopEnableButton": { - "message": "Aktifkan Aplikasi Desktop" - }, - "desktopEnableButtonDescription": { - "message": "Klik untuk menjalankan semua proses latar belakang di aplikasi desktop." - }, - "desktopErrorNavigateSettingsCTA": { - "message": "Kembali ke Halaman Pengaturan" - }, - "desktopErrorRestartMMCTA": { - "message": "Mulai ulang MetaMask" - }, - "desktopNotFoundErrorCTA": { - "message": "Unduh MetaMask Desktop" - }, - "desktopNotFoundErrorDescription1": { - "message": "Pastikan Anda memiliki aplikasi desktop dan menjalankannya." - }, - "desktopNotFoundErrorDescription2": { - "message": "Jika Anda belum menginstal aplikasi desktop, unduh di situs web MetaMask." - }, - "desktopNotFoundErrorTitle": { - "message": "MetaMask Desktop tidak ditemukan" - }, - "desktopOpenOrDownloadCTA": { - "message": "Buka MetaMask Desktop" - }, - "desktopOutdatedErrorCTA": { - "message": "Perbarui MetaMask Desktop" - }, - "desktopOutdatedErrorDescription": { - "message": "Aplikasi MetaMask desktop perlu ditingkatkan." - }, - "desktopOutdatedErrorTitle": { - "message": "MetaMask Desktop sudah usang" - }, - "desktopOutdatedExtensionErrorCTA": { - "message": "Perbarui Ekstensi MetaMask" - }, - "desktopOutdatedExtensionErrorDescription": { - "message": "Ekstensi MetaMask perlu ditingkatkan." - }, - "desktopOutdatedExtensionErrorTitle": { - "message": "Ekstensi MetaMask sudah usang" - }, - "desktopPageDescription": { - "message": "Jika penyandingan berhasil, ekstensi akan dimulai ulang dan Anda harus memasukkan kembali kata sandi." - }, - "desktopPageSubTitle": { - "message": "Buka MetaMask Desktop dan ketikkan kode ini" - }, - "desktopPageTitle": { - "message": "Pasangkan dengan Desktop" - }, - "desktopPairedWarningDeepLink": { - "message": "Buka Pengaturan di MetaMask Desktop" - }, - "desktopPairedWarningDescription": { - "message": "Jika Anda ingin memulai pemasangan baru, hapus koneksi saat ini." - }, - "desktopPairedWarningTitle": { - "message": "MM Desktop sudah dipasangkan" - }, - "desktopPairingExpireMessage": { - "message": "Kode berakhir dalam $1 detik" - }, - "desktopRouteNotFoundErrorDescription": { - "message": "desktopRouteNotFoundErrorDescription" - }, - "desktopRouteNotFoundErrorTitle": { - "message": "desktopRouteNotFoundErrorTitle" + "details": { + "message": "Detail" }, - "desktopUnexpectedErrorCTA": { - "message": "Kembali ke Beranda MetaMask" + "developerOptions": { + "message": "Opsi Pengembang" }, - "desktopUnexpectedErrorDescription": { - "message": "Periksa MetaMask Desktop untuk memulihkan koneksi" + "developerOptionsResetStatesAnnouncementsDescription": { + "message": "Reset boolean isShown bernilai salah untuk semua pengumuman. Pengumuman adalah notifikasi yang ditampilkan di modal popup Yang Baru." }, - "desktopUnexpectedErrorTitle": { - "message": "Terjadi kesalahan..." + "developerOptionsResetStatesOnboarding": { + "message": "Reset berbagai state terkait orientasi dan alihkan ke halaman orientasi \"Amankan Dompet Anda\"." }, - "details": { - "message": "Detail" + "developerOptionsServiceWorkerKeepAlive": { + "message": "Menjadikan stempel waktu disimpan ke session.storage secara kontinu" }, "disabledGasOptionToolTipMessage": { "message": "“$1” dinonaktifkan karena tidak memenuhi kenaikan minimum 10% dari biaya gas asli.", @@ -1233,12 +1367,38 @@ "disconnectAllAccountsConfirmationDescription": { "message": "Anda yakin ingin memutus koneksi? Fungsionalitas situs Anda bisa hilang." }, + "disconnectAllAccountsText": { + "message": "akun" + }, + "disconnectAllSnapsText": { + "message": "Snap" + }, + "disconnectAllText": { + "message": "Jika Anda memutus koneksi $1 dari $2, Anda harus menghubungkannya kembali agar dapat menggunakannya lagi.", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`, $2 represents the website hostname" + }, + "disconnectAllTitle": { + "message": "Putuskan semua koneksi $1", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`" + }, "disconnectPrompt": { "message": "Putuskan koneksi $1" }, "disconnectThisAccount": { "message": "Putuskan koneksi akun ini" }, + "disconnectedAllAccountsToast": { + "message": "Semua akun terputus koneksinya dari $1", + "description": "$1 is name of the dapp`" + }, + "disconnectedSingleAccountToast": { + "message": "$1 terputus koneksinya dari $2", + "description": "$1 is name of the name and $2 represents the dapp name`" + }, + "discoverSnaps": { + "message": "Temukan Snap", + "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." + }, "dismiss": { "message": "Lewatkan" }, @@ -1248,9 +1408,21 @@ "dismissReminderField": { "message": "Lewatkan pengingat pencadangan Frasa Pemulihan Rahasia" }, + "displayNftMedia": { + "message": "Tampilkan media NFT" + }, + "displayNftMediaDescription": { + "message": "Alamat IP dapat diketahui oleh OpenSea atau pihak ketiga lainnya saat menampilkan media dan data NFT. Ini memungkinkan penyerang menghubungkan alamat IP dengan alamat Ethereum Anda. Deteksi otomatis NFT bergantung pada pengaturan ini, dan tidak akan tersedia saat dinonaktifkan." + }, + "doNotShare": { + "message": "Jangan bagikan ini kepada siapa pun" + }, "domain": { "message": "Domain" }, + "domainNotSupportedOnNetwork": { + "message": "Jaringan tidak mendukung pencarian domain" + }, "done": { "message": "Selesai" }, @@ -1269,6 +1441,9 @@ "downloadStateLogs": { "message": "Unduh log status" }, + "dragAndDropBanner": { + "message": "Anda dapat menyeret jaringan untuk menyusun ulang. " + }, "dropped": { "message": "Terputus" }, @@ -1367,6 +1542,9 @@ "editSpeedUpEditGasFeeModalTitle": { "message": "Edit biaya gas percepatan" }, + "enable": { + "message": "Aktifkan" + }, "enableAutoDetect": { "message": " Aktifkan deteksi otomatis" }, @@ -1397,6 +1575,18 @@ "enhancedTokenDetectionAlertMessage": { "message": "Saat ini, deteksi token lanjutan tersedia di $1. $2" }, + "ensDomainsSettingDescriptionIntroduction": { + "message": "MetaMask memungkinkan Anda melihat domain ENS pada bilah alamat browser Anda. Berikut cara kerjanya:" + }, + "ensDomainsSettingDescriptionOutroduction": { + "message": "Ingatlah bahwa alamat IP akan diketahui oleh layanan pihak ketiga IPFS saat menggunakan fitur ini." + }, + "ensDomainsSettingDescriptionPart1": { + "message": "MetaMask memeriksa kontrak ENS Ethereum untuk menemukan kode yang terhubung ke nama ENS." + }, + "ensDomainsSettingDescriptionPart2": { + "message": "Jika kode terhubung ke IPFS, Anda dapat melihat konten yang dikaitkan dengannya (umumnya situs web)." + }, "ensDomainsSettingTitle": { "message": "Tampilkan domain ENS di bilah alamat" }, @@ -1438,6 +1628,9 @@ "message": "Detail kesalahan", "description": "Title for collapsible section that displays error details for debugging purposes" }, + "errorGettingSafeChainList": { + "message": "Terjadi kesalahan saat mendapatkan daftar rantai aman, lanjutkan dengan hati-hati." + }, "errorMessage": { "message": "Pesan: $1", "description": "Displayed error message for debugging purposes. $1 is the error message" @@ -1469,6 +1662,9 @@ "message": "Terjadi kesalahan pada $1", "description": "$1 represents the name of the snap" }, + "estimatedFee": { + "message": "Estimasi biaya" + }, "ethGasPriceFetchWarning": { "message": "Biaya gas cadangan diberikan karena layanan estimasi gas utama saat ini tidak tersedia." }, @@ -1495,12 +1691,24 @@ "message": "Eksperimental" }, "extendWalletWithSnaps": { - "message": "Perluas pengalaman dompet.", + "message": "Jelajahi Snap yang dibuat oleh komunitas untuk menyesuaikan pengalaman web3 Anda", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "extensionInsallCompleteDescription": { + "message": "Kembali ke orientasi produk MetaMask Institutional untuk menghubungkan akun kustodian atau kustodian mandiri milik Anda." + }, + "extensionInsallCompleteTitle": { + "message": "Penginstalan ekstensi selesai" + }, "externalExtension": { "message": "Ekstensi eksternal" }, + "externalNameSourcesSetting": { + "message": "Nama panggilan yang diusulkan" + }, + "externalNameSourcesSettingDescription": { + "message": "Kami akan mengambil nama panggilan yang diusulkan untuk alamat yang berinteraksi dengan Anda dari sumber pihak ketiga seperti Etherscan, Infura, dan Lens Protocol. Sumber-sumber ini akan dapat melihat alamat-alamat tersebut dan alamat IP Anda. Alamat akun Anda tidak akan diketahui oleh pihak ketiga." + }, "failed": { "message": "Gagal" }, @@ -1519,6 +1727,9 @@ "feeAssociatedRequest": { "message": "Biaya dikaitkan dengan permintaan ini." }, + "feeDetails": { + "message": "Detail biaya" + }, "fiat": { "message": "Fiat", "description": "Exchange type" @@ -1551,6 +1762,9 @@ "message": "Saya menerima risikonya", "description": "this text is shown on a button, which the user presses to confirm they understand the risks of using Flask" }, + "floatAmountToken": { + "message": "Jumlah token harus berupa bilangan bulat" + }, "followUsOnTwitter": { "message": "Ikuti kami di Twitter" }, @@ -1573,6 +1787,9 @@ "fromTokenLists": { "message": "Dari daftar token: $1" }, + "function": { + "message": "Fungsi: $1" + }, "functionApprove": { "message": "Fungsi: Setujui" }, @@ -1582,6 +1799,13 @@ "functionType": { "message": "Jenis fungsi" }, + "fundYourWallet": { + "message": "Danai dompet Anda" + }, + "fundYourWalletDescription": { + "message": "Mulailah dengan menambahkan sejumlah $1 ke dompet Anda.", + "description": "$1 is the token symbol" + }, "gas": { "message": "Gas" }, @@ -1592,6 +1816,9 @@ "message": "Biaya gas ini telah disarankan oleh $1. Pengabaian dapat menyebabkan masalah pada transaksi Anda. Hubungi $1 jika ada pertanyaan.", "description": "$1 represents the Dapp's origin" }, + "gasIsETH": { + "message": "Gas bernilai $1 " + }, "gasLimit": { "message": "Batas gas" }, @@ -1636,6 +1863,9 @@ "message": "$1 jam", "description": "$1 represents a number of hours" }, + "gasTimingLow": { + "message": "Lambat" + }, "gasTimingMinutesShort": { "message": "$1 mnt", "description": "$1 represents a number of minutes" @@ -1650,15 +1880,29 @@ "general": { "message": "Umum" }, - "globalTitle": { - "message": "Menu global" + "generalCameraError": { + "message": "Kami tidak dapat mengakses kamera Anda. Harap coba lagi." }, - "globalTourDescription": { - "message": "Lihat portofolio, situs terhubung, pengaturan, dan lainnya" + "generalCameraErrorTitle": { + "message": "Terjadi kesalahan...." + }, + "genericExplorerView": { + "message": "Lihat akun di $1" + }, + "getStartedWithNFTs": { + "message": "Dapatkan $1 untuk membeli NFT", + "description": "$1 is the token symbol" + }, + "getStartedWithNFTsDescription": { + "message": "Mulailah menggunakan NFT dengan menambahkan sejumlah $1 ke dompet Anda.", + "description": "$1 is the token symbol" }, "goBack": { "message": "Kembali" }, + "goToSite": { + "message": "Buka situs" + }, "goerli": { "message": "Jaringan uji Goerli" }, @@ -1700,15 +1944,24 @@ "hexData": { "message": "Data Hex" }, + "hiddenAccounts": { + "message": "Akun tersembunyi" + }, "hide": { "message": "Sembunyikan" }, + "hideAccount": { + "message": "Sembunyikan akun" + }, "hideFullTransactionDetails": { "message": "Sembunyikan detail transaksi lengkap" }, "hideSeedPhrase": { "message": "Sembunyikan frasa seed" }, + "hideSentitiveInfo": { + "message": "Sembunyikan informasi sensitif" + }, "hideToken": { "message": "Sembunyikan token" }, @@ -1782,7 +2035,7 @@ "message": "tahan untuk mengungkapkan lingkaran terbuka" }, "id": { - "message": "Id" + "message": "ID" }, "ignoreAll": { "message": "Abaikan semua" @@ -1790,6 +2043,9 @@ "ignoreTokenWarning": { "message": "Jika Anda menyembunyikan token, token tersebut tidak akan ditampilkan di dompet Anda. Namun, Anda masih dapat menambahkannya dengan mencarinya." }, + "imToken": { + "message": "imToken" + }, "import": { "message": "Impor", "description": "Button to import an account from a selected file" @@ -1848,6 +2104,9 @@ "importTokensCamelCase": { "message": "Impor token" }, + "importTokensError": { + "message": "Kami tidak dapat mengimpor token. Coba lagi nanti." + }, "importWithCount": { "message": "Impor $1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -1866,6 +2125,9 @@ "initialTransactionConfirmed": { "message": "Transaksi awal Anda dikonfirmasikan oleh jaringan. Klik Oke untuk kembali." }, + "inlineAlert": { + "message": "Peringatan" + }, "inputLogicEmptyState": { "message": "Masukkan angka yang menurut Anda dapat digunakan pihak ketiga sekarang atau di masa mendatang. Anda selalu dapat meningkatkan batas penggunaan nantinya." }, @@ -1876,6 +2138,27 @@ "inputLogicHigherNumber": { "message": "Ini memungkinkan pihak ketiga menggunakan semua saldo token Anda hingga mencapai batas atau Anda mencabut batas penggunaan. Jika ini bukan yang dimaksudkan, pertimbangkan untuk menetapkan batas penggunaan yang lebih rendah." }, + "insightWarning": { + "message": "peringatan" + }, + "insightWarningCheckboxMessage": { + "message": "$1 permintaan dari $2", + "description": "$1 is the action i.e. sign, confirm. $2 is the origin making the request." + }, + "insightWarningContentPlural": { + "message": "Tinjau $1 sebelum $2. Setelah dibuat, $3 tidak dapat diubah.", + "description": "$1 the 'insightWarnings' message (2 warnings) representing warnings, $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningContentSingular": { + "message": "Tinjau $1 sebelum $2. Setelah dibuat, $3 tidak dapat diubah.", + "description": "$1 is the 'insightWarning' message (1 warning), $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningHeader": { + "message": "Permintaan ini mungkin berisiko" + }, + "insightWarnings": { + "message": "peringatan" + }, "insightsFromSnap": { "message": "Wawasan dari $1", "description": "$1 represents the name of the snap" @@ -1883,9 +2166,18 @@ "install": { "message": "Instal" }, + "installExtension": { + "message": "Instal ekstensi" + }, + "installExtensionDescription": { + "message": "Versi dompet web3 terkemuka di dunia yang sesuai dengan institusi, MetaMask." + }, "installOrigin": { "message": "Instal asal" }, + "installRequest": { + "message": "Tambahkan ke MetaMask" + }, "installedOn": { "message": "Diinstal di $1", "description": "$1 is the date when the snap has been installed" @@ -1914,6 +2206,12 @@ "insufficientTokens": { "message": "Token tidak cukup." }, + "interactingWith": { + "message": "Berinteraksi dengan" + }, + "interactingWithTransactionDescription": { + "message": "Ini merupakan kontrak yang berinteraksi dengan Anda. Lindungi diri dari penipu dengan memverifikasi detailnya." + }, "invalidAddress": { "message": "Alamat tidak valid" }, @@ -1986,6 +2284,9 @@ "ipfsToggleModalSettings": { "message": "Pengaturan > Keamanan dan privasi" }, + "isSigningOrSubmitting": { + "message": "Transaksi sebelumnya sedang ditandatangani atau dikirim" + }, "jazzAndBlockies": { "message": "Jazzicons dan Blockies merupakan dua gaya ikon unik yang berbeda untuk membantu Anda mengidentifikasi akun dengan cepat." }, @@ -1999,6 +2300,24 @@ "message": "File JSON", "description": "format for importing an account" }, + "keyringAccountName": { + "message": "Nama akun" + }, + "keyringAccountPublicAddress": { + "message": "Alamat Publik" + }, + "keyringSnapRemovalResult1": { + "message": "$1 $2dihapus", + "description": "Displays the result after removal of a keyring snap. $1 is the snap name, $2 is whether it is successful or not" + }, + "keyringSnapRemovalResultNotSuccessful": { + "message": "tidak ", + "description": "Displays the `not` word in $2." + }, + "keyringSnapRemoveConfirmation": { + "message": "Ketik $1 untuk mengonfirmasi bahwa Anda ingin menghapus snap ini:", + "description": "Asks user to input the name nap prior to deleting the snap. $1 is the snap name" + }, "keystone": { "message": "Keystone" }, @@ -2017,9 +2336,15 @@ "lastSold": { "message": "Terakhir terjual" }, + "lavaDomeCopyWarning": { + "message": "Demi keamanan Anda, memilih teks ini tidak tersedia untuk saat ini." + }, "layer1Fees": { "message": "Biaya layer 1" }, + "layer2Fees": { + "message": "Biaya layer 2" + }, "learnCancelSpeeedup": { "message": "Pelajari cara $1", "description": "$1 is link to cancel or speed up transactions" @@ -2037,9 +2362,21 @@ "learnMoreUpperCase": { "message": "Pelajari selengkapnya" }, + "learnMoreUpperCaseWithDot": { + "message": "Pelajari selengkapnya." + }, "learnScamRisk": { "message": "penipuan dan risiko keamanan." }, + "learnToBridge": { + "message": "Pelajari bridge" + }, + "leaveMetaMask": { + "message": "Keluar dari MetaMask?" + }, + "leaveMetaMaskDesc": { + "message": "Anda akan mengunjungi situs di luar MetaMask. Periksa kembali URL sebelum melanjutkan." + }, "ledgerAccountRestriction": { "message": "Manfaatkan akun terakhir Anda sebelum menambahkan yang baru." }, @@ -2058,6 +2395,18 @@ "ledgerDeviceOpenFailureMessage": { "message": "Perangkat Ledger gagal dibuka. Ledger Anda mungkin terhubung ke perangkat lunak lain. Tutup Ledger Live atau aplikasi lain yang terhubung ke perangkat Ledger Anda, dan coba hubungkan kembali." }, + "ledgerErrorConnectionIssue": { + "message": "Hubungkan kembali ledger Anda, buka aplikasi ETH dan coba lagi." + }, + "ledgerErrorDevicedLocked": { + "message": "Ledger Anda terkunci. Buka lalu coba lagi." + }, + "ledgerErrorEthAppNotOpen": { + "message": "Untuk mengatasi masalah ini, buka aplikasi ETH di perangkat Anda dan coba lagi." + }, + "ledgerErrorTransactionDataNotPadded": { + "message": "Data input transaksi Ethereum tidak cukup lengkap." + }, "ledgerLiveApp": { "message": "Aplikasi Ledger Live" }, @@ -2077,6 +2426,9 @@ "lightTheme": { "message": "Terang" }, + "likeToImportToken": { + "message": "Ingin mengimpor token ini?" + }, "likeToImportTokens": { "message": "Apakah Anda ingin menambahkan token ini?" }, @@ -2086,6 +2438,9 @@ "lineaMainnet": { "message": "Linea Mainnet" }, + "lineaSepolia": { + "message": "Jaringan uji Linea Sepolia" + }, "link": { "message": "Tautan" }, @@ -2098,8 +2453,11 @@ "loading": { "message": "Memuat..." }, - "loadingNFTs": { - "message": "Memuat NFT..." + "loadingScreenHardwareWalletMessage": { + "message": "Selesaikan transaksi di dompet perangkat keras." + }, + "loadingScreenSnapMessage": { + "message": "Selesaikan transaksi di Snap." }, "loadingTokens": { "message": "Memuat token..." @@ -2146,6 +2504,9 @@ "message": "Pastikan tidak ada yang melihat layar Anda", "description": "Warning to users to be care while creating and saving their new Secret Recovery Phrase" }, + "manageInSettings": { + "message": "Kelola di pengaturan" + }, "max": { "message": "Maks" }, @@ -2180,15 +2541,34 @@ "metaMaskConnectStatusParagraphTwo": { "message": "Tombol status koneksi menunjukkan apakah situs web yang Anda kunjungi terhubung ke akun Anda yang dipilih saat ini." }, + "metadataModalSourceTooltip": { + "message": "$1 dihosting pada npm dan $2 merupakan pengenal unik Snap ini.", + "description": "$1 is the snap name and $2 is the snap NPM id." + }, "metamaskInstitutionalVersion": { "message": "Versi MetaMask Institutional" }, + "metamaskNotificationsAreOff": { + "message": "Saat ini notifikasi dompet tidak aktif." + }, + "metamaskPortfolio": { + "message": "Portfolio MetaMask." + }, "metamaskSwapsOfflineDescription": { "message": "MetaMask Swap sedang dalam pemeliharaan. Harap periksa kembali nanti." }, "metamaskVersion": { "message": "Versi MetaMask" }, + "methodData": { + "message": "Metode" + }, + "methodDataTransactionDescription": { + "message": "Ini merupakan tindakan khusus yang akan diambil. Data ini dapat dipalsukan, jadi pastikan Anda memercayai situs tersebut." + }, + "methodNotSupported": { + "message": "Akun ini tidak mendukung." + }, "metrics": { "message": "Metrik" }, @@ -2224,11 +2604,17 @@ "mmiBuiltAroundTheWorld": { "message": "MetaMask Institutional dirancang dan dibangun di seluruh dunia." }, + "mmiNewNFTDetectedInNFTsTabMessage": { + "message": "Izinkan MetaMask Institutional mendeteksi dan menampilkan NFT di dompet secara otomatis." + }, + "mmiPasswordSetupDetails": { + "message": "Kata sandi ini hanya akan membuka ekstensi MetaMask Institutional." + }, "more": { "message": "selengkapnya" }, "multipleSnapConnectionWarning": { - "message": "$1 ingin terhubung dengan $2 snap. Lanjutkan jika Anda memercayai situs web ini.", + "message": "$1 ingin menggunakan Snap $2", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." }, "mustSelectOne": { @@ -2237,10 +2623,80 @@ "name": { "message": "Nama" }, + "nameAddressLabel": { + "message": "Alamat", + "description": "Label above address field in name component modal." + }, + "nameInstructionsNew": { + "message": "Jika Anda mengetahui alamat ini, berikan nama panggilan agar dapat dikenali di kemudian hari.", + "description": "Instruction text in name component modal when value is not recognised." + }, + "nameInstructionsRecognized": { + "message": "Alamat ini memiliki nama panggilan default, tetapi Anda dapat mengeditnya atau menjelajahi saran lainnya.", + "description": "Instruction text in name component modal when value is recognized but not saved." + }, + "nameInstructionsSaved": { + "message": "Anda telah menambahkan nama panggilan untuk alamat ini sebelumnya. Anda dapat mengedit atau melihat nama panggilan lain yang disarankan.", + "description": "Instruction text in name component modal when value is saved." + }, + "nameLabel": { + "message": "Nama panggilan", + "description": "Label above name input field in name component modal." + }, + "nameModalMaybeProposedName": { + "message": "Mungkin: $1", + "description": "$1 is the proposed name" + }, + "nameModalTitleNew": { + "message": "Alamat tidak dikenal", + "description": "Title of the modal created by the name component when value is not recognised." + }, + "nameModalTitleRecognized": { + "message": "Alamat yang dikenali", + "description": "Title of the modal created by the name component when value is recognized but not saved." + }, + "nameModalTitleSaved": { + "message": "Alamat tersimpan", + "description": "Title of the modal created by the name component when value is saved." + }, + "nameProviderProposedBy": { + "message": "Diusulkan oleh $1", + "description": "$1 is the name of the provider" + }, + "nameProvider_ens": { + "message": "Layanan Nama Ethereum (ENS)" + }, + "nameProvider_etherscan": { + "message": "Etherscan" + }, + "nameProvider_lens": { + "message": "Lens Protocol" + }, + "nameProvider_token": { + "message": "MetaMask" + }, + "nameSetPlaceholder": { + "message": "Pilih nama panggilan...", + "description": "Placeholder text for name input field in name component modal." + }, + "nativePermissionRequestDescription": { + "message": "Ingin situs ini melakukan hal berikut?", + "description": "Description below header used on Permission Connect screen for native permissions." + }, "nativeToken": { "message": "Token asli di jaringan ini adalah $1. Ini merupakan token yang digunakan untuk biaya gas.", "description": "$1 represents the name of the native token on the current network" }, + "nativeTokenScamWarningConversion": { + "message": "Edit detail jaringan" + }, + "nativeTokenScamWarningDescription": { + "message": "Jaringan ini tidak cocok dengan ID chain atau nama yang terkait. Banyak token populer menggunakan nama $1, menjadikannya target penipuan. Penipu dapat mengelabui Anda agar mengirimkan mata uang yang lebih berharga sebagai imbalannya. Verifikasikan semuanya sebelum melanjutkan.", + "description": "$1 represents the currency name" + }, + "nativeTokenScamWarningTitle": { + "message": "Ini berpotensi penipuan" + }, "needHelp": { "message": "Butuh bantuan? Hubungi $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -2261,6 +2717,9 @@ "negativeETH": { "message": "Tidak dapat mengirim jumlah negatif ETH." }, + "negativeOrZeroAmountToken": { + "message": "Tidak dapat mengirim aset dalam jumlah negatif atau nol." + }, "network": { "message": "Jaringan:" }, @@ -2291,6 +2750,9 @@ "networkNameBSC": { "message": "BSC" }, + "networkNameBase": { + "message": "Dasar" + }, "networkNameDefinition": { "message": "Nama yang dikaitkan dengan jaringan ini." }, @@ -2300,12 +2762,21 @@ "networkNameGoerli": { "message": "Goerli" }, + "networkNameLinea": { + "message": "Linea" + }, + "networkNameOpMainnet": { + "message": "OP Mainnet" + }, "networkNamePolygon": { "message": "Polygon" }, "networkNameTestnet": { "message": "Testnet" }, + "networkNameZkSyncEra": { + "message": "zkSync Era" + }, "networkProvider": { "message": "Penyedia jaringan" }, @@ -2358,6 +2829,19 @@ "newContract": { "message": "Kontrak baru" }, + "newNFTDetectedInImportNFTsMessageStrongText": { + "message": "Pengaturan > Keamanan dan privasi" + }, + "newNFTDetectedInImportNFTsMsg": { + "message": "Untuk melihat NFT menggunakan OpenSea, aktifkan 'Tampilkan Media NFT' di $1.", + "description": "$1 is used for newNFTDetectedInImportNFTsMessageStrongText" + }, + "newNFTDetectedInNFTsTabMessage": { + "message": "Izinkan MetaMask mendeteksi dan menampilkan NFT di dompet secara otomatis." + }, + "newNFTsAutodetected": { + "message": "Autodeteksi NFT" + }, "newNetworkAdded": { "message": "“$1” berhasil ditambahkan!" }, @@ -2367,6 +2851,12 @@ "newPassword": { "message": "Kata sandi baru (min 8 karakter)" }, + "newPrivacyPolicyActionButton": { + "message": "Baca selengkapnya" + }, + "newPrivacyPolicyTitle": { + "message": "Kami telah memperbarui kebijakan privasi" + }, "newTokensImportedMessage": { "message": "Anda berhasil mengimpor $1.", "description": "$1 is the string of symbols of all the tokens imported" @@ -2388,6 +2878,9 @@ "message": "Token ini merupakan NFT. Tambahkan ke $1", "description": "$1 is a clickable link with text defined by the 'importNFTPage' key" }, + "nftAlreadyAdded": { + "message": "NFT telah ditambahkan." + }, "nftDisclaimer": { "message": "Penafian: MetaMask mengambil file media dari url sumber. URL ini terkadang diubah oleh pasar tempat NFT dicetak." }, @@ -2423,12 +2916,21 @@ "noAddressForName": { "message": "Alamat untuk nama ini belum diatur." }, + "noConnectedAccountDescription": { + "message": "Pilih akun yang ingin Anda gunakan di situs ini untuk melanjutkan." + }, + "noConnectedAccountTitle": { + "message": "MetaMask tidak terhubung ke situs ini" + }, "noConversionDateAvailable": { "message": "Tanggal konversi mata uang tidak tersedia" }, "noConversionRateAvailable": { "message": "Nilai konversi tidak tersedia" }, + "noDomainResolution": { + "message": "Tidak ada resolusi untuk domain yang tersedia." + }, "noNFTs": { "message": "Belum ada NFT" }, @@ -2447,6 +2949,9 @@ "noWebcamFoundTitle": { "message": "Webcam tidak ditemukan" }, + "nonCustodialAccounts": { + "message": "MetaMask Institutional memungkinkan Anda untuk menggunakan akun non-kustodian, apabila berencana menggunakan akun ini untuk mencadangkan Frasa Pemulihan Rahasia." + }, "nonce": { "message": "Nonce" }, @@ -2477,69 +2982,137 @@ "notePlaceholder": { "message": "Pemberi persetujuan akan melihat catatan ini saat menyetujui transaksi di kustodian." }, - "notificationTransactionFailedMessage": { - "message": "Transaksi $1 gagal! $2", - "description": "Content of the browser notification that appears when a transaction fails" + "notificationDetail": { + "message": "Detail" }, - "notificationTransactionFailedMessageMMI": { - "message": "Transaksi gagal! $1", - "description": "Content of the browser notification that appears when a transaction fails in MMI" + "notificationDetailBaseFee": { + "message": "Biaya dasar (GWEI)" }, - "notificationTransactionFailedTitle": { - "message": "Transaksi gagal", - "description": "Title of the browser notification that appears when a transaction fails" + "notificationDetailGasLimit": { + "message": "Batas gas (unit)" }, - "notificationTransactionSuccessMessage": { - "message": "Transaksi $1 dikonfirmasi!", - "description": "Content of the browser notification that appears when a transaction is confirmed" + "notificationDetailGasUsed": { + "message": "Gas yang digunakan (unit)" }, - "notificationTransactionSuccessTitle": { - "message": "Transaksi terkonfirmasi", - "description": "Title of the browser notification that appears when a transaction is confirmed" + "notificationDetailMaxFee": { + "message": "Biaya maks per gas" }, - "notificationTransactionSuccessView": { - "message": "Lihat di $1", - "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" + "notificationDetailNetwork": { + "message": "Jaringan" }, - "notifications": { - "message": "Notifikasi" + "notificationDetailNetworkFee": { + "message": "Biaya jaringan" }, - "notifications20ActionText": { - "message": "Pelajari selengkapnya", - "description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a ledger page to resolve the U2F connection issue." + "notificationDetailPriorityFee": { + "message": "Biaya prioritas (GWEI)" }, - "notifications20Description": { - "message": "Jika menggunakan Firefox versi terbaru, Anda dapat mengalami masalah terkait Firefox yang menghentikan dukungan U2F.", - "description": "Description of a notification in the 'See What's New' popup. Describes the U2F support being dropped by firefox and that it affects ledger users." + "notificationItemCheckBlockExplorer": { + "message": "Periksa di BlockExplorer" }, - "notifications20Title": { - "message": "Pengguna Ledger dan Firefox Mengalami Masalah Koneksi", - "description": "Title for a notification in the 'See What's New' popup. Tells users that latest firefox users using U2F may experience connection issues." + "notificationItemCollection": { + "message": "Koleksi" }, - "notifications24ActionText": { - "message": "Mengerti" + "notificationItemConfirmed": { + "message": "Dikonfirmasi" }, - "notifications24Description": { - "message": "Pengaturan biaya gas lanjutan kini diingat berdasarkan jaringan yang Anda gunakan. Artinya, Anda dapat menetapkan biaya gas lanjutan yang spesifik untuk setiap jaringan dan menghindari kelebihan pembayaran untuk gas atau transaksi yang macet." + "notificationItemError": { + "message": "Saat ini biaya tidak dapat dipulihkan" }, - "notifications24Title": { - "message": "Biaya gas lanjutan berdasarkan jaringan" + "notificationItemFrom": { + "message": "Dari" + }, + "notificationItemLidoStakeReadyToBeWithdrawn": { + "message": "Penarikan Siap" + }, + "notificationItemLidoStakeReadyToBeWithdrawnMessage": { + "message": "Kini Anda dapat menarik $1 yang belum di-stake" + }, + "notificationItemLidoWithdrawalRequestedMessage": { + "message": "Permintaan untuk membatalkan stake $1 telah dikirim" + }, + "notificationItemNFTReceivedFrom": { + "message": "Menerima NFT dari" + }, + "notificationItemNFTSentTo": { + "message": "Mengirim NFT ke" + }, + "notificationItemNetwork": { + "message": "Jaringan" + }, + "notificationItemRate": { + "message": "Tarif (termasuk biaya)" + }, + "notificationItemReceived": { + "message": "Diterima" + }, + "notificationItemReceivedFrom": { + "message": "Diterima dari" + }, + "notificationItemSent": { + "message": "Terkirim" + }, + "notificationItemSentTo": { + "message": "Terkirim ke" + }, + "notificationItemStakeCompleted": { + "message": "Stake selesai" + }, + "notificationItemStaked": { + "message": "Di-stake" + }, + "notificationItemStakingProvider": { + "message": "Penyedia Stake" + }, + "notificationItemStatus": { + "message": "Status" + }, + "notificationItemSwapped": { + "message": "Ditukar" }, - "notifications8ActionText": { - "message": "Buka Pengaturan > Lanjutan", - "description": "Description on an action button that appears in the What's New popup. Tells the user that if they click it, they will go to our Advanced settings page." + "notificationItemSwappedFor": { + "message": "untuk" + }, + "notificationItemTo": { + "message": "Ke" + }, + "notificationItemTransactionId": { + "message": "ID Transaksi" + }, + "notificationItemUnStakeCompleted": { + "message": "Pembatalan Stake selesai" + }, + "notificationItemUnStaked": { + "message": "Stake dibatalkan" + }, + "notificationItemUnStakingRequested": { + "message": "Permintaan pembatalan stake" + }, + "notificationTransactionFailedMessage": { + "message": "Transaksi $1 gagal! $2", + "description": "Content of the browser notification that appears when a transaction fails" + }, + "notificationTransactionFailedMessageMMI": { + "message": "Transaksi gagal! $1", + "description": "Content of the browser notification that appears when a transaction fails in MMI" + }, + "notificationTransactionFailedTitle": { + "message": "Transaksi gagal", + "description": "Title of the browser notification that appears when a transaction fails" + }, + "notificationTransactionSuccessMessage": { + "message": "Transaksi $1 dikonfirmasi!", + "description": "Content of the browser notification that appears when a transaction is confirmed" }, - "notifications8DescriptionOne": { - "message": "Pada MetaMask v10.4.0, Anda tidak lagi memerlukan Ledger Live untuk menghubungkan perangkat Ledger Anda ke MetaMask.", - "description": "Description of a notification in the 'See What's New' popup. Describes changes for how Ledger Live is no longer needed to connect the device." + "notificationTransactionSuccessTitle": { + "message": "Transaksi terkonfirmasi", + "description": "Title of the browser notification that appears when a transaction is confirmed" }, - "notifications8DescriptionTwo": { - "message": "Untuk pengalaman Ledger yang lebih mudah dan stabil, buka tab Pengaturan > Lanjutan dan alihkan 'Jenis Koneksi Ledger Pilihan' ke 'WebHID'.", - "description": "Description of a notification in the 'See What's New' popup. Describes how the user can turn off the Ledger Live setting." + "notificationTransactionSuccessView": { + "message": "Lihat di $1", + "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" }, - "notifications8Title": { - "message": "Peningkatan koneksi Ledger", - "description": "Title for a notification in the 'See What's New' popup. Notifies ledger users that there is an improvement in how they can connect their device." + "notifications": { + "message": "Notifikasi" }, "notificationsDropLedgerFirefoxDescription": { "message": "Firefox tidak lagi mendukung U2F, sehingga Ledger tidak akan berfungsi dengan MetaMask di Firefox. Cobalah MetaMask di Google Chrome sebagai gantinya.", @@ -2549,33 +3122,37 @@ "message": "Menghapus Dukungan Ledger untuk Firefox", "description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped." }, - "notificationsEmptyText": { - "message": "Di sinilah Anda bisa menemukan pemberitahuan dari snap yang Anda instal." - }, - "notificationsHeader": { - "message": "Notifikasi" + "notificationsFeatureToggle": { + "message": "Aktifkan Notifikasi Dompet", + "description": "Experimental feature title" }, - "notificationsInfos": { - "message": "$1 dari $2", - "description": "$1 is the date at which the notification has been dispatched and $2 is the link to the snap that dispatched the notification." + "notificationsFeatureToggleDescription": { + "message": "Ini mengaktifkan notifikasi dompet seperti mengirim/menerima dana atau nft dan pengumuman fitur.", + "description": "Description of the experimental notifications feature" }, "notificationsMarkAllAsRead": { "message": "Tandai semua telah dibaca" }, - "notificationsOpenBetaSnapsActionText": { - "message": "Selengkapnya" + "notificationsPageEmptyTitle": { + "message": "Tak ada apa pun di sini" + }, + "notificationsPageErrorContent": { + "message": "Coba kunjungi halaman ini lagi." }, - "notificationsOpenBetaSnapsDescriptionOne": { - "message": "🎉 Kami sangat gembira mengumumkan versi Open Beta dari MetaMask Snap!" + "notificationsPageErrorTitle": { + "message": "Telah terjadi kesalahan" }, - "notificationsOpenBetaSnapsDescriptionThree": { - "message": "Personalisasikan dompet Anda dengan snap yang dibuat oleh komunitas pengembang!" + "notificationsPageNoNotificationsContent": { + "message": "Anda belum menerima notifikasi." }, - "notificationsOpenBetaSnapsDescriptionTwo": { - "message": "Snap membantu Anda melakukan lebih banyak hal dengan MetaMask — seperti terhubung ke lebih banyak jaringan, melihat wawasan transaksi, dan mendapatkan notifikasi khusus." + "notificationsSettingsBoxError": { + "message": "Terjadi kesalahan. Coba lagi." }, - "notificationsOpenBetaSnapsTitle": { - "message": "Memperkenalkan MetaMask Snap" + "notificationsSettingsPageAllowNotifications": { + "message": "Pantau terus segala yang terjadi di dompet Anda dengan notifikasi. Untuk menggunakan notifikasi, kami menggunakan profil untuk menyinkronkan beberapa pengaturan di seluruh perangkat Anda. $1" + }, + "notificationsSettingsPageAllowNotificationsLink": { + "message": "Pelajari cara kami melindungi privasi Anda saat menggunakan fitur ini." }, "numberOfNewTokensDetectedPlural": { "message": "$1 token baru ditemukan di akun ini", @@ -2599,6 +3176,9 @@ "on": { "message": "Nyala" }, + "onboarding": { + "message": "Orientasi" + }, "onboardingAdvancedPrivacyIPFSDescription": { "message": "Gateway IPFS memungkinkan untuk mengakses dan melihat data yang disimpan oleh pihak ketiga. Anda dapat menambahkan gateway IPFS khusus atau melanjutkan menggunakan default." }, @@ -2629,51 +3209,45 @@ "onboardingMetametricsAgree": { "message": "Saya setuju" }, - "onboardingMetametricsAllowOptOut": { - "message": "Selalu izinkan Anda untuk keluar melalui Pengaturan" - }, - "onboardingMetametricsDataTerms": { - "message": "Data ini dikumpulkan sehingga bersifat anonim untuk tujuan Peraturan Perlindungan Data Umum (UE) 2016/679." - }, "onboardingMetametricsDescription": { - "message": "MetaMask ingin mengumpulkan data penggunaan untuk lebih memahami cara pengguna kami berinteraksi dengan MetaMask. Data ini akan digunakan untuk menyediakan layanan, termasuk meningkatkan layanan berdasarkan penggunaan Anda." + "message": "Kami ingin mengumpulkan data penggunaan dasar dan diagnostik untuk meningkatkan MetaMask. Pahami bahwa kami tidak pernah menjual data yang Anda berikan di sini." }, "onboardingMetametricsDescription2": { - "message": "MetaMask akan..." + "message": "Saat kami mengumpulkan metrik, maka akan selalu..." }, "onboardingMetametricsDisagree": { "message": "Tidak, terima kasih" }, "onboardingMetametricsInfuraTerms": { - "message": "* Saat Anda menggunakan Infura sebagai penyedia RPC awal di MetaMask, Infura akan mengumpulkan alamat IP dan alamat dompet Ethereum Anda saat mengirim transaksi. Kami tidak menyimpan informasi ini dengan cara yang memungkinkan sistem kami menghubungkan kedua bagian data tersebut. Untuk informasi lebih lanjut seputar cara MetaMask dan Infura berinteraksi dari perspektif pengumpulan data, lihat pembaruan $1. Untuk informasi lebih lanjut seputar praktik privasi kami secara umum, lihat $2 kami.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" + "message": "Kami akan memberitahukan keputusan untuk menggunakan data ini dengan tujuan lain. Anda dapat meninjau $1 kami untuk informasi selengkapnya. Ingat, Anda dapat membuka pengaturan dan memilih keluar setiap saat.", + "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, "onboardingMetametricsInfuraTermsPolicy": { - "message": "Kebijakan Privasi di sini" - }, - "onboardingMetametricsInfuraTermsPolicyLink": { - "message": "di sini" + "message": "Kebijakan Privasi" }, "onboardingMetametricsModalTitle": { "message": "Tambahkan jaringan khusus" }, "onboardingMetametricsNeverCollect": { - "message": "$1 mengumpulkan informasi yang tidak kami perlukan untuk menyediakan layanan (seperti kunci, alamat, hash transaksi, atau saldo)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 klik dan tampilan pada aplikasi disimpan, tetapi tidak untuk detail lainnya (seperti alamat publik).", + "description": "$1 represents `onboardingMetametricsNeverCollectEmphasis`" + }, + "onboardingMetametricsNeverCollectEmphasis": { + "message": "Pribadi:" }, "onboardingMetametricsNeverCollectIP": { - "message": "$1 mengumpulkan alamat IP lengkap Anda*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 kami menggunakan alamat IP sementara waktu untuk mendeteksi lokasi umum (seperti negara atau wilayah Anda), tetapi alamat tersebut tidak pernah disimpan.", + "description": "$1 represents `onboardingMetametricsNeverCollectIPEmphasis`" }, - "onboardingMetametricsNeverEmphasis": { - "message": "Jangan" + "onboardingMetametricsNeverCollectIPEmphasis": { + "message": "Umum:" }, "onboardingMetametricsNeverSellData": { - "message": "$1 menjual data. Jangan pernah!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 memutuskan jika Anda ingin membagikan atau menghapus data penggunaan melalui pengaturan setiap saat.", + "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" }, - "onboardingMetametricsSendAnonymize": { - "message": "Kirim klik anonim dan acara tampilan laman" + "onboardingMetametricsNeverSellDataEmphasis": { + "message": "Opsional:" }, "onboardingMetametricsTitle": { "message": "Bantu kami meningkatkan MetaMask" @@ -2714,15 +3288,26 @@ "onboardingPinExtensionTitle": { "message": "Pemasangan MetaMask Anda selesai!" }, + "onboardingPinMmiExtensionLabel": { + "message": "Sematkan MetaMask Institutional" + }, "onboardingUsePhishingDetectionDescription": { "message": "Peringatan deteksi pengelabuan bergantung pada komunikasi dengan $1. jsDeliver akan mendapat akses ke alamat IP Anda. Lihat $2.", "description": "The $1 is the word 'jsDeliver', from key 'jsDeliver' and $2 is the words Privacy Policy from key 'privacyMsg', both separated here so that it can be wrapped as a link" }, + "onekey": { + "message": "OneKey" + }, "onlyAddTrustedNetworks": { "message": "Penyedia jaringan jahat dapat berbohong tentang status blockchain dan merekam aktivitas jaringan Anda. Hanya tambahkan jaringan kustom yang Anda percayai." }, "onlyConnectTrust": { - "message": "Hanya hubungkan ke situs yang Anda percayai." + "message": "Hanya hubungkan ke situs yang Anda percayai. $1", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." + }, + "openCustodianApp": { + "message": "Buka aplikasi $1", + "description": "The $1 is the name of the Custodian that will be open" }, "openFullScreenForLedgerWebHid": { "message": "Buka layar penuh untuk menghubungkan Ledger Anda.", @@ -2734,6 +3319,15 @@ "openSeaNew": { "message": "OpenSea" }, + "openSeaToBlockaidBtnLabel": { + "message": "Jelajahi Snap" + }, + "openSeaToBlockaidDescription": { + "message": "Peringatan keamanan tidak lagi tersedia di jaringan ini. Menginstal Snap dapat meningkatkan keamanan Anda." + }, + "openSeaToBlockaidTitle": { + "message": "Perhatian!" + }, "operationFailed": { "message": "Pengoperasian Gagal" }, @@ -2777,6 +3371,9 @@ "password": { "message": "Kata sandi" }, + "passwordMmiTermsWarning": { + "message": "Saya memahami bahwa MetaMask Institutional tidak dapat memulihkan kata sandi ini untuk saya. $1" + }, "passwordNotLongEnough": { "message": "Kata sandi kurang panjang" }, @@ -2803,6 +3400,10 @@ "message": "Tempel string kunci pribadi Anda di sini:", "description": "For importing an account from a private key" }, + "paymasterInUse": { + "message": "Gas untuk transaksi ini akan dibayar oleh paymaster.", + "description": "Alert shown in transaction confirmation if paymaster in use." + }, "pending": { "message": "Menunggu" }, @@ -2816,18 +3417,26 @@ "message": "Anda memiliki (1) transaksi yang tertunda.", "description": "$1 is count of pending transactions" }, - "permissionRequest": { - "message": "Permintaan izin" + "permissionDetails": { + "message": "Detail izin" }, - "permissionRequestCapitalized": { + "permissionRequest": { "message": "Permintaan izin" }, "permissionRequested": { "message": "Diminta sekarang" }, + "permissionRequestedForAccounts": { + "message": "Diminta sekarang untuk $1", + "description": "Permission cell status for requested permission including accounts, rendered as AvatarGroup which is $1." + }, "permissionRevoked": { "message": "Dicabut dalam pembaruan ini" }, + "permissionRevokedForAccounts": { + "message": "Dicabut dalam pembaruan ini untuk $1", + "description": "Permission cell status for revoked permission including accounts, rendered as AvatarGroup which is $1." + }, "permission_accessNamedSnap": { "message": "Hubungkan ke $1.", "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." @@ -2836,6 +3445,10 @@ "message": "Akses internet.", "description": "The description of the `endowment:network-access` permission." }, + "permission_accessNetworkDescription": { + "message": "Izinkan $1 untuk mengakses internet. Ini dapat digunakan untuk mengirim dan menerima data dari server pihak ketiga.", + "description": "An extended description of the `endowment:network-access` permission. $1 is the snap name." + }, "permission_accessSnap": { "message": "Hubungkan ke Snap $1.", "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." @@ -2848,10 +3461,18 @@ "message": "Jadwalkan dan lakukan tindakan berkala.", "description": "The description for the `snap_cronjob` permission" }, + "permission_cronjobDescription": { + "message": "Izinkan $1 untuk melakukan tindakan yang diatur secara berkala pada waktu, tanggal, atau interval yang tetap. Ini dapat digunakan untuk memicu interaksi atau notifikasi yang peka terhadap waktu.", + "description": "An extended description for the `snap_cronjob` permission. $1 is the snap name." + }, "permission_dialog": { "message": "Tampilkan jendela dialog di MetaMask.", "description": "The description for the `snap_dialog` permission" }, + "permission_dialogDescription": { + "message": "Izinkan $1 untuk menampilkan sembulan MetaMask yang berisi teks khusus, kolom input, dan tombol untuk menyetujui atau menolak suatu tindakan.\nDapat digunakan untuk membuat peringatan, konfirmasi, dan alur keikutsertaan untuk Snap.", + "description": "An extended description for the `snap_dialog` permission. $1 is the snap name." + }, "permission_ethereumAccounts": { "message": "Lihat alamat, saldo akun, aktivitas, dan mulai transaksi", "description": "The description for the `eth_accounts` permission" @@ -2860,30 +3481,138 @@ "message": "Akses penyedia Ethereum.", "description": "The description for the `endowment:ethereum-provider` permission" }, + "permission_ethereumProviderDescription": { + "message": "Izinkan $1 untuk berkomunikasi dengan MetaMask secara langsung, agar dapat membaca data dari blockchain serta menyarankan pesan dan transaksi.", + "description": "An extended description for the `endowment:ethereum-provider` permission. $1 is the snap name." + }, + "permission_getEntropy": { + "message": "Dapatkan kunci arbitrer unik untuk $1.", + "description": "The description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getEntropyDescription": { + "message": "Izinkan $1 untuk mendapatkan kunci arbitrer unik untuk $1 tanpa mengeksposnya. Kunci ini terpisah dari akun MetaMask dan tidak terkait dengan kunci pribadi atau Frasa Pemulihan Rahasia. Snap lain tidak dapat mengakses informasi ini.", + "description": "An extended description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getLocale": { + "message": "Lihat bahasa pilihan Anda.", + "description": "The description for the `snap_getLocale` permission" + }, + "permission_getLocaleDescription": { + "message": "Izinkan $1 mengakses bahasa pilihan Anda dari pengaturan MetaMask. Ini dapat digunakan untuk melokalisasi dan menampilkan konten $1 menggunakan bahasa Anda.", + "description": "An extended description for the `snap_getLocale` permission. $1 is the snap name." + }, + "permission_homePage": { + "message": "Tampilkan layar khusus", + "description": "The description for the `endowment:page-home` permission" + }, + "permission_homePageDescription": { + "message": "Izinkan $1 menampilkan layar beranda khusus di MetaMask. Ini dapat digunakan untuk antarmuka pengguna, konfigurasi, dan dasbor.", + "description": "An extended description for the `endowment:page-home` permission. $1 is the snap name." + }, + "permission_keyring": { + "message": "Izinkan permintaan untuk menambah dan mengontrol akun Ethereum", + "description": "The description for the `endowment:keyring` permission" + }, + "permission_keyringDescription": { + "message": "Izinkan $1 menerima permintaan untuk menambah atau menghapus akun, serta menandatangani dan bertransaksi atas nama akun tersebut.", + "description": "An extended description for the `endowment:keyring` permission. $1 is the snap name." + }, "permission_lifecycleHooks": { "message": "Gunakan lifecycle hook.", "description": "The description for the `endowment:lifecycle-hooks` permission" }, + "permission_lifecycleHooksDescription": { + "message": "Izinkan $1 menggunakan lifecycle hook untuk menjalankan kode pada waktu tertentu selama siklus hidupnya.", + "description": "An extended description for the `endowment:lifecycle-hooks` permission. $1 is the snap name." + }, "permission_manageAccounts": { "message": "Tambah dan kontrol akun Ethereum", "description": "The description for `snap_manageAccounts` permission" }, + "permission_manageAccountsDescription": { + "message": "Izinkan $1 untuk menambah atau menghapus akun Ethereum, lalu bertransaksi dan menandatangani menggunakan akun ini.", + "description": "An extended description for the `snap_manageAccounts` permission. $1 is the snap name." + }, + "permission_manageBip32Keys": { + "message": "Kelola akun $1.", + "description": "The description for the `snap_getBip32Entropy` permission. $1 is a derivation path, e.g. 'm/44'/0'/0' (secp256k1)'." + }, + "permission_manageBip44AndBip32KeysDescription": { + "message": "Izinkan $1 untuk mengelola akun dan aset pada jaringan yang diminta. Akun-akun ini diperoleh dan dicadangkan menggunakan frasa pemulihan rahasia (tanpa mengungkapkannya). Dengan kemampuannya untuk mendapatkan kunci, $1 dapat mendukung berbagai protokol blockchain di luar Ethereum (EVM).", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions. $1 is the snap name." + }, + "permission_manageBip44Keys": { + "message": "Kelola akun $1.", + "description": "The description for the `snap_getBip44Entropy` permission. $1 is the name of a protocol, e.g. 'Filecoin'." + }, "permission_manageState": { "message": "Simpan dan kelola datanya di perangkat Anda.", "description": "The description for the `snap_manageState` permission" }, + "permission_manageStateDescription": { + "message": "Izinkan $1 untuk menyimpan, memperbarui, dan memulihkan data secara aman dengan enkripsi. Snap lain tidak dapat mengakses informasi ini.", + "description": "An extended description for the `snap_manageState` permission. $1 is the snap name." + }, + "permission_nameLookup": { + "message": "Menyediakan pencarian domain dan alamat.", + "description": "The description for the `endowment:name-lookup` permission." + }, + "permission_nameLookupDescription": { + "message": "Izinkan Snap untuk mengambil dan menampilkan pencarian alamat dan domain pada bagian UI MetaMask yang berbeda.", + "description": "An extended description for the `endowment:name-lookup` permission." + }, "permission_notifications": { "message": "Tampilkan pemberitahuan.", "description": "The description for the `snap_notify` permission" }, + "permission_notificationsDescription": { + "message": "Izinkan $1 untuk menampilkan notifikasi dalam MetaMask. Teks notifikasi singkat dapat dipicu oleh Snap untuk informasi yang dapat ditindaklanjuti atau peka terhadap waktu.", + "description": "An extended description for the `snap_notify` permission. $1 is the snap name." + }, + "permission_rpc": { + "message": "Izinkan $1 untuk terhubung secara langsung dengan $2.", + "description": "The description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescription": { + "message": "Izinkan $1 untuk mengirim pesan ke $2 dan menerima tanggapan dari $2.", + "description": "An extended description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescriptionOriginList": { + "message": "$1 dan $2", + "description": "A list of allowed origins where $2 is the last origin of the list and $1 is the rest of the list separated by ','." + }, + "permission_signatureInsight": { + "message": "Tampilkan modal wawasan tanda tangan.", + "description": "The description for the `endowment:signature-insight` permission" + }, + "permission_signatureInsightDescription": { + "message": "Izinkan $1 untuk menampilkan modal dengan wawasan seputar permintaan tanda tangan sebelum disetujui. Ini dapat digunakan sebagai solusi anti pengelabuan dan keamanan.", + "description": "An extended description for the `endowment:signature-insight` permission. $1 is the snap name." + }, + "permission_signatureInsightOrigin": { + "message": "Lihat asal situs web yang memulai permintaan tanda tangan", + "description": "The description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission" + }, + "permission_signatureInsightOriginDescription": { + "message": "Izinkan $1 untuk melihat asal (URI) situs web yang memulai permintaan tanda tangan. Ini dapat digunakan sebagai solusi anti pengelabuan dan keamanan.", + "description": "An extended description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission. $1 is the snap name." + }, "permission_transactionInsight": { "message": "Dapatkan dan tampilkan wawasan transaksi.", "description": "The description for the `endowment:transaction-insight` permission" }, + "permission_transactionInsightDescription": { + "message": "Izinkan $1 untuk membaca kode transaksi dan menampilkan wawasan dalam UI MetaMask. Ini dapat digunakan sebagai solusi anti pengelabuan dan keamanan.", + "description": "An extended description for the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_transactionInsightOrigin": { "message": "Lihat asal situs web yang mengirimkan transaksi", "description": "The description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission" }, + "permission_transactionInsightOriginDescription": { + "message": "Izinkan $1 untuk melihat asal (URI) situs web yang menyarankan transaksi. Ini dapat digunakan sebagai solusi anti pengelabuan dan keamanan.", + "description": "An extended description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_unknown": { "message": "Izin tidak dikenal: $1", "description": "$1 is the name of a requested permission that is not recognized." @@ -2892,29 +3621,66 @@ "message": "Lihat kunci publik Anda untuk $1 ($2).", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a derivation path, e.g. 'm/44'/0'/0''. $2 is the elliptic curve name, e.g. 'secp256k1'." }, + "permission_viewBip32PublicKeysDescription": { + "message": "Izinkan $2 untuk melihat kunci publik (dan alamat) untuk $1. Ini tidak memberi kendali atas akun atau aset.", + "description": "An extended description for the `snap_getBip32PublicKey` permission. $1 is a derivation path (name). $2 is the snap name." + }, "permission_viewNamedBip32PublicKeys": { "message": "Lihat kunci publik Anda untuk $1.", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a name for the derivation path, e.g., 'Ethereum accounts'." }, + "permission_walletSwitchEthereumChain": { + "message": "Beralih dan gunakan jaringan berikut", + "description": "The label for the `wallet_switchEthereumChain` permission" + }, "permission_webAssembly": { "message": "Mendukung WebAssembly.", "description": "The description of the `endowment:webassembly` permission." }, + "permission_webAssemblyDescription": { + "message": "Izinkan $1 untuk mengakses lingkungan pelaksanaan tingkat rendah melalui WebAssembly.", + "description": "An extended description of the `endowment:webassembly` permission. $1 is the snap name." + }, "permissions": { "message": "Izin" }, - "permissionsTitle": { - "message": "Izin" + "permissionsPageEmptyContent": { + "message": "Tak ada yang bisa dilihat di sini" + }, + "permissionsPageEmptySubContent": { + "message": "Di sinilah Anda dapat melihat izin yang Anda berikan untuk Snap yang terinstal atau situs yang terhubung." }, - "permissionsTourDescription": { - "message": "Temukan akun yang terhubung dan kelola izin di sini" + "permissionsPageTourDescription": { + "message": "Ini merupakan panel kontrol Anda untuk mengelola izin yang diberikan ke situs yang terhubung dan Snap yang terinstal." + }, + "permissionsPageTourTitle": { + "message": "Situs yang terhubung kini memiliki izin" }, "personalAddressDetected": { "message": "Alamat pribadi terdeteksi. Masukkan alamat kontrak token." }, + "petnamesEnabledToggle": { + "message": "Izinkan nama panggilan" + }, + "petnamesEnabledToggleDescription": { + "message": "Ini memungkinkan Anda untuk menetapkan nama panggilan ke alamat mana pun. Kami akan menyarankan nama untuk alamat tempat Anda berinteraksi, jika memungkinkan." + }, + "pinExtensionDescription": { + "message": "Navigasikan ke menu ekstensi dan sematkan MetaMask Institutional untuk akses tanpa batas." + }, + "pinExtensionTitle": { + "message": "Sematkan ekstensi" + }, + "pinToTop": { + "message": "Sematkan ke atas" + }, "pleaseConfirm": { "message": "Harap konfirmasikan" }, + "plusMore": { + "message": "+ $1 lagi", + "description": "$1 is the number of additional items" + }, "plusXMore": { "message": "+ $1 lagi", "description": "$1 is a number of additional but unshown items in a list- this message will be shown in place of those items" @@ -2940,6 +3706,9 @@ "primaryCurrencySettingDescription": { "message": "Pilih asal untuk memprioritaskan nilai yang ditampilkan dalam mata uang asal chain (contoh, ETH). Pilih Fiat untuk memprioritaskan nilai yang ditampilkan dalam mata uang fiat yang Anda pilih." }, + "primaryType": { + "message": "Tipe primer" + }, "priorityFee": { "message": "Biaya prioritas" }, @@ -2960,6 +3729,18 @@ "message": "Kunci pribadi untuk $1", "description": "$1 represents the account name" }, + "privateKeyHidden": { + "message": "Kunci pribadi disembunyikan", + "description": "Explains that the private key input is hidden" + }, + "privateKeyShow": { + "message": "Tampilkan/Sembunyikan input kunci pribadi", + "description": "Describes a toggle that is used to show or hide the private key input" + }, + "privateKeyShown": { + "message": "Kunci pribadi ini sedang ditampilkan", + "description": "Explains that the private key input is being shown" + }, "privateKeyWarning": { "message": "Peringatan: Jangan ungkapkan kunci ini. Siapa pun yang memiliki kunci pribadi Anda dapat mencuri aset yang disimpan di akun Anda." }, @@ -2969,6 +3750,21 @@ "proceedWithTransaction": { "message": "Saya tetap ingin melanjutkan" }, + "productAnnouncements": { + "message": "Pengumuman produk" + }, + "profileSync": { + "message": "Sinkronisasi Profil" + }, + "profileSyncConfirmation": { + "message": "Jika sinkronisasi profil dinonaktifkan, Anda tidak dapat menerima notifikasi." + }, + "profileSyncDescription": { + "message": "Membuat profil yang digunakan MetaMask untuk menyinkronkan beberapa pengaturan di antara perangkat Anda. Ini diperlukan untuk mendapatkan notifikasi. $1." + }, + "profileSyncPrivacyLink": { + "message": "Pelajari cara kami melindungi privasi Anda" + }, "proposedApprovalLimit": { "message": "Batas persetujuan yang diajukan" }, @@ -2978,6 +3774,78 @@ "publicAddress": { "message": "Alamat publik" }, + "pushPlatformNotificationsFundsReceivedDescription": { + "message": "Anda menerima $1 $2" + }, + "pushPlatformNotificationsFundsReceivedDescriptionDefault": { + "message": "Anda menerima beberapa token" + }, + "pushPlatformNotificationsFundsReceivedTitle": { + "message": "Dana diterima" + }, + "pushPlatformNotificationsFundsSentDescription": { + "message": "Anda berhasil mengirimkan $1 $2" + }, + "pushPlatformNotificationsFundsSentDescriptionDefault": { + "message": "Anda berhasil mengirimkan beberapa token" + }, + "pushPlatformNotificationsFundsSentTitle": { + "message": "Dana terkirim" + }, + "pushPlatformNotificationsNftReceivedDescription": { + "message": "Anda menerima NFT baru" + }, + "pushPlatformNotificationsNftReceivedTitle": { + "message": "NFT diterima" + }, + "pushPlatformNotificationsNftSentDescription": { + "message": "Anda berhasil mengirimkan NFT" + }, + "pushPlatformNotificationsNftSentTitle": { + "message": "NFT terkirim" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedDescription": { + "message": "Stake Lido berhasil" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedTitle": { + "message": "Stake selesai" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnDescription": { + "message": "Stake Lido kini siap untuk ditarik" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnTitle": { + "message": "Stake siap untuk penarikan" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedDescription": { + "message": "Penarikan Lido berhasil" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedTitle": { + "message": "Penarikan selesai" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedDescription": { + "message": "Permintaan penarikan Lido telah dikirim" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedTitle": { + "message": "Penarikan diminta" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedDescription": { + "message": "Stake RocketPool berhasil" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedTitle": { + "message": "Stake selesai" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedDescription": { + "message": "Pembatalan stake RocketPool berhasil" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedTitle": { + "message": "Pembatalan stake selesai" + }, + "pushPlatformNotificationsSwapCompletedDescription": { + "message": "Swap MetaMask berhasil" + }, + "pushPlatformNotificationsSwapCompletedTitle": { + "message": "Swap selesai" + }, "queued": { "message": "Antrean" }, @@ -2996,9 +3864,15 @@ "receive": { "message": "Terima" }, + "receiveTokensCamelCase": { + "message": "Terima token" + }, "recipientAddressPlaceholder": { "message": "Masukkan alamat publik (0x) atau nama ENS" }, + "recipientAddressPlaceholderFlask": { + "message": "Masukkan alamat publik (0x) atau nama domain" + }, "recommendedGasLabel": { "message": "Direkomendasikan" }, @@ -3026,6 +3900,12 @@ "recoveryPhraseReminderTitle": { "message": "Lindungi dana Anda" }, + "redesignedConfirmationsEnabledToggle": { + "message": "Penyempurnaan permintaan tanda tangan" + }, + "redesignedConfirmationsToggleDescription": { + "message": "Aktifkan ini untuk melihat permintaan tanda tangan dalam format yang disempurnakan." + }, "refreshList": { "message": "Segarkan daftar" }, @@ -3068,15 +3948,30 @@ "removeJWTDescription": { "message": "Yakin ingin menghapus token ini? Semua akun yang ditetapkan ke token ini juga akan dihapus dari ekstensi:" }, + "removeKeyringSnap": { + "message": "Akun berikut akan dihapus dari MetaMask saat menghapus Snap ini:" + }, + "removeKeyringSnapToolTip": { + "message": "Snap mengontrol akun. Jika dihapus, maka akun tersebut akan dihapus juga dari MetaMask, tetapi akun tersebut akan tetap berada di blockchain." + }, "removeNFT": { "message": "Hapus NFT" }, + "removeNftErrorMessage": { + "message": "Kami tidak dapat menghapus NFT ini." + }, "removeNftMessage": { "message": "NFT berhasil dihapus!" }, "removeSnap": { "message": "Hapus Snap" }, + "removeSnapAccountDescription": { + "message": "Jika Anda melanjutkan, akun ini tidak lagi tersedia di MetaMask." + }, + "removeSnapAccountTitle": { + "message": "Hapus akun" + }, "removeSnapConfirmation": { "message": "Yakin ingin menghapus $1?", "description": "$1 represents the name of the snap" @@ -3087,12 +3982,24 @@ "replace": { "message": "mengganti" }, + "reportIssue": { + "message": "Laporkan masalah" + }, "requestFlaggedAsMaliciousFallbackCopyReason": { "message": "Penyedia keamanan belum membagikan detail tambahan" }, "requestFlaggedAsMaliciousFallbackCopyReasonTitle": { "message": "Permintaan ditandai sebagai berbahaya" }, + "requestFrom": { + "message": "Permintaan dari" + }, + "requestFromInfo": { + "message": "Ini merupakan situs yang meminta tanda tangan Anda." + }, + "requestFromTransactionDescription": { + "message": "Ini merupakan situs yang meminta konfirmasi Anda." + }, "requestMayNotBeSafe": { "message": "Permintaan mungkin tidak aman" }, @@ -3114,6 +4021,9 @@ "reset": { "message": "Atur ulang" }, + "resetStates": { + "message": "Reset State" + }, "resetWallet": { "message": "Reset dompet" }, @@ -3142,7 +4052,7 @@ "message": "Pulihkan data pengguna" }, "restoreUserDataDescription": { - "message": "Anda dapat memulihkan pengaturan pengguna yang berisi preferensi dan alamat akun dari file JSON yang dicadangkan sebelumnya." + "message": "Anda dapat memulihkan data seperti kontak dan preferensi dari file cadangan." }, "resultPageError": { "message": "Kesalahan" @@ -3196,9 +4106,15 @@ "message": "Dukungan MetaMask tidak akan pernah memintanya.", "description": "The bolded texted in the second part of 'revealSeedWordsWarning'" }, + "revealSensitiveContent": { + "message": "Tampilkan konten sensitif" + }, "revealTheSeedPhrase": { "message": "Ungkap frasa seed" }, + "reviewAlerts": { + "message": "Tinjau peringatan" + }, "revokeAllTokensTitle": { "message": "Cabut izin untuk mengakses dan mentransfer seluruh $1 Anda?", "description": "$1 is the symbol of the token for which the user is revoking approval" @@ -3249,6 +4165,9 @@ "searchAccounts": { "message": "Cari akun" }, + "searchTokens": { + "message": "Cari token" + }, "secretRecoveryPhrase": { "message": "Frasa Pemulihan Rahasia" }, @@ -3265,7 +4184,8 @@ "message": "Peringatan keamanan" }, "securityAlertsDescription": { - "message": "Fitur ini memperingatkan Anda tentang aktivitas berbahaya di Mainnet Ethereum dengan secara aktif meninjau permintaan transaksi dan tanda tangan sambil menjaga privasi. Data Anda tidak dibagikan dengan pihak ketiga yang menyediakan layanan ini. Selalu lakukan uji tuntas sendiri sebelum menyetujui permintaan apa pun. Tidak ada jaminan bahwa fitur ini akan mendeteksi semua aktivitas berbahaya." + "message": "Fitur ini memperingatkan Anda tentang aktivitas jahat dengan meninjau permintaan transaksi dan tanda tangan secara aktif. $1", + "description": "Link to learn more about security alerts" }, "securityAndPrivacy": { "message": "Keamanan & privasi" @@ -3355,6 +4275,9 @@ "selectAnAccountHelp": { "message": "Pilih akun kustodian untuk digunakan di MetaMask Institutional." }, + "selectEnableDisplayMediaPrivacyPreference": { + "message": "Aktifkan Tampilkan Media NFT" + }, "selectHdPath": { "message": "Pilih path HD" }, @@ -3376,18 +4299,41 @@ "send": { "message": "Kirim" }, + "sendAToken": { + "message": "Kirimkan token" + }, "sendBugReport": { "message": "Kirimi kami laporan bug." }, + "sendNoContactsConversionText": { + "message": "klik di sini" + }, + "sendNoContactsDescription": { + "message": "Kontak memungkinkan Anda untuk mengirim transaksi dengan aman ke akun lain beberapa kali. Untuk membuat kontak, $1", + "description": "$1 represents the action text 'click here'" + }, + "sendNoContactsTitle": { + "message": "Anda belum memiliki kontak" + }, + "sendSelectReceiveAsset": { + "message": "Pilih aset yang akan diterima" + }, + "sendSelectSendAsset": { + "message": "Pilih aset yang akan dikirim" + }, "sendSpecifiedTokens": { "message": "Kirim $1", "description": "Symbol of the specified token" }, - "sendTo": { - "message": "Kirim ke" + "sendSwapSubmissionWarning": { + "message": "Mengklik tombol ini akan langsung memulai transaksi swap. Tinjau detail transaksi sebelum melanjutkan." + }, + "sendTokenAsToken": { + "message": "Kirim $1 sebagai $2", + "description": "Used in the transaction display list to describe a swap and send. $1 and $2 are the symbols of tokens in involved in the swap." }, - "sendTokens": { - "message": "Kirim token" + "sendingAsset": { + "message": "Mengirim $1" }, "sendingDisabled": { "message": "Belum mendukung pengiriman aset NFT ERC-1155." @@ -3400,9 +4346,15 @@ "message": "Peringatan: Anda akan mengirim kontrak token yang berpotensi mengakibatkan hilangnya dana. $1", "description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning" }, + "sendingZeroAmount": { + "message": "Anda sedang mengirim 0 $1." + }, "sepolia": { "message": "Jaringan uji Sepolia" }, + "serviceWorkerKeepAlive": { + "message": "Service Worker Tetap Menyala" + }, "setAdvancedPrivacySettingsDetails": { "message": "MetaMask menggunakan layanan pihak ketiga tepercaya ini untuk meningkatkan kegunaan dan keamanan produk." }, @@ -3414,7 +4366,7 @@ "description": "The token symbol that is being approved" }, "settingAddSnapAccount": { - "message": "Tambahkan akun snap" + "message": "Tambahkan akun Snap" }, "settings": { "message": "Pengaturan" @@ -3422,9 +4374,21 @@ "settingsSearchMatchingNotFound": { "message": "Tidak menemukan hasil yang cocok." }, + "settingsSubHeadingSignaturesAndTransactions": { + "message": "Permintaan tanda tangan dan transaksi" + }, "show": { "message": "Tampil" }, + "showAccount": { + "message": "Tampilkan akun" + }, + "showExtensionInFullSizeView": { + "message": "Tampilkan ekstensi dalam tampilan berukuran penuh" + }, + "showExtensionInFullSizeViewDescription": { + "message": "Aktifkan ini untuk membuat tampilan berukuran penuh sebagai default saat mengklik ikon ekstensi." + }, "showFiatConversionInTestnets": { "message": "Tampilkan konversi di jaringan uji" }, @@ -3444,6 +4408,9 @@ "message": "Pilih ini untuk menggunakan Etherscan untuk menampilkan transaksi yang masuk di daftar transaksi", "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" }, + "showIncomingTransactionsExplainer": { + "message": "Ini bergantung pada API pihak ketiga yang berbeda untuk setiap jaringan, yang mengungkap alamat Ethereum dan alamat IP Anda." + }, "showMore": { "message": "Tampilkan selengkapnya" }, @@ -3483,9 +4450,46 @@ "signin": { "message": "Masuk" }, + "signing": { + "message": "Penandatanganan" + }, + "simulationDetailsFailed": { + "message": "Terjadi kesalahan saat memuat estimasi Anda." + }, + "simulationDetailsFiatNotAvailable": { + "message": "Tidak Tersedia" + }, + "simulationDetailsIncomingHeading": { + "message": "Anda menerima" + }, + "simulationDetailsNoBalanceChanges": { + "message": "Tidak ada perubahan yang terprediksi untuk dompet Anda" + }, + "simulationDetailsOutgoingHeading": { + "message": "Anda mengirim" + }, + "simulationDetailsTitle": { + "message": "Estimasi perubahan" + }, + "simulationDetailsTitleTooltip": { + "message": "Estimasi perubahan merupakan hal yang mungkin terjadi jika Anda melakukan transaksi ini. Ini hanyalah prediksi, bukan jaminan." + }, + "simulationDetailsTotalFiat": { + "message": "Total = $1", + "description": "$1 is the total amount in fiat currency on one side of the transaction" + }, + "simulationDetailsTransactionReverted": { + "message": "Transaksi ini kemungkinan besar akan gagal" + }, "simulationErrorMessageV2": { "message": "Kami tidak dapat memperkirakan gas. Tampaknya ada kesalahan dalam kontrak dan transaksi ini berpotensi gagal." }, + "simulationsSettingDescription": { + "message": "Aktifkan untuk mengestimasikan perubahan saldo transaksi sebelum Anda mengonfirmasikannya. Ini tidak menjamin hasil akhir transaksi Anda. $1" + }, + "simulationsSettingSubHeader": { + "message": "Estimasikan perubahan saldo" + }, "skip": { "message": "Lewati" }, @@ -3498,20 +4502,99 @@ "smartContracts": { "message": "Kontrak cerdas" }, - "smartSwapsAreHere": { - "message": "Smart Swap telah hadir!" - }, - "smartSwapsDescription": { - "message": "MetaMask Swaps kini semakin pintar! Mengaktifkan Smart Swap akan mengizinkan MetaMask mengoptimalkan Swap secara terprogram untuk membantu:" - }, "smartSwapsErrorNotEnoughFunds": { "message": "Dana tidak cukup untuk pertukaran cerdas." }, "smartSwapsErrorUnavailable": { "message": "Smart Swap tidak tersedia untuk sementara waktu." }, + "smartTransactionCancelled": { + "message": "Transaksi Anda dibatalkan" + }, + "smartTransactionCancelledDescription": { + "message": "Transaksi Anda tidak dapat diselesaikan, sehingga dibatalkan agar Anda tidak perlu membayar biaya gas yang tidak seharusnya." + }, + "smartTransactionError": { + "message": "Transaksi Anda gagal" + }, + "smartTransactionErrorDescription": { + "message": "Perubahan pasar yang mendadak dapat menyebabkan kegagalan. Jika masalah berlanjut, hubungi dukungan pelanggan MetaMask." + }, + "smartTransactionPending": { + "message": "Mengirimkan transaksi Anda" + }, + "smartTransactionSuccess": { + "message": "Transaksi Anda selesai" + }, + "smartTransactionTakingTooLong": { + "message": "Maaf telah menunggu" + }, + "smartTransactionTakingTooLongDescription": { + "message": "Jika transaksi tidak diselesaikan dalam $1, transaksi akan dibatalkan dan Anda tidak akan dikenakan biaya gas.", + "description": "$1 is remaining time in seconds" + }, + "smartTransactions": { + "message": "Transaksi Pintar" + }, + "smartTransactionsBenefit1": { + "message": "Tingkat keberhasilan 99,5%" + }, + "smartTransactionsBenefit2": { + "message": "Menghemat uang Anda" + }, + "smartTransactionsBenefit3": { + "message": "Pembaruan waktu nyata" + }, + "smartTransactionsDescription": { + "message": "Raih tingkat keberhasilan yang lebih tinggi, perlindungan frontrunning, dan visibilitas yang lebih baik dengan Transaksi Pintar." + }, + "smartTransactionsDescription2": { + "message": "Hanya tersedia di Ethereum. Aktifkan atau nonaktifkan kapan saja di pengaturan. $1", + "description": "$1 is an external link to learn more about Smart Transactions" + }, + "smartTransactionsOptItModalTitle": { + "message": "Peningkatan Perlindungan Transaksi" + }, + "snapAccountCreated": { + "message": "Akun dibuat" + }, + "snapAccountCreatedDescription": { + "message": "Akun baru Anda siap digunakan!" + }, + "snapAccountCreationFailed": { + "message": "Pembuatan akun gagal" + }, + "snapAccountCreationFailedDescription": { + "message": "$1 tidak berhasil membuat akun untuk Anda.", + "description": "$1 is the snap name" + }, + "snapAccountRedirectFinishSigningTitle": { + "message": "Selesaikan penandatanganan" + }, + "snapAccountRedirectSiteDescription": { + "message": "Ikuti petunjuk dari $1" + }, + "snapAccountRemovalFailed": { + "message": "Penghapusan akun gagal" + }, + "snapAccountRemovalFailedDescription": { + "message": "$1 tidak berhasil menghapus akun ini untuk Anda.", + "description": "$1 is the snap name" + }, + "snapAccountRemoved": { + "message": "Akun dihapus" + }, + "snapAccountRemovedDescription": { + "message": "Akun ini tidak lagi tersedia untuk digunakan di MetaMask." + }, + "snapAccounts": { + "message": "Akun Snap" + }, + "snapAccountsDescription": { + "message": "Akun yang dikontrol oleh Snap pihak ketiga." + }, "snapConnectionWarning": { - "message": "$1 ingin terhubung ke $2. Lanjutkan hanya jika Anda memercayai situs web ini.", + "message": "$1 ingin menggunakan $2", "description": "$2 is the snap and $1 is the dapp requesting connection to the snap." }, "snapContent": { @@ -3522,15 +4605,35 @@ "message": "Situs web" }, "snapInstallRequest": { - "message": "Menginstal $1 memberinya izin berikut. Lanjutkan hanya jika Anda memercayai $1.", + "message": "Anda memberikan izin berikut dengan menginstal $1.", "description": "$1 is the snap name." }, "snapInstallSuccess": { "message": "Instalasi selesai" }, + "snapInstallWarningCheck": { + "message": "$1 meminta izin untuk melakukan hal berikut:", + "description": "Warning message used in popup displayed on snap install. $1 is the snap name." + }, "snapInstallWarningHeading": { "message": "Lanjutkan dengan hati-hati" }, + "snapInstallWarningPermissionDescriptionForBip32View": { + "message": "Izinkan $1 untuk melihat kunci publik (dan alamat). Ini tidak memberi kendali atas akun atau aset.", + "description": "An extended description for the `snap_getBip32PublicKey` permission used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionDescriptionForEntropy": { + "message": "Izinkan Snap $1 untuk mengelola akun dan aset pada jaringan yang diminta. Akun-akun ini diperoleh dan dicadangkan menggunakan frasa pemulihan rahasia (tanpa mengungkapkannya). Dengan kemampuannya untuk mendapatkan kunci, $1 dapat mendukung berbagai protokol blockchain di luar Ethereum (EVM).", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionNameForEntropy": { + "message": "Kelola akun $1", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, + "snapInstallWarningPermissionNameForViewPublicKey": { + "message": "Lihat kunci publik untuk $1", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, "snapInstallationErrorDescription": { "message": "$1 tidak dapat diinstal.", "description": "Error description used when snap installation fails. $1 is the snap name." @@ -3548,6 +4651,10 @@ "snapResultSuccessDescription": { "message": "$1 siap digunakan" }, + "snapUpdateAlertDescription": { + "message": "Dapatkan versi terbaru $1", + "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." + }, "snapUpdateAvailable": { "message": "Pembaruan tersedia" }, @@ -3559,22 +4666,40 @@ "message": "Pembaruan gagal", "description": "Error title used when snap update fails." }, + "snapUpdateRequest": { + "message": "Anda memberikan izin berikut dengan memperbarui $1.", + "description": "$1 is the Snap name." + }, "snapUpdateSuccess": { "message": "Pembaruan selesai" }, + "snapUrlIsBlocked": { + "message": "Snap ini ingin mengarahkan Anda ke situs yang diblokir. $1." + }, "snaps": { "message": "Snap" }, - "snapsInvalidUIError": { - "message": "UI yang ditentukan oleh snap tidak valid." + "snapsConnected": { + "message": "Snap terhubung" }, "snapsNoInsight": { "message": "Snap tidak mengembalikan wawasan apa pun" }, + "snapsPrivacyWarningFirstMessage": { + "message": "Anda menyatakan bahwa Snap yang diinstal adalah Layanan Pihak Ketiga, kecuali jika diidentifikasi lain, sebagaimana dijelaskan dalam $1 Consensys. Penggunaan Layanan Pihak Ketiga diatur oleh syarat dan ketentuan terpisah yang ditetapkan oleh penyedia Layanan Pihak Ketiga. Consensys tidak merekomendasikan penggunaan Snap oleh orang tertentu karena alasan tertentu. Anda mengakses, mengandalkan, atau menggunakan Layanan Pihak Ketiga dengan risiko sendiri. Consensys menafikan semua tanggung jawab dan kewajiban atas kerugian yang timbul karena penggunaan Layanan Pihak Ketiga.", + "description": "First part of a message in popup modal displayed when installing a snap for the first time. $1 is terms of use link." + }, "snapsPrivacyWarningSecondMessage": { "message": "Setiap informasi yang Anda bagikan kepada Layanan Pihak Ketiga akan dikumpulkan langsung oleh Layanan Pihak Ketiga tersebut sesuai dengan kebijakan privasinya. Baca kebijakan privasinya untuk informasi lebih lanjut.", "description": "Second part of a message in popup modal displayed when installing a snap for the first time." }, + "snapsPrivacyWarningThirdMessage": { + "message": "Consensys tidak memiliki akses ke informasi yang Anda bagikan kepada Layanan Pihak Ketiga.", + "description": "Third part of a message in popup modal displayed when installing a snap for the first time." + }, + "snapsSettings": { + "message": "Pengaturan Snap" + }, "snapsTermsOfUse": { "message": "Ketentuan Penggunaan" }, @@ -3588,12 +4713,19 @@ "someNetworksMayPoseSecurity": { "message": "Beberapa jaringan dapat menimbulkan risiko keamanan dan/atau privasi. Pahami risikonya sebelum menambahkan dan menggunakan jaringan." }, + "somethingDoesntLookRight": { + "message": "Ada yang tidak beres? $1", + "description": "A false positive message for users to contact support. $1 is a link to the support page." + }, "somethingIsWrong": { "message": "Terjadi kesalahan. Coba muat ulang halaman." }, "somethingWentWrong": { "message": "Ups! Terjadi kesalahan." }, + "source": { + "message": "Sumber" + }, "speedUp": { "message": "Percepat" }, @@ -3728,6 +4860,14 @@ "stake": { "message": "Stake" }, + "startYourJourney": { + "message": "Mulailah perjalanan Anda dengan $1", + "description": "$1 is the token symbol" + }, + "startYourJourneyDescription": { + "message": "Mulailah dengan web3 dengan menambahkan sejumlah $1 ke dompet Anda.", + "description": "$1 is the token symbol" + }, "stateLogError": { "message": "Terjadi kesalahan pada log status pengambilan." }, @@ -3740,6 +4880,9 @@ "stateLogsDescription": { "message": "Log status berisi alamat akun publik Anda dan transaksi terkirim." }, + "states": { + "message": "State" + }, "status": { "message": "Status" }, @@ -3783,18 +4926,6 @@ "strong": { "message": "Kuat" }, - "stxBenefit1": { - "message": "Meminimalkan biaya transaksi" - }, - "stxBenefit2": { - "message": "Kurangi potensi kegagalan transaksi \t" - }, - "stxBenefit3": { - "message": "Hapus transaksi yang macet" - }, - "stxBenefit4": { - "message": "Cegah perilaku front running \t" - }, "stxCancelled": { "message": "Pertukaran akan gagal" }, @@ -3804,6 +4935,10 @@ "stxCancelledSubDescription": { "message": "Cobalah untuk menukar lagi. Kami akan selalu hadir untuk melindungi Anda dari risiko serupa di lain waktu." }, + "stxEstimatedCompletion": { + "message": "Estimasi penyelesaian dalam < $1", + "description": "$1 is remeaning time in minutes and seconds, e.g. 0:10" + }, "stxFailure": { "message": "Pertukaran gagal" }, @@ -3811,6 +4946,9 @@ "message": "Perubahan pasar yang terjadi secara tiba-tiba dapat menyebabkan kegagalan. Jika masalah berlanjut, hubungi $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInDescription": { + "message": "Aktifkan Transaksi Pintar untuk transaksi yang lebih andal dan aman di Mainnet Ethereum. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Kirimkan Swap Anda secara pribadi..." }, @@ -3849,12 +4987,21 @@ "submitted": { "message": "Terkirim" }, + "suggestedTokenSymbol": { + "message": "Simbol ticker yang disarankan:" + }, "support": { "message": "Dukungan" }, "supportCenter": { "message": "Kunjungi pusat dukungan kami" }, + "surveyConversion": { + "message": "Ikuti survei kami" + }, + "surveyTitle": { + "message": "Bentuk masa depan MetaMask" + }, "swap": { "message": "Pertukaran" }, @@ -3874,6 +5021,9 @@ "swapAmountReceivedInfo": { "message": "Ini merupakan jumlah minimum yang akan Anda terima. Anda bisa mendapatkan lebih banyak lagi tergantung pada selip." }, + "swapAndSend": { + "message": "Tukar & Kirim" + }, "swapAnyway": { "message": "Tetap tukar" }, @@ -3989,6 +5139,10 @@ "message": "Termasuk $1% biaya MetaMask.", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." }, + "swapIncludesMMFeeAlt": { + "message": "Kuotasi mencerminkan biaya MetaMask sebesar $1%", + "description": "Provides information about the fee that metamask takes for swaps using the latest copy. $1 is a decimal number." + }, "swapIncludesMetaMaskFeeViewAllQuotes": { "message": "Termasuk $1% biaya MetaMask – $2", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number and $2 is a link to view all quotes." @@ -3996,6 +5150,9 @@ "swapLearnMore": { "message": "Pelajari selengkapnya seputar Swap" }, + "swapLiquiditySourceInfo": { + "message": "Kami mencari beberapa sumber likuiditas (bursa, agregator, dan pendiri pasar profesional) untuk membandingkan tarif bursa dan biaya jaringan." + }, "swapLowSlippage": { "message": "Selip rendah" }, @@ -4268,6 +5425,9 @@ "switchEthereumChainConfirmationTitle": { "message": "Izinkan situs ini untuk beralih jaringan?" }, + "switchInputCurrency": { + "message": "Ganti mata uang input" + }, "switchNetwork": { "message": "Beralih jaringan" }, @@ -4281,14 +5441,15 @@ "switchToThisAccount": { "message": "Beralih ke akun ini" }, - "switchedTo": { - "message": "Anda telah beralih ke" + "switchedNetworkToastDecline": { + "message": "Jangan tampilkan lagi" }, - "switcherTitle": { - "message": "Pengalih jaringan" + "switchedNetworkToastMessage": { + "message": "$1 kini telah aktif di $2", + "description": "$1 represents the account name, $2 represents the network name" }, - "switcherTourDescription": { - "message": "Klik ikon untuk beralih jaringan atau menambahkan jaringan baru" + "switchedTo": { + "message": "Anda telah beralih ke" }, "switchingNetworksCancelsPendingConfirmations": { "message": "Mengalihkan jaringan akan membatalkan semua konfirmasi yang berstatus menunggu" @@ -4388,6 +5549,18 @@ "toggleEthSignOn": { "message": "AKTIF (Tidak disarankan)" }, + "toggleRequestQueueDescription": { + "message": "Hal ini memungkinkan Anda memilih jaringan untuk setiap situs, daripada satu jaringan yang dipilih untuk semua situs. Fitur ini akan mencegah Anda berpindah jaringan secara manual, yang dapat merusak pengalaman pengguna di situs tertentu." + }, + "toggleRequestQueueField": { + "message": "Pilih jaringan untuk setiap situs" + }, + "toggleRequestQueueOff": { + "message": "Nonaktif" + }, + "toggleRequestQueueOn": { + "message": "Aktif" + }, "token": { "message": "Token" }, @@ -4404,7 +5577,7 @@ "message": "Alamat kontrak token" }, "tokenDecimalFetchFailed": { - "message": "Desimal token diperlukan." + "message": "Desimal token diperlukan. Temukan di: $1" }, "tokenDecimalTitle": { "message": "Desimal token:" @@ -4443,6 +5616,9 @@ "tooltipSatusConnected": { "message": "terhubung" }, + "tooltipSatusConnectedUpperCase": { + "message": "Terhubung" + }, "tooltipSatusNotConnected": { "message": "tidak terhubung" }, @@ -4583,6 +5759,39 @@ "tryAgain": { "message": "Coba lagi" }, + "turnOff": { + "message": "Nonaktifkan" + }, + "turnOffMetamaskNotificationsError": { + "message": "Terjadi kesalahan saat menonaktifkan notifikasi. Coba lagi nanti." + }, + "turnOn": { + "message": "Aktifkan" + }, + "turnOnMetamaskNotifications": { + "message": "Aktifkan notifikasi" + }, + "turnOnMetamaskNotificationsButton": { + "message": "Aktifkan" + }, + "turnOnMetamaskNotificationsError": { + "message": "Terjadi kesalahan saat membuat notifikasi. Coba lagi nanti." + }, + "turnOnMetamaskNotificationsMessageFirst": { + "message": "Pantau terus segala yang terjadi di dompet Anda dengan notifikasi." + }, + "turnOnMetamaskNotificationsMessagePrivacyBold": { + "message": "Pengaturan > Notifikasi." + }, + "turnOnMetamaskNotificationsMessagePrivacyLink": { + "message": "Pelajari cara kami melindungi privasi Anda saat menggunakan fitur ini." + }, + "turnOnMetamaskNotificationsMessageSecond": { + "message": "Untuk menggunakan notifikasi dompet, kami menggunakan profil untuk menyinkronkan beberapa pengaturan di seluruh perangkat Anda. $1" + }, + "turnOnMetamaskNotificationsMessageThird": { + "message": "Notifikasi dapat dinonaktifkan setiap saat di $1" + }, "turnOnTokenDetection": { "message": "Aktifkan deteksi token yang ditingkatkan" }, @@ -4614,6 +5823,10 @@ "unknownNetwork": { "message": "Jaringan pribadi tidak dikenal" }, + "unknownNetworkForKeyEntropy": { + "message": "Jaringan tidak dikenal", + "description": "Displayed on places like Snap install warning when regular name is not available." + }, "unknownQrCode": { "message": "Kesalahan: Kami tidak dapat mengidentifikasi kode QR itu" }, @@ -4626,6 +5839,9 @@ "unlockMessage": { "message": "Web terdesentralisasi menunggu" }, + "unpin": { + "message": "Batal semat" + }, "unrecognizedChain": { "message": "Jaringan kustom ini tidak dikenali", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." @@ -4643,6 +5859,9 @@ "update": { "message": "Perbarui" }, + "updateRequest": { + "message": "Permintaan pembaruan" + }, "updatedWithDate": { "message": "Diperbarui $1" }, @@ -4667,12 +5886,25 @@ "useNftDetection": { "message": "Deteksi otomatis NFT" }, + "useNftDetectionDescriptionText": { + "message": "Izinkan MetaMask menambahkan NFT yang Anda miliki menggunakan layanan pihak ketiga (seperti OpenSea). Autodeteksi NFT mengekspos alamat IP dan akun Anda ke layanan ini. Mengaktifkan fitur ini dapat mengaitkan alamat IP dengan alamat Ethereum Anda dan menampilkan NFT palsu yang di-airdrop oleh penipu. Anda dapat menambahkan token secara manual untuk menghindari risiko ini." + }, "usePhishingDetection": { "message": "Gunakan deteksi phishing" }, "usePhishingDetectionDescription": { "message": "Menampilkan peringatan untuk domain phishing yang menargetkan pengguna Ethereum" }, + "useSafeChainsListValidation": { + "message": "Pemeriksaan detail jaringan" + }, + "useSafeChainsListValidationDescription": { + "message": "MetaMask menggunakan layanan pihak ketiga yang disebut $1 untuk menampilkan detail jaringan yang akurat dan terstandardisasi. Hal ini dapat mengurangi kemungkinan Anda untuk terhubung ke jaringan berbahaya atau salah. Saat menggunakan fitur ini, alamat IP akan diketahui oleh chainid.network." + }, + "useSafeChainsListValidationWebsite": { + "message": "chainid.network", + "description": "useSafeChainsListValidationWebsite is separated from the rest of the text so that we can bold the third party service name in the middle of them" + }, "useSiteSuggestion": { "message": "Gunakan saran situs" }, @@ -4685,6 +5917,9 @@ "userName": { "message": "Nama pengguna" }, + "userOpContractDeployError": { + "message": "Penerapan kontrak dari akun kontrak cerdas tidak didukung" + }, "verifyContractDetails": { "message": "Verifikasikan detail pihak ketiga" }, @@ -4702,6 +5937,9 @@ "view": { "message": "Lihat" }, + "viewActivity": { + "message": "Lihat aktivitas" + }, "viewAllDetails": { "message": "Lihat semua detail" }, @@ -4725,7 +5963,7 @@ }, "viewOnCustomBlockExplorer": { "message": "Lihat $1 di $2", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "Lihat $1 di Etherscan", @@ -4737,6 +5975,9 @@ "viewOnOpensea": { "message": "Lihat di Opensea" }, + "viewTransaction": { + "message": "Lihat transaksi" + }, "viewinCustodianApp": { "message": "Lihat di aplikasi kustodian" }, @@ -4744,6 +5985,9 @@ "message": "Lihat $1 di explorer", "description": "$1 is the action type. e.g (Account, Transaction, Swap)" }, + "visitSite": { + "message": "Kunjungi situs" + }, "visitWebSite": { "message": "Kunjungi situs web kami" }, @@ -4782,6 +6026,10 @@ "warning": { "message": "Peringatan" }, + "warningFromSnap": { + "message": "Peringatan dari $1", + "description": "$1 represents the name of the snap" + }, "warningTooltipText": { "message": "$1 Pihak ketiga dapat mempergunakan seluruh saldo token Anda tanpa pemberitahuan atau persetujuan lebih lanjut. Lindungi diri Anda dengan menyesuaikan batas penggunaan yang lebih rendah.", "description": "$1 is a warning icon with text 'Be careful' in 'warning' colour" @@ -4789,6 +6037,9 @@ "weak": { "message": "Lemah" }, + "web3": { + "message": "Web3" + }, "web3ShimUsageNotification": { "message": "Kami melihat situs web saat ini mencoba menggunakan API window.web3 yang dihapus. Jika situs tersebut tampak bermasalah, klik $1 untuk informasi selengkapnya.", "description": "$1 is a clickable link." @@ -4829,10 +6080,6 @@ "whatsThis": { "message": "Apa ini?" }, - "xOfY": { - "message": "$1 dari $2", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$1 dari $2 berstatus menunggu", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" @@ -4840,6 +6087,9 @@ "yes": { "message": "Ya" }, + "you": { + "message": "Anda" + }, "youHaveAddedAll": { "message": "Anda telah menambahkan semua jaringan populer. Anda dapat menemukan lebih banyak jaringan $1 atau dapat $2", "description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'" @@ -4862,6 +6112,12 @@ "yourPrivateSeedPhrase": { "message": "Frasa Pemulihan Rahasia pribadi Anda" }, + "yourTransactionConfirmed": { + "message": "Transaksi telah dikonfirmasi" + }, + "yourTransactionJustConfirmed": { + "message": "Kami tidak dapat membatalkan transaksi Anda sebelum dikonfirmasi di blockchain." + }, "zeroGasPriceOnSpeedUpError": { "message": "Biaya gas nol pada percepatan" } diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index e56fbdab8df1..6a43d90d1624 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -241,16 +241,10 @@ "message": "Tutti i tuoi $1", "description": "$1 is the symbol or name of the token that the user is approving spending" }, - "allowExternalExtensionTo": { - "message": "Permetti a questa estensione di:" - }, "allowSpendToken": { "message": "Dai il permesso di spendere tuoi $1?", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "Permetti a questo sito di:" - }, "allowWithdrawAndSpend": { "message": "Consenti a $1 di ritirare e spendere fino a questo importo:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -390,9 +384,6 @@ "cancel": { "message": "Annulla" }, - "cancelEdit": { - "message": "Annulla modifica" - }, "cancelPopoverTitle": { "message": "Annulla transazione" }, @@ -456,26 +447,6 @@ "connectManually": { "message": "Connettiti al sito manualmente" }, - "connectTo": { - "message": "Connettiti a $1", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "Connettiti a tutti i tuoi $1", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "account", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "Connettiti a $1", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1 account", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "Connetti con MetaMask" }, @@ -1195,7 +1166,8 @@ "message": "Una rete malevola può mentire sullo stato della blockchain e registrare le tue azioni. Aggiungi solo reti fidate." }, "onlyConnectTrust": { - "message": "Connettiti solo con siti di cui ti fidi." + "message": "Connettiti solo con siti di cui ti fidi.", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." }, "origin": { "message": "Origine" @@ -1377,9 +1349,6 @@ "message": "Invia $1", "description": "Symbol of the specified token" }, - "sendTokens": { - "message": "Invia Tokens" - }, "settings": { "message": "Impostazioni" }, @@ -1825,10 +1794,6 @@ "whatsThis": { "message": "Cos'è?" }, - "xOfY": { - "message": "$1 di $2", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "youNeedToAllowCameraAccess": { "message": "Devi consentire l'accesso alla fotocamera per usare questa funzionalità." }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 076254176f8b..4ca1b2faaf7f 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -130,12 +130,21 @@ "account": { "message": "アカウント" }, + "accountActivity": { + "message": "アカウントアクティビティ" + }, + "accountActivityText": { + "message": "通知を受けたいアカウントを選択してください:" + }, "accountDetails": { "message": "アカウントの詳細" }, "accountIdenticon": { "message": "アカウントのアイデンティコン" }, + "accountIsntConnectedToastText": { + "message": "$1は$2に接続されていません" + }, "accountName": { "message": "アカウント名" }, @@ -153,6 +162,12 @@ "accountSelectionRequired": { "message": "アカウントを選択する必要があります!" }, + "accounts": { + "message": "アカウント" + }, + "accountsConnected": { + "message": "アカウントが接続されました" + }, "active": { "message": "アクティブ" }, @@ -243,6 +258,9 @@ "addIPFSGateway": { "message": "優先IPFSゲートウェイを追加" }, + "addImportAccount": { + "message": "アカウントまたはハードウェアウォレットを追加" + }, "addMemo": { "message": "メモを追加" }, @@ -256,6 +274,9 @@ "message": "このネットワーク接続はサードパーティに依存しているため、信頼性が低かったり、サードパーティによるアクティビティの追跡が可能になる可能性があります。$1", "description": "$1 is Learn more link" }, + "addNewAccount": { + "message": "新しいアカウントを追加" + }, "addNewToken": { "message": "新しいトークンを追加" }, @@ -265,6 +286,12 @@ "addNfts": { "message": "NFTを追加" }, + "addSnapAccountToggle": { + "message": "「アカウントSnapの追加 (ベータ版)」を有効にする" + }, + "addSnapAccountsDescription": { + "message": "この機能をオンにすると、アカウントリストから直接新しいベータ版のアカウントSnapを追加できるようになります。アカウントSnapをインストールする際は、サードパーティサービスである点にご注意ください。" + }, "addSuggestedNFTs": { "message": "推奨されたNFTを追加" }, @@ -281,6 +308,9 @@ "addingCustomNetwork": { "message": "ネットワークを追加中" }, + "addingTokens": { + "message": "トークンを追加しています" + }, "address": { "message": "アドレス" }, @@ -316,9 +346,27 @@ "airgapVault": { "message": "AirGap Vault" }, + "alert": { + "message": "アラート" + }, + "alertBannerMultipleAlertsDescription": { + "message": "このリクエストを承認すると、詐欺が判明しているサードパーティに資産をすべて奪われる可能性があります。" + }, + "alertBannerMultipleAlertsTitle": { + "message": "複数アラート!" + }, "alertDisableTooltip": { "message": "これは「設定」>「アラート」で変更できます" }, + "alertModalAcknowledge": { + "message": "リスクを承知したうえで続行します" + }, + "alertModalDetails": { + "message": "アラートの詳細" + }, + "alertModalReviewAllAlerts": { + "message": "すべてのアラートを確認する" + }, "alertSettingsUnconnectedAccount": { "message": "選択した未接続のアカウントを使用してWebサイトをブラウズしています" }, @@ -334,6 +382,9 @@ "alerts": { "message": "アラート" }, + "all": { + "message": "すべて" + }, "allCustodianAccountsConnectedSubtitle": { "message": "すでにすべてのカストディアンアカウントを接続したか、MetaMask Institutionalに接続するアカウントがありません。" }, @@ -344,23 +395,26 @@ "message": "すべての$1", "description": "$1 is the symbol or name of the token that the user is approving spending" }, + "allPermissions": { + "message": "すべてのアクセス許可" + }, "allYourNFTsOf": { "message": "$1のすべてのNFT", "description": "$1 is a link to contract on the block explorer when we're not able to retrieve a erc721 or erc1155 name" }, - "allowExternalExtensionTo": { - "message": "この外部拡張機能に次の操作を許可します" + "allow": { + "message": "許可する" + }, + "allowMmiToConnectToCustodian": { + "message": "これにより、MMIが$1に接続してアカウントをインポートできるようになります。" + }, + "allowNotifications": { + "message": "通知を許可する" }, "allowSpendToken": { "message": "$1へのアクセス許可を与えますか?", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "このサイトに次の操作を許可します" - }, - "allowThisSnapTo": { - "message": "このsnapに次の操作を許可します:" - }, "allowWithdrawAndSpend": { "message": "$1に以下の額までの引き出しと使用を許可します。", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -368,6 +422,23 @@ "amount": { "message": "金額" }, + "amountReceived": { + "message": "受取額" + }, + "amountSent": { + "message": "送金額" + }, + "andForListItems": { + "message": "$1、および$2", + "description": "$1 is the first item, $2 is the last item in a list of items. Used in Snap Install Warning modal." + }, + "andForTwoItems": { + "message": "$1および$2", + "description": "$1 is the first item, $2 is the second item. Used in Snap Install Warning modal." + }, + "announcements": { + "message": "お知らせ" + }, "appDescription": { "message": "ブラウザにあるイーサリアムウォレット", "description": "The description of the application" @@ -402,6 +473,10 @@ "approveButtonText": { "message": "承認" }, + "approveIncreaseAllowance": { + "message": "$1の使用上限を上げる", + "description": "The token symbol that is being approved" + }, "approveSpendingCap": { "message": "$1の使用上限を承認する", "description": "The token symbol that is being approved" @@ -427,6 +502,10 @@ "message": "$1に承認", "description": "$1 is the approval date for a permission" }, + "approvedOnForAccounts": { + "message": "$1に$2に対して承認済み", + "description": "$1 is the approval date for a permission. $2 is the AvatarGroup component displaying account images." + }, "areYouSure": { "message": "よろしいですか?" }, @@ -439,6 +518,12 @@ "attemptSendingAssets": { "message": "1つのネットワークから別のネットワークに直接アセットを送ろうとすると、アセットが永久に失われる可能性があります。必ずブリッジを使用してください。" }, + "attemptSendingAssetsWithPortfolio": { + "message": "別のネットワークからアセットを送ろうとすると、アセットが失われる可能性があります。$1などのブリッジを使ってネットワーク間で安全に送金してください。" + }, + "attemptToCancelSwapForFree": { + "message": "無料でスワップのキャンセルを試行" + }, "attemptingConnect": { "message": "ブロックチェーンへの接続を試みています。" }, @@ -479,6 +564,9 @@ "backupApprovalNotice": { "message": "シークレットリカバリーフレーズをバックアップして、ウォレットと資金の安全を確保してください。" }, + "backupKeyringSnapReminder": { + "message": "削除する前に、このSnapが作成したすべてのアカウントに自分でアクセスできることを確認してください" + }, "backupNow": { "message": "今すぐバックアップ" }, @@ -500,6 +588,30 @@ "basic": { "message": "基本" }, + "basicConfigurationBannerCTA": { + "message": "基本機能をオンにする" + }, + "basicConfigurationBannerTitle": { + "message": "基本機能はオフになっています" + }, + "basicConfigurationLabel": { + "message": "基本機能" + }, + "basicConfigurationModalCheckbox": { + "message": "理解したうえで続行します" + }, + "basicConfigurationModalDisclaimerOff": { + "message": "これは、MetaMaskでの時間が完全に最適化されないことを意味します。基本機能 (トークンの詳細、最適なガス設定など) は利用できません。" + }, + "basicConfigurationModalDisclaimerOn": { + "message": "MetaMaskでの時間を最適化するには、この機能をオンにする必要があります。基本機能 (トークンの詳細、最適なガス設定など) は、Web3エクスペリエンスに重要です。" + }, + "basicConfigurationModalHeadingOff": { + "message": "基本機能をオフにする" + }, + "basicConfigurationModalHeadingOn": { + "message": "基本機能をオンにする" + }, "beCareful": { "message": "ご注意ください" }, @@ -571,6 +683,9 @@ "blockaidDescriptionTransferFarming": { "message": "このリクエストを承認すると、詐欺が判明しているサードパーティに資産をすべて奪われます。" }, + "blockaidMessage": { + "message": "プライバシーを保護 - サードパーティとデータが一切共有されません。Arbitrum、Avalanche、BNB Chain、イーサリアムメインネット、Linea、Optimism、Polygon、Base、Sepoliaで利用可能。" + }, "blockaidTitleDeceptive": { "message": "これは虚偽のリクエストです" }, @@ -586,6 +701,9 @@ "bridge": { "message": "ブリッジ" }, + "bridgeDontSend": { + "message": "ブリッジを使用してください" + }, "browserNotSupported": { "message": "ご使用のブラウザはサポートされていません..." }, @@ -598,6 +716,9 @@ "busy": { "message": "ビジー状態" }, + "buyAndSell": { + "message": "購入・売却" + }, "buyAsset": { "message": "$1を購入", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -609,6 +730,10 @@ "buyNow": { "message": "今すぐ購入" }, + "buyToken": { + "message": "$1を購入", + "description": "$1 is the token symbol" + }, "bytes": { "message": "バイト" }, @@ -618,9 +743,6 @@ "cancel": { "message": "キャンセル" }, - "cancelEdit": { - "message": "編集をキャンセル" - }, "cancelPopoverTitle": { "message": "トランザクションをキャンセル" }, @@ -647,6 +769,9 @@ "chainIdExistsErrorMsg": { "message": "このチェーンIDは現在$1ネットワークで使用されています。" }, + "chainListReturnedDifferentTickerSymbol": { + "message": "このトークンシンボルは、入力されたネットワーク名またはチェーンIDと一致しません。人気のトークンの多くはシンボルが似ているため、詐欺師がそれを利用してより価値の高いトークンを送り返すように仕向ける可能性があります。続行する前にすべてを確認してください。" + }, "chooseYourNetwork": { "message": "ネットワークを選択してください" }, @@ -682,9 +807,19 @@ "close": { "message": "閉じる" }, + "closeExtension": { + "message": "拡張機能を閉じる" + }, + "closeWindowAnytime": { + "message": "このウィンドウはいつでも閉じることができます。" + }, "coingecko": { "message": "CoinGecko" }, + "comboNoOptions": { + "message": "オプションが見つかりません", + "description": "Default text shown in the combo field dropdown if no options." + }, "configureSnapPopupDescription": { "message": "MetaMaskから移動してこのsnapを構成します。" }, @@ -703,12 +838,42 @@ "confirm": { "message": "確認" }, + "confirmAlertModalAcknowledge": { + "message": "アラートを確認したうえで続行します" + }, + "confirmAlertModalDetails": { + "message": "サインインすると、詐欺が判明しているサードパーティにすべての資産を奪われる可能性があります。続ける前にアラートを確認してください。" + }, + "confirmAlertModalTitle": { + "message": "資産が危険にさらされている可能性があります" + }, + "confirmConnectCustodianRedirect": { + "message": "「続行」をクリックすると、$1にリダイレクトされます。" + }, + "confirmConnectCustodianText": { + "message": "アカウントを接続するには、$1アカウントにログインして「MMIに接続」ボタンをクリックしてください。" + }, + "confirmConnectionTitle": { + "message": "$1への接続の確定" + }, "confirmPassword": { "message": "パスワードの確認" }, "confirmRecoveryPhrase": { "message": "シークレットリカバリーフレーズの確認" }, + "confirmTitleDescContractInteractionTransaction": { + "message": "このトランザクションの内容を完全に理解し、要求元のサイトを信頼する場合にのみ確定してください。" + }, + "confirmTitleDescSignature": { + "message": "このメッセージの内容を承認し、要求元のサイトを信頼する場合にのみ確定してください。" + }, + "confirmTitleSignature": { + "message": "署名要求" + }, + "confirmTitleTransaction": { + "message": "トランザクションの要求" + }, "confirmed": { "message": "確認されました" }, @@ -724,9 +889,15 @@ "connect": { "message": "接続" }, + "connectAccount": { + "message": "アカウントの接続" + }, "connectAccountOrCreate": { "message": "アカウントを接続するか、または新規に作成します" }, + "connectAccounts": { + "message": "アカウントを接続" + }, "connectCustodialAccountMenu": { "message": "カストディアルアカウントを接続" }, @@ -736,36 +907,25 @@ "connectCustodialAccountTitle": { "message": "カストディアルアカウント" }, + "connectCustodianAccounts": { + "message": "$1アカウントの接続" + }, "connectManually": { "message": "現在のサイトに手動で接続" }, + "connectMoreAccounts": { + "message": "他のアカウントを接続" + }, "connectSnap": { "message": "$1を接続", "description": "$1 is the snap for which a connection is being requested." }, - "connectTo": { - "message": "$1に接続", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "すべての$1に接続", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "アカウント", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "$1に接続", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1アカウント", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "MetaMaskを使用して接続" }, + "connectedAccounts": { + "message": "接続されたアカウント" + }, "connectedAccountsDescriptionPlural": { "message": "このサイトに接続されているアカウントを$1個持っています。", "description": "$1 is the number of accounts" @@ -776,6 +936,13 @@ "connectedAccountsEmptyDescription": { "message": "MetaMaskはこのサイトに接続されていません。web3サイトに接続するには、そのサイトの接続ボタンをクリックしてください。" }, + "connectedAccountsListTooltip": { + "message": "$1はアカウントの残高、アドレス、アクティビティを確認し、接続されたアカウントで承認するトランザクションを提案できます。", + "description": "$1 is the origin name" + }, + "connectedAccountsToast": { + "message": "接続されたアカウントが更新されました" + }, "connectedSites": { "message": "接続済みのサイト" }, @@ -787,12 +954,21 @@ "message": "$1はどのサイトとも接続されていません。", "description": "$1 is the account name" }, + "connectedSnapAndNoAccountDescription": { + "message": "MetaMaskはこのサイトに接続されていますが、まだアカウントは接続されていません" + }, + "connectedWith": { + "message": "接続先" + }, "connecting": { "message": "接続中..." }, "connectingTo": { "message": "$1に接続中" }, + "connectingToDeprecatedNetwork": { + "message": "「$1」は段階的に廃止されており、機能しない可能性があります。別のネットワークをお試しください。" + }, "connectingToGoerli": { "message": "Goerliテストネットワークに接続中" }, @@ -802,6 +978,9 @@ "connectingToLineaMainnet": { "message": "Lineaメインネットに接続中" }, + "connectingToLineaSepolia": { + "message": "Linea Sepoliaテストネットワークに接続中" + }, "connectingToMainnet": { "message": "イーサリアムメインネットに接続中" }, @@ -831,6 +1010,12 @@ "continue": { "message": "続行" }, + "continueMmiOnboarding": { + "message": "MetaMask Institutionalのオンボーディングを続ける" + }, + "continueToWallet": { + "message": "ウォレットに進む" + }, "contract": { "message": "コントラクト" }, @@ -882,6 +1067,9 @@ "copyAddress": { "message": "アドレスをクリップボードにコピー" }, + "copyPrivateKey": { + "message": "秘密鍵をコピー" + }, "copyRawTransactionData": { "message": "未処理のトランザクションデータをコピー" }, @@ -900,6 +1088,15 @@ "createPassword": { "message": "パスワードを作成" }, + "createSnapAccountDescription": { + "message": "$1がMetaMaskへの新しいアカウントの追加を要求しています。" + }, + "createSnapAccountTitle": { + "message": "アカウントの作成" + }, + "crossChainSwapsLink": { + "message": "MetaMask Portfolioでネットワーク間でスワップ" + }, "cryptoCompare": { "message": "CryptoCompare" }, @@ -950,10 +1147,16 @@ "message": "カストディアン" }, "custodianAccountAddedDesc": { - "message": "カストディアンアカウントをMetaMask Institutionalで使えるようになりました。" + "message": "MetaMask Institutionalでアカウントが使えるようになりました。" }, "custodianAccountAddedTitle": { - "message": "選択されたカストディアンアカウントが追加されました。" + "message": "選択された$1個のアカウントが追加されました。" + }, + "custodianQRCodeScan": { + "message": "$1モバイルアプリでQRコードをスキャンします" + }, + "custodianQRCodeScanDescription": { + "message": "または、$1アカウントにログインして「MMIに接続」ボタンをクリックしてください" }, "custodianReplaceRefreshTokenChangedFailed": { "message": "$1に移動して、ユーザーインターフェースの「MMIに接続」ボタンをクリックし、アカウントをMMIに再接続します。" @@ -1025,6 +1228,12 @@ "customerSupport": { "message": "カスタマーサポート" }, + "customizeYourNotifications": { + "message": "通知のカスタマイズ" + }, + "customizeYourNotificationsText": { + "message": "受け取る通知の種類をオンにします" + }, "dappRequestedSpendingCap": { "message": "サイトが使用上限を要求しました" }, @@ -1108,6 +1317,18 @@ "deposit": { "message": "入金" }, + "deprecatedGoerliNtwrkMsg": { + "message": "イーサリアムシステムのアップデートに伴い、Goerliテストネットワークはまもなく段階的に廃止される予定です。" + }, + "deprecatedNetwork": { + "message": "このネットワークはサポートされなくなりました" + }, + "deprecatedNetworkButtonMsg": { + "message": "了解" + }, + "deprecatedNetworkDescription": { + "message": "接続しているネットワークは現在MetaMaskによりサポートされていません。$1" + }, "description": { "message": "説明" }, @@ -1115,110 +1336,20 @@ "message": "$1からの説明", "description": "$1 represents the name of the snap" }, - "desktopApp": { - "message": "デスクトップアプリ" - }, - "desktopConnectionCriticalErrorDescription": { - "message": "このエラーは一時的なものかもしれないので、拡張機能を再起動するか、MetaMask Desktopを無効にしてみてください。" - }, - "desktopConnectionCriticalErrorTitle": { - "message": "MetaMaskがうまく起動できませんでした" - }, - "desktopConnectionLostErrorDescription": { - "message": "デスクトップアプリが正常に動作していることを確認するか、MetaMask Desktopを無効にしてください。" - }, - "desktopConnectionLostErrorTitle": { - "message": "MetaMask Desktopの接続が失われました" - }, - "desktopDisableButton": { - "message": "デスクトップアプリを無効にする" - }, - "desktopDisableErrorCTA": { - "message": "MetaMask Desktopを無効にする" - }, - "desktopEnableButton": { - "message": "MetaMask Desktopを有効にする" - }, - "desktopEnableButtonDescription": { - "message": "クリックして、デスクトップアプリのすべてのバックグラウンドプロセスを実行します。" - }, - "desktopErrorNavigateSettingsCTA": { - "message": "設定ページに戻る" - }, - "desktopErrorRestartMMCTA": { - "message": "MetaMaskを再起動" - }, - "desktopNotFoundErrorCTA": { - "message": "MetaMask Desktopをダウンロード" - }, - "desktopNotFoundErrorDescription1": { - "message": "デスクトップアプリが正常に動作していることを確認してください。" - }, - "desktopNotFoundErrorDescription2": { - "message": "デスクトップアプリがインストールされていない場合は、MetaMaskのWebサイトでダウンロードしてください。" - }, - "desktopNotFoundErrorTitle": { - "message": "MetaMask Desktopが見つかりませんでした" - }, - "desktopOpenOrDownloadCTA": { - "message": "MetaMask Desktopを開く" - }, - "desktopOutdatedErrorCTA": { - "message": "MetaMask Desktopを更新" - }, - "desktopOutdatedErrorDescription": { - "message": "ご使用のMetaMaskデスクトップアプリはアップグレードが必要です。" - }, - "desktopOutdatedErrorTitle": { - "message": "MetaMask Desktopが古くなっています" - }, - "desktopOutdatedExtensionErrorCTA": { - "message": "MetaMask拡張機能を更新" - }, - "desktopOutdatedExtensionErrorDescription": { - "message": "ご使用のMetaMask拡張機能はアップグレードが必要です。" - }, - "desktopOutdatedExtensionErrorTitle": { - "message": "MetaMask拡張機能が古くなっています" - }, - "desktopPageDescription": { - "message": "ペアリングが成功したら、拡張機能が再起動し、パスワードの再入力が必要になります。" - }, - "desktopPageSubTitle": { - "message": "MetaMask Desktopを開いてこのコードを入力してください" - }, - "desktopPageTitle": { - "message": "Desktopとのペアリング" - }, - "desktopPairedWarningDeepLink": { - "message": "MetaMask Desktopの設定に移動" - }, - "desktopPairedWarningDescription": { - "message": "新しいペアリングを開始するには、現在の接続を削除してください。" - }, - "desktopPairedWarningTitle": { - "message": "MM Desktopがすでにペアリングされています" - }, - "desktopPairingExpireMessage": { - "message": "コードはあと$1秒で期限切れになります" - }, - "desktopRouteNotFoundErrorDescription": { - "message": "desktopRouteNotFoundErrorDescription" - }, - "desktopRouteNotFoundErrorTitle": { - "message": "desktopRouteNotFoundErrorTitle" + "details": { + "message": "詳細" }, - "desktopUnexpectedErrorCTA": { - "message": "MetaMaskのホームに戻る" + "developerOptions": { + "message": "開発者用オプション" }, - "desktopUnexpectedErrorDescription": { - "message": "MetaMask Desktopを確認して接続を復元してください" + "developerOptionsResetStatesAnnouncementsDescription": { + "message": "すべてのお知らせのisShownのブール値をfalseにリセットします。お知らせとは、「最新情報」ポップアップモーダルに表示される通知のことです。" }, - "desktopUnexpectedErrorTitle": { - "message": "何か問題が発生しました..." + "developerOptionsResetStatesOnboarding": { + "message": "オンボーディングに関するさまざまなステートをリセットし、「ウォレットのセキュリティ保護」オンボーディングページにリダイレクトします。" }, - "details": { - "message": "詳細" + "developerOptionsServiceWorkerKeepAlive": { + "message": "タイムスタンプがセッションストレージに継続的に保存されるようになります" }, "disabledGasOptionToolTipMessage": { "message": "元のガス代の10%以上という増額の条件を満たしていないため、「$1」は無効になっています。", @@ -1233,12 +1364,38 @@ "disconnectAllAccountsConfirmationDescription": { "message": "本当に接続解除しますか?サイトの機能を失う可能性があります。" }, + "disconnectAllAccountsText": { + "message": "アカウント" + }, + "disconnectAllSnapsText": { + "message": "Snap" + }, + "disconnectAllText": { + "message": "$1と$2の接続を解除した場合、再び使用するには再度接続する必要があります。", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`, $2 represents the website hostname" + }, + "disconnectAllTitle": { + "message": "すべての$1の接続を解除", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`" + }, "disconnectPrompt": { "message": "$1を接続解除" }, "disconnectThisAccount": { "message": "このアカウントを接続解除" }, + "disconnectedAllAccountsToast": { + "message": "すべてのアカウントの$1への接続が解除されました", + "description": "$1 is name of the dapp`" + }, + "disconnectedSingleAccountToast": { + "message": "$1の$2への接続が解除されました", + "description": "$1 is name of the name and $2 represents the dapp name`" + }, + "discoverSnaps": { + "message": "Snapのご紹介", + "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." + }, "dismiss": { "message": "閉じる" }, @@ -1248,9 +1405,21 @@ "dismissReminderField": { "message": "シークレットリカバリーフレーズのバックアップリマインダーを解除" }, + "displayNftMedia": { + "message": "NFTメディアの表示" + }, + "displayNftMediaDescription": { + "message": "NFTのメディアとデータを表示した場合、IPアドレスがOpenSeaをはじめとするサードパーティに公開されます。その結果、攻撃者がユーザーのIPアドレスとイーサリアムアドレスを関連付けられるようになる可能性があります。NFTの自動検出はこの設定に依存しており、この設定を無効にすると利用できなくなります。" + }, + "doNotShare": { + "message": "これは誰にも教えないでください" + }, "domain": { "message": "ドメイン" }, + "domainNotSupportedOnNetwork": { + "message": "ネットワークがドメイン検索をサポートしていません" + }, "done": { "message": "完了" }, @@ -1269,6 +1438,9 @@ "downloadStateLogs": { "message": "ステートログをダウンロード" }, + "dragAndDropBanner": { + "message": "ネットワークをドラッグして並び替えることができます。" + }, "dropped": { "message": "削除されました" }, @@ -1367,6 +1539,9 @@ "editSpeedUpEditGasFeeModalTitle": { "message": "高速化用のガス代を編集" }, + "enable": { + "message": "有効にする" + }, "enableAutoDetect": { "message": " 自動検出を有効にする" }, @@ -1397,6 +1572,18 @@ "enhancedTokenDetectionAlertMessage": { "message": "改善されたトークン検出は現在$1で利用可能です。$2" }, + "ensDomainsSettingDescriptionIntroduction": { + "message": "MetaMaskは、ENSドメインをブラウザのアドレスバーに直接表示します。使い方は次の通りです:" + }, + "ensDomainsSettingDescriptionOutroduction": { + "message": "この機能を使用すると、IPアドレスがIPFSのサードパーティサービスに公開されます。" + }, + "ensDomainsSettingDescriptionPart1": { + "message": "MetaMaskはイーサリアムのENSコントラクトを確認し、ENS名に接続されたコードを取得します。" + }, + "ensDomainsSettingDescriptionPart2": { + "message": "コードがIPFSにリンクしている場合、関連付けられたコンテンツ (通常Webサイト) を見ることができます。" + }, "ensDomainsSettingTitle": { "message": "アドレスバーにENSドメインを表示する" }, @@ -1438,6 +1625,9 @@ "message": "エラーの詳細", "description": "Title for collapsible section that displays error details for debugging purposes" }, + "errorGettingSafeChainList": { + "message": "安全なチェーンリストの取得中にエラーが発生しました。慎重に続けてください。" + }, "errorMessage": { "message": "メッセージ: $1", "description": "Displayed error message for debugging purposes. $1 is the error message" @@ -1469,6 +1659,9 @@ "message": "$1でエラーが発生しました", "description": "$1 represents the name of the snap" }, + "estimatedFee": { + "message": "予想手数料" + }, "ethGasPriceFetchWarning": { "message": "現在メインのガスの見積もりサービスが利用できないため、バックアップのガス価格が提供されています。" }, @@ -1495,12 +1688,24 @@ "message": "試験運用" }, "extendWalletWithSnaps": { - "message": "ウォレットのユーザー体験をカスタマイズします。", + "message": "Web3のエクスペリエンスをカスタマイズする、コミュニティが開発したSnapをご覧ください", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "extensionInsallCompleteDescription": { + "message": "MetaMask Institutionalの製品オンボーディングに戻って、カストディアルまたはセルフカストディアルアカウントを接続します。" + }, + "extensionInsallCompleteTitle": { + "message": "拡張機能のインストールが完了しました" + }, "externalExtension": { "message": "外部拡張機能" }, + "externalNameSourcesSetting": { + "message": "ニックネームの提案" + }, + "externalNameSourcesSettingDescription": { + "message": "当社はEtherscan、Infura、Lensプロトコルなどのサードパーティソースから、やり取りがあるアドレスのニックネームの提案を取得します。これらのソースは対象となるアドレスとユーザーのIPアドレスを把握できます。ユーザーのアカウントアドレスはサードパーティに公開されません。" + }, "failed": { "message": "失敗しました" }, @@ -1519,6 +1724,9 @@ "feeAssociatedRequest": { "message": "このリクエストには手数料がかかります。" }, + "feeDetails": { + "message": "手数料の詳細" + }, "fiat": { "message": "法定通貨", "description": "Exchange type" @@ -1551,6 +1759,9 @@ "message": "リスクを受け入れる", "description": "this text is shown on a button, which the user presses to confirm they understand the risks of using Flask" }, + "floatAmountToken": { + "message": "トークンの金額は整数で入力する必要があります" + }, "followUsOnTwitter": { "message": "Twitterでフォロー" }, @@ -1573,6 +1784,9 @@ "fromTokenLists": { "message": "トークンリストから: $1" }, + "function": { + "message": "機能: $1" + }, "functionApprove": { "message": "機能: 承認" }, @@ -1582,6 +1796,13 @@ "functionType": { "message": "機能の種類" }, + "fundYourWallet": { + "message": "ウォレットへの入金" + }, + "fundYourWalletDescription": { + "message": "ウォレットに$1を追加して開始します。", + "description": "$1 is the token symbol" + }, "gas": { "message": "ガス" }, @@ -1592,6 +1813,9 @@ "message": "このガス代は$1により提案されています。これを上書きすると、トランザクションに問題が発生する可能性があります。ご質問がございましたら、$1までお問い合わせください。", "description": "$1 represents the Dapp's origin" }, + "gasIsETH": { + "message": "ガス代は$1です" + }, "gasLimit": { "message": "ガスリミット" }, @@ -1636,6 +1860,9 @@ "message": "$1時間", "description": "$1 represents a number of hours" }, + "gasTimingLow": { + "message": "低速" + }, "gasTimingMinutesShort": { "message": "$1分", "description": "$1 represents a number of minutes" @@ -1650,15 +1877,29 @@ "general": { "message": "一般" }, - "globalTitle": { - "message": "グローバルメニュー" + "generalCameraError": { + "message": "カメラにアクセスできませんでした。もう一度お試しください" }, - "globalTourDescription": { - "message": "ポートフォリオ、接続されたサイト、設定などを確認できます" + "generalCameraErrorTitle": { + "message": "問題が発生しました...." + }, + "genericExplorerView": { + "message": "$1でアカウントを表示" + }, + "getStartedWithNFTs": { + "message": "$1を入手してNFTを購入", + "description": "$1 is the token symbol" + }, + "getStartedWithNFTsDescription": { + "message": "ウォレットに$1を追加してNFTの利用を開始します。", + "description": "$1 is the token symbol" }, "goBack": { "message": "戻る" }, + "goToSite": { + "message": "サイトに移動" + }, "goerli": { "message": "Goerliテストネットワーク" }, @@ -1700,15 +1941,24 @@ "hexData": { "message": "16進データ" }, + "hiddenAccounts": { + "message": "非表示のアカウント" + }, "hide": { "message": "非表示" }, + "hideAccount": { + "message": "アカウントを非表示" + }, "hideFullTransactionDetails": { "message": "完全なトランザクション情報を非表示" }, "hideSeedPhrase": { "message": "シードフレーズを非表示" }, + "hideSentitiveInfo": { + "message": "機密情報を非表示" + }, "hideToken": { "message": "トークンを非表示" }, @@ -1790,6 +2040,9 @@ "ignoreTokenWarning": { "message": "トークンを非表示にするとウォレットに表示されなくなりますが、検索して追加することはできます。" }, + "imToken": { + "message": "imToken" + }, "import": { "message": "インポート", "description": "Button to import an account from a selected file" @@ -1848,6 +2101,9 @@ "importTokensCamelCase": { "message": "トークンをインポート" }, + "importTokensError": { + "message": "トークンをインポートできませんでした。後ほど再度お試しください。" + }, "importWithCount": { "message": "$1をインポート", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -1866,6 +2122,9 @@ "initialTransactionConfirmed": { "message": "最初のトランザクションはネットワークによって承認されました。戻るには「OK」をクリックします。" }, + "inlineAlert": { + "message": "アラート" + }, "inputLogicEmptyState": { "message": "現在または今後サードパーティが使用しても構わない額のみを入力してください。使用上限は後でいつでも増額できます。" }, @@ -1876,6 +2135,27 @@ "inputLogicHigherNumber": { "message": "これにより、上限に達するか使用上限が取り消されるまで、サードパーティがトークン残高全額を使用できるようになります。これを意図していない場合は、使用上限を低めに設定することをお勧めします。" }, + "insightWarning": { + "message": "警告" + }, + "insightWarningCheckboxMessage": { + "message": "$2の要求を$1する", + "description": "$1 is the action i.e. sign, confirm. $2 is the origin making the request." + }, + "insightWarningContentPlural": { + "message": "$2する前に$1を確認してください。$3は元に戻せません。", + "description": "$1 the 'insightWarnings' message (2 warnings) representing warnings, $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningContentSingular": { + "message": "$2する前に$1を確認してください。$3は元に戻せません。", + "description": "$1 is the 'insightWarning' message (1 warning), $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningHeader": { + "message": "この要求はリスクを伴う可能性があります" + }, + "insightWarnings": { + "message": "警告" + }, "insightsFromSnap": { "message": "$1からのインサイト", "description": "$1 represents the name of the snap" @@ -1883,9 +2163,18 @@ "install": { "message": "インストール" }, + "installExtension": { + "message": "拡張機能をインストール" + }, + "installExtensionDescription": { + "message": "世界をリードするWeb3ウォレット、MetaMaskの企業対応版です。" + }, "installOrigin": { "message": "インストール元" }, + "installRequest": { + "message": "MetaMaskに追加" + }, "installedOn": { "message": "$1にインストール", "description": "$1 is the date when the snap has been installed" @@ -1914,6 +2203,12 @@ "insufficientTokens": { "message": "トークンが不十分です。" }, + "interactingWith": { + "message": "相手:" + }, + "interactingWithTransactionDescription": { + "message": "このコントラクトとやり取りしています。詳細を確認して詐欺師から身を守りましょう。" + }, "invalidAddress": { "message": "無効なアドレス" }, @@ -1986,6 +2281,9 @@ "ipfsToggleModalSettings": { "message": "「設定」>「セキュリティとプライバシー」" }, + "isSigningOrSubmitting": { + "message": "以前のトランザクションがまだ署名中または送信中です" + }, "jazzAndBlockies": { "message": "JazziconとBlockieは、アカウントを一目で見分けるためのユニークなアイコンであり、2つの異なるスタイルが特徴です。" }, @@ -1999,6 +2297,24 @@ "message": "JSONファイル", "description": "format for importing an account" }, + "keyringAccountName": { + "message": "アカウント名" + }, + "keyringAccountPublicAddress": { + "message": "パブリックアドレス" + }, + "keyringSnapRemovalResult1": { + "message": "$1の削除を完了$2", + "description": "Displays the result after removal of a keyring snap. $1 is the snap name, $2 is whether it is successful or not" + }, + "keyringSnapRemovalResultNotSuccessful": { + "message": "できませんでした", + "description": "Displays the `not` word in $2." + }, + "keyringSnapRemoveConfirmation": { + "message": "「$1」と入力して、このSnapを削除することを確定してください:", + "description": "Asks user to input the name nap prior to deleting the snap. $1 is the snap name" + }, "keystone": { "message": "Keystone" }, @@ -2017,9 +2333,15 @@ "lastSold": { "message": "前回の売却" }, + "lavaDomeCopyWarning": { + "message": "安全上の理由により、現在このテキストは選択できません。" + }, "layer1Fees": { "message": "レイヤー1手数料" }, + "layer2Fees": { + "message": "レイヤー2手数料" + }, "learnCancelSpeeedup": { "message": "$1の方法を学ぶ", "description": "$1 is link to cancel or speed up transactions" @@ -2037,9 +2359,21 @@ "learnMoreUpperCase": { "message": "詳細" }, + "learnMoreUpperCaseWithDot": { + "message": "詳細。" + }, "learnScamRisk": { "message": "詐欺やセキュリティのリスク。" }, + "learnToBridge": { + "message": "ブリッジの使い方" + }, + "leaveMetaMask": { + "message": "MetaMaskから離れますか?" + }, + "leaveMetaMaskDesc": { + "message": "MetaMask以外のサイトにアクセスしようとしています。続行する前にURLをもう一度確認してください。" + }, "ledgerAccountRestriction": { "message": "新しいアカウントを追加するには、その前に最後のアカウントを使用する必要があります。" }, @@ -2058,6 +2392,18 @@ "ledgerDeviceOpenFailureMessage": { "message": "Ledgerデバイスを開けませんでした。Ledgerが他のソフトウェアに接続されている可能性があります。Ledger LiveまたはLedgerデバイスに接続されている他のアプリケーションを閉じて、もう一度接続してみてください。" }, + "ledgerErrorConnectionIssue": { + "message": "Ledgerを接続し直し、ETHアプリを開いてもう一度お試しください。" + }, + "ledgerErrorDevicedLocked": { + "message": "Ledgerがロックされています。ロックを解除してからもう一度お試しください。" + }, + "ledgerErrorEthAppNotOpen": { + "message": "この問題を解決するには、デバイスでETHアプリケーションを開いてもう一度お試しください。" + }, + "ledgerErrorTransactionDataNotPadded": { + "message": "イーサリアムトランザクションの入力データが十分にパディングされていません。" + }, "ledgerLiveApp": { "message": "Ledger Liveアプリ" }, @@ -2077,6 +2423,9 @@ "lightTheme": { "message": "ライト" }, + "likeToImportToken": { + "message": "このトークンをインポートしますか?" + }, "likeToImportTokens": { "message": "これらのトークンを追加しますか?" }, @@ -2086,6 +2435,9 @@ "lineaMainnet": { "message": "Lineaメインネット" }, + "lineaSepolia": { + "message": "Linea Sepoliaテストネットワーク" + }, "link": { "message": "リンク" }, @@ -2098,8 +2450,11 @@ "loading": { "message": "ロードしています..." }, - "loadingNFTs": { - "message": "NFTをロードしています..." + "loadingScreenHardwareWalletMessage": { + "message": "ハードウェアウォレットでトランザクションを完了させてください。" + }, + "loadingScreenSnapMessage": { + "message": "Snapでトランザクションを完了させてください。" }, "loadingTokens": { "message": "トークンをロードしています..." @@ -2146,6 +2501,9 @@ "message": "誰にも見られていないことを確認してください", "description": "Warning to users to be care while creating and saving their new Secret Recovery Phrase" }, + "manageInSettings": { + "message": "設定で管理" + }, "max": { "message": "最大" }, @@ -2180,15 +2538,34 @@ "metaMaskConnectStatusParagraphTwo": { "message": "訪問しているWebサイトが現在選択しているアカウントに接続されている場合、接続ステータスボタンが表示されます。" }, + "metadataModalSourceTooltip": { + "message": "$1はnpmでホストされていて、$2はこのSnapの一意のIDです。", + "description": "$1 is the snap name and $2 is the snap NPM id." + }, "metamaskInstitutionalVersion": { "message": "MetaMask Institutionalバージョン" }, + "metamaskNotificationsAreOff": { + "message": "ウォレット通知は現在アクティブではありません" + }, + "metamaskPortfolio": { + "message": "MetaMask Portfolio。" + }, "metamaskSwapsOfflineDescription": { "message": "MetaMask Swapsはメンテナンス中です。後でもう一度確認してください。" }, "metamaskVersion": { "message": "MetaMaskのバージョン" }, + "methodData": { + "message": "方法" + }, + "methodDataTransactionDescription": { + "message": "これが実行される具体的なアクションです。このデータには改ざんの可能性があるため、相手のサイトが信頼できることを確認してください。" + }, + "methodNotSupported": { + "message": "このアカウントではサポートされていません。" + }, "metrics": { "message": "メトリクス" }, @@ -2224,11 +2601,17 @@ "mmiBuiltAroundTheWorld": { "message": "MetaMaskは、世界中でデザイン・開発されています。" }, + "mmiNewNFTDetectedInNFTsTabMessage": { + "message": "MetaMask Institutionalによるウォレット内のNFTの自動検出と表示を許可します。" + }, + "mmiPasswordSetupDetails": { + "message": "このパスワードはMetaMask Institutional拡張機能のロックしか解除しません。" + }, "more": { "message": "他" }, "multipleSnapConnectionWarning": { - "message": "$1が$2個のsnapとの接続を要求しています。このWebサイトが信頼できる場合にのみ続行してください。", + "message": "$1が$2 Snapの使用を求めています", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." }, "mustSelectOne": { @@ -2237,10 +2620,80 @@ "name": { "message": "名前" }, + "nameAddressLabel": { + "message": "アドレス", + "description": "Label above address field in name component modal." + }, + "nameInstructionsNew": { + "message": "このアドレスを知っている場合は、今後認識できるようニックネームを付けてください。", + "description": "Instruction text in name component modal when value is not recognised." + }, + "nameInstructionsRecognized": { + "message": "このアドレスにはデフォルトのニックネームがありますが、編集したり、他の提案を閲覧したりできます。", + "description": "Instruction text in name component modal when value is recognized but not saved." + }, + "nameInstructionsSaved": { + "message": "以前このアドレスのニックネームを追加しています。編集するか、他のニックネームの提案を参照できます。", + "description": "Instruction text in name component modal when value is saved." + }, + "nameLabel": { + "message": "ニックネーム", + "description": "Label above name input field in name component modal." + }, + "nameModalMaybeProposedName": { + "message": "たとえば: $1", + "description": "$1 is the proposed name" + }, + "nameModalTitleNew": { + "message": "不明なアドレス", + "description": "Title of the modal created by the name component when value is not recognised." + }, + "nameModalTitleRecognized": { + "message": "認識されたアドレス", + "description": "Title of the modal created by the name component when value is recognized but not saved." + }, + "nameModalTitleSaved": { + "message": "保存したアドレス", + "description": "Title of the modal created by the name component when value is saved." + }, + "nameProviderProposedBy": { + "message": "提案元: $1", + "description": "$1 is the name of the provider" + }, + "nameProvider_ens": { + "message": "イーサリアムネームサービス (ENS)" + }, + "nameProvider_etherscan": { + "message": "Etherscan" + }, + "nameProvider_lens": { + "message": "Lensプロトコル" + }, + "nameProvider_token": { + "message": "MetaMask" + }, + "nameSetPlaceholder": { + "message": "ニックネームを選択...", + "description": "Placeholder text for name input field in name component modal." + }, + "nativePermissionRequestDescription": { + "message": "このサイトに次のことを希望しますか?", + "description": "Description below header used on Permission Connect screen for native permissions." + }, "nativeToken": { "message": "このネットワークのネイティブトークンは$1です。ガス代にもこのトークンが使用されます。", "description": "$1 represents the name of the native token on the current network" }, + "nativeTokenScamWarningConversion": { + "message": "ネットワークの詳細を編集" + }, + "nativeTokenScamWarningDescription": { + "message": "このネットワークは関連付けられているチェーンIDまたは名前と一致していません。人気のトークンの多くが「$1」という名前を使用しているため、詐欺の対象となっています。詐欺師はより価値の高い通貨を送り返すよう仕向けてくる可能性があります。続行する前にすべてを確認してください。", + "description": "$1 represents the currency name" + }, + "nativeTokenScamWarningTitle": { + "message": "これは詐欺の可能性があります" + }, "needHelp": { "message": "アシスタンスが必要な場合は、$1にお問い合わせください", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -2261,6 +2714,9 @@ "negativeETH": { "message": "負の額のETHを送金することはできません。" }, + "negativeOrZeroAmountToken": { + "message": "資産をマイナスまたはゼロの金額で送ることはできません。" + }, "network": { "message": "ネットワーク:" }, @@ -2291,6 +2747,9 @@ "networkNameBSC": { "message": "BSC" }, + "networkNameBase": { + "message": "Base" + }, "networkNameDefinition": { "message": "このネットワークに関連付けられている名前。" }, @@ -2300,12 +2759,21 @@ "networkNameGoerli": { "message": "Goerli" }, + "networkNameLinea": { + "message": "Linea" + }, + "networkNameOpMainnet": { + "message": "OPメインネット" + }, "networkNamePolygon": { "message": "Polygon" }, "networkNameTestnet": { "message": "テストネット" }, + "networkNameZkSyncEra": { + "message": "zkSync Era" + }, "networkProvider": { "message": "ネットワークプロバイダー" }, @@ -2358,6 +2826,19 @@ "newContract": { "message": "新しいコントラクト" }, + "newNFTDetectedInImportNFTsMessageStrongText": { + "message": "「設定」>「セキュリティとプライバシー」" + }, + "newNFTDetectedInImportNFTsMsg": { + "message": "OpenSeaを使用してNFTを表示するには、$1で「NFTメディアの表示」をオンにしてください。", + "description": "$1 is used for newNFTDetectedInImportNFTsMessageStrongText" + }, + "newNFTDetectedInNFTsTabMessage": { + "message": "MetaMaskによるウォレット内のNFTの自動検出と表示を許可します。" + }, + "newNFTsAutodetected": { + "message": "NFTの自動検出" + }, "newNetworkAdded": { "message": "「$1」が追加されました!" }, @@ -2367,6 +2848,12 @@ "newPassword": { "message": "新しいパスワード (最低8文字)" }, + "newPrivacyPolicyActionButton": { + "message": "続きを表示" + }, + "newPrivacyPolicyTitle": { + "message": "プライバシーポリシーが更新されました" + }, "newTokensImportedMessage": { "message": "$1をインポートしました。", "description": "$1 is the string of symbols of all the tokens imported" @@ -2388,6 +2875,9 @@ "message": "このトークンはNFTです。$1で追加してください", "description": "$1 is a clickable link with text defined by the 'importNFTPage' key" }, + "nftAlreadyAdded": { + "message": "NFTがすでに追加されています。" + }, "nftDisclaimer": { "message": "開示事項: MetaMaskはソースURLからメディアファイルを取得します。このURLは時々、NFTがミントされたマーケットプレイスにより変更されることがあります。" }, @@ -2423,12 +2913,21 @@ "noAddressForName": { "message": "この名前にアドレスが設定されていません。" }, + "noConnectedAccountDescription": { + "message": "続行するには、このサイトで使用するアカウントを選択してください。" + }, + "noConnectedAccountTitle": { + "message": "MetaMaskはこのサイトに接続されていません" + }, "noConversionDateAvailable": { "message": "通貨換算日がありません" }, "noConversionRateAvailable": { "message": "利用可能な換算レートがありません" }, + "noDomainResolution": { + "message": "指定されたドメインの名前解決ができません。" + }, "noNFTs": { "message": "NFTはまだありません" }, @@ -2447,6 +2946,9 @@ "noWebcamFoundTitle": { "message": "Webカメラが見つかりません" }, + "nonCustodialAccounts": { + "message": "MetaMask Institutionalでは、非カストディアルアカウントを使用できます。これらのアカウントを使用する場合は、シークレットリカバリーフレーズをバックアップしてください。" + }, "nonce": { "message": "ナンス" }, @@ -2477,6 +2979,111 @@ "notePlaceholder": { "message": "承認者がカストディアンでトランザクションを承認する際に、この備考が表示されます。" }, + "notificationDetail": { + "message": "詳細" + }, + "notificationDetailBaseFee": { + "message": "基本料金 (gwei)" + }, + "notificationDetailGasLimit": { + "message": "ガスリミット (単位)" + }, + "notificationDetailGasUsed": { + "message": "使用ガス (単位)" + }, + "notificationDetailMaxFee": { + "message": "ガス1単位あたりの最大手数料" + }, + "notificationDetailNetwork": { + "message": "ネットワーク" + }, + "notificationDetailNetworkFee": { + "message": "ネットワーク手数料" + }, + "notificationDetailPriorityFee": { + "message": "優先手数料 (gwei)" + }, + "notificationItemCheckBlockExplorer": { + "message": "BlockExplorerで確認する" + }, + "notificationItemCollection": { + "message": "コレクション" + }, + "notificationItemConfirmed": { + "message": "確定されました" + }, + "notificationItemError": { + "message": "現在手数料を取得できません" + }, + "notificationItemFrom": { + "message": "移動元" + }, + "notificationItemLidoStakeReadyToBeWithdrawn": { + "message": "出金準備ができました" + }, + "notificationItemLidoStakeReadyToBeWithdrawnMessage": { + "message": "これでステーキングされていない $1 を引き出すことができます" + }, + "notificationItemLidoWithdrawalRequestedMessage": { + "message": "$1 のステーキングを解除するリクエストが送信されました" + }, + "notificationItemNFTReceivedFrom": { + "message": "NFTを次の元から受け取りました:" + }, + "notificationItemNFTSentTo": { + "message": "NFTを次の相手に送りました:" + }, + "notificationItemNetwork": { + "message": "ネットワーク" + }, + "notificationItemRate": { + "message": "レート (手数料込み)" + }, + "notificationItemReceived": { + "message": "受け取りました" + }, + "notificationItemReceivedFrom": { + "message": "次の元から受け取りました:" + }, + "notificationItemSent": { + "message": "送りました" + }, + "notificationItemSentTo": { + "message": "次の相手に送りました:" + }, + "notificationItemStakeCompleted": { + "message": "ステーキングが完了しました" + }, + "notificationItemStaked": { + "message": "ステーキングしました" + }, + "notificationItemStakingProvider": { + "message": "ステーキングプロバイダー" + }, + "notificationItemStatus": { + "message": "ステータス" + }, + "notificationItemSwapped": { + "message": "スワップ完了" + }, + "notificationItemSwappedFor": { + "message": "for" + }, + "notificationItemTo": { + "message": "移動先" + }, + "notificationItemTransactionId": { + "message": "トランザクションID" + }, + "notificationItemUnStakeCompleted": { + "message": "ステーキングの解除が完了しました" + }, + "notificationItemUnStaked": { + "message": "ステーキングが寛恕されました" + }, + "notificationItemUnStakingRequested": { + "message": "ステーキングの解除がリクエストされました" + }, "notificationTransactionFailedMessage": { "message": "トランザクション $1 に失敗しました!$2", "description": "Content of the browser notification that appears when a transaction fails" @@ -2494,52 +3101,15 @@ "description": "Content of the browser notification that appears when a transaction is confirmed" }, "notificationTransactionSuccessTitle": { - "message": "トランザクションの承認完了", - "description": "Title of the browser notification that appears when a transaction is confirmed" - }, - "notificationTransactionSuccessView": { - "message": "$1で表示", - "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" - }, - "notifications": { - "message": "通知" - }, - "notifications20ActionText": { - "message": "詳細", - "description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a ledger page to resolve the U2F connection issue." - }, - "notifications20Description": { - "message": "Firefoxの最新バージョンを使用している場合、FirefoxのU2Fサポート廃止に関連した問題が発生する可能性があります。", - "description": "Description of a notification in the 'See What's New' popup. Describes the U2F support being dropped by firefox and that it affects ledger users." - }, - "notifications20Title": { - "message": "LedgerとFirefoxのユーザーに発生している接続の問題について", - "description": "Title for a notification in the 'See What's New' popup. Tells users that latest firefox users using U2F may experience connection issues." - }, - "notifications24ActionText": { - "message": "了解" - }, - "notifications24Description": { - "message": "使用中のネットワークに基づき高度なガス代設定が保存されるようになりました。これにより、ネットワークごとに高度なガス代設定を行い、ガス代の払い過ぎやトランザクション詰まりを防ぐことができます。" - }, - "notifications24Title": { - "message": "ネットワークごとの高度なガス代設定" - }, - "notifications8ActionText": { - "message": "「設定」>「高度な設定」に移動します", - "description": "Description on an action button that appears in the What's New popup. Tells the user that if they click it, they will go to our Advanced settings page." - }, - "notifications8DescriptionOne": { - "message": "MetaMask v10.4.0以降では、LedgerデバイスのMetaMaskへの接続にLedger Liveが不要になりました。", - "description": "Description of a notification in the 'See What's New' popup. Describes changes for how Ledger Live is no longer needed to connect the device." + "message": "トランザクションの承認完了", + "description": "Title of the browser notification that appears when a transaction is confirmed" }, - "notifications8DescriptionTwo": { - "message": "Ledgerをより簡単かつ安定してご利用いただくには、「設定」の「高度な設定」タブに移動し、「優先Ledger接続タイプ」を「WebHID」に切り替えてください。", - "description": "Description of a notification in the 'See What's New' popup. Describes how the user can turn off the Ledger Live setting." + "notificationTransactionSuccessView": { + "message": "$1で表示", + "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" }, - "notifications8Title": { - "message": "Ledgerの接続の改善", - "description": "Title for a notification in the 'See What's New' popup. Notifies ledger users that there is an improvement in how they can connect their device." + "notifications": { + "message": "通知" }, "notificationsDropLedgerFirefoxDescription": { "message": "FirefoxはU2Fをサポートしなくなったため、LedgerはFirefox版の MetaMaskでは機能しません。代わりにGoogle Chrome版のMetaMaskをお試しください。", @@ -2549,33 +3119,37 @@ "message": "FirefoxでのLedger サポートの停止", "description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped." }, - "notificationsEmptyText": { - "message": "ここには、インストールしたsnapからの通知が表示されます。" - }, - "notificationsHeader": { - "message": "通知" + "notificationsFeatureToggle": { + "message": "ウォレットの通知を有効にする", + "description": "Experimental feature title" }, - "notificationsInfos": { - "message": "$1に$2から", - "description": "$1 is the date at which the notification has been dispatched and $2 is the link to the snap that dispatched the notification." + "notificationsFeatureToggleDescription": { + "message": "これにより、資金やNFTのやり取りなどに関するウォレットの通知と、機能に関するお知らせが有効になります。", + "description": "Description of the experimental notifications feature" }, "notificationsMarkAllAsRead": { "message": "すべて既読にする" }, - "notificationsOpenBetaSnapsActionText": { - "message": "詳細" + "notificationsPageEmptyTitle": { + "message": "ここに表示する内容はありません" + }, + "notificationsPageErrorContent": { + "message": "このページにもう一度アクセスしてみてください" + }, + "notificationsPageErrorTitle": { + "message": "エラーが発生しました" }, - "notificationsOpenBetaSnapsDescriptionOne": { - "message": "🎉 MetaMask Snapsのオープンベータについてお知らせします!" + "notificationsPageNoNotificationsContent": { + "message": "まだ通知を受け取っていません。" }, - "notificationsOpenBetaSnapsDescriptionThree": { - "message": "開発者コミュニティによって開発されたsnapで、ウォレットをカスタマイズできます!" + "notificationsSettingsBoxError": { + "message": "問題が発生しました。もう一度お試しください。" }, - "notificationsOpenBetaSnapsDescriptionTwo": { - "message": "Snapsを使えば、他のネットワークへの接続やトランザクションインサイトの表示、カスタム通知の取得など、MetaMaskでより多くのことができるようになります。" + "notificationsSettingsPageAllowNotifications": { + "message": "通知を使えば、ウォレットで何が起きているか常に把握できます。通知を使用するには、プロファイルを使用してデバイス間で一部の設定を同期します。$1" }, - "notificationsOpenBetaSnapsTitle": { - "message": "MetaMask Snapsのご紹介" + "notificationsSettingsPageAllowNotificationsLink": { + "message": "この機能を使用する際に当社がどのようにユーザーのプライバシーを保護するのか、ご覧ください。" }, "numberOfNewTokensDetectedPlural": { "message": "$1種類の新しいトークンがこのアカウントで見つかりました", @@ -2599,6 +3173,9 @@ "on": { "message": "オン" }, + "onboarding": { + "message": "オンボーディング" + }, "onboardingAdvancedPrivacyIPFSDescription": { "message": "IPFSゲートウェイにより、第三者がホスティングしているデータへのアクセスと表示が可能になります。カスタムIPFSゲートウェイを追加するか、引き続きデフォルトを使用できます。" }, @@ -2629,51 +3206,45 @@ "onboardingMetametricsAgree": { "message": "同意します" }, - "onboardingMetametricsAllowOptOut": { - "message": "いつでも設定からオプトアウトできるようにします" - }, - "onboardingMetametricsDataTerms": { - "message": "一般データ保護規則 (EU) 2016/679 の目的に従い、このデータは集約され匿名化されます。" - }, "onboardingMetametricsDescription": { - "message": "MetaMaskは、ユーザーによるMetaMaskの使用状況をより詳細に把握するため、使用データを収集したいと考えています。このデータは、使用状況に基づくサービスの改善を含め、サービスの提供を目的に使用されます。" + "message": "MetaMaskの改善を目的に、基本的な使用状況および診断データを収集したいと思います。ここで提供されるデータが販売されることはありません。" }, "onboardingMetametricsDescription2": { - "message": "MetaMaskは..." + "message": "指標を収集する際、常に次の条件が適用されます..." }, "onboardingMetametricsDisagree": { "message": "結構です" }, "onboardingMetametricsInfuraTerms": { - "message": "* MetaMaskでInfuraをデフォルトのRPCプロバイダーとして使用する場合、Infuraはトランザクションの送信時にユーザーのIPアドレスおよびイーサリアムウォレットアドレスを収集します。当社がこれらの情報を、システムによりこれら2つのデータが関連付けられる形で保管することはありません。データ収集の観点から見たMetaMaskとInfuraとのやり取りに関する詳細は、当社の最新の$1をご覧ください。当社のプライバシー慣行全般に関する詳細は、$2をご覧ください。", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" + "message": "このデータを他の目的に使用する際は、お知らせします。詳細は当社の$1をご覧ください。設定でいつでもオプトアウトできます。", + "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, "onboardingMetametricsInfuraTermsPolicy": { - "message": "こちらのプライバシーポリシー" - }, - "onboardingMetametricsInfuraTermsPolicyLink": { - "message": "こちら" + "message": "プライバシー ポリシー" }, "onboardingMetametricsModalTitle": { "message": "カスタムネットワークを追加" }, "onboardingMetametricsNeverCollect": { - "message": "サービスの提供に不要な情報 (キー、アドレス、トランザクションハッシュ、残高) を収集することは、$1", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 アプリのクリックやビューは保存されますが、その他の詳細 (ユーザーのパブリックアドレスなど) は保存されません。", + "description": "$1 represents `onboardingMetametricsNeverCollectEmphasis`" + }, + "onboardingMetametricsNeverCollectEmphasis": { + "message": "非公開:" }, "onboardingMetametricsNeverCollectIP": { - "message": "ユーザーの完全なIPアドレスを収集することは、$1*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 大まかな位置情報 (国や地域など) の検出にユーザーのIPアドレスが一時的に使用されますが、保存されることはありません。", + "description": "$1 represents `onboardingMetametricsNeverCollectIPEmphasis`" }, - "onboardingMetametricsNeverEmphasis": { - "message": "一切ありません" + "onboardingMetametricsNeverCollectIPEmphasis": { + "message": "一般:" }, "onboardingMetametricsNeverSellData": { - "message": "データを販売することは$1。絶対です!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 使用状況データを共有するか削除するかは、設定でいつでも指定できます。", + "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" }, - "onboardingMetametricsSendAnonymize": { - "message": "匿名のクリックおよびページ閲覧イベントを送信" + "onboardingMetametricsNeverSellDataEmphasis": { + "message": "任意:" }, "onboardingMetametricsTitle": { "message": "MetaMaskの改善にご協力ください" @@ -2714,15 +3285,26 @@ "onboardingPinExtensionTitle": { "message": "MetaMaskのインストールが完了しました!" }, + "onboardingPinMmiExtensionLabel": { + "message": "MetaMask Institutionalをピン留めする" + }, "onboardingUsePhishingDetectionDescription": { "message": "フィッシング検出アラートには$1との通信が必要です。jsDeliverはユーザーのIPアドレスにアクセスします。$2をご覧ください。", "description": "The $1 is the word 'jsDeliver', from key 'jsDeliver' and $2 is the words Privacy Policy from key 'privacyMsg', both separated here so that it can be wrapped as a link" }, + "onekey": { + "message": "OneKey" + }, "onlyAddTrustedNetworks": { "message": "悪意のあるネットワーク プロバイダーは、ブロックチェーンのステートを偽り、ユーザーのネットワークアクティビティを記録することがあります。信頼するカスタムネットワークのみを追加してください。" }, "onlyConnectTrust": { - "message": "信頼するサイトにのみ接続してください。" + "message": "信頼するサイトにのみ接続してください。$1", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." + }, + "openCustodianApp": { + "message": "$1アプリを開く", + "description": "The $1 is the name of the Custodian that will be open" }, "openFullScreenForLedgerWebHid": { "message": "全画面モードにしてLedgerを接続します。", @@ -2734,6 +3316,15 @@ "openSeaNew": { "message": "OpenSea" }, + "openSeaToBlockaidBtnLabel": { + "message": "Snapを閲覧" + }, + "openSeaToBlockaidDescription": { + "message": "このネットワークでセキュリティアラートが使用できなくなりました。Snapをインストールすると、セキュリティが向上する可能性があります。" + }, + "openSeaToBlockaidTitle": { + "message": "ご注意!" + }, "operationFailed": { "message": "操作に失敗しました" }, @@ -2777,6 +3368,9 @@ "password": { "message": "パスワード" }, + "passwordMmiTermsWarning": { + "message": "私は、MetaMask Institutionalがこのパスワードを復元できないことを理解しています。$1" + }, "passwordNotLongEnough": { "message": "パスワードの長さが足りません" }, @@ -2803,6 +3397,10 @@ "message": "秘密鍵の文字列をここに貼り付けます:", "description": "For importing an account from a private key" }, + "paymasterInUse": { + "message": "このトランザクションのガス代はペイマスターにより支払われます。", + "description": "Alert shown in transaction confirmation if paymaster in use." + }, "pending": { "message": "保留中" }, @@ -2816,18 +3414,26 @@ "message": "保留中のトランザクションが1件あります。", "description": "$1 is count of pending transactions" }, - "permissionRequest": { - "message": "許可のリクエスト" + "permissionDetails": { + "message": "アクセス許可の詳細" }, - "permissionRequestCapitalized": { + "permissionRequest": { "message": "許可のリクエスト" }, "permissionRequested": { "message": "現在リクエスト中" }, + "permissionRequestedForAccounts": { + "message": "$1に対して要求済み", + "description": "Permission cell status for requested permission including accounts, rendered as AvatarGroup which is $1." + }, "permissionRevoked": { "message": "この更新で取り消し" }, + "permissionRevokedForAccounts": { + "message": "この更新で$1に対して取り消し済み", + "description": "Permission cell status for revoked permission including accounts, rendered as AvatarGroup which is $1." + }, "permission_accessNamedSnap": { "message": "$1に接続。", "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." @@ -2836,6 +3442,10 @@ "message": "インターネットにアクセスします。", "description": "The description of the `endowment:network-access` permission." }, + "permission_accessNetworkDescription": { + "message": "$1によるインターネットへのアクセスを許可します。これは、サードパーティサーバーとのデータの送受信に使用されます。", + "description": "An extended description of the `endowment:network-access` permission. $1 is the snap name." + }, "permission_accessSnap": { "message": "$1 snapに接続します。", "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." @@ -2848,10 +3458,18 @@ "message": "定期的なアクションのスケジュール設定と実行。", "description": "The description for the `snap_cronjob` permission" }, + "permission_cronjobDescription": { + "message": "$1が一定の時刻、日付、または間隔で定期的に実行されるアクションを実行することを許可します。これは、時間依存のやり取りや通知のトリガーに使用されます。", + "description": "An extended description for the `snap_cronjob` permission. $1 is the snap name." + }, "permission_dialog": { "message": "MetaMaskにダイアログウィンドウを表示します。", "description": "The description for the `snap_dialog` permission" }, + "permission_dialogDescription": { + "message": "$1がカスタムテキスト、入力フィールド、アクションの承認・拒否ボタンを備えたMetaMaskポップアップを表示することを許可します。\nこれは、Snapのアラート、承認、オプトインフローなどの作成に使用されます。", + "description": "An extended description for the `snap_dialog` permission. $1 is the snap name." + }, "permission_ethereumAccounts": { "message": "アドレス、アカウント残高、アクティビティを表示して、承認するトランザクションを提案", "description": "The description for the `eth_accounts` permission" @@ -2860,30 +3478,138 @@ "message": "イーサリアムプロバイダーにアクセスします。", "description": "The description for the `endowment:ethereum-provider` permission" }, + "permission_ethereumProviderDescription": { + "message": "$1がブロックチェーンのデータを読み込みメッセージやトランザクションを提案するために、MetaMaskと直接通信することを許可します。", + "description": "An extended description for the `endowment:ethereum-provider` permission. $1 is the snap name." + }, + "permission_getEntropy": { + "message": "$1に固有の任意のキーを導出します。", + "description": "The description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getEntropyDescription": { + "message": "$1が、$1固有の任意のキーを公開せずに導出することを許可します。これらのキーはMetaMaskアカウントとは切り離されており、秘密鍵やシークレットリカバリーフレーズとは関連性がありません。他のSnapはこの情報にアクセスできません。", + "description": "An extended description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getLocale": { + "message": "言語設定の表示", + "description": "The description for the `snap_getLocale` permission" + }, + "permission_getLocaleDescription": { + "message": "$1がMetaMaskの言語設定にアクセスできるようにします。これは、$1のコンテンツをユーザーの言語にローカライズして表示するために使用されます。", + "description": "An extended description for the `snap_getLocale` permission. $1 is the snap name." + }, + "permission_homePage": { + "message": "カスタム画面の表示", + "description": "The description for the `endowment:page-home` permission" + }, + "permission_homePageDescription": { + "message": "$1がMetaMaskでカスタムホーム画面を表示することを許可します。これは、ユーザーインターフェース、構成、ダッシュボードに使用されます。", + "description": "An extended description for the `endowment:page-home` permission. $1 is the snap name." + }, + "permission_keyring": { + "message": "イーサリアムアカウントの追加と制御の要求を許可する", + "description": "The description for the `endowment:keyring` permission" + }, + "permission_keyringDescription": { + "message": "$1がアカウントの追加または削除のリクエストを受け取ることや、これらのアカウントの代理で署名やトランザクションを行うことを許可します。", + "description": "An extended description for the `endowment:keyring` permission. $1 is the snap name." + }, "permission_lifecycleHooks": { "message": "ライフサイクルフックを使用します。", "description": "The description for the `endowment:lifecycle-hooks` permission" }, + "permission_lifecycleHooksDescription": { + "message": "$1がライフサイクルフックを使用して、ライフサイクルの特定のタイミングでコードを実行することを許可します。", + "description": "An extended description for the `endowment:lifecycle-hooks` permission. $1 is the snap name." + }, "permission_manageAccounts": { "message": "イーサリアムアカウントを追加して管理します", "description": "The description for `snap_manageAccounts` permission" }, + "permission_manageAccountsDescription": { + "message": "$1がイーサリアムアカウントを追加または削除し、これらのアカウントでトランザクションや署名を行うことを許可します。", + "description": "An extended description for the `snap_manageAccounts` permission. $1 is the snap name." + }, + "permission_manageBip32Keys": { + "message": "$1アカウントの管理", + "description": "The description for the `snap_getBip32Entropy` permission. $1 is a derivation path, e.g. 'm/44'/0'/0' (secp256k1)'." + }, + "permission_manageBip44AndBip32KeysDescription": { + "message": "$1による要求されたネットワークでのアカウントおよび資産の管理を許可します。これらのアカウントはシークレットリカバリーフレーズを (公開せずに) 使用して導出およびバックアップされます。キーを導出できることで、$1はイーサリアム (EVM) だけでなく、様々なブロックチェーンプロトコルをサポートできるようになります。", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions. $1 is the snap name." + }, + "permission_manageBip44Keys": { + "message": "$1アカウントの管理", + "description": "The description for the `snap_getBip44Entropy` permission. $1 is the name of a protocol, e.g. 'Filecoin'." + }, "permission_manageState": { "message": "デバイスにデータを保管し管理します。", "description": "The description for the `snap_manageState` permission" }, + "permission_manageStateDescription": { + "message": "$1が暗号化を使用して安全にデータを保管、更新、取得することを許可します。他のSnapはこの情報にアクセスできません。", + "description": "An extended description for the `snap_manageState` permission. $1 is the snap name." + }, + "permission_nameLookup": { + "message": "ドメインとアドレス検索を提供します。", + "description": "The description for the `endowment:name-lookup` permission." + }, + "permission_nameLookupDescription": { + "message": "SnapがMetaMask UIのさまざまな部分でアドレスとドメイン検索の取得と表示を行うことを許可します。", + "description": "An extended description for the `endowment:name-lookup` permission." + }, "permission_notifications": { "message": "通知を表示します。", "description": "The description for the `snap_notify` permission" }, + "permission_notificationsDescription": { + "message": "$1がMetaMask内に通知を表示することを許可します。Snapは、行動を促す情報や緊急性の高い情報に関する短い通知テキストをトリガーできます。", + "description": "An extended description for the `snap_notify` permission. $1 is the snap name." + }, + "permission_rpc": { + "message": "$1が$2と直接やり取りすることを許可します。", + "description": "The description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescription": { + "message": "$1による$2へのメッセージの送信と$2からの応答の受信を許可します。", + "description": "An extended description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescriptionOriginList": { + "message": "$1および$2", + "description": "A list of allowed origins where $2 is the last origin of the list and $1 is the rest of the list separated by ','." + }, + "permission_signatureInsight": { + "message": "署名分析情報モーダルの表示。", + "description": "The description for the `endowment:signature-insight` permission" + }, + "permission_signatureInsightDescription": { + "message": "署名要求の承認前に、$1がモーダルを表示して署名要求に関する分析情報を提供することを許可します。これはフィッシング対策やセキュリティソリューションに使用されます。", + "description": "An extended description for the `endowment:signature-insight` permission. $1 is the snap name." + }, + "permission_signatureInsightOrigin": { + "message": "署名要求を開始したWebサイトの出所を表示する", + "description": "The description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission" + }, + "permission_signatureInsightOriginDescription": { + "message": "$1による署名要求を開始したWebサイトの出所 (URI) の確認を許可します。これは、フィッシング対策やセキュリティソリューションに使用されます。", + "description": "An extended description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission. $1 is the snap name." + }, "permission_transactionInsight": { "message": "トランザクションインサイトを取得して表示します。", "description": "The description for the `endowment:transaction-insight` permission" }, + "permission_transactionInsightDescription": { + "message": "$1によるトランザクションのデコードと、MetaMask UI内でのインサイトの表示を許可します。これは、フィッシング対策やセキュリティソリューションに使用されます。", + "description": "An extended description for the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_transactionInsightOrigin": { "message": "トランザクションを提案しているWebサイトの提供元を確認します", "description": "The description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission" }, + "permission_transactionInsightOriginDescription": { + "message": "$1が、トランザクションを提案するWebサイトの出所 (URI) を確認することを許可します。これは、フィッシング対策やセキュリティソリューションに使用されます。", + "description": "An extended description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_unknown": { "message": "不明な許可: $1", "description": "$1 is the name of a requested permission that is not recognized." @@ -2892,29 +3618,66 @@ "message": "$1 ($2) の公開鍵を表示します。", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a derivation path, e.g. 'm/44'/0'/0''. $2 is the elliptic curve name, e.g. 'secp256k1'." }, + "permission_viewBip32PublicKeysDescription": { + "message": "$2が、$1の公開鍵 (およびアドレス) を表示することを許可します。これは、アカウントや資産のコントロールを許可するものでは一切ありません。", + "description": "An extended description for the `snap_getBip32PublicKey` permission. $1 is a derivation path (name). $2 is the snap name." + }, "permission_viewNamedBip32PublicKeys": { "message": "$1の公開鍵を表示します。", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a name for the derivation path, e.g., 'Ethereum accounts'." }, + "permission_walletSwitchEthereumChain": { + "message": "次のネットワークに切り替えて使用します", + "description": "The label for the `wallet_switchEthereumChain` permission" + }, "permission_webAssembly": { "message": "WebAssemblyのサポート", "description": "The description of the `endowment:webassembly` permission." }, + "permission_webAssemblyDescription": { + "message": "$1がWebAssemblyを介して低レベルの実行環境にアクセスすることを許可します。", + "description": "An extended description of the `endowment:webassembly` permission. $1 is the snap name." + }, "permissions": { "message": "許可" }, - "permissionsTitle": { - "message": "許可" + "permissionsPageEmptyContent": { + "message": "ここに表示する内容はありません" }, - "permissionsTourDescription": { - "message": "ここで接続されたアカウントを見つけて許可の管理を行います" + "permissionsPageEmptySubContent": { + "message": "ここには、インストールされたSnapや接続されたサイトに付与したアクセス許可が表示されます。" + }, + "permissionsPageTourDescription": { + "message": "これは、接続されたサイトやインストールされたSnapに付与したアクセス許可を管理するための、コントロールパネルです。" + }, + "permissionsPageTourTitle": { + "message": "「接続済みのサイト」が「アクセス許可」に変更されました" }, "personalAddressDetected": { "message": "個人アドレスが検出されました。トークンコントラクトアドレスを入力してください。" }, + "petnamesEnabledToggle": { + "message": "ニックネームを許可する" + }, + "petnamesEnabledToggleDescription": { + "message": "これにより、すべてのアドレスにニックネームを割り当てられるようになります。可能な場合、やり取りがあるアドレスの名前が提案されます。" + }, + "pinExtensionDescription": { + "message": "拡張機能のメニューに移動し、MetaMask Institutionalをピン留めすると、スムーズにアクセスできます。" + }, + "pinExtensionTitle": { + "message": "拡張機能をピン留めする" + }, + "pinToTop": { + "message": "最上部にピン留め" + }, "pleaseConfirm": { "message": "確認してください" }, + "plusMore": { + "message": "他$1件", + "description": "$1 is the number of additional items" + }, "plusXMore": { "message": "その他$1件", "description": "$1 is a number of additional but unshown items in a list- this message will be shown in place of those items" @@ -2940,6 +3703,9 @@ "primaryCurrencySettingDescription": { "message": "チェーンのネイティブ通貨 (ETHなど) による値の表示を優先するには、「ネイティブ」を選択します。選択した法定通貨による値の表示を優先するには、「法定通貨」を選択します。" }, + "primaryType": { + "message": "基本型" + }, "priorityFee": { "message": "優先手数料" }, @@ -2960,6 +3726,18 @@ "message": "$1の秘密鍵", "description": "$1 represents the account name" }, + "privateKeyHidden": { + "message": "秘密鍵は非表示になっています", + "description": "Explains that the private key input is hidden" + }, + "privateKeyShow": { + "message": "秘密鍵の入力の表示・非表示を切り替えます", + "description": "Describes a toggle that is used to show or hide the private key input" + }, + "privateKeyShown": { + "message": "秘密鍵は表示されています", + "description": "Explains that the private key input is being shown" + }, "privateKeyWarning": { "message": "警告: この鍵は絶対に公開しないでください。秘密鍵を持つ人は誰でも、アカウントに保持されているアセットを盗むことができます。" }, @@ -2969,6 +3747,21 @@ "proceedWithTransaction": { "message": "それでも続行" }, + "productAnnouncements": { + "message": "製品に関するお知らせ" + }, + "profileSync": { + "message": "プロファイルの同期" + }, + "profileSyncConfirmation": { + "message": "プロファイルの同期をオフにすると、通知を受け取ることができなくなります。" + }, + "profileSyncDescription": { + "message": "MetaMaskが一部の設定をデバイス間で同期するために使用するプロファイルを作成します。これは通知の受取に必要です。$1。" + }, + "profileSyncPrivacyLink": { + "message": "当社がどのようにユーザーのプライバシーを保護するのか、ご覧ください" + }, "proposedApprovalLimit": { "message": "提案された承認限度額" }, @@ -2978,6 +3771,78 @@ "publicAddress": { "message": "パブリックアドレス" }, + "pushPlatformNotificationsFundsReceivedDescription": { + "message": "$1 $2を受け取りました" + }, + "pushPlatformNotificationsFundsReceivedDescriptionDefault": { + "message": "トークンを受け取りました" + }, + "pushPlatformNotificationsFundsReceivedTitle": { + "message": "資金の受領" + }, + "pushPlatformNotificationsFundsSentDescription": { + "message": "$1 $2を送りました" + }, + "pushPlatformNotificationsFundsSentDescriptionDefault": { + "message": "トークンを送りました" + }, + "pushPlatformNotificationsFundsSentTitle": { + "message": "資金の送付" + }, + "pushPlatformNotificationsNftReceivedDescription": { + "message": "新しいNFTを受け取りました" + }, + "pushPlatformNotificationsNftReceivedTitle": { + "message": "NFTの受領" + }, + "pushPlatformNotificationsNftSentDescription": { + "message": "NFTを送りました" + }, + "pushPlatformNotificationsNftSentTitle": { + "message": "NFTの送付" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedDescription": { + "message": "Lidoのステーキングが完了しました" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedTitle": { + "message": "ステーキング完了" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnDescription": { + "message": "Lidoのステークの出金準備ができました" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnTitle": { + "message": "ステークの出金準備完了" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedDescription": { + "message": "Lidoの出金が完了しました" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedTitle": { + "message": "出金完了" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedDescription": { + "message": "Lidoの出金リクエストが送信されました" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedTitle": { + "message": "出金のリクエスト" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedDescription": { + "message": "RocketPoolのステーキングが完了しました" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedTitle": { + "message": "ステーキング完了" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedDescription": { + "message": "RocketPoolのステーキングの解除が完了しました" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedTitle": { + "message": "ステーキングの解除完了" + }, + "pushPlatformNotificationsSwapCompletedDescription": { + "message": "MetaMaskスワップが完了しました" + }, + "pushPlatformNotificationsSwapCompletedTitle": { + "message": "スワップ完了" + }, "queued": { "message": "キュー待ち" }, @@ -2996,9 +3861,15 @@ "receive": { "message": "受取" }, + "receiveTokensCamelCase": { + "message": "トークンの受取" + }, "recipientAddressPlaceholder": { "message": "パブリックアドレス (0x) またはENS名を入力してください" }, + "recipientAddressPlaceholderFlask": { + "message": "パブリックアドレス (0x) またはドメイン名を入力してください" + }, "recommendedGasLabel": { "message": "推奨" }, @@ -3026,6 +3897,12 @@ "recoveryPhraseReminderTitle": { "message": "資産を守りましょう" }, + "redesignedConfirmationsEnabledToggle": { + "message": "改善された署名要求" + }, + "redesignedConfirmationsToggleDescription": { + "message": "この機能をオンにすると、強化された形式で署名要求が表示されます。" + }, "refreshList": { "message": "リストを更新" }, @@ -3068,15 +3945,30 @@ "removeJWTDescription": { "message": "このトークンを削除してよろしいですか?このトークンに割り当てられているすべてのアカウントが、同時に拡張機能から削除されます: " }, + "removeKeyringSnap": { + "message": "このSnapを削除すると、これらのアカウントがMetaMaskから削除されます:" + }, + "removeKeyringSnapToolTip": { + "message": "Snapはアカウントをコントロールするため、Snapを削除するとアカウントもMetaMaskから削除されますが、ブロックチェーン上から削除されることはありません。" + }, "removeNFT": { "message": "NFTを削除" }, + "removeNftErrorMessage": { + "message": "このNFTを削除できませんでした。" + }, "removeNftMessage": { "message": "NFTが削除されました!" }, "removeSnap": { "message": "snapを削除" }, + "removeSnapAccountDescription": { + "message": "続行すると、このアカウントはMetaMaskで使用できなくなります。" + }, + "removeSnapAccountTitle": { + "message": "アカウントを削除" + }, "removeSnapConfirmation": { "message": "$1を削除してよろしいですか?", "description": "$1 represents the name of the snap" @@ -3087,12 +3979,24 @@ "replace": { "message": "置き換え" }, + "reportIssue": { + "message": "問題を報告する" + }, "requestFlaggedAsMaliciousFallbackCopyReason": { "message": "セキュリティプロバイダーが追加情報を共有していません" }, "requestFlaggedAsMaliciousFallbackCopyReasonTitle": { "message": "リクエストが悪質なものとして分類されました" }, + "requestFrom": { + "message": "要求元" + }, + "requestFromInfo": { + "message": "これは署名を求めているサイトです。" + }, + "requestFromTransactionDescription": { + "message": "これが承認を要求しているサイトです。" + }, "requestMayNotBeSafe": { "message": "リクエストは安全でない可能性があります" }, @@ -3114,6 +4018,9 @@ "reset": { "message": "リセット" }, + "resetStates": { + "message": "ステートのリセット" + }, "resetWallet": { "message": "ウォレットをリセット" }, @@ -3196,9 +4103,15 @@ "message": "MetaMaskサポートがこの情報を尋ねることはありません。", "description": "The bolded texted in the second part of 'revealSeedWordsWarning'" }, + "revealSensitiveContent": { + "message": "機密のコンテンツを確認" + }, "revealTheSeedPhrase": { "message": "シードフレーズを確認" }, + "reviewAlerts": { + "message": "アラートを確認する" + }, "revokeAllTokensTitle": { "message": "すべての$1へのアクセスおよび転送許可を取り消しますか?", "description": "$1 is the symbol of the token for which the user is revoking approval" @@ -3249,6 +4162,9 @@ "searchAccounts": { "message": "アカウントを検索" }, + "searchTokens": { + "message": "トークンを検索" + }, "secretRecoveryPhrase": { "message": "シークレットリカバリーフレーズ" }, @@ -3265,7 +4181,8 @@ "message": "セキュリティアラート" }, "securityAlertsDescription": { - "message": "この機能は、ユーザーのプライバシーを守りつつ、トランザクションと署名リクエストをアクティブに確認することで、イーサリアムメインネットでの悪質な行為に対する警告を発します。ユーザーのデータはこのサービスを提供するサードパーティと共有されません。リクエストを承認する前に、必ず独自のデューデリジェンスを行ってください。この機能がすべての悪質な行為を検出するという保証はありません。" + "message": "この機能は、トランザクションと署名要求を能動的に確認し、悪質なアクティビティに関するアラートを発します。$1", + "description": "Link to learn more about security alerts" }, "securityAndPrivacy": { "message": "セキュリティとプライバシー" @@ -3355,6 +4272,9 @@ "selectAnAccountHelp": { "message": "MetaMask Institutionalで使用するカストディアンアカウントを選択します。" }, + "selectEnableDisplayMediaPrivacyPreference": { + "message": "NFTメディアの表示をオンにする" + }, "selectHdPath": { "message": "HDパスを選択" }, @@ -3376,18 +4296,41 @@ "send": { "message": "送金" }, + "sendAToken": { + "message": "トークンを送信" + }, "sendBugReport": { "message": "バグの報告をお送りください。" }, + "sendNoContactsConversionText": { + "message": "ここをクリック" + }, + "sendNoContactsDescription": { + "message": "連絡先を使用すると、別のアカウントに安全に何度もトランザクションを送信できます。連絡先を作成するには、$1", + "description": "$1 represents the action text 'click here'" + }, + "sendNoContactsTitle": { + "message": "まだ連絡先がありません" + }, + "sendSelectReceiveAsset": { + "message": "受け取るアラートを選択してください" + }, + "sendSelectSendAsset": { + "message": "送る資産を選択してください" + }, "sendSpecifiedTokens": { "message": "$1を送金", "description": "Symbol of the specified token" }, - "sendTo": { - "message": "送金先:" + "sendSwapSubmissionWarning": { + "message": "このボタンをクリックすると、直ちにスワップトランザクションが開始します。続ける前に、以下のトランザクションの詳細を確認してください。" }, - "sendTokens": { - "message": "トークンを送信" + "sendTokenAsToken": { + "message": "$1を$2として送金", + "description": "Used in the transaction display list to describe a swap and send. $1 and $2 are the symbols of tokens in involved in the swap." + }, + "sendingAsset": { + "message": "$1を送信中" }, "sendingDisabled": { "message": "ERC-1155 NFTアセットの送信は、まだサポートされていません。" @@ -3400,9 +4343,15 @@ "message": "警告: 資金の喪失に繋がる可能性のあるトークンコントラクトに送信しようとしています。$1", "description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning" }, + "sendingZeroAmount": { + "message": "0 $1を送ろうとしています" + }, "sepolia": { "message": "Sepoliaテストネットワーク" }, + "serviceWorkerKeepAlive": { + "message": "Service Worker Keep Alive" + }, "setAdvancedPrivacySettingsDetails": { "message": "MetaMaskはこれらの信頼できるサードパーティサービスを使用して、製品の使いやすさと安全性を向上させています。" }, @@ -3422,9 +4371,21 @@ "settingsSearchMatchingNotFound": { "message": "一致する結果が見つかりませんでした。" }, + "settingsSubHeadingSignaturesAndTransactions": { + "message": "署名およびトランザクション要求" + }, "show": { "message": "表示" }, + "showAccount": { + "message": "アカウントを表示" + }, + "showExtensionInFullSizeView": { + "message": "拡張機能をフルサイズで表示" + }, + "showExtensionInFullSizeViewDescription": { + "message": "この機能をオンにすると、拡張機能アイコンをクリックした時にフルサイズ表示がデフォルトになります。" + }, "showFiatConversionInTestnets": { "message": "テストネット上に換算レートを表示" }, @@ -3444,6 +4405,9 @@ "message": "これは、ユーザーのイーサリアムアドレスおよびIPアドレスにアクセスする$1に依存します。$2", "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" }, + "showIncomingTransactionsExplainer": { + "message": "これは、ネットワークごとに異なるサードパーティAPIに依存します。これにより、イーサリアムアドレスとIPアドレスが公開されます。" + }, "showMore": { "message": "他を表示" }, @@ -3483,9 +4447,46 @@ "signin": { "message": "サインイン" }, + "signing": { + "message": "署名" + }, + "simulationDetailsFailed": { + "message": "予測結果の読み込み中にエラーが発生しました。" + }, + "simulationDetailsFiatNotAvailable": { + "message": "利用できません" + }, + "simulationDetailsIncomingHeading": { + "message": "受取額" + }, + "simulationDetailsNoBalanceChanges": { + "message": "ウォレット残高の増減は予測されていません" + }, + "simulationDetailsOutgoingHeading": { + "message": "送金額" + }, + "simulationDetailsTitle": { + "message": "予測される増減額" + }, + "simulationDetailsTitleTooltip": { + "message": "予測される変化は、このトランザクションを実行すると起きる可能性がある変化です。これは単に予測に過ぎず、保証されたものではありません。" + }, + "simulationDetailsTotalFiat": { + "message": "合計 = $1", + "description": "$1 is the total amount in fiat currency on one side of the transaction" + }, + "simulationDetailsTransactionReverted": { + "message": "このトランザクションはおそらく失敗します" + }, "simulationErrorMessageV2": { "message": "ガス代を見積もることができませんでした。コントラクトにエラーがある可能性があり、このトランザクションは失敗するかもしれません。" }, + "simulationsSettingDescription": { + "message": "トランザクションを確定する前に残高の増減を予測するには、この機能をオンにします。これはトランザクションの最終的な結果を保証するものではありません。$1" + }, + "simulationsSettingSubHeader": { + "message": "予測される残高の増減" + }, "skip": { "message": "スキップ" }, @@ -3498,20 +4499,99 @@ "smartContracts": { "message": "スマートコントラクト" }, - "smartSwapsAreHere": { - "message": "スマートスワップの登場です!" - }, - "smartSwapsDescription": { - "message": "MetaMask Swapsがはるかに賢くなりました!スマートスワップを有効にすると、MetaMaskがプログラムに従ってスワップを最適化できるようになるため、以下のようなメリットがあります。" - }, "smartSwapsErrorNotEnoughFunds": { "message": "スマートスワップに必要な資金が不足しています。" }, "smartSwapsErrorUnavailable": { "message": "スマートスワップは一時的にご利用いただけません。" }, + "smartTransactionCancelled": { + "message": "トランザクションがキャンセルされました" + }, + "smartTransactionCancelledDescription": { + "message": "トランザクションを完了できなかったため、不要なガス代の支払いを避けるためにキャンセルされました。" + }, + "smartTransactionError": { + "message": "トランザクションに失敗しました" + }, + "smartTransactionErrorDescription": { + "message": "突然の市場の変化により失敗する場合があります。問題が解決されない場合は、MetaMaskカスタマーサポートにお問い合わせください。" + }, + "smartTransactionPending": { + "message": "トランザクションを送信中" + }, + "smartTransactionSuccess": { + "message": "トランザクションが完了しました" + }, + "smartTransactionTakingTooLong": { + "message": "お待たせして申し訳ございません" + }, + "smartTransactionTakingTooLongDescription": { + "message": "$1以内にトランザクションが完了しない場合はキャンセルされ、ガス代は請求されません。", + "description": "$1 is remaining time in seconds" + }, + "smartTransactions": { + "message": "スマートトランザクション" + }, + "smartTransactionsBenefit1": { + "message": "99.5%の成功率" + }, + "smartTransactionsBenefit2": { + "message": "お金を節約できます" + }, + "smartTransactionsBenefit3": { + "message": "リアルタイムの最新情報" + }, + "smartTransactionsDescription": { + "message": "スマートトランザクションで、成功率を上げ、フロントランニングを防ぎ、可視性を高めましょう。" + }, + "smartTransactionsDescription2": { + "message": "イーサリアムでのみご利用いただけ、いつでも設定で有効・無効を切り替えられます。$1", + "description": "$1 is an external link to learn more about Smart Transactions" + }, + "smartTransactionsOptItModalTitle": { + "message": "強化されたトランザクション保護" + }, + "snapAccountCreated": { + "message": "アカウントが作成されました" + }, + "snapAccountCreatedDescription": { + "message": "新しいアカウントの使用準備ができました!" + }, + "snapAccountCreationFailed": { + "message": "アカウントの作成に失敗しました" + }, + "snapAccountCreationFailedDescription": { + "message": "$1はアカウントを作成できませんでした。", + "description": "$1 is the snap name" + }, + "snapAccountRedirectFinishSigningTitle": { + "message": "署名を完了させる" + }, + "snapAccountRedirectSiteDescription": { + "message": "$1の指示に従ってください" + }, + "snapAccountRemovalFailed": { + "message": "アカウントの削除に失敗しました" + }, + "snapAccountRemovalFailedDescription": { + "message": "$1がこのアカウントを削除できませんでした。", + "description": "$1 is the snap name" + }, + "snapAccountRemoved": { + "message": "アカウントが削除されました" + }, + "snapAccountRemovedDescription": { + "message": "このアカウントはMetaMaskで使用できなくなります。" + }, + "snapAccounts": { + "message": "アカウントSnap" + }, + "snapAccountsDescription": { + "message": "サードパーティSnapが制御するアカウント" + }, "snapConnectionWarning": { - "message": "$1が$2への接続を要求しています。このWebサイトが信頼できる場合にのみ続行してください。", + "message": "$1が$2の使用を求めています", "description": "$2 is the snap and $1 is the dapp requesting connection to the snap." }, "snapContent": { @@ -3522,15 +4602,35 @@ "message": "Webサイト" }, "snapInstallRequest": { - "message": "$1をインストールすることで、次のアクセス許可が付与されます。$1を信頼できる場合にのみ続行してください。", + "message": "$1をインストールすると、次のアクセス許可が付与されます。", "description": "$1 is the snap name." }, "snapInstallSuccess": { "message": "インストール完了" }, + "snapInstallWarningCheck": { + "message": "$1が次の許可を求めています:", + "description": "Warning message used in popup displayed on snap install. $1 is the snap name." + }, "snapInstallWarningHeading": { "message": "慎重に進めてください" }, + "snapInstallWarningPermissionDescriptionForBip32View": { + "message": "$1が公開鍵 (およびアドレス) を表示することを許可します。これは、アカウントや資産のコントロールを許可するものでは一切ありません。", + "description": "An extended description for the `snap_getBip32PublicKey` permission used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionDescriptionForEntropy": { + "message": "$1 Snapによる要求されたネットワークでのアカウントおよび資産の管理を許可します。これらのアカウントはシークレットリカバリーフレーズを (公開せずに) 使用して導出およびバックアップされます。キーを導出できることで、$1はイーサリアム (EVM) だけでなく、様々なブロックチェーンプロトコルをサポートできるようになります。", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionNameForEntropy": { + "message": "$1アカウントの管理", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, + "snapInstallWarningPermissionNameForViewPublicKey": { + "message": "$1の公開鍵の表示", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, "snapInstallationErrorDescription": { "message": "$1をインストールできませんでした。", "description": "Error description used when snap installation fails. $1 is the snap name." @@ -3548,6 +4648,10 @@ "snapResultSuccessDescription": { "message": "$1を使用する準備が整いました" }, + "snapUpdateAlertDescription": { + "message": "$1の最新バージョンを入手", + "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." + }, "snapUpdateAvailable": { "message": "アップデートが利用できます" }, @@ -3559,22 +4663,40 @@ "message": "更新失敗", "description": "Error title used when snap update fails." }, + "snapUpdateRequest": { + "message": "$1をアップデートすると、次のアクセス許可が付与されます。", + "description": "$1 is the Snap name." + }, "snapUpdateSuccess": { "message": "更新完了" }, + "snapUrlIsBlocked": { + "message": "このSnapがブロックされたサイトに移動しようとしています。$1。" + }, "snaps": { "message": "Snaps" }, - "snapsInvalidUIError": { - "message": "snapに指定されたUIが無効です。" + "snapsConnected": { + "message": "Snapが接続されました" }, "snapsNoInsight": { "message": "snapがインサイトを返しませんでした" }, + "snapsPrivacyWarningFirstMessage": { + "message": "ユーザーは、別途特定されていない限り、インストールするSnapがConsensys$1で定義されているサードパーティサービスであることを認めたものとみなされます。サードパーティサービスの使用には、当該サードパーティサービスプロバイダーにより定められた、別の諸条件が適用されます。Consensysは、いかなる理由であっても、特定の人物によるSnapの使用を一切推奨しません。サードパーティサービスへのアクセス、依存、使用は、ユーザーの自己責任で行うものとします。Consensysは、サードパーティサービスの使用によりアカウントで発生する損失について、一切責任および賠償責任を負いません。", + "description": "First part of a message in popup modal displayed when installing a snap for the first time. $1 is terms of use link." + }, "snapsPrivacyWarningSecondMessage": { "message": "サードパーティサービスと共有する情報は、当該サードパーティサービスにより、それぞれのプライバシーポリシーに従い直接収集されます。詳細は、各サードパーティサービスのプライバシーポリシーをご覧ください。", "description": "Second part of a message in popup modal displayed when installing a snap for the first time." }, + "snapsPrivacyWarningThirdMessage": { + "message": "Consensysは、ユーザーがサードパーティと共有した情報に一切アクセスできません。", + "description": "Third part of a message in popup modal displayed when installing a snap for the first time." + }, + "snapsSettings": { + "message": "Snapの設定" + }, "snapsTermsOfUse": { "message": "利用規約" }, @@ -3588,12 +4710,19 @@ "someNetworksMayPoseSecurity": { "message": "ネットワークによっては、セキュリティやプライバシーの面でリスクが伴う可能性があります。ネットワークを追加・使用する前にリスクを理解するようにしてください。" }, + "somethingDoesntLookRight": { + "message": "何か不審な点があれば、$1", + "description": "A false positive message for users to contact support. $1 is a link to the support page." + }, "somethingIsWrong": { "message": "エラーが発生しました。ページを再度読み込んでみてください。" }, "somethingWentWrong": { "message": "申し訳ありません。問題が発生しました。" }, + "source": { + "message": "ソース" + }, "speedUp": { "message": "高速化" }, @@ -3728,6 +4857,14 @@ "stake": { "message": "ステーク" }, + "startYourJourney": { + "message": "$1で利用開始", + "description": "$1 is the token symbol" + }, + "startYourJourneyDescription": { + "message": "ウォレットに$1を追加してWeb3の利用を開始します。", + "description": "$1 is the token symbol" + }, "stateLogError": { "message": "ステートログの取得中にエラーが発生しました。" }, @@ -3740,6 +4877,9 @@ "stateLogsDescription": { "message": "ステートログには、パブリックアカウントアドレスと送信済みトランザクションが含まれています。" }, + "states": { + "message": "ステート" + }, "status": { "message": "ステータス" }, @@ -3783,18 +4923,6 @@ "strong": { "message": "強" }, - "stxBenefit1": { - "message": "トランザクションコストを最小化" - }, - "stxBenefit2": { - "message": "トランザクションの失敗数を低減" - }, - "stxBenefit3": { - "message": "トランザクションの停滞を解消" - }, - "stxBenefit4": { - "message": "フロントランニングを防止" - }, "stxCancelled": { "message": "スワップが失敗するところでした" }, @@ -3804,6 +4932,10 @@ "stxCancelledSubDescription": { "message": "もう一度スワップをお試しください。次回は同様のリスクを避けられるようサポートします。" }, + "stxEstimatedCompletion": { + "message": "$1未満で完了予定", + "description": "$1 is remeaning time in minutes and seconds, e.g. 0:10" + }, "stxFailure": { "message": "スワップに失敗しました" }, @@ -3811,6 +4943,9 @@ "message": "突然の市場変動が失敗の原因になります。問題が解決されないようでしたら、$1にお問い合わせください。", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInDescription": { + "message": "スマートトランザクションをオンにして、イーサリアムメインネット上でのトランザクションの信頼性と安全性を高めましょう。$1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "スワップを非公開で送信中..." }, @@ -3849,12 +4984,21 @@ "submitted": { "message": "送信済み" }, + "suggestedTokenSymbol": { + "message": "推奨ティッカーシンボル:" + }, "support": { "message": "サポート" }, "supportCenter": { "message": "サポートセンターをご利用ください" }, + "surveyConversion": { + "message": "アンケートに回答する" + }, + "surveyTitle": { + "message": "MetaMaskの未来を形作りましょう" + }, "swap": { "message": "スワップ" }, @@ -3874,6 +5018,9 @@ "swapAmountReceivedInfo": { "message": "これは受け取る最低額です。スリッページによりそれ以上の額を受け取ることもあります。" }, + "swapAndSend": { + "message": "スワップして送金" + }, "swapAnyway": { "message": "スワップを続ける" }, @@ -3989,6 +5136,10 @@ "message": "$1%のMetaMask手数料が含まれています。", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." }, + "swapIncludesMMFeeAlt": { + "message": "クォートには$1%のMetaMask手数料が含まれています", + "description": "Provides information about the fee that metamask takes for swaps using the latest copy. $1 is a decimal number." + }, "swapIncludesMetaMaskFeeViewAllQuotes": { "message": "$1%のMetaMask手数料が含まれています – $2", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number and $2 is a link to view all quotes." @@ -3996,6 +5147,9 @@ "swapLearnMore": { "message": "Swapsの詳細" }, + "swapLiquiditySourceInfo": { + "message": "弊社は、為替レートとネットワーク手数料を比較するために、複数の流動性供給源 (取引所、アグリゲーター、専門のマーケットメーカー) を検索します。" + }, "swapLowSlippage": { "message": "低スリッページ" }, @@ -4268,6 +5422,9 @@ "switchEthereumChainConfirmationTitle": { "message": "このサイトによるネットワークの切り替えを許可しますか?" }, + "switchInputCurrency": { + "message": "通貨の変更" + }, "switchNetwork": { "message": "ネットワークを切り替える" }, @@ -4281,14 +5438,15 @@ "switchToThisAccount": { "message": "このアカウントに切り替える" }, - "switchedTo": { - "message": "次に切り替えました:" + "switchedNetworkToastDecline": { + "message": "今後表示しない" }, - "switcherTitle": { - "message": "ネットワークスイッチャー" + "switchedNetworkToastMessage": { + "message": "$1が$2で有効になりました", + "description": "$1 represents the account name, $2 represents the network name" }, - "switcherTourDescription": { - "message": "アイコンをクリックしてネットワークを切り替えるか、新しいネットワークを追加します" + "switchedTo": { + "message": "次に切り替えました:" }, "switchingNetworksCancelsPendingConfirmations": { "message": "ネットワークを切り替えると、保留中の承認がすべてキャンセルされます" @@ -4388,6 +5546,18 @@ "toggleEthSignOn": { "message": "オン (非推奨)" }, + "toggleRequestQueueDescription": { + "message": "これにより、選択した単一のネットワークをすべてのサイトで使用するのではなく、サイトごとにネットワークを選択できます。この機能により、特定のサイトでのユーザーエクスペリエンスの妨げとなる、ネットワークの手動切り替えが不要になります。" + }, + "toggleRequestQueueField": { + "message": "サイトごとにネットワークを選択する" + }, + "toggleRequestQueueOff": { + "message": "オフ" + }, + "toggleRequestQueueOn": { + "message": "オン" + }, "token": { "message": "トークン" }, @@ -4404,7 +5574,7 @@ "message": "トークンコントラクトアドレス" }, "tokenDecimalFetchFailed": { - "message": "トークンの10進数が必要です。" + "message": "トークンの小数点以下の桁数が必要です。確認はこちら: $1" }, "tokenDecimalTitle": { "message": "トークンの小数桁数:" @@ -4443,6 +5613,9 @@ "tooltipSatusConnected": { "message": "接続済み" }, + "tooltipSatusConnectedUpperCase": { + "message": "接続済み" + }, "tooltipSatusNotConnected": { "message": "未接続" }, @@ -4583,6 +5756,39 @@ "tryAgain": { "message": "再試行" }, + "turnOff": { + "message": "オフにする" + }, + "turnOffMetamaskNotificationsError": { + "message": "通知を無効化する際にエラーが発生しました。後でもう一度お試しください。" + }, + "turnOn": { + "message": "オンにする" + }, + "turnOnMetamaskNotifications": { + "message": "通知をオンにする" + }, + "turnOnMetamaskNotificationsButton": { + "message": "オンにする" + }, + "turnOnMetamaskNotificationsError": { + "message": "通知の作成中にエラーが発生しました。後でもう一度お試しください。" + }, + "turnOnMetamaskNotificationsMessageFirst": { + "message": "通知を使えば、ウォレットで何が起きているか常に把握できます。" + }, + "turnOnMetamaskNotificationsMessagePrivacyBold": { + "message": "「設定」>「通知」。" + }, + "turnOnMetamaskNotificationsMessagePrivacyLink": { + "message": "この機能を使用する際に当社がどのようにユーザーのプライバシーを保護するのか、ご覧ください。" + }, + "turnOnMetamaskNotificationsMessageSecond": { + "message": "ウォレット通知を使用するために、プロファイルを使用して一部の設定をデバイス間で同期します。$1" + }, + "turnOnMetamaskNotificationsMessageThird": { + "message": "通知は$1でいつでもオフにできます" + }, "turnOnTokenDetection": { "message": "強化されたトークン検出をオンにする" }, @@ -4614,6 +5820,10 @@ "unknownNetwork": { "message": "不明なプライベートネットワーク" }, + "unknownNetworkForKeyEntropy": { + "message": "不明なネットワーク", + "description": "Displayed on places like Snap install warning when regular name is not available." + }, "unknownQrCode": { "message": "エラー: QRコードを識別できませんでした" }, @@ -4626,6 +5836,9 @@ "unlockMessage": { "message": "分散型インターネットが待っています" }, + "unpin": { + "message": "ピン留めを解除" + }, "unrecognizedChain": { "message": "このカスタムネットワークは認識されていません", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." @@ -4643,6 +5856,9 @@ "update": { "message": "更新" }, + "updateRequest": { + "message": "更新リクエスト" + }, "updatedWithDate": { "message": "$1が更新されました" }, @@ -4667,12 +5883,25 @@ "useNftDetection": { "message": "NFTを自動検出" }, + "useNftDetectionDescriptionText": { + "message": "MetaMaskが、サードパーティサービス (例: OpenSea) を使って、ユーザーが所有するNFTを追加することを許可します。NFTの自動検出機能を利用すると、ユーザーのIPとアカウントアドレスがこれらのサービスに公開されます。この機能を有効にした場合、ユーザーのIPアドレスとイーサリアムアドレスが紐付けられ、詐欺師によりエアドロップされた偽のNFTが表示される可能性があります。このリスクを回避するため、手動でトークンを追加することもできます。" + }, "usePhishingDetection": { "message": "フィッシング検出を使用" }, "usePhishingDetectionDescription": { "message": "イーサリアムユーザーを対象としたドメインのフィッシングに対して警告を表示します" }, + "useSafeChainsListValidation": { + "message": "ネットワーク情報の確認" + }, + "useSafeChainsListValidationDescription": { + "message": "MetaMaskは$1というサードパーティサービスを利用して、正確かつ標準化されたネットワーク情報を表示しています。これにより、悪質なネットワークや正しくないネットワークに接続してしまう可能性が減ります。この機能を使用すると、ユーザーのIPアドレスがchainid.networkに公開されます。" + }, + "useSafeChainsListValidationWebsite": { + "message": "chainid.network", + "description": "useSafeChainsListValidationWebsite is separated from the rest of the text so that we can bold the third party service name in the middle of them" + }, "useSiteSuggestion": { "message": "サイトの提案を使用" }, @@ -4685,6 +5914,9 @@ "userName": { "message": "ユーザー名" }, + "userOpContractDeployError": { + "message": "スマートコントラクトアカウントからのコントラクトの展開はサポートされていません" + }, "verifyContractDetails": { "message": "サードパーティの詳細を確認" }, @@ -4702,6 +5934,9 @@ "view": { "message": "表示" }, + "viewActivity": { + "message": "アクティビティを表示" + }, "viewAllDetails": { "message": "すべての詳細の表示" }, @@ -4725,7 +5960,7 @@ }, "viewOnCustomBlockExplorer": { "message": "$1を$2で表示", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "$1をEtherscanで表示", @@ -4737,6 +5972,9 @@ "viewOnOpensea": { "message": "Openseaで表示" }, + "viewTransaction": { + "message": "トランザクションを表示" + }, "viewinCustodianApp": { "message": "カストディアンアプリで表示" }, @@ -4744,6 +5982,9 @@ "message": "$1をエクスプローラーで表示", "description": "$1 is the action type. e.g (Account, Transaction, Swap)" }, + "visitSite": { + "message": "サイトにアクセス" + }, "visitWebSite": { "message": "弊社Webサイトにアクセス" }, @@ -4782,6 +6023,10 @@ "warning": { "message": "警告" }, + "warningFromSnap": { + "message": "$1からの警告", + "description": "$1 represents the name of the snap" + }, "warningTooltipText": { "message": "$1 このサードパーティは今後、通知や承諾なしにトークン残高全額を使用できます。使用上限をより低い金額にカスタマイズして、自分の身を守りましょう。", "description": "$1 is a warning icon with text 'Be careful' in 'warning' colour" @@ -4789,6 +6034,9 @@ "weak": { "message": "弱" }, + "web3": { + "message": "Web3" + }, "web3ShimUsageNotification": { "message": "現在のWebサイトが、削除済みのwindow.web3 APIの使用を検知しました。サイトが破損しているようであれば、$1をクリックして詳細を確認してください。", "description": "$1 is a clickable link." @@ -4829,10 +6077,6 @@ "whatsThis": { "message": "これは何ですか?" }, - "xOfY": { - "message": "$2中の$1", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$2件中$1件が保留中", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" @@ -4840,6 +6084,9 @@ "yes": { "message": "はい" }, + "you": { + "message": "ユーザー" + }, "youHaveAddedAll": { "message": "すべての人気ネットワークを追加しました。$1で他のネットワークを発見するか、$2できます。", "description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'" @@ -4862,6 +6109,12 @@ "yourPrivateSeedPhrase": { "message": "シークレットリカバリーフレーズ" }, + "yourTransactionConfirmed": { + "message": "トランザクションはすでに確定済みです" + }, + "yourTransactionJustConfirmed": { + "message": "ブロックチェーン上で確定しているため、トランザクションをキャンセルできませんでした。" + }, "zeroGasPriceOnSpeedUpError": { "message": "高速化用のガス価格がゼロです" } diff --git a/app/_locales/kn/messages.json b/app/_locales/kn/messages.json index a31a5abe1882..0e44c06e69ce 100644 --- a/app/_locales/kn/messages.json +++ b/app/_locales/kn/messages.json @@ -630,9 +630,6 @@ "send": { "message": "ಕಳುಹಿಸು" }, - "sendTokens": { - "message": "ಟೋಕನ್‌ಗಳನ್ನು ಕಳುಹಿಸಿ" - }, "settings": { "message": "ಸೆಟ್ಟಿಂಗ್‌ಗಳು" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index 668779dfc90d..af94a9026392 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -130,12 +130,21 @@ "account": { "message": "계정" }, + "accountActivity": { + "message": "계정 활동" + }, + "accountActivityText": { + "message": "알림을 수신할 계정을 선택하세요." + }, "accountDetails": { "message": "계정 세부 정보" }, "accountIdenticon": { "message": "계정 식별 아이콘" }, + "accountIsntConnectedToastText": { + "message": "$1은(는) $2에 연결되지 않았습니다" + }, "accountName": { "message": "계정 이름" }, @@ -153,6 +162,12 @@ "accountSelectionRequired": { "message": "계정을 선택해야 합니다!" }, + "accounts": { + "message": "계정" + }, + "accountsConnected": { + "message": "계정 연결됨" + }, "active": { "message": "활성" }, @@ -243,6 +258,9 @@ "addIPFSGateway": { "message": "선호하는 IPFS 게이트웨이를 추가하세요" }, + "addImportAccount": { + "message": "계정 또는 하드웨어 지갑 추가" + }, "addMemo": { "message": "메모 추가" }, @@ -256,6 +274,9 @@ "message": "이 네트워크 연결은 타사 서비스를 이용합니다. 연결의 보안이 취약하거나 타사에 연결 내용이 노출될 수 있습니다. $1", "description": "$1 is Learn more link" }, + "addNewAccount": { + "message": "새 계정 추가" + }, "addNewToken": { "message": "신규 토큰 추가" }, @@ -265,6 +286,12 @@ "addNfts": { "message": "NFT 추가" }, + "addSnapAccountToggle": { + "message": "\"계정 Snap 추가(베타)\" 활성화" + }, + "addSnapAccountsDescription": { + "message": "이 기능을 사용하면 계정 목록에서 바로 새 베타 계정 Snap을 추가할 수 있습니다. 설치하는 계정 Snap은 타사 서비스라는 점을 명심하세요." + }, "addSuggestedNFTs": { "message": "추천 NFT 추가" }, @@ -281,6 +308,9 @@ "addingCustomNetwork": { "message": "네트워크 추가" }, + "addingTokens": { + "message": "토큰 추가" + }, "address": { "message": "주소" }, @@ -316,9 +346,27 @@ "airgapVault": { "message": "에어갭 볼트" }, + "alert": { + "message": "경고" + }, + "alertBannerMultipleAlertsDescription": { + "message": "이 요청을 승인하면 스캠을 목적으로 하는 제3자가 회원님의 자산을 모두 가져갈 수 있습니다." + }, + "alertBannerMultipleAlertsTitle": { + "message": "여러 경고!" + }, "alertDisableTooltip": { "message": "\"설정 > 경고\"에서 변경할 수 있습니다" }, + "alertModalAcknowledge": { + "message": "위험성을 인지했으며, 계속 진행합니다" + }, + "alertModalDetails": { + "message": "경고 세부 사항" + }, + "alertModalReviewAllAlerts": { + "message": "모든 경고 검토하기" + }, "alertSettingsUnconnectedAccount": { "message": "연결되지 않은 계정을 선택하여 웹사이트 탐색" }, @@ -334,6 +382,9 @@ "alerts": { "message": "경고" }, + "all": { + "message": "모두" + }, "allCustodianAccountsConnectedSubtitle": { "message": "현재 모든 수탁 계정이 연결되어 있거나 MetaMask Institutional에 연결할 계정이 없습니다." }, @@ -344,23 +395,26 @@ "message": "내 모든 $1", "description": "$1 is the symbol or name of the token that the user is approving spending" }, + "allPermissions": { + "message": "모든 권한" + }, "allYourNFTsOf": { "message": "$1의 모든 내 NFT", "description": "$1 is a link to contract on the block explorer when we're not able to retrieve a erc721 or erc1155 name" }, - "allowExternalExtensionTo": { - "message": "이 외부 확장을 다음에 허용:" + "allow": { + "message": "허용" + }, + "allowMmiToConnectToCustodian": { + "message": "허용할 경우, MMI가 $1에 연결하여 계정을 가져올 수 있습니다." + }, + "allowNotifications": { + "message": "알림 허용" }, "allowSpendToken": { "message": "$1에 액세스할 수 있는 권한을 부여하시겠습니까?", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "다음에 이 사이트를 허용:" - }, - "allowThisSnapTo": { - "message": "다음에 이 스냅을 허용:" - }, "allowWithdrawAndSpend": { "message": "$1에서 다음 금액까지 인출 및 지출하도록 허용:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -368,6 +422,23 @@ "amount": { "message": "금액" }, + "amountReceived": { + "message": "수취 금액" + }, + "amountSent": { + "message": "송금액" + }, + "andForListItems": { + "message": "$1, 그리고 $2", + "description": "$1 is the first item, $2 is the last item in a list of items. Used in Snap Install Warning modal." + }, + "andForTwoItems": { + "message": "$1 및 $2", + "description": "$1 is the first item, $2 is the second item. Used in Snap Install Warning modal." + }, + "announcements": { + "message": "공지" + }, "appDescription": { "message": "브라우저의 이더리움 지갑", "description": "The description of the application" @@ -402,6 +473,10 @@ "approveButtonText": { "message": "승인" }, + "approveIncreaseAllowance": { + "message": "지출 한도 $1 증액", + "description": "The token symbol that is being approved" + }, "approveSpendingCap": { "message": "$1 지출 한도 승인", "description": "The token symbol that is being approved" @@ -427,6 +502,10 @@ "message": "$1에 승인", "description": "$1 is the approval date for a permission" }, + "approvedOnForAccounts": { + "message": "$2 관련하여 $1에 승인됨", + "description": "$1 is the approval date for a permission. $2 is the AvatarGroup component displaying account images." + }, "areYouSure": { "message": "확실한가요?" }, @@ -439,6 +518,12 @@ "attemptSendingAssets": { "message": "한 네트워크에서 다른 네트워크로 자산을 직접 전송하면 자산이 영구적으로 손실될 수 있습니다. 반드시 브릿지를 이용하세요." }, + "attemptSendingAssetsWithPortfolio": { + "message": "다른 네트워크에서 자산을 전송하려고 하면 자산이 손실될 수 있습니다. $1 같은 브릿지를 사용하여 네트워크 간에 자산을 안전하게 전송하세요." + }, + "attemptToCancelSwapForFree": { + "message": "무료 스왑 취소 시도" + }, "attemptingConnect": { "message": "블록체인에 연결 중입니다." }, @@ -479,6 +564,9 @@ "backupApprovalNotice": { "message": "비밀복구구문을 백업하여 지갑과 자금을 안전하게 보호하세요." }, + "backupKeyringSnapReminder": { + "message": "제거하기 전에 이 Snap에서 생성한 계정에 직접 액세스할 수 있는지 확인하세요" + }, "backupNow": { "message": "지금 백업" }, @@ -486,7 +574,7 @@ "message": "데이터를 백업하세요" }, "backupUserDataDescription": { - "message": "기본 설정과 계정 주소가 포함된 사용자 설정을 JSON 파일로 백업할 수 있습니다." + "message": "기본 설정과 계약이 포함된 사용자 설정을 JSON 파일로 백업할 수 있습니다." }, "balance": { "message": "잔액" @@ -500,6 +588,30 @@ "basic": { "message": "기본" }, + "basicConfigurationBannerCTA": { + "message": "기본 기능 켜기" + }, + "basicConfigurationBannerTitle": { + "message": "기본 기능이 꺼져 있습니다." + }, + "basicConfigurationLabel": { + "message": "기본 기능" + }, + "basicConfigurationModalCheckbox": { + "message": "이해했습니다. 계속 진행하겠습니다" + }, + "basicConfigurationModalDisclaimerOff": { + "message": "이렇게 하면 MetaMask에서 시간을 완전히 최적화할 수 없습니다. 기본 기능(토큰 세부 정보, 최적의 가스 설정 등)을 사용할 수 없게 됩니다." + }, + "basicConfigurationModalDisclaimerOn": { + "message": "MetaMask에서 시간을 최적화하려면 이 기능을 켜야 합니다. 기본 기능(토큰 세부 정보, 최적의 가스 설정 등)은 웹3 경험에 중요한 요소입니다." + }, + "basicConfigurationModalHeadingOff": { + "message": "기본 기능 끄기" + }, + "basicConfigurationModalHeadingOn": { + "message": "기본 기능 켜기" + }, "beCareful": { "message": "주의하세요" }, @@ -571,6 +683,9 @@ "blockaidDescriptionTransferFarming": { "message": "이 요청을 승인하면 스캠과 같은 타사가 회원님의 모든 자산을 가져갈 수 있습니다." }, + "blockaidMessage": { + "message": "개인정보 보호 - 제3자와 데이터를 공유하지 않습니다. Arbitrum, Avalanche, BNB Chain, 이더리움 메인넷, Linea, Optimism, Polygon, Base, Sepolia에서 사용할 수 있습니다." + }, "blockaidTitleDeceptive": { "message": "사기성 요청입니다" }, @@ -586,6 +701,9 @@ "bridge": { "message": "브리지" }, + "bridgeDontSend": { + "message": "전송하지 마세요, 브릿지 하세요" + }, "browserNotSupported": { "message": "지원되지 않는 브라우저입니다..." }, @@ -598,6 +716,9 @@ "busy": { "message": "바쁨" }, + "buyAndSell": { + "message": "매수 및 매도" + }, "buyAsset": { "message": "$1 구매", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -609,6 +730,10 @@ "buyNow": { "message": "지금 구매" }, + "buyToken": { + "message": "$1 구매", + "description": "$1 is the token symbol" + }, "bytes": { "message": "바이트" }, @@ -618,9 +743,6 @@ "cancel": { "message": "취소" }, - "cancelEdit": { - "message": "편집 취소" - }, "cancelPopoverTitle": { "message": "트랜잭션 취소" }, @@ -647,6 +769,9 @@ "chainIdExistsErrorMsg": { "message": "이 체인 ID는 현재 $1 네트워크에서 사용됩니다." }, + "chainListReturnedDifferentTickerSymbol": { + "message": "이 토큰 심볼이 입력한 네트워크 이름 또는 체인 ID와 일치하지 않습니다. 여러 인기 토큰이 비슷한 심볼을 사용합니다. 사기꾼은 이를 이용해 더 가격이 높은 토큰을 보내도록 속일 수 있습니다. 계속하기 전에 모든 사항을 확인하세요." + }, "chooseYourNetwork": { "message": "네트워크 선택" }, @@ -682,9 +807,19 @@ "close": { "message": "닫기" }, + "closeExtension": { + "message": "확장 닫기" + }, + "closeWindowAnytime": { + "message": "언제든 이 창을 닫을 수 있습니다." + }, "coingecko": { "message": "CoinGecko" }, + "comboNoOptions": { + "message": "옵션을 찾을 수 없습니다", + "description": "Default text shown in the combo field dropdown if no options." + }, "configureSnapPopupDescription": { "message": "이제 이 스냅 구성을 위해 MetaMask 페이지를 떠나게 됩니다." }, @@ -703,12 +838,42 @@ "confirm": { "message": "컨펌" }, + "confirmAlertModalAcknowledge": { + "message": "경고를 인지했으며, 계속 진행합니다" + }, + "confirmAlertModalDetails": { + "message": "로그인하면 스캠을 목적으로 하는 제3자가 회원님의 자산을 모두 가져갈 수 있습니다. 계속하기 전에 경고를 검토하세요." + }, + "confirmAlertModalTitle": { + "message": "자산이 위험할 수 있습니다" + }, + "confirmConnectCustodianRedirect": { + "message": "계속을 클릭하면 $1(으)로 리디렉션됩니다." + }, + "confirmConnectCustodianText": { + "message": "계정을 연결하려면 $1에 로그인하여 'MMI에 연결' 버튼을 클릭하세요." + }, + "confirmConnectionTitle": { + "message": "$1에 연결 확인" + }, "confirmPassword": { "message": "비밀번호 컨펌" }, "confirmRecoveryPhrase": { "message": "비밀복구구문 컨펌" }, + "confirmTitleDescContractInteractionTransaction": { + "message": "요청하는 사이트를 신뢰하고 그 내용을 완전히 이해하는 경우에만 이 트랜젝션을 컨펌하세요." + }, + "confirmTitleDescSignature": { + "message": "요청하는 사이트를 신뢰하고 그 내용을 완전히 이해하는 경우에만 이 메시지를 컨펌하세요." + }, + "confirmTitleSignature": { + "message": "서명 요청" + }, + "confirmTitleTransaction": { + "message": "트랜젝션 요청" + }, "confirmed": { "message": "컨펌됨" }, @@ -724,9 +889,15 @@ "connect": { "message": "연결" }, + "connectAccount": { + "message": "계정 연결" + }, "connectAccountOrCreate": { "message": "계정 연결 또는 새 계정 만들기" }, + "connectAccounts": { + "message": "계정 연결" + }, "connectCustodialAccountMenu": { "message": "수탁 계정 연결" }, @@ -736,36 +907,25 @@ "connectCustodialAccountTitle": { "message": "수탁 계정" }, + "connectCustodianAccounts": { + "message": "$1 계정 연결" + }, "connectManually": { "message": "현재 사이트에 직접 연결" }, + "connectMoreAccounts": { + "message": "더 많은 계정 연결" + }, "connectSnap": { "message": "$1 연결", "description": "$1 is the snap for which a connection is being requested." }, - "connectTo": { - "message": "$1에 연결", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "모든 $1에 연결", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "계정", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "$1에 연결", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1개 계정", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "MetaMask로 연결" }, + "connectedAccounts": { + "message": "연결된 계정" + }, "connectedAccountsDescriptionPlural": { "message": "이 사이트에 계정 $1개가 연결되어 있습니다.", "description": "$1 is the number of accounts" @@ -776,6 +936,13 @@ "connectedAccountsEmptyDescription": { "message": "MetaMask가 이 사이트에 연결되어 있지 않습니다. web3 사이트를 연결하려면 사이트에서 연결 버튼을 찾아 클릭하세요." }, + "connectedAccountsListTooltip": { + "message": "$1은(는) 계정 잔액, 주소, 활동을 확인하고 연결된 계정에 대해 승인할 거래를 제안할 수 있습니다.", + "description": "$1 is the origin name" + }, + "connectedAccountsToast": { + "message": "연결 계정 업데이트됨" + }, "connectedSites": { "message": "연결된 사이트" }, @@ -787,12 +954,21 @@ "message": "$1 계정은 어떤 사이트에도 연결되어 있지 않습니다.", "description": "$1 is the account name" }, + "connectedSnapAndNoAccountDescription": { + "message": "MetaMask는 이 사이트와 연결되어 있지만, 아직 연결된 계정이 없습니다" + }, + "connectedWith": { + "message": "연결 대상:" + }, "connecting": { "message": "연결 중..." }, "connectingTo": { "message": "$1에 연결 중" }, + "connectingToDeprecatedNetwork": { + "message": "'$1' 네트워크는 단계적으로 지원 중단되므로 작동하지 않을 수 있습니다. 다른 네트워크를 사용해 보세요." + }, "connectingToGoerli": { "message": "Goerli 테스트 네트워크에 연결 중" }, @@ -802,6 +978,9 @@ "connectingToLineaMainnet": { "message": "Linea 메인넷에 연결 중" }, + "connectingToLineaSepolia": { + "message": "Linea Sepolia 테스트 네트워크에 연결 중" + }, "connectingToMainnet": { "message": "이더리움 메인넷에 연결 중" }, @@ -831,6 +1010,12 @@ "continue": { "message": "계속" }, + "continueMmiOnboarding": { + "message": "MetaMask Institutional 온보딩 계속" + }, + "continueToWallet": { + "message": "지갑으로 계속" + }, "contract": { "message": "계약" }, @@ -882,6 +1067,9 @@ "copyAddress": { "message": "주소를 클립보드에 복사" }, + "copyPrivateKey": { + "message": "개인 키 복사" + }, "copyRawTransactionData": { "message": "원시 트랜잭션 데이터 복사" }, @@ -900,6 +1088,15 @@ "createPassword": { "message": "비밀번호 생성" }, + "createSnapAccountDescription": { + "message": "$1에서 MetaMask에 새로운 계정을 추가하려고 합니다." + }, + "createSnapAccountTitle": { + "message": "계정 생성" + }, + "crossChainSwapsLink": { + "message": "MetaMask Portfolio로 네트워크 간 스왑" + }, "cryptoCompare": { "message": "CryptoCompare" }, @@ -950,10 +1147,16 @@ "message": "수탁자" }, "custodianAccountAddedDesc": { - "message": "이제 MetaMask Institutional에서 수탁 계정을 사용할 수 있습니다." + "message": "이제 MetaMask Institutional에서 계정을 사용할 수 있습니다." }, "custodianAccountAddedTitle": { - "message": "선택한 수탁 계정을 추가했습니다." + "message": "선택한 $1 계정을 추가했습니다." + }, + "custodianQRCodeScan": { + "message": "$1 모바일 앱으로 QR 코드를 스캔하세요" + }, + "custodianQRCodeScanDescription": { + "message": "또는 $1 계정에 로그인하여 'MMI에 연결' 버튼을 클릭하세요" }, "custodianReplaceRefreshTokenChangedFailed": { "message": "계정을 MMI에 다시 연결하려면 $1에서 해당 사용자 인터페이스를 찾아 'MMI로 연결' 버튼을 클릭하면 됩니다." @@ -1017,7 +1220,7 @@ "message": "이 네트워크에서는 아직 토큰 감지 기능을 사용할 수 없습니다. 토큰을 직접 가져오고 해당 토큰을 신뢰할 수 있는지 반드시 확인하세요. $1에 대해 알아보기" }, "customTokenWarningInTokenDetectionNetwork": { - "message": "토큰을 직접 가져오기 전에 해당 토큰을 신뢰할 수 있는지 반드시 확인하세요. $1에 대해 알아보기." + "message": "토큰을 생성하기 전에 해당 토큰을 신뢰할 수 있는지 반드시 확인하세요. $1에 대해 알아보기." }, "customTokenWarningInTokenDetectionNetworkWithTDOFF": { "message": "불러오기 전에 토큰의 신뢰성을 확인하세요. $1 상황을 피하는 방법을 알아보세요. 또한 $2 토큰 감지 기능을 활성화할 수 있습니다." @@ -1025,6 +1228,12 @@ "customerSupport": { "message": "고객 지원" }, + "customizeYourNotifications": { + "message": "알림 맞춤 설정" + }, + "customizeYourNotificationsText": { + "message": "수신하려는 알림의 유형을 켜세요." + }, "dappRequestedSpendingCap": { "message": "사이트에서 지출 한도를 요청했습니다" }, @@ -1108,6 +1317,18 @@ "deposit": { "message": "예치" }, + "deprecatedGoerliNtwrkMsg": { + "message": "이더리움 시스템 업데이트로 인해 Goerli 테스트 네트워크는 곧 단계적으로 지원 중단될 예정입니다." + }, + "deprecatedNetwork": { + "message": "이 네트워크는 더 이상 지원되지 않습니다" + }, + "deprecatedNetworkButtonMsg": { + "message": "확인" + }, + "deprecatedNetworkDescription": { + "message": "연결하려는 네트워크는 Metamask에서 더 이상 지원되지 않습니다. $1" + }, "description": { "message": "설명" }, @@ -1115,110 +1336,20 @@ "message": "$1 설명", "description": "$1 represents the name of the snap" }, - "desktopApp": { - "message": "데스크톱 앱" - }, - "desktopConnectionCriticalErrorDescription": { - "message": "이는 간헐적인 오류일 수 있습니다. 확장 프로그램을 다시 시작하거나 MetaMask 데스크톱을 비활성화해 보세요." - }, - "desktopConnectionCriticalErrorTitle": { - "message": "MetaMask 시작 중 문제가 발생했습니다" - }, - "desktopConnectionLostErrorDescription": { - "message": "데스크톱 앱이 실행 중인지 확인하거나 MetaMask 데스크톱을 비활성화하세요." - }, - "desktopConnectionLostErrorTitle": { - "message": "MetaMask 데스크톱 연결이 끊어졌습니다" - }, - "desktopDisableButton": { - "message": "데스크톱 앱 비활성화" - }, - "desktopDisableErrorCTA": { - "message": "MetaMask 데스크톱 앱 비활성화" - }, - "desktopEnableButton": { - "message": "데스크톱 앱 활성화" - }, - "desktopEnableButtonDescription": { - "message": "클릭하여 데스크톱 앱의 모든 배경 절차를 실행하세요." - }, - "desktopErrorNavigateSettingsCTA": { - "message": "설정 페이지로 돌아가기" - }, - "desktopErrorRestartMMCTA": { - "message": "MetaMask 재시작" - }, - "desktopNotFoundErrorCTA": { - "message": "MetaMask 데스크톱 다운로드" - }, - "desktopNotFoundErrorDescription1": { - "message": "데스크톱 앱이 실행 중인지 확인하세요." - }, - "desktopNotFoundErrorDescription2": { - "message": "데스크톱 앱이 설치되어 있지 않다면 MetaMask 웹사이트에서 다운로드하세요." - }, - "desktopNotFoundErrorTitle": { - "message": "MetaMask 데스크톱을 찾을 수 없습니다" - }, - "desktopOpenOrDownloadCTA": { - "message": "MetaMask 데스크톱 열기" - }, - "desktopOutdatedErrorCTA": { - "message": "MetaMask 데스크톱 업데이트" - }, - "desktopOutdatedErrorDescription": { - "message": "MetaMask 데스크톱 앱을 업그레이드해야 합니다." - }, - "desktopOutdatedErrorTitle": { - "message": "MetaMask 데스크톱이 최신 버전이 아닙니다" - }, - "desktopOutdatedExtensionErrorCTA": { - "message": "MetaMask 확장 프로그램 업데이트" - }, - "desktopOutdatedExtensionErrorDescription": { - "message": "MetaMask 확장 프로그램을 업그레이드해야 합니다." - }, - "desktopOutdatedExtensionErrorTitle": { - "message": "MetaMask 확장 프로그램이 최신 버전이 아닙니다" - }, - "desktopPageDescription": { - "message": "페어링에 성공하면 확장 프로그램이 다시 시작되며 비밀번호를 다시 입력해야 합니다." - }, - "desktopPageSubTitle": { - "message": "MetaMask 데스크톱을 열고 이 코드를 입력하세요" - }, - "desktopPageTitle": { - "message": "데스크톱 페어링" - }, - "desktopPairedWarningDeepLink": { - "message": "MetaMask 데스크톱 설정으로 이동하세요" - }, - "desktopPairedWarningDescription": { - "message": "새로 페어링하기 원하시면 현재 연결 상태를 해제하세요." - }, - "desktopPairedWarningTitle": { - "message": "MM 데스크톱이 이미 페어링되었습니다" - }, - "desktopPairingExpireMessage": { - "message": "코드는 $1초 후에 만료됩니다" - }, - "desktopRouteNotFoundErrorDescription": { - "message": "desktopRouteNotFoundErrorDescription" - }, - "desktopRouteNotFoundErrorTitle": { - "message": "desktopRouteNotFoundErrorTitle" + "details": { + "message": "세부 정보" }, - "desktopUnexpectedErrorCTA": { - "message": "MetaMask 홈으로 돌아가기" + "developerOptions": { + "message": "개발자 옵션" }, - "desktopUnexpectedErrorDescription": { - "message": "MetaMask 데스크톱을 확인하여 연결을 복구하세요" + "developerOptionsResetStatesAnnouncementsDescription": { + "message": "Resets isShown boolean to false for all announcements. Announcements are the notifications shown in the What's New popup modal." }, - "desktopUnexpectedErrorTitle": { - "message": "문제가 발생했습니다..." + "developerOptionsResetStatesOnboarding": { + "message": "온보딩과 관련된 다양한 상태를 초기화하고 '지갑 보안' 온보딩 페이지로 리디렉션합니다." }, - "details": { - "message": "세부 정보" + "developerOptionsServiceWorkerKeepAlive": { + "message": "session.storage에 타임스탬프가 지속적으로 저장됩니다" }, "disabledGasOptionToolTipMessage": { "message": "“$1” 유형은 오리지널 가스비를 최소 10% 인상해야 하는 기준에 미치지 못하므로 비활성화되었습니다.", @@ -1233,12 +1364,38 @@ "disconnectAllAccountsConfirmationDescription": { "message": "연결을 해제하시겠습니까? 사이트 기능을 이용하지 못하게 될 수도 있습니다." }, + "disconnectAllAccountsText": { + "message": "계정" + }, + "disconnectAllSnapsText": { + "message": "Snap" + }, + "disconnectAllText": { + "message": "$2에서 $1의 연결을 끊은 경우, 다시 사용하려면 다시 연결해야 합니다.", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`, $2 represents the website hostname" + }, + "disconnectAllTitle": { + "message": "모든 $1 연결 해제", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`" + }, "disconnectPrompt": { "message": "$1 연결 해제" }, "disconnectThisAccount": { "message": "이 계정 연결 해제" }, + "disconnectedAllAccountsToast": { + "message": "모든 계정이 $1에서 연결 해제됨", + "description": "$1 is name of the dapp`" + }, + "disconnectedSingleAccountToast": { + "message": "$1, $2에서 연결 해제됨", + "description": "$1 is name of the name and $2 represents the dapp name`" + }, + "discoverSnaps": { + "message": "Snap 알아보기", + "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." + }, "dismiss": { "message": "해지" }, @@ -1248,9 +1405,21 @@ "dismissReminderField": { "message": "비밀복구구문 백업 알림 해지" }, + "displayNftMedia": { + "message": "NFT 미디어 표시" + }, + "displayNftMediaDescription": { + "message": "NFT 미디어와 데이터를 표시하면 IP 주소가 OpenSea나 기타 제삼자에게 노출될 수 있습니다. 공격자는 이를 통해 회원님의 IP 주소와 이더리움 주소를 연결할 수 있습니다. NFT 자동 감지는 이 설정을 사용하며, 이 설정이 꺼져 있는 경우 사용할 수 없습니다." + }, + "doNotShare": { + "message": "누구와도 공유하지 마세요" + }, "domain": { "message": "도메인" }, + "domainNotSupportedOnNetwork": { + "message": "네트워크에서 도메인 조회를 지원하지 않음" + }, "done": { "message": "완료" }, @@ -1269,6 +1438,9 @@ "downloadStateLogs": { "message": "상태 로그 다운로드" }, + "dragAndDropBanner": { + "message": "네트워크를 드래그하여 순서를 변경할 수 있습니다. " + }, "dropped": { "message": "중단됨" }, @@ -1367,6 +1539,9 @@ "editSpeedUpEditGasFeeModalTitle": { "message": "가스비 가속 편집" }, + "enable": { + "message": "활성화" + }, "enableAutoDetect": { "message": " 자동 감지 활성화" }, @@ -1397,6 +1572,18 @@ "enhancedTokenDetectionAlertMessage": { "message": "$1에서 향상된 토큰 감지 기능을 사용할 수 있습니다. $2" }, + "ensDomainsSettingDescriptionIntroduction": { + "message": "MetaMask를 사용하면 브라우저의 주소창에서 ENS 도메인을 바로 볼 수 있습니다. 방법은 다음과 같습니다." + }, + "ensDomainsSettingDescriptionOutroduction": { + "message": "이 기능을 사용하면 IPFS 제삼자 서비스에 회원님의 IP 주소가 노출된다는 사실을 명심하세요." + }, + "ensDomainsSettingDescriptionPart1": { + "message": "MetaMask에서는 이더리움의 ENS 계약을 확인하여 해당 ENS 이름과 연결되어 있는 코드를 찾습니다." + }, + "ensDomainsSettingDescriptionPart2": { + "message": "해당 코드가 IPFS와 링크되어 있으면 관련 콘텐츠(주로 웹사이트)를 볼 수 있습니다." + }, "ensDomainsSettingTitle": { "message": "주소창에 ENS 도메인 표시하기" }, @@ -1438,6 +1625,9 @@ "message": "오류 세부 정보", "description": "Title for collapsible section that displays error details for debugging purposes" }, + "errorGettingSafeChainList": { + "message": "안전 체인 목록을 가져오는 동안 오류가 발생했습니다. 주의하여 계속 진행하세요." + }, "errorMessage": { "message": "메시지: $1", "description": "Displayed error message for debugging purposes. $1 is the error message" @@ -1469,6 +1659,9 @@ "message": "$1 오류", "description": "$1 represents the name of the snap" }, + "estimatedFee": { + "message": "예상 수수료" + }, "ethGasPriceFetchWarning": { "message": "현재 주요 가스 견적 서비스를 사용할 수 없으므로 백업 가스 가격을 제공합니다." }, @@ -1495,12 +1688,24 @@ "message": "실험적" }, "extendWalletWithSnaps": { - "message": "지갑 경험을 개인 맞춤하세요.", + "message": "커뮤니티에서 만들어진 Snap을 알아보고 웹3 경험을 개인 맞춤하세요.", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "extensionInsallCompleteDescription": { + "message": "MetaMask Institutional 제품 온보딩으로 돌아가 수탁 또는 자기 수탁 계정을 연결합니다." + }, + "extensionInsallCompleteTitle": { + "message": "확장 설치 완료" + }, "externalExtension": { "message": "외부 확장" }, + "externalNameSourcesSetting": { + "message": "추천 닉네임" + }, + "externalNameSourcesSettingDescription": { + "message": "회원님이 상호작용하는 주소에 대한 추천 닉네임을 Etherscan, Infura, Lens Protocol과 같은 제3자에게서 가져옵니다. 이러한 제3자는 해당 주소와 회원님의 IP 주소를 볼 수 있습니다. 회원님의 계정 주소는 제3자에게 노출되지 않습니다." + }, "failed": { "message": "실패" }, @@ -1519,6 +1724,9 @@ "feeAssociatedRequest": { "message": "수수료가 이 요청과 연결되어 있습니다." }, + "feeDetails": { + "message": "수수료 세부 정보" + }, "fiat": { "message": "명목", "description": "Exchange type" @@ -1551,6 +1759,9 @@ "message": "본인은 이 위험을 감수합니다", "description": "this text is shown on a button, which the user presses to confirm they understand the risks of using Flask" }, + "floatAmountToken": { + "message": "토큰 금액은 정수여야 합니다" + }, "followUsOnTwitter": { "message": "트위터에서 팔로우하세요" }, @@ -1573,6 +1784,9 @@ "fromTokenLists": { "message": "가져올 토큰 목록: $1" }, + "function": { + "message": "기능: $1" + }, "functionApprove": { "message": "기능: 승인" }, @@ -1582,6 +1796,13 @@ "functionType": { "message": "기능 유형" }, + "fundYourWallet": { + "message": "지갑에 자금 추가" + }, + "fundYourWalletDescription": { + "message": "지갑에 $1의 자금을 추가하여 시작하세요.", + "description": "$1 is the token symbol" + }, "gas": { "message": "가스" }, @@ -1592,6 +1813,9 @@ "message": "$1에서 이 가스비를 제안했습니다. 이를 무시하면 트랜잭션에 문제가 발생할 수 있습니다. 질문이 있는 경우 $1에 문의하세요.", "description": "$1 represents the Dapp's origin" }, + "gasIsETH": { + "message": "가스는 $1입니다 " + }, "gasLimit": { "message": "가스 한도" }, @@ -1636,6 +1860,9 @@ "message": "$1 시간", "description": "$1 represents a number of hours" }, + "gasTimingLow": { + "message": "느림" + }, "gasTimingMinutesShort": { "message": "$1 분", "description": "$1 represents a number of minutes" @@ -1650,15 +1877,29 @@ "general": { "message": "일반" }, - "globalTitle": { - "message": "글로벌 메뉴" + "generalCameraError": { + "message": "카메라에 액세스할 수 없습니다. 다시 시도하세요." + }, + "generalCameraErrorTitle": { + "message": "오류가 발생했습니다...." }, - "globalTourDescription": { - "message": "포트폴리오, 연결된 사이트, 설정 등을 확인하세요" + "genericExplorerView": { + "message": "$1에서 계정 보기" + }, + "getStartedWithNFTs": { + "message": "$1 받고 NFT 구매하기", + "description": "$1 is the token symbol" + }, + "getStartedWithNFTsDescription": { + "message": "지갑에 $1의 자금을 추가하여 시작하세요.", + "description": "$1 is the token symbol" }, "goBack": { "message": "뒤로 가기" }, + "goToSite": { + "message": "사이트로 이동" + }, "goerli": { "message": "Goerli 테스트 네트워크" }, @@ -1700,15 +1941,24 @@ "hexData": { "message": "헥스 데이터" }, + "hiddenAccounts": { + "message": "숨긴 계정" + }, "hide": { "message": "숨기기" }, + "hideAccount": { + "message": "계정 숨기기" + }, "hideFullTransactionDetails": { "message": "전체 트랜잭션 세부 정보 숨기기" }, "hideSeedPhrase": { "message": "시드 구문 숨기기" }, + "hideSentitiveInfo": { + "message": "민감한 정보 숨기기" + }, "hideToken": { "message": "토큰 숨기기" }, @@ -1790,6 +2040,9 @@ "ignoreTokenWarning": { "message": "토큰을 숨기면 지갑에 표시되지 않습니다. 하지만 이를 검색하여 추가할 수 있습니다." }, + "imToken": { + "message": "imToken" + }, "import": { "message": "가져오기", "description": "Button to import an account from a selected file" @@ -1848,6 +2101,9 @@ "importTokensCamelCase": { "message": "토큰 가져오기" }, + "importTokensError": { + "message": "토큰을 가져올 수 없습니다. 나중에 다시 시도하세요." + }, "importWithCount": { "message": "$1 불러오기", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -1866,6 +2122,9 @@ "initialTransactionConfirmed": { "message": "최초 트랜잭션을 네트워크에서 컨펌했습니다. 돌아가려면 컨펌을 클릭하세요." }, + "inlineAlert": { + "message": "경고" + }, "inputLogicEmptyState": { "message": "타사에서 현재나 추후 지출하기에 무리가 없는 금액만 입력하세요. 지출 한도는 나중에 언제든지 상향할 수 있습니다." }, @@ -1876,6 +2135,27 @@ "inputLogicHigherNumber": { "message": "이렇게 하면 토큰 잔액이 한도에 도달하거나 지출 한도를 철회할 때까지 제삼자가 모든 토큰 잔액을 지출할 수 있게 됩니다. 이를 원하지 않는다면 지출 한도를 하향하세요." }, + "insightWarning": { + "message": "경고" + }, + "insightWarningCheckboxMessage": { + "message": "$2의 $1 요청", + "description": "$1 is the action i.e. sign, confirm. $2 is the origin making the request." + }, + "insightWarningContentPlural": { + "message": "$2 전에 $1을(를) 확인하세요. $3 후에는 되돌릴 수 없습니다.", + "description": "$1 the 'insightWarnings' message (2 warnings) representing warnings, $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningContentSingular": { + "message": "$2 전에 $1을(를) 확인하세요. $3 후에는 되돌릴 수 없습니다.", + "description": "$1 is the 'insightWarning' message (1 warning), $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningHeader": { + "message": "이 요청은 위험성이 높습니다." + }, + "insightWarnings": { + "message": "경고" + }, "insightsFromSnap": { "message": "$1 인사이트", "description": "$1 represents the name of the snap" @@ -1883,9 +2163,18 @@ "install": { "message": "설치" }, + "installExtension": { + "message": "확장 설치" + }, + "installExtensionDescription": { + "message": "기관의 규정을 준수하는 세계 최고의 웹3 지갑, MetaMask입니다." + }, "installOrigin": { "message": "출처 설치" }, + "installRequest": { + "message": "MetaMask에 추가" + }, "installedOn": { "message": "$1에 설치됨", "description": "$1 is the date when the snap has been installed" @@ -1914,6 +2203,12 @@ "insufficientTokens": { "message": "토큰이 부족합니다." }, + "interactingWith": { + "message": "다음과 상호 작용:" + }, + "interactingWithTransactionDescription": { + "message": "지금 상호작용하고 있는 계약입니다. 세부 정보를 확인하여 사기를 방지하세요." + }, "invalidAddress": { "message": "잘못된 주소" }, @@ -1986,6 +2281,9 @@ "ipfsToggleModalSettings": { "message": "설정 > 보안 및 개인정보" }, + "isSigningOrSubmitting": { + "message": "이전 트랜잭션이 아직 서명 또는 제출 중입니다." + }, "jazzAndBlockies": { "message": "Jazzicons와 Blockies는 계정을 한눈에 식별할 수 있게 도와주는 두 가지 고유한 아이콘 스타일입니다." }, @@ -1999,6 +2297,24 @@ "message": "JSON 파일", "description": "format for importing an account" }, + "keyringAccountName": { + "message": "계정 이름" + }, + "keyringAccountPublicAddress": { + "message": "공개 주소" + }, + "keyringSnapRemovalResult1": { + "message": "$1 제거 $2", + "description": "Displays the result after removal of a keyring snap. $1 is the snap name, $2 is whether it is successful or not" + }, + "keyringSnapRemovalResultNotSuccessful": { + "message": "실패 ", + "description": "Displays the `not` word in $2." + }, + "keyringSnapRemoveConfirmation": { + "message": "$1을(를) 입력하여 이 스냅을 제거할지 확인합니다:", + "description": "Asks user to input the name nap prior to deleting the snap. $1 is the snap name" + }, "keystone": { "message": "Keystone" }, @@ -2017,9 +2333,15 @@ "lastSold": { "message": "최근 판매" }, + "lavaDomeCopyWarning": { + "message": "안전을 위해 지금은 이 텍스트를 선택할 수 없습니다." + }, "layer1Fees": { "message": "레이어 1 요금" }, + "layer2Fees": { + "message": "레이어 2 요금" + }, "learnCancelSpeeedup": { "message": "$1 방법 알아보기", "description": "$1 is link to cancel or speed up transactions" @@ -2037,9 +2359,21 @@ "learnMoreUpperCase": { "message": "자세히 알아보기" }, + "learnMoreUpperCaseWithDot": { + "message": "자세히 알아보세요." + }, "learnScamRisk": { "message": "사기 및 보안 위험" }, + "learnToBridge": { + "message": "브릿지 알아보기" + }, + "leaveMetaMask": { + "message": "MetaMask를 나가시겠습니까?" + }, + "leaveMetaMaskDesc": { + "message": "MetaMask 외부의 사이트를 방문하려고 합니다. 계속하기 전에 URL을 다시 한번 확인하세요." + }, "ledgerAccountRestriction": { "message": "새 계정을 추가하려면 먼저 기존의 최종 계정을 사용해야 합니다." }, @@ -2058,6 +2392,18 @@ "ledgerDeviceOpenFailureMessage": { "message": "Ledger 장치를 열지 못했습니다. Ledger가 다른 소프트웨어에 연결되어 있을 수 있습니다. Ledger Live 또는 Ledger 장치에 연결된 다른 응용 프로그램을 닫고 다시 연결하세요." }, + "ledgerErrorConnectionIssue": { + "message": "Ledger를 다시 연결하고, ETH 앱을 열어 다시 시도하세요." + }, + "ledgerErrorDevicedLocked": { + "message": "Ledger가 잠겨있습니다. 잠금 해제하고 다시 시도하세요." + }, + "ledgerErrorEthAppNotOpen": { + "message": "문제를 해결하려면 기기에서 ETH 앱을 열고 다시 시도하세요." + }, + "ledgerErrorTransactionDataNotPadded": { + "message": "이더리움 트랜잭션의 입력 데이터가 충분히 패딩되지 않았습니다." + }, "ledgerLiveApp": { "message": "Ledger Live 앱" }, @@ -2077,6 +2423,9 @@ "lightTheme": { "message": "라이트" }, + "likeToImportToken": { + "message": "이 토큰을 가져올까요?" + }, "likeToImportTokens": { "message": "이 토큰을 추가하시겠습니까?" }, @@ -2086,6 +2435,9 @@ "lineaMainnet": { "message": "Linea 메인넷" }, + "lineaSepolia": { + "message": "Linea Sepolia 테스트 네트워크" + }, "link": { "message": "링크" }, @@ -2098,8 +2450,11 @@ "loading": { "message": "로드 중..." }, - "loadingNFTs": { - "message": "NFT 불러오는 중..." + "loadingScreenHardwareWalletMessage": { + "message": "하드웨어 지갑에서 트랜잭션을 완료하세요." + }, + "loadingScreenSnapMessage": { + "message": "Snap에서 트랜잭션을 완료하세요." }, "loadingTokens": { "message": "토큰 불러오는 중..." @@ -2146,6 +2501,9 @@ "message": "다른 사람이 이 화면을 보고 있지는 않은지 확인하세요.", "description": "Warning to users to be care while creating and saving their new Secret Recovery Phrase" }, + "manageInSettings": { + "message": "설정에서 관리" + }, "max": { "message": "최대" }, @@ -2180,15 +2538,34 @@ "metaMaskConnectStatusParagraphTwo": { "message": "방문 중인 웹사이트가 현재 선택한 계정에 연결되어 있다면 연결 상태 버튼이 표시됩니다." }, + "metadataModalSourceTooltip": { + "message": "$1 스냅은 npm이 호스팅합니다. 이 Snap의 고유 식별자는 $2 입니다.", + "description": "$1 is the snap name and $2 is the snap NPM id." + }, "metamaskInstitutionalVersion": { "message": "MetaMask Institutional 버전" }, + "metamaskNotificationsAreOff": { + "message": "현재 지갑 알림이 꺼져 있습니다." + }, + "metamaskPortfolio": { + "message": "MetaMask Portfolio." + }, "metamaskSwapsOfflineDescription": { "message": "MetaMask Swaps 점검 중입니다. 나중에 다시 확인하세요." }, "metamaskVersion": { "message": "MetaMask 버전" }, + "methodData": { + "message": "메소드" + }, + "methodDataTransactionDescription": { + "message": "이는 구체적인 조치 사항입니다. 이 데이터는 위조될 수 있으므로, 상대 사이트를 신뢰할 수 있는지 확인하세요." + }, + "methodNotSupported": { + "message": "이 계정에서는 지원되지 않습니다." + }, "metrics": { "message": "메트릭" }, @@ -2224,11 +2601,17 @@ "mmiBuiltAroundTheWorld": { "message": "MetaMask Institutional은 전 세계적으로 설계 및 구축되었습니다." }, + "mmiNewNFTDetectedInNFTsTabMessage": { + "message": "MetaMask Institutional을 통해 자동으로 NFT를 감지하여 지갑에 표시할 수 있습니다." + }, + "mmiPasswordSetupDetails": { + "message": "이 비밀번호는 MetaMask Institutional 확장만 잠금 해제합니다." + }, "more": { "message": "그 외" }, "multipleSnapConnectionWarning": { - "message": "$1에서 $2개의 스냅 연결을 원합니다. 해당 웹사이트를 신뢰할 수 있는 경우에만 진행하세요.", + "message": "$1에서 $2 Snap 사용을 원합니다.", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." }, "mustSelectOne": { @@ -2237,10 +2620,80 @@ "name": { "message": "이름" }, + "nameAddressLabel": { + "message": "주소", + "description": "Label above address field in name component modal." + }, + "nameInstructionsNew": { + "message": "이 주소를 알고 있다면 나중에 알아볼 수 있도록 닉네임을 지정하세요.", + "description": "Instruction text in name component modal when value is not recognised." + }, + "nameInstructionsRecognized": { + "message": "이 주소에는 기본 닉네임이 있지만, 편집하거나 다른 추천 닉네임을 찾아볼 수 있습니다.", + "description": "Instruction text in name component modal when value is recognized but not saved." + }, + "nameInstructionsSaved": { + "message": "이 전에 이 주소에 닉네임을 추가한 적이 있습니다. 편집하거나 다른 추천 닉네임을 볼 수 있습니다.", + "description": "Instruction text in name component modal when value is saved." + }, + "nameLabel": { + "message": "닉네임", + "description": "Label above name input field in name component modal." + }, + "nameModalMaybeProposedName": { + "message": "가능한 닉네임: $1", + "description": "$1 is the proposed name" + }, + "nameModalTitleNew": { + "message": "알 수 없는 주소", + "description": "Title of the modal created by the name component when value is not recognised." + }, + "nameModalTitleRecognized": { + "message": "인식된 주소", + "description": "Title of the modal created by the name component when value is recognized but not saved." + }, + "nameModalTitleSaved": { + "message": "저장된 주소", + "description": "Title of the modal created by the name component when value is saved." + }, + "nameProviderProposedBy": { + "message": "추천인: $1", + "description": "$1 is the name of the provider" + }, + "nameProvider_ens": { + "message": "이더리움 네임 서비스(ENS)" + }, + "nameProvider_etherscan": { + "message": "Etherscan" + }, + "nameProvider_lens": { + "message": "Lens Protocol" + }, + "nameProvider_token": { + "message": "MetaMask" + }, + "nameSetPlaceholder": { + "message": "닉네임을 선택하세요...", + "description": "Placeholder text for name input field in name component modal." + }, + "nativePermissionRequestDescription": { + "message": "이 사이트가 다음을 수행하기 원하십니까?", + "description": "Description below header used on Permission Connect screen for native permissions." + }, "nativeToken": { "message": "이 네트워크의 네이티브 토큰은 $1입니다. 이는 가스비 지불에 사용하는 토큰입니다.", "description": "$1 represents the name of the native token on the current network" }, + "nativeTokenScamWarningConversion": { + "message": "네트워크 세부 정보 편집" + }, + "nativeTokenScamWarningDescription": { + "message": "이 네트워크는 연결된 체인 ID 또는 이름이 일치하지 않습니다. 여러 인기 토큰이 $1(이)라는 이름을 사용하기 때문에 사기의 표적이 되고 있습니다. 사기꾼은 더 가격이 높은 암호화폐를 주겠다고 속일 수 있습니다. 계속하기 전에 모든 사항을 확인하세요.", + "description": "$1 represents the currency name" + }, + "nativeTokenScamWarningTitle": { + "message": "사기일 수 있습니다" + }, "needHelp": { "message": "도움이 필요하신가요? $1에 문의하세요.", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -2261,6 +2714,9 @@ "negativeETH": { "message": "음수 ETH 양은 전송할 수 없습니다." }, + "negativeOrZeroAmountToken": { + "message": "마이너스 또는 금액이 0인 자산은 보낼 수 없습니다." + }, "network": { "message": "네트워크:" }, @@ -2291,6 +2747,9 @@ "networkNameBSC": { "message": "BSC" }, + "networkNameBase": { + "message": "기본" + }, "networkNameDefinition": { "message": "이 네트워크와 연결된 이름입니다." }, @@ -2300,12 +2759,21 @@ "networkNameGoerli": { "message": "Goerli" }, + "networkNameLinea": { + "message": "Linea" + }, + "networkNameOpMainnet": { + "message": "OP 메인넷" + }, "networkNamePolygon": { "message": "Polygon" }, "networkNameTestnet": { "message": "테스트넷" }, + "networkNameZkSyncEra": { + "message": "zkSync Era" + }, "networkProvider": { "message": "네트워크 공급업체" }, @@ -2358,6 +2826,19 @@ "newContract": { "message": "새 계약" }, + "newNFTDetectedInImportNFTsMessageStrongText": { + "message": "설정 > 보안 및 개인정보" + }, + "newNFTDetectedInImportNFTsMsg": { + "message": "OpenSea를 사용하여 NFT를 확인하려면 $1에서 ‘NFT 미디어 표시’ 기능을 켜세요.", + "description": "$1 is used for newNFTDetectedInImportNFTsMessageStrongText" + }, + "newNFTDetectedInNFTsTabMessage": { + "message": "MetaMask를 통해 자동으로 NFT를 감지하여 지갑에 표시할 수 있습니다." + }, + "newNFTsAutodetected": { + "message": "NFT 자동 감지" + }, "newNetworkAdded": { "message": "“$1”(을)를 성공적으로 추가했습니다!" }, @@ -2367,6 +2848,12 @@ "newPassword": { "message": "새 비밀번호(8자 이상)" }, + "newPrivacyPolicyActionButton": { + "message": "자세히 보기" + }, + "newPrivacyPolicyTitle": { + "message": "개인정보 처리방침이 개정되었습니다" + }, "newTokensImportedMessage": { "message": "$1 토큰을 성공적으로 불러왔습니다.", "description": "$1 is the string of symbols of all the tokens imported" @@ -2388,6 +2875,9 @@ "message": "이 토큰은 NFT입니다. $1에 추가하세요", "description": "$1 is a clickable link with text defined by the 'importNFTPage' key" }, + "nftAlreadyAdded": { + "message": "NFT가 이미 추가되었습니다." + }, "nftDisclaimer": { "message": "면책 조항: MetaMask는 소스 URL에서 미디어 파일을 가져옵니다. 이러한 URL은 때때로 NFT가 민팅된 마켓플레이스에서 변경되기도 합니다." }, @@ -2423,12 +2913,21 @@ "noAddressForName": { "message": "이 이름에 설정된 주소가 없습니다." }, + "noConnectedAccountDescription": { + "message": "이 사이트에서 계속 사용하고자 하는 계정을 선택하세요." + }, + "noConnectedAccountTitle": { + "message": "MetaMask가 이 사이트와 연결되어 있지 않습니다" + }, "noConversionDateAvailable": { "message": "사용 가능한 통화 변환 날짜 없음" }, "noConversionRateAvailable": { "message": "사용 가능한 환율 없음" }, + "noDomainResolution": { + "message": "도메인에 대한 해결 방법이 제공되지 않았습니다." + }, "noNFTs": { "message": "아직 NFT가 없음" }, @@ -2447,6 +2946,9 @@ "noWebcamFoundTitle": { "message": "웹캠을 찾을 수 없음" }, + "nonCustodialAccounts": { + "message": "MetaMask Institutional은 이러한 계정을 비밀복구구문 백업에 사용하려는 경우 비수탁형 계정을 사용할 수 있도록 허용합니다." + }, "nonce": { "message": "논스" }, @@ -2477,6 +2979,111 @@ "notePlaceholder": { "message": "수탁 기관에서 트랜잭션이 승인되면 승인자가 이 참고 사항을 보게 됩니다." }, + "notificationDetail": { + "message": "세부 정보" + }, + "notificationDetailBaseFee": { + "message": "기본 수수료(GWEI)" + }, + "notificationDetailGasLimit": { + "message": "가스 한도(단위)" + }, + "notificationDetailGasUsed": { + "message": "사용한 가스(단위)" + }, + "notificationDetailMaxFee": { + "message": "가스당 최대 수수료" + }, + "notificationDetailNetwork": { + "message": "네트워크" + }, + "notificationDetailNetworkFee": { + "message": "네트워크 수수료" + }, + "notificationDetailPriorityFee": { + "message": "우선 수수료(GWEI)" + }, + "notificationItemCheckBlockExplorer": { + "message": "BlockExplorer에서 확인하기" + }, + "notificationItemCollection": { + "message": "컬렉션" + }, + "notificationItemConfirmed": { + "message": "컨펌" + }, + "notificationItemError": { + "message": "현재 수수료를 조회할 수 없습니다" + }, + "notificationItemFrom": { + "message": "발신:" + }, + "notificationItemLidoStakeReadyToBeWithdrawn": { + "message": "출금 준비 완료" + }, + "notificationItemLidoStakeReadyToBeWithdrawnMessage": { + "message": "이제 언스테이킹한 $1을(를) 출금할 수 있습니다" + }, + "notificationItemLidoWithdrawalRequestedMessage": { + "message": "$1 언스테이킹 요청이 전송되었습니다" + }, + "notificationItemNFTReceivedFrom": { + "message": "수취한 NFT 출처:" + }, + "notificationItemNFTSentTo": { + "message": "전송한 NFT 수취 대상:" + }, + "notificationItemNetwork": { + "message": "네트워크" + }, + "notificationItemRate": { + "message": "환율(수수료 포함)" + }, + "notificationItemReceived": { + "message": "받음" + }, + "notificationItemReceivedFrom": { + "message": "발신처:" + }, + "notificationItemSent": { + "message": "전송 완료" + }, + "notificationItemSentTo": { + "message": "수신처:" + }, + "notificationItemStakeCompleted": { + "message": "스테이킹 완료" + }, + "notificationItemStaked": { + "message": "스테이킹됨" + }, + "notificationItemStakingProvider": { + "message": "스테이킹 공급자" + }, + "notificationItemStatus": { + "message": "상태" + }, + "notificationItemSwapped": { + "message": "스왑" + }, + "notificationItemSwappedFor": { + "message": "대상:" + }, + "notificationItemTo": { + "message": "수신:" + }, + "notificationItemTransactionId": { + "message": "트랜잭션 ID" + }, + "notificationItemUnStakeCompleted": { + "message": "언스테이킹 완료" + }, + "notificationItemUnStaked": { + "message": "언스테이킹됨" + }, + "notificationItemUnStakingRequested": { + "message": "언스테이킹 요청 완료" + }, "notificationTransactionFailedMessage": { "message": "$1 트랜잭션에 실패했습니다! $2", "description": "Content of the browser notification that appears when a transaction fails" @@ -2502,44 +3109,7 @@ "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" }, "notifications": { - "message": "알림" - }, - "notifications20ActionText": { - "message": "자세히 알아보기", - "description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a ledger page to resolve the U2F connection issue." - }, - "notifications20Description": { - "message": "Firefox 최신 버전을 사용하신다면 Firefox에서 U2F 지원 중단과 관련된 문제가 발생할 수 있습니다.", - "description": "Description of a notification in the 'See What's New' popup. Describes the U2F support being dropped by firefox and that it affects ledger users." - }, - "notifications20Title": { - "message": "Ledger 및 Firefox 사용자의 연결 문제점 경험", - "description": "Title for a notification in the 'See What's New' popup. Tells users that latest firefox users using U2F may experience connection issues." - }, - "notifications24ActionText": { - "message": "확인" - }, - "notifications24Description": { - "message": "이제 사용 중인 네트워크에 따라 고급 가스비 설정을 기억합니다. 즉, 각 네트워크에 대해 특정 고급 가스비를 설정하여 가스비가 과다하게 지출되거나 트랜잭션이 중단되는 것을 방지할 수 있습니다." - }, - "notifications24Title": { - "message": "네트워크별 고급 가스비" - }, - "notifications8ActionText": { - "message": "설정 > 고급으로 이동", - "description": "Description on an action button that appears in the What's New popup. Tells the user that if they click it, they will go to our Advanced settings page." - }, - "notifications8DescriptionOne": { - "message": "MetaMask v10.4.0부터는 Ledger 장치를 MetaMask에 연결할 때 더 이상 Ledger Live를 사용하지 않아도 됩니다.", - "description": "Description of a notification in the 'See What's New' popup. Describes changes for how Ledger Live is no longer needed to connect the device." - }, - "notifications8DescriptionTwo": { - "message": "더 쉽고 안정적인 Ledger 경험을 위해 설정의 고급 탭으로 이동하여 '선호하는 Ledger 연결 유형'을 'WebHID'로 전환하세요.", - "description": "Description of a notification in the 'See What's New' popup. Describes how the user can turn off the Ledger Live setting." - }, - "notifications8Title": { - "message": "Ledger 연결 개선 사항", - "description": "Title for a notification in the 'See What's New' popup. Notifies ledger users that there is an improvement in how they can connect their device." + "message": "알림" }, "notificationsDropLedgerFirefoxDescription": { "message": "Firefox에서 더 이상 U2F를 지원하지 않아 Firefox를 이용한 MetaMask에서 Ledger를 이용할 수 없습니다. 대신 Google Chrome에서 MetaMask를 이용해 보세요.", @@ -2549,33 +3119,37 @@ "message": "Firefox의 Ledger 지원 중단", "description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped." }, - "notificationsEmptyText": { - "message": "설치한 스냅에서 알림을 찾을 수 있는 곳입니다." - }, - "notificationsHeader": { - "message": "알림" + "notificationsFeatureToggle": { + "message": "지갑 알림 활성화", + "description": "Experimental feature title" }, - "notificationsInfos": { - "message": "$1($2)", - "description": "$1 is the date at which the notification has been dispatched and $2 is the link to the snap that dispatched the notification." + "notificationsFeatureToggleDescription": { + "message": "자금 또는 NFT 보내기/받기와 기능 알림 등의 지갑 알림을 활성화합니다.", + "description": "Description of the experimental notifications feature" }, "notificationsMarkAllAsRead": { "message": "모두 읽음으로 표시" }, - "notificationsOpenBetaSnapsActionText": { - "message": "자세히 알아보기" + "notificationsPageEmptyTitle": { + "message": "표시할 항목이 없습니다" }, - "notificationsOpenBetaSnapsDescriptionOne": { - "message": "🎉 MetaMask Snaps의 오픈 베타가 시작되었습니다!" + "notificationsPageErrorContent": { + "message": "이 페이지를 다시 방문해 주세요." }, - "notificationsOpenBetaSnapsDescriptionThree": { - "message": "개발자 커뮤니티가 구축한 스냅으로 지갑을 개별 맞춤하세요!" + "notificationsPageErrorTitle": { + "message": "오류가 발생했습니다" }, - "notificationsOpenBetaSnapsDescriptionTwo": { - "message": "스냅은 추가 네트워크 연결, 트랜잭션 인사이트 확인, 커스텀 알림 받기 등 사용자가 MetaMask에서 더욱 다양한 기능을 사용할 수 있도록 합니다." + "notificationsPageNoNotificationsContent": { + "message": "아직 알림을 받지 못했습니다." }, - "notificationsOpenBetaSnapsTitle": { - "message": "MetaMask Snaps 소개" + "notificationsSettingsBoxError": { + "message": "문제가 발생했습니다. 다시 시도해 주세요." + }, + "notificationsSettingsPageAllowNotifications": { + "message": "알림을 통해 지갑에서 무슨 일이 일어나고 있는지 계속 확인하세요. 알림 기능을 사용하려면 프로필을 사용해 기기 간에 일부 설정을 동기화해야 합니다. $1" + }, + "notificationsSettingsPageAllowNotificationsLink": { + "message": "이 기능을 사용하는 동안 개인정보가 어떻게 보호되는지 알아보세요." }, "numberOfNewTokensDetectedPlural": { "message": "계정에서 $1개의 새로운 토큰이 발견됨", @@ -2599,6 +3173,9 @@ "on": { "message": "켜기" }, + "onboarding": { + "message": "온보딩" + }, "onboardingAdvancedPrivacyIPFSDescription": { "message": "IPFS 게이트웨이를 사용하면 타사 호스팅 데이터에 액세스하여 이를 볼 수 있습니다. 사용자 지정 IPFS 게이트웨이를 추가하셔도 좋고 기본 설정을 계속 사용하셔도 됩니다." }, @@ -2629,51 +3206,45 @@ "onboardingMetametricsAgree": { "message": "동의함" }, - "onboardingMetametricsAllowOptOut": { - "message": "언제든 설정을 통해 옵트아웃할 수 있습니다." - }, - "onboardingMetametricsDataTerms": { - "message": "이 데이터는 집계 처리된 정보이며 일반 데이터 보호 규정 (EU) 2016/679의 목적에 따라 익명으로 관리됩니다." - }, "onboardingMetametricsDescription": { - "message": "MetaMask는 사용자가 MetaMask를 어떻게 사용하는지 이해하기 위해 기본적인 사용 데이터를 수집하고자 합니다. 이 데이터는 사용자 경험을 통한 서비스 개선에 사용됩니다." + "message": "MetaMask를 개선하기 위해 기본적인 사용 및 진단 데이터를 수집하고자 합니다. MetaMask는 제공받은 데이터를 절대 판매하지 않습니다." }, "onboardingMetametricsDescription2": { - "message": "MetaMask에서는..." + "message": "메트릭을 수집할 때는 항상..." }, "onboardingMetametricsDisagree": { "message": "괜찮습니다" }, "onboardingMetametricsInfuraTerms": { - "message": "* MetaMask에서 Infura를 기본 RPC 공급업체로 이용하는 경우, 트랜잭션 전송 시 Infura가 IP 주소와 이더리움 지갑 주소 정보를 수집합니다. MetaMask는 해당 두 정보를 연계할 수 있는 방식으로 정보를 저장하지 않습니다. 데이터 수집 관점에서 MetaMask와 Infura가 인터렉션하는 방법에 대한 자세한 내용은 $1 업데이트를 참조하세요. 일반적인 개인정보 처리방침에 대한 자세한 내용은 $2에서 확인하세요.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" + "message": "이 데이터를 다른 목적으로 사용하기로 결정하면 알려드리겠습니다. 자세한 내용은 $1을(를) 참고하세요. 언제든지 설정으로 이동하여 해제할 수 있습니다.", + "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, "onboardingMetametricsInfuraTermsPolicy": { "message": "개인정보 처리방침" }, - "onboardingMetametricsInfuraTermsPolicyLink": { - "message": "여기" - }, "onboardingMetametricsModalTitle": { "message": "맞춤 네트워크 추가" }, "onboardingMetametricsNeverCollect": { - "message": "$1에서는 서비스 제공에 필요하지 않은 정보(예: 키, 주소, 트랜잭션 해시 또는 잔액)를 수집합니다.", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 앱의 클릭 수와 조회수는 저장되지만, 공개 주소와 같은 기타 세부 정보는 저장되지 않습니다.", + "description": "$1 represents `onboardingMetametricsNeverCollectEmphasis`" + }, + "onboardingMetametricsNeverCollectEmphasis": { + "message": "개인 정보:" }, "onboardingMetametricsNeverCollectIP": { - "message": "$1에서는 사용자의 IP 주소 전체를 수집합니다.", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 MetaMask는 사용자의 국가나 지역과 같은 일반적인 위치를 찾기 위해 일시적으로 사용자의 IP 주소를 사용하지만, 이 정보는 저장되지 않습니다.", + "description": "$1 represents `onboardingMetametricsNeverCollectIPEmphasis`" }, - "onboardingMetametricsNeverEmphasis": { - "message": "절대로" + "onboardingMetametricsNeverCollectIPEmphasis": { + "message": "일반:" }, "onboardingMetametricsNeverSellData": { - "message": "$1에서는 데이터를 판매합니다. 항상요!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 언제든지 설정을 통해 사용 데이터를 공유할지 삭제할지 결정할 수 있습니다.", + "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" }, - "onboardingMetametricsSendAnonymize": { - "message": "익명 클릭 및 페이지뷰 이벤트 보내기" + "onboardingMetametricsNeverSellDataEmphasis": { + "message": "선택 사항:" }, "onboardingMetametricsTitle": { "message": "MetaMask 개선에 도움을 주세요" @@ -2714,15 +3285,26 @@ "onboardingPinExtensionTitle": { "message": "MetaMask 설치가 완료되었습니다!" }, + "onboardingPinMmiExtensionLabel": { + "message": "MetaMask Institutional 고정" + }, "onboardingUsePhishingDetectionDescription": { "message": "피싱 감지 경고는 $1과(와)의 통신에 의존합니다. jsDeliver는 회원님의 IP 주소에 액세스할 수 있습니다. $2 보기.", "description": "The $1 is the word 'jsDeliver', from key 'jsDeliver' and $2 is the words Privacy Policy from key 'privacyMsg', both separated here so that it can be wrapped as a link" }, + "onekey": { + "message": "OneKey" + }, "onlyAddTrustedNetworks": { "message": "악성 네트워크 공급업체는 블록체인 상태를 거짓으로 보고하고 네트워크 활동을 기록할 수 있습니다. 신뢰하는 맞춤 네트워크만 추가하세요." }, "onlyConnectTrust": { - "message": "신뢰하는 사이트만 연결하세요." + "message": "신뢰하는 사이트만 연결하세요. $1", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." + }, + "openCustodianApp": { + "message": "$1 앱 열기", + "description": "The $1 is the name of the Custodian that will be open" }, "openFullScreenForLedgerWebHid": { "message": "전체 화면으로 이동하여 Ledger를 연결하세요.", @@ -2734,6 +3316,15 @@ "openSeaNew": { "message": "OpenSea" }, + "openSeaToBlockaidBtnLabel": { + "message": "Snap 탐색" + }, + "openSeaToBlockaidDescription": { + "message": "이 네트워크에서 더 이상 보안 경고를 사용할 수 없습니다. Snap을 설치하면 보안을 강화할 수 있습니다." + }, + "openSeaToBlockaidTitle": { + "message": "주의하세요!" + }, "operationFailed": { "message": "작업에 실패했습니다" }, @@ -2777,6 +3368,9 @@ "password": { "message": "비밀번호" }, + "passwordMmiTermsWarning": { + "message": "MetaMask Institutional이 이 비밀번호를 복구할 수 없음을 이해합니다. $1" + }, "passwordNotLongEnough": { "message": "비밀번호가 짧습니다." }, @@ -2803,6 +3397,10 @@ "message": "여기에 비공개 키 문자열을 붙여넣으세요.", "description": "For importing an account from a private key" }, + "paymasterInUse": { + "message": "이 거래에 대한 가스비는 지불 담당자가 지불합니다.", + "description": "Alert shown in transaction confirmation if paymaster in use." + }, "pending": { "message": "보류 중" }, @@ -2816,18 +3414,26 @@ "message": "보류 중인 (1) 트랜잭션이 있습니다.", "description": "$1 is count of pending transactions" }, - "permissionRequest": { - "message": "권한 요청" + "permissionDetails": { + "message": "권한 세부 정보" }, - "permissionRequestCapitalized": { + "permissionRequest": { "message": "권한 요청" }, "permissionRequested": { "message": "지금 요청됨" }, + "permissionRequestedForAccounts": { + "message": "$1 승인 지금 요청됨", + "description": "Permission cell status for requested permission including accounts, rendered as AvatarGroup which is $1." + }, "permissionRevoked": { "message": "이 업데이트에서 취소됨" }, + "permissionRevokedForAccounts": { + "message": "이 업데이트에서 $1 취소됨", + "description": "Permission cell status for revoked permission including accounts, rendered as AvatarGroup which is $1." + }, "permission_accessNamedSnap": { "message": "$1에 연결", "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." @@ -2836,6 +3442,10 @@ "message": "인터넷에 액세스합니다.", "description": "The description of the `endowment:network-access` permission." }, + "permission_accessNetworkDescription": { + "message": "$1의 인터넷 액세스를 허용합니다. 제삼자 서버와 데이터를 주고받는 데 모두 사용할 수 있습니다.", + "description": "An extended description of the `endowment:network-access` permission. $1 is the snap name." + }, "permission_accessSnap": { "message": "$1 스냅에 연결", "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." @@ -2848,10 +3458,18 @@ "message": "정기적 활동 예약 및 실행", "description": "The description for the `snap_cronjob` permission" }, + "permission_cronjobDescription": { + "message": "$1에게 고정된 시간이나 날짜, 간격으로 주기적으로 실행되는 작업을 수행하도록 허용합니다. 시간에 민감한 상호작용이나 알림을 트리거하는 데 사용할 수 있습니다.", + "description": "An extended description for the `snap_cronjob` permission. $1 is the snap name." + }, "permission_dialog": { "message": "MetaMask 대화창 표시", "description": "The description for the `snap_dialog` permission" }, + "permission_dialogDescription": { + "message": "$1 스냅이 MetaMask 팝업을 만들고 여기에 맞춤 텍스트와 입력란, 그리고 버튼을 표시하여 승인 또는 거부에 활용하도록 허용합니다.\n이는 경고, 컨펌, Snap에 필요한 옵트인 플로우 등을 만드는 데 사용할 수 있습니다.", + "description": "An extended description for the `snap_dialog` permission. $1 is the snap name." + }, "permission_ethereumAccounts": { "message": "주소, 계정 잔액, 활동 및 승인할 트랜잭션 추천 보기", "description": "The description for the `eth_accounts` permission" @@ -2860,30 +3478,138 @@ "message": "이더리움 공급자에 액세스합니다.", "description": "The description for the `endowment:ethereum-provider` permission" }, + "permission_ethereumProviderDescription": { + "message": "$1 스냅이 MetaMask와 직접 소통하여 블록체인에서 데이터를 읽고 메시지 및 트랜잭션을 제안하도록 허용합니다.", + "description": "An extended description for the `endowment:ethereum-provider` permission. $1 is the snap name." + }, + "permission_getEntropy": { + "message": "$1에 대해 고유한 키를 임의로 파생합니다.", + "description": "The description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getEntropyDescription": { + "message": "$1 스냅이 노출을 피하여 $1에 고유한 임의의 키를 파생하도록 허용합니다. 이 키는 MetaMask 계정과 별개이며 개인 키 또는 비밀복구구문과 관련이 없습니다. 다른 Snap은 이 정보에 액세스할 수 없습니다.", + "description": "An extended description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getLocale": { + "message": "원하는 언어로 변경하세요.", + "description": "The description for the `snap_getLocale` permission" + }, + "permission_getLocaleDescription": { + "message": "MetaMask 설정에서 원하는 언어로 $1 스냅을 사용하세요. 이 기능을 사용하면 선택한 언어로 $1의 콘텐츠를 현지화하고 표시할 수 있습니다.", + "description": "An extended description for the `snap_getLocale` permission. $1 is the snap name." + }, + "permission_homePage": { + "message": "사용자 지정 화면 표시", + "description": "The description for the `endowment:page-home` permission" + }, + "permission_homePageDescription": { + "message": "$1에서 MetaMask의 사용자 지정 홈 화면 구성에 참여하도록 허용합니다. 이는 사용자 인터페이스, 구성, 대시보드에 사용할 수 있습니다.", + "description": "An extended description for the `endowment:page-home` permission. $1 is the snap name." + }, + "permission_keyring": { + "message": "이더리움 계정 추가 및 제어 요청 허용", + "description": "The description for the `endowment:keyring` permission" + }, + "permission_keyringDescription": { + "message": "$1 스냅이 계정 추가 또는 제거 요청을 받고 해당 계정을 대신하여 서명하고 트랜잭션할 수 있도록 합니다.", + "description": "An extended description for the `endowment:keyring` permission. $1 is the snap name." + }, "permission_lifecycleHooks": { "message": "라이프사이클 훅 사용", "description": "The description for the `endowment:lifecycle-hooks` permission" }, + "permission_lifecycleHooksDescription": { + "message": "$1 스냅이 라이프사이클 훅을 사용하도록 허용하여 라이프사이클 동안 코드를 특정 횟수만큼 실행합니다.", + "description": "An extended description for the `endowment:lifecycle-hooks` permission. $1 is the snap name." + }, "permission_manageAccounts": { "message": "이더리움 계정 추가 및 제어", "description": "The description for `snap_manageAccounts` permission" }, + "permission_manageAccountsDescription": { + "message": "$1 스냅이 이더리움 계정을 추가 또는 제거하도록 허용한 후, 해당 계정을 이용하여 트랜잭션하고 서명합니다.", + "description": "An extended description for the `snap_manageAccounts` permission. $1 is the snap name." + }, + "permission_manageBip32Keys": { + "message": "$1 계정 관리", + "description": "The description for the `snap_getBip32Entropy` permission. $1 is a derivation path, e.g. 'm/44'/0'/0' (secp256k1)'." + }, + "permission_manageBip44AndBip32KeysDescription": { + "message": "$1 스냅이 요청된 네트워크에서 계정과 자산을 관리하도록 허용합니다. 해당 계정은 비밀복구구문(공개하지 않음)을 사용하여 파생되고 백업됩니다. 키를 파생할 수 있는 기능을 통해 $1 스냅은 이더리움(EVM)뿐 아니라 다양한 블록체인 프로토콜을 지원할 수 있습니다.", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions. $1 is the snap name." + }, + "permission_manageBip44Keys": { + "message": "$1 계정 관리", + "description": "The description for the `snap_getBip44Entropy` permission. $1 is the name of a protocol, e.g. 'Filecoin'." + }, "permission_manageState": { "message": "장치의 데이터를 저장하고 관리합니다.", "description": "The description for the `snap_manageState` permission" }, + "permission_manageStateDescription": { + "message": "$1 스냅이 암호화를 통해 데이터를 안전하게 저장, 업데이트, 검색하도록 허용합니다. 다른 Snap은 이 정보에 액세스할 수 없습니다.", + "description": "An extended description for the `snap_manageState` permission. $1 is the snap name." + }, + "permission_nameLookup": { + "message": "도메인 및 주소 조회를 제공합니다.", + "description": "The description for the `endowment:name-lookup` permission." + }, + "permission_nameLookupDescription": { + "message": "Snap이 주소 및 도메인 조회를 가져와 MetaMask UI의 다른 부분에 표시하도록 허용합니다.", + "description": "An extended description for the `endowment:name-lookup` permission." + }, "permission_notifications": { "message": "알림을 표시합니다.", "description": "The description for the `snap_notify` permission" }, + "permission_notificationsDescription": { + "message": "$1 스냅이 MetaMask에서 알림을 표시하도록 허용합니다. Snap이 작업이 필요하거나 기한이 있는 정보를 짧은 알림으로 트리거할 수 있습니다.", + "description": "An extended description for the `snap_notify` permission. $1 is the snap name." + }, + "permission_rpc": { + "message": "$1 측이 $2 스냅과 직접 소통하도록 허용합니다.", + "description": "The description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescription": { + "message": "$$1 측이 $2 스냅으로 메시지를 전송하고 $2에서 응답을 받도록 허용합니다.", + "description": "An extended description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescriptionOriginList": { + "message": "$1 및 $2", + "description": "A list of allowed origins where $2 is the last origin of the list and $1 is the rest of the list separated by ','." + }, + "permission_signatureInsight": { + "message": "서명 인사이트 모달을 표시합니다.", + "description": "The description for the `endowment:signature-insight` permission" + }, + "permission_signatureInsightDescription": { + "message": "$1 스냅이 승인 전에 서명 요청에 대한 인사이트가 포함된 모달을 표시하도록 허용합니다. 피싱 방지 및 보안 솔루션에 사용할 수 있습니다.", + "description": "An extended description for the `endowment:signature-insight` permission. $1 is the snap name." + }, + "permission_signatureInsightOrigin": { + "message": "서명 요청 웹사이트의 출처 보기", + "description": "The description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission" + }, + "permission_signatureInsightOriginDescription": { + "message": "$1 스냅이 서명 요청을 시작하는 웹사이트의 출처(URI) 를 볼 수 있도록 허용합니다. 피싱 방지와 보안 솔루션에 사용할 수 있습니다.", + "description": "An extended description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission. $1 is the snap name." + }, "permission_transactionInsight": { "message": "트랜잭션 인사이트를 가져와 표시합니다.", "description": "The description for the `endowment:transaction-insight` permission" }, + "permission_transactionInsightDescription": { + "message": "$1 스냅이 트랜잭션을 디코딩하고 MetaMask UI에서 인사이트를 표시하도록 허용합니다. 피싱 방지와 보안 솔루션에 사용할 수 있습니다.", + "description": "An extended description for the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_transactionInsightOrigin": { "message": "트랜잭션을 추천하는 웹사이트 출처 보기", "description": "The description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission" }, + "permission_transactionInsightOriginDescription": { + "message": "$1 스냅이 트랜잭션을 제안하는 웹사이트의 출처(URI)를 볼 수 있도록 허용합니다. 피싱 방지와 보안 솔루션에 사용할 수 있습니다.", + "description": "An extended description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_unknown": { "message": "알 수 없는 권한: $1", "description": "$1 is the name of a requested permission that is not recognized." @@ -2892,29 +3618,66 @@ "message": "$1 공개 키 보기($2).", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a derivation path, e.g. 'm/44'/0'/0''. $2 is the elliptic curve name, e.g. 'secp256k1'." }, + "permission_viewBip32PublicKeysDescription": { + "message": "$2 스냅이 $1에 대한 공개 키(및 주소)를 볼 수 있도록 허용합니다. 이를 통해 계정이나 자산에 대한 통제권이 부여되지는 않습니다.", + "description": "An extended description for the `snap_getBip32PublicKey` permission. $1 is a derivation path (name). $2 is the snap name." + }, "permission_viewNamedBip32PublicKeys": { "message": "$1에 관한 공개 키 보기", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a name for the derivation path, e.g., 'Ethereum accounts'." }, + "permission_walletSwitchEthereumChain": { + "message": "다음 네트워크로 전환하여 사용", + "description": "The label for the `wallet_switchEthereumChain` permission" + }, "permission_webAssembly": { "message": "WebAssembly 지원", "description": "The description of the `endowment:webassembly` permission." }, + "permission_webAssemblyDescription": { + "message": "$1 스냅이 WebAssembly를 통해 하위 레벨 실행 환경에 액세스하도록 허용합니다.", + "description": "An extended description of the `endowment:webassembly` permission. $1 is the snap name." + }, "permissions": { "message": "권한" }, - "permissionsTitle": { - "message": "권한" + "permissionsPageEmptyContent": { + "message": "표시할 항목이 없습니다" + }, + "permissionsPageEmptySubContent": { + "message": "여기에서 설치된 Snap 또는 연결된 사이트의 권한을 확인할 수 있습니다." + }, + "permissionsPageTourDescription": { + "message": "연결된 사이트 또는 설치된 Snap의 권한을 관리하기 위한 제어판입니다." }, - "permissionsTourDescription": { - "message": "연결된 계정을 찾아 여기서 권한을 관리하세요" + "permissionsPageTourTitle": { + "message": "이제 연결된 사이트에 권한이 부여됩니다" }, "personalAddressDetected": { "message": "개인 주소가 발견되었습니다. 토큰 계약 주소를 입력하세요." }, + "petnamesEnabledToggle": { + "message": "닉네임 허용" + }, + "petnamesEnabledToggleDescription": { + "message": "이 기능을 사용하면 모든 주소에 닉네임을 지정할 수 있습니다. 가능한 경우 상호 작용하는 주소에 닉네임을 추천합니다." + }, + "pinExtensionDescription": { + "message": "확장 메뉴로 이동 후 MetaMask Institutional을 고정하여 원활하게 액세스하세요." + }, + "pinExtensionTitle": { + "message": "확장 고정" + }, + "pinToTop": { + "message": "맨 위에 고정" + }, "pleaseConfirm": { "message": "컨펌하세요" }, + "plusMore": { + "message": "+ $1개 추가", + "description": "$1 is the number of additional items" + }, "plusXMore": { "message": "+ 그 외 $1개", "description": "$1 is a number of additional but unshown items in a list- this message will be shown in place of those items" @@ -2940,6 +3703,9 @@ "primaryCurrencySettingDescription": { "message": "체인의 고유 통화(예: ETH)로 값을 우선 표시하려면 고유를 선택합니다. 선택한 명목 통화로 값을 우선 표시하려면 명목을 선택합니다." }, + "primaryType": { + "message": "기본 유형" + }, "priorityFee": { "message": "우선 요금" }, @@ -2960,6 +3726,18 @@ "message": "$1 비공개 키", "description": "$1 represents the account name" }, + "privateKeyHidden": { + "message": "개인 키 입력이 표시되지 않습니다", + "description": "Explains that the private key input is hidden" + }, + "privateKeyShow": { + "message": "개인 키 입력 표시/숨기기", + "description": "Describes a toggle that is used to show or hide the private key input" + }, + "privateKeyShown": { + "message": "이 개인 키 입력은 표시됩니다", + "description": "Explains that the private key input is being shown" + }, "privateKeyWarning": { "message": "경고: 이 키를 노출하지 마세요. 비공개 키가 있는 사람이라면 누구든 회원님의 계정에 있는 자산을 훔칠 수 있습니다." }, @@ -2969,6 +3747,21 @@ "proceedWithTransaction": { "message": "계속 진행" }, + "productAnnouncements": { + "message": "제품 공지" + }, + "profileSync": { + "message": "프로필 동기화" + }, + "profileSyncConfirmation": { + "message": "프로필 동기화를 끄면 알림을 받을 수 없게 됩니다." + }, + "profileSyncDescription": { + "message": "MetaMask가 기기 간에 일부 설정을 동기화하는 데 사용할 프로필을 생성합니다. 알림을 받으려면 프로필이 필요합니다. $1." + }, + "profileSyncPrivacyLink": { + "message": "개인 정보 보호 방법 알아보기" + }, "proposedApprovalLimit": { "message": "제안된 승인 한도" }, @@ -2978,6 +3771,78 @@ "publicAddress": { "message": "공개 주소" }, + "pushPlatformNotificationsFundsReceivedDescription": { + "message": "$1 $2을(를) 받았습니다" + }, + "pushPlatformNotificationsFundsReceivedDescriptionDefault": { + "message": "토큰을 받았습니다" + }, + "pushPlatformNotificationsFundsReceivedTitle": { + "message": "자금 수령 완료" + }, + "pushPlatformNotificationsFundsSentDescription": { + "message": "$1 $2을(를) 보냈습니다" + }, + "pushPlatformNotificationsFundsSentDescriptionDefault": { + "message": "토큰을 보냈습니다" + }, + "pushPlatformNotificationsFundsSentTitle": { + "message": "자금 전송 완료" + }, + "pushPlatformNotificationsNftReceivedDescription": { + "message": "새 NFT를 받았습니다" + }, + "pushPlatformNotificationsNftReceivedTitle": { + "message": "NFT 수령 완료" + }, + "pushPlatformNotificationsNftSentDescription": { + "message": "NFT를 보냈습니다" + }, + "pushPlatformNotificationsNftSentTitle": { + "message": "NFT 전송 완료" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedDescription": { + "message": "Lido 스테이킹에 성공했습니다" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedTitle": { + "message": "스테이킹 완료" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnDescription": { + "message": "Lido 스테이킹이 인출 준비가 되었습니다" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnTitle": { + "message": "스테이킹 인출 준비 완료" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedDescription": { + "message": "Lido 인출에 성공했습니다" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedTitle": { + "message": "인출 완료" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedDescription": { + "message": "Lido 인출 요청이 제출되었습니다" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedTitle": { + "message": "인출 요청 완료" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedDescription": { + "message": "RocketPool 스테이킹에 성공했습니다" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedTitle": { + "message": "스테이킹 완료" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedDescription": { + "message": "RocketPool 언스테이킹에 성공했습니다" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedTitle": { + "message": "언스테이킹 완료" + }, + "pushPlatformNotificationsSwapCompletedDescription": { + "message": "MetaMask 스왑에 성공했습니다" + }, + "pushPlatformNotificationsSwapCompletedTitle": { + "message": "스왑 완료" + }, "queued": { "message": "대기열에 지정됨" }, @@ -2996,9 +3861,15 @@ "receive": { "message": "받기" }, + "receiveTokensCamelCase": { + "message": "토큰 받기" + }, "recipientAddressPlaceholder": { "message": "공개 주소(0x) 또는 ENS 제목 입력" }, + "recipientAddressPlaceholderFlask": { + "message": "공개 주소(0x) 또는 도메인 이름 입력" + }, "recommendedGasLabel": { "message": "권장됨" }, @@ -3026,6 +3897,12 @@ "recoveryPhraseReminderTitle": { "message": "자신의 자금을 지키세요" }, + "redesignedConfirmationsEnabledToggle": { + "message": "개선된 서명 요청" + }, + "redesignedConfirmationsToggleDescription": { + "message": "이 기능을 켜면 개선된 형식의 서명 요청을 확인할 수 있습니다." + }, "refreshList": { "message": "새로 고침 목록" }, @@ -3068,15 +3945,30 @@ "removeJWTDescription": { "message": "정말 이 토큰을 삭제하시겠습니까? 이 토큰에 할당된 모든 계정이 확장 프로그램에서도 제거됩니다." }, + "removeKeyringSnap": { + "message": "이 Snap을 제거하면 이 계정들이 MetaMask에서 제거됩니다:" + }, + "removeKeyringSnapToolTip": { + "message": "Snap은 계정을 제어하며 Snap을 제거하면 계정도 MetaMask에서 제거되지만, 블록체인에는 남게 됩니다." + }, "removeNFT": { "message": "NFT 제거" }, + "removeNftErrorMessage": { + "message": "이 NFT를 제거할 수 없습니다." + }, "removeNftMessage": { "message": "NFT가 성공적으로 제거되었습니다!" }, "removeSnap": { "message": "스냅 제거" }, + "removeSnapAccountDescription": { + "message": "계속하면 이 계정을 MetaMask에서 사용할 수 없습니다." + }, + "removeSnapAccountTitle": { + "message": "계정 제거" + }, "removeSnapConfirmation": { "message": "$1(을)를 제거하시겠습니까?", "description": "$1 represents the name of the snap" @@ -3087,12 +3979,24 @@ "replace": { "message": "대체" }, + "reportIssue": { + "message": "문제 신고" + }, "requestFlaggedAsMaliciousFallbackCopyReason": { "message": "보안 공급입체가 추가 정보를 공유하지 않았습니다" }, "requestFlaggedAsMaliciousFallbackCopyReasonTitle": { "message": "악성으로 플래그 표시된 요청" }, + "requestFrom": { + "message": "요청자:" + }, + "requestFromInfo": { + "message": "서명이 필요한 사이트입니다." + }, + "requestFromTransactionDescription": { + "message": "컨펌이 필요한 사이트입니다." + }, "requestMayNotBeSafe": { "message": "요청이 안전하지 않을 수 있습니다" }, @@ -3114,6 +4018,9 @@ "reset": { "message": "재설정" }, + "resetStates": { + "message": "상태 초기화" + }, "resetWallet": { "message": "지갑 초기화" }, @@ -3196,9 +4103,15 @@ "message": "MetaMask 지원팀은 이러한 정보를 절대로 묻지 않습니다,", "description": "The bolded texted in the second part of 'revealSeedWordsWarning'" }, + "revealSensitiveContent": { + "message": "민감한 콘텐츠 공개" + }, "revealTheSeedPhrase": { "message": "시드 구문 보기" }, + "reviewAlerts": { + "message": "경고 검토하기" + }, "revokeAllTokensTitle": { "message": "모든 $1에 액세스할 수 있는 권한을 철회하시겠습니까?", "description": "$1 is the symbol of the token for which the user is revoking approval" @@ -3249,6 +4162,9 @@ "searchAccounts": { "message": "계정 검색" }, + "searchTokens": { + "message": "토큰 검색" + }, "secretRecoveryPhrase": { "message": "비밀복구구문" }, @@ -3265,7 +4181,8 @@ "message": "보안 경고" }, "securityAlertsDescription": { - "message": "이 기능은 개인정보를 보호하면서 트랜잭션 및 서명 요청을 적극적으로 검토하여 이더리움 메인넷에서 악의적인 활동이 있는 경우 경고합니다. 사용자 데이터는 이 서비스를 제공하는 제삼자와 공유되지 않습니다. 요청을 승인하기 전에 항상 직접 확인하세요. 이 기능이 모든 악의적인 활동 탐지를 보장하는 것은 아닙니다." + "message": "이 기능은 거래 및 서명 요청을 적극적으로 검토하여 악의적인 활동을 경고합니다. $1", + "description": "Link to learn more about security alerts" }, "securityAndPrivacy": { "message": "보안 및 프라이버시" @@ -3355,6 +4272,9 @@ "selectAnAccountHelp": { "message": "MetaMask Institutional에서 사용할 수탁 계정을 선택하세요." }, + "selectEnableDisplayMediaPrivacyPreference": { + "message": "NFT 미디어 표시 켜기" + }, "selectHdPath": { "message": "HD 경로 선택" }, @@ -3376,18 +4296,41 @@ "send": { "message": "보내기" }, + "sendAToken": { + "message": "토큰 보내기" + }, "sendBugReport": { "message": "버그 리포트 전송" }, + "sendNoContactsConversionText": { + "message": "여기를 클릭" + }, + "sendNoContactsDescription": { + "message": "연락처를 사용하면 다른 계정으로 여러 번 트랜잭션을 안전하게 전송할 수 있습니다. 연락처를 만들려면, $1", + "description": "$1 represents the action text 'click here'" + }, + "sendNoContactsTitle": { + "message": "아직 연락처가 없습니다" + }, + "sendSelectReceiveAsset": { + "message": "수취할 자산 선택" + }, + "sendSelectSendAsset": { + "message": "전송할 자산 선택" + }, "sendSpecifiedTokens": { "message": "$1 보내기", "description": "Symbol of the specified token" }, - "sendTo": { - "message": "보낼 대상:" + "sendSwapSubmissionWarning": { + "message": "이 버튼을 클릭하면 즉시 스왑 트랜젝션이 시작됩니다. 계속하기 전에 트랜젝션 세부 정보를 검토하세요." }, - "sendTokens": { - "message": "토큰 보내기" + "sendTokenAsToken": { + "message": "$2(으)로 $1 전송하기", + "description": "Used in the transaction display list to describe a swap and send. $1 and $2 are the symbols of tokens in involved in the swap." + }, + "sendingAsset": { + "message": "$1 전송하기" }, "sendingDisabled": { "message": "ERC-1155 NFT 자산은 아직 지원되지 않습니다." @@ -3400,9 +4343,15 @@ "message": "경고: 자금 손실이 발생할 수 있는 토큰 계약으로 전송하게 됩니다. $1", "description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning" }, + "sendingZeroAmount": { + "message": "0 $1 전송 중입이니다." + }, "sepolia": { "message": "Sepolia 테스트 네트워크" }, + "serviceWorkerKeepAlive": { + "message": "서비스 작업자 유지" + }, "setAdvancedPrivacySettingsDetails": { "message": "이와 같이 MetaMask는 신용있는 타사의 서비스를 사용하여 제품 가용성과 안전성을 향상합니다." }, @@ -3422,9 +4371,21 @@ "settingsSearchMatchingNotFound": { "message": "검색 결과가 없습니다." }, + "settingsSubHeadingSignaturesAndTransactions": { + "message": "서명 및 트랜잭션 요청" + }, "show": { "message": "보기" }, + "showAccount": { + "message": "계정 표시" + }, + "showExtensionInFullSizeView": { + "message": "확장 브라우저를 전체 화면으로 보기" + }, + "showExtensionInFullSizeViewDescription": { + "message": "이 옵션을 이용하면 확장 아이콘을 클릭할 때 기본으로 전체 화면이 나타납니다." + }, "showFiatConversionInTestnets": { "message": "테스트넷에 전환 표시" }, @@ -3444,6 +4405,9 @@ "message": "이 항목을 선택하면 Etherscan을 사용해 거래 목록에 수신 거래를 표시할 수 있습니다.", "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" }, + "showIncomingTransactionsExplainer": { + "message": "이는 네트워크마다 다른 제삼자 API에 의존하며, 이더리움 주소와 IP 주소가 노출됩니다." + }, "showMore": { "message": "더 보기" }, @@ -3483,9 +4447,46 @@ "signin": { "message": "로그인" }, + "signing": { + "message": "서명" + }, + "simulationDetailsFailed": { + "message": "추정치를 불러오는 동안 오류가 발생했습니다." + }, + "simulationDetailsFiatNotAvailable": { + "message": "이용할 수 없음" + }, + "simulationDetailsIncomingHeading": { + "message": "받음:" + }, + "simulationDetailsNoBalanceChanges": { + "message": "지갑에 예상 변동 사항 없음" + }, + "simulationDetailsOutgoingHeading": { + "message": "보냄:" + }, + "simulationDetailsTitle": { + "message": "예상 변동 사항" + }, + "simulationDetailsTitleTooltip": { + "message": "예상 변동 사항은 이 트랜잭션을 진행할 경우 발생하는 결과를 예측한 것입니다. 이는 예측일 뿐 결과를 보장하지는 않습니다." + }, + "simulationDetailsTotalFiat": { + "message": "합계 = $1", + "description": "$1 is the total amount in fiat currency on one side of the transaction" + }, + "simulationDetailsTransactionReverted": { + "message": "이 트랜잭션은 실패할 가능성이 높습니다" + }, "simulationErrorMessageV2": { "message": "가스를 추정할 수 없었습니다. 계약에 오류가 있을 수 있으며 이 트랜잭션이 실패할 수 있습니다." }, + "simulationsSettingDescription": { + "message": "이 기능을 켜면 트랜잭션을 확정하기 전에 트랜잭션의 잔액 변동을 추정할 수 있습니다. 이 기능이 트랜잭션의 최종 결과를 보장하지는 않습니다. $1" + }, + "simulationsSettingSubHeader": { + "message": "예상 잔액 변동" + }, "skip": { "message": "건너뛰기" }, @@ -3498,20 +4499,99 @@ "smartContracts": { "message": "스마트 계약" }, - "smartSwapsAreHere": { - "message": "스마트 스왑이 시작되었습니다!" - }, - "smartSwapsDescription": { - "message": "MetaMask 스왑이 더욱 스마트해졌습니다! 스마트 스왑을 활성화하면 MetaMask가 프로그램을 통해 스왑을 최적화하여 다음과 같은 활동에 도움을 드립니다." - }, "smartSwapsErrorNotEnoughFunds": { "message": "스마트 스왑 자금 부족" }, "smartSwapsErrorUnavailable": { "message": "스마트 스왑을 잠시 사용할 수 없습니다." }, + "smartTransactionCancelled": { + "message": "트랜잭션이 취소되었습니다" + }, + "smartTransactionCancelledDescription": { + "message": "트랜잭션이 완료되지 않았습니다. 가스비 지출이 없도록 트랜잭션을 취소했습니다." + }, + "smartTransactionError": { + "message": "트랜잭션 실패" + }, + "smartTransactionErrorDescription": { + "message": "시장 상황이 갑자기 변하면 실패할 수 있습니다. 문제가 지속되면 MetaMask 고객 지원으로 문의하세요." + }, + "smartTransactionPending": { + "message": "트랜잭션 제출 중" + }, + "smartTransactionSuccess": { + "message": "트랜잭션 완료" + }, + "smartTransactionTakingTooLong": { + "message": "기다리게 해서 죄송합니다" + }, + "smartTransactionTakingTooLongDescription": { + "message": "$1 이내에 트랜잭션이 완료되지 않으면 트랜잭션이 취소되고 가스비가 부과되지 않습니다.", + "description": "$1 is remaining time in seconds" + }, + "smartTransactions": { + "message": "스마트 트랜잭션" + }, + "smartTransactionsBenefit1": { + "message": "99.5% 성공률" + }, + "smartTransactionsBenefit2": { + "message": "비용 절감" + }, + "smartTransactionsBenefit3": { + "message": "실시간 업데이트" + }, + "smartTransactionsDescription": { + "message": "스마트 트랜잭션으로 선행거래를 방지하고 더 높은 성공률과 가시성을 확보하세요." + }, + "smartTransactionsDescription2": { + "message": "이더리움에서만 사용할 수 있습니다. 설정에서 언제든지 활성화하거나 비활성화할 수 있습니다. $1", + "description": "$1 is an external link to learn more about Smart Transactions" + }, + "smartTransactionsOptItModalTitle": { + "message": "트랜잭션 보호 강화" + }, + "snapAccountCreated": { + "message": "계정 생성됨" + }, + "snapAccountCreatedDescription": { + "message": "새 계정을 사용할 준비가 되었습니다!" + }, + "snapAccountCreationFailed": { + "message": "계정 생성 실패" + }, + "snapAccountCreationFailedDescription": { + "message": "$1에서 계정을 만들지 못했습니다.", + "description": "$1 is the snap name" + }, + "snapAccountRedirectFinishSigningTitle": { + "message": "서명 완료" + }, + "snapAccountRedirectSiteDescription": { + "message": "$1의 지침을 따르세요" + }, + "snapAccountRemovalFailed": { + "message": "계정 삭제 실패" + }, + "snapAccountRemovalFailedDescription": { + "message": "$1에서 계정을 삭제하지 못했습니다.", + "description": "$1 is the snap name" + }, + "snapAccountRemoved": { + "message": "계정 제거됨" + }, + "snapAccountRemovedDescription": { + "message": "이 계정은 더 이상 MetaMask에서 사용할 수 없습니다." + }, + "snapAccounts": { + "message": "계정 Snap" + }, + "snapAccountsDescription": { + "message": "제삼자 Snap이 제어하는 계정입니다." + }, "snapConnectionWarning": { - "message": "$1에서 $2 스냅 연결을 원합니다. 해당 웹사이트를 신뢰할 수 있는 경우에만 진행하세요.", + "message": "$1에서 $2 사용을 원합니다.", "description": "$2 is the snap and $1 is the dapp requesting connection to the snap." }, "snapContent": { @@ -3522,15 +4602,35 @@ "message": "웹사이트" }, "snapInstallRequest": { - "message": "$1 설치는 다음과 같은 권한을 허용합니다. $1 스냅을 신뢰하는 경우에만 계속 진행하세요.", + "message": "$1 설치는 다음과 같은 권한을 허용합니다.", "description": "$1 is the snap name." }, "snapInstallSuccess": { "message": "설치 완료" }, + "snapInstallWarningCheck": { + "message": "$1 스냅이 다음을 수행할 수 있는 권한을 요청합니다:", + "description": "Warning message used in popup displayed on snap install. $1 is the snap name." + }, "snapInstallWarningHeading": { "message": "주의하여 진행하세요" }, + "snapInstallWarningPermissionDescriptionForBip32View": { + "message": "$1 스냅이 사용자의 공개 키(및 주소)를 볼 수 있도록 허용합니다. 이를 통해 계정이나 자산에 대한 통제권이 부여되지는 않습니다.", + "description": "An extended description for the `snap_getBip32PublicKey` permission used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionDescriptionForEntropy": { + "message": "$1 Snap이 요청된 네트워크에서 계정과 자산을 관리하도록 허용합니다. 해당 계정은 비밀복구구문(공개하지 않음)을 사용하여 파생되고 백업됩니다. 키를 파생할 수 있는 기능을 통해 $1 스냅은 이더리움(EVM)뿐 아니라 다양한 블록체인 프로토콜을 지원할 수 있습니다.", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionNameForEntropy": { + "message": "$1 계정 관리", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, + "snapInstallWarningPermissionNameForViewPublicKey": { + "message": "$1에 관한 공개 키 보기", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, "snapInstallationErrorDescription": { "message": "$1 스냅을 설치할 수 없습니다.", "description": "Error description used when snap installation fails. $1 is the snap name." @@ -3548,6 +4648,10 @@ "snapResultSuccessDescription": { "message": "$1 사용 가능" }, + "snapUpdateAlertDescription": { + "message": "$1의 최신 버전 받기", + "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." + }, "snapUpdateAvailable": { "message": "업데이트 가능" }, @@ -3559,22 +4663,40 @@ "message": "업데이트 실패", "description": "Error title used when snap update fails." }, + "snapUpdateRequest": { + "message": "$1 업데이트는 다음과 같은 권한을 허용합니다.", + "description": "$1 is the Snap name." + }, "snapUpdateSuccess": { "message": "업데이트 완료" }, + "snapUrlIsBlocked": { + "message": "이 Snap이 차단된 사이트로 이동하려 합니다. $1." + }, "snaps": { "message": "스냅" }, - "snapsInvalidUIError": { - "message": "스냅에서 지정한 UI가 올바르지 않습니다." + "snapsConnected": { + "message": "Snap 연결됨" }, "snapsNoInsight": { "message": "스냅이 인사이트를 가져오지 못했습니다" }, + "snapsPrivacyWarningFirstMessage": { + "message": "귀하는 Consensys $1에 정의된 바와 같이 달리 명시되지 않는 한 설치하는 모든 Snap이 타사 서비스임을 인정합니다. 타사 서비스 이용은 해당 타사 서비스 제공업체가 정한 별도의 약관이 적용됩니다. Consensys는 특정인이 특정한 이유로 Snap을 사용하는 것을 권장하지 않습니다. 타사 서비스에 액세스, 신뢰, 사용하는 것은 본인의 책임입니다. Consensys는 타사 서비스 사용으로 인해 귀하의 계정에 발생하는 손실에 대한 모든 책임과 의무를 부인합니다.", + "description": "First part of a message in popup modal displayed when installing a snap for the first time. $1 is terms of use link." + }, "snapsPrivacyWarningSecondMessage": { "message": "타사와 공유하는 모든 정보는 해당 타사의 개인정보 처리방침에 따라 직접 수집됩니다. 더 자세한 내용은 해당 회사의 개인정보 처리방침을 참고하시기 바랍니다.", "description": "Second part of a message in popup modal displayed when installing a snap for the first time." }, + "snapsPrivacyWarningThirdMessage": { + "message": "Consensys는 귀하가 타사와 공유한 정보에 접근할 수 없습니다.", + "description": "Third part of a message in popup modal displayed when installing a snap for the first time." + }, + "snapsSettings": { + "message": "Snap 설정" + }, "snapsTermsOfUse": { "message": "이용약관" }, @@ -3588,12 +4710,19 @@ "someNetworksMayPoseSecurity": { "message": "네트워크에 따라 보안이나 개인 정보 유출의 위험이 있을 수 있습니다. 네트워크 추가 및 사용 이전에 위험 요소를 파악하세요." }, + "somethingDoesntLookRight": { + "message": "무언가 잘못되었나요? $1", + "description": "A false positive message for users to contact support. $1 is a link to the support page." + }, "somethingIsWrong": { "message": "문제가 발생했습니다. 페이지를 다시 로드하세요." }, "somethingWentWrong": { "message": "죄송합니다! 문제가 생겼습니다." }, + "source": { + "message": "소스" + }, "speedUp": { "message": "가속화" }, @@ -3728,6 +4857,14 @@ "stake": { "message": "스테이크" }, + "startYourJourney": { + "message": "$1 토큰으로 여정을 시작하세요", + "description": "$1 is the token symbol" + }, + "startYourJourneyDescription": { + "message": "지갑에 $1 토큰을 추가하여 웹3를 시작하세요.", + "description": "$1 is the token symbol" + }, "stateLogError": { "message": "상태 로그를 가져오는 도중 오류가 발생했습니다." }, @@ -3740,6 +4877,9 @@ "stateLogsDescription": { "message": "상태 로그에 공개 계정 주소와 전송된 트랜잭션이 있습니다." }, + "states": { + "message": "상태" + }, "status": { "message": "상태" }, @@ -3783,18 +4923,6 @@ "strong": { "message": "강함" }, - "stxBenefit1": { - "message": "트랜잭션 비용 최소화하기" - }, - "stxBenefit2": { - "message": "트랜잭션 실패 줄이기" - }, - "stxBenefit3": { - "message": "중단된 트랜잭션 제거하기" - }, - "stxBenefit4": { - "message": "프런트 러닝 방지" - }, "stxCancelled": { "message": "스왑이 실패했을 것입니다" }, @@ -3804,6 +4932,10 @@ "stxCancelledSubDescription": { "message": "스왑을 다시 진행하세요. 다음에도 유사한 위험이 발생한다면 보호해 드리겠습니다." }, + "stxEstimatedCompletion": { + "message": "예상 잔여 시간: <$1", + "description": "$1 is remeaning time in minutes and seconds, e.g. 0:10" + }, "stxFailure": { "message": "스왑 실패" }, @@ -3811,6 +4943,9 @@ "message": "시장 상황이 갑자기 변하면 실패할 수 있습니다. 문제가 지속되면 $1(으)로 문의하세요.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInDescription": { + "message": "이더리움 메인넷에서 더욱 안정적이고 안전하게 트랜잭션을 진행하려면 스마트 트랜잭션을 활성화하세요. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "스왑을 비공개로 제출하는 중..." }, @@ -3849,12 +4984,21 @@ "submitted": { "message": "제출됨" }, + "suggestedTokenSymbol": { + "message": "추천 티커 심볼:" + }, "support": { "message": "지원" }, "supportCenter": { "message": "지원 센터 방문하기" }, + "surveyConversion": { + "message": "설문조사에 참여하세요" + }, + "surveyTitle": { + "message": "MetaMask의 미래를 그리세요" + }, "swap": { "message": "스왑" }, @@ -3874,6 +5018,9 @@ "swapAmountReceivedInfo": { "message": "수신하는 최소 금액입니다. 슬리패지에 따라 추가 금액을 받을 수도 있습니다." }, + "swapAndSend": { + "message": "스왑 및 전송" + }, "swapAnyway": { "message": "스왑 계속 진행" }, @@ -3989,6 +5136,10 @@ "message": "$1%의 MetaMask 요금이 포함됩니다.", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." }, + "swapIncludesMMFeeAlt": { + "message": "견적에는 $1%의 MetaMask 수수료가 반영됩니다", + "description": "Provides information about the fee that metamask takes for swaps using the latest copy. $1 is a decimal number." + }, "swapIncludesMetaMaskFeeViewAllQuotes": { "message": "$1% MetaMask 요금 - $2 포함", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number and $2 is a link to view all quotes." @@ -3996,6 +5147,9 @@ "swapLearnMore": { "message": "스왑 자세히 알아보기" }, + "swapLiquiditySourceInfo": { + "message": "저희는 여러 유동성 공급원(거래소, 애그리게이터, 투자전문기관)을 검색하여 환율과 네트워크 수수료를 비교해 드립니다." + }, "swapLowSlippage": { "message": "낮은 슬리피지" }, @@ -4268,6 +5422,9 @@ "switchEthereumChainConfirmationTitle": { "message": "이 사이트가 네트워크를 전환하도록 허용하시겠습니까?" }, + "switchInputCurrency": { + "message": "입력 통화 전환" + }, "switchNetwork": { "message": "네트워크 전환" }, @@ -4281,14 +5438,15 @@ "switchToThisAccount": { "message": "이 계정으로 전환" }, - "switchedTo": { - "message": "다음으로 변경했습니다:" + "switchedNetworkToastDecline": { + "message": "다시 표시 안 함" }, - "switcherTitle": { - "message": "네트워크 전환기" + "switchedNetworkToastMessage": { + "message": "$1 계정이 현재 $2 네트워크에서 활성화되어 있습니다", + "description": "$1 represents the account name, $2 represents the network name" }, - "switcherTourDescription": { - "message": "아이콘을 클릭하면 네트워크가 변경되거나 새로운 네트워크가 추가됩니다" + "switchedTo": { + "message": "다음으로 변경했습니다:" }, "switchingNetworksCancelsPendingConfirmations": { "message": "네트워크를 전환하면 대기 중인 모든 컨펌 작업이 취소됩니다." @@ -4388,6 +5546,18 @@ "toggleEthSignOn": { "message": "켜기(비권장 사항)" }, + "toggleRequestQueueDescription": { + "message": "이 기능을 이용하면 모든 사이트에 한 가지 네트워크를 선택하여 사용하는 대신, 사이트별로 네트워크를 다르게 선택할 수 있습니다. 이 기능을 사용하면 수동으로 네트워크를 전환하지 않아도 되므로 특정 사이트에서 사용자 경험이 저해되지 않습니다." + }, + "toggleRequestQueueField": { + "message": "각 사이트별 네트워크 선택" + }, + "toggleRequestQueueOff": { + "message": "끄기" + }, + "toggleRequestQueueOn": { + "message": "켜기" + }, "token": { "message": "토큰" }, @@ -4404,7 +5574,7 @@ "message": "토큰 계약 주소" }, "tokenDecimalFetchFailed": { - "message": "토큰 소수자리 필요" + "message": "토큰 십진수가 필요합니다. $1에서 찾아보세요" }, "tokenDecimalTitle": { "message": "토큰 소수점:" @@ -4443,6 +5613,9 @@ "tooltipSatusConnected": { "message": "연결됨" }, + "tooltipSatusConnectedUpperCase": { + "message": "연결됨" + }, "tooltipSatusNotConnected": { "message": "연결되지 않음" }, @@ -4583,6 +5756,39 @@ "tryAgain": { "message": "다시 시도" }, + "turnOff": { + "message": "끄기" + }, + "turnOffMetamaskNotificationsError": { + "message": "알림을 비활성화하는 동안 오류가 발생했습니다. 나중에 다시 시도해 주세요." + }, + "turnOn": { + "message": "켜기" + }, + "turnOnMetamaskNotifications": { + "message": "알림 켜기" + }, + "turnOnMetamaskNotificationsButton": { + "message": "켜기" + }, + "turnOnMetamaskNotificationsError": { + "message": "알림을 생성하는 동안 오류가 발생했습니다. 나중에 다시 시도해 주세요." + }, + "turnOnMetamaskNotificationsMessageFirst": { + "message": "알림을 통해 지갑에서 무슨 일이 일어나고 있는지 계속 확인하세요." + }, + "turnOnMetamaskNotificationsMessagePrivacyBold": { + "message": "설정 > 알림." + }, + "turnOnMetamaskNotificationsMessagePrivacyLink": { + "message": "이 기능을 사용하는 동안 개인정보가 어떻게 보호되는지 알아보세요." + }, + "turnOnMetamaskNotificationsMessageSecond": { + "message": "지갑 알림 기능을 사용하려면 프로필을 사용해 기기 간에 일부 설정을 동기화해야 합니다. $1" + }, + "turnOnMetamaskNotificationsMessageThird": { + "message": "$1에서 언제든지 알림을 끌 수 있습니다" + }, "turnOnTokenDetection": { "message": "향상된 토큰 감지 켜기" }, @@ -4614,6 +5820,10 @@ "unknownNetwork": { "message": "알 수 없는 비공개 네트워크" }, + "unknownNetworkForKeyEntropy": { + "message": "알 수 없는 네트워크", + "description": "Displayed on places like Snap install warning when regular name is not available." + }, "unknownQrCode": { "message": "오류: QR 코드를 식별할 수 없습니다." }, @@ -4626,6 +5836,9 @@ "unlockMessage": { "message": "분산된 웹이 다음을 대기 중" }, + "unpin": { + "message": "고정 해제" + }, "unrecognizedChain": { "message": "이 맞춤 네트워크는 인식되지 않았습니다.", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." @@ -4643,6 +5856,9 @@ "update": { "message": "업데이트" }, + "updateRequest": { + "message": "업데이트 요청" + }, "updatedWithDate": { "message": "$1에 업데이트됨" }, @@ -4667,12 +5883,25 @@ "useNftDetection": { "message": "NFT 자동 감지" }, + "useNftDetectionDescriptionText": { + "message": "MetaMask가 제삼자 서비스(예: OpenSea)를 이용하여 회원님의 NFT를 추가할 수 있도록 합니다. NFT를 자동 감지하면 이러한 서비스에 IP와 계정 주소가 노출됩니다. 이 기능을 켜면 IP 주소가 이더리움 주소와 연결되고 사기꾼이 에어드랍한 가짜 NFT가 표시될 수 있습니다. 이러한 위험을 피하기 위해 수동으로 토큰을 추가할 수 있습니다." + }, "usePhishingDetection": { "message": "피싱 감지 사용" }, "usePhishingDetectionDescription": { "message": "이더리움 사용자를 노리는 피싱 도메인에 대한 경고를 표시합니다" }, + "useSafeChainsListValidation": { + "message": "네트워크 세부 정보 확인" + }, + "useSafeChainsListValidationDescription": { + "message": "MetaMask는 $1(이)라는 제삼자 서비스를 사용하여 정확하고 표준화된 네트워크 세부 정보를 표시합니다. 이를 통해 악성 또는 잘못된 네트워크에 연결할 가능성이 줄어듭니다. 이 기능을 사용하면 사용자의 IP 주소가 chainid.network에 노출됩니다." + }, + "useSafeChainsListValidationWebsite": { + "message": "chainid.network", + "description": "useSafeChainsListValidationWebsite is separated from the rest of the text so that we can bold the third party service name in the middle of them" + }, "useSiteSuggestion": { "message": "사이트 제안 사용" }, @@ -4685,6 +5914,9 @@ "userName": { "message": "사용자 이름" }, + "userOpContractDeployError": { + "message": "스마트 계약 계정에서 계약 배포는 지원되지 않습니다." + }, "verifyContractDetails": { "message": "타사 세부 정보 확인" }, @@ -4702,6 +5934,9 @@ "view": { "message": "보기" }, + "viewActivity": { + "message": "활동 보기" + }, "viewAllDetails": { "message": "모든 세부 정보 보기" }, @@ -4725,7 +5960,7 @@ }, "viewOnCustomBlockExplorer": { "message": "$2에서 $1 보기", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "Etherscan에서 $1 보기", @@ -4737,6 +5972,9 @@ "viewOnOpensea": { "message": "Opensea에서 보기" }, + "viewTransaction": { + "message": "트랜잭션 보기" + }, "viewinCustodianApp": { "message": "수탁 앱에서 보기" }, @@ -4744,6 +5982,9 @@ "message": "Explorer에서 $1 보기", "description": "$1 is the action type. e.g (Account, Transaction, Swap)" }, + "visitSite": { + "message": "사이트 방문" + }, "visitWebSite": { "message": "웹사이트를 방문하세요" }, @@ -4782,6 +6023,10 @@ "warning": { "message": "경고" }, + "warningFromSnap": { + "message": "$1의 경고", + "description": "$1 represents the name of the snap" + }, "warningTooltipText": { "message": "$1 타사는 추가 통보나 동의 없이도 남은 토큰 전체를 사용할 수 있습니다. 보호를 위해 지출 한도를 하향하세요.", "description": "$1 is a warning icon with text 'Be careful' in 'warning' colour" @@ -4789,6 +6034,9 @@ "weak": { "message": "약함" }, + "web3": { + "message": "웹3" + }, "web3ShimUsageNotification": { "message": "현재의 웹사이트가 제거된 window.web3 API를 이용하려고 합니다. 이 사이트가 제대로 작동하지 않는 경우, $1을(를) 클릭해 자세히 알아보세요.", "description": "$1 is a clickable link." @@ -4829,10 +6077,6 @@ "whatsThis": { "message": "이것은 무엇인가요?" }, - "xOfY": { - "message": "$1/$2개", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$1/$2개 보류 중", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" @@ -4840,6 +6084,9 @@ "yes": { "message": "예" }, + "you": { + "message": "회원님" + }, "youHaveAddedAll": { "message": "모든 인기 네트워크를 추가했습니다. $1에서 더 많은 네트워크를 확인하거나 $2을(를) 할 수 있습니다.", "description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'" @@ -4862,6 +6109,12 @@ "yourPrivateSeedPhrase": { "message": "비밀복구구문" }, + "yourTransactionConfirmed": { + "message": "트랜잭션이 이미 확인되었습니다" + }, + "yourTransactionJustConfirmed": { + "message": "블록체인에서 거래가 확인되기 전에는 거래를 취소할 수 없습니다." + }, "zeroGasPriceOnSpeedUpError": { "message": "가속화 시 가스 가격 0" } diff --git a/app/_locales/lt/messages.json b/app/_locales/lt/messages.json index a4cb441b9ecf..893d0a345fd5 100644 --- a/app/_locales/lt/messages.json +++ b/app/_locales/lt/messages.json @@ -630,9 +630,6 @@ "send": { "message": "Siųsti" }, - "sendTokens": { - "message": "Siųsti žetonus" - }, "settings": { "message": "Nustatymai" }, diff --git a/app/_locales/lv/messages.json b/app/_locales/lv/messages.json index 129d7986b3f1..bf058e6bb2fe 100644 --- a/app/_locales/lv/messages.json +++ b/app/_locales/lv/messages.json @@ -626,9 +626,6 @@ "send": { "message": "Sūtīt" }, - "sendTokens": { - "message": "Nosūtīt marķierus" - }, "settings": { "message": "Iestatījumi" }, diff --git a/app/_locales/ms/messages.json b/app/_locales/ms/messages.json index a387ae49623c..61e4c37cae7a 100644 --- a/app/_locales/ms/messages.json +++ b/app/_locales/ms/messages.json @@ -610,9 +610,6 @@ "send": { "message": "Hantar" }, - "sendTokens": { - "message": "Hantar Token" - }, "settings": { "message": "Tetapan" }, diff --git a/app/_locales/nl/messages.json b/app/_locales/nl/messages.json index 3cc25f6cf73b..fc847537e00b 100644 --- a/app/_locales/nl/messages.json +++ b/app/_locales/nl/messages.json @@ -256,9 +256,6 @@ "send": { "message": "Sturen" }, - "sendTokens": { - "message": "Stuur tokens" - }, "settings": { "message": "instellingen" }, diff --git a/app/_locales/no/messages.json b/app/_locales/no/messages.json index cc202847e646..c2825ea5bfe7 100644 --- a/app/_locales/no/messages.json +++ b/app/_locales/no/messages.json @@ -611,9 +611,6 @@ "selectType": { "message": "Velg type " }, - "sendTokens": { - "message": "Send tokener" - }, "settings": { "message": "Innstillinger" }, diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json index 9f33919237fa..3d3b2428bac3 100644 --- a/app/_locales/ph/messages.json +++ b/app/_locales/ph/messages.json @@ -96,12 +96,6 @@ "alerts": { "message": "Mga Alerto" }, - "allowExternalExtensionTo": { - "message": "Payagan ang external extension na ito na:" - }, - "allowThisSiteTo": { - "message": "Payagan ang site na ito na:" - }, "allowWithdrawAndSpend": { "message": "Payagan ang $1 na mag-withdraw at gastusin ang sumusunod na halaga:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -249,26 +243,6 @@ "connectManually": { "message": "Manu-manong kumonekta sa kasalukuyang site" }, - "connectTo": { - "message": "Kumonekta sa $1", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "Ikonekta sa lahat ng iyong $1", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "mga account", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "Kumonekta sa $1", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "Mga $1 account", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "Kumonekta sa MetaMask" }, @@ -960,7 +934,8 @@ "message": "Magagawa ng nakakapinsalang network provider na magsinungaling tungkol sa status ng blockchain at itala ang aktibidad ng iyong network. Magdagdag lang ng mga custom na network na pinagkakatiwalaan mo." }, "onlyConnectTrust": { - "message": "Kumonekta lang sa mga site na pinagkakatiwalaan mo." + "message": "Kumonekta lang sa mga site na pinagkakatiwalaan mo.", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." }, "origin": { "message": "Pinagmulan" @@ -1211,9 +1186,6 @@ "message": "Magpadala ng $1", "description": "Symbol of the specified token" }, - "sendTokens": { - "message": "Magpadala ng Mga Token" - }, "settings": { "message": "Mga Setting" }, @@ -1774,10 +1746,6 @@ "whatsThis": { "message": "Ano ito?" }, - "xOfY": { - "message": "$1 ng $2", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$1 sa $2 ang nakabinbin", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" diff --git a/app/_locales/pl/messages.json b/app/_locales/pl/messages.json index 842c9b6f234e..a49b7bd23b16 100644 --- a/app/_locales/pl/messages.json +++ b/app/_locales/pl/messages.json @@ -624,9 +624,6 @@ "send": { "message": "Wyślij" }, - "sendTokens": { - "message": "Wyślij tokeny" - }, "settings": { "message": "Ustawienia" }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index eac5878b5df5..fe80de66b981 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -130,12 +130,21 @@ "account": { "message": "Conta" }, + "accountActivity": { + "message": "Atividade da conta" + }, + "accountActivityText": { + "message": "Selecione as contas das quais deseja receber notificações:" + }, "accountDetails": { "message": "Detalhes da conta" }, "accountIdenticon": { "message": "Identicon da conta" }, + "accountIsntConnectedToastText": { + "message": "$1 não está conectado a $2" + }, "accountName": { "message": "Nome da conta" }, @@ -153,6 +162,12 @@ "accountSelectionRequired": { "message": "Você precisa selecionar uma conta!" }, + "accounts": { + "message": "Contas" + }, + "accountsConnected": { + "message": "Contas conectadas" + }, "active": { "message": "Ativo" }, @@ -243,6 +258,9 @@ "addIPFSGateway": { "message": "Adicione seu gateway IPFS preferencial" }, + "addImportAccount": { + "message": "Adicionar conta ou carteira de hardware" + }, "addMemo": { "message": "Adicionar observação" }, @@ -256,6 +274,9 @@ "message": "Esta conexão de rede depende de terceiros. Esta conexão pode ser menos confiável ou permitir que terceiros rastreiem atividades. $1", "description": "$1 is Learn more link" }, + "addNewAccount": { + "message": "Adicionar uma nova conta" + }, "addNewToken": { "message": "Adicionar novo token" }, @@ -265,6 +286,12 @@ "addNfts": { "message": "Adicionar NFTs" }, + "addSnapAccountToggle": { + "message": "Ativar \"Adicionar Snap da conta (Beta)\"" + }, + "addSnapAccountsDescription": { + "message": "Ao ativar este recurso, você terá a opção de adicionar os novos Snaps de conta (Beta) direto da sua lista de contas. Se você instalar um Snap de conta, lembre-se de que ele é um serviço terceirizado." + }, "addSuggestedNFTs": { "message": "Adicionar NFTs sugeridos" }, @@ -281,6 +308,9 @@ "addingCustomNetwork": { "message": "Adicionar rede" }, + "addingTokens": { + "message": "Adicionando tokens" + }, "address": { "message": "Endereço" }, @@ -316,9 +346,27 @@ "airgapVault": { "message": "AirGap Vault" }, + "alert": { + "message": "Alerta" + }, + "alertBannerMultipleAlertsDescription": { + "message": "Se você aprovar esta solicitação, um terceiro conhecido por aplicar golpes poderá se apropriar de todos os seus ativos." + }, + "alertBannerMultipleAlertsTitle": { + "message": "Vários alertas!" + }, "alertDisableTooltip": { "message": "Isso pode ser alterado em \"Configurações > Alertas\"" }, + "alertModalAcknowledge": { + "message": "Eu reconheço o risco e ainda quero prosseguir" + }, + "alertModalDetails": { + "message": "Detalhes do alerta" + }, + "alertModalReviewAllAlerts": { + "message": "Conferir todos os alertas" + }, "alertSettingsUnconnectedAccount": { "message": "Navegando em um site com uma conta não conectada selecionada" }, @@ -334,6 +382,9 @@ "alerts": { "message": "Alertas" }, + "all": { + "message": "Tudo" + }, "allCustodianAccountsConnectedSubtitle": { "message": "Você já conectou todas as sua contas custodiantes ou não tem nenhuma conta para conectar ao MetaMask Institutional." }, @@ -344,23 +395,26 @@ "message": "Todos os seus $1", "description": "$1 is the symbol or name of the token that the user is approving spending" }, + "allPermissions": { + "message": "Todas as permissões" + }, "allYourNFTsOf": { "message": "Todos os seus NFTs de $1", "description": "$1 is a link to contract on the block explorer when we're not able to retrieve a erc721 or erc1155 name" }, - "allowExternalExtensionTo": { - "message": "Permitir que essa extensão externa:" + "allow": { + "message": "Permitir" + }, + "allowMmiToConnectToCustodian": { + "message": "Isso permite que o MMI se conecte ao $1 para importar suas contas." + }, + "allowNotifications": { + "message": "Permitir notificações" }, "allowSpendToken": { "message": "Você dá permissão para acessar seus $1?", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "Permitir que esse site:" - }, - "allowThisSnapTo": { - "message": "Permitir que esse snap:" - }, "allowWithdrawAndSpend": { "message": "Permitir que $1 saque e gaste até o seguinte valor:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -368,6 +422,23 @@ "amount": { "message": "Valor" }, + "amountReceived": { + "message": "Valor recebido" + }, + "amountSent": { + "message": "Valor enviado" + }, + "andForListItems": { + "message": "$1 e $2", + "description": "$1 is the first item, $2 is the last item in a list of items. Used in Snap Install Warning modal." + }, + "andForTwoItems": { + "message": "$1 e $2", + "description": "$1 is the first item, $2 is the second item. Used in Snap Install Warning modal." + }, + "announcements": { + "message": "Comunicados" + }, "appDescription": { "message": "Uma carteira de Ethereum no seu navegador", "description": "The description of the application" @@ -402,6 +473,10 @@ "approveButtonText": { "message": "Aprovar" }, + "approveIncreaseAllowance": { + "message": "Aumentar limite de gastos de $1", + "description": "The token symbol that is being approved" + }, "approveSpendingCap": { "message": "Aprovar limite de gastos de $1", "description": "The token symbol that is being approved" @@ -427,6 +502,10 @@ "message": "Aprovada em $1", "description": "$1 is the approval date for a permission" }, + "approvedOnForAccounts": { + "message": "Aprovada em $1 para $2", + "description": "$1 is the approval date for a permission. $2 is the AvatarGroup component displaying account images." + }, "areYouSure": { "message": "Tem certeza?" }, @@ -439,12 +518,21 @@ "attemptSendingAssets": { "message": "Se você tentar enviar ativos diretamente de uma rede para outra, isso poderá resultar na perda permanente deles. Certifique-se de usar uma ponte." }, + "attemptSendingAssetsWithPortfolio": { + "message": "Você poderá perder seus ativos se tentar enviá-los a partir de outra rede. Transfira os fundos com segurança entre redes usando uma ponte, como $1" + }, + "attemptToCancelSwapForFree": { + "message": "Tentar cancelar a troca sem custo" + }, "attemptingConnect": { "message": "Tentando conexão com a blockchain." }, "attributions": { "message": "Atribuições" }, + "auroraRpcDeprecationMessage": { + "message": "O URL de RPC (Chamadas de Procedimento Remoto) da Infura não oferece mais suporte à rede Aurora." + }, "authorizedPermissions": { "message": "Você concedeu as seguintes permissões" }, @@ -479,6 +567,9 @@ "backupApprovalNotice": { "message": "Faça backup da Frase de Recuperação Secreta para manter sua carteira e seus fundos em segurança." }, + "backupKeyringSnapReminder": { + "message": "Confirme se você consegue acessar por conta própria as contas criadas por esse Snap antes de removê-las" + }, "backupNow": { "message": "Fazer backup agora" }, @@ -486,7 +577,7 @@ "message": "Faça backup dos seus dados" }, "backupUserDataDescription": { - "message": "Você pode fazer backup das configurações de usuário contendo preferências e endereços de contas para um arquivo JSON." + "message": "Você pode fazer backup de dados como seus contatos e preferências." }, "balance": { "message": "Saldo" @@ -500,6 +591,30 @@ "basic": { "message": "Básico" }, + "basicConfigurationBannerCTA": { + "message": "Ativar funcionalidade básica" + }, + "basicConfigurationBannerTitle": { + "message": "A funcionalidade básica está desativada" + }, + "basicConfigurationLabel": { + "message": "Funcionalidade básica" + }, + "basicConfigurationModalCheckbox": { + "message": "Entendo e quero continuar" + }, + "basicConfigurationModalDisclaimerOff": { + "message": "Isso significa que você não otimizará totalmente seu tempo na MetaMask. Os recursos básicos (como detalhes de tokens, configurações ideias de gás e outros) não estarão disponíveis." + }, + "basicConfigurationModalDisclaimerOn": { + "message": "Para otimizar seu tempo na MetaMask, você precisará ativar este recurso. As funções básicas (como detalhes dos tokens, configurações ideais de gás e outras) são importantes para a experiência na web3." + }, + "basicConfigurationModalHeadingOff": { + "message": "Desativar funcionalidade básica" + }, + "basicConfigurationModalHeadingOn": { + "message": "Ativar funcionalidade básica" + }, "beCareful": { "message": "Tenha cuidado" }, @@ -571,6 +686,9 @@ "blockaidDescriptionTransferFarming": { "message": "Se você aprovar essa solicitação, algum terceiro conhecido por aplicar golpes poderá tomar todos os seus ativos." }, + "blockaidMessage": { + "message": "Proteção de privacidade: nenhum dado é compartilhado com terceiros. Disponível em Arbitrum, Avalanche, BNB Chain, Mainnet da Ethereum, Linea, Optimism, Polygon, Base e Sepolia." + }, "blockaidTitleDeceptive": { "message": "Esta solicitação é enganosa" }, @@ -586,6 +704,9 @@ "bridge": { "message": "Ponte" }, + "bridgeDontSend": { + "message": "Usar uma ponte, não enviar" + }, "browserNotSupported": { "message": "Seu navegador não é compatível..." }, @@ -598,6 +719,9 @@ "busy": { "message": "Ocupado" }, + "buyAndSell": { + "message": "Comprar e vender" + }, "buyAsset": { "message": "Comprar $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -609,6 +733,10 @@ "buyNow": { "message": "Comprar agora" }, + "buyToken": { + "message": "Comprar $1", + "description": "$1 is the token symbol" + }, "bytes": { "message": "Bytes" }, @@ -618,9 +746,6 @@ "cancel": { "message": "Cancelar" }, - "cancelEdit": { - "message": "Cancelar edição" - }, "cancelPopoverTitle": { "message": "Cancelar transação" }, @@ -647,6 +772,9 @@ "chainIdExistsErrorMsg": { "message": "Esse ID da cadeia é usado pela rede $1." }, + "chainListReturnedDifferentTickerSymbol": { + "message": "O símbolo deste token não corresponde ao nome ou ID da cadeia inseridos para a rede. Muitos tokens populares apresentam símbolos semelhantes, que podem ser usados por golpistas para induzir você ao erro de enviar um token mais valioso em troca. Verifique todos os detalhes antes de continuar." + }, "chooseYourNetwork": { "message": "Escolha sua rede" }, @@ -682,9 +810,19 @@ "close": { "message": "Fechar" }, + "closeExtension": { + "message": "Fechar extensão" + }, + "closeWindowAnytime": { + "message": "Você pode fechar esta janela a qualquer momento." + }, "coingecko": { "message": "CoinGecko" }, + "comboNoOptions": { + "message": "Nenhuma opção encontrada", + "description": "Default text shown in the combo field dropdown if no options." + }, "configureSnapPopupDescription": { "message": "Você está saindo da MetaMask para configurar esse snap." }, @@ -703,12 +841,42 @@ "confirm": { "message": "Confirmar" }, + "confirmAlertModalAcknowledge": { + "message": "Confirmo que recebi os alertas e ainda quero prosseguir" + }, + "confirmAlertModalDetails": { + "message": "Se você fizer login, um terceiro conhecido por aplicar golpes poderá se apropriar de todos os seus ativos. Confira os alertas antes de prosseguir." + }, + "confirmAlertModalTitle": { + "message": "Seus ativos podem estar em risco" + }, + "confirmConnectCustodianRedirect": { + "message": "Você será redirecionado para $1 ao clicar em continuar." + }, + "confirmConnectCustodianText": { + "message": "Para conectar suas contas, faça login em sua conta $1 e clique no botão \"conectar ao MMI\"." + }, + "confirmConnectionTitle": { + "message": "Confirmar conexão ao $1" + }, "confirmPassword": { "message": "Confirmar a senha" }, "confirmRecoveryPhrase": { "message": "Confirmar Frase de Recuperação Secreta" }, + "confirmTitleDescContractInteractionTransaction": { + "message": "Só confirme essa transação se você entende integralmente o conteúdo e confia no site solicitante." + }, + "confirmTitleDescSignature": { + "message": "Confirme esta mensagem somente se você aprova o conteúdo e confia no site solicitante." + }, + "confirmTitleSignature": { + "message": "Solicitação de assinatura" + }, + "confirmTitleTransaction": { + "message": "Solicitação de transação" + }, "confirmed": { "message": "Confirmada" }, @@ -724,9 +892,15 @@ "connect": { "message": "Conectar" }, + "connectAccount": { + "message": "Conectar conta" + }, "connectAccountOrCreate": { "message": "Conectar conta ou criar nova" }, + "connectAccounts": { + "message": "Conectar contas" + }, "connectCustodialAccountMenu": { "message": "Conectar conta custodiada" }, @@ -736,36 +910,25 @@ "connectCustodialAccountTitle": { "message": "Contas custodiadas" }, + "connectCustodianAccounts": { + "message": "Conectar contas $1" + }, "connectManually": { "message": "Conectar manualmente ao site atual" }, + "connectMoreAccounts": { + "message": "Conectar mais contas" + }, "connectSnap": { "message": "Conectar $1", "description": "$1 is the snap for which a connection is being requested." }, - "connectTo": { - "message": "Conectar a $1", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "Conecte-se a todas as suas $1", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "contas", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "Conecte-se a $1", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1 contas", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "Conectar-se com a MetaMask" }, + "connectedAccounts": { + "message": "Contas conectadas" + }, "connectedAccountsDescriptionPlural": { "message": "Você tem $1 contas conectadas a este site.", "description": "$1 is the number of accounts" @@ -776,6 +939,13 @@ "connectedAccountsEmptyDescription": { "message": "A MetaMask não está conectada a esse site. Para conectar-se a um site da web3, encontre e clique no botão \"conectar\"." }, + "connectedAccountsListTooltip": { + "message": "$1 pode ver o saldo, endereço e atividade da conta, além das transações sugeridas para aprovar para contas conectadas.", + "description": "$1 is the origin name" + }, + "connectedAccountsToast": { + "message": "As contas conectadas foram atualizadas" + }, "connectedSites": { "message": "Sites conectados" }, @@ -787,12 +957,21 @@ "message": "$1 não está conectada a nenhum site.", "description": "$1 is the account name" }, + "connectedSnapAndNoAccountDescription": { + "message": "A MetaMask está conectada a este site, mas nenhuma conta está conectada ainda" + }, + "connectedWith": { + "message": "Conectado com" + }, "connecting": { "message": "Conectando..." }, "connectingTo": { "message": "Conectando a $1" }, + "connectingToDeprecatedNetwork": { + "message": "'$1' está sendo descontinuada e poderá não funcionar. Tente outra rede." + }, "connectingToGoerli": { "message": "Conectando à rede de teste Goerli" }, @@ -802,6 +981,9 @@ "connectingToLineaMainnet": { "message": "Conectando-se à Mainnet do Linea" }, + "connectingToLineaSepolia": { + "message": "Conectando à rede de teste Linea Sepolia" + }, "connectingToMainnet": { "message": "Conectando à Mainnet da Ethereum" }, @@ -831,6 +1013,12 @@ "continue": { "message": "Continuar" }, + "continueMmiOnboarding": { + "message": "Continuar integração com o MetaMask Institutional" + }, + "continueToWallet": { + "message": "Prosseguir para a carteira" + }, "contract": { "message": "Contrato" }, @@ -882,6 +1070,9 @@ "copyAddress": { "message": "Copiar endereço para a área de transferência" }, + "copyPrivateKey": { + "message": "Copiar chave privada" + }, "copyRawTransactionData": { "message": "Copiar dados brutos da transação" }, @@ -900,6 +1091,15 @@ "createPassword": { "message": "Criar senha" }, + "createSnapAccountDescription": { + "message": "$1 quer adicionar uma nova conta à MetaMask." + }, + "createSnapAccountTitle": { + "message": "Criar conta" + }, + "crossChainSwapsLink": { + "message": "Faça trocas entre redes com o MetaMask Portfolio" + }, "cryptoCompare": { "message": "CryptoCompare" }, @@ -950,10 +1150,16 @@ "message": "Custodiante" }, "custodianAccountAddedDesc": { - "message": "Agora você pode usar suas contas de custódia no MetaMask Institutional." + "message": "Agora você pode usar suas contas no MetaMask Institutional." }, "custodianAccountAddedTitle": { - "message": "As contas de custódia selecionadas foram adicionadas." + "message": "As $1 contas selecionadas foram adicionadas." + }, + "custodianQRCodeScan": { + "message": "Leia o QR code com seu app da $1 para dispositivos móveis" + }, + "custodianQRCodeScanDescription": { + "message": "Ou faça login em sua conta $1 e clique no botão \"Conectar ao MMI\"" }, "custodianReplaceRefreshTokenChangedFailed": { "message": "Acesse $1 e clique no botão \"Conectar ao MMI\" dentro da respectiva interface de usuário para reconectar suas contas ao MMI." @@ -1017,7 +1223,7 @@ "message": "A detecção de tokens ainda não está disponível nesta rede. Por favor, importe o token manualmente e certifique-se de que ele é confiável. Saiba mais sobre $1" }, "customTokenWarningInTokenDetectionNetwork": { - "message": "Antes de importar um token manualmente, certifique-se de que ele é confiável. Saiba mais sobre $1." + "message": "Qualquer pessoa pode criar um token, inclusive versões falsas de tokens existentes. Saiba mais sobre $1" }, "customTokenWarningInTokenDetectionNetworkWithTDOFF": { "message": "Certifique-se de que confia no token antes de importá-lo. Saiba como evitar $1. Você também pode ativar a detecção de tokens $2." @@ -1025,6 +1231,12 @@ "customerSupport": { "message": "suporte ao cliente" }, + "customizeYourNotifications": { + "message": "Personalize suas notificações" + }, + "customizeYourNotificationsText": { + "message": "Ative os tipos de notificação que deseja receber:" + }, "dappRequestedSpendingCap": { "message": "Limite de gastos solicitado pelo site" }, @@ -1108,6 +1320,18 @@ "deposit": { "message": "Depositar" }, + "deprecatedGoerliNtwrkMsg": { + "message": "Devido a atualizações no sistema Ethereum, a rede de teste Goerli será descontinuada em breve." + }, + "deprecatedNetwork": { + "message": "Essa rede foi descontinuada" + }, + "deprecatedNetworkButtonMsg": { + "message": "Entendi" + }, + "deprecatedNetworkDescription": { + "message": "A rede à qual você está tentando conectar-se não é mais suportada pela MetaMask. $1" + }, "description": { "message": "Descrição" }, @@ -1115,110 +1339,20 @@ "message": "Descrição de $1", "description": "$1 represents the name of the snap" }, - "desktopApp": { - "message": "Aplicativo para desktop" - }, - "desktopConnectionCriticalErrorDescription": { - "message": "Esse erro pode ser intermitente. Por isso, tente reiniciar a extensão ou desative a MetaMask para desktop." - }, - "desktopConnectionCriticalErrorTitle": { - "message": "A MetaMask teve problemas para iniciar" - }, - "desktopConnectionLostErrorDescription": { - "message": "Por favor, certifique-se de que o app para desktop está funcionando ou desative a MetaMask para desktop." - }, - "desktopConnectionLostErrorTitle": { - "message": "Conexão perdida com a MetaMask para desktop" - }, - "desktopDisableButton": { - "message": "Desativar app para desktop" - }, - "desktopDisableErrorCTA": { - "message": "Desativar a MetaMask para desktop" - }, - "desktopEnableButton": { - "message": "Ativar o app para desktop" - }, - "desktopEnableButtonDescription": { - "message": "Clique para executar todos os processos em segundo plano no app para desktop." - }, - "desktopErrorNavigateSettingsCTA": { - "message": "Voltar à página de configurações" - }, - "desktopErrorRestartMMCTA": { - "message": "Reiniciar a MetaMask" - }, - "desktopNotFoundErrorCTA": { - "message": "Baixar MetaMask para desktop" - }, - "desktopNotFoundErrorDescription1": { - "message": "Por favor, certifique-se de que o app para desktop está funcionando." - }, - "desktopNotFoundErrorDescription2": { - "message": "Se não tiver o app para desktop instalado, por favor, baixe-o no site da MetaMask." - }, - "desktopNotFoundErrorTitle": { - "message": "A MetaMask para desktop não foi encontrada" - }, - "desktopOpenOrDownloadCTA": { - "message": "Abrir a MetaMask para desktop" - }, - "desktopOutdatedErrorCTA": { - "message": "Atualizar a MetaMask para desktop" - }, - "desktopOutdatedErrorDescription": { - "message": "Seu app da MetaMask para desktop precisa ser atualizado." - }, - "desktopOutdatedErrorTitle": { - "message": "A MetaMask para desktop está desatualizada" - }, - "desktopOutdatedExtensionErrorCTA": { - "message": "Atualizar extensão da MetaMask" - }, - "desktopOutdatedExtensionErrorDescription": { - "message": "Sua extensão da MetaMask precisa ser atualizada." - }, - "desktopOutdatedExtensionErrorTitle": { - "message": "A extensão da MetaMask está desatualizada" - }, - "desktopPageDescription": { - "message": "Se o emparelhamento for bem-sucedido, a extensão será reiniciada e você precisará reinserir sua senha." - }, - "desktopPageSubTitle": { - "message": "Abra sua MetaMask para desktop e digite este código" - }, - "desktopPageTitle": { - "message": "Emparelhar com desktop" - }, - "desktopPairedWarningDeepLink": { - "message": "Ir às configurações na MetaMask para desktop" - }, - "desktopPairedWarningDescription": { - "message": "Se quiser iniciar um novo emparelhamento, remova a conexão atual." - }, - "desktopPairedWarningTitle": { - "message": "A MM para desktop já está emparelhada" - }, - "desktopPairingExpireMessage": { - "message": "O código expira em $1 segundos" - }, - "desktopRouteNotFoundErrorDescription": { - "message": "desktopRouteNotFoundErrorDescription" - }, - "desktopRouteNotFoundErrorTitle": { - "message": "desktopRouteNotFoundErrorTitle" + "details": { + "message": "Detalhes" }, - "desktopUnexpectedErrorCTA": { - "message": "Voltar à tela inicial da MetaMask" + "developerOptions": { + "message": "Opções para desenvolvedores" }, - "desktopUnexpectedErrorDescription": { - "message": "Verifique sua MetaMask para desktop para restaurar a conexão" + "developerOptionsResetStatesAnnouncementsDescription": { + "message": "Redefine o valor booleano de isShown para falso em todos os comunicados. Comunicados são as notificações exibidas na tela pop-up de \"Novidades\"." }, - "desktopUnexpectedErrorTitle": { - "message": "Algo deu errado..." + "developerOptionsResetStatesOnboarding": { + "message": "Redefine vários estados relacionados a integração e redireciona para a página \"Proteja sua carteira\" da integração." }, - "details": { - "message": "Detalhes" + "developerOptionsServiceWorkerKeepAlive": { + "message": "Resulta no salvamento contínuo de um carimbo de data/hora em session.storage" }, "disabledGasOptionToolTipMessage": { "message": "“$1” está desativado porque não satisfaz o aumento mínimo de 10% em relação à taxa de gás original.", @@ -1233,12 +1367,38 @@ "disconnectAllAccountsConfirmationDescription": { "message": "Quer mesmo desconectar? Você pode perder a funcionalidade do site." }, + "disconnectAllAccountsText": { + "message": "contas" + }, + "disconnectAllSnapsText": { + "message": "Snaps" + }, + "disconnectAllText": { + "message": "Se desconectar $1 de $2, você precisará reconectar para usar novamente.", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`, $2 represents the website hostname" + }, + "disconnectAllTitle": { + "message": "Desconectar $1", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`" + }, "disconnectPrompt": { "message": "Desconectar $1" }, "disconnectThisAccount": { "message": "Desconectar esta conta" }, + "disconnectedAllAccountsToast": { + "message": "Todas as contas foram desconectadas de $1", + "description": "$1 is name of the dapp`" + }, + "disconnectedSingleAccountToast": { + "message": "$1 desconectada de $2", + "description": "$1 is name of the name and $2 represents the dapp name`" + }, + "discoverSnaps": { + "message": "Descobrir Snaps", + "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." + }, "dismiss": { "message": "Descartar" }, @@ -1248,9 +1408,21 @@ "dismissReminderField": { "message": "Descartar o lembrete de backup da Frase de Recuperação Secreta" }, + "displayNftMedia": { + "message": "Exibir arquivos de mídia de NFTs" + }, + "displayNftMediaDescription": { + "message": "Exibir arquivos de mídia e dados de NFTs expõe seu endereço IP à OpenSea ou outros terceiros. Isso pode possibilitar que invasores associem seu endereço IP ao seu endereço Ethereum. A detecção automática de NFTs depende dessa configuração e ficará indisponível quando ela estiver desativada." + }, + "doNotShare": { + "message": "Não compartilhe isso com ninguém" + }, "domain": { "message": "Domínio" }, + "domainNotSupportedOnNetwork": { + "message": "A rede não suporta a consulta de domínio" + }, "done": { "message": "Concluído" }, @@ -1269,6 +1441,9 @@ "downloadStateLogs": { "message": "Baixar logs de estado" }, + "dragAndDropBanner": { + "message": "Você pode arrastar as redes para reordená-las. " + }, "dropped": { "message": "Abandonada" }, @@ -1367,6 +1542,9 @@ "editSpeedUpEditGasFeeModalTitle": { "message": "Editar taxa de gás para aceleração" }, + "enable": { + "message": "Ativar" + }, "enableAutoDetect": { "message": " Ativar detecção automática" }, @@ -1397,6 +1575,18 @@ "enhancedTokenDetectionAlertMessage": { "message": "A detecção aprimorada de tokens está disponível no momento em $1. $2" }, + "ensDomainsSettingDescriptionIntroduction": { + "message": "A MetaMask permite que você veja domínios ENS direto na barra de endereços do seu navegador. Veja como funciona:" + }, + "ensDomainsSettingDescriptionOutroduction": { + "message": "Tenha em mente que usar esse recurso expõe seu endereço IP a serviços de IPFS de terceiros." + }, + "ensDomainsSettingDescriptionPart1": { + "message": "A MetaMask verifica o contrato ENS da Ethereum para encontrar o código conectado ao nome ENS." + }, + "ensDomainsSettingDescriptionPart2": { + "message": "Se o código estiver vinculado ao IPFS, você poderá ver o conteúdo associado a ele (geralmente um site)." + }, "ensDomainsSettingTitle": { "message": "Exibir domínios ENS na barra de endereço" }, @@ -1438,6 +1628,9 @@ "message": "Detalhes do erro", "description": "Title for collapsible section that displays error details for debugging purposes" }, + "errorGettingSafeChainList": { + "message": "Erro ao obter uma lista segura da cadeia. Por favor, prossiga com cautela." + }, "errorMessage": { "message": "Mensagem: $1", "description": "Displayed error message for debugging purposes. $1 is the error message" @@ -1469,6 +1662,9 @@ "message": "Erro com $1", "description": "$1 represents the name of the snap" }, + "estimatedFee": { + "message": "Taxa estimada" + }, "ethGasPriceFetchWarning": { "message": "O preço de backup do gás é fornecido porque a estimativa de gás principal está indisponível no momento." }, @@ -1495,12 +1691,24 @@ "message": "Experimental" }, "extendWalletWithSnaps": { - "message": "Personalize sua experiência com a carteira.", + "message": "Explore Snaps desenvolvidos pela comunidade para personalizar sua experiência na web3", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "extensionInsallCompleteDescription": { + "message": "Volte à integração do produto MetaMask Institutional para conectar suas contas custodiadas ou autocustodiadas." + }, + "extensionInsallCompleteTitle": { + "message": "Instalação de extensão concluída" + }, "externalExtension": { "message": "Extensão externa" }, + "externalNameSourcesSetting": { + "message": "Apelidos propostos" + }, + "externalNameSourcesSettingDescription": { + "message": "Buscaremos os apelidos propostos para os endereços com os quais você interage em fontes terceirizadas como Etherscan, Infura e Lens Protocol. Essas fontes poderão ver esses endereços e seu endereço IP. O endereço da sua conta não será exposto a terceiros." + }, "failed": { "message": "Falha" }, @@ -1519,6 +1727,9 @@ "feeAssociatedRequest": { "message": "Há uma taxa associada a essa solicitação." }, + "feeDetails": { + "message": "Detalhes da taxa" + }, "fiat": { "message": "Fiduciária", "description": "Exchange type" @@ -1551,6 +1762,9 @@ "message": "Eu aceito os riscos", "description": "this text is shown on a button, which the user presses to confirm they understand the risks of using Flask" }, + "floatAmountToken": { + "message": "A quantidade de tokens deve ser um número inteiro" + }, "followUsOnTwitter": { "message": "Siga-nos no Twitter" }, @@ -1573,6 +1787,9 @@ "fromTokenLists": { "message": "Das listas de tokens: $1" }, + "function": { + "message": "Função: $1" + }, "functionApprove": { "message": "Função: aprovar" }, @@ -1582,6 +1799,13 @@ "functionType": { "message": "Tipo de função" }, + "fundYourWallet": { + "message": "Adicione valores à sua carteira" + }, + "fundYourWalletDescription": { + "message": "Comece adicionando $1 à sua carteira.", + "description": "$1 is the token symbol" + }, "gas": { "message": "Gás" }, @@ -1592,6 +1816,9 @@ "message": "Essa taxa de gás foi sugerida por $1. Sua substituição pode causar um problema com a sua transação. Entre em contato com $1 se tiver perguntas.", "description": "$1 represents the Dapp's origin" }, + "gasIsETH": { + "message": "O gás é $1 " + }, "gasLimit": { "message": "Limite de gás" }, @@ -1636,6 +1863,9 @@ "message": "$1 h", "description": "$1 represents a number of hours" }, + "gasTimingLow": { + "message": "Lento" + }, "gasTimingMinutesShort": { "message": "$1 min", "description": "$1 represents a number of minutes" @@ -1650,15 +1880,29 @@ "general": { "message": "Geral" }, - "globalTitle": { - "message": "Menu global" + "generalCameraError": { + "message": "Não pudemos acessar sua câmera. Por favor, tente de novo." }, - "globalTourDescription": { - "message": "Veja seu portfólio, sites conectados, configurações e mais" + "generalCameraErrorTitle": { + "message": "Algo deu errado..." + }, + "genericExplorerView": { + "message": "Ver conta na $1" + }, + "getStartedWithNFTs": { + "message": "Adquira $1 para comprar NFTs", + "description": "$1 is the token symbol" + }, + "getStartedWithNFTsDescription": { + "message": "Comece sua jornada com NFTs adicionando $1 à sua carteira.", + "description": "$1 is the token symbol" }, "goBack": { "message": "Voltar" }, + "goToSite": { + "message": "Ir ao site" + }, "goerli": { "message": "Rede de teste Goerli" }, @@ -1700,15 +1944,24 @@ "hexData": { "message": "Dados hexa" }, + "hiddenAccounts": { + "message": "Contas ocultas" + }, "hide": { "message": "Ocultar" }, + "hideAccount": { + "message": "Ocultar conta" + }, "hideFullTransactionDetails": { "message": "Ocultar detalhes completos da transação" }, "hideSeedPhrase": { "message": "Ocultar frase-semente" }, + "hideSentitiveInfo": { + "message": "Ocultar informações confidenciais" + }, "hideToken": { "message": "Ocultar token" }, @@ -1790,6 +2043,9 @@ "ignoreTokenWarning": { "message": "Se você ocultar tokens, eles não serão exibidos em sua carteira. No entanto, você ainda pode pesquisá-los para adicioná-los." }, + "imToken": { + "message": "imToken" + }, "import": { "message": "Importar", "description": "Button to import an account from a selected file" @@ -1848,6 +2104,9 @@ "importTokensCamelCase": { "message": "Importar tokens" }, + "importTokensError": { + "message": "Não foi possível importar os tokens. Volte a tentar mais tarde." + }, "importWithCount": { "message": "Importar $1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -1866,6 +2125,9 @@ "initialTransactionConfirmed": { "message": "Sua transação inicial foi confirmada pela rede. Clique em OK para voltar." }, + "inlineAlert": { + "message": "Alerta" + }, "inputLogicEmptyState": { "message": "Somente insira um número com o qual esteja confortável de o terceiro gastar agora ou no futuro. Você pode aumentar o limite de gastos a qualquer momento." }, @@ -1876,6 +2138,27 @@ "inputLogicHigherNumber": { "message": "Isso permite que o terceiro gaste todo o seu saldo de tokens até atingir o limite ou até você revogar o limite de gastos. Se a intenção não é essa, considere definir um limite de gastos menor." }, + "insightWarning": { + "message": "aviso" + }, + "insightWarningCheckboxMessage": { + "message": "$1 a solicitação de $2", + "description": "$1 is the action i.e. sign, confirm. $2 is the origin making the request." + }, + "insightWarningContentPlural": { + "message": "Revise os $1 antes de $2. Sua $3 é irreversível depois de realizada.", + "description": "$1 the 'insightWarnings' message (2 warnings) representing warnings, $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningContentSingular": { + "message": "Revise o $1 antes de $2. Sua $3 é irreversível depois de realizada.", + "description": "$1 is the 'insightWarning' message (1 warning), $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningHeader": { + "message": "Essa solicitação pode ser arriscada" + }, + "insightWarnings": { + "message": "avisos" + }, "insightsFromSnap": { "message": "Insights de $1", "description": "$1 represents the name of the snap" @@ -1883,9 +2166,18 @@ "install": { "message": "Instalar" }, + "installExtension": { + "message": "Instalar extensão" + }, + "installExtensionDescription": { + "message": "A versão em conformidade institucional da principal carteira web3 do mundo, a MetaMask." + }, "installOrigin": { "message": "Origem da instalação" }, + "installRequest": { + "message": "Adicionar à MetaMask" + }, "installedOn": { "message": "Instalado em $1", "description": "$1 is the date when the snap has been installed" @@ -1914,6 +2206,12 @@ "insufficientTokens": { "message": "Tokens insuficientes." }, + "interactingWith": { + "message": "Interagindo com" + }, + "interactingWithTransactionDescription": { + "message": "Este é o contrato com o qual você está interagindo. Proteja-se contra golpistas verificando os detalhes." + }, "invalidAddress": { "message": "Endereço inválido" }, @@ -1986,6 +2284,9 @@ "ipfsToggleModalSettings": { "message": "Configurações > Segurança e Privacidade" }, + "isSigningOrSubmitting": { + "message": "Uma transação anterior ainda está sendo assinada ou enviada" + }, "jazzAndBlockies": { "message": "Jazzicons e Blockies são dois estilos diferentes de ícones únicos que ajudam você a identificar uma conta num relance." }, @@ -1999,6 +2300,24 @@ "message": "Arquivo JSON", "description": "format for importing an account" }, + "keyringAccountName": { + "message": "Nome da conta" + }, + "keyringAccountPublicAddress": { + "message": "Endereço público" + }, + "keyringSnapRemovalResult1": { + "message": "$1 $2removido", + "description": "Displays the result after removal of a keyring snap. $1 is the snap name, $2 is whether it is successful or not" + }, + "keyringSnapRemovalResultNotSuccessful": { + "message": "não ", + "description": "Displays the `not` word in $2." + }, + "keyringSnapRemoveConfirmation": { + "message": "Digite $1 para confirmar que deseja remover esse Snap:", + "description": "Asks user to input the name nap prior to deleting the snap. $1 is the snap name" + }, "keystone": { "message": "Keystone" }, @@ -2017,9 +2336,15 @@ "lastSold": { "message": "Última venda" }, + "lavaDomeCopyWarning": { + "message": "Para sua segurança, não é possível selecionar este texto no momento." + }, "layer1Fees": { "message": "Taxas de camada 1" }, + "layer2Fees": { + "message": "Taxas da Camada 2" + }, "learnCancelSpeeedup": { "message": "Saiba como $1", "description": "$1 is link to cancel or speed up transactions" @@ -2037,9 +2362,21 @@ "learnMoreUpperCase": { "message": "Saiba mais" }, + "learnMoreUpperCaseWithDot": { + "message": "Saiba mais." + }, "learnScamRisk": { "message": "golpes e riscos de segurança." }, + "learnToBridge": { + "message": "Aprenda a usar uma ponte" + }, + "leaveMetaMask": { + "message": "Sair da MetaMask?" + }, + "leaveMetaMaskDesc": { + "message": "Você está prestes a visitar um site fora da MetaMask. Confirme o URL antes de continuar." + }, "ledgerAccountRestriction": { "message": "Você precisa usar sua última conta antes de adicionar uma nova." }, @@ -2058,6 +2395,18 @@ "ledgerDeviceOpenFailureMessage": { "message": "Ocorreu uma falha ao abrir o dispositivo Ledger. Seu Ledger pode não estar conectado a outros softwares. Feche o Ledger Live ou outros aplicativos conectados ao seu dispositivo Ledger e tente reconectar." }, + "ledgerErrorConnectionIssue": { + "message": "Reconecte sua Ledger, abra o app ETH e tente novamente." + }, + "ledgerErrorDevicedLocked": { + "message": "Sua Ledger está bloqueada. Desbloqueie-a e tente novamente." + }, + "ledgerErrorEthAppNotOpen": { + "message": "Para resolver o problema, abra o aplicativo ETH em seu dispositivo e tente novamente." + }, + "ledgerErrorTransactionDataNotPadded": { + "message": "Os dados de entrada da transação Ethereum não têm padding suficiente." + }, "ledgerLiveApp": { "message": "Ledger Live App" }, @@ -2077,6 +2426,9 @@ "lightTheme": { "message": "Claro" }, + "likeToImportToken": { + "message": "Gostaria de importar esse token?" + }, "likeToImportTokens": { "message": "Gostaria de importar esses tokens?" }, @@ -2086,6 +2438,9 @@ "lineaMainnet": { "message": "Mainnet do Linea" }, + "lineaSepolia": { + "message": "Rede de teste Linea Sepolia" + }, "link": { "message": "Link" }, @@ -2098,8 +2453,11 @@ "loading": { "message": "Carregando..." }, - "loadingNFTs": { - "message": "Carregando NFTs..." + "loadingScreenHardwareWalletMessage": { + "message": "Por favor, conclua a transação na carteira de hardware." + }, + "loadingScreenSnapMessage": { + "message": "Por favor, conclua a transação no Snap." }, "loadingTokens": { "message": "Carregando tokens..." @@ -2146,6 +2504,9 @@ "message": "Certifique-se de que ninguém está olhando", "description": "Warning to users to be care while creating and saving their new Secret Recovery Phrase" }, + "manageInSettings": { + "message": "Gerenciar em configurações" + }, "max": { "message": "Máximo" }, @@ -2180,15 +2541,34 @@ "metaMaskConnectStatusParagraphTwo": { "message": "O botão de status da conexão mostra se o website que você está visitando está conectado à conta selecionada no momento." }, + "metadataModalSourceTooltip": { + "message": "$1 está hospedado no npm e $2 é o identificador específico deste Snap.", + "description": "$1 is the snap name and $2 is the snap NPM id." + }, "metamaskInstitutionalVersion": { "message": "Versão MetaMask Institutional" }, + "metamaskNotificationsAreOff": { + "message": "As notificações de carteiras estão inativas no momento." + }, + "metamaskPortfolio": { + "message": "MetaMask Portfolio." + }, "metamaskSwapsOfflineDescription": { "message": "O recurso de Trocas da MetaMask está em manutenção. Verifique novamente mais tarde." }, "metamaskVersion": { "message": "Versão da MetaMask" }, + "methodData": { + "message": "Método" + }, + "methodDataTransactionDescription": { + "message": "Esta é a ação específica que será realizada. Estes dados podem ser falsos, portanto certifique-se de que confia no site do outro lado." + }, + "methodNotSupported": { + "message": "Não suportado com esta conta." + }, "metrics": { "message": "Métricas" }, @@ -2224,11 +2604,17 @@ "mmiBuiltAroundTheWorld": { "message": "O MetaMask Institutional é projetado e desenvolvido ao redor do mundo." }, + "mmiNewNFTDetectedInNFTsTabMessage": { + "message": "Permita que o MetaMask Institutional detecte e exiba NFTs automaticamente na sua carteira." + }, + "mmiPasswordSetupDetails": { + "message": "Essa senha desbloqueará somente sua extensão MetaMask Institutional." + }, "more": { "message": "mais" }, "multipleSnapConnectionWarning": { - "message": "$1 deseja conectar-se a $2 snaps. Prossiga apenas se você confia no site.", + "message": "$1 quer usar Snaps de $2", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." }, "mustSelectOne": { @@ -2237,10 +2623,80 @@ "name": { "message": "Nome" }, + "nameAddressLabel": { + "message": "Endereço", + "description": "Label above address field in name component modal." + }, + "nameInstructionsNew": { + "message": "Se você conhece esse endereço, dê um apelido a ele para reconhecê-lo posteriormente.", + "description": "Instruction text in name component modal when value is not recognised." + }, + "nameInstructionsRecognized": { + "message": "Esse endereço tem um apelido padrão, mas você pode editá-lo ou explorar outras sugestões.", + "description": "Instruction text in name component modal when value is recognized but not saved." + }, + "nameInstructionsSaved": { + "message": "Você já adicionou um apelido para esse endereço. Você pode editá-lo ou ver outros apelidos sugeridos.", + "description": "Instruction text in name component modal when value is saved." + }, + "nameLabel": { + "message": "Apelido", + "description": "Label above name input field in name component modal." + }, + "nameModalMaybeProposedName": { + "message": "Talvez: $1", + "description": "$1 is the proposed name" + }, + "nameModalTitleNew": { + "message": "Endereço desconhecido", + "description": "Title of the modal created by the name component when value is not recognised." + }, + "nameModalTitleRecognized": { + "message": "Endereço reconhecido", + "description": "Title of the modal created by the name component when value is recognized but not saved." + }, + "nameModalTitleSaved": { + "message": "Endereço salvo", + "description": "Title of the modal created by the name component when value is saved." + }, + "nameProviderProposedBy": { + "message": "Proposto por $1", + "description": "$1 is the name of the provider" + }, + "nameProvider_ens": { + "message": "Serviço de nomes Ethereum (ENS)" + }, + "nameProvider_etherscan": { + "message": "Etherscan" + }, + "nameProvider_lens": { + "message": "Lens Protocol" + }, + "nameProvider_token": { + "message": "MetaMask" + }, + "nameSetPlaceholder": { + "message": "Escolha um apelido...", + "description": "Placeholder text for name input field in name component modal." + }, + "nativePermissionRequestDescription": { + "message": "Deseja que este site faça o seguinte?", + "description": "Description below header used on Permission Connect screen for native permissions." + }, "nativeToken": { "message": "O token nativo dessa rede é $1. Esse é o token usado para taxas de gás.", "description": "$1 represents the name of the native token on the current network" }, + "nativeTokenScamWarningConversion": { + "message": "Editar detalhes da rede" + }, + "nativeTokenScamWarningDescription": { + "message": "Esta rede não corresponde ao seu ID da cadeia ou nome associado. Como muitos tokens populares usam o nome $1, ele é visado para golpes. Golpistas podem enganar você para que envie a eles alguma moeda mais valiosa em troca. Confirme todas as informações antes de prosseguir.", + "description": "$1 represents the currency name" + }, + "nativeTokenScamWarningTitle": { + "message": "Isto é um possível golpe" + }, "needHelp": { "message": "Precisa de ajuda? Contate $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -2261,6 +2717,9 @@ "negativeETH": { "message": "Não é possível enviar valores negativos de ETH." }, + "negativeOrZeroAmountToken": { + "message": "Não é possível enviar valores negativos ou zerados de ativos." + }, "network": { "message": "Ethereum:" }, @@ -2291,6 +2750,9 @@ "networkNameBSC": { "message": "BSC" }, + "networkNameBase": { + "message": "Base" + }, "networkNameDefinition": { "message": "O nome associado a essa rede." }, @@ -2300,12 +2762,21 @@ "networkNameGoerli": { "message": "Goerli" }, + "networkNameLinea": { + "message": "Linea" + }, + "networkNameOpMainnet": { + "message": "Mainnet da OP" + }, "networkNamePolygon": { "message": "Polygon" }, "networkNameTestnet": { "message": "Testnet" }, + "networkNameZkSyncEra": { + "message": "zkSync Era" + }, "networkProvider": { "message": "Provedor de rede" }, @@ -2358,6 +2829,19 @@ "newContract": { "message": "Novo contrato" }, + "newNFTDetectedInImportNFTsMessageStrongText": { + "message": "Configurações > Segurança e privacidade" + }, + "newNFTDetectedInImportNFTsMsg": { + "message": "Para usar o OpenSea para ver seus NFTs, ative \"Exibir arquivos de mídia de NFTs\" em $1.", + "description": "$1 is used for newNFTDetectedInImportNFTsMessageStrongText" + }, + "newNFTDetectedInNFTsTabMessage": { + "message": "Permita que a MetaMask detecte e exiba NFTs automaticamente na sua carteira." + }, + "newNFTsAutodetected": { + "message": "Detecção automática de NFTs" + }, "newNetworkAdded": { "message": "“$1” foi adicionado com sucesso!" }, @@ -2367,6 +2851,12 @@ "newPassword": { "message": "Nova senha (no mínimo 8 caracteres)" }, + "newPrivacyPolicyActionButton": { + "message": "Saiba mais" + }, + "newPrivacyPolicyTitle": { + "message": "Atualizamos nossa política de privacidade" + }, "newTokensImportedMessage": { "message": "Você importou $1 com sucesso.", "description": "$1 is the string of symbols of all the tokens imported" @@ -2388,6 +2878,9 @@ "message": "Esse token é um NFT. Adicione-o à $1", "description": "$1 is a clickable link with text defined by the 'importNFTPage' key" }, + "nftAlreadyAdded": { + "message": "O NFT já foi adicionado." + }, "nftDisclaimer": { "message": "Aviso: a MetaMask obtém o arquivo de mídia do URL de origem. Às vezes, esse URL é modificado pelo marketplace onde o NFT foi mintado." }, @@ -2423,12 +2916,21 @@ "noAddressForName": { "message": "Não foi configurado nenhum endereço para esse nome." }, + "noConnectedAccountDescription": { + "message": "Selecione uma conta que você deseja usar neste site para continuar." + }, + "noConnectedAccountTitle": { + "message": "A MetaMask não está conectada a este site" + }, "noConversionDateAvailable": { "message": "Não há uma data de conversão de moeda disponível" }, "noConversionRateAvailable": { "message": "Não há uma taxa de conversão disponível" }, + "noDomainResolution": { + "message": "Nenhuma resolução fornecida para o domínio." + }, "noNFTs": { "message": "Nenhum NFT até agora" }, @@ -2447,6 +2949,9 @@ "noWebcamFoundTitle": { "message": "Webcam não encontrada" }, + "nonCustodialAccounts": { + "message": "O MetaMask Institutional permite que você use contas não custodiadas. Se você planeja usá-las, faça backup da sua Frase de Recuperação Secreta." + }, "nonce": { "message": "Nonce" }, @@ -2477,6 +2982,111 @@ "notePlaceholder": { "message": "O aprovador verá essa observação ao aprovar a transação no custodiante." }, + "notificationDetail": { + "message": "Detalhes" + }, + "notificationDetailBaseFee": { + "message": "Taxa-base (GWEI)" + }, + "notificationDetailGasLimit": { + "message": "Limite de gás (unidades)" + }, + "notificationDetailGasUsed": { + "message": "Gás utilizado (unidades)" + }, + "notificationDetailMaxFee": { + "message": "Taxa máxima por gás" + }, + "notificationDetailNetwork": { + "message": "Rede" + }, + "notificationDetailNetworkFee": { + "message": "Taxa de rede" + }, + "notificationDetailPriorityFee": { + "message": "Taxa de prioridade (GWEI)" + }, + "notificationItemCheckBlockExplorer": { + "message": "Verifique no BlockExplorer" + }, + "notificationItemCollection": { + "message": "Coleção" + }, + "notificationItemConfirmed": { + "message": "Confirmado" + }, + "notificationItemError": { + "message": "Não é possível obter as taxas no momento" + }, + "notificationItemFrom": { + "message": "De" + }, + "notificationItemLidoStakeReadyToBeWithdrawn": { + "message": "Saque pronto" + }, + "notificationItemLidoStakeReadyToBeWithdrawnMessage": { + "message": "Você já pode sacar seus $1 sem staking" + }, + "notificationItemLidoWithdrawalRequestedMessage": { + "message": "Sua solicitação de remover $1 do staking foi enviada" + }, + "notificationItemNFTReceivedFrom": { + "message": "NFT recebido de" + }, + "notificationItemNFTSentTo": { + "message": "NFT enviado para" + }, + "notificationItemNetwork": { + "message": "Rede" + }, + "notificationItemRate": { + "message": "Cotação (taxa inclusa)" + }, + "notificationItemReceived": { + "message": "Recebido" + }, + "notificationItemReceivedFrom": { + "message": "Recebido de" + }, + "notificationItemSent": { + "message": "Enviado" + }, + "notificationItemSentTo": { + "message": "Enviado para" + }, + "notificationItemStakeCompleted": { + "message": "Staking concluído" + }, + "notificationItemStaked": { + "message": "Staking executado" + }, + "notificationItemStakingProvider": { + "message": "Provedor de staking" + }, + "notificationItemStatus": { + "message": "Status" + }, + "notificationItemSwapped": { + "message": "Swap executado" + }, + "notificationItemSwappedFor": { + "message": "por" + }, + "notificationItemTo": { + "message": "Para" + }, + "notificationItemTransactionId": { + "message": "ID da transação" + }, + "notificationItemUnStakeCompleted": { + "message": "Retirada de staking concluída" + }, + "notificationItemUnStaked": { + "message": "Retirada de staking executada" + }, + "notificationItemUnStakingRequested": { + "message": "Retirada de staking solicitada" + }, "notificationTransactionFailedMessage": { "message": "Falha na transação $1! $2", "description": "Content of the browser notification that appears when a transaction fails" @@ -2491,55 +3101,18 @@ }, "notificationTransactionSuccessMessage": { "message": "Transação $1 confirmada!", - "description": "Content of the browser notification that appears when a transaction is confirmed" - }, - "notificationTransactionSuccessTitle": { - "message": "Transação confirmada", - "description": "Title of the browser notification that appears when a transaction is confirmed" - }, - "notificationTransactionSuccessView": { - "message": "Ver em $1", - "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" - }, - "notifications": { - "message": "Notificações" - }, - "notifications20ActionText": { - "message": "Saiba mais", - "description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a ledger page to resolve the U2F connection issue." - }, - "notifications20Description": { - "message": "Se você está usando a versão mais recente do Firefox, talvez esteja com um problema relacionado ao Firefox ter abandonado o suporte ao U2F.", - "description": "Description of a notification in the 'See What's New' popup. Describes the U2F support being dropped by firefox and that it affects ledger users." - }, - "notifications20Title": { - "message": "Usuários do Ledger e Firefox com problemas de conexão", - "description": "Title for a notification in the 'See What's New' popup. Tells users that latest firefox users using U2F may experience connection issues." - }, - "notifications24ActionText": { - "message": "Entendi" - }, - "notifications24Description": { - "message": "As configurações de taxas de gás avançadas agora são lembradas com base na rede que você estiver usando. Isso significa que você pode definir taxas de gás avançadas específicas para cada rede e evitar pagar a mais por gás ou por transações travadas." - }, - "notifications24Title": { - "message": "Taxas de gás avançadas por rede" - }, - "notifications8ActionText": { - "message": "Ir para Configurações > Avançado", - "description": "Description on an action button that appears in the What's New popup. Tells the user that if they click it, they will go to our Advanced settings page." + "description": "Content of the browser notification that appears when a transaction is confirmed" }, - "notifications8DescriptionOne": { - "message": "A partir da MetaMask v10.4.0, não é mais necessário o Ledger Live para conectar o seu dispositivo Ledger à MetaMask.", - "description": "Description of a notification in the 'See What's New' popup. Describes changes for how Ledger Live is no longer needed to connect the device." + "notificationTransactionSuccessTitle": { + "message": "Transação confirmada", + "description": "Title of the browser notification that appears when a transaction is confirmed" }, - "notifications8DescriptionTwo": { - "message": "Para ter uma experiência mais fácil e estável com o Ledger, vá até a aba Configurações > Avançado e alterne o \"Tipo de conexão preferencial com o Ledger\" para \"WebHID\".", - "description": "Description of a notification in the 'See What's New' popup. Describes how the user can turn off the Ledger Live setting." + "notificationTransactionSuccessView": { + "message": "Ver em $1", + "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" }, - "notifications8Title": { - "message": "Melhoria na conexão com o Ledger", - "description": "Title for a notification in the 'See What's New' popup. Notifies ledger users that there is an improvement in how they can connect their device." + "notifications": { + "message": "Notificações" }, "notificationsDropLedgerFirefoxDescription": { "message": "O Firefox não oferece mais suporte ao U2F, então a Ledger não funcionará com a MetaMask no Firefox. Em vez disso, experimente a MetaMask no Google Chrome.", @@ -2549,33 +3122,37 @@ "message": "Suporte à Ledger descontinuado no Firefox", "description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped." }, - "notificationsEmptyText": { - "message": "Aqui você encontra notificações dos seus snaps instalados." - }, - "notificationsHeader": { - "message": "Notificações" + "notificationsFeatureToggle": { + "message": "Ativar notificações da carteira", + "description": "Experimental feature title" }, - "notificationsInfos": { - "message": "$1 de $2", - "description": "$1 is the date at which the notification has been dispatched and $2 is the link to the snap that dispatched the notification." + "notificationsFeatureToggleDescription": { + "message": "Isso habilita as notificações da carteira, como enviar/receber valores ou NFTs e avisos de recursos.", + "description": "Description of the experimental notifications feature" }, "notificationsMarkAllAsRead": { "message": "Marcar todas como lidas" }, - "notificationsOpenBetaSnapsActionText": { - "message": "Saiba mais" + "notificationsPageEmptyTitle": { + "message": "Não há nada aqui" + }, + "notificationsPageErrorContent": { + "message": "Tente acessar esta página novamente." }, - "notificationsOpenBetaSnapsDescriptionOne": { - "message": "🎉 Estamos empolgados de anunciar o Beta Aberto do MetaMask Snaps!" + "notificationsPageErrorTitle": { + "message": "Ocorreu um erro" }, - "notificationsOpenBetaSnapsDescriptionThree": { - "message": "Personalize sua carteira com snaps criados pela comunidade de desenvolvedores!" + "notificationsPageNoNotificationsContent": { + "message": "Você ainda não recebeu nenhuma notificação." }, - "notificationsOpenBetaSnapsDescriptionTwo": { - "message": "Os snaps ajudam a fazer mais com a MetaMask, como conectar-se a mais redes, ver insights de transações e receber notificações personalizadas." + "notificationsSettingsBoxError": { + "message": "Ocorreu um erro. Tente novamente." }, - "notificationsOpenBetaSnapsTitle": { - "message": "Apresentamos o MetaMask Snaps" + "notificationsSettingsPageAllowNotifications": { + "message": "Fique por dentro do que acontece na sua carteira com as notificações. Para isso, nós usamos um perfil para sincronizar algumas configurações entre seus dispositivos. $1" + }, + "notificationsSettingsPageAllowNotificationsLink": { + "message": "Saiba como protegemos sua privacidade enquanto usa este recurso." }, "numberOfNewTokensDetectedPlural": { "message": "$1 novos tokens encontrados nesta conta", @@ -2599,6 +3176,9 @@ "on": { "message": "Ativado" }, + "onboarding": { + "message": "Integração" + }, "onboardingAdvancedPrivacyIPFSDescription": { "message": "O gateway IPFS possibilita acessar e visualizar dados hospedados por terceiros. Você pode adicionar um gateway IPFS personalizado ou continuar usando o padrão." }, @@ -2629,51 +3209,45 @@ "onboardingMetametricsAgree": { "message": "Concordo" }, - "onboardingMetametricsAllowOptOut": { - "message": "Permite que você cancele a inscrição a qualquer momento nas Configurações" - }, - "onboardingMetametricsDataTerms": { - "message": "Esses dados são agregados e, portanto, anônimos para os fins do Regulamento Geral sobre a Proteção de Dados (UE) de 2016/679." - }, "onboardingMetametricsDescription": { - "message": "A MetaMask gostaria de reunir dados de uso para entender melhor como nossos usuários interagem com a MetaMask. Esses dados serão usados para prestar o serviço, o que inclui melhorá-lo com base em seu uso." + "message": "Gostaríamos de coletar dados básicos de uso para melhorar a MetaMask. Saiba que nunca vendemos os dados que você fornece aqui." }, "onboardingMetametricsDescription2": { - "message": "A MetaMask..." + "message": "Quando coletamos as métricas, elas sempre são..." }, "onboardingMetametricsDisagree": { "message": "Não, obrigado" }, "onboardingMetametricsInfuraTerms": { - "message": "* Quando você usa a Infura como seu provedor RPC padrão na MetaMask, a Infura coleta seu endereço IP e da carteira de Ethereum quando você envia uma transação. Não armazenamos essas informações de forma que permita aos nossos sistemas cruzarem os dois fragmentos de dados. Para obter mais informações sobre como a MetaMask e a Infura interagem da perspectiva da coleta de dados, veja nossa atualização $1. Para obter mais informações sobre nossas práticas de privacidade em geral, veja nossa $2.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" + "message": "Informaremos a você se decidirmos usar esses dados para outras finalidades. Você pode analisar nossa $1 para obter mais informações. Lembre-se: você pode acessar as configurações e revogar a permissão a qualquer momento.", + "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, "onboardingMetametricsInfuraTermsPolicy": { - "message": "Política de Privacidade aqui" - }, - "onboardingMetametricsInfuraTermsPolicyLink": { - "message": "aqui" + "message": "Política de Privacidade" }, "onboardingMetametricsModalTitle": { "message": "Adicionar rede personalizada" }, "onboardingMetametricsNeverCollect": { - "message": "$1 coletará informações de que não precisamos para prestar o serviço (tais como chaves, endereços, hashes de transações ou saldos)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 cliques e visualizações no app são armazenados, mas outros detalhes (como seu endereço público) não são.", + "description": "$1 represents `onboardingMetametricsNeverCollectEmphasis`" + }, + "onboardingMetametricsNeverCollectEmphasis": { + "message": "Privadas:" }, "onboardingMetametricsNeverCollectIP": { - "message": "$1 coletará seu endereço IP completo*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 usamos temporariamente o seu endereço IP para detectar uma localização geral (como seu país ou região), mas ele nunca é armazenado.", + "description": "$1 represents `onboardingMetametricsNeverCollectIPEmphasis`" }, - "onboardingMetametricsNeverEmphasis": { - "message": "Nunca" + "onboardingMetametricsNeverCollectIPEmphasis": { + "message": "Gerais:" }, "onboardingMetametricsNeverSellData": { - "message": "$1 venderá dados. Jamais!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 você decide se quer compartilhar ou excluir seus dados de uso nas configurações, a qualquer momento.", + "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" }, - "onboardingMetametricsSendAnonymize": { - "message": "Enviará eventos de cliques e visualizações de páginas anonimizados" + "onboardingMetametricsNeverSellDataEmphasis": { + "message": "Opcionais:" }, "onboardingMetametricsTitle": { "message": "Ajude-nos a melhorar a MetaMask" @@ -2714,15 +3288,26 @@ "onboardingPinExtensionTitle": { "message": "Sua instalação da MetaMask está concluída!" }, + "onboardingPinMmiExtensionLabel": { + "message": "Fixar MetaMask Institutional" + }, "onboardingUsePhishingDetectionDescription": { "message": "Os alertas de detecção de phishing dependem de comunicação com $1. O jsDeliver terá acesso ao seu endereço IP. Veja $2.", "description": "The $1 is the word 'jsDeliver', from key 'jsDeliver' and $2 is the words Privacy Policy from key 'privacyMsg', both separated here so that it can be wrapped as a link" }, + "onekey": { + "message": "OneKey" + }, "onlyAddTrustedNetworks": { "message": "Um provedor de rede mal-intencionado pode mentir sobre o estado da blockchain e registrar as atividades da sua rede. Adicione somente as redes personalizadas em que você confia." }, "onlyConnectTrust": { - "message": "Conecte-se somente com sites em que você confia." + "message": "Conecte-se somente com sites em que você confia. $1", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." + }, + "openCustodianApp": { + "message": "Abrir aplicativo $1", + "description": "The $1 is the name of the Custodian that will be open" }, "openFullScreenForLedgerWebHid": { "message": "Abra o app em tela cheia para conectar seu Ledger.", @@ -2734,6 +3319,15 @@ "openSeaNew": { "message": "OpenSea" }, + "openSeaToBlockaidBtnLabel": { + "message": "Explorar snaps" + }, + "openSeaToBlockaidDescription": { + "message": "Os alertas de segurança não estão mais disponíveis nesta rede. Instalar um snap pode melhorar sua segurança." + }, + "openSeaToBlockaidTitle": { + "message": "Atenção!" + }, "operationFailed": { "message": "Falha na operação" }, @@ -2777,6 +3371,9 @@ "password": { "message": "Senha" }, + "passwordMmiTermsWarning": { + "message": "Compreendo que o MetaMask Institutional não pode recuperar essa senha para mim. $1" + }, "passwordNotLongEnough": { "message": "A senha não é longa o suficiente" }, @@ -2803,6 +3400,10 @@ "message": "Cole aqui a sequência de caracteres da sua chave privada:", "description": "For importing an account from a private key" }, + "paymasterInUse": { + "message": "O gás desta transação será pago por um tesoureiro.", + "description": "Alert shown in transaction confirmation if paymaster in use." + }, "pending": { "message": "Pendente" }, @@ -2816,18 +3417,26 @@ "message": "Você tem (1) transação pendente.", "description": "$1 is count of pending transactions" }, - "permissionRequest": { - "message": "Solicitação de permissão" + "permissionDetails": { + "message": "Detalhes da permissão" }, - "permissionRequestCapitalized": { + "permissionRequest": { "message": "Solicitação de permissão" }, "permissionRequested": { "message": "Solicitada agora" }, + "permissionRequestedForAccounts": { + "message": "Solicitada agora para $1", + "description": "Permission cell status for requested permission including accounts, rendered as AvatarGroup which is $1." + }, "permissionRevoked": { "message": "Revogada nesta atualização" }, + "permissionRevokedForAccounts": { + "message": "Revogada nessa atualização para $1", + "description": "Permission cell status for revoked permission including accounts, rendered as AvatarGroup which is $1." + }, "permission_accessNamedSnap": { "message": "Conectar a $1.", "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." @@ -2836,6 +3445,10 @@ "message": "Acesse a internet.", "description": "The description of the `endowment:network-access` permission." }, + "permission_accessNetworkDescription": { + "message": "Permita que $1 acesse a internet. Isso pode ser usado para enviar e receber dados de servidores de terceiros.", + "description": "An extended description of the `endowment:network-access` permission. $1 is the snap name." + }, "permission_accessSnap": { "message": "Conecte-se ao snap $1.", "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." @@ -2848,10 +3461,18 @@ "message": "Agende e execute ações periódicas.", "description": "The description for the `snap_cronjob` permission" }, + "permission_cronjobDescription": { + "message": "Permita que $1 realize ações que são executadas periodicamente em horários, datas ou intervalos fixos. Isso pode ser usado para disparar interações ou notificações sensíveis ao tempo.", + "description": "An extended description for the `snap_cronjob` permission. $1 is the snap name." + }, "permission_dialog": { "message": "Exibir janelas de diálogo na MetaMask.", "description": "The description for the `snap_dialog` permission" }, + "permission_dialogDescription": { + "message": "Permita que $1 exiba pop-ups da MetaMask com texto personalizado, campo para entrada de informações e botões para aprovar ou recusar uma ação.\nPode ser usado, por exemplo, para criar alertas, confirmações e fluxos de adesão para um Snap.", + "description": "An extended description for the `snap_dialog` permission. $1 is the snap name." + }, "permission_ethereumAccounts": { "message": "Ver endereço, saldo da conta, atividade e iniciar transações", "description": "The description for the `eth_accounts` permission" @@ -2860,34 +3481,138 @@ "message": "Acesse o provedor do Ethereum.", "description": "The description for the `endowment:ethereum-provider` permission" }, + "permission_ethereumProviderDescription": { + "message": "Permita que $1 se comunique diretamente com a MetaMask, para que possa ler dados da blockchain e sugerir mensagens e transações.", + "description": "An extended description for the `endowment:ethereum-provider` permission. $1 is the snap name." + }, + "permission_getEntropy": { + "message": "Derivar chaves arbitrárias únicas para $1.", + "description": "The description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getEntropyDescription": { + "message": "Permita que $1 derive chaves arbitrárias únicas para $1 sem as expor. Essas chaves são separadas das suas contas na MetaMask e não estão relacionadas às suas chaves privadas ou à Frase de Recuperação Secreta. Os outros Snaps não podem acessar essas informações.", + "description": "An extended description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getLocale": { + "message": "Ver seu idioma de preferência.", + "description": "The description for the `snap_getLocale` permission" + }, + "permission_getLocaleDescription": { + "message": "Permita que $1 acesse seu idioma de preferência a partir de suas configurações da MetaMask. Isso pode ser usado para traduzir e exibir o conteúdo de $1 usando seu idioma.", + "description": "An extended description for the `snap_getLocale` permission. $1 is the snap name." + }, + "permission_homePage": { + "message": "Exibe uma tela personalizada", + "description": "The description for the `endowment:page-home` permission" + }, + "permission_homePageDescription": { + "message": "Permite que $1 exiba uma tela inicial personalizada na MetaMask. Isso pode ser usado para interfaces de usuário, configurações e painéis.", + "description": "An extended description for the `endowment:page-home` permission. $1 is the snap name." + }, + "permission_keyring": { + "message": "Permita solicitações para adicionar e controlar contas Ethereum", + "description": "The description for the `endowment:keyring` permission" + }, + "permission_keyringDescription": { + "message": "Permita que $1 receba solicitações para adicionar ou remover contas, além de assinar e realizar transações em nome dessas contas.", + "description": "An extended description for the `endowment:keyring` permission. $1 is the snap name." + }, "permission_lifecycleHooks": { "message": "Usar ganchos de ciclo de vida.", "description": "The description for the `endowment:lifecycle-hooks` permission" }, + "permission_lifecycleHooksDescription": { + "message": "Permita que $1 use ganchos de ciclo de vida para executar códigos em momentos específicos durante seu ciclo de vida.", + "description": "An extended description for the `endowment:lifecycle-hooks` permission. $1 is the snap name." + }, "permission_manageAccounts": { "message": "Adicionar e controlar contas Ethereum", "description": "The description for `snap_manageAccounts` permission" }, + "permission_manageAccountsDescription": { + "message": "Permita que $1 adicione ou remova contas Ethereum e, depois, realize transações e assine com essas contas.", + "description": "An extended description for the `snap_manageAccounts` permission. $1 is the snap name." + }, + "permission_manageBip32Keys": { + "message": "Gerenciar contas de $1.", + "description": "The description for the `snap_getBip32Entropy` permission. $1 is a derivation path, e.g. 'm/44'/0'/0' (secp256k1)'." + }, + "permission_manageBip44AndBip32KeysDescription": { + "message": "Permita que $1 gerencie contas e ativos na rede solicitada. Essas contas são derivadas e passam por backup usando sua Frase de Recuperação Secreta (sem a revelar). Com o poder de derivar chaves, $1 pode dar suporte a uma variedade de protocolos da blockchain além da Ethereum (EVMs).", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions. $1 is the snap name." + }, + "permission_manageBip44Keys": { + "message": "Gerenciar contas de $1.", + "description": "The description for the `snap_getBip44Entropy` permission. $1 is the name of a protocol, e.g. 'Filecoin'." + }, "permission_manageState": { "message": "Armazenar e gerenciar dados pertinentes em seu dispositivo.", "description": "The description for the `snap_manageState` permission" }, + "permission_manageStateDescription": { + "message": "Permita que $1 armazene, atualize e recupere dados de forma segura com criptografia. Outros Snaps não podem acessar essas informações.", + "description": "An extended description for the `snap_manageState` permission. $1 is the snap name." + }, + "permission_nameLookup": { + "message": "Fornecer consultas de domínios e endereços.", + "description": "The description for the `endowment:name-lookup` permission." + }, + "permission_nameLookupDescription": { + "message": "Permitir que o Snap busque e exiba consultas de endereços e domínios em diferentes partes da IU da MetaMask.", + "description": "An extended description for the `endowment:name-lookup` permission." + }, "permission_notifications": { "message": "Mostrar notificações.", "description": "The description for the `snap_notify` permission" }, "permission_notificationsDescription": { - "message": "Permitir que o snap exiba notificações dentro da MetaMask. Um breve texto de notificação pode ser disparado por um snap para informações acionáveis ou sensíveis ao tempo.", + "message": "Permita que $1 exiba notificações dentro da MetaMask. Um breve texto de notificação pode ser disparado por um Snap para informações acionáveis ou sensíveis ao tempo.", "description": "An extended description for the `snap_notify` permission. $1 is the snap name." }, + "permission_rpc": { + "message": "Permitir que $1 se comunique diretamente com $2.", + "description": "The description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescription": { + "message": "Permita que $1 envie mensagens a $2 e receba resposta de $2.", + "description": "An extended description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescriptionOriginList": { + "message": "$1 e $2", + "description": "A list of allowed origins where $2 is the last origin of the list and $1 is the rest of the list separated by ','." + }, + "permission_signatureInsight": { + "message": "Exibir o modal de insights de assinatura.", + "description": "The description for the `endowment:signature-insight` permission" + }, + "permission_signatureInsightDescription": { + "message": "Permita que $1 exiba um modal com insights sobre solicitações de assinatura antes de aprová-las. Isso pode ser usado para soluções de segurança e antiphishing.", + "description": "An extended description for the `endowment:signature-insight` permission. $1 is the snap name." + }, + "permission_signatureInsightOrigin": { + "message": "Veja as origens de sites que iniciam solicitações de assinatura", + "description": "The description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission" + }, + "permission_signatureInsightOriginDescription": { + "message": "Permita que $1 veja a origem (URI) dos sites que iniciam solicitações de assinatura. Isso pode ser usado para soluções de segurança e antiphishing.", + "description": "An extended description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission. $1 is the snap name." + }, "permission_transactionInsight": { "message": "Busque e exiba insights de transações.", "description": "The description for the `endowment:transaction-insight` permission" }, + "permission_transactionInsightDescription": { + "message": "Permita que $1 decodifique transações e exiba informações dentro da interface da MetaMask. Isso pode ser usado para soluções de segurança e antiphishing.", + "description": "An extended description for the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_transactionInsightOrigin": { "message": "Verá as origens dos sites que sugerem transações", "description": "The description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission" }, + "permission_transactionInsightOriginDescription": { + "message": "Permita que $1 veja a origem (URI) dos sites que sugerirem transações. Isso pode ser usado para soluções de segurança e antiphishing.", + "description": "An extended description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_unknown": { "message": "Permissão desconhecida: $1", "description": "$1 is the name of a requested permission that is not recognized." @@ -2896,29 +3621,66 @@ "message": "Ver sua chave pública para $1 ($2).", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a derivation path, e.g. 'm/44'/0'/0''. $2 is the elliptic curve name, e.g. 'secp256k1'." }, + "permission_viewBip32PublicKeysDescription": { + "message": "Permita que $2 veja suas chaves públicas (e endereços) referentes a $1. Isso não concede nenhum tipo de controle das contas ou ativos.", + "description": "An extended description for the `snap_getBip32PublicKey` permission. $1 is a derivation path (name). $2 is the snap name." + }, "permission_viewNamedBip32PublicKeys": { "message": "Veja sua chave pública para $1.", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a name for the derivation path, e.g., 'Ethereum accounts'." }, + "permission_walletSwitchEthereumChain": { + "message": "Troque e use a seguinte rede", + "description": "The label for the `wallet_switchEthereumChain` permission" + }, "permission_webAssembly": { "message": "Suporte a WebAssembly.", "description": "The description of the `endowment:webassembly` permission." }, + "permission_webAssemblyDescription": { + "message": "Permita que $1 acesse ambientes de execução de baixo nível via WebAssembly.", + "description": "An extended description of the `endowment:webassembly` permission. $1 is the snap name." + }, "permissions": { "message": "Permissões" }, - "permissionsTitle": { - "message": "Permissões" + "permissionsPageEmptyContent": { + "message": "Não há nada aqui" + }, + "permissionsPageEmptySubContent": { + "message": "Aqui você pode ver as permissões que deu aos snaps instalados ou sites conectados." }, - "permissionsTourDescription": { - "message": "Encontre suas contas conectadas e gerencie permissões aqui" + "permissionsPageTourDescription": { + "message": "Este é o seu painel de controle para gerenciar as permissões dadas aos sites conectados e snaps instalados." + }, + "permissionsPageTourTitle": { + "message": "Sites conectados agora são permissões" }, "personalAddressDetected": { "message": "Endereço pessoal detectado. Insira o endereço de contrato do token." }, + "petnamesEnabledToggle": { + "message": "Permitir apelidos" + }, + "petnamesEnabledToggleDescription": { + "message": "Isso permite que você atribua um apelido a qualquer endereço. Sempre que possível, vamos sugerir nomes para os endereços com os quais você interage." + }, + "pinExtensionDescription": { + "message": "Navegue até o menu da extensão e fixe o MetaMask Institutional para acessar facilmente." + }, + "pinExtensionTitle": { + "message": "Fixar extensão" + }, + "pinToTop": { + "message": "Fixar ao topo" + }, "pleaseConfirm": { "message": "Por favor, confirme" }, + "plusMore": { + "message": "E mais $1", + "description": "$1 is the number of additional items" + }, "plusXMore": { "message": "E mais $1", "description": "$1 is a number of additional but unshown items in a list- this message will be shown in place of those items" @@ -2944,6 +3706,9 @@ "primaryCurrencySettingDescription": { "message": "Selecione Nativa para priorizar a exibição de valores na moeda nativa da cadeia (por ex., ETH). Selecione Fiduciária para priorizar a exibição de valores na moeda fiduciária selecionada." }, + "primaryType": { + "message": "Tipo primário" + }, "priorityFee": { "message": "Taxa de prioridade" }, @@ -2964,6 +3729,18 @@ "message": "Chave privada de $1", "description": "$1 represents the account name" }, + "privateKeyHidden": { + "message": "A chave privada está oculta", + "description": "Explains that the private key input is hidden" + }, + "privateKeyShow": { + "message": "Exibir/ocultar a inserção da chave privada", + "description": "Describes a toggle that is used to show or hide the private key input" + }, + "privateKeyShown": { + "message": "Esta chave privada está sendo exibida", + "description": "Explains that the private key input is being shown" + }, "privateKeyWarning": { "message": "Atenção: jamais revele essa chave. Qualquer pessoa com acesso às suas chaves privadas poderá roubar os ativos de sua conta." }, @@ -2973,6 +3750,21 @@ "proceedWithTransaction": { "message": "Quero prosseguir mesmo assim" }, + "productAnnouncements": { + "message": "Anúncios de produtos" + }, + "profileSync": { + "message": "Sincronização de perfil" + }, + "profileSyncConfirmation": { + "message": "Se você desativar a sincronização de perfil, não poderá receber notificações." + }, + "profileSyncDescription": { + "message": "Cria um perfil que a MetaMask usa para sincronizar algumas configurações entre seus dispositivos. Isso é necessário para receber notificações. $1." + }, + "profileSyncPrivacyLink": { + "message": "Saiba como protegemos sua privacidade" + }, "proposedApprovalLimit": { "message": "Limite de aprovação proposto" }, @@ -2982,6 +3774,78 @@ "publicAddress": { "message": "Endereço público" }, + "pushPlatformNotificationsFundsReceivedDescription": { + "message": "Você recebeu $1 $2" + }, + "pushPlatformNotificationsFundsReceivedDescriptionDefault": { + "message": "Você recebeu alguns tokens" + }, + "pushPlatformNotificationsFundsReceivedTitle": { + "message": "Fundos recebidos" + }, + "pushPlatformNotificationsFundsSentDescription": { + "message": "Você enviou $1 $2 com sucesso" + }, + "pushPlatformNotificationsFundsSentDescriptionDefault": { + "message": "Você enviou alguns tokens com sucesso" + }, + "pushPlatformNotificationsFundsSentTitle": { + "message": "Fundos enviados" + }, + "pushPlatformNotificationsNftReceivedDescription": { + "message": "Você recebeu novos NFTs" + }, + "pushPlatformNotificationsNftReceivedTitle": { + "message": "NFT recebido" + }, + "pushPlatformNotificationsNftSentDescription": { + "message": "Você enviou um NFT com sucesso" + }, + "pushPlatformNotificationsNftSentTitle": { + "message": "NFT enviado" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedDescription": { + "message": "Seu staking na Lido foi bem-sucedido" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedTitle": { + "message": "Staking concluído" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnDescription": { + "message": "Seu staking na Lido está pronto para ser retirado" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnTitle": { + "message": "Staking pronto para ser retirado" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedDescription": { + "message": "Sua retirada da Lido foi bem-sucedida" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedTitle": { + "message": "Retirada concluída" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedDescription": { + "message": "Sua solicitação de retirada da Lido foi enviada" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedTitle": { + "message": "Retirada solicitada" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedDescription": { + "message": "Seu staking na Rocket Pool foi bem-sucedido" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedTitle": { + "message": "Staking concluído" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedDescription": { + "message": "Sua retirada de staking na Rocket Pool foi bem-sucedida" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedTitle": { + "message": "Retirada de staking concluída" + }, + "pushPlatformNotificationsSwapCompletedDescription": { + "message": "Sua troca na MetaMask foi bem-sucedida" + }, + "pushPlatformNotificationsSwapCompletedTitle": { + "message": "Troca concluída" + }, "queued": { "message": "Na fila" }, @@ -3000,9 +3864,15 @@ "receive": { "message": "Receber" }, + "receiveTokensCamelCase": { + "message": "Receber tokens" + }, "recipientAddressPlaceholder": { "message": "Insira o endereço público (0x) ou o nome ENS" }, + "recipientAddressPlaceholderFlask": { + "message": "Insira o endereço público (0x) ou nome do domínio" + }, "recommendedGasLabel": { "message": "Recomendado" }, @@ -3030,6 +3900,12 @@ "recoveryPhraseReminderTitle": { "message": "Proteja seus fundos" }, + "redesignedConfirmationsEnabledToggle": { + "message": "Solicitações de assinatura aprimoradas" + }, + "redesignedConfirmationsToggleDescription": { + "message": "Ative para ver as solicitações de assinatura em um formato aprimorado." + }, "refreshList": { "message": "Atualizar lista" }, @@ -3072,14 +3948,29 @@ "removeJWTDescription": { "message": "Tem certeza de que deseja remover este token? Todas as contas atribuídas a ele também serão removidas da extensão: " }, + "removeKeyringSnap": { + "message": "Remover esse Snap removerá estas contas da MetaMask:" + }, + "removeKeyringSnapToolTip": { + "message": "O Snap controla as contas e, ao removê-lo, as contas também serão removidas da MetaMask, mas permanecerão na blockchain." + }, "removeNFT": { "message": "Remover NFT" }, + "removeNftErrorMessage": { + "message": "Não foi possível remover este NFT." + }, "removeNftMessage": { "message": "O NFT foi removido com sucesso!" }, "removeSnap": { - "message": "Remover snap" + "message": "Remover Snap" + }, + "removeSnapAccountDescription": { + "message": "Se você prosseguir, essa conta não estará mais disponível na MetaMask." + }, + "removeSnapAccountTitle": { + "message": "Remover conta" }, "removeSnapConfirmation": { "message": "Tem certeza de que deseja remover $1?", @@ -3091,12 +3982,24 @@ "replace": { "message": "substituir" }, + "reportIssue": { + "message": "Comunicar um problema" + }, "requestFlaggedAsMaliciousFallbackCopyReason": { "message": "O provedor de segurança não compartilhou mais detalhes" }, "requestFlaggedAsMaliciousFallbackCopyReasonTitle": { "message": "Solicitação sinalizada como mal-intencionada" }, + "requestFrom": { + "message": "Solicitação de" + }, + "requestFromInfo": { + "message": "Este é o site solicitando sua assinatura." + }, + "requestFromTransactionDescription": { + "message": "Este é o site solicitando sua confirmação." + }, "requestMayNotBeSafe": { "message": "A solicitação pode não ser segura" }, @@ -3118,6 +4021,9 @@ "reset": { "message": "Redefinir" }, + "resetStates": { + "message": "Redefinir estados" + }, "resetWallet": { "message": "Redefinir carteira" }, @@ -3146,7 +4052,7 @@ "message": "Restaurar dados do usuário" }, "restoreUserDataDescription": { - "message": "Você pode restaurar as configurações do usuário contendo preferências e endereços de contas a partir de um arquivo de backup JSON." + "message": "Você pode restaurar dados como contatos e preferências a partir de um arquivo de backup." }, "resultPageError": { "message": "Erro" @@ -3200,9 +4106,15 @@ "message": "O Suporte da MetaMask nunca solicitará essa informação.", "description": "The bolded texted in the second part of 'revealSeedWordsWarning'" }, + "revealSensitiveContent": { + "message": "Revelar conteúdo confidencial" + }, "revealTheSeedPhrase": { "message": "Revelar a frase-semente" }, + "reviewAlerts": { + "message": "Conferir alertas" + }, "revokeAllTokensTitle": { "message": "Revogar permissão de acesso e transferência de todos os seus $1?", "description": "$1 is the symbol of the token for which the user is revoking approval" @@ -3253,6 +4165,9 @@ "searchAccounts": { "message": "Pesquisar contas" }, + "searchTokens": { + "message": "Pesquisar tokens" + }, "secretRecoveryPhrase": { "message": "Frase de Recuperação Secreta" }, @@ -3269,7 +4184,8 @@ "message": "Alertas de segurança" }, "securityAlertsDescription": { - "message": "Esse recurso alerta sobre atividades mal-intencionadas na Mainnet da Ethereum ao analisar ativamente solicitações de transações e assinaturas enquanto preserva sua privacidade. Seus dados não são compartilhados com os terceiros que prestam esse serviço. Sempre faça sua própria devida diligência antes de aprovar solicitações. Não há garantia de que esse recurso detectará toda e qualquer atividade mal-intencionada." + "message": "Esse recurso alerta você sobre atividades mal-intencionadas analisando ativamente as solicitações de transações e assinaturas. $1", + "description": "Link to learn more about security alerts" }, "securityAndPrivacy": { "message": "Segurança e Privacidade" @@ -3359,6 +4275,9 @@ "selectAnAccountHelp": { "message": "Selecione as contas custodiantes para usar no MetaMask Institutional." }, + "selectEnableDisplayMediaPrivacyPreference": { + "message": "Ativar Exibir arquivos de mídia de NFTs" + }, "selectHdPath": { "message": "Selecione o caminho do disco rígido" }, @@ -3380,18 +4299,41 @@ "send": { "message": "Enviar" }, + "sendAToken": { + "message": "Enviar um token" + }, "sendBugReport": { "message": "Envie-nos um relatório de bugs." }, + "sendNoContactsConversionText": { + "message": "clique aqui" + }, + "sendNoContactsDescription": { + "message": "Contatos permitem que você envie transações de forma segura para outra conta diversas vezes. Para criar um contato, $1", + "description": "$1 represents the action text 'click here'" + }, + "sendNoContactsTitle": { + "message": "Você ainda não tem nenhum contato" + }, + "sendSelectReceiveAsset": { + "message": "Selecionar ativo para receber" + }, + "sendSelectSendAsset": { + "message": "Selecionar ativo para enviar" + }, "sendSpecifiedTokens": { "message": "Enviar $1", "description": "Symbol of the specified token" }, - "sendTo": { - "message": "Enviar para" + "sendSwapSubmissionWarning": { + "message": "Clicar neste botão iniciará imediatamente sua transação de swap. Confira os detalhes da sua transação antes de prosseguir." + }, + "sendTokenAsToken": { + "message": "Enviar $1 como $2", + "description": "Used in the transaction display list to describe a swap and send. $1 and $2 are the symbols of tokens in involved in the swap." }, - "sendTokens": { - "message": "Enviar tokens" + "sendingAsset": { + "message": "Enviando $1" }, "sendingDisabled": { "message": "O envio de ativos NFT ERC-1155 ainda não é aceito." @@ -3404,9 +4346,15 @@ "message": "Aviso: você está prestes a enviar a um contrato de token que pode resultar em perda de fundos. $1", "description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning" }, + "sendingZeroAmount": { + "message": "Você está enviando 0 $1." + }, "sepolia": { "message": "Rede de teste Sepolia" }, + "serviceWorkerKeepAlive": { + "message": "Service Worker Keep Alive" + }, "setAdvancedPrivacySettingsDetails": { "message": "A MetaMask utiliza esses serviços terceirizados de confiança para aumentar a usabilidade e a segurança dos produtos." }, @@ -3418,7 +4366,7 @@ "description": "The token symbol that is being approved" }, "settingAddSnapAccount": { - "message": "Adicionar conta de snaps" + "message": "Adicionar Snap da conta" }, "settings": { "message": "Configurações" @@ -3426,9 +4374,21 @@ "settingsSearchMatchingNotFound": { "message": "Nenhum resultado correspondente encontrado." }, + "settingsSubHeadingSignaturesAndTransactions": { + "message": "Solicitações de assinaturas e transações" + }, "show": { "message": "Exibir" }, + "showAccount": { + "message": "Exibir conta" + }, + "showExtensionInFullSizeView": { + "message": "Exibir extensão na visão de tamanho real" + }, + "showExtensionInFullSizeViewDescription": { + "message": "Ative esta opção para tornar a visão de tamanho real o seu padrão ao clicar no ícone da extensão." + }, "showFiatConversionInTestnets": { "message": "Exibir conversão nas redes de teste" }, @@ -3448,6 +4408,9 @@ "message": "Isso depende de $1, que terá acesso ao seu endereço Ethereum e ao seu endereço IP. $2", "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" }, + "showIncomingTransactionsExplainer": { + "message": "Isso depende de diferentes APIs de terceiros para cada rede, o que expõe seu endereço Ethereum e seu endereço IP." + }, "showMore": { "message": "Exibir mais" }, @@ -3487,9 +4450,46 @@ "signin": { "message": "Entrar" }, + "signing": { + "message": "Assinando" + }, + "simulationDetailsFailed": { + "message": "Houve um erro ao carregar sua estimativa." + }, + "simulationDetailsFiatNotAvailable": { + "message": "Não disponível" + }, + "simulationDetailsIncomingHeading": { + "message": "Você recebe" + }, + "simulationDetailsNoBalanceChanges": { + "message": "Nenhuma alteração prevista para sua carteira" + }, + "simulationDetailsOutgoingHeading": { + "message": "Você envia" + }, + "simulationDetailsTitle": { + "message": "Alterações estimadas" + }, + "simulationDetailsTitleTooltip": { + "message": "As alterações estimadas podem acontecer se você prosseguir com essa transação. É apenas uma previsão, não uma garantia." + }, + "simulationDetailsTotalFiat": { + "message": "Total = $1", + "description": "$1 is the total amount in fiat currency on one side of the transaction" + }, + "simulationDetailsTransactionReverted": { + "message": "Essa transação provavelmente falhará" + }, "simulationErrorMessageV2": { "message": "Não conseguimos estimar o preço do gás. Pode haver um erro no contrato, e essa transação poderá falhar." }, + "simulationsSettingDescription": { + "message": "Ative para estimar as alterações de saldo das transações antes de confirmá-las. Isso não garante o resultado das suas transações. $1" + }, + "simulationsSettingSubHeader": { + "message": "Estimar alterações de saldo" + }, "skip": { "message": "Pular" }, @@ -3502,20 +4502,99 @@ "smartContracts": { "message": "Contratos inteligentes" }, - "smartSwapsAreHere": { - "message": "As trocas inteligentes chegaram!" - }, - "smartSwapsDescription": { - "message": "As trocas na MetaMask ficaram muito mais inteligentes! Ativar as trocas inteligentes permitirá que a MetaMask otimize programaticamente sua troca para ajudar:" - }, "smartSwapsErrorNotEnoughFunds": { "message": "Fundos insuficientes para uma troca inteligente." }, "smartSwapsErrorUnavailable": { "message": "As trocas inteligentes estão temporariamente indisponíveis." }, + "smartTransactionCancelled": { + "message": "Sua transação foi cancelada" + }, + "smartTransactionCancelledDescription": { + "message": "Não foi possível concluir sua transação. Ela foi cancelada para evitar que você pague taxas de gás desnecessárias." + }, + "smartTransactionError": { + "message": "Falha na transação" + }, + "smartTransactionErrorDescription": { + "message": "Mudanças repentinas no mercado podem provocar falhas. Se o problema continuar, fale com o suporte ao cliente da MetaMask." + }, + "smartTransactionPending": { + "message": "Enviando sua transação" + }, + "smartTransactionSuccess": { + "message": "Sua transação foi concluída" + }, + "smartTransactionTakingTooLong": { + "message": "Desculpe pela espera" + }, + "smartTransactionTakingTooLongDescription": { + "message": "Se a sua transação não for finalizada em $1, ela será cancelada e você não pagará gás.", + "description": "$1 is remaining time in seconds" + }, + "smartTransactions": { + "message": "Transações inteligentes" + }, + "smartTransactionsBenefit1": { + "message": "99,5% de taxa de sucesso" + }, + "smartTransactionsBenefit2": { + "message": "Faz você economizar dinheiro" + }, + "smartTransactionsBenefit3": { + "message": "Atualizações em tempo real" + }, + "smartTransactionsDescription": { + "message": "Desbloqueie taxas de sucesso maiores, proteção contra front running e melhor visibilidade com as transações inteligentes." + }, + "smartTransactionsDescription2": { + "message": "Disponível somente na Ethereum. Ative ou desative a qualquer momento nas configurações. $1", + "description": "$1 is an external link to learn more about Smart Transactions" + }, + "smartTransactionsOptItModalTitle": { + "message": "Proteção de transações aprimorada" + }, + "snapAccountCreated": { + "message": "Conta criada" + }, + "snapAccountCreatedDescription": { + "message": "Sua nova conta está pronta para ser usada!" + }, + "snapAccountCreationFailed": { + "message": "Falha na criação da conta" + }, + "snapAccountCreationFailedDescription": { + "message": "$1 não conseguiu criar uma conta para você.", + "description": "$1 is the snap name" + }, + "snapAccountRedirectFinishSigningTitle": { + "message": "Finalizar assinatura" + }, + "snapAccountRedirectSiteDescription": { + "message": "Siga as instruções de $1" + }, + "snapAccountRemovalFailed": { + "message": "Falha na remoção da conta" + }, + "snapAccountRemovalFailedDescription": { + "message": "$1 não conseguiu remover essa conta para você.", + "description": "$1 is the snap name" + }, + "snapAccountRemoved": { + "message": "Conta removida" + }, + "snapAccountRemovedDescription": { + "message": "Essa conta não estará mais disponível para uso na MetaMask." + }, + "snapAccounts": { + "message": "Snaps da conta" + }, + "snapAccountsDescription": { + "message": "Contas controladas por Snaps de terceiros." + }, "snapConnectionWarning": { - "message": "$1 deseja conectar-se a $2. Continue apenas se você confia no site.", + "message": "$1 quer usar $2", "description": "$2 is the snap and $1 is the dapp requesting connection to the snap." }, "snapContent": { @@ -3526,15 +4605,35 @@ "message": "Site" }, "snapInstallRequest": { - "message": "Instalar $1 concede as permissões a seguir. Continue apenas se você confia em $1.", + "message": "Ao instalar $1, serão dadas as permissões a seguir.", "description": "$1 is the snap name." }, "snapInstallSuccess": { "message": "Instalação concluída" }, + "snapInstallWarningCheck": { + "message": "$1 quer permissão para fazer o seguinte:", + "description": "Warning message used in popup displayed on snap install. $1 is the snap name." + }, "snapInstallWarningHeading": { "message": "Prossiga com cautela" }, + "snapInstallWarningPermissionDescriptionForBip32View": { + "message": "Permita que $1 veja suas chaves públicas (e endereços). Isso não concede nenhum tipo de controle das contas ou ativos.", + "description": "An extended description for the `snap_getBip32PublicKey` permission used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionDescriptionForEntropy": { + "message": "Permita que o Snap $1 gerencie contas e ativos nas redes solicitadas. Essas contas são derivadas e passam por backup usando sua Frase de Recuperação Secreta (sem a revelar). Com o poder de derivar chaves, $1 pode dar suporte a uma variedade de protocolos da blockchain além da Ethereum (EVMs).", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionNameForEntropy": { + "message": "Gerenciar contas $1", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, + "snapInstallWarningPermissionNameForViewPublicKey": { + "message": "Ver sua chave pública para $1", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, "snapInstallationErrorDescription": { "message": "$1 não pôde ser instalado.", "description": "Error description used when snap installation fails. $1 is the snap name." @@ -3552,6 +4651,10 @@ "snapResultSuccessDescription": { "message": "$1 está pronto para ser usado" }, + "snapUpdateAlertDescription": { + "message": "Baixe a última versão de $1", + "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." + }, "snapUpdateAvailable": { "message": "Atualização disponível" }, @@ -3563,22 +4666,40 @@ "message": "Falha na atualização", "description": "Error title used when snap update fails." }, + "snapUpdateRequest": { + "message": "Ao atualizar $1, serão dadas as permissões a seguir.", + "description": "$1 is the Snap name." + }, "snapUpdateSuccess": { "message": "Atualização concluída" }, + "snapUrlIsBlocked": { + "message": "Esse Snap deseja levar você a um site bloqueado. $1." + }, "snaps": { "message": "Snaps" }, - "snapsInvalidUIError": { - "message": "A IU especificada pelo snap é inválida." + "snapsConnected": { + "message": "Snaps conectados" }, "snapsNoInsight": { "message": "O snap não retornou nenhum insight" }, + "snapsPrivacyWarningFirstMessage": { + "message": "Você reconhece que qualquer Snap instalado é um Serviço Terceirizado, a menos que identificado de outra forma, conforme definido nos $1 da Consensys. Seu uso de Serviços Terceirizados é regido por termos e condições separados, estabelecidos pelo prestador de Serviços Terceirizados. A Consensys não faz recomendação de uso de nenhum Snap a nenhuma pessoa específica por qualquer motivo específico. Você acessa, confia e usa o Serviço Terceirizado por sua conta e risco. A Consensys se isenta de toda e qualquer responsabilidade por perdas relacionadas ao seu uso de Serviços Terceirizados.", + "description": "First part of a message in popup modal displayed when installing a snap for the first time. $1 is terms of use link." + }, "snapsPrivacyWarningSecondMessage": { "message": "Informações compartilhadas com Serviços de Terceiros serão coletadas diretamente por eles, de acordo com políticas de privacidade próprias. Por favor, consulte-as para obter mais informações.", "description": "Second part of a message in popup modal displayed when installing a snap for the first time." }, + "snapsPrivacyWarningThirdMessage": { + "message": "A Consensys não tem acesso às informações que você compartilha com Serviços Terceirizados.", + "description": "Third part of a message in popup modal displayed when installing a snap for the first time." + }, + "snapsSettings": { + "message": "Configurações de Snaps" + }, "snapsTermsOfUse": { "message": "Termos de Uso" }, @@ -3592,12 +4713,19 @@ "someNetworksMayPoseSecurity": { "message": "Algumas redes podem representar riscos de segurança e/ou privacidade. Tenha os riscos em mente antes de adicionar e usar uma rede." }, + "somethingDoesntLookRight": { + "message": "Alguma coisa não parece certa? $1", + "description": "A false positive message for users to contact support. $1 is a link to the support page." + }, "somethingIsWrong": { "message": "Algo deu errado. Tente recarregar a página." }, "somethingWentWrong": { "message": "Ops! Algo deu errado." }, + "source": { + "message": "Fonte" + }, "speedUp": { "message": "Acelerar" }, @@ -3732,6 +4860,14 @@ "stake": { "message": "Stake" }, + "startYourJourney": { + "message": "Comece sua jornada com $1", + "description": "$1 is the token symbol" + }, + "startYourJourneyDescription": { + "message": "Comece sua jornada na web3 adicionando $1 à sua conta.", + "description": "$1 is the token symbol" + }, "stateLogError": { "message": "Erro ao recuperar os logs de estado." }, @@ -3744,6 +4880,9 @@ "stateLogsDescription": { "message": "Logs de estado podem conter o seu endereço e transações enviadas da sua conta pública." }, + "states": { + "message": "Estados" + }, "status": { "message": "Status" }, @@ -3787,18 +4926,6 @@ "strong": { "message": "Forte" }, - "stxBenefit1": { - "message": "Minimize os custos das transações" - }, - "stxBenefit2": { - "message": "Reduza as falhas nas transações" - }, - "stxBenefit3": { - "message": "Elimine transações travadas" - }, - "stxBenefit4": { - "message": "Previna o front-running (uso de informações privilegiadas para negociações)" - }, "stxCancelled": { "message": "A troca teria falhado" }, @@ -3808,6 +4935,10 @@ "stxCancelledSubDescription": { "message": "Tente trocar novamente. Estaremos aqui para proteger você contra riscos semelhantes no futuro." }, + "stxEstimatedCompletion": { + "message": "Conclusão estimada em até $1", + "description": "$1 is remeaning time in minutes and seconds, e.g. 0:10" + }, "stxFailure": { "message": "Falha na troca" }, @@ -3815,6 +4946,9 @@ "message": "Mudanças repentinas no mercado podem causar falhas. Se o problema persistir, entre em contato com $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInDescription": { + "message": "Ative as Transações Inteligentes para fazer transações mais confiáveis ​​e seguras na Mainnet da Ethereum. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Enviando sua troca de forma privada..." }, @@ -3853,12 +4987,21 @@ "submitted": { "message": "Enviada" }, + "suggestedTokenSymbol": { + "message": "Símbolo do ticker sugerido:" + }, "support": { "message": "Suporte" }, "supportCenter": { "message": "Visite a nossa Central de Suporte" }, + "surveyConversion": { + "message": "Responda à nossa pesquisa" + }, + "surveyTitle": { + "message": "Molde o futuro da MetaMask" + }, "swap": { "message": "Troca" }, @@ -3878,6 +5021,9 @@ "swapAmountReceivedInfo": { "message": "Esse é o valor mínimo que você receberá. Você pode receber mais, dependendo do slippage." }, + "swapAndSend": { + "message": "Executar swap e enviar" + }, "swapAnyway": { "message": "Trocar mesmo assim" }, @@ -3993,6 +5139,10 @@ "message": "Inclui uma taxa de $1% da MetaMask.", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." }, + "swapIncludesMMFeeAlt": { + "message": "A cotação reflete a taxa de $1% da MetaMask", + "description": "Provides information about the fee that metamask takes for swaps using the latest copy. $1 is a decimal number." + }, "swapIncludesMetaMaskFeeViewAllQuotes": { "message": "Inclui uma taxa de $1% da MetaMask – $2", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number and $2 is a link to view all quotes." @@ -4000,6 +5150,9 @@ "swapLearnMore": { "message": "Saiba mais sobre as trocas" }, + "swapLiquiditySourceInfo": { + "message": "Pesquisamos várias fontes de liquidez (corretoras, agregadores e formadores de mercado profissionais) para comparar taxas de câmbio e taxas de rede." + }, "swapLowSlippage": { "message": "Slippage baixo" }, @@ -4272,6 +5425,9 @@ "switchEthereumChainConfirmationTitle": { "message": "Permitir que esse site alterne a rede?" }, + "switchInputCurrency": { + "message": "Alternar moeda de entrada" + }, "switchNetwork": { "message": "Alternar rede" }, @@ -4285,14 +5441,15 @@ "switchToThisAccount": { "message": "Alternar para esta conta" }, - "switchedTo": { - "message": "Você alternou para" + "switchedNetworkToastDecline": { + "message": "Não exibir novamente" }, - "switcherTitle": { - "message": "Alternador de redes" + "switchedNetworkToastMessage": { + "message": "$1 agora está ativa na $2", + "description": "$1 represents the account name, $2 represents the network name" }, - "switcherTourDescription": { - "message": "Clique no ícone para alternar as redes ou adicionar uma nova" + "switchedTo": { + "message": "Você alternou para" }, "switchingNetworksCancelsPendingConfirmations": { "message": "A alternância de redes cancelará todas as confirmações pendentes" @@ -4392,6 +5549,18 @@ "toggleEthSignOn": { "message": "LIGADO (não recomendado)" }, + "toggleRequestQueueDescription": { + "message": "Isso permite que você selecione uma rede para cada site em vez de uma única rede selecionada para todos eles. O recurso evitará que você alterne manualmente entre redes, o que pode atrapalhar sua experiência de usuário em determinados sites." + }, + "toggleRequestQueueField": { + "message": "Selecionar redes para cada site" + }, + "toggleRequestQueueOff": { + "message": "Não" + }, + "toggleRequestQueueOn": { + "message": "Sim" + }, "token": { "message": "Token" }, @@ -4408,7 +5577,7 @@ "message": "Endereço de contrato do token" }, "tokenDecimalFetchFailed": { - "message": "A casa decimal do token é necessária." + "message": "É necessário o decimal do token. Encontre-o em: $1" }, "tokenDecimalTitle": { "message": "Decimal do token:" @@ -4447,6 +5616,9 @@ "tooltipSatusConnected": { "message": "conectada" }, + "tooltipSatusConnectedUpperCase": { + "message": "Conectado" + }, "tooltipSatusNotConnected": { "message": "não conectada" }, @@ -4587,6 +5759,39 @@ "tryAgain": { "message": "Tente novamente" }, + "turnOff": { + "message": "Desativar" + }, + "turnOffMetamaskNotificationsError": { + "message": "Ocorreu um erro ao desativar as notificações. Tente novamente mais tarde." + }, + "turnOn": { + "message": "Ativar" + }, + "turnOnMetamaskNotifications": { + "message": "Ativar notificações" + }, + "turnOnMetamaskNotificationsButton": { + "message": "Ativar" + }, + "turnOnMetamaskNotificationsError": { + "message": "Ocorreu um erro ao criar as notificações. Tente novamente mais tarde." + }, + "turnOnMetamaskNotificationsMessageFirst": { + "message": "Fique por dentro do que acontece na sua carteira com notificações." + }, + "turnOnMetamaskNotificationsMessagePrivacyBold": { + "message": "Configurações > Notificações." + }, + "turnOnMetamaskNotificationsMessagePrivacyLink": { + "message": "Saiba como protegemos sua privacidade enquanto usa este recurso." + }, + "turnOnMetamaskNotificationsMessageSecond": { + "message": "Para usar as notificações da carteira, nós usamos um perfil para sincronizar algumas configurações entre seus dispositivos. $1" + }, + "turnOnMetamaskNotificationsMessageThird": { + "message": "Você pode desativar as notificações a qualquer momento em $1" + }, "turnOnTokenDetection": { "message": "Ativar detecção avançada de token" }, @@ -4618,6 +5823,10 @@ "unknownNetwork": { "message": "Rede privada desconhecida" }, + "unknownNetworkForKeyEntropy": { + "message": "Rede desconhecida", + "description": "Displayed on places like Snap install warning when regular name is not available." + }, "unknownQrCode": { "message": "Erro: não conseguimos identificar esse código QR" }, @@ -4630,6 +5839,9 @@ "unlockMessage": { "message": "A web descentralizada te aguarda" }, + "unpin": { + "message": "Desafixar" + }, "unrecognizedChain": { "message": "Essa rede personalizada não foi reconhecida", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." @@ -4647,6 +5859,9 @@ "update": { "message": "Atualizar" }, + "updateRequest": { + "message": "Solicitação de atualização" + }, "updatedWithDate": { "message": "Atualizado em $1" }, @@ -4671,12 +5886,25 @@ "useNftDetection": { "message": "Detectar NFTs automaticamente" }, + "useNftDetectionDescriptionText": { + "message": "Permita que a MetaMask use serviços de terceiros (como o OpenSea) para adicionar os NFTs que você possui. A detecção automática de NFTs expõe seu endereço IP e o endereço da sua conta a esses serviços. Ativar esse recurso pode associar seu endereço IP ao seu endereço Ethereum e exibir NFTs falsos enviados por golpistas via AirDrop. Você pode adicionar tokens manualmente para evitar esse risco." + }, "usePhishingDetection": { "message": "Usar detecção de phishing" }, "usePhishingDetectionDescription": { "message": "Exibir uma advertência para os domínios de phishing destinados a usuários do Ethereum" }, + "useSafeChainsListValidation": { + "message": "Verificação de dados da rede" + }, + "useSafeChainsListValidationDescription": { + "message": "A MetaMask usa um serviço terceirizado chamado $1 para exibir dados precisos e padronizados das redes. Isso reduz suas chances de se conectar a uma rede mal-intencionada ou incorreta. Ao usar esse recurso, seu endereço IP é exposto à chainid.network." + }, + "useSafeChainsListValidationWebsite": { + "message": "chainid.network", + "description": "useSafeChainsListValidationWebsite is separated from the rest of the text so that we can bold the third party service name in the middle of them" + }, "useSiteSuggestion": { "message": "Usar sugestão do site" }, @@ -4689,6 +5917,9 @@ "userName": { "message": "Nome de usuário" }, + "userOpContractDeployError": { + "message": "A implementação do contrato a partir de uma conta de contrato inteligente não é suportada" + }, "verifyContractDetails": { "message": "Verificar dados do terceiro" }, @@ -4706,6 +5937,9 @@ "view": { "message": "Ver" }, + "viewActivity": { + "message": "Ver atividade" + }, "viewAllDetails": { "message": "Ver todos os detalhes" }, @@ -4729,7 +5963,7 @@ }, "viewOnCustomBlockExplorer": { "message": "Ver $1 em $2", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "Ver $1 no Etherscan", @@ -4741,6 +5975,9 @@ "viewOnOpensea": { "message": "Ver na OpenSea" }, + "viewTransaction": { + "message": "Ver transação" + }, "viewinCustodianApp": { "message": "Ver no app custodiante" }, @@ -4748,6 +5985,9 @@ "message": "Ver $1 no explorador", "description": "$1 is the action type. e.g (Account, Transaction, Swap)" }, + "visitSite": { + "message": "Visitar site" + }, "visitWebSite": { "message": "Visite nosso site" }, @@ -4786,6 +6026,10 @@ "warning": { "message": "Atenção" }, + "warningFromSnap": { + "message": "Aviso de $1", + "description": "$1 represents the name of the snap" + }, "warningTooltipText": { "message": "$1 O terceiro pode gastar todo o seu saldo de tokens sem aviso ou consentimento. Proteja-se personalizando um limite de gastos menor.", "description": "$1 is a warning icon with text 'Be careful' in 'warning' colour" @@ -4793,6 +6037,9 @@ "weak": { "message": "Fraca" }, + "web3": { + "message": "Web3" + }, "web3ShimUsageNotification": { "message": "Percebemos que o site atual tentou usar a API window.web3 removida. Se o site parecer estar corrompido, clique em $1 para obter mais informações.", "description": "$1 is a clickable link." @@ -4833,10 +6080,6 @@ "whatsThis": { "message": "O que é isso?" }, - "xOfY": { - "message": "$1 de $2", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$1 de $2 pendente(s)", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" @@ -4844,6 +6087,9 @@ "yes": { "message": "Sim" }, + "you": { + "message": "Você" + }, "youHaveAddedAll": { "message": "Você adicionou todas as redes populares. Você pode descobrir mais redes $1 Ou você pode $2", "description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'" @@ -4866,6 +6112,12 @@ "yourPrivateSeedPhrase": { "message": "Sua Frase de Recuperação Secreta" }, + "yourTransactionConfirmed": { + "message": "Transação já confirmada" + }, + "yourTransactionJustConfirmed": { + "message": "Não pudemos cancelar sua transação antes de ser confirmada na blockchain." + }, "zeroGasPriceOnSpeedUpError": { "message": "O preço do gás está zerado na aceleração" } diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index c2fe68724a82..cc4c97e70ff6 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -172,16 +172,10 @@ "alerts": { "message": "Alertas" }, - "allowExternalExtensionTo": { - "message": "Permitir que essa extensão externa:" - }, "allowSpendToken": { "message": "Você concede acesso aos seus $1?", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "Permitir que esse site:" - }, "allowWithdrawAndSpend": { "message": "Permitir que $1 saque e gaste até o seguinte valor:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -308,9 +302,6 @@ "cancel": { "message": "Cancelar" }, - "cancelEdit": { - "message": "Cancelar edição" - }, "cancelPopoverTitle": { "message": "Cancelar transação" }, @@ -377,26 +368,6 @@ "connectManually": { "message": "Conectar manualmente ao site atual" }, - "connectTo": { - "message": "Conectar a $1", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "Conecte-se a todas as suas $1", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "contas", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "Conecte-se a $1", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1 contas", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "Conectar-se com a MetaMask" }, @@ -1410,22 +1381,6 @@ "notEnoughGas": { "message": "Não há gás suficiente" }, - "notifications8ActionText": { - "message": "Ir para Configurações Avançadas", - "description": "Description on an action button that appears in the What's New popup. Tells the user that if they click it, they will go to our Advanced settings page." - }, - "notifications8DescriptionOne": { - "message": "A partir da MetaMask v10.4.0, não é mais necessário o Ledger Live para conectar o seu dispositivo Ledger à MetaMask.", - "description": "Description of a notification in the 'See What's New' popup. Describes changes for how Ledger Live is no longer needed to connect the device." - }, - "notifications8DescriptionTwo": { - "message": "Para uma experiência mais fácil e estável com o ledger, vá até a aba Avançado das configurações e troque o \"Tipo de conexão preferencial com o Ledger\" para \"WebHID\".", - "description": "Description of a notification in the 'See What's New' popup. Describes how the user can turn off the Ledger Live setting." - }, - "notifications8Title": { - "message": "Melhoria na conexão com o Ledger", - "description": "Title for a notification in the 'See What's New' popup. Notifies ledger users that there is an improvement in how they can connect their device." - }, "ofTextNofM": { "message": "de" }, @@ -1491,7 +1446,8 @@ "message": "Um provedor de rede mal-intencionado pode mentir sobre o estado do blockchain e registrar as atividades da sua rede. Adicione somente as redes personalizadas em que você confia." }, "onlyConnectTrust": { - "message": "Conecte-se somente com sites em que você confia." + "message": "Conecte-se somente com sites em que você confia.", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." }, "openFullScreenForLedgerWebHid": { "message": "Abra a MetaMask em tela cheia para conectar sua ledger por meio do WebHID.", @@ -1825,12 +1781,6 @@ "message": "Enviar $1", "description": "Symbol of the specified token" }, - "sendTo": { - "message": "Enviar para" - }, - "sendTokens": { - "message": "Enviar tokens" - }, "sendingDisabled": { "message": "O envio de ativos NFT ERC-1155 ainda não é aceito." }, @@ -2547,7 +2497,7 @@ }, "viewOnCustomBlockExplorer": { "message": "Ver $1 em $2", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "Ver $1 no Etherscan", @@ -2622,10 +2572,6 @@ "whatsThis": { "message": "O que é isso?" }, - "xOfY": { - "message": "$1 de $2", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$1 de $2 pendente", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" diff --git a/app/_locales/ro/messages.json b/app/_locales/ro/messages.json index 1049ba58d9bb..fa02911ca8f3 100644 --- a/app/_locales/ro/messages.json +++ b/app/_locales/ro/messages.json @@ -617,9 +617,6 @@ "send": { "message": "Trimite" }, - "sendTokens": { - "message": "Trimiteți indicative" - }, "settings": { "message": "Setări" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 857be230dc68..3106cf4540f4 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -130,12 +130,21 @@ "account": { "message": "Счет" }, + "accountActivity": { + "message": "Активность счета" + }, + "accountActivityText": { + "message": "Выберите счета, о которых хотите получать уведомления:" + }, "accountDetails": { "message": "Реквизиты счета" }, "accountIdenticon": { "message": "Идентикон счета" }, + "accountIsntConnectedToastText": { + "message": "$1 не подключен к $2" + }, "accountName": { "message": "Имя счета" }, @@ -153,6 +162,12 @@ "accountSelectionRequired": { "message": "Вам необходимо выбрать счет!" }, + "accounts": { + "message": "Счета" + }, + "accountsConnected": { + "message": "Счета подключены" + }, "active": { "message": "Активный" }, @@ -243,6 +258,9 @@ "addIPFSGateway": { "message": "Добавьте предпочтительный шлюз IPFS" }, + "addImportAccount": { + "message": "Добавить счет или аппаратный кошелек" + }, "addMemo": { "message": "Добавить примечание" }, @@ -256,6 +274,9 @@ "message": "Это сетевое подключение зависит от третьих сторон. Оно может быть менее надежным или позволять третьим лицам отслеживать активность. $1", "description": "$1 is Learn more link" }, + "addNewAccount": { + "message": "Добавить новый счет" + }, "addNewToken": { "message": "Добавить новый токен" }, @@ -265,6 +286,12 @@ "addNfts": { "message": "Добавить NFT" }, + "addSnapAccountToggle": { + "message": "Включите «Добавить Snap счета (бета)»" + }, + "addSnapAccountsDescription": { + "message": "Включение этой функции даст вам возможность добавлять новые бета-версии Snaps счетов прямо из списка счетов. Когда вы устанавливаете Snap счета, помните, что это сторонний сервис." + }, "addSuggestedNFTs": { "message": "Добавить рекомендованные NFT" }, @@ -281,6 +308,9 @@ "addingCustomNetwork": { "message": "Добавление сети" }, + "addingTokens": { + "message": "Добавление токенов" + }, "address": { "message": "Адрес" }, @@ -316,9 +346,27 @@ "airgapVault": { "message": "AirGap Vault" }, + "alert": { + "message": "Оповещение" + }, + "alertBannerMultipleAlertsDescription": { + "message": "Если вы одобрите этот запрос, третья сторона, которая, как известно, совершала мошеннические действия, может похитить все ваши активы." + }, + "alertBannerMultipleAlertsTitle": { + "message": "Множественные оповещения!" + }, "alertDisableTooltip": { "message": "Это можно изменить в разделе «Настройки» > «Оповещения»" }, + "alertModalAcknowledge": { + "message": "Я осознал(-а) риск и все еще хочу продолжить" + }, + "alertModalDetails": { + "message": "Сведения об оповещении" + }, + "alertModalReviewAllAlerts": { + "message": "Просмотреть все оповещения" + }, "alertSettingsUnconnectedAccount": { "message": "Просмотр веб-сайта с выбранным неподключенным счетом" }, @@ -334,6 +382,9 @@ "alerts": { "message": "Оповещения" }, + "all": { + "message": "Все" + }, "allCustodianAccountsConnectedSubtitle": { "message": "Вы либо уже подключили все свои счета депозитария, либо у вас нет счета для подключения к MetaMask Institutional." }, @@ -344,23 +395,26 @@ "message": "Все ваши $1", "description": "$1 is the symbol or name of the token that the user is approving spending" }, + "allPermissions": { + "message": "Все разрешения" + }, "allYourNFTsOf": { "message": "Все ваши NFT из $1", "description": "$1 is a link to contract on the block explorer when we're not able to retrieve a erc721 or erc1155 name" }, - "allowExternalExtensionTo": { - "message": "Разрешить этому внешнему расширению:" + "allow": { + "message": "Разрешить" + }, + "allowMmiToConnectToCustodian": { + "message": "Это позволит MMI подключиться к $1 для импорта ваших счетов." + }, + "allowNotifications": { + "message": "Разрешить уведомления" }, "allowSpendToken": { "message": "Разрешить доступ к вашему $1?", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "Разрешить этому сайту:" - }, - "allowThisSnapTo": { - "message": "Разрешить этот snap к:" - }, "allowWithdrawAndSpend": { "message": "Разрешить $1 снять и потратить до следующей суммы:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -368,6 +422,23 @@ "amount": { "message": "Сумма" }, + "amountReceived": { + "message": "Полученная сумма" + }, + "amountSent": { + "message": "Отправленная сумма" + }, + "andForListItems": { + "message": "$1, и $2", + "description": "$1 is the first item, $2 is the last item in a list of items. Used in Snap Install Warning modal." + }, + "andForTwoItems": { + "message": "$1 и $2", + "description": "$1 is the first item, $2 is the second item. Used in Snap Install Warning modal." + }, + "announcements": { + "message": "Объявления" + }, "appDescription": { "message": "Кошелек Ethereum в вашем браузере", "description": "The description of the application" @@ -402,6 +473,10 @@ "approveButtonText": { "message": "Одобрить" }, + "approveIncreaseAllowance": { + "message": "Увеличить лимит расходов $1", + "description": "The token symbol that is being approved" + }, "approveSpendingCap": { "message": "Одобрить лимит расходов в размере $1", "description": "The token symbol that is being approved" @@ -427,6 +502,10 @@ "message": "Одобрено $1", "description": "$1 is the approval date for a permission" }, + "approvedOnForAccounts": { + "message": "Одобрено $1 для $2", + "description": "$1 is the approval date for a permission. $2 is the AvatarGroup component displaying account images." + }, "areYouSure": { "message": "Вы уверены?" }, @@ -439,12 +518,21 @@ "attemptSendingAssets": { "message": "Попытка отправки активов напрямую из одной сети в другую может привести к необратимой потере активов. Следует использовать мост." }, + "attemptSendingAssetsWithPortfolio": { + "message": "Попытка отправки активов напрямую из одной сети в другую может привести к необратимой потере активов. Следует использовать мост, такой как $1" + }, + "attemptToCancelSwapForFree": { + "message": "Бесплатная попытка отменить своп" + }, "attemptingConnect": { "message": "Попытка подключения к блокчейну..." }, "attributions": { "message": "Атрибуции" }, + "auroraRpcDeprecationMessage": { + "message": "URL-адрес Infura RPC больше не поддерживает Aurora." + }, "authorizedPermissions": { "message": "Вы предоставили следующие разрешения" }, @@ -479,14 +567,17 @@ "backupApprovalNotice": { "message": "Создайте резервную копию своей секретной фразы для восстановления, чтобы обезопасить свой кошелек и средства." }, + "backupKeyringSnapReminder": { + "message": "Прежде чем удалять его, убедитесь, что у вас есть доступ к счетам, созданным с помощью этого Snap" + }, "backupNow": { "message": "Создать резервную копию сейчас" }, "backupUserData": { - "message": "Создайте резервную копию ваших данных" + "message": "Создайте резервную копию своих данных" }, "backupUserDataDescription": { - "message": "Вы можете создать резервную копию пользовательских настроек, содержащих настройки и адреса счетов, в файл JSON." + "message": "Вы можете создавать резервные копии таких данных, как ваши контакты и настройки." }, "balance": { "message": "Баланс" @@ -500,6 +591,30 @@ "basic": { "message": "Базовый" }, + "basicConfigurationBannerCTA": { + "message": "Включить базовый функционал" + }, + "basicConfigurationBannerTitle": { + "message": "Базовый функционал отключен" + }, + "basicConfigurationLabel": { + "message": "Базовый функционал" + }, + "basicConfigurationModalCheckbox": { + "message": "Я понимаю и хочу продолжить" + }, + "basicConfigurationModalDisclaimerOff": { + "message": "Это означает, что вы не сможете полностью оптимизировать свое время в MetaMask. Вам будут недоступны базовые функции (например, сведения о токенах, оптимальные настройки газа и т. д.)." + }, + "basicConfigurationModalDisclaimerOn": { + "message": "Чтобы оптимизировать свое время в MetaMask, вам необходимо включить эту функцию. Базовые функции (например, сведения о токенах, оптимальные настройки газа и другие) важны для работы с web3." + }, + "basicConfigurationModalHeadingOff": { + "message": "Выключить базовый функционал" + }, + "basicConfigurationModalHeadingOn": { + "message": "Включить базовый функционал" + }, "beCareful": { "message": "Будьте осторожны" }, @@ -571,6 +686,9 @@ "blockaidDescriptionTransferFarming": { "message": "Если вы одобрите этот запрос, третья сторона, известная мошенничеством, похитит все ваши активы." }, + "blockaidMessage": { + "message": "Сохранение конфиденциальности – никакие данные не передаются третьим сторонам. Доступно в Arbitrum, Avalanche, BNB Chain, Мейн-нете Ethereum, Linea, Optimism, Polygon, Base и Sepolia." + }, "blockaidTitleDeceptive": { "message": "Это запрос с целью обмана" }, @@ -586,6 +704,9 @@ "bridge": { "message": "Мост" }, + "bridgeDontSend": { + "message": "Мост, не отправлять" + }, "browserNotSupported": { "message": "Ваш браузер не поддерживается..." }, @@ -598,6 +719,9 @@ "busy": { "message": "Занят" }, + "buyAndSell": { + "message": "Купить и продать" + }, "buyAsset": { "message": "Купить $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -609,6 +733,10 @@ "buyNow": { "message": "Купить сейчас" }, + "buyToken": { + "message": "Купить $1", + "description": "$1 is the token symbol" + }, "bytes": { "message": "Байты" }, @@ -618,9 +746,6 @@ "cancel": { "message": "Отмена" }, - "cancelEdit": { - "message": "Отменить изменение" - }, "cancelPopoverTitle": { "message": "Отменить транзакцию" }, @@ -647,6 +772,9 @@ "chainIdExistsErrorMsg": { "message": "Этот ID блокчейна в настоящее время используется сетью $1." }, + "chainListReturnedDifferentTickerSymbol": { + "message": "Этот символ токена не соответствует введенному имени сети или идентификатору блокчейна. Многие популярные токены обозначаются похожими символами, которые мошенники могут использовать, чтобы обманом заставить вас отправить им взамен более ценный токен. Проверьте все, прежде чем продолжить." + }, "chooseYourNetwork": { "message": "Выберите свою сеть" }, @@ -682,9 +810,19 @@ "close": { "message": "Закрыть" }, + "closeExtension": { + "message": "Закрыть расширение" + }, + "closeWindowAnytime": { + "message": "Вы можете закрыть это окно в любое время." + }, "coingecko": { "message": "CoinGecko" }, + "comboNoOptions": { + "message": "Вариантов не найдено", + "description": "Default text shown in the combo field dropdown if no options." + }, "configureSnapPopupDescription": { "message": "Теперь вы покидаете MetaMask, чтобы настроить этот snap." }, @@ -703,12 +841,42 @@ "confirm": { "message": "Подтвердить" }, + "confirmAlertModalAcknowledge": { + "message": "Я подтвердил(-а) получение оповещений и все еще хочу продолжить" + }, + "confirmAlertModalDetails": { + "message": "Если вы войдете, третья сторона, которая, как известно, совершала мошеннические действия, может похитиь твсе ваши активы. Прежде чем продолжить, просмотрите оповещения." + }, + "confirmAlertModalTitle": { + "message": "Ваши активы могут быть в опасности" + }, + "confirmConnectCustodianRedirect": { + "message": "Мы перенаправим вас на $1 после нажатия кнопки «Продолжить»." + }, + "confirmConnectCustodianText": { + "message": "Чтобы подключить свои счета, войдите в свой счет $1 и нажмите кнопку «Подключиться к MMI»." + }, + "confirmConnectionTitle": { + "message": "Подтвердите подключение к $1" + }, "confirmPassword": { "message": "Подтвердить пароль" }, "confirmRecoveryPhrase": { "message": "Подтвердите секретную фразу для восстановления" }, + "confirmTitleDescContractInteractionTransaction": { + "message": "Подтверждайте эту транзакцию только в том случае, если вы полностью понимаете ее содержание и доверяете запрашивающему сайту." + }, + "confirmTitleDescSignature": { + "message": "Подтверждайте это сообщение только в том случае, если вы одобряете его содержание и доверяете запрашивающему сайту." + }, + "confirmTitleSignature": { + "message": "Запрос подписи" + }, + "confirmTitleTransaction": { + "message": "Запрос транзакции" + }, "confirmed": { "message": "Подтвержден(-а/о)" }, @@ -724,9 +892,15 @@ "connect": { "message": "Подключиться" }, + "connectAccount": { + "message": "Подключить счет" + }, "connectAccountOrCreate": { "message": "Подключите счет или создайте новый" }, + "connectAccounts": { + "message": "Подключить счета" + }, "connectCustodialAccountMenu": { "message": "Подключить депозитарный счет" }, @@ -736,36 +910,25 @@ "connectCustodialAccountTitle": { "message": "Депозитарные счета" }, + "connectCustodianAccounts": { + "message": "Подключить счета $1" + }, "connectManually": { "message": "Подключиться к текущему сайту вручную" }, + "connectMoreAccounts": { + "message": "Подключить еще счета" + }, "connectSnap": { "message": "Подключиться к $1", "description": "$1 is the snap for which a connection is being requested." }, - "connectTo": { - "message": "Подключиться к $1", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "Подключиться ко всем вашим $1", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "счетам", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "Подключиться к $1", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1 счетам", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "Подключиться с помощью MetaMask" }, + "connectedAccounts": { + "message": "Подключенные счета" + }, "connectedAccountsDescriptionPlural": { "message": "К этому сайту подключено $1 ваших счета(-ов).", "description": "$1 is the number of accounts" @@ -776,6 +939,13 @@ "connectedAccountsEmptyDescription": { "message": "MetaMask не подключен к этому сайту. Чтобы подключиться к сайту web3, найдите и нажмите кнопку подключения." }, + "connectedAccountsListTooltip": { + "message": "$1 может видеть баланс счета, адрес, активность и предлагать транзакции для одобрения для подключенных счетов.", + "description": "$1 is the origin name" + }, + "connectedAccountsToast": { + "message": "Подключенные счета обновлены" + }, "connectedSites": { "message": "Подключенные сайты" }, @@ -787,12 +957,21 @@ "message": "$1 не подключен ни к каким сайтам.", "description": "$1 is the account name" }, + "connectedSnapAndNoAccountDescription": { + "message": "MetaMask подключен к этому сайту, но счета пока не подключены" + }, + "connectedWith": { + "message": "Подключен(-а) к" + }, "connecting": { "message": "Подключение..." }, "connectingTo": { "message": "Подключение к $1" }, + "connectingToDeprecatedNetwork": { + "message": "«$1» постепенно выводится из эксплуатации и может не работать. Попробуйте другую сеть." + }, "connectingToGoerli": { "message": "Подключение к тестовой сети Goerli..." }, @@ -802,6 +981,9 @@ "connectingToLineaMainnet": { "message": "Подключение к Мейн-нету Linea" }, + "connectingToLineaSepolia": { + "message": "Подключение к тестовой сети Linea Sepolia..." + }, "connectingToMainnet": { "message": "Подключение к Мейн-нету Ethereum..." }, @@ -831,6 +1013,12 @@ "continue": { "message": "Продолжить" }, + "continueMmiOnboarding": { + "message": "Продолжить регистрацию в MetaMask Institutional" + }, + "continueToWallet": { + "message": "Перейти в кошелек" + }, "contract": { "message": "Контракт" }, @@ -882,6 +1070,9 @@ "copyAddress": { "message": "Скопировать адрес в буфер обмена" }, + "copyPrivateKey": { + "message": "Копировать закрытый ключ" + }, "copyRawTransactionData": { "message": "Копировать необработанные данные транзакции" }, @@ -900,6 +1091,15 @@ "createPassword": { "message": "Создать пароль" }, + "createSnapAccountDescription": { + "message": "$1 хочет добавить новый счет в MetaMask." + }, + "createSnapAccountTitle": { + "message": "Создать счет" + }, + "crossChainSwapsLink": { + "message": "Меняйте сети с помощью MetaMask Portfolio" + }, "cryptoCompare": { "message": "CryptoCompare" }, @@ -950,10 +1150,16 @@ "message": "Депозитарий" }, "custodianAccountAddedDesc": { - "message": "Теперь вы можете использовать свои депозитарные счета в MetaMask Institutional." + "message": "Теперь вы можете использовать свои счета в MetaMask Institutional." }, "custodianAccountAddedTitle": { - "message": "Добавлены выбранные депозитарные счета." + "message": "Добавлены $1 выбранных счета(-ов)." + }, + "custodianQRCodeScan": { + "message": "Отсканируйте QR-код с помощью мобильного приложения $1" + }, + "custodianQRCodeScanDescription": { + "message": "Или войдите в свой счет $1 и нажмите кнопку «Подключиться к MMI»" }, "custodianReplaceRefreshTokenChangedFailed": { "message": "Перейдите к $1 и нажмите кнопку «Подключиться к MMI» в их пользовательском интерфейсе, чтобы снова подключить свои счета к MMI." @@ -1017,7 +1223,7 @@ "message": "Определение токена пока недоступно в этой сети. Импортируйте токен вручную и убедитесь, что вы ему доверяете. Подробнее о $1" }, "customTokenWarningInTokenDetectionNetwork": { - "message": "Прежде чем импортировать токен вручную, убедитесь, что вы ему доверяете. Подробнее о $1" + "message": "Кто угодно может создать токен, в том числе поддельные версии существующих токенов. Узнайте подробнее о $1" }, "customTokenWarningInTokenDetectionNetworkWithTDOFF": { "message": "Перед импортом убедитесь, что вы доверяете токену. Узнайте, как избежать $1. Вы также можете включить определение токена $2." @@ -1025,6 +1231,12 @@ "customerSupport": { "message": "поддержка клиентов" }, + "customizeYourNotifications": { + "message": "Настройте свои уведомления" + }, + "customizeYourNotificationsText": { + "message": "Включите типы уведомлений, которые вы хотите получать:" + }, "dappRequestedSpendingCap": { "message": "Сайт запросил лимит расходов" }, @@ -1108,6 +1320,18 @@ "deposit": { "message": "Депозит" }, + "deprecatedGoerliNtwrkMsg": { + "message": "Из-за обновлений системы Ethereum тестовая сеть Goerli скоро будет закрыта." + }, + "deprecatedNetwork": { + "message": "Эта сеть устарела" + }, + "deprecatedNetworkButtonMsg": { + "message": "Понятно" + }, + "deprecatedNetworkDescription": { + "message": "Сеть, к которой вы пытаетесь подключиться, больше не поддерживается Metamask. $1" + }, "description": { "message": "Описание" }, @@ -1115,110 +1339,20 @@ "message": "Описание из $1", "description": "$1 represents the name of the snap" }, - "desktopApp": { - "message": "Приложение для ПК" - }, - "desktopConnectionCriticalErrorDescription": { - "message": "Эта ошибка может быть периодической, поэтому попробуйте перезапустить расширение или отключить MetaMask Desktop." - }, - "desktopConnectionCriticalErrorTitle": { - "message": "У MetaMask возникли проблемы с запуском" - }, - "desktopConnectionLostErrorDescription": { - "message": "Убедитесь, что у вас имеется и запущено приложение для ПК, или отключите MetaMask Desktop." - }, - "desktopConnectionLostErrorTitle": { - "message": "Соединение с MetaMask Desktop потеряно" - }, - "desktopDisableButton": { - "message": "Отключить приложение для ПК" - }, - "desktopDisableErrorCTA": { - "message": "Отключить MetaMask Desktop" - }, - "desktopEnableButton": { - "message": "Включить приложение для ПК" - }, - "desktopEnableButtonDescription": { - "message": "Нажмите, чтобы запустить все фоновые процессы в приложении для ПК." - }, - "desktopErrorNavigateSettingsCTA": { - "message": "Вернуться на страницу «Настройки»" - }, - "desktopErrorRestartMMCTA": { - "message": "Перезапустить MetaMask" - }, - "desktopNotFoundErrorCTA": { - "message": "Скачать MetaMask Desktop" - }, - "desktopNotFoundErrorDescription1": { - "message": "Убедитесь, что у вас имеется и запущено приложение для ПК." - }, - "desktopNotFoundErrorDescription2": { - "message": "Если у вас не установлено приложение для ПК, скачайте его с веб-сайта MetaMask." - }, - "desktopNotFoundErrorTitle": { - "message": "MetaMask Desktop не найдено" - }, - "desktopOpenOrDownloadCTA": { - "message": "Открыть MetaMask Desktop" - }, - "desktopOutdatedErrorCTA": { - "message": "Обновить MetaMask Desktop" - }, - "desktopOutdatedErrorDescription": { - "message": "Ваше приложение MetaMask Desktop требует апгрейда." - }, - "desktopOutdatedErrorTitle": { - "message": "MetaMask Desktop устарело" - }, - "desktopOutdatedExtensionErrorCTA": { - "message": "Обновить расширение MetaMask" - }, - "desktopOutdatedExtensionErrorDescription": { - "message": "Ваше расширение MetaMask требует апгрейда." - }, - "desktopOutdatedExtensionErrorTitle": { - "message": "Расширение MetaMask устарело" - }, - "desktopPageDescription": { - "message": "Если сопряжение пройдет успешно, расширение перезапустится, и вам потребуется повторно ввести свой пароль." - }, - "desktopPageSubTitle": { - "message": "Откройте MetaMask Desktop и введите этот код" - }, - "desktopPageTitle": { - "message": "Установить сопряжение с Desktop" - }, - "desktopPairedWarningDeepLink": { - "message": "Перейдите в Настройки в MetaMask Desktop" - }, - "desktopPairedWarningDescription": { - "message": "Если вы хотите начать новое сопряжение, отключите текущее соединение." - }, - "desktopPairedWarningTitle": { - "message": "MM Desktop уже сопряжено" - }, - "desktopPairingExpireMessage": { - "message": "Срок кода истекает через $1 секунд(-ы)" - }, - "desktopRouteNotFoundErrorDescription": { - "message": "desktopRouteNotFoundErrorDescription" - }, - "desktopRouteNotFoundErrorTitle": { - "message": "desktopRouteNotFoundErrorTitle" + "details": { + "message": "Подробности" }, - "desktopUnexpectedErrorCTA": { - "message": "Назад на главную страницу MetaMask" + "developerOptions": { + "message": "Параметры разработчика" }, - "desktopUnexpectedErrorDescription": { - "message": "Проверьте свое MetaMask Desktop, чтобы восстановить соединение" + "developerOptionsResetStatesAnnouncementsDescription": { + "message": "Сбрасывает логическое значение isShown в значение false для всех объявлений. Объявления — это уведомления, отображаемые во всплывающем модальном окне «Что нового»." }, - "desktopUnexpectedErrorTitle": { - "message": "Что-то пошло не так..." + "developerOptionsResetStatesOnboarding": { + "message": "Сбрасывает различные состояния, связанные с регистрацией, и перенаправляет на страницу регистрации «Защитите свой кошелек»." }, - "details": { - "message": "Подробности" + "developerOptionsServiceWorkerKeepAlive": { + "message": "В результате отметка времени постоянно сохраняется в session.storage" }, "disabledGasOptionToolTipMessage": { "message": "$1 отключена, поскольку не соответствует минимальному увеличению на 10% от первоначальной платы за газ.", @@ -1233,12 +1367,38 @@ "disconnectAllAccountsConfirmationDescription": { "message": "Уверены, что хотите отключить? Вы можете потерять доступ к функциям сайта." }, + "disconnectAllAccountsText": { + "message": "счета" + }, + "disconnectAllSnapsText": { + "message": "Snaps" + }, + "disconnectAllText": { + "message": "Если вы отключите свои $1 от $2, вам придется повторно подключиться, чтобы использовать их снова.", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`, $2 represents the website hostname" + }, + "disconnectAllTitle": { + "message": "Отключить все $1", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`" + }, "disconnectPrompt": { "message": "Отключить $1" }, "disconnectThisAccount": { "message": "Отключить этот счет" }, + "disconnectedAllAccountsToast": { + "message": "Все счета отключены от $1", + "description": "$1 is name of the dapp`" + }, + "disconnectedSingleAccountToast": { + "message": "$1 отключен от $2", + "description": "$1 is name of the name and $2 represents the dapp name`" + }, + "discoverSnaps": { + "message": "Откройте для себя Snaps", + "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." + }, "dismiss": { "message": "Отклонить" }, @@ -1248,9 +1408,21 @@ "dismissReminderField": { "message": "Отклонить напоминание о необходимости создать резервную копию секретной фразы для восстановления" }, + "displayNftMedia": { + "message": "Показать носитель NFT" + }, + "displayNftMediaDescription": { + "message": "Отображение носителя и данных NFT раскрывает ваш IP-адрес для OpenSea или других третьих сторон. Это может позволить злоумышленникам связать ваш IP-адрес с вашим адресом Ethereum. Автоопределение NFT зависит от этого параметра и будет недоступно, если он отключен." + }, + "doNotShare": { + "message": "Не сообщайте ее никому" + }, "domain": { "message": "Домен" }, + "domainNotSupportedOnNetwork": { + "message": "Сеть не поддерживает поиск домена" + }, "done": { "message": "Выполнено" }, @@ -1269,6 +1441,9 @@ "downloadStateLogs": { "message": "Скачать журналы состояния" }, + "dragAndDropBanner": { + "message": "Вы можете перетаскивать сети, чтобы изменять их порядок. " + }, "dropped": { "message": "Отменено" }, @@ -1367,6 +1542,9 @@ "editSpeedUpEditGasFeeModalTitle": { "message": "Изменить плату за газ за ускорение" }, + "enable": { + "message": "Включить" + }, "enableAutoDetect": { "message": " Включить автоопределение" }, @@ -1397,6 +1575,18 @@ "enhancedTokenDetectionAlertMessage": { "message": "Улучшенное определение токенов в настоящее время доступно на $1. $2" }, + "ensDomainsSettingDescriptionIntroduction": { + "message": "MetaMask позволяет вам видеть домены ENS прямо в адресной строке вашего браузера. Вот как это работает:" + }, + "ensDomainsSettingDescriptionOutroduction": { + "message": "Имейте в виду, что использование этой функции открывает доступ к вашему IP-адресу сторонним сервисам IPFS." + }, + "ensDomainsSettingDescriptionPart1": { + "message": "MetaMask сверяется с контрактом ENS Ethereum, чтобы найти код, связанный с именем ENS." + }, + "ensDomainsSettingDescriptionPart2": { + "message": "Если код ссылается на IPFS, вы можете увидеть связанный с ним контент (обычно веб-сайт)." + }, "ensDomainsSettingTitle": { "message": "Показать домены ENS в адресной строке" }, @@ -1438,6 +1628,9 @@ "message": "Сведения об ошибке", "description": "Title for collapsible section that displays error details for debugging purposes" }, + "errorGettingSafeChainList": { + "message": "Ошибка при получении списка безопасных блокчейнов. Продолжайте с осторожностью." + }, "errorMessage": { "message": "Сообщение: $1", "description": "Displayed error message for debugging purposes. $1 is the error message" @@ -1469,6 +1662,9 @@ "message": "Ошибка с $1", "description": "$1 represents the name of the snap" }, + "estimatedFee": { + "message": "Примерная комиссия" + }, "ethGasPriceFetchWarning": { "message": "Указана резервная цена газа, поскольку основной сервис определения цены газа сейчас недоступен." }, @@ -1495,12 +1691,24 @@ "message": "Экспериментальные" }, "extendWalletWithSnaps": { - "message": "Настройте кошелек под себя.", + "message": "Изучите Snaps, созданные сообществом, чтобы персонализировать работу с web3", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "extensionInsallCompleteDescription": { + "message": "Вернитесь к настройке продукта MetaMask Institutional, чтобы подключить свои депозитарные или само-дерпозитарные счета." + }, + "extensionInsallCompleteTitle": { + "message": "Установка расширения завершена" + }, "externalExtension": { "message": "Внешнее расширение" }, + "externalNameSourcesSetting": { + "message": "Предлагаемые псевдонимы" + }, + "externalNameSourcesSettingDescription": { + "message": "Мы будем получать предлагаемые псевдонимы для адресов, с которыми вы взаимодействуете, из сторонних источников, таких как Etherscan, Infura и Lens Protocol. Эти источники могут видеть эти адреса и ваш IP-адрес. Адрес вашего счета не будет доступен третьим сторонам." + }, "failed": { "message": "Не удалось" }, @@ -1519,6 +1727,9 @@ "feeAssociatedRequest": { "message": "За выполнение этого запроса взимается комиссия." }, + "feeDetails": { + "message": "Сведения о комиссии" + }, "fiat": { "message": "Фиатная", "description": "Exchange type" @@ -1551,6 +1762,9 @@ "message": "Я принимаю риски", "description": "this text is shown on a button, which the user presses to confirm they understand the risks of using Flask" }, + "floatAmountToken": { + "message": "Сумма токена должна быть целым числом" + }, "followUsOnTwitter": { "message": "Подпишитесь на нас в Twitter" }, @@ -1573,6 +1787,9 @@ "fromTokenLists": { "message": "Из списков токенов: $1" }, + "function": { + "message": "Функция: $1" + }, "functionApprove": { "message": "Функция: Одобрить" }, @@ -1582,6 +1799,13 @@ "functionType": { "message": "Тип функции" }, + "fundYourWallet": { + "message": "Пополните свой кошелек" + }, + "fundYourWalletDescription": { + "message": "Начните с добавления $1 в свой кошелек.", + "description": "$1 is the token symbol" + }, "gas": { "message": "Газ" }, @@ -1592,6 +1816,9 @@ "message": "Эта плата за газ была предложена $1. Ее переопредление может вызвать проблемы с вашей транзакцией. При наличии вопросов обратитесь к $1.", "description": "$1 represents the Dapp's origin" }, + "gasIsETH": { + "message": "Газ стоит $1 " + }, "gasLimit": { "message": "Лимит газа" }, @@ -1636,6 +1863,9 @@ "message": "$1 ч", "description": "$1 represents a number of hours" }, + "gasTimingLow": { + "message": "Медленная" + }, "gasTimingMinutesShort": { "message": "$1 мин.", "description": "$1 represents a number of minutes" @@ -1650,15 +1880,29 @@ "general": { "message": "Общие" }, - "globalTitle": { - "message": "Глобальное меню" + "generalCameraError": { + "message": "Нам не удалось получить доступ к вашей камере. Пожалуйста, попробуйте еще раз." + }, + "generalCameraErrorTitle": { + "message": "Что-то пошло не так...." + }, + "genericExplorerView": { + "message": "Посмотреть счет на $1" }, - "globalTourDescription": { - "message": "Просматривайте свой Portfolio, подключенные сайты, настройки и многое другое" + "getStartedWithNFTs": { + "message": "Получите $1 для покупки NFT", + "description": "$1 is the token symbol" + }, + "getStartedWithNFTsDescription": { + "message": "Начните использовать NFT, добавив $1 в свой кошелек.", + "description": "$1 is the token symbol" }, "goBack": { "message": "Назад" }, + "goToSite": { + "message": "Перейти на сайт" + }, "goerli": { "message": "Тестовая сеть Goerli" }, @@ -1700,15 +1944,24 @@ "hexData": { "message": "Шестнадцатеричные данные" }, + "hiddenAccounts": { + "message": "Скрыть счета" + }, "hide": { "message": "Скрыть" }, + "hideAccount": { + "message": "Скрыть счет" + }, "hideFullTransactionDetails": { "message": "Скрыть полную информацию о транзакции" }, "hideSeedPhrase": { "message": "Скрыть сид-фразу" }, + "hideSentitiveInfo": { + "message": "Скрыть конфиденциальную информацию" + }, "hideToken": { "message": "Скрыть токен" }, @@ -1790,6 +2043,9 @@ "ignoreTokenWarning": { "message": "Если вы скроете токены, они не будут отображаться в вашем кошельке. Однако вы все равно можете добавить их, выполнив поиск по ним." }, + "imToken": { + "message": "imToken" + }, "import": { "message": "Импорт", "description": "Button to import an account from a selected file" @@ -1848,6 +2104,9 @@ "importTokensCamelCase": { "message": "Импорт токенов" }, + "importTokensError": { + "message": "Нам не удалось импортировать токены. Повторите попытку позже." + }, "importWithCount": { "message": "Импортировать $1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -1866,6 +2125,9 @@ "initialTransactionConfirmed": { "message": "Ваша первоначальная транзакция подтверждена сетью. Нажмите ОК, чтобы вернуться." }, + "inlineAlert": { + "message": "Оповещение" + }, "inputLogicEmptyState": { "message": "Введите только ту сумму, которую третья сторона, по вашему мнению, может тратить сейчас или в будущем. Вы всегда можете увеличить лимит расходов позже." }, @@ -1876,6 +2138,27 @@ "inputLogicHigherNumber": { "message": "Это позволяет третьей стороне расходовать весь ваш баланс токенов до тех пор, пока не будет достигнут лимит расходов или вы не отмените его. Если вы не хотите такого развития событий, подумайте о снижении лимита расходов." }, + "insightWarning": { + "message": "предупреждение" + }, + "insightWarningCheckboxMessage": { + "message": "$1 запрос $2", + "description": "$1 is the action i.e. sign, confirm. $2 is the origin making the request." + }, + "insightWarningContentPlural": { + "message": "Просмотрите $1 предупреждения(-ий) перед $2. После того как вы сделаете это, $3 нельзя будет отменить.", + "description": "$1 the 'insightWarnings' message (2 warnings) representing warnings, $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningContentSingular": { + "message": "Просмотрите $1 перед $2. После того как вы сделаете это, $3 нельзя будет отменить.", + "description": "$1 is the 'insightWarning' message (1 warning), $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningHeader": { + "message": "Этот запрос может быть рискованным" + }, + "insightWarnings": { + "message": "предупреждения" + }, "insightsFromSnap": { "message": "Аналитика от $1", "description": "$1 represents the name of the snap" @@ -1883,9 +2166,18 @@ "install": { "message": "Установите," }, + "installExtension": { + "message": "Установить расширение" + }, + "installExtensionDescription": { + "message": "Соответствующая институциональным требованиям версия ведущего в мире web3-кошелька MetaMask." + }, "installOrigin": { "message": "Источник установки" }, + "installRequest": { + "message": "Добавить в MetaMask" + }, "installedOn": { "message": "Установлено на $1", "description": "$1 is the date when the snap has been installed" @@ -1914,6 +2206,12 @@ "insufficientTokens": { "message": "Недостаточно токенов." }, + "interactingWith": { + "message": "Взаимодействие с" + }, + "interactingWithTransactionDescription": { + "message": "Это контракт, с которым вы взаимодействуете. Защитите себя от мошенников, подтвердив данные" + }, "invalidAddress": { "message": "Недействительный адрес" }, @@ -1986,6 +2284,9 @@ "ipfsToggleModalSettings": { "message": "Настройки > Безопасность и конфиденциальность" }, + "isSigningOrSubmitting": { + "message": "Предыдущая транзакция все еще подписывается или отправляется" + }, "jazzAndBlockies": { "message": "Jazzicons и Blockies — это два разных стиля уникальных значков, которые помогут вам с первого взгляда идентифицировать свой счет." }, @@ -1999,6 +2300,24 @@ "message": "JSON-файл", "description": "format for importing an account" }, + "keyringAccountName": { + "message": "Название счета" + }, + "keyringAccountPublicAddress": { + "message": "Публичный адрес" + }, + "keyringSnapRemovalResult1": { + "message": "$1 $2 удален", + "description": "Displays the result after removal of a keyring snap. $1 is the snap name, $2 is whether it is successful or not" + }, + "keyringSnapRemovalResultNotSuccessful": { + "message": "не", + "description": "Displays the `not` word in $2." + }, + "keyringSnapRemoveConfirmation": { + "message": "Введите $1, чтобы подтвердить, что вы хотите удалить этот Snap:", + "description": "Asks user to input the name nap prior to deleting the snap. $1 is the snap name" + }, "keystone": { "message": "Keystone" }, @@ -2017,9 +2336,15 @@ "lastSold": { "message": "Последняя продажа" }, + "lavaDomeCopyWarning": { + "message": "В целях вашей безопасности выбор этого текста в данный момент недоступен." + }, "layer1Fees": { "message": "Комиссии 1-го уровня" }, + "layer2Fees": { + "message": "Комиссии 2-го уровня" + }, "learnCancelSpeeedup": { "message": "Узнайте подробнее, как $1", "description": "$1 is link to cancel or speed up transactions" @@ -2037,9 +2362,21 @@ "learnMoreUpperCase": { "message": "Подробнее" }, + "learnMoreUpperCaseWithDot": { + "message": "Узнайте подробнее." + }, "learnScamRisk": { "message": "мошенничество и угрозы безопасности." }, + "learnToBridge": { + "message": "Научитесь создавать мост для" + }, + "leaveMetaMask": { + "message": "Выйти из MetaMask?" + }, + "leaveMetaMaskDesc": { + "message": "Вы собираетесь посетить сайт за пределами MetaMask. Прежде чем продолжить, перепроверьте URL-адрес." + }, "ledgerAccountRestriction": { "message": "Вам необходимо использовать свой последний счет, прежде чем вы сможете добавить новый." }, @@ -2058,6 +2395,18 @@ "ledgerDeviceOpenFailureMessage": { "message": "Не удалось открыть Ledger. Он может быть подключен к другой программе. Закройте Ledger Live или другие приложения, подключенные к Ledger, и снова попробуйте подключиться." }, + "ledgerErrorConnectionIssue": { + "message": "Переподключите свой Ledger, откройте приложение ETH и повторите попытку." + }, + "ledgerErrorDevicedLocked": { + "message": "Ваш Ledger заблокирован. Разблокируйте его и повторите попытку." + }, + "ledgerErrorEthAppNotOpen": { + "message": "Чтобы решить проблему, откройте приложение ETH на своем устройстве и повторите попытку." + }, + "ledgerErrorTransactionDataNotPadded": { + "message": "Входные данные транзакции Ethereum недостаточно подробно заполнены." + }, "ledgerLiveApp": { "message": "приложение Ledger Live" }, @@ -2077,6 +2426,9 @@ "lightTheme": { "message": "Светлая" }, + "likeToImportToken": { + "message": "Хотите импортировать этот токен?" + }, "likeToImportTokens": { "message": "Вы хотели бы импортировать эти токены?" }, @@ -2086,6 +2438,9 @@ "lineaMainnet": { "message": "Мейн-нет Linea" }, + "lineaSepolia": { + "message": "Тестовая сеть Linea Sepolia" + }, "link": { "message": "Ссылка" }, @@ -2098,8 +2453,11 @@ "loading": { "message": "Загрузка..." }, - "loadingNFTs": { - "message": "Загрузка NFT..." + "loadingScreenHardwareWalletMessage": { + "message": "Завершите транзакцию в аппаратном кошельке." + }, + "loadingScreenSnapMessage": { + "message": "Завершите транзакцию в Snap." }, "loadingTokens": { "message": "Загрузка токенов..." @@ -2146,6 +2504,9 @@ "message": "Убедитесь, что никто не смотрит", "description": "Warning to users to be care while creating and saving their new Secret Recovery Phrase" }, + "manageInSettings": { + "message": "Управляйте в настройках" + }, "max": { "message": "Макс." }, @@ -2180,15 +2541,34 @@ "metaMaskConnectStatusParagraphTwo": { "message": "Кнопка статуса подключения показывает, подключен ли посещаемый вами веб-сайт, к выбранному вами в настоящее время счету." }, + "metadataModalSourceTooltip": { + "message": "$1 размещается на npm, а $2 — это уникальный идентификатор Snap.", + "description": "$1 is the snap name and $2 is the snap NPM id." + }, "metamaskInstitutionalVersion": { "message": "Версия MetaMask Institutional" }, + "metamaskNotificationsAreOff": { + "message": "Уведомления кошелька в настоящее время неактивны." + }, + "metamaskPortfolio": { + "message": "MetaMask Portfolio." + }, "metamaskSwapsOfflineDescription": { "message": "Сервис свопов MetaMask на техобслуживании. Зайдите позже." }, "metamaskVersion": { "message": "Версия MetaMask" }, + "methodData": { + "message": "Метод" + }, + "methodDataTransactionDescription": { + "message": "Это конкретные действия, которые будут предприняты. Эти данные могут быть подделаны, поэтому убедитесь, что вы доверяете сайту на другом конце." + }, + "methodNotSupported": { + "message": "Не поддерживается с этим счётом." + }, "metrics": { "message": "Показатели" }, @@ -2224,11 +2604,17 @@ "mmiBuiltAroundTheWorld": { "message": "MetaMask Institutional разработан и создан с учетом потребностей в разных частях мира." }, + "mmiNewNFTDetectedInNFTsTabMessage": { + "message": "Разрешите MetaMask Institutional автоматически определять и отображать NFT в вашем кошельке." + }, + "mmiPasswordSetupDetails": { + "message": "Этот пароль разблокирует только ваше расширение MetaMask Institutional." + }, "more": { "message": "больше" }, "multipleSnapConnectionWarning": { - "message": "$1 хочет подключиться с помощью Snaps $2. Продолжайте, только если вы доверяете этому веб-сайту.", + "message": "$1 хочет использовать $2 Snaps", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." }, "mustSelectOne": { @@ -2237,10 +2623,80 @@ "name": { "message": "Имя" }, + "nameAddressLabel": { + "message": "Адрес", + "description": "Label above address field in name component modal." + }, + "nameInstructionsNew": { + "message": "Если вы знаете этот адрес, присвойте ему псевдоним, чтобы узнавать его в будущем.", + "description": "Instruction text in name component modal when value is not recognised." + }, + "nameInstructionsRecognized": { + "message": "У этого адреса есть псевдоним по умолчанию, но вы можете изменить его или рассмотреть другие рекомендации.", + "description": "Instruction text in name component modal when value is recognized but not saved." + }, + "nameInstructionsSaved": { + "message": "Вы уже добавили псевдоним для этого адреса ранее. Вы можете редактировать или просматривать другие рекомендованные псевдонимы.", + "description": "Instruction text in name component modal when value is saved." + }, + "nameLabel": { + "message": "Ник", + "description": "Label above name input field in name component modal." + }, + "nameModalMaybeProposedName": { + "message": "Может быть: $1", + "description": "$1 is the proposed name" + }, + "nameModalTitleNew": { + "message": "Неизвестный адрес", + "description": "Title of the modal created by the name component when value is not recognised." + }, + "nameModalTitleRecognized": { + "message": "Распознанный адрес", + "description": "Title of the modal created by the name component when value is recognized but not saved." + }, + "nameModalTitleSaved": { + "message": "Сохраненный адрес", + "description": "Title of the modal created by the name component when value is saved." + }, + "nameProviderProposedBy": { + "message": "Предложено $1", + "description": "$1 is the name of the provider" + }, + "nameProvider_ens": { + "message": "Служба имен Ethereum (ENS)" + }, + "nameProvider_etherscan": { + "message": "Etherscan" + }, + "nameProvider_lens": { + "message": "Протокол Lens" + }, + "nameProvider_token": { + "message": "MetaMask" + }, + "nameSetPlaceholder": { + "message": "Выберите псевдоним...", + "description": "Placeholder text for name input field in name component modal." + }, + "nativePermissionRequestDescription": { + "message": "Вы хотите, чтобы этот сайт делал следующее?", + "description": "Description below header used on Permission Connect screen for native permissions." + }, "nativeToken": { "message": "Нативный токен этой сети — $1. Этот токен используется для внесения платы за газ.", "description": "$1 represents the name of the native token on the current network" }, + "nativeTokenScamWarningConversion": { + "message": "Изменить сведения о сети" + }, + "nativeTokenScamWarningDescription": { + "message": "Эта сеть не соответствует ID или имени связанного с ней блокчейна. Многие популярные токены используют название $1, что делает его объектом мошенничества. Мошенники могут обманом заставить вас отправить им взамен более ценную валюту. Проверьте все, прежде чем продолжить.", + "description": "$1 represents the currency name" + }, + "nativeTokenScamWarningTitle": { + "message": "Это потенциальное мошенничество" + }, "needHelp": { "message": "Нужна помощь? Обратитесь в $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -2261,6 +2717,9 @@ "negativeETH": { "message": "Невозможно отправить отрицательную сумму ETH." }, + "negativeOrZeroAmountToken": { + "message": "Невозможно отправить отрицательную или нулевую сумму актива." + }, "network": { "message": "Сеть:" }, @@ -2291,6 +2750,9 @@ "networkNameBSC": { "message": "BSC" }, + "networkNameBase": { + "message": "Base" + }, "networkNameDefinition": { "message": "Имя, связанное с этой сетью." }, @@ -2300,12 +2762,21 @@ "networkNameGoerli": { "message": "Goerli" }, + "networkNameLinea": { + "message": "Linea" + }, + "networkNameOpMainnet": { + "message": "Мейн-нет OP" + }, "networkNamePolygon": { "message": "Polygon" }, "networkNameTestnet": { "message": "Тестнет" }, + "networkNameZkSyncEra": { + "message": "zkSync Era" + }, "networkProvider": { "message": "Поставщик услуг сети" }, @@ -2358,6 +2829,19 @@ "newContract": { "message": "Новый контракт" }, + "newNFTDetectedInImportNFTsMessageStrongText": { + "message": "Настройки > Безопасность и конфиденциальность" + }, + "newNFTDetectedInImportNFTsMsg": { + "message": "Чтобы использовать OpenSea для просмотра своих NFT, включите «Показать носитель NFT» в $1.", + "description": "$1 is used for newNFTDetectedInImportNFTsMessageStrongText" + }, + "newNFTDetectedInNFTsTabMessage": { + "message": "Разрешите MetaMask автоматически определять и отображать NFT в вашем кошельке." + }, + "newNFTsAutodetected": { + "message": "Автоопределение NFT" + }, "newNetworkAdded": { "message": "«$1» успешно добавлен!" }, @@ -2367,6 +2851,12 @@ "newPassword": { "message": "Новый пароль (мин. 8 знаков)" }, + "newPrivacyPolicyActionButton": { + "message": "Подробнее" + }, + "newPrivacyPolicyTitle": { + "message": "Мы обновили нашу политику конфиденциальности" + }, "newTokensImportedMessage": { "message": "Вы успешно импортировали $1.", "description": "$1 is the string of symbols of all the tokens imported" @@ -2388,6 +2878,9 @@ "message": "Этот токен является NFT. Добавьте на $1", "description": "$1 is a clickable link with text defined by the 'importNFTPage' key" }, + "nftAlreadyAdded": { + "message": "NFT уже добавлен." + }, "nftDisclaimer": { "message": "Отказ от ответственности: MetaMask извлекает медиафайл из исходного URL. Этот URL иногда изменяется торговой площадкой, на которой был выполнен минтинг NFT." }, @@ -2423,12 +2916,21 @@ "noAddressForName": { "message": "Для этого имени не задан адрес." }, + "noConnectedAccountDescription": { + "message": "Для продолжения выберите счет, который вы хотите использовать на этом сайте." + }, + "noConnectedAccountTitle": { + "message": "MetaMask не подключен к этому сайту" + }, "noConversionDateAvailable": { "message": "Дата обмена валюты недоступна" }, "noConversionRateAvailable": { "message": "Нет доступного обменного курса" }, + "noDomainResolution": { + "message": "Разрешение для домена не предоставлено." + }, "noNFTs": { "message": "Пока нет NFT" }, @@ -2447,6 +2949,9 @@ "noWebcamFoundTitle": { "message": "Веб-камера не найдена" }, + "nonCustodialAccounts": { + "message": "MetaMask Institutional позволяет вам использовать некастодиальные счета, если вы планируете использовать эти счета для резервного копирования секретной фразы для восстановления." + }, "nonce": { "message": "Одноразовый номер" }, @@ -2477,6 +2982,111 @@ "notePlaceholder": { "message": "Утверждающее лицо увидит это примечание при одобрении транзакции у депозитария." }, + "notificationDetail": { + "message": "Подробности" + }, + "notificationDetailBaseFee": { + "message": "Базовая комиссия (Гвей)" + }, + "notificationDetailGasLimit": { + "message": "Лимит газа (единицы)" + }, + "notificationDetailGasUsed": { + "message": "Использовано газа (единицы)" + }, + "notificationDetailMaxFee": { + "message": "Макс. комиссия на газ" + }, + "notificationDetailNetwork": { + "message": "Сеть" + }, + "notificationDetailNetworkFee": { + "message": "Комиссия сети" + }, + "notificationDetailPriorityFee": { + "message": "Плата за приоритет (Гвей)" + }, + "notificationItemCheckBlockExplorer": { + "message": "Проверить в BlockExplorer" + }, + "notificationItemCollection": { + "message": "Коллекция" + }, + "notificationItemConfirmed": { + "message": "Подтверждено" + }, + "notificationItemError": { + "message": "Сейчас невозможно получить данные о комиссиях" + }, + "notificationItemFrom": { + "message": "От" + }, + "notificationItemLidoStakeReadyToBeWithdrawn": { + "message": "Вывод выполнен" + }, + "notificationItemLidoStakeReadyToBeWithdrawnMessage": { + "message": "Теперь вы можете вывести свои $1, не используемые в стейкинге" + }, + "notificationItemLidoWithdrawalRequestedMessage": { + "message": "Ваш запрос на отмену стейкинга $1 отправлен" + }, + "notificationItemNFTReceivedFrom": { + "message": "Получил(-а) NFT от" + }, + "notificationItemNFTSentTo": { + "message": "Отправил(-а) NFT в адрес" + }, + "notificationItemNetwork": { + "message": "Сеть" + }, + "notificationItemRate": { + "message": "Курс (включая комиссию)" + }, + "notificationItemReceived": { + "message": "Получено" + }, + "notificationItemReceivedFrom": { + "message": "Получено от" + }, + "notificationItemSent": { + "message": "Отправлено" + }, + "notificationItemSentTo": { + "message": "Отправлено в адрес" + }, + "notificationItemStakeCompleted": { + "message": "Стейкинг завершен" + }, + "notificationItemStaked": { + "message": "В стейкинге" + }, + "notificationItemStakingProvider": { + "message": "Провайдер стейкинга" + }, + "notificationItemStatus": { + "message": "Статус" + }, + "notificationItemSwapped": { + "message": "Обменяно" + }, + "notificationItemSwappedFor": { + "message": "за" + }, + "notificationItemTo": { + "message": "В" + }, + "notificationItemTransactionId": { + "message": "ID транзакции" + }, + "notificationItemUnStakeCompleted": { + "message": "Отмена стейкинга завершена" + }, + "notificationItemUnStaked": { + "message": "Стейкинг отменен" + }, + "notificationItemUnStakingRequested": { + "message": "Запрошена отмена стейкинга" + }, "notificationTransactionFailedMessage": { "message": "Транзакция $1 не удалась! $2", "description": "Content of the browser notification that appears when a transaction fails" @@ -2494,52 +3104,15 @@ "description": "Content of the browser notification that appears when a transaction is confirmed" }, "notificationTransactionSuccessTitle": { - "message": "Подтвержденная транзакция", - "description": "Title of the browser notification that appears when a transaction is confirmed" - }, - "notificationTransactionSuccessView": { - "message": "Смотреть на $1", - "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" - }, - "notifications": { - "message": "Уведомления" - }, - "notifications20ActionText": { - "message": "Подробнее", - "description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a ledger page to resolve the U2F connection issue." - }, - "notifications20Description": { - "message": "Если вы используете последнюю версию Firefox, у вас может возникнуть проблема, связанная с отказом Firefox от поддержки U2F.", - "description": "Description of a notification in the 'See What's New' popup. Describes the U2F support being dropped by firefox and that it affects ledger users." - }, - "notifications20Title": { - "message": "Пользователи Ledger и Firefox испытывают проблемы с подключением", - "description": "Title for a notification in the 'See What's New' popup. Tells users that latest firefox users using U2F may experience connection issues." - }, - "notifications24ActionText": { - "message": "Понятно" - }, - "notifications24Description": { - "message": "Расширенные настройки платы за газ теперь запоминаются в зависимости от используемой вами сети. Это означает, что вы можете установить конкретную дополнительную плату за газ для каждой сети и избежать переплаты за газ или зависших транзакций." - }, - "notifications24Title": { - "message": "Дополнительная плата за газ по сети" - }, - "notifications8ActionText": { - "message": "Перейдите в «Настройки»> «Дополнительно».", - "description": "Description on an action button that appears in the What's New popup. Tells the user that if they click it, they will go to our Advanced settings page." - }, - "notifications8DescriptionOne": { - "message": "Начиная с версии MetaMask 10.4.0, вам больше не требуется Ledger Live для подключения Ledger к MetaMask.", - "description": "Description of a notification in the 'See What's New' popup. Describes changes for how Ledger Live is no longer needed to connect the device." + "message": "Подтвержденная транзакция", + "description": "Title of the browser notification that appears when a transaction is confirmed" }, - "notifications8DescriptionTwo": { - "message": "Чтобы упростить и повысить стабильность работы с Ledger, перейдите на вкладку «Дополнительно» в настройках и смените «Предпочитаемый тип подключения с Ledger» на «WebHID».", - "description": "Description of a notification in the 'See What's New' popup. Describes how the user can turn off the Ledger Live setting." + "notificationTransactionSuccessView": { + "message": "Смотреть на $1", + "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" }, - "notifications8Title": { - "message": "Улучшение связи с Ledger", - "description": "Title for a notification in the 'See What's New' popup. Notifies ledger users that there is an improvement in how they can connect their device." + "notifications": { + "message": "Уведомления" }, "notificationsDropLedgerFirefoxDescription": { "message": "Firefox больше не поддерживает U2F, поэтому Ledger не будет работать с MetaMask в Firefox. Вместо этого попробуйте MetaMask в Google Chrome.", @@ -2549,33 +3122,37 @@ "message": "Прекращение поддержки Ledger в Firefox", "description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped." }, - "notificationsEmptyText": { - "message": "Здесь вы можете найти уведомления от установленных snap." - }, - "notificationsHeader": { - "message": "Уведомления" + "notificationsFeatureToggle": { + "message": "Включить уведомления кошелька", + "description": "Experimental feature title" }, - "notificationsInfos": { - "message": "$1 из $2", - "description": "$1 is the date at which the notification has been dispatched and $2 is the link to the snap that dispatched the notification." + "notificationsFeatureToggleDescription": { + "message": "Это позволяет получать уведомления кошелька, такие как уведомления об отправке/получении средств или Nft, а также объявления о функциях.", + "description": "Description of the experimental notifications feature" }, "notificationsMarkAllAsRead": { "message": "Отметить все как прочитанные" }, - "notificationsOpenBetaSnapsActionText": { - "message": "Подробнее" + "notificationsPageEmptyTitle": { + "message": "Здесь нечего смотреть" + }, + "notificationsPageErrorContent": { + "message": "Попробуйте еще раз посетить эту страницу." }, - "notificationsOpenBetaSnapsDescriptionOne": { - "message": "🎉 Мы рады объявить об открытой бета-версии MetaMask Snaps!" + "notificationsPageErrorTitle": { + "message": "Возникла ошибка" }, - "notificationsOpenBetaSnapsDescriptionThree": { - "message": "Персонализируйте свой кошелек с помощью snaps, созданных сообществом разработчиков!" + "notificationsPageNoNotificationsContent": { + "message": "Вы еще не получили ни одного уведомления." }, - "notificationsOpenBetaSnapsDescriptionTwo": { - "message": "Snaps помогают вам делать больше с MetaMask — например, подключаться к большему количеству сетей, просматривать статистику транзакций и получать настраиваемые уведомления." + "notificationsSettingsBoxError": { + "message": "Возникла проблема, повторите попытку позже." }, - "notificationsOpenBetaSnapsTitle": { - "message": "Представляем MetaMask Snaps" + "notificationsSettingsPageAllowNotifications": { + "message": "Будьте в курсе того, что происходит в вашем кошельке, с помощью уведомлений. Чтобы отправлять уведомления, мы используем профиль для синхронизации некоторых настроек на ваших устройствах. $1" + }, + "notificationsSettingsPageAllowNotificationsLink": { + "message": "Узнайте, как мы защищаем вашу конфиденциальность при использовании этой функции." }, "numberOfNewTokensDetectedPlural": { "message": "$1 новых токена(-ов) найдены в этом счете", @@ -2599,6 +3176,9 @@ "on": { "message": "Вкл." }, + "onboarding": { + "message": "Регистрация" + }, "onboardingAdvancedPrivacyIPFSDescription": { "message": "Шлюз IPFS позволяет получать доступ к данным, размещенным третьими сторонами, и просматривать их. Вы можете добавить пользовательский шлюз IPFS или продолжить использовать шлюз по умолчанию." }, @@ -2629,51 +3209,45 @@ "onboardingMetametricsAgree": { "message": "Я согласен(-на)" }, - "onboardingMetametricsAllowOptOut": { - "message": "Всегда разрешать вам отказываться в Настройках" - }, - "onboardingMetametricsDataTerms": { - "message": "Эти данные агрегированы и, следовательно, являются анонимными для целей Общего регламента по защите данных (ЕС) 2016/679." - }, "onboardingMetametricsDescription": { - "message": "MetaMask хотел бы собрать данные об использовании, чтобы лучше понять, как наши пользователи взаимодействуют с MetaMask. Эти данные будут использоваться для предоставления обслуживания, в том числе его улучшения услуги на основе вашего использования." + "message": "Мы хотели бы собрать базовые данные об использовании и диагностике для улучшения MetaMask. Помните, что мы никогда не продаем данные, которые вы здесь предоставляете." }, "onboardingMetametricsDescription2": { - "message": "MetaMask..." + "message": "Когда мы собираем показатели, они всегда будут..." }, "onboardingMetametricsDisagree": { "message": "Нет, спасибо" }, "onboardingMetametricsInfuraTerms": { - "message": "* Когда вы используете Infura в качестве поставщика RPC по умолчанию в MetaMask, Infura будет собирать ваш IP-адрес и адрес вашего кошелька Ethereum при отправке транзакции. Мы не храним эту информацию таким образом, чтобы наши системы могли связать эти две части данных. Для получения дополнительной информации о том, как MetaMask и Infura взаимодействуют с точки зрения сбора данных, см. нашу обновленную $1. Для получения дополнительной информации о нашей политике конфиденциальности в целом см. нашу $2.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" + "message": "Мы сообщим вам, если решим использовать эти данные для других целей. Вы можете ознакомиться с нашей $1 для получения дополнительной информации. Помните, что вы можете перейти в настройки и отказаться в любой момент.", + "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, "onboardingMetametricsInfuraTermsPolicy": { - "message": "Политику конфиденциальности здесь" - }, - "onboardingMetametricsInfuraTermsPolicyLink": { - "message": "здесь" + "message": "Политикой конфиденциальности" }, "onboardingMetametricsModalTitle": { "message": "Добавить пользовательскую сеть" }, "onboardingMetametricsNeverCollect": { - "message": "$1 не будет собирать информацию, которая нам не нужна для предоставления услуги (например, ключи, адреса, хэши транзакций или остатки)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 клики и просмотры в приложении сохраняются, но другие данные (например, ваш публичный адрес) — нет.", + "description": "$1 represents `onboardingMetametricsNeverCollectEmphasis`" + }, + "onboardingMetametricsNeverCollectEmphasis": { + "message": "Приватными:" }, "onboardingMetametricsNeverCollectIP": { - "message": "$1 не сохраняет ваш полный IP-адрес*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 мы временно используем ваш IP-адрес для определения общего местоположения (например, вашей страны или региона), но он никогда не сохраняется.", + "description": "$1 represents `onboardingMetametricsNeverCollectIPEmphasis`" }, - "onboardingMetametricsNeverEmphasis": { - "message": "Никогда" + "onboardingMetametricsNeverCollectIPEmphasis": { + "message": "Общедоступными:" }, "onboardingMetametricsNeverSellData": { - "message": "$1 не продает данные. Никогда!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 вы в любое время решаете, хотите ли вы поделиться своими данными об использовании или удалить их в настройках.", + "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" }, - "onboardingMetametricsSendAnonymize": { - "message": "Отправлять анонимизированные события кликов и просмотров страниц" + "onboardingMetametricsNeverSellDataEmphasis": { + "message": "Необязательными:" }, "onboardingMetametricsTitle": { "message": "Помогите нам улучшить MetaMask" @@ -2714,15 +3288,26 @@ "onboardingPinExtensionTitle": { "message": "Установка MetaMask завершена!" }, + "onboardingPinMmiExtensionLabel": { + "message": "Закрепить MetaMask Institutional" + }, "onboardingUsePhishingDetectionDescription": { "message": "Оповещения об обнаружении фишинга зависят от связи с $1. jsDeliver получит доступ к вашему IP-адресу. Посмотрите $ 2.", "description": "The $1 is the word 'jsDeliver', from key 'jsDeliver' and $2 is the words Privacy Policy from key 'privacyMsg', both separated here so that it can be wrapped as a link" }, + "onekey": { + "message": "OneKey" + }, "onlyAddTrustedNetworks": { "message": "Вредоносный сетевой провайдер может дезинформировать о состоянии блокчейна и записывать ваши действия в сети. Добавляйте только те пользовательские сети, которым доверяете." }, "onlyConnectTrust": { - "message": "Подключайтесь только к сайтам, которым доверяете." + "message": "Подключайтесь только к сайтам, которым доверяете. $1", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." + }, + "openCustodianApp": { + "message": "Открыть приложение $1", + "description": "The $1 is the name of the Custodian that will be open" }, "openFullScreenForLedgerWebHid": { "message": "Перейдите в полноэкранный режим, чтобы подключить свой Ledger.", @@ -2734,6 +3319,15 @@ "openSeaNew": { "message": "OpenSea" }, + "openSeaToBlockaidBtnLabel": { + "message": "Обзор Snaps" + }, + "openSeaToBlockaidDescription": { + "message": "Оповещения безопасности больше не доступны в этой сети. Установка Snap может повысить вашу безопасность." + }, + "openSeaToBlockaidTitle": { + "message": "Внимание!" + }, "operationFailed": { "message": "Операция не удалась" }, @@ -2777,6 +3371,9 @@ "password": { "message": "Пароль" }, + "passwordMmiTermsWarning": { + "message": "Я понимаю, что MetaMask Institutional не может восстановить этот пароль для меня. $1" + }, "passwordNotLongEnough": { "message": "Пароль недостаточно длинный" }, @@ -2803,6 +3400,10 @@ "message": "Вставьте строку вашего закрытого ключа сюда:", "description": "For importing an account from a private key" }, + "paymasterInUse": { + "message": "Газ за транзакцию будет оплачен на paymaster.", + "description": "Alert shown in transaction confirmation if paymaster in use." + }, "pending": { "message": "Ожидающий" }, @@ -2816,18 +3417,26 @@ "message": "У вас есть (1) ожидающая транзакция.", "description": "$1 is count of pending transactions" }, - "permissionRequest": { - "message": "Запрос разрешения" + "permissionDetails": { + "message": "Сведения о разрешении" }, - "permissionRequestCapitalized": { + "permissionRequest": { "message": "Запрос разрешения" }, "permissionRequested": { "message": "Запрошено сейчас" }, + "permissionRequestedForAccounts": { + "message": "Запрошено сейчас для $1", + "description": "Permission cell status for requested permission including accounts, rendered as AvatarGroup which is $1." + }, "permissionRevoked": { "message": "Отменено в этом обновлении" }, + "permissionRevokedForAccounts": { + "message": "Отменено в этом обновлении для $1", + "description": "Permission cell status for revoked permission including accounts, rendered as AvatarGroup which is $1." + }, "permission_accessNamedSnap": { "message": "Подключиться к $1.", "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." @@ -2836,6 +3445,10 @@ "message": "Доступ в Интернет.", "description": "The description of the `endowment:network-access` permission." }, + "permission_accessNetworkDescription": { + "message": "Предоставьте $1 доступ к Интернету. Его можно использовать как для отправки, так и для получения данных со сторонних серверов.", + "description": "An extended description of the `endowment:network-access` permission. $1 is the snap name." + }, "permission_accessSnap": { "message": "Подключение к спапу $1.", "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." @@ -2848,10 +3461,18 @@ "message": "Планируйте и выполняйте периодические действия.", "description": "The description for the `snap_cronjob` permission" }, + "permission_cronjobDescription": { + "message": "Разрешите $1выполнять действия, которые выполняются периодически в фиксированное время, даты или интервалы. Его можно использовать для запуска срочных взаимодействий или уведомлений.", + "description": "An extended description for the `snap_cronjob` permission. $1 is the snap name." + }, "permission_dialog": { "message": "Отображение диалоговых окон в MetaMask.", "description": "The description for the `snap_dialog` permission" }, + "permission_dialogDescription": { + "message": "Разрешите $1 отображать всплывающие окна MetaMask с настраиваемым текстом, полем ввода и кнопками для одобрения или отклонения действия.\nМожет использоваться для создания, например, оповещения, подтверждения и процедуры получения согласия для snap.", + "description": "An extended description for the `snap_dialog` permission. $1 is the snap name." + }, "permission_ethereumAccounts": { "message": "См. адрес, баланс счета, активность и рекомендуйте транзакции для одобрения", "description": "The description for the `eth_accounts` permission" @@ -2860,30 +3481,138 @@ "message": "Получите доступ к поставщику Ethereum.", "description": "The description for the `endowment:ethereum-provider` permission" }, + "permission_ethereumProviderDescription": { + "message": "Разрешите $1 связываться с MetaMask напрямую, чтобы он мог считывать данные из блокчейна и предлагать сообщения и транзакции.", + "description": "An extended description for the `endowment:ethereum-provider` permission. $1 is the snap name." + }, + "permission_getEntropy": { + "message": "Извлекайте произвольные ключи, уникальные для этого $1.", + "description": "The description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getEntropyDescription": { + "message": "Разрешите $1 извлекать произвольные ключи, уникальные для этого $1, не раскрывая их. Эти ключи отделены от вашего(-их) счета(-ов) MetaMask и не связаны с вашими закрытыми ключами или секретной фразой для восстановления. Другие snaps не могут получить доступ к этой информации.", + "description": "An extended description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getLocale": { + "message": "Просмотрите свой предпочитаемый язык.", + "description": "The description for the `snap_getLocale` permission" + }, + "permission_getLocaleDescription": { + "message": "Разрешите $1 получить доступ к предпочитаемому вами языку в настройках MetaMask. Его можно использовать для локализации и отображения содержимого $1 на вашем языке.", + "description": "An extended description for the `snap_getLocale` permission. $1 is the snap name." + }, + "permission_homePage": { + "message": "Показать пользовательский экран", + "description": "The description for the `endowment:page-home` permission" + }, + "permission_homePageDescription": { + "message": "Разрешите $1 отображает собственный главный экран в MetaMask. Эту функцию можно использовать для пользовательских интерфейсов, конфигурации и инфопанелей.", + "description": "An extended description for the `endowment:page-home` permission. $1 is the snap name." + }, + "permission_keyring": { + "message": "Разрешить запросы на добавление и управление счетами Ethereum", + "description": "The description for the `endowment:keyring` permission" + }, + "permission_keyringDescription": { + "message": "Разрешите $1 получать запросы на добавление или удаление счетов, а также подписывать и совершать транзакции от имени этих счетов.", + "description": "An extended description for the `endowment:keyring` permission. $1 is the snap name." + }, "permission_lifecycleHooks": { "message": "Используйте хуки жизненного цикла.", "description": "The description for the `endowment:lifecycle-hooks` permission" }, + "permission_lifecycleHooksDescription": { + "message": "Разрешите $1 использовать обработчики жизненного цикла для запуска кода в определенное время в течение его жизненного цикла.", + "description": "An extended description for the `endowment:lifecycle-hooks` permission. $1 is the snap name." + }, "permission_manageAccounts": { "message": "Добавляйте счета Ethereum и управляйте ими", "description": "The description for `snap_manageAccounts` permission" }, + "permission_manageAccountsDescription": { + "message": "Разрешите $1 добавлять или удалять счета Ethereum, а затем совершать транзакции и подписывать с использованием этих счетов.", + "description": "An extended description for the `snap_manageAccounts` permission. $1 is the snap name." + }, + "permission_manageBip32Keys": { + "message": "Управлять счетами $1.", + "description": "The description for the `snap_getBip32Entropy` permission. $1 is a derivation path, e.g. 'm/44'/0'/0' (secp256k1)'." + }, + "permission_manageBip44AndBip32KeysDescription": { + "message": "Разрешите $1 управлять счетами и активами в запрошенной сети. Создание и резервное копирование этих счетов выполняется с использованием вашей секретной фразы для восстановления (без ее раскрытия). Благодаря возможности получения ключей $1 может поддерживать различные протоколы блокчейна, помимо Ethereum (EVM).", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions. $1 is the snap name." + }, + "permission_manageBip44Keys": { + "message": "Управлять счетами $1.", + "description": "The description for the `snap_getBip44Entropy` permission. $1 is the name of a protocol, e.g. 'Filecoin'." + }, "permission_manageState": { "message": "Храните и управляйте его данными на вашем устройстве.", "description": "The description for the `snap_manageState` permission" }, + "permission_manageStateDescription": { + "message": "Разрешите $1 безопасно хранить, обновлять и извлекать данные с помощью шифрования. Другие snaps не могут получить доступ к этой информации.", + "description": "An extended description for the `snap_manageState` permission. $1 is the snap name." + }, + "permission_nameLookup": { + "message": "Выдаёт результаты поиска домена и адреса.", + "description": "The description for the `endowment:name-lookup` permission." + }, + "permission_nameLookupDescription": { + "message": "Разрешите snap получать и отображать результаты поиска адресов и доменов в разных частях пользовательского интерфейса MetaMask.", + "description": "An extended description for the `endowment:name-lookup` permission." + }, "permission_notifications": { "message": "Показать уведомления.", "description": "The description for the `snap_notify` permission" }, + "permission_notificationsDescription": { + "message": "Разрешите $1 отображать уведомления в MetaMask. Текст короткого уведомления может отображаться snap для получения информации, требующей действий, или срочной информации.", + "description": "An extended description for the `snap_notify` permission. $1 is the snap name." + }, + "permission_rpc": { + "message": "Разрешите $1 напрямую взаимодействовать с $2.", + "description": "The description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescription": { + "message": "Разрешите $1 отправлять сообщения в адрес $2 и получать ответ от $2.", + "description": "An extended description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescriptionOriginList": { + "message": "$1 и $2", + "description": "A list of allowed origins where $2 is the last origin of the list and $1 is the rest of the list separated by ','." + }, + "permission_signatureInsight": { + "message": "Показывать модальное окно с информацией о подписях.", + "description": "The description for the `endowment:signature-insight` permission" + }, + "permission_signatureInsightDescription": { + "message": "Разрешить $1 показывать модальное окно с информацией по любому запросу на подпись перед утверждением. Это можно использовать в решениях для защиты от фишинга и обеспечения безопасности.", + "description": "An extended description for the `endowment:signature-insight` permission. $1 is the snap name." + }, + "permission_signatureInsightOrigin": { + "message": "Просматривайте источник веб-сайтов, которые инициируют запрос на подпись", + "description": "The description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission" + }, + "permission_signatureInsightOriginDescription": { + "message": "Разрешите $1 просматривать источник (URI) веб-сайтов, которые инициируют запросы на подпись. Это можно использовать в решениях для защиты от фишинга и обеспечения безопасности.", + "description": "An extended description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission. $1 is the snap name." + }, "permission_transactionInsight": { "message": "Получайте и отображайте подробную информацию о транзакциях.", "description": "The description for the `endowment:transaction-insight` permission" }, + "permission_transactionInsightDescription": { + "message": "Разрешите $1 декодировать транзакции и показывать информацию в пользовательском интерфейсе MetaMask. Это можно использовать для защиты от фишинга и обеспечения безопасности.", + "description": "An extended description for the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_transactionInsightOrigin": { "message": "Смотрите происхождение веб-сайтов, которые предлагают транзакции", "description": "The description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission" }, + "permission_transactionInsightOriginDescription": { + "message": "Разрешить $1 видеть происхождение (URI) веб-сайтов, предлагающих транзакции. Это можно использовать для защиты от фишинга и обеспечения безопасности.", + "description": "An extended description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_unknown": { "message": "Неизвестное разрешение: $1", "description": "$1 is the name of a requested permission that is not recognized." @@ -2892,29 +3621,66 @@ "message": "Просмотрите свой открытый ключ для $1 ($2).", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a derivation path, e.g. 'm/44'/0'/0''. $2 is the elliptic curve name, e.g. 'secp256k1'." }, + "permission_viewBip32PublicKeysDescription": { + "message": "Разрешите $2 просматривать ваши открытые ключи (и адреса) для $1. Это не дает никакого контроля над счетами или активами.", + "description": "An extended description for the `snap_getBip32PublicKey` permission. $1 is a derivation path (name). $2 is the snap name." + }, "permission_viewNamedBip32PublicKeys": { "message": "Просмотрите свой открытый ключ для $1.", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a name for the derivation path, e.g., 'Ethereum accounts'." }, + "permission_walletSwitchEthereumChain": { + "message": "Переключитесь и используйте следующую сеть", + "description": "The label for the `wallet_switchEthereumChain` permission" + }, "permission_webAssembly": { "message": "Поддержка WebAssembly.", "description": "The description of the `endowment:webassembly` permission." }, + "permission_webAssemblyDescription": { + "message": "Разрешите $1 доступ к низкоуровневым средам исполнения через WebAssembly.", + "description": "An extended description of the `endowment:webassembly` permission. $1 is the snap name." + }, "permissions": { "message": "Разрешения" }, - "permissionsTitle": { - "message": "Разрешения" + "permissionsPageEmptyContent": { + "message": "Здесь не на что смотреть" + }, + "permissionsPageEmptySubContent": { + "message": "Здесь вы можете увидеть разрешения, которые вы предоставили установленным Snaps или подключенным сайтам." }, - "permissionsTourDescription": { - "message": "Найдите свои подключенные счета и управляйте разрешениями здесь" + "permissionsPageTourDescription": { + "message": "Это ваша панель управления для управления разрешениями, предоставленными подключенным сайтам и установленным Snaps." + }, + "permissionsPageTourTitle": { + "message": "Подключенные сайты теперь имеют разрешения" }, "personalAddressDetected": { "message": "Обнаружен личный адрес. Введите адрес контракта токена." }, + "petnamesEnabledToggle": { + "message": "Разрешить псевдонимы" + }, + "petnamesEnabledToggleDescription": { + "message": "Эта функция позволяет вам присвоить псевдоним любому адресу. По возможности мы будем предлагать имена адресов, с которыми вы взаимодействуете." + }, + "pinExtensionDescription": { + "message": "Перейдите в меню расширения и закрепите MetaMask Institutional для беспрепятственного доступа." + }, + "pinExtensionTitle": { + "message": "Закрепить расширение" + }, + "pinToTop": { + "message": "Закрепить вверху" + }, "pleaseConfirm": { "message": "Пожалуйста, подтвердите" }, + "plusMore": { + "message": "+ еще $1", + "description": "$1 is the number of additional items" + }, "plusXMore": { "message": "+ еще $1", "description": "$1 is a number of additional but unshown items in a list- this message will be shown in place of those items" @@ -2940,6 +3706,9 @@ "primaryCurrencySettingDescription": { "message": "Выберите «собственная», чтобы установить приоритет отображения значений в собственной валюте блокчейна (например, ETH). Выберите «Фиатная», чтобы установить приоритет отображения значений в выбранной фиатной валюте." }, + "primaryType": { + "message": "Основной тип" + }, "priorityFee": { "message": "Плата за приоритет" }, @@ -2960,6 +3729,18 @@ "message": "Закрытый ключ за $1", "description": "$1 represents the account name" }, + "privateKeyHidden": { + "message": "Закрытый ключ скрыт", + "description": "Explains that the private key input is hidden" + }, + "privateKeyShow": { + "message": "Показать/скрыть закрытый ключ при вводе", + "description": "Describes a toggle that is used to show or hide the private key input" + }, + "privateKeyShown": { + "message": "Этот закрытый ключ отображается", + "description": "Explains that the private key input is being shown" + }, "privateKeyWarning": { "message": "Предупреждение: никогда не раскрывайте этот ключ. Любой, у кого есть ваши закрытые ключи, может украсть любые активы, хранящиеся на вашем счете." }, @@ -2969,6 +3750,21 @@ "proceedWithTransaction": { "message": "Я все равно хочу продолжить" }, + "productAnnouncements": { + "message": "Объявления о продуктах" + }, + "profileSync": { + "message": "Синхронизация профиля" + }, + "profileSyncConfirmation": { + "message": "Если вы отключите синхронизацию профиля, вы не сможете получать уведомления." + }, + "profileSyncDescription": { + "message": "Создает профиль, который MetaMask использует для синхронизации некоторых настроек между вашими устройствами. Это необходимо для получения уведомлений. $1." + }, + "profileSyncPrivacyLink": { + "message": "Узнайте, как мы защищаем вашу конфиденциальность" + }, "proposedApprovalLimit": { "message": "Предлагаемый лимит одобрения" }, @@ -2978,6 +3774,78 @@ "publicAddress": { "message": "Публичный адрес" }, + "pushPlatformNotificationsFundsReceivedDescription": { + "message": "Вы получили $1 $2" + }, + "pushPlatformNotificationsFundsReceivedDescriptionDefault": { + "message": "Вы получили несколько токенов" + }, + "pushPlatformNotificationsFundsReceivedTitle": { + "message": "Средства получены" + }, + "pushPlatformNotificationsFundsSentDescription": { + "message": "Вы успешно отправили $1 $2" + }, + "pushPlatformNotificationsFundsSentDescriptionDefault": { + "message": "Вы успешно отправили несколько токенов" + }, + "pushPlatformNotificationsFundsSentTitle": { + "message": "Средства отправлены" + }, + "pushPlatformNotificationsNftReceivedDescription": { + "message": "Вы получили новые NFT" + }, + "pushPlatformNotificationsNftReceivedTitle": { + "message": "NFT получен" + }, + "pushPlatformNotificationsNftSentDescription": { + "message": "Вы успешно отправили NFT" + }, + "pushPlatformNotificationsNftSentTitle": { + "message": "NFT отправлен" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedDescription": { + "message": "Ваш стейкинг Lido выполнен" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedTitle": { + "message": "Стейкинг выполнен" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnDescription": { + "message": "Ваша доля Lido готова к выводу" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnTitle": { + "message": "Доля готова к выводу" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedDescription": { + "message": "Ваш вывод средств из Lido выполнен" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedTitle": { + "message": "Вывод средств завершен" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedDescription": { + "message": "Ваш запрос на вывод средств из Lido отправлен" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedTitle": { + "message": "Запрошен вывод средств" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedDescription": { + "message": "Ваш стейкинг RocketPool выполнен" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedTitle": { + "message": "Стейкинг выполнен" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedDescription": { + "message": "Выполнена отмена стейкинга RocketPool" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedTitle": { + "message": "Отмена стейкинга завершена" + }, + "pushPlatformNotificationsSwapCompletedDescription": { + "message": "Ваш обмен MetaMask выполнен" + }, + "pushPlatformNotificationsSwapCompletedTitle": { + "message": "Обмен выполнен" + }, "queued": { "message": "В очереди" }, @@ -2996,9 +3864,15 @@ "receive": { "message": "Получить" }, + "receiveTokensCamelCase": { + "message": "Получить токены" + }, "recipientAddressPlaceholder": { "message": "Введите публичный адрес (0x) или имя ENS" }, + "recipientAddressPlaceholderFlask": { + "message": "Введите публичный адрес (0x) или имя домена" + }, "recommendedGasLabel": { "message": "Рекомендовано" }, @@ -3026,6 +3900,12 @@ "recoveryPhraseReminderTitle": { "message": "Защитите свои средства" }, + "redesignedConfirmationsEnabledToggle": { + "message": "Улучшенные запросы подписи" + }, + "redesignedConfirmationsToggleDescription": { + "message": "Включите эту опцию, чтобы видеть запросы на подпись в расширенном формате." + }, "refreshList": { "message": "Обновить список" }, @@ -3068,14 +3948,29 @@ "removeJWTDescription": { "message": "Уверены, что хотите удалить этот токен? Все счета, назначенные этому токену, также будут удалены из расширения: " }, + "removeKeyringSnap": { + "message": "Удаление этого Snap приведет к удалению этих счетов из MetaMask:" + }, + "removeKeyringSnapToolTip": { + "message": "Snap контролирует счета, и при его удалении счета будут удалены и из MetaMask, но останутся в блокчейне." + }, "removeNFT": { "message": "Удалить NFT" }, + "removeNftErrorMessage": { + "message": "Нам не удалось удалить этот NFT." + }, "removeNftMessage": { "message": "NFT успешно удален!" }, "removeSnap": { - "message": "Удалить snap" + "message": "Удалить Snap" + }, + "removeSnapAccountDescription": { + "message": "Если вы продолжите, этот счет больше не будет доступен в MetaMask." + }, + "removeSnapAccountTitle": { + "message": "Удалить счет" }, "removeSnapConfirmation": { "message": "Уверены, что хотите удалить $1?", @@ -3087,12 +3982,24 @@ "replace": { "message": "заменить" }, + "reportIssue": { + "message": "Сообщить о проблеме" + }, "requestFlaggedAsMaliciousFallbackCopyReason": { "message": "Поставщик услуг безопасности не поделился дополнительной информацией" }, "requestFlaggedAsMaliciousFallbackCopyReasonTitle": { "message": "Запрос помечен как вредоносный" }, + "requestFrom": { + "message": "Запрос от" + }, + "requestFromInfo": { + "message": "Это сайт, который запрашивает вашу подпись." + }, + "requestFromTransactionDescription": { + "message": "Это сайт, запрашивающий ваше подтверждение." + }, "requestMayNotBeSafe": { "message": "Запрос может быть небезопасным" }, @@ -3114,6 +4021,9 @@ "reset": { "message": "Сбросить" }, + "resetStates": { + "message": "Сбросить состояния" + }, "resetWallet": { "message": "Сбросить кошелек" }, @@ -3196,9 +4106,15 @@ "message": "Поддержка MetaMask никогда не будет запрашивать этот ключ.", "description": "The bolded texted in the second part of 'revealSeedWordsWarning'" }, + "revealSensitiveContent": { + "message": "Показать конфиденциальный контент" + }, "revealTheSeedPhrase": { "message": "Показать сид-фразу" }, + "reviewAlerts": { + "message": "Просмотреть оповещения" + }, "revokeAllTokensTitle": { "message": "Отозвать разрешение на доступ ко всем вашим $1 и их перевод?", "description": "$1 is the symbol of the token for which the user is revoking approval" @@ -3249,6 +4165,9 @@ "searchAccounts": { "message": "Поиск счетов" }, + "searchTokens": { + "message": "Поиск токенов" + }, "secretRecoveryPhrase": { "message": "Секретная фраза для восстановления" }, @@ -3265,7 +4184,8 @@ "message": "Оповещения безопасности" }, "securityAlertsDescription": { - "message": "Эта функция предупреждает вас о вредоносной активности в Мейн-нете Ethereum, активно просматривая запросы транзакций и подписей, сохраняя при этом вашу конфиденциальность. Ваши данные не передаются третьей стороне, предоставляющей эту услугу. Всегда проводите комплексную проверку перед утверждением каких-либо запросов. Нет никакой гарантии, что эта функция обнаружит всю вредоносную активность." + "message": "Эта функция предупреждает вас о вредоносной активности, активно проверяя транзакции и запросы на подпись. $1", + "description": "Link to learn more about security alerts" }, "securityAndPrivacy": { "message": "Безопасность и конфиденциальность" @@ -3355,6 +4275,9 @@ "selectAnAccountHelp": { "message": "Выберите депозитарные счета для использования в MetaMask Institutional." }, + "selectEnableDisplayMediaPrivacyPreference": { + "message": "Включить отображение носителя NFT" + }, "selectHdPath": { "message": "Выберите путь HD" }, @@ -3376,18 +4299,41 @@ "send": { "message": "Отправить" }, + "sendAToken": { + "message": "Отправить токен" + }, "sendBugReport": { "message": "Отправьте нам отчет об ошибке." }, + "sendNoContactsConversionText": { + "message": "нажмите здесь" + }, + "sendNoContactsDescription": { + "message": "Контакты позволяют безопасно отправлять транзакции в другой счет несколько раз. Чтобы создать контакт, $1", + "description": "$1 represents the action text 'click here'" + }, + "sendNoContactsTitle": { + "message": "У вас пока нет контактов" + }, + "sendSelectReceiveAsset": { + "message": "Выберите актив для получения" + }, + "sendSelectSendAsset": { + "message": "Выберите актив для отправки" + }, "sendSpecifiedTokens": { "message": "Отправить $1", "description": "Symbol of the specified token" }, - "sendTo": { - "message": "Отправить в адрес" + "sendSwapSubmissionWarning": { + "message": "Нажатие этой кнопки немедленно инициирует транзакцию обмена. Прежде чем продолжить, проверьте детали транзакции." + }, + "sendTokenAsToken": { + "message": "Отправить $1 как $2", + "description": "Used in the transaction display list to describe a swap and send. $1 and $2 are the symbols of tokens in involved in the swap." }, - "sendTokens": { - "message": "Отправить токены" + "sendingAsset": { + "message": "Идет отправка $1" }, "sendingDisabled": { "message": "Отправка NFT-активов ERC-1155 пока не поддерживается." @@ -3400,9 +4346,15 @@ "message": "Предупреждение: вы собираетесь отправить контракт на токены, что может привести к потере средств. $1", "description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning" }, + "sendingZeroAmount": { + "message": "Вы отправляете 0 $1." + }, "sepolia": { "message": "Тестовая сеть Sepolia" }, + "serviceWorkerKeepAlive": { + "message": "Поддерживать активным сервисный модуль" + }, "setAdvancedPrivacySettingsDetails": { "message": "MetaMask использует эти доверенные сторонние сервисы для повышения удобства использования и безопасности продукта." }, @@ -3414,7 +4366,7 @@ "description": "The token symbol that is being approved" }, "settingAddSnapAccount": { - "message": "Добавить счет snap" + "message": "Добавить Snap счета" }, "settings": { "message": "Настройки" @@ -3422,9 +4374,21 @@ "settingsSearchMatchingNotFound": { "message": "Совпадений не найдено." }, + "settingsSubHeadingSignaturesAndTransactions": { + "message": "Запросы на подпись или транзакции" + }, "show": { "message": "Показать" }, + "showAccount": { + "message": "Показать счет" + }, + "showExtensionInFullSizeView": { + "message": "Пказать расширение в полноразмерном виде" + }, + "showExtensionInFullSizeViewDescription": { + "message": "Включите этот параметр, чтобы полноразмерный просмотр отображался по умолчанию при щелчке по значку расширения." + }, "showFiatConversionInTestnets": { "message": "Показывать обмен в тестовых сетях" }, @@ -3444,6 +4408,9 @@ "message": "Это использует $1, который будет иметь доступ к вашему адресу Ethereum и вашему IP-адресу. $2", "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" }, + "showIncomingTransactionsExplainer": { + "message": "Это базируется на различных сторонних API для каждой сети, которые раскрывают ваш адрес Ethereum и ваш IP-адрес." + }, "showMore": { "message": "Показать больше" }, @@ -3483,9 +4450,46 @@ "signin": { "message": "Войти" }, + "signing": { + "message": "Подписание" + }, + "simulationDetailsFailed": { + "message": "Не удалось загрузить прогноз." + }, + "simulationDetailsFiatNotAvailable": { + "message": "Недоступно" + }, + "simulationDetailsIncomingHeading": { + "message": "Вы получаете" + }, + "simulationDetailsNoBalanceChanges": { + "message": "Никаких изменений в вашем кошельке не прогнозируется" + }, + "simulationDetailsOutgoingHeading": { + "message": "Вы отправляете" + }, + "simulationDetailsTitle": { + "message": "Прогнозируемые изменения" + }, + "simulationDetailsTitleTooltip": { + "message": "Прогнозируемые изменения — это то, что может произойти, если вы завершите эту транзакцию. Это всего лишь прогноз, а не гарантия." + }, + "simulationDetailsTotalFiat": { + "message": "Итого = $1", + "description": "$1 is the total amount in fiat currency on one side of the transaction" + }, + "simulationDetailsTransactionReverted": { + "message": "Эта транзакция, скорее всего, не удастся" + }, "simulationErrorMessageV2": { "message": "Мы не смогли оценить размер платы за газ. В контракте может быть ошибка, и эта транзакция может завершиться неудачно." }, + "simulationsSettingDescription": { + "message": "Включите эту опцию, чтобы спрогнозировать изменения баланса транзакций перед их подтверждением. Это не гарантирует окончательный результат ваших транзакций. $1" + }, + "simulationsSettingSubHeader": { + "message": "Спрогнозировать изменения баланса" + }, "skip": { "message": "Пропустить" }, @@ -3498,20 +4502,99 @@ "smartContracts": { "message": "Смарт-контракты" }, - "smartSwapsAreHere": { - "message": "Появились смарт-свопы!" - }, - "smartSwapsDescription": { - "message": "Свопы MetaMask стали намного умнее! Включение смарт-свопов позволит MetaMask программно оптимизировать ваш своп, чтобы помочь:" - }, "smartSwapsErrorNotEnoughFunds": { "message": "Недостаточно средств для смарт-свопа." }, "smartSwapsErrorUnavailable": { "message": "Смарт-свопы временно недоступны." }, + "smartTransactionCancelled": { + "message": "Ваша транзакция отменена" + }, + "smartTransactionCancelledDescription": { + "message": "Не удалось завершить вашу транзакцию, поэтому она была отменена, чтобы избавить вас от ненужной платы за газ." + }, + "smartTransactionError": { + "message": "Ваша транзакция не удалась" + }, + "smartTransactionErrorDescription": { + "message": "Внезапные изменения на рынке могут привести к неудачам. Если проблема не исчезнет, ​​обратитесь в поддержку MetaMask." + }, + "smartTransactionPending": { + "message": "Ваша транзакция отправляется" + }, + "smartTransactionSuccess": { + "message": "Ваша транзакция завершена" + }, + "smartTransactionTakingTooLong": { + "message": "Извините за ожидание" + }, + "smartTransactionTakingTooLongDescription": { + "message": "Если ваша транзакция не будет завершена в течение $1, она будет отменена и с вас не будет взиматься плата за газ.", + "description": "$1 is remaining time in seconds" + }, + "smartTransactions": { + "message": "Умные транзакции" + }, + "smartTransactionsBenefit1": { + "message": "Коэффициент успеха 99,5%" + }, + "smartTransactionsBenefit2": { + "message": "Экономит вам деньги" + }, + "smartTransactionsBenefit3": { + "message": "Обновления в реальном времени" + }, + "smartTransactionsDescription": { + "message": "Откройте для себя более высокие коэффициенты успеха, передовую защиту и лучшую прозрачность с помощью умных транзакций." + }, + "smartTransactionsDescription2": { + "message": "Доступно только на Ethereum. Включайте или отключайте в любое время в настройках. $1", + "description": "$1 is an external link to learn more about Smart Transactions" + }, + "smartTransactionsOptItModalTitle": { + "message": "Улучшенная защита транзакций" + }, + "snapAccountCreated": { + "message": "Счет создан" + }, + "snapAccountCreatedDescription": { + "message": "Ваш новый счет готов к использованию!" + }, + "snapAccountCreationFailed": { + "message": "Не удалось создать счет" + }, + "snapAccountCreationFailedDescription": { + "message": "$1 не удалось создать для вас счет.", + "description": "$1 is the snap name" + }, + "snapAccountRedirectFinishSigningTitle": { + "message": "Завершить подписание" + }, + "snapAccountRedirectSiteDescription": { + "message": "Следуйте инструкциям от $1" + }, + "snapAccountRemovalFailed": { + "message": "Не удалось удалить счет" + }, + "snapAccountRemovalFailedDescription": { + "message": "$1 не удалось удалить для вас этот счет.", + "description": "$1 is the snap name" + }, + "snapAccountRemoved": { + "message": "Счет удален" + }, + "snapAccountRemovedDescription": { + "message": "Этот счет больше не будет доступен для использования в MetaMask." + }, + "snapAccounts": { + "message": "Snaps счета" + }, + "snapAccountsDescription": { + "message": "Счета, контролируемые сторонними Snap." + }, "snapConnectionWarning": { - "message": "$1 хочет подключиться к $2. Продолжайте, только если вы доверяете этому сайту.", + "message": "$1 хочет использовать $2", "description": "$2 is the snap and $1 is the dapp requesting connection to the snap." }, "snapContent": { @@ -3522,15 +4605,35 @@ "message": "Веб-сайт" }, "snapInstallRequest": { - "message": "Установка $1 дает ему следующие разрешения. Продолжайте, только если доверяете $1.", + "message": "Установка $1 дает ему следующие разрешения.", "description": "$1 is the snap name." }, "snapInstallSuccess": { "message": "Установка завершена" }, + "snapInstallWarningCheck": { + "message": "$1 требуется разрешение, чтобы сделать следующее:", + "description": "Warning message used in popup displayed on snap install. $1 is the snap name." + }, "snapInstallWarningHeading": { "message": "Действуйте с осторожностью" }, + "snapInstallWarningPermissionDescriptionForBip32View": { + "message": "Разрешите $1 просматривать ваши открытые ключи (и адреса). Это не дает никакого контроля над счетами или активами.", + "description": "An extended description for the `snap_getBip32PublicKey` permission used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionDescriptionForEntropy": { + "message": "Разрешите $1 управлять счетами и активами в запрошенной(-ых) сети(-ях). Создание и резервное копирование этих счетов выполняется с использованием вашей секретной фразы для восстановления (без ее раскрытия). Благодаря возможности получения ключей $1 может поддерживать различные протоколы блокчейна, помимо Ethereum (EVM).", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionNameForEntropy": { + "message": "Управлять счетами $1", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, + "snapInstallWarningPermissionNameForViewPublicKey": { + "message": "Посмотрите свой открытый ключ для $1", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, "snapInstallationErrorDescription": { "message": "Не удалось установить $1.", "description": "Error description used when snap installation fails. $1 is the snap name." @@ -3548,6 +4651,10 @@ "snapResultSuccessDescription": { "message": "$1 готово к использованию" }, + "snapUpdateAlertDescription": { + "message": "Получите последнюю версию $1", + "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." + }, "snapUpdateAvailable": { "message": "Доступно обновление" }, @@ -3559,22 +4666,40 @@ "message": "Ошибка обновления", "description": "Error title used when snap update fails." }, + "snapUpdateRequest": { + "message": "Обновление $1 дает ему следующие разрешения.", + "description": "$1 is the Snap name." + }, "snapUpdateSuccess": { "message": "Обновление завершено" }, + "snapUrlIsBlocked": { + "message": "Этот Snap хочет перенаправить вас на заблокированный сайт. $1." + }, "snaps": { "message": "Snaps" }, - "snapsInvalidUIError": { - "message": "Пользовательский интерфейс, указанный snap, недействителен." + "snapsConnected": { + "message": "Snaps подключены" }, "snapsNoInsight": { "message": "Этот snap не выдал никакой аналитики" }, + "snapsPrivacyWarningFirstMessage": { + "message": "Вы признаете, что Snap, который вы устанавливаете, является Сторонней службой, как она определена в $1 Consensys, кроме случаев, когда он определяется иначе. Использование вами Сторонних служб регулируется отдельными положениями и условиями, установленными сторонним поставщиком услуг. Consensys не рекомендует использовать Snap каком-либо конкретному лицу по какой-либо конкретной причине. Вы получаете доступ к Сторонней службе, полагаетесь на нее или используете его на свой страх и риск. Consensys отказывается от любой ответственности и ответственности за любые убытки, связанные с использованием вами сторонних услуг.", + "description": "First part of a message in popup modal displayed when installing a snap for the first time. $1 is terms of use link." + }, "snapsPrivacyWarningSecondMessage": { "message": "Любая информация, которую вы передаете Сторонним службам, будет собираться непосредственно этими Сторонними службами в соответствии с их политикой конфиденциальности. Пожалуйста, обратитесь к их политике конфиденциальности для получения дополнительной информации.", "description": "Second part of a message in popup modal displayed when installing a snap for the first time." }, + "snapsPrivacyWarningThirdMessage": { + "message": "Consensys не имеет доступа к информации, которую вы передаете Сторонним службам.", + "description": "Third part of a message in popup modal displayed when installing a snap for the first time." + }, + "snapsSettings": { + "message": "Настройки Snap" + }, "snapsTermsOfUse": { "message": "Условия использования" }, @@ -3588,12 +4713,19 @@ "someNetworksMayPoseSecurity": { "message": "Некоторые сети могут представлять угрозу безопасности и/или конфиденциальности. Прежде чем добавлять и использовать сеть, ознакомьтесь с рисками." }, + "somethingDoesntLookRight": { + "message": "Что-то не так? $1", + "description": "A false positive message for users to contact support. $1 is a link to the support page." + }, "somethingIsWrong": { "message": "Что-то пошло не так. Попробуйте перезагрузить страницу." }, "somethingWentWrong": { "message": "Ой! Что-то пошло не так." }, + "source": { + "message": "Источник" + }, "speedUp": { "message": "Ускорить" }, @@ -3728,6 +4860,14 @@ "stake": { "message": "Выполнить стейкинг" }, + "startYourJourney": { + "message": "Начните свое путешествие с $1", + "description": "$1 is the token symbol" + }, + "startYourJourneyDescription": { + "message": "Начните использовать Web3, добавив $1 в свой кошелек.", + "description": "$1 is the token symbol" + }, "stateLogError": { "message": "Ошибка при получении журналов состояния." }, @@ -3740,6 +4880,9 @@ "stateLogsDescription": { "message": "Журналы состояния содержат ваши адреса публичных счетов и отправленные транзакции." }, + "states": { + "message": "Состояния" + }, "status": { "message": "Статус" }, @@ -3783,18 +4926,6 @@ "strong": { "message": "Сильный" }, - "stxBenefit1": { - "message": "Минимизируйте транзакционные издержки" - }, - "stxBenefit2": { - "message": "Уменьшите количество сбоев транзакций" - }, - "stxBenefit3": { - "message": "Устраните зависание транзакций" - }, - "stxBenefit4": { - "message": "Предотвратите опережение" - }, "stxCancelled": { "message": "Своп бы не удался" }, @@ -3804,6 +4935,10 @@ "stxCancelledSubDescription": { "message": "Попробуйте выполнить своп еще раз. Мы готовы защитить вас от подобных рисков в следующий раз." }, + "stxEstimatedCompletion": { + "message": "Предполагаемое завершение через < $1", + "description": "$1 is remeaning time in minutes and seconds, e.g. 0:10" + }, "stxFailure": { "message": "Своп не удался" }, @@ -3811,6 +4946,9 @@ "message": "Внезапные изменения на рынке могут привести к отказам. Если проблема не устранена, обратитесь по адресу $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInDescription": { + "message": "Включите умные транзакции для более надежных и безопасных транзакций в Мейн-нете Ethereum. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Приватная отправка вашего свопа..." }, @@ -3849,12 +4987,21 @@ "submitted": { "message": "Отправлено" }, + "suggestedTokenSymbol": { + "message": "Рекомендуемый символ-тикер:" + }, "support": { "message": "Поддержка" }, "supportCenter": { "message": "Посетите наш центр поддержки" }, + "surveyConversion": { + "message": "Пройдите наш опрос" + }, + "surveyTitle": { + "message": "Сформируйте будущее MetaMask" + }, "swap": { "message": "Своп" }, @@ -3874,6 +5021,9 @@ "swapAmountReceivedInfo": { "message": "Это минимальная сумма, которую вы получите. Вы можете получить больше в зависимости от проскальзывания." }, + "swapAndSend": { + "message": "Обменять и отправить" + }, "swapAnyway": { "message": "Все равно выполнить своп" }, @@ -3989,6 +5139,10 @@ "message": "Включает комиссию MetaMask в размере $1%.", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." }, + "swapIncludesMMFeeAlt": { + "message": "Котировка с учетом комиссии MetaMask в размере $1 %", + "description": "Provides information about the fee that metamask takes for swaps using the latest copy. $1 is a decimal number." + }, "swapIncludesMetaMaskFeeViewAllQuotes": { "message": "Включает комиссию MetaMask в размере $1% — $2.", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number and $2 is a link to view all quotes." @@ -3996,6 +5150,9 @@ "swapLearnMore": { "message": "Узнайте больше о свопах" }, + "swapLiquiditySourceInfo": { + "message": "Мы ищем по разным источникам ликвидности (биржи, агрегаторы и профессиональные маркет-мейкеры), чтобы сравнивать обменные курсы и комиссии сети." + }, "swapLowSlippage": { "message": "Низкое проскальзывание" }, @@ -4268,6 +5425,9 @@ "switchEthereumChainConfirmationTitle": { "message": "Разрешить этому сайту сменить сеть?" }, + "switchInputCurrency": { + "message": "Изменить входную валюту" + }, "switchNetwork": { "message": "Сменить сеть" }, @@ -4281,14 +5441,15 @@ "switchToThisAccount": { "message": "Переключиться на этот счет" }, - "switchedTo": { - "message": "Вы переключились на" + "switchedNetworkToastDecline": { + "message": "Не показывать снова" }, - "switcherTitle": { - "message": "Переключатель сети" + "switchedNetworkToastMessage": { + "message": "$1 теперь активен в $2", + "description": "$1 represents the account name, $2 represents the network name" }, - "switcherTourDescription": { - "message": "Нажмите на значок для переключения сетей или добавления новой сети" + "switchedTo": { + "message": "Вы переключились на" }, "switchingNetworksCancelsPendingConfirmations": { "message": "В случае смены сетей все ожидающие подтверждения будут отменены" @@ -4388,6 +5549,18 @@ "toggleEthSignOn": { "message": "ВКЛ. (не рекомендуется)" }, + "toggleRequestQueueDescription": { + "message": "Это позволяет вам выбрать сеть для каждого сайта вместо одной выбранной сети для всех сайтов. Эта функция не позволит вам переключать сети вручную, что может снизить удобство использования некоторых сайтов." + }, + "toggleRequestQueueField": { + "message": "Выберите сети для каждого сайта" + }, + "toggleRequestQueueOff": { + "message": "Выкл." + }, + "toggleRequestQueueOn": { + "message": "Вкл." + }, "token": { "message": "Токен" }, @@ -4404,7 +5577,7 @@ "message": "Адрес контракта токена" }, "tokenDecimalFetchFailed": { - "message": "Укажите число десятичных знаков токена." + "message": "Требуется десятичный токен. Найдите его здесь: $1" }, "tokenDecimalTitle": { "message": "Десятичный токен:" @@ -4443,6 +5616,9 @@ "tooltipSatusConnected": { "message": "подключено" }, + "tooltipSatusConnectedUpperCase": { + "message": "Подключен" + }, "tooltipSatusNotConnected": { "message": "не подключено" }, @@ -4583,6 +5759,39 @@ "tryAgain": { "message": "Попробуйте еще раз" }, + "turnOff": { + "message": "Выключить" + }, + "turnOffMetamaskNotificationsError": { + "message": "Произошла ошибка при отключении уведомлений. Повторите попытку позже." + }, + "turnOn": { + "message": "Включить" + }, + "turnOnMetamaskNotifications": { + "message": "Включить уведомления" + }, + "turnOnMetamaskNotificationsButton": { + "message": "Включить" + }, + "turnOnMetamaskNotificationsError": { + "message": "Произошла ошибка при создании уведомлений. Повторите попытку позже." + }, + "turnOnMetamaskNotificationsMessageFirst": { + "message": "Будьте в курсе того, что происходит в вашем кошельке, с помощью уведомлений." + }, + "turnOnMetamaskNotificationsMessagePrivacyBold": { + "message": "Настройки > Уведомления." + }, + "turnOnMetamaskNotificationsMessagePrivacyLink": { + "message": "Узнайте, как мы защищаем вашу конфиденциальность при использовании этой функции." + }, + "turnOnMetamaskNotificationsMessageSecond": { + "message": "Чтобы отправлять уведомления кошелька, мы используем профиль для синхронизации некоторых настроек на ваших устройствах ($1)." + }, + "turnOnMetamaskNotificationsMessageThird": { + "message": "Вы можете отключить уведомления в любое время в $1" + }, "turnOnTokenDetection": { "message": "Включите расширенное определение токенов" }, @@ -4614,6 +5823,10 @@ "unknownNetwork": { "message": "Неизвестная частная сеть" }, + "unknownNetworkForKeyEntropy": { + "message": "Неизвестная сеть", + "description": "Displayed on places like Snap install warning when regular name is not available." + }, "unknownQrCode": { "message": "Ошибка: мы не смогли идентифицировать этот QR-код" }, @@ -4626,6 +5839,9 @@ "unlockMessage": { "message": "Децентрализованная сеть ждет вас" }, + "unpin": { + "message": "Открепить" + }, "unrecognizedChain": { "message": "Эта пользовательская сеть не распознана. Мы рекомендуем $1, прежде чем продолжить", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." @@ -4643,6 +5859,9 @@ "update": { "message": "Обновить" }, + "updateRequest": { + "message": "Запрос обновления" + }, "updatedWithDate": { "message": "Обновлено $1" }, @@ -4667,12 +5886,25 @@ "useNftDetection": { "message": "Автоопределение NFT" }, + "useNftDetectionDescriptionText": { + "message": "Разрешает MetaMask добавлять ваши собственные NFT с помощью сторонних сервисов (например, OpenSea). Автоопределение NFT раскрывает ваш IP-адрес и адрес счета этим сервисам. Включение этой функции может связать ваш IP-адрес с вашим адресом Ethereum и отобразить поддельные NFT-файлы, аирдропнутые мошенниками. Вы можете добавлять токены вручную, чтобы избежать этой угрозы." + }, "usePhishingDetection": { "message": "Использовать обнаружение фишинга" }, "usePhishingDetectionDescription": { "message": "Показывать предупреждение для фишинговых доменов, нацеленных на пользователей Ethereum" }, + "useSafeChainsListValidation": { + "message": "Проверка сведений о сети" + }, + "useSafeChainsListValidationDescription": { + "message": "MetaMask использует сторонний сервис под названием $1 для отображения точных и стандартизированных сведений о сети. Это снижает ваши шансы подключиться к вредоносной или неправильной сети. При использовании этой функции ваш IP-адрес доступен сети chainid.network." + }, + "useSafeChainsListValidationWebsite": { + "message": "chainid.network", + "description": "useSafeChainsListValidationWebsite is separated from the rest of the text so that we can bold the third party service name in the middle of them" + }, "useSiteSuggestion": { "message": "Использовать рекомендацию сайта" }, @@ -4685,6 +5917,9 @@ "userName": { "message": "Имя пользователя" }, + "userOpContractDeployError": { + "message": "Развертывание контракта из счета смарт-контракта не поддерживается" + }, "verifyContractDetails": { "message": "Проверьте информацию о третьей стороне" }, @@ -4702,6 +5937,9 @@ "view": { "message": "Просмотр" }, + "viewActivity": { + "message": "Смотреть активность" + }, "viewAllDetails": { "message": "Смотреть все сведения" }, @@ -4725,7 +5963,7 @@ }, "viewOnCustomBlockExplorer": { "message": "Смотреть $1 в $2", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "Смотреть 1$ на Etherscan", @@ -4737,6 +5975,9 @@ "viewOnOpensea": { "message": "Смотреть на OpenSea" }, + "viewTransaction": { + "message": "Смотреть транзакцию" + }, "viewinCustodianApp": { "message": "Смотреть в приложении депозитария" }, @@ -4744,6 +5985,9 @@ "message": "Смотреть $1 в обозревателе", "description": "$1 is the action type. e.g (Account, Transaction, Swap)" }, + "visitSite": { + "message": "Посетить сайт" + }, "visitWebSite": { "message": "Посетите наш веб-сайт" }, @@ -4782,6 +6026,10 @@ "warning": { "message": "Предупреждение" }, + "warningFromSnap": { + "message": "Предупреждение от $1", + "description": "$1 represents the name of the snap" + }, "warningTooltipText": { "message": "$1 Третья сторона может потратить весь ваш баланс токенов без дополнительного уведомления или согласия. Защитите себя, установив более низкий лимит расходов.", "description": "$1 is a warning icon with text 'Be careful' in 'warning' colour" @@ -4789,6 +6037,9 @@ "weak": { "message": "Слабый" }, + "web3": { + "message": "Web3" + }, "web3ShimUsageNotification": { "message": "Мы заметили, что текущий веб-сайт пытался использовать удаленный API window.web3. Если сайт не работает, нажмите $1 для получения дополнительной информации.", "description": "$1 is a clickable link." @@ -4829,10 +6080,6 @@ "whatsThis": { "message": "Что это?" }, - "xOfY": { - "message": "$1 из $2", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$1 из $2 ожидающих", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" @@ -4840,6 +6087,9 @@ "yes": { "message": "Да" }, + "you": { + "message": "Вы" + }, "youHaveAddedAll": { "message": "Вы добавили все популярные сети. Вы можете открыть для себя больше сетей $1 или можете $2", "description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'" @@ -4862,6 +6112,12 @@ "yourPrivateSeedPhrase": { "message": "Ваша личная секретная фраза для восстановления" }, + "yourTransactionConfirmed": { + "message": "Транзакция уже подтверждена" + }, + "yourTransactionJustConfirmed": { + "message": "Нам не удалось отменить вашу транзакцию до ее подтверждения в блокчейне." + }, "zeroGasPriceOnSpeedUpError": { "message": "Нулевая цена газа при ускорении" } diff --git a/app/_locales/sk/messages.json b/app/_locales/sk/messages.json index 944422083c69..a136cc940f79 100644 --- a/app/_locales/sk/messages.json +++ b/app/_locales/sk/messages.json @@ -602,9 +602,6 @@ "send": { "message": "Odeslat" }, - "sendTokens": { - "message": "Odeslat tokeny" - }, "settings": { "message": "Nastavení" }, diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json index 244e8be17993..bfc2a7d8b1d1 100644 --- a/app/_locales/sl/messages.json +++ b/app/_locales/sl/messages.json @@ -618,9 +618,6 @@ "send": { "message": "Pošlji" }, - "sendTokens": { - "message": "Pošlji žetone" - }, "settings": { "message": "Nastavitve" }, diff --git a/app/_locales/sr/messages.json b/app/_locales/sr/messages.json index ae1228074921..eaf957f685d7 100644 --- a/app/_locales/sr/messages.json +++ b/app/_locales/sr/messages.json @@ -621,9 +621,6 @@ "send": { "message": "Пошаљи" }, - "sendTokens": { - "message": "Pošalji tokene" - }, "settings": { "message": "Podešavanja" }, diff --git a/app/_locales/sv/messages.json b/app/_locales/sv/messages.json index 32ebce7028b4..2f130ff20383 100644 --- a/app/_locales/sv/messages.json +++ b/app/_locales/sv/messages.json @@ -614,9 +614,6 @@ "send": { "message": "Skicka" }, - "sendTokens": { - "message": "Skicka tokens" - }, "settings": { "message": "Inställningar" }, diff --git a/app/_locales/sw/messages.json b/app/_locales/sw/messages.json index 44303dbbf6cb..652a45bdcf27 100644 --- a/app/_locales/sw/messages.json +++ b/app/_locales/sw/messages.json @@ -608,9 +608,6 @@ "send": { "message": "Tuma" }, - "sendTokens": { - "message": "Tuma Vianzio" - }, "settings": { "message": "Mipangilio" }, diff --git a/app/_locales/ta/messages.json b/app/_locales/ta/messages.json index 1e47cf563a0c..d1277cdb0e52 100644 --- a/app/_locales/ta/messages.json +++ b/app/_locales/ta/messages.json @@ -359,9 +359,6 @@ "send": { "message": "அனுப்பு" }, - "sendTokens": { - "message": "டோக்கன்களை அனுப்பவும்" - }, "settings": { "message": "அமைப்புகள்" }, diff --git a/app/_locales/th/messages.json b/app/_locales/th/messages.json index 186ce473d859..05f4970d383a 100644 --- a/app/_locales/th/messages.json +++ b/app/_locales/th/messages.json @@ -323,9 +323,6 @@ "send": { "message": "ส่ง" }, - "sendTokens": { - "message": "ส่งโทเค็น" - }, "settings": { "message": "การตั้งค่า" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 1127db132f1c..4a570071faa5 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -130,12 +130,21 @@ "account": { "message": "Account" }, + "accountActivity": { + "message": "Aktibidad ng account" + }, + "accountActivityText": { + "message": "Piliin ang mga account na nais mong makakuha ng abiso:" + }, "accountDetails": { "message": "Mga detalye ng account" }, "accountIdenticon": { "message": "Identicon ng Account" }, + "accountIsntConnectedToastText": { + "message": "Hindi nakakoneka ang $1 sa $2" + }, "accountName": { "message": "Pangalan ng Account" }, @@ -153,6 +162,12 @@ "accountSelectionRequired": { "message": "Kailangan mong pumili ng account!" }, + "accounts": { + "message": "Mga Account" + }, + "accountsConnected": { + "message": "Mga konektadong account" + }, "active": { "message": "Aktibo" }, @@ -243,6 +258,9 @@ "addIPFSGateway": { "message": "Idagdag ang mas gusto mong IPFS gateway" }, + "addImportAccount": { + "message": "Magdagdag ng account o wallet na hardware" + }, "addMemo": { "message": "Magdagdag ng memo" }, @@ -256,6 +274,9 @@ "message": "Ang koneksyon sa network na ito ay umaasa sa mga third party. Ang koneksyon na ito ay maaaring hindi gaanong maaasahan o binibigyang-daan ang mga third-party na mag-track ng aktibidad. $1", "description": "$1 is Learn more link" }, + "addNewAccount": { + "message": "Magdagdag ng bagong account" + }, "addNewToken": { "message": "Magdagdag ng bagong token" }, @@ -265,6 +286,12 @@ "addNfts": { "message": "Magdagdag ng mga NFT" }, + "addSnapAccountToggle": { + "message": "Paganahin ang \"Idagdag ang account Snap (Beta)\"" + }, + "addSnapAccountsDescription": { + "message": "Ang pag-on sa feature na ito ay magbibigay sa iyo ng opsyong idagdag ang bagong Beta account Snaps mula mismo sa listahan ng iyong account. Kung nag-install ka ng account Snap, tandaan na ito ay isang serbisyo ng third-party." + }, "addSuggestedNFTs": { "message": "Magdagdag ng mga iminumungkahing NFT" }, @@ -281,6 +308,9 @@ "addingCustomNetwork": { "message": "Nagdaragdag ng Network" }, + "addingTokens": { + "message": "Nagdaragdag ng mga token" + }, "address": { "message": "Address" }, @@ -316,9 +346,27 @@ "airgapVault": { "message": "AirGap Vault" }, + "alert": { + "message": "Alerto" + }, + "alertBannerMultipleAlertsDescription": { + "message": "Kung aaprubahan mo ang kahilingang ito, maaaring kunin ng third party na kilala sa mga panloloko ang lahat asset mo." + }, + "alertBannerMultipleAlertsTitle": { + "message": "Iba't ibang alerto!" + }, "alertDisableTooltip": { "message": "Puwede itong baguhin sa \"Mga Setting > Mga Alerto\"" }, + "alertModalAcknowledge": { + "message": "Kinikilala ko ang panganib at nais ko pa rin magpatuloy" + }, + "alertModalDetails": { + "message": "Mga Detalye ng Alerto" + }, + "alertModalReviewAllAlerts": { + "message": "Suriin ang lahat ng alerto" + }, "alertSettingsUnconnectedAccount": { "message": "Nagba-browse sa isang website na may napiling hindi konektadong account" }, @@ -334,6 +382,9 @@ "alerts": { "message": "Mga Alerto" }, + "all": { + "message": "Lahat" + }, "allCustodianAccountsConnectedSubtitle": { "message": "Alinman sa nakakonekta na ang lahat ng iyong custodian account o wala kang anumang account na nakakonekta sa MetaMask Institutional." }, @@ -344,23 +395,26 @@ "message": "Lahat ng iyong $1", "description": "$1 is the symbol or name of the token that the user is approving spending" }, + "allPermissions": { + "message": "Lahat ng Pahintulot" + }, "allYourNFTsOf": { "message": "Lahat ng iyong NFT mula sa $1", "description": "$1 is a link to contract on the block explorer when we're not able to retrieve a erc721 or erc1155 name" }, - "allowExternalExtensionTo": { - "message": "Payagan ang external extension na ito na:" + "allow": { + "message": "Payagan" + }, + "allowMmiToConnectToCustodian": { + "message": "Papayagan nito ang MMI na kumonekto sa $1 para i-import ang iyong mga account." + }, + "allowNotifications": { + "message": "Payagan ang mga notipikasyon" }, "allowSpendToken": { "message": "Magbigay ng pahintulot na ma-access ang iyong $1?", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "Payagan ang site na ito na:" - }, - "allowThisSnapTo": { - "message": "Payagan ang snap na ito sa:" - }, "allowWithdrawAndSpend": { "message": "Payagan ang $1 na mag-withdraw at gastusin ang sumusunod na halaga:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -368,6 +422,23 @@ "amount": { "message": "Halaga" }, + "amountReceived": { + "message": "Halagang Natanggap" + }, + "amountSent": { + "message": "Halagang Ipinadala" + }, + "andForListItems": { + "message": "$1, at $2", + "description": "$1 is the first item, $2 is the last item in a list of items. Used in Snap Install Warning modal." + }, + "andForTwoItems": { + "message": "$1 at $2", + "description": "$1 is the first item, $2 is the second item. Used in Snap Install Warning modal." + }, + "announcements": { + "message": "Mga Anunsiyo" + }, "appDescription": { "message": "Ethereum Wallet sa iyong Browser", "description": "The description of the application" @@ -402,6 +473,10 @@ "approveButtonText": { "message": "Aprubahan" }, + "approveIncreaseAllowance": { + "message": "Itaas ang limitasyon sa paggastos ng $1", + "description": "The token symbol that is being approved" + }, "approveSpendingCap": { "message": "Aprubahan ang limitasyon sa paggastos ng $1", "description": "The token symbol that is being approved" @@ -427,6 +502,10 @@ "message": "Inaprubahan noong $1", "description": "$1 is the approval date for a permission" }, + "approvedOnForAccounts": { + "message": "Inaprubahan sa $1 para sa $2", + "description": "$1 is the approval date for a permission. $2 is the AvatarGroup component displaying account images." + }, "areYouSure": { "message": "Sigurado ka ba?" }, @@ -439,6 +518,12 @@ "attemptSendingAssets": { "message": "Kung tatangkain mong magpadala ng mga asset nang direkta mula sa isang network papunta sa isa pa, maaari itong magresulta sa permanenteng pagkawala ng asset. Siguraduhing gumamit ng bridge." }, + "attemptSendingAssetsWithPortfolio": { + "message": "Maaaring mawala ang iyong mga asset kung susubukan mong ipadala ito mula sa ibang network. Ilipat ang mga pondo nang ligtas sa pagitan ng mga network gamit ang isang bridge, tulad ng $1" + }, + "attemptToCancelSwapForFree": { + "message": "Subukang kanselahin ang swap nang libre" + }, "attemptingConnect": { "message": "Sinusubukang kumonekta sa blockchain." }, @@ -479,6 +564,9 @@ "backupApprovalNotice": { "message": "I-back up ang iyong Lihim na Parirala sa Pagbawi para mapanatiling secure ang iyong wallet at mga pondo." }, + "backupKeyringSnapReminder": { + "message": "Siguraduhin na maaari mong maakses ang anumang account na nilikha ng Snap na ito sa sarili mo bago ito alisin" + }, "backupNow": { "message": "I-back up na" }, @@ -500,6 +588,30 @@ "basic": { "message": "Panimula" }, + "basicConfigurationBannerCTA": { + "message": "I-on ang batayang kapakinabangan" + }, + "basicConfigurationBannerTitle": { + "message": "Naka-off ang batayang kapakinabangan" + }, + "basicConfigurationLabel": { + "message": "Batayang kapakinabangan" + }, + "basicConfigurationModalCheckbox": { + "message": "Nauunawaan ko at nais kong magpatuloy" + }, + "basicConfigurationModalDisclaimerOff": { + "message": "Ibig sabihin nito hindi mo lubos na mao-optimize ang iyong oras sa MetaMask. Ang mga batayang tampok (tulad ng mga detalye ng token, optimal na settings ng gas, at iba pa) ay hindi magiging available para sa iyo." + }, + "basicConfigurationModalDisclaimerOn": { + "message": "Upang ma-optimize ang iyong oras sa MetaMask, kailangan mong i-on ang tampok na ito. Ang mga batayang function (tulad ng mga detalye ng token, optimal na settings ng gas, at iba pa) ay mahalaga sa karanasan sa web3." + }, + "basicConfigurationModalHeadingOff": { + "message": "I-off ang batayang kapakinabangan" + }, + "basicConfigurationModalHeadingOn": { + "message": "I-on ang batayang kapakinabangan" + }, "beCareful": { "message": "Mag-ingat" }, @@ -571,6 +683,9 @@ "blockaidDescriptionTransferFarming": { "message": "Kung aaprubahan mo ang kahilingang ito, kukunin ng third party na kilala sa mga panloloko ang lahat ng asset mo." }, + "blockaidMessage": { + "message": "Pagpapanatili ng privacy - walang data na ibinabahagi sa mga third party. Available sa Arbitrum, Avalanche, BNB chain, Ethereum Mainnet, Linea, Optimism, Polygon, Base at Sepolia." + }, "blockaidTitleDeceptive": { "message": "Ito ay mapanlinlang na kahilingan" }, @@ -586,6 +701,9 @@ "bridge": { "message": "Bridge" }, + "bridgeDontSend": { + "message": "Bridge, huwag ipadala" + }, "browserNotSupported": { "message": "Hindi sinusuportahan ang iyong browser..." }, @@ -598,6 +716,9 @@ "busy": { "message": "Busy" }, + "buyAndSell": { + "message": "Bumili at Magbenta" + }, "buyAsset": { "message": "Bumili ng $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -609,6 +730,10 @@ "buyNow": { "message": "Bilhin Ngayon" }, + "buyToken": { + "message": "Bumili ng $1", + "description": "$1 is the token symbol" + }, "bytes": { "message": "Bytes" }, @@ -618,9 +743,6 @@ "cancel": { "message": "Kanselahin" }, - "cancelEdit": { - "message": "Kanselahin ang Pag-edit" - }, "cancelPopoverTitle": { "message": "Kanselahin ang transaksyon" }, @@ -647,6 +769,9 @@ "chainIdExistsErrorMsg": { "message": "Ang ID ng Chain na ito ay kasalukuyang ginagamit ng $1 network." }, + "chainListReturnedDifferentTickerSymbol": { + "message": "Ang simbolo ng token na ito ay hindi tugma sa pangalan ng network o chaid ID na inilagay. Maraming popular na token ang gumagamit ng magkakatulad ng simbolo, na maaaring gamitin ng mga scammer para lokohin ka na magpadala ka ng mas mahalagang token bilang kapalit. Beripikahin ang lahat bago ka magpatuloy." + }, "chooseYourNetwork": { "message": "Piliin ang iyong network" }, @@ -682,9 +807,19 @@ "close": { "message": "Isara" }, + "closeExtension": { + "message": "Isara ang extension" + }, + "closeWindowAnytime": { + "message": "Maaari mong isara ang window na ito anumang oras." + }, "coingecko": { "message": "CoinGecko" }, + "comboNoOptions": { + "message": "Walang opsyon na nahanap", + "description": "Default text shown in the combo field dropdown if no options." + }, "configureSnapPopupDescription": { "message": "Papaalis ka na ngayon sa MetaMask para ma-configure ang snap na ito." }, @@ -703,12 +838,42 @@ "confirm": { "message": "Kumpirmahin" }, + "confirmAlertModalAcknowledge": { + "message": "Kinikilala ko ang mga alerto at nais ko pa rin magpatuloy" + }, + "confirmAlertModalDetails": { + "message": "Kung mag-sign in ka, maaaring kunin ng third party na kilala sa mga panloloko ang lahat ng iyong mga asset. Mangyaring suriin ang mga alerto bago ka magpatuloy." + }, + "confirmAlertModalTitle": { + "message": "Maaaring nasa panganib ang iyong mga asset" + }, + "confirmConnectCustodianRedirect": { + "message": "Ire-redirect ka namin sa $1 sa pagpindot ng magpatuloy." + }, + "confirmConnectCustodianText": { + "message": "Para ikonekta ang iyong mga account mag-log in sa iyong account sa $1 at pindutin ang button na 'kumonekta sa MMI'." + }, + "confirmConnectionTitle": { + "message": "Kumpirmahin ang koneksyon sa $1" + }, "confirmPassword": { "message": "Kumpirmahin ang password" }, "confirmRecoveryPhrase": { "message": "Kumpirmahin ang Lihim na Parirala sa Pagbawi" }, + "confirmTitleDescContractInteractionTransaction": { + "message": "Kumpirmahin lamang ang transaksyong ito kung ganap mong nauunawaan ang nilalaman at nagtitiwala sa site na humihiling." + }, + "confirmTitleDescSignature": { + "message": "Kumpirmahin lamang ang mensaheng ito kung ganap mong nauunawaan ang nilalaman at nagtitiwala sa site na humihiling." + }, + "confirmTitleSignature": { + "message": "Kahilingan sa paglagda" + }, + "confirmTitleTransaction": { + "message": "Hiling na Transaksyon" + }, "confirmed": { "message": "Nakumpirma" }, @@ -724,9 +889,15 @@ "connect": { "message": "Kumonekta" }, + "connectAccount": { + "message": "Ikonekta ang account" + }, "connectAccountOrCreate": { "message": "Ikonekta ang account o gumawa ng bago" }, + "connectAccounts": { + "message": "Ikonekta ang mga account" + }, "connectCustodialAccountMenu": { "message": "Ikonekta ang Custodial Account" }, @@ -736,36 +907,25 @@ "connectCustodialAccountTitle": { "message": "Mga Custodial Account" }, + "connectCustodianAccounts": { + "message": "Kumonekta sa $1 account" + }, "connectManually": { "message": "Manu-manong kumonekta sa kasalukuyang site" }, + "connectMoreAccounts": { + "message": "Ikonekta ang higit pang mga account" + }, "connectSnap": { "message": "Ikonekta ang $1", "description": "$1 is the snap for which a connection is being requested." }, - "connectTo": { - "message": "Kumonekta sa $1", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "Ikonekta sa lahat ng iyong $1", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "mga account", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "Kumonekta sa $1", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "Mga $1 account", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "Kumonekta sa MetaMask" }, + "connectedAccounts": { + "message": "Mga konektadong account" + }, "connectedAccountsDescriptionPlural": { "message": "Mayroon kang $1 account na nakakonekta sa site na ito.", "description": "$1 is the number of accounts" @@ -776,6 +936,13 @@ "connectedAccountsEmptyDescription": { "message": "Ang MetaMask ay hindi konektado sa site na ito. Upang kumonekta sa isang web3 site, hanapin at i-click ang button na kumonekta." }, + "connectedAccountsListTooltip": { + "message": "Maaaring makita ng $1 ang balanse ng account, address, aktibidad, at magmungkahi ng mga transaksyon na aprubahan para sa mga konektadong account.", + "description": "$1 is the origin name" + }, + "connectedAccountsToast": { + "message": "In-update ang mga konektadong account" + }, "connectedSites": { "message": "Mga konektadong site" }, @@ -787,12 +954,21 @@ "message": "Ang $1 ay hindi nakakonekta sa anumang site.", "description": "$1 is the account name" }, + "connectedSnapAndNoAccountDescription": { + "message": "Konektado ang MetaMask sa site na ito, ngunit wala pang mga account ang konektado" + }, + "connectedWith": { + "message": "Nakakonekta sa" + }, "connecting": { "message": "Kumokonekta..." }, "connectingTo": { "message": "Kumokonekta sa $1" }, + "connectingToDeprecatedNetwork": { + "message": "Ang '$1' ay itinitigil na at maaaring hindi gumana. Sumubok muli ng ibang network." + }, "connectingToGoerli": { "message": "Kumokonekta sa Goerli Test Network" }, @@ -802,6 +978,9 @@ "connectingToLineaMainnet": { "message": "Kumokonekta sa Linea Mainnet" }, + "connectingToLineaSepolia": { + "message": "Kumokonekta sa Linea Sepolia test network" + }, "connectingToMainnet": { "message": "Kumokonekta sa Mainnet ng Ethereum" }, @@ -831,6 +1010,12 @@ "continue": { "message": "Magpatuloy" }, + "continueMmiOnboarding": { + "message": "Magpatuloy sa onboarding sa MetaMask Institutional" + }, + "continueToWallet": { + "message": "Magpatuloy sa wallet" + }, "contract": { "message": "Kontrata" }, @@ -882,6 +1067,9 @@ "copyAddress": { "message": "Kopyahin ang address sa clipboard" }, + "copyPrivateKey": { + "message": "Kopyahin ang pribadong key" + }, "copyRawTransactionData": { "message": "Kopyahin ang raw na data ng transaksyon" }, @@ -900,6 +1088,15 @@ "createPassword": { "message": "Gumawa ng password" }, + "createSnapAccountDescription": { + "message": "Ang $1 ay nais na magdagdag ng bagong account sa MetaMask." + }, + "createSnapAccountTitle": { + "message": "Gumawa ng account" + }, + "crossChainSwapsLink": { + "message": "Mag-swap sa mga network gamit ang MetaMask Portfolio" + }, "cryptoCompare": { "message": "CryptoCompare" }, @@ -955,6 +1152,12 @@ "custodianAccountAddedTitle": { "message": "Naidagdag na ang mga napiling custodian account." }, + "custodianQRCodeScan": { + "message": "I-scan ang QR code gamit ang iyong $1 mobile app" + }, + "custodianQRCodeScanDescription": { + "message": "O mag-login sa iyong $1 account at pindutin ang button na 'Kumonekta sa MMI'" + }, "custodianReplaceRefreshTokenChangedFailed": { "message": "Magpunta sa $1 at i-click ang button na 'Ikonekta sa MMI' sa loob ng kanilang user interface para ikonektang muli ang iyong mga account sa MMI." }, @@ -1025,6 +1228,12 @@ "customerSupport": { "message": "suporta sa kostumer" }, + "customizeYourNotifications": { + "message": "I-customize ang mga notipikasyon mo" + }, + "customizeYourNotificationsText": { + "message": "I-on ang mga uri ng notipikasyon na nais mong matanggap:" + }, "dappRequestedSpendingCap": { "message": "Humiling ang site ng limitasyon sa paggastos" }, @@ -1108,6 +1317,18 @@ "deposit": { "message": "Deposito" }, + "deprecatedGoerliNtwrkMsg": { + "message": "Dahil sa mga update sa sistema ng Ethereum, ang Goerli test network malapit nang itigil." + }, + "deprecatedNetwork": { + "message": "Ang network na ito ay hindi na suportado" + }, + "deprecatedNetworkButtonMsg": { + "message": "Nakuha ko" + }, + "deprecatedNetworkDescription": { + "message": "Ang network na sinusubukan mong ikonekta ay hindi na suportado ng Metamask. $1" + }, "description": { "message": "Deskripsyon" }, @@ -1115,110 +1336,20 @@ "message": "Deskripsyon mula sa $1", "description": "$1 represents the name of the snap" }, - "desktopApp": { - "message": "Desktop App" - }, - "desktopConnectionCriticalErrorDescription": { - "message": "Maaaring paulit-ulit ang error na ito, kaya subukang i-restart ang extension o huwag paganahin ang MetaMask Desktop." - }, - "desktopConnectionCriticalErrorTitle": { - "message": "Nagkaroon ng problema sa pagsisimula ang MetaMask" - }, - "desktopConnectionLostErrorDescription": { - "message": "Siguraduhing mayroon kang desktop app at gumagana ito o huwag paganahin ang MetaMask Desktop." - }, - "desktopConnectionLostErrorTitle": { - "message": "Nawala ang koneksyon sa MetaMask Desktop" - }, - "desktopDisableButton": { - "message": "Huwag paganahin ang Desktop App" - }, - "desktopDisableErrorCTA": { - "message": "Huwag paganahin ang MetaMask Desktop" - }, - "desktopEnableButton": { - "message": "Paganahin ang Desktop App" - }, - "desktopEnableButtonDescription": { - "message": "I-click para paganahin ang lahat ng proseso sa background sa desktop app." - }, - "desktopErrorNavigateSettingsCTA": { - "message": "Bumalik sa Pahina ng Mga Setting" - }, - "desktopErrorRestartMMCTA": { - "message": "I-restart ang MetaMask" - }, - "desktopNotFoundErrorCTA": { - "message": "I-download ang MetaMask Desktop" - }, - "desktopNotFoundErrorDescription1": { - "message": "Siguraduhing nakabukas at gumagana ang iyong desktop app." - }, - "desktopNotFoundErrorDescription2": { - "message": "Kung wala kang naka-install na desktop app, mangyaring i-download ito sa website ng MetaMask." - }, - "desktopNotFoundErrorTitle": { - "message": "Ang MetaMask Desktop ay hindi natagpuan" - }, - "desktopOpenOrDownloadCTA": { - "message": "Buksan ang MetaMask Desktop" - }, - "desktopOutdatedErrorCTA": { - "message": "I-update ang MetaMask Desktop" - }, - "desktopOutdatedErrorDescription": { - "message": "Kailangang i-upgrade ang iyong MetaMask desktop app." - }, - "desktopOutdatedErrorTitle": { - "message": "Luma na ang MetaMask Desktop" - }, - "desktopOutdatedExtensionErrorCTA": { - "message": "I-update ang Extension ng MetaMask" - }, - "desktopOutdatedExtensionErrorDescription": { - "message": "Kailangang i-upgrade ang iyong extension ng MetaMask." - }, - "desktopOutdatedExtensionErrorTitle": { - "message": "Luma na ang Extension ng MetaMask" - }, - "desktopPageDescription": { - "message": "Kapag matagumpay ang pagpapares, magre-restart ang extension at kailangan mong ilagay muli ang iyong password." - }, - "desktopPageSubTitle": { - "message": "Buksan ang iyong MetaMask Desktop at i-type ang code na ito" - }, - "desktopPageTitle": { - "message": "Ipares sa Desktop" - }, - "desktopPairedWarningDeepLink": { - "message": "Pumunta sa Mga Setting sa MetaMask Desktop" - }, - "desktopPairedWarningDescription": { - "message": "Kung gusto mong magsimula ng bagong pairing, alisin ang kasalukuyang koneksyon." - }, - "desktopPairedWarningTitle": { - "message": "Nakapares na ang MM Desktop" - }, - "desktopPairingExpireMessage": { - "message": "Mapapaso na ang code sa loob ng $1 segundo" - }, - "desktopRouteNotFoundErrorDescription": { - "message": "desktopRouteNotFoundErrorDescription" + "details": { + "message": "Mga Detalye" }, - "desktopRouteNotFoundErrorTitle": { - "message": "desktopRouteNotFoundErrorTitle" + "developerOptions": { + "message": "Mga Opsyon ng Developer" }, - "desktopUnexpectedErrorCTA": { - "message": "Bumalik sa MetaMask Home" + "developerOptionsResetStatesAnnouncementsDescription": { + "message": "Ang mga reset ay ipinapakita sa boolean para maging false sa lahat ng anunsiyo. Ang mga anunisyo ay mga notipikasyon na ipinapakita sa What's New popup modal." }, - "desktopUnexpectedErrorDescription": { - "message": "Suriin ang iyong MetaMask Desktop para maibalik ang koneksyon" + "developerOptionsResetStatesOnboarding": { + "message": "Nire-reset ang iba't ibang estado kaugnay sa onboarding at nire-redirect sa \"Secure Your Wallet\" onboarding page." }, - "desktopUnexpectedErrorTitle": { - "message": "Nagkaproblema..." - }, - "details": { - "message": "Mga Detalye" + "developerOptionsServiceWorkerKeepAlive": { + "message": "Magreresulta sa isang timestamp na tuloy-tuloy na naka-save sa session.storage" }, "disabledGasOptionToolTipMessage": { "message": "Ang “$1” ay hindi pinagagana dahil hindi nito naabot ang pinakamababang 10% na dagdag mula sa orihinal na bayad sa gas.", @@ -1233,12 +1364,38 @@ "disconnectAllAccountsConfirmationDescription": { "message": "Sigurado ka bang gusto mong idiskonekta? Maaaring mawala ang functionality ng site." }, + "disconnectAllAccountsText": { + "message": "mga account" + }, + "disconnectAllSnapsText": { + "message": "Mga Snap" + }, + "disconnectAllText": { + "message": "Kapag idiniskonekta mo ang iyong $1 mula sa $2, kailangan mong muling ikonekta para gamitin muli.", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`, $2 represents the website hostname" + }, + "disconnectAllTitle": { + "message": "Idiskonekta ang lahat ng $1", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`" + }, "disconnectPrompt": { "message": "Idiskonekta $1" }, "disconnectThisAccount": { "message": "Idiskonekta ang account na ito" }, + "disconnectedAllAccountsToast": { + "message": "Nadiskonekta ang lahat ng account mula sa $1", + "description": "$1 is name of the dapp`" + }, + "disconnectedSingleAccountToast": { + "message": "Ang $1 ay nadiskonekta mula sa $2", + "description": "$1 is name of the name and $2 represents the dapp name`" + }, + "discoverSnaps": { + "message": "Diskubrehin ang mga Snap", + "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." + }, "dismiss": { "message": "I-dismiss" }, @@ -1248,9 +1405,21 @@ "dismissReminderField": { "message": "I-dismiss ang back up na paalala ng Lihim na Parirala sa Pagbawi" }, + "displayNftMedia": { + "message": "Ipakita ang NFT media" + }, + "displayNftMediaDescription": { + "message": "Ang pagpapakita ng NFT media at data ay naglalantad sa iyong IP address sa OpenSea o sa ibang mga third party. Maaari nitong payagan ang mga umaatake na iugnay ang iyong IP address sa iyong Ethereum address. Umaasa ang awtomatikong pagtuklas ng NFT sa setting na ito, at hindi magagamit kapag naka-off ito." + }, + "doNotShare": { + "message": "Huwag ibahagi ito sa sinuman" + }, "domain": { "message": "Domain" }, + "domainNotSupportedOnNetwork": { + "message": "Hindi sinusuportahan ng network ang domain lookup" + }, "done": { "message": "Tapos na" }, @@ -1269,6 +1438,9 @@ "downloadStateLogs": { "message": "I-download ang mga log ng estado" }, + "dragAndDropBanner": { + "message": "Maaari mong i-drag ang mga network para isaayos ang mga ito. " + }, "dropped": { "message": "Binitawan" }, @@ -1367,6 +1539,9 @@ "editSpeedUpEditGasFeeModalTitle": { "message": "I-edit ang pagpapabilis ng bayad sa gas" }, + "enable": { + "message": "Payagan" + }, "enableAutoDetect": { "message": " Paganahin ang autodetect" }, @@ -1397,6 +1572,18 @@ "enhancedTokenDetectionAlertMessage": { "message": "Ang pinahusay na pagtuklas ng token ay kasalukuyang magagamit sa $1. $2" }, + "ensDomainsSettingDescriptionIntroduction": { + "message": "Pinahihintulutan ng MetaMask na makita mo ang mga ENS mula mismo sa address bar ng iyong browser. Here's how it works:" + }, + "ensDomainsSettingDescriptionOutroduction": { + "message": "Mangyaring tandaan na ang paggamit ng tampok na ito ay naglalantad sa iyong IP address sa serbisyong third party." + }, + "ensDomainsSettingDescriptionPart1": { + "message": "Sinusuri ng MetaMask ang kontrata ng ENS ng Ethereum para mahanap ang code na konektado sa pangalan ng ENS." + }, + "ensDomainsSettingDescriptionPart2": { + "message": "Kung ang code ay naka-link sa IPFS, maaari mong makita ang content na kaugnay rito (kadalasan ay website)." + }, "ensDomainsSettingTitle": { "message": "Ipinapakita ang mga ENS domain sa address bar" }, @@ -1438,6 +1625,9 @@ "message": "Mga Detalye ng Error", "description": "Title for collapsible section that displays error details for debugging purposes" }, + "errorGettingSafeChainList": { + "message": "May error habang kinukuha ang ligtas na chain list, mangyaring magpatuloy nang may pag-iingat." + }, "errorMessage": { "message": "Mensahe: $1", "description": "Displayed error message for debugging purposes. $1 is the error message" @@ -1469,6 +1659,9 @@ "message": "Error sa $1", "description": "$1 represents the name of the snap" }, + "estimatedFee": { + "message": "Tinatayang singil" + }, "ethGasPriceFetchWarning": { "message": "Ang backup na presyo ng gas ay ibinigay dahil ang pangunahing serbisyo ng pagtantya ng gas ay hindi available sa ngayon." }, @@ -1495,12 +1688,24 @@ "message": "Eksperimental" }, "extendWalletWithSnaps": { - "message": "I-customize ang iyong karanasan sa wallet.", + "message": "Tuklasin ang mga Snap na binuo ng komunidad para i-customize ang iyong karanasan sa web3", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "extensionInsallCompleteDescription": { + "message": "Bumalik sa onboarding ng produkto ng MetaMask Institutional para ikonekta ang iyong custodial o self-custodial na mga account." + }, + "extensionInsallCompleteTitle": { + "message": "Kumpleto na ang pag-install ng extension" + }, "externalExtension": { "message": "External Extension" }, + "externalNameSourcesSetting": { + "message": "Mga mungkahing palayaw" + }, + "externalNameSourcesSettingDescription": { + "message": "Kami ay kukuha ng ilang mungkahing palayaw para sa mga address na nakikipag-ugnayan ka mula sa mga third-party source tulad ng Etherscan, Infura, at Lens Protocol. Ang mga source na ito ay maaaring makita ang mga address na ito at ang iyong iyong IP address. Ang iyong address ay hindi ilalantad sa mga third party." + }, "failed": { "message": "Nabigo" }, @@ -1519,6 +1724,9 @@ "feeAssociatedRequest": { "message": "May nauugnay na bayad para sa kahilingang ito." }, + "feeDetails": { + "message": "Mga detalye ng singil" + }, "fiat": { "message": "Fiat", "description": "Exchange type" @@ -1551,6 +1759,9 @@ "message": "Tinatanggap ko ang mga panganib", "description": "this text is shown on a button, which the user presses to confirm they understand the risks of using Flask" }, + "floatAmountToken": { + "message": "Ang halaga ng token ay dapat isang integer" + }, "followUsOnTwitter": { "message": "I-follow kami sa Twitter" }, @@ -1573,6 +1784,9 @@ "fromTokenLists": { "message": "Mula sa mga listahan ng token: $1" }, + "function": { + "message": "Function: $1" + }, "functionApprove": { "message": "Function: Aprubahan" }, @@ -1582,6 +1796,13 @@ "functionType": { "message": "Uri ng Function" }, + "fundYourWallet": { + "message": "Pondohan ang iyong wallet" + }, + "fundYourWalletDescription": { + "message": "Magsimula sa pamamagitan ng pagdagdag ng $1 sa iyong wallet.", + "description": "$1 is the token symbol" + }, "gas": { "message": "Gas" }, @@ -1592,6 +1813,9 @@ "message": "Ang bayad sa gas na ito ay iminungkahi ng $1. Ang pag-override dito ay maaaring magdulot ng problema sa iyong transaksyon. Mangyaring makipag-ugnayan sa $1 kung mayroon kang mga tanong.", "description": "$1 represents the Dapp's origin" }, + "gasIsETH": { + "message": "Ang gas ay $1 " + }, "gasLimit": { "message": "Limitasyon ng gas" }, @@ -1636,6 +1860,9 @@ "message": "$1 oras", "description": "$1 represents a number of hours" }, + "gasTimingLow": { + "message": "Mabagal" + }, "gasTimingMinutesShort": { "message": "$1 min", "description": "$1 represents a number of minutes" @@ -1650,15 +1877,29 @@ "general": { "message": "Pangkalahatan" }, - "globalTitle": { - "message": "Global menu" + "generalCameraError": { + "message": "Hindi namin ma-access ang iyong camera. Mangyaring subukan ulit." + }, + "generalCameraErrorTitle": { + "message": "Nagkaproblema...." + }, + "genericExplorerView": { + "message": "Tingnan ang account sa $1" }, - "globalTourDescription": { - "message": "Tingnan ang iyong portfolio, mga nakakonektang site, setting at marami pang iba" + "getStartedWithNFTs": { + "message": "Kumuha ng $1 para bumili ng mga NFT", + "description": "$1 is the token symbol" + }, + "getStartedWithNFTsDescription": { + "message": "Magsimula sa mga NFT sa pamamagitan ng pagdagdag ng $1 sa iyong wallet.", + "description": "$1 is the token symbol" }, "goBack": { "message": "Bumalik" }, + "goToSite": { + "message": "Magpunta sa site" + }, "goerli": { "message": "Goerli Test Network" }, @@ -1700,15 +1941,24 @@ "hexData": { "message": "Hex na data" }, + "hiddenAccounts": { + "message": "Nakatagong mga account" + }, "hide": { "message": "Itago" }, + "hideAccount": { + "message": "Itago ang account" + }, "hideFullTransactionDetails": { "message": "Itago ang buong detalye ng transaksyon" }, "hideSeedPhrase": { "message": "Itago ang pariralang binhi" }, + "hideSentitiveInfo": { + "message": "Itago ang sensitibong impormasyon" + }, "hideToken": { "message": "Itago ang token" }, @@ -1790,6 +2040,9 @@ "ignoreTokenWarning": { "message": "Kung itatago mo ang mga token, hindi ipapakita ang mga ito sa iyong wallet. Gayunpaman, maaari mo pa ring idagdag ang mga ito sa pamamagitan ng paghahanap sa kanila." }, + "imToken": { + "message": "imToken" + }, "import": { "message": "Mag-import", "description": "Button to import an account from a selected file" @@ -1848,6 +2101,9 @@ "importTokensCamelCase": { "message": "Mag-import ng mga token" }, + "importTokensError": { + "message": "Hindi namin ma-import ang mga token. Pakisubukan ulit mamaya." + }, "importWithCount": { "message": "Mag-import ng $1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -1866,6 +2122,9 @@ "initialTransactionConfirmed": { "message": "Nakumpirma na ng network ang iyong inisyal na transaksyon. I-click ang OK para bumalik." }, + "inlineAlert": { + "message": "Alerto" + }, "inputLogicEmptyState": { "message": "Maglagay lamang ng numero na komportable ka sa paggastos ng third party ngayon o sa hinaharap. Maaari mong palaging taasan ang limitasyon sa paggastos sa ibang pagkakataon." }, @@ -1876,6 +2135,27 @@ "inputLogicHigherNumber": { "message": "Pinapayagan nito ang third party na gastusin ang lahat ng balanse ng iyong token hanggang sa maabot nito ang limitasyon o bawiin mo ang limitasyon sa paggastos. Kung hindi ito nilayon, isaalang-alang ang pagtatakda ng mas mababang limitasyon sa paggastos." }, + "insightWarning": { + "message": "babala" + }, + "insightWarningCheckboxMessage": { + "message": "$1 ang hiling ni $2", + "description": "$1 is the action i.e. sign, confirm. $2 is the origin making the request." + }, + "insightWarningContentPlural": { + "message": "Suriin ang $1 bago ang $2. Kapag nagawa na, ang $3 ay hindi na mapapawalang-bisa.", + "description": "$1 the 'insightWarnings' message (2 warnings) representing warnings, $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningContentSingular": { + "message": "Suriin ang $1 bago ang $2. Kapag nagawa na, ang $3 ay hindi na mapapawalang-bisa.", + "description": "$1 is the 'insightWarning' message (1 warning), $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningHeader": { + "message": "Ang hiling na ito ay maaaring mapanganib" + }, + "insightWarnings": { + "message": "mga babala" + }, "insightsFromSnap": { "message": "Mga kaalaman mula sa $1", "description": "$1 represents the name of the snap" @@ -1883,9 +2163,18 @@ "install": { "message": "I-install" }, + "installExtension": { + "message": "I-install ang extension" + }, + "installExtensionDescription": { + "message": "Ang institution-compliant na bersyon ng nangungunang web3 wallet sa mundo, MetaMask." + }, "installOrigin": { "message": "I-install ang pinagmulan" }, + "installRequest": { + "message": "Idagdag sa MetaMask" + }, "installedOn": { "message": "Na-install sa $1", "description": "$1 is the date when the snap has been installed" @@ -1914,6 +2203,12 @@ "insufficientTokens": { "message": "Hindi sapat ang token." }, + "interactingWith": { + "message": "Nakikipag-ugnayan sa" + }, + "interactingWithTransactionDescription": { + "message": "Sa kontrata na ito ka nakikipag-ugnayan ka. Protektahan ang iyong sarili mula sa mga scammer sa pamamagitan ng pagberipika ng mga detalye." + }, "invalidAddress": { "message": "Di-wastong address" }, @@ -1986,6 +2281,9 @@ "ipfsToggleModalSettings": { "message": "Mga Setting > Seguridad at pagkapribado" }, + "isSigningOrSubmitting": { + "message": "Isang nakaraang transaksyon ay pinipirmahan o ipinapasa" + }, "jazzAndBlockies": { "message": "Ang mga Jazzicon at Blockies ay dalawang magkaibang istilo ng mga natatanging icon na makakatulong sa iyong makilala ang isang account sa isang sulyap." }, @@ -1999,6 +2297,24 @@ "message": "File na JSON", "description": "format for importing an account" }, + "keyringAccountName": { + "message": "Pangalan ng Account" + }, + "keyringAccountPublicAddress": { + "message": "Pampublikong Address" + }, + "keyringSnapRemovalResult1": { + "message": "Inalis ang $1 $2", + "description": "Displays the result after removal of a keyring snap. $1 is the snap name, $2 is whether it is successful or not" + }, + "keyringSnapRemovalResultNotSuccessful": { + "message": "hindi ", + "description": "Displays the `not` word in $2." + }, + "keyringSnapRemoveConfirmation": { + "message": "I-type ang $1 para kumpirmahin na nais mong alisin ang snap na ito:", + "description": "Asks user to input the name nap prior to deleting the snap. $1 is the snap name" + }, "keystone": { "message": "Keystone" }, @@ -2017,9 +2333,15 @@ "lastSold": { "message": "Huling naibenta" }, + "lavaDomeCopyWarning": { + "message": "Para sa iyong kaligtasan, ang pagpil ng tekstong ito ay hindi available ngayon." + }, "layer1Fees": { "message": "Layer 1 na bayad" }, + "layer2Fees": { + "message": "Layer 2 na bayad" + }, "learnCancelSpeeedup": { "message": "Alamin kung paano sa $1", "description": "$1 is link to cancel or speed up transactions" @@ -2037,9 +2359,21 @@ "learnMoreUpperCase": { "message": "Matuto pa" }, + "learnMoreUpperCaseWithDot": { + "message": "Matuto pa." + }, "learnScamRisk": { "message": "mga panloloko at panganib sa seguridad." }, + "learnToBridge": { + "message": "Matutong mag-bridge" + }, + "leaveMetaMask": { + "message": "Umalis sa MetaMask?" + }, + "leaveMetaMaskDesc": { + "message": "Bibisita ka sa isang site sa labas ng MetaMask. I-double-check ang URL bago magpatuloy." + }, "ledgerAccountRestriction": { "message": "Kailangan mong gamitin ang huli mong account bago ka magdagdag ng panibago." }, @@ -2058,6 +2392,18 @@ "ledgerDeviceOpenFailureMessage": { "message": "Nabigong mabuksan ang Ledger device. Ang iyong Ledger ay maaaring konektado sa ibang software. Pakisara ang Ledger Live o iba pang mga application na konektado sa iyong Ledger device, at subukan muling ikonekta." }, + "ledgerErrorConnectionIssue": { + "message": "Muling ikonekta ang iyong ledger, buksan ang ETH app at subukan muli." + }, + "ledgerErrorDevicedLocked": { + "message": "Naka-lock ang iyong Ledger. I-unlock ito at pagkatapos ay subukan muli." + }, + "ledgerErrorEthAppNotOpen": { + "message": "Para malutas ang isyu, buksan ang ETH application sa iyong device at muling subukan." + }, + "ledgerErrorTransactionDataNotPadded": { + "message": "Ang input data ng transaksyon sa Ethereum ay hindi sapat na naka-pad." + }, "ledgerLiveApp": { "message": "Ledger Live App" }, @@ -2077,6 +2423,9 @@ "lightTheme": { "message": "Maliwanag" }, + "likeToImportToken": { + "message": "Gusto mo bang i-import ang token na ito?" + }, "likeToImportTokens": { "message": "Gusto mo bang i-import ang mga token na ito?" }, @@ -2086,6 +2435,9 @@ "lineaMainnet": { "message": "Linea Mainnet" }, + "lineaSepolia": { + "message": "Linea Sepolia test network" + }, "link": { "message": "Link" }, @@ -2098,8 +2450,11 @@ "loading": { "message": "Nilo-load..." }, - "loadingNFTs": { - "message": "Nilo-load ang mga NFT..." + "loadingScreenHardwareWalletMessage": { + "message": "Mangyaring kumpletuhin ang transaksyon sa hardware wallet." + }, + "loadingScreenSnapMessage": { + "message": "Mangyaring kumpletuhin ang transaksyon sa Snap." }, "loadingTokens": { "message": "Nilo-load ang Mga Token..." @@ -2146,6 +2501,9 @@ "message": "Siguraduhing walang tumitingin", "description": "Warning to users to be care while creating and saving their new Secret Recovery Phrase" }, + "manageInSettings": { + "message": "Pamahalaan sa mga setting" + }, "max": { "message": "Max" }, @@ -2180,15 +2538,34 @@ "metaMaskConnectStatusParagraphTwo": { "message": "Makikita sa button ng katayuan ng koneksyon kung nakakonekta ang website na binibisita mo sa kasalukuyan mong napiling account." }, + "metadataModalSourceTooltip": { + "message": "Ang $1 ay naka-host sa npm at $2 ang natatanging pagkakailanlan ng Snap.", + "description": "$1 is the snap name and $2 is the snap NPM id." + }, "metamaskInstitutionalVersion": { "message": "Bersyon ng MetaMask Institutional" }, + "metamaskNotificationsAreOff": { + "message": "Hindi active sa kasalukuyan ang mga notipikasyon sa wallet." + }, + "metamaskPortfolio": { + "message": "MetaMask Portfolio." + }, "metamaskSwapsOfflineDescription": { "message": "Kasalukuyang minementina ang MetaMask Swaps. Bumalik sa ibang pagkakataon." }, "metamaskVersion": { "message": "Bersyon ng MetaMask" }, + "methodData": { + "message": "Pamamaraan" + }, + "methodDataTransactionDescription": { + "message": "Ito ang espesipikong aksyon na gagawin. Ang data na ito ay maaaring mapeke, kaya siguraduhin na pinagkakatiwalaan mo ang site sa kabilang panig." + }, + "methodNotSupported": { + "message": "Hindi suportado sa account na ito." + }, "metrics": { "message": "Metrics" }, @@ -2224,11 +2601,17 @@ "mmiBuiltAroundTheWorld": { "message": "Ang MetaMask Institutional ay dinisenyo at binuo sa buong mundo." }, + "mmiNewNFTDetectedInNFTsTabMessage": { + "message": "Hayaan ang MetaMask Institutional na awtomatikong na detect ang mga NFT sa iyong wallet." + }, + "mmiPasswordSetupDetails": { + "message": "Ang password na ito ay maga-unlock sa iyong MetaMask Institutional extension lamang." + }, "more": { "message": "higit pa" }, "multipleSnapConnectionWarning": { - "message": "Gustong kumonekta ng $1 sa $2 (na) snap. Magpatuloy lang kung pinagkakatiwalaan mo ang website na ito.", + "message": "Si $1 ay gustong gumamit ng $2 Snaps", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." }, "mustSelectOne": { @@ -2237,10 +2620,80 @@ "name": { "message": "Pangalan" }, + "nameAddressLabel": { + "message": "Address", + "description": "Label above address field in name component modal." + }, + "nameInstructionsNew": { + "message": "Kung alam mo ang address na ito, bigyan ito ng palayaw para makilala ito sa hinaharap.", + "description": "Instruction text in name component modal when value is not recognised." + }, + "nameInstructionsRecognized": { + "message": "Ang address na ito ay may default na palayaw, ngunit maaari mo itong i-edit o tuklasin ang iba pang mungkahi.", + "description": "Instruction text in name component modal when value is recognized but not saved." + }, + "nameInstructionsSaved": { + "message": "Nagdagdag ka ng palayaw para sa address na ito noon. Maaari mong i-edit o tingnan ang iba pang mungkahing palayaw.", + "description": "Instruction text in name component modal when value is saved." + }, + "nameLabel": { + "message": "Palayaw", + "description": "Label above name input field in name component modal." + }, + "nameModalMaybeProposedName": { + "message": "Baka: $1", + "description": "$1 is the proposed name" + }, + "nameModalTitleNew": { + "message": "Hindi kilalang address", + "description": "Title of the modal created by the name component when value is not recognised." + }, + "nameModalTitleRecognized": { + "message": "Kilalang address", + "description": "Title of the modal created by the name component when value is recognized but not saved." + }, + "nameModalTitleSaved": { + "message": "Nai-save na address", + "description": "Title of the modal created by the name component when value is saved." + }, + "nameProviderProposedBy": { + "message": "Minungkahi ng $1", + "description": "$1 is the name of the provider" + }, + "nameProvider_ens": { + "message": "Ethereum Name Service (ENS)" + }, + "nameProvider_etherscan": { + "message": "Etherscan" + }, + "nameProvider_lens": { + "message": "Lens Protocol" + }, + "nameProvider_token": { + "message": "MetaMask" + }, + "nameSetPlaceholder": { + "message": "Pumili ng palayaw...", + "description": "Placeholder text for name input field in name component modal." + }, + "nativePermissionRequestDescription": { + "message": "Gusto mo bang gawin ng site na ito ang mga sumusunod?", + "description": "Description below header used on Permission Connect screen for native permissions." + }, "nativeToken": { "message": "Ang native token sa network na ito ay $1. Ito ang token na ginagamit para sa mga bayad sa gas.", "description": "$1 represents the name of the native token on the current network" }, + "nativeTokenScamWarningConversion": { + "message": "I-edit ang mga detalye ng network" + }, + "nativeTokenScamWarningDescription": { + "message": "Ang network na ito ay hindi tugma sa kaugnay na chain ID o pangalan nito. Maraming popular na token ang gumagamit ng pangalang $1, kaya nagiging puntirya ito ng mga scam. Maaari kang linlangin ng mga scammer na magpadala sa kanila ng mas mahal na currency bilang kapalit. I-verify ang lahat bago magpatuloy.", + "description": "$1 represents the currency name" + }, + "nativeTokenScamWarningTitle": { + "message": "Isa itong potensyal na scam" + }, "needHelp": { "message": "Kailangan ng tulong? Makipag-ugnayan sa $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -2261,6 +2714,9 @@ "negativeETH": { "message": "Hindi makakapagpadala ng mga negatibong halaga ng ETH." }, + "negativeOrZeroAmountToken": { + "message": "Hindi maaaring magpadala ng negatibo o zero na halaga ng asset." + }, "network": { "message": "Network:" }, @@ -2291,6 +2747,9 @@ "networkNameBSC": { "message": "BSC" }, + "networkNameBase": { + "message": "Base" + }, "networkNameDefinition": { "message": "Ang pangalan ay nauugnay sa network na ito." }, @@ -2300,12 +2759,21 @@ "networkNameGoerli": { "message": "Goerli" }, + "networkNameLinea": { + "message": "Linea" + }, + "networkNameOpMainnet": { + "message": "OP Mainnet" + }, "networkNamePolygon": { "message": "Polygon" }, "networkNameTestnet": { "message": "Testnet" }, + "networkNameZkSyncEra": { + "message": "zkSync Era" + }, "networkProvider": { "message": "Network provider" }, @@ -2358,6 +2826,19 @@ "newContract": { "message": "Bagong kontrata" }, + "newNFTDetectedInImportNFTsMessageStrongText": { + "message": "Settings > Seguridad at pagkapribado" + }, + "newNFTDetectedInImportNFTsMsg": { + "message": "Upang gamitin ang Opensea para makita ang iyong NFT, i-on ang 'I-display ang NFT Media'' sa $1.", + "description": "$1 is used for newNFTDetectedInImportNFTsMessageStrongText" + }, + "newNFTDetectedInNFTsTabMessage": { + "message": "Hayaan ang MetaMask na awtomatikong i-detect at magpakita ng mga NFT sa iyong wallet." + }, + "newNFTsAutodetected": { + "message": "NFT autodetection" + }, "newNetworkAdded": { "message": "Ang “$1” matagumpay na naidagdag!" }, @@ -2367,6 +2848,12 @@ "newPassword": { "message": "Bagong password (min na 8 char)" }, + "newPrivacyPolicyActionButton": { + "message": "Magbasa pa" + }, + "newPrivacyPolicyTitle": { + "message": "Binago namin ang aming patakaran sa pagkapribado" + }, "newTokensImportedMessage": { "message": "Matagumpay mong na-import ang $1.", "description": "$1 is the string of symbols of all the tokens imported" @@ -2388,6 +2875,9 @@ "message": "Ang token na ito ay isang NFT. Idagdag sa $1", "description": "$1 is a clickable link with text defined by the 'importNFTPage' key" }, + "nftAlreadyAdded": { + "message": "Naidagdag na ang NFT." + }, "nftDisclaimer": { "message": "Disclaimer: Kinukuha ng MetaMask ang media file mula sa pinagmulang url. Ang url na ito kung minsan ay pinapalitan ng marketplace kung saan naka-mint ang NFT." }, @@ -2423,12 +2913,21 @@ "noAddressForName": { "message": "Walang naitakdang address para sa pangalang ito." }, + "noConnectedAccountDescription": { + "message": "Pumili ng account na gusto mong gamitin sa site na ito para magpatuloy." + }, + "noConnectedAccountTitle": { + "message": "Ang MetaMask ay hindi nakakonekta sa site na ito" + }, "noConversionDateAvailable": { "message": "Walang available na petsa sa pagpapapalit ng currency" }, "noConversionRateAvailable": { "message": "Hindi available ang rate ng palitan" }, + "noDomainResolution": { + "message": "Walang resolusyon para sa ibinigay na domain." + }, "noNFTs": { "message": "Wala pang mga NFT" }, @@ -2447,6 +2946,9 @@ "noWebcamFoundTitle": { "message": "Hindi nakita ang webcam" }, + "nonCustodialAccounts": { + "message": "Pinapayagan ka ng MetaMask Institutional na gumamit ng mga non-custodial na account, kung plano mong gamitin ang mga account na ito na i-backup ang Lihim na Parirala sa Pagbawi." + }, "nonce": { "message": "Nonce" }, @@ -2477,6 +2979,111 @@ "notePlaceholder": { "message": "Makikita ng nag-apruba ang tala na ito kapag inaprubahan ang transaksyon sa custodian." }, + "notificationDetail": { + "message": "Mga detalye" + }, + "notificationDetailBaseFee": { + "message": "Batayang bayad (GWEI)" + }, + "notificationDetailGasLimit": { + "message": "Limitasyon ng gas (mga unit)" + }, + "notificationDetailGasUsed": { + "message": "Ginamit na gas (mga unit)" + }, + "notificationDetailMaxFee": { + "message": "Pinakamataas na bayad bawat gas" + }, + "notificationDetailNetwork": { + "message": "Network" + }, + "notificationDetailNetworkFee": { + "message": "Bayad sa network" + }, + "notificationDetailPriorityFee": { + "message": "Bayad sa priyoridad (GWEI)" + }, + "notificationItemCheckBlockExplorer": { + "message": "Tingnan sa BlockExplorer" + }, + "notificationItemCollection": { + "message": "Koleksyon" + }, + "notificationItemConfirmed": { + "message": "Nakumpirma" + }, + "notificationItemError": { + "message": "Hindi mabawi ang mga bayarin sa kasalukuyan" + }, + "notificationItemFrom": { + "message": "Mula kay/sa" + }, + "notificationItemLidoStakeReadyToBeWithdrawn": { + "message": "Handa na ang Pag-withdraw" + }, + "notificationItemLidoStakeReadyToBeWithdrawnMessage": { + "message": "Maaari mo ng i-withdraw ang iyong in-unstake na $1" + }, + "notificationItemLidoWithdrawalRequestedMessage": { + "message": "Ang iyong hiling na i-unstake ang $1 ay naipadala na" + }, + "notificationItemNFTReceivedFrom": { + "message": "Nakatanggap ng NFT mula kay/sa" + }, + "notificationItemNFTSentTo": { + "message": "Ipinadala ang NFT kay/sa" + }, + "notificationItemNetwork": { + "message": "Network" + }, + "notificationItemRate": { + "message": "Halaga (kasama ang bayarin)" + }, + "notificationItemReceived": { + "message": "Natanggap" + }, + "notificationItemReceivedFrom": { + "message": "Natanggap mula kay/sa" + }, + "notificationItemSent": { + "message": "Ipinadala" + }, + "notificationItemSentTo": { + "message": "Ipinadala kay/sa" + }, + "notificationItemStakeCompleted": { + "message": "Nakumpleto ang pag-stake" + }, + "notificationItemStaked": { + "message": "Nai-stake" + }, + "notificationItemStakingProvider": { + "message": "Tagapagbigay ng Staking" + }, + "notificationItemStatus": { + "message": "Katayuan" + }, + "notificationItemSwapped": { + "message": "Nai-swap" + }, + "notificationItemSwappedFor": { + "message": "para kay/sa" + }, + "notificationItemTo": { + "message": "Sa/Kay" + }, + "notificationItemTransactionId": { + "message": "ID ng Transaksyon" + }, + "notificationItemUnStakeCompleted": { + "message": "Nakumpleto ang pag-unstake" + }, + "notificationItemUnStaked": { + "message": "Na-unstake" + }, + "notificationItemUnStakingRequested": { + "message": "Hiniling ang pag-unstake" + }, "notificationTransactionFailedMessage": { "message": "Nabigo ang transaksyon $1! $2", "description": "Content of the browser notification that appears when a transaction fails" @@ -2504,43 +3111,6 @@ "notifications": { "message": "Mga Abiso" }, - "notifications20ActionText": { - "message": "Matuto pa", - "description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a ledger page to resolve the U2F connection issue." - }, - "notifications20Description": { - "message": "Kung ikaw ay nasa pinakabagong bersyon ng Firefox, maaari kang makaranas ng isyu na nauugnay sa Firefox dropping U2F support.", - "description": "Description of a notification in the 'See What's New' popup. Describes the U2F support being dropped by firefox and that it affects ledger users." - }, - "notifications20Title": { - "message": "Ang mga User ng Ledger at Firefox ay Nakakaranas ng Isyu sa Koneksyon", - "description": "Title for a notification in the 'See What's New' popup. Tells users that latest firefox users using U2F may experience connection issues." - }, - "notifications24ActionText": { - "message": "Nakuha ko" - }, - "notifications24Description": { - "message": "Ang setting sa paunang gas fee ay matatandaan ngayon ayon sa network na iyong ginagamit. Ibig sabihin maaari mong itakda ang ispesipikong paunang gas fee para sa bawat network at maiwasan ang pagbayad nang sobra para sa gas fee o naiwan na transaksyon." - }, - "notifications24Title": { - "message": "Paunang gas fee ayon sa network" - }, - "notifications8ActionText": { - "message": "Magpunta sa Mga Advanced Setting", - "description": "Description on an action button that appears in the What's New popup. Tells the user that if they click it, they will go to our Advanced settings page." - }, - "notifications8DescriptionOne": { - "message": "Para sa MetaMask v10.4.0, hindi mo na kailangang ikonekta ang Ledger Live sa iyong Ledger device sa MetaMask.", - "description": "Description of a notification in the 'See What's New' popup. Describes changes for how Ledger Live is no longer needed to connect the device." - }, - "notifications8DescriptionTwo": { - "message": "Para sa mas madali at mas maayos na karanasan sa ledger, magpunta sa Advanced tab ng Mga Setting at ilipat sa 'WebHID' ang 'Napiling Uri ng Koneksyon ng Ledger'.", - "description": "Description of a notification in the 'See What's New' popup. Describes how the user can turn off the Ledger Live setting." - }, - "notifications8Title": { - "message": "Pagpapabuti ng koneksyon ng ledger", - "description": "Title for a notification in the 'See What's New' popup. Notifies ledger users that there is an improvement in how they can connect their device." - }, "notificationsDropLedgerFirefoxDescription": { "message": "Hindi na sinusuportahan ng Firefox ang U2F, kaya ang Ledger ay hindi gagana sa MetaMask sa Firefox. Subukan ang MetaMask sa Google Chrome.", "description": "Description of a notification in the 'See What's New' popup. Describes that ledger will not longer be supported for firefox users and they should use MetaMask on chrome for ledger support instead." @@ -2549,33 +3119,37 @@ "message": "Hindi na ipagpapatuloy ang Ledger Support para s Firefox", "description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped." }, - "notificationsEmptyText": { - "message": "Dito mo makikita ang mga notipikasyon mula sa iyong naka-install na snaps." + "notificationsFeatureToggle": { + "message": "Paganahin ang Mga Wallet Notification", + "description": "Experimental feature title" }, - "notificationsHeader": { - "message": "Mga Abiso" - }, - "notificationsInfos": { - "message": "$1 mula $2", - "description": "$1 is the date at which the notification has been dispatched and $2 is the link to the snap that dispatched the notification." + "notificationsFeatureToggleDescription": { + "message": "Pinapagana nito ang mga notipikasyon sa wallet tulad ng pagpapadala/pagtanggap ng mga pondo o nft at anunsiyo sa mga tampok.", + "description": "Description of the experimental notifications feature" }, "notificationsMarkAllAsRead": { "message": "Markahan ang lahat bilang nabasa na" }, - "notificationsOpenBetaSnapsActionText": { - "message": "Matuto pa" + "notificationsPageEmptyTitle": { + "message": "Walang makikita rito" + }, + "notificationsPageErrorContent": { + "message": "Mangyaring subukang bisitahin muli ang pahinang ito." }, - "notificationsOpenBetaSnapsDescriptionOne": { - "message": "🎉 Nasasabik kaming ianunsiyo ang Open Beta ng MetaMask Snaps!" + "notificationsPageErrorTitle": { + "message": "Mayroong naging error" }, - "notificationsOpenBetaSnapsDescriptionThree": { - "message": "Ipersonalisa ang iyong wallet gamit ang mga snap na binuo ng developer community!" + "notificationsPageNoNotificationsContent": { + "message": "Hindi ka pa nakatanggap ng anumang notipikasyon." }, - "notificationsOpenBetaSnapsDescriptionTwo": { - "message": "Ang Snaps ay makakatulong sa iyo na maraming magawa sa MetaMask -- tulad ng kumonekta sa maraming network, tingnan ang mga insight sa transaksyon, at makakuha ng custom na notipikasyon." + "notificationsSettingsBoxError": { + "message": "Nagkaproblema. Pakisubukan muli." }, - "notificationsOpenBetaSnapsTitle": { - "message": "Ipinakikilala ang MetaMask Snaps" + "notificationsSettingsPageAllowNotifications": { + "message": "Manatiling may-alam sa nangyayari sa iyong wallet gamit ang mga notipikasyon. Para gamitin ang mga notipikasyon, gumagamit kami ng profile para i-sync ang ilang mga setting sa lahat ng iyong mga device. $1" + }, + "notificationsSettingsPageAllowNotificationsLink": { + "message": "Matutunan kung paano namin protektahan ang iyong pagkapribado habang gamit ang tampok na ito." }, "numberOfNewTokensDetectedPlural": { "message": "$1 (na) bagong token ang nakita sa account na ito", @@ -2599,6 +3173,9 @@ "on": { "message": "Naka-on" }, + "onboarding": { + "message": "Onboarding" + }, "onboardingAdvancedPrivacyIPFSDescription": { "message": "Ginagawang posible ng IPFS gateway na ma-access at makita ang datos na pinangangasiwaan ng mga third party. Maaari kang magdagdag ng custom na IPFS gateway o magpatuloy sa paggamit ng default." }, @@ -2629,51 +3206,45 @@ "onboardingMetametricsAgree": { "message": "Sumasang-ayon ako" }, - "onboardingMetametricsAllowOptOut": { - "message": "Palagi kang pinapayagan na mag-opt out sa pamamagitan ng Mga Setting" - }, - "onboardingMetametricsDataTerms": { - "message": "Ang datos na ito ay pinagsama-sama at samakatuwid ay hindi nagpapakilala para sa mga layunin ng General Data Protection Regulation (EU) 2016/679." - }, "onboardingMetametricsDescription": { - "message": "Nais ng MetaMask na mangalap ng datos ng paggamit upang mas maunawaan kung paano nakikipag-ugnayan ang aming mga user sa MetaMask. Gagamitin ang datos na ito upang ibigay ang serbisyo, na kinabibilangan ng pagpapabuti ng serbisyo batay sa iyong paggamit." + "message": "Nais naming mangalap ng data para sa batayang paggamit upang mapahusay ang MetaMask. Dapat mong malaman na hindi namin ibebenta ang data na iyong ibibigay rito." }, "onboardingMetametricsDescription2": { - "message": "Ang MetaMask ay..." + "message": "Kapag kami ay nangangalap ng metrics, ito ay palaging..." }, "onboardingMetametricsDisagree": { "message": "Salamat nalang" }, "onboardingMetametricsInfuraTerms": { - "message": "* Kapag ginamit mo ang Infura bilang iyong default na provider ng RPC sa MetaMask, kukunin ng Infura ang iyong IP address at ang iyong Ethereum wallet address kapag nagpadala ka ng transaksyon. Hindi namin iniimbak ang impormasyong ito sa paraan na nagpapahintulot sa aming mga system na iugnay ang dalawang piraso ng data na iyon. Para sa higit pang impormasyon kung paano nakikipag-ugnayan ang MetaMask at Infura mula sa pananaw ng pagkolekta ng data, tingnan ang aming update na $1. Para sa higit pang impormasyon sa aming mga kasanayan sa pagkapribado sa pangkalahatan, tingnan ang aming $2.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" + "message": "Ipapaalam namin sa iyo kung magdesisyon kaming gamitin ang data na ito para sa ibang layunin. Maaari mong suriin ang aming $1 para sa karagdagang impormasyon. Tandaan, maaari kang magpunta sa mga setting at mag-opt out anumang oras.", + "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, "onboardingMetametricsInfuraTermsPolicy": { - "message": "Patakaran sa Pagkapribado dito" - }, - "onboardingMetametricsInfuraTermsPolicyLink": { - "message": "dito" + "message": "Patakaran sa Pagkapribado" }, "onboardingMetametricsModalTitle": { "message": "Magdagdag ng custom na network" }, "onboardingMetametricsNeverCollect": { - "message": "Kinokolekta ng $1 ang impormasyon na hindi namin kailangan para ibigay ang serbisyo (tulad ng mga key, address, hash ng transaksyon, o balanse)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 mga click at view sa app ay nakaimbak, ngunit ang ibang detalye (tulad ng iyong address) ay hindi.", + "description": "$1 represents `onboardingMetametricsNeverCollectEmphasis`" + }, + "onboardingMetametricsNeverCollectEmphasis": { + "message": "Pribado:" }, "onboardingMetametricsNeverCollectIP": { - "message": "Kinokolekta ng $1 ang iyong buong IP address*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 pansamantala naming ginamit ang iyong IP address upang malaman ang pangkalahatang lokasyon (tulad ng iyong bansa o rehiyon), ngunit hindi ito iniimbak.", + "description": "$1 represents `onboardingMetametricsNeverCollectIPEmphasis`" }, - "onboardingMetametricsNeverEmphasis": { - "message": "Hindi kailanman" + "onboardingMetametricsNeverCollectIPEmphasis": { + "message": "Pangkalahatan:" }, "onboardingMetametricsNeverSellData": { - "message": "Ang $1 ay nagbebenta ng datos. Kailanman!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 ikaw ang magdedesisyon kung nais mong ibahagi o burahin ang iyong data sa paggamit sa pamamagitan ng mga setting anumang oras.", + "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" }, - "onboardingMetametricsSendAnonymize": { - "message": "Magpapadala ng mga anonymous na kaganapang pag-click at pagtingin sa page" + "onboardingMetametricsNeverSellDataEmphasis": { + "message": "Opsyonal:" }, "onboardingMetametricsTitle": { "message": "Tulungan kaming mapahusay ang MetaMask" @@ -2714,15 +3285,26 @@ "onboardingPinExtensionTitle": { "message": "Ang pag-install ng iyong MetaMask ay kumpleto na!" }, + "onboardingPinMmiExtensionLabel": { + "message": "I-pin ang MetaMask Institutional" + }, "onboardingUsePhishingDetectionDescription": { "message": "Ang mga alerto sa pagtuklas ng phishing ay umaasa sa komunikasyon sa $1. Ang jsDeliver ay magkakaroon ng access sa iyong IP address. Tingnan ang $2.", "description": "The $1 is the word 'jsDeliver', from key 'jsDeliver' and $2 is the words Privacy Policy from key 'privacyMsg', both separated here so that it can be wrapped as a link" }, + "onekey": { + "message": "OneKey" + }, "onlyAddTrustedNetworks": { "message": "Ang isang mapaminsalang network provider ay maaaring magsinungaling tungkol sa estado ng blockchain at itala ang iyong aktibidad sa network. Magdagdag lamang ng mga custom na network na pinagkakatiwalaan mo." }, "onlyConnectTrust": { - "message": "Kumonekta lang sa mga site na pinagkakatiwalaan mo." + "message": "Kumonekta lang sa mga site na pinagkakatiwalaan mo. $1", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." + }, + "openCustodianApp": { + "message": "Buksan ang $1 app", + "description": "The $1 is the name of the Custodian that will be open" }, "openFullScreenForLedgerWebHid": { "message": "Pumunta sa full screen para ikonekta ang iyong Ledger.", @@ -2734,6 +3316,15 @@ "openSeaNew": { "message": "OpenSea" }, + "openSeaToBlockaidBtnLabel": { + "message": "Galugarin ang mga Snap" + }, + "openSeaToBlockaidDescription": { + "message": "Ang mga alerto sa seguridad ay hindi na available sa network na ito. Ang pag-install ng Snap ay maaaring magpahusay sa iyong seguridad." + }, + "openSeaToBlockaidTitle": { + "message": "Paalala!" + }, "operationFailed": { "message": "Nabigo ang Operasyon" }, @@ -2777,6 +3368,9 @@ "password": { "message": "Password" }, + "passwordMmiTermsWarning": { + "message": "Nauunawaan kong hindi maaaring bawiin ng MetaMask Institutional ang password na ito para sa akin. $1" + }, "passwordNotLongEnough": { "message": "Hindi sapat ang haba ng password" }, @@ -2803,6 +3397,10 @@ "message": "I-paste ang string ng iyong pribadong key dito:", "description": "For importing an account from a private key" }, + "paymasterInUse": { + "message": "Ang gas para sa transaksyon na ito ay babayaran ng isang paymaster.", + "description": "Alert shown in transaction confirmation if paymaster in use." + }, "pending": { "message": "Nakabinbin" }, @@ -2816,18 +3414,26 @@ "message": "Mayroon kang ($1) nakabinbin na transaksyon.", "description": "$1 is count of pending transactions" }, - "permissionRequest": { - "message": "Kahilingan sa pahintulot" + "permissionDetails": { + "message": "Mga detalye ng permiso" }, - "permissionRequestCapitalized": { + "permissionRequest": { "message": "Kahilingan sa pahintulot" }, "permissionRequested": { "message": "Hiniling ngayon" }, + "permissionRequestedForAccounts": { + "message": "Hiniling ngayon para sa $1", + "description": "Permission cell status for requested permission including accounts, rendered as AvatarGroup which is $1." + }, "permissionRevoked": { "message": "Pinawalang-bisa sa update na ito" }, + "permissionRevokedForAccounts": { + "message": "Pinawalang-bisa sa update na ito para sa $1", + "description": "Permission cell status for revoked permission including accounts, rendered as AvatarGroup which is $1." + }, "permission_accessNamedSnap": { "message": "Kumonekta sa $1.", "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." @@ -2836,6 +3442,10 @@ "message": "I-access ang Internet.", "description": "The description of the `endowment:network-access` permission." }, + "permission_accessNetworkDescription": { + "message": "Payagan ang $1 na i-access ang internet. Maaari itong magamit kapwa sa pagpapadala at pagtanggap ng datos sa mga third-party server.", + "description": "An extended description of the `endowment:network-access` permission. $1 is the snap name." + }, "permission_accessSnap": { "message": "Kumonekta sa $1 snap.", "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." @@ -2848,10 +3458,18 @@ "message": "Mag-iskedyul at magsagawa ng mga pana-panahong mga aksyon.", "description": "The description for the `snap_cronjob` permission" }, + "permission_cronjobDescription": { + "message": "Payagan ang $1 na magsagawa ng mga aksyon na tumatakbo nang pana-panahon sa mga takdang oras, petsa, at agwat. Maaari itong gamitin para magpaumpisa ng sensitibo sa oras na mga interaksyon o notipikasyon.", + "description": "An extended description for the `snap_cronjob` permission. $1 is the snap name." + }, "permission_dialog": { "message": "Ipakita ang mga dialog window sa MetaMask.", "description": "The description for the `snap_dialog` permission" }, + "permission_dialogDescription": { + "message": "Payagan ang $1 na magpakita ng mga popup ng MetaMask na may custom na teksto, input field, at mga button para aprubahan o tanggihan ang isang aksyon. \nMaaaring gamitin para gumawa ng hal. mga alerto, kumpirmasyon, at opt-in flow para sa isang snap.", + "description": "An extended description for the `snap_dialog` permission. $1 is the snap name." + }, "permission_ethereumAccounts": { "message": "Tingnan ang mga address, balanse ng account, aktibidad at simulan ang iyong mga transaksyon", "description": "The description for the `eth_accounts` permission" @@ -2860,30 +3478,138 @@ "message": "I-access ang provider ng Ethereum.", "description": "The description for the `endowment:ethereum-provider` permission" }, + "permission_ethereumProviderDescription": { + "message": "Payagan ang $1 na makipag-ugnayan sa MetaMask nang direkta, para mabasa nito ang datos mula sa blockchain at makapagmungkahi ng mga mensahe at transaksyon.", + "description": "An extended description for the `endowment:ethereum-provider` permission. $1 is the snap name." + }, + "permission_getEntropy": { + "message": "Humango ng mga arbitrary key na natatangi sa $1.", + "description": "The description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getEntropyDescription": { + "message": "Payagan ang $1 na humango ng mga arbitrary key na natatangi sa $1, nang hindi inilalantad ang mga ito. Ang mga key na ito ay hiwalay sa iyong (mga) MetaMask account at hindi nauugnay sa iyong mga pribadong key o Lihim na Parirala sa Pagbawi. Hindi maa-access ng ibang mga snap ang impormasyong ito.", + "description": "An extended description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getLocale": { + "message": "Tingnan ang napili mong wika.", + "description": "The description for the `snap_getLocale` permission" + }, + "permission_getLocaleDescription": { + "message": "Payagan ang $1 na i-access ang iyong mas gustong wika mula sa iyong mga setting sa MetaMask. Maaari itong gamitin para i-localize at ipakita ang content ng $1 gamit ang iyong wika.", + "description": "An extended description for the `snap_getLocale` permission. $1 is the snap name." + }, + "permission_homePage": { + "message": "Magpakita ng custom na screen", + "description": "The description for the `endowment:page-home` permission" + }, + "permission_homePageDescription": { + "message": "Hayaan ang $1 na magpakita ng custom na home screen sa MetaMask. Maaari itong gamitin para sa mga user interface, configuration, at mga dashboard.", + "description": "An extended description for the `endowment:page-home` permission. $1 is the snap name." + }, + "permission_keyring": { + "message": "Payagan ang mga kahilingan para sa pagdaragdag at pagkontrol ng mga Ethereum account", + "description": "The description for the `endowment:keyring` permission" + }, + "permission_keyringDescription": { + "message": "Hayaan ang $1 na makatanggap ng mga kahilingan na magdagdag o mag-alis ng mga account, at pumirma at makipagtransaksyon sa ngalan ng mga account na ito.", + "description": "An extended description for the `endowment:keyring` permission. $1 is the snap name." + }, "permission_lifecycleHooks": { "message": "Gumagamit ng mga lifecycle hook.", "description": "The description for the `endowment:lifecycle-hooks` permission" }, + "permission_lifecycleHooksDescription": { + "message": "Payagan ang $1 na gumamit ng mga lifecycle hook para magpatakbo ng code sa mga partikular na oras sa panahon ng lifecycle nito.", + "description": "An extended description for the `endowment:lifecycle-hooks` permission. $1 is the snap name." + }, "permission_manageAccounts": { "message": "Magdagdag at kontrolin ang mga Ethereum account", "description": "The description for `snap_manageAccounts` permission" }, + "permission_manageAccountsDescription": { + "message": "Payagan ang $1 na magdagdag o mag-alis ng mga Ethereum account, at saka makipagtransaksyon at pumirma gamit ang mga account na ito.", + "description": "An extended description for the `snap_manageAccounts` permission. $1 is the snap name." + }, + "permission_manageBip32Keys": { + "message": "Pamahalaan ang mga $1 account.", + "description": "The description for the `snap_getBip32Entropy` permission. $1 is a derivation path, e.g. 'm/44'/0'/0' (secp256k1)'." + }, + "permission_manageBip44AndBip32KeysDescription": { + "message": "Payagan ang $1 na mamahala ng mga account at asset sa hiniling na network. Ang mga account na ito ay hinango at naka-back up gamit ang iyong lihim na parirala sa pagbawi (nang hindi ibinubunyag ito). Gamit ang kapangyarihan na maghango ng mga key, masusuportahan ng $1 ang iba't ibang blockchain protocol bukod sa Etheruem (mga EVM).", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions. $1 is the snap name." + }, + "permission_manageBip44Keys": { + "message": "Pamahalaan ang mga $1 account.", + "description": "The description for the `snap_getBip44Entropy` permission. $1 is the name of a protocol, e.g. 'Filecoin'." + }, "permission_manageState": { "message": "Iimbak at pamahalaan ang datos nito sa iyong device.", "description": "The description for the `snap_manageState` permission" }, + "permission_manageStateDescription": { + "message": "Payagan ang $1 na mag-imbak, mag-update, at mag-retrieve ng datos sa secure na paraan gamit ang pag-encrypt. Hindi maa-access ng ibang mga snap ang impormasyong ito.", + "description": "An extended description for the `snap_manageState` permission. $1 is the snap name." + }, + "permission_nameLookup": { + "message": "Magbigay ng mga domain at address lookup.", + "description": "The description for the `endowment:name-lookup` permission." + }, + "permission_nameLookupDescription": { + "message": "Payagan ang snap na kumuha at magpakita ng mga address at domain lookup sa iba't ibang bahagi ng MetaMask UI.", + "description": "An extended description for the `endowment:name-lookup` permission." + }, "permission_notifications": { "message": "Ipakita ang mga notipikasyon.", "description": "The description for the `snap_notify` permission" }, + "permission_notificationsDescription": { + "message": "Payagan ang $1 na magpakita ng mga notipikasyon sa loob ng MetaMask. Isang maikling tekstong notipikasyon ang maaaring mapaumpisa ng isang snap para sa naaaksyunan o sensitibo sa oras na impormasyon.", + "description": "An extended description for the `snap_notify` permission. $1 is the snap name." + }, + "permission_rpc": { + "message": "Payagan ang $1 na makipag-ugnayan nang direkta sa $2.", + "description": "The description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescription": { + "message": "Payagan ang $1 na magpadala ng mga mensahe sa $2 at makatanggap ng sagot mula sa $2.", + "description": "An extended description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescriptionOriginList": { + "message": "$1 at $2", + "description": "A list of allowed origins where $2 is the last origin of the list and $1 is the rest of the list separated by ','." + }, + "permission_signatureInsight": { + "message": "I-display ang signature insights modal.", + "description": "The description for the `endowment:signature-insight` permission" + }, + "permission_signatureInsightDescription": { + "message": "Pahintulutan ang $1 na mag-display ng modal na may insight sa anumng hiling sa pirma bago aprubahan. Maaari itong gamitin para sa anti-phishing at solusyon sa seguridad.", + "description": "An extended description for the `endowment:signature-insight` permission. $1 is the snap name." + }, + "permission_signatureInsightOrigin": { + "message": "Tingnan ang pinagmulan ng mga website ng nagsimula ng hiling na pirma", + "description": "The description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission" + }, + "permission_signatureInsightOriginDescription": { + "message": "Pahintulutan ang $1 na makita ang pinagmulan (URI) ng mga website na nagmumungkahi ng mga transaksyon. Maaari itong gamitin para sa anti-phishing at mga solusyon sa seguridad.", + "description": "An extended description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission. $1 is the snap name." + }, "permission_transactionInsight": { "message": "Kunin at ipakita ang mga insight sa transaksyon.", "description": "The description for the `endowment:transaction-insight` permission" }, + "permission_transactionInsightDescription": { + "message": "Payagan ang $1 na mag-decode ng mga transaksyon at magpakita ng mga insight sa loob ng MetaMask UI. Maaari itong gamitin para sa anti-phishing at mga solusyon sa seguridad.", + "description": "An extended description for the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_transactionInsightOrigin": { "message": "Tingnan ang pinagmulan ng mga website na nagmumungkahi ng mga transaksyon", "description": "The description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission" }, + "permission_transactionInsightOriginDescription": { + "message": "Payagan ang $1 na makita ang pinagmulan (URI) ng mga website na nagmumungkahi ng mga transaksyon. Maaari itong gamitin para sa anti-phishing at mga solusyon sa seguridad.", + "description": "An extended description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_unknown": { "message": "Hindi kilalang pahintulot: $1", "description": "$1 is the name of a requested permission that is not recognized." @@ -2892,29 +3618,66 @@ "message": "Tingnan ang iyong pampublikong key para sa $1 ($2).", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a derivation path, e.g. 'm/44'/0'/0''. $2 is the elliptic curve name, e.g. 'secp256k1'." }, + "permission_viewBip32PublicKeysDescription": { + "message": "Payagan ang $2 na tingnan ang iyong mga pampublikong key (at mga address) para sa $1. Hindi ito nagkakaloob ng anumang kontrol ng mga account o asset.", + "description": "An extended description for the `snap_getBip32PublicKey` permission. $1 is a derivation path (name). $2 is the snap name." + }, "permission_viewNamedBip32PublicKeys": { "message": "Tingnan ang iyong pampublikong key para sa $1.", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a name for the derivation path, e.g., 'Ethereum accounts'." }, + "permission_walletSwitchEthereumChain": { + "message": "Lumipat sa at gamitin ang sumusunod na network", + "description": "The label for the `wallet_switchEthereumChain` permission" + }, "permission_webAssembly": { "message": "Suporta para sa WebAssembly.", "description": "The description of the `endowment:webassembly` permission." }, + "permission_webAssemblyDescription": { + "message": "Payagan ang $1 na ma-access ang mga low-level execution environment sa pamamagitan ng WebAssembly.", + "description": "An extended description of the `endowment:webassembly` permission. $1 is the snap name." + }, "permissions": { "message": "Mga Pahintulot" }, - "permissionsTitle": { - "message": "Mga Pahintulot" + "permissionsPageEmptyContent": { + "message": "Walang makikita dito" + }, + "permissionsPageEmptySubContent": { + "message": "Dito mo makikita ang mga pahintulot na iyong binigay sa mga naka-install na Snap o konektadong site." }, - "permissionsTourDescription": { - "message": "Hanapin ang mga nakakonekta mong account at pamahalaan ang mga pahintulot dito" + "permissionsPageTourDescription": { + "message": "Ito ang iyong control panel para pamahalaan ang mga permiso na ibinigay sa mga konektadong Snap." + }, + "permissionsPageTourTitle": { + "message": "Ang mga konektadong site ay pahintulot na ngayon" }, "personalAddressDetected": { "message": "Natukoy ang personal na address. Ilagay ang address ng kontrata ng token." }, + "petnamesEnabledToggle": { + "message": "Pahintulutan ang mga palayaw" + }, + "petnamesEnabledToggleDescription": { + "message": "Magbibigay-daan ito sa iyo na magtalaga ng palayaw sa anumang address. Magbibigay kami ng mungkahi para sa mga address na may ugnayan ka kapag posible." + }, + "pinExtensionDescription": { + "message": "Mag-navigate sa menu ng extension at i-pin ang MetaMask Institutional para sa maginhawang pag-akses." + }, + "pinExtensionTitle": { + "message": "I-pin ang extension" + }, + "pinToTop": { + "message": "I-pin sa itaas" + }, "pleaseConfirm": { "message": "Pakikumpirma" }, + "plusMore": { + "message": "+ $1 pa", + "description": "$1 is the number of additional items" + }, "plusXMore": { "message": "+ $1 pa", "description": "$1 is a number of additional but unshown items in a list- this message will be shown in place of those items" @@ -2940,6 +3703,9 @@ "primaryCurrencySettingDescription": { "message": "Piliin ang native para maisapriyoridad ang pagpapakita ng mga value sa native na currency ng chain (hal. ETH). Piliin ang Fiat para maisapriyoridad ang pagpapakita ng mga value sa napili mong fiat na salapi." }, + "primaryType": { + "message": "Pangunahing uri" + }, "priorityFee": { "message": "Bayad sa priyoridad" }, @@ -2960,6 +3726,18 @@ "message": "Pribadong key para sa $1", "description": "$1 represents the account name" }, + "privateKeyHidden": { + "message": "Ang pribadong key ay nakatago", + "description": "Explains that the private key input is hidden" + }, + "privateKeyShow": { + "message": "Ipakita/Itago ang pribadong key input", + "description": "Describes a toggle that is used to show or hide the private key input" + }, + "privateKeyShown": { + "message": "Ang pribadong key ay na ito ay ipinapakita", + "description": "Explains that the private key input is being shown" + }, "privateKeyWarning": { "message": "Babala: Huwag ipaalam ang key na ito. Ang sinumang mayroon ng iyong mga pribadong key ay maaaring magnakaw ng anumang asset sa iyong account." }, @@ -2969,6 +3747,21 @@ "proceedWithTransaction": { "message": "Gusto ko pa ring magpatuloy" }, + "productAnnouncements": { + "message": "Mga anunsiyo ng produkto" + }, + "profileSync": { + "message": "Pag-sync ng Profile" + }, + "profileSyncConfirmation": { + "message": "Kapag in-off mo ang pag-sync ng profile, hindi ka makakatanggap ng mga notipikasyon." + }, + "profileSyncDescription": { + "message": "Lumikha ng profile na gagamitin ng MetaMask upang i-sync ang ilang mga setting sa iyong mga device. Kailangan ito para makakuha ng mga notipikasyon. $1." + }, + "profileSyncPrivacyLink": { + "message": "Matutunan kung paano namin protektahan ang iyong pagkapribado" + }, "proposedApprovalLimit": { "message": "Iminumungkahing Limitasyon sa Pag-apruba" }, @@ -2978,6 +3771,78 @@ "publicAddress": { "message": "Pampublikong address" }, + "pushPlatformNotificationsFundsReceivedDescription": { + "message": "Nakatanggap ka ng $1 $2" + }, + "pushPlatformNotificationsFundsReceivedDescriptionDefault": { + "message": "Nakatanggap ka ng ilang token" + }, + "pushPlatformNotificationsFundsReceivedTitle": { + "message": "Natanggap ang mga pondo" + }, + "pushPlatformNotificationsFundsSentDescription": { + "message": "Matagumpay kang nakapagpadala ng $1 $2" + }, + "pushPlatformNotificationsFundsSentDescriptionDefault": { + "message": "Matagumpay kang nakapagpadala ng ilang token" + }, + "pushPlatformNotificationsFundsSentTitle": { + "message": "Naipadala ang mga pondo" + }, + "pushPlatformNotificationsNftReceivedDescription": { + "message": "Nakatanggap ka ng mga bagong NFT" + }, + "pushPlatformNotificationsNftReceivedTitle": { + "message": "Natanggap ang NFT" + }, + "pushPlatformNotificationsNftSentDescription": { + "message": "Matagumpay kang nakapagpadala ng NFT" + }, + "pushPlatformNotificationsNftSentTitle": { + "message": "Naipadala ang NFT" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedDescription": { + "message": "Matagumpay ang iyong Lido stake" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedTitle": { + "message": "Nakumpleto ang pag-stake" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnDescription": { + "message": "Handa ng i-withdraw ang iyong Lido stake" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnTitle": { + "message": "Handa ng i-withdraw ang stake" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedDescription": { + "message": "Matagumpay ang pag-withdraw ng iyong Lido stake" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedTitle": { + "message": "Nakumpleto ang pag-withdraw" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedDescription": { + "message": "Ipinasa ang hiling na pag-withdraw ng iyong Lido" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedTitle": { + "message": "Hiniling ang pag-withdraw" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedDescription": { + "message": "Matagumpay ang iyong RocketPool stake" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedTitle": { + "message": "Nakumpleto ang pag-stake" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedDescription": { + "message": "Matagumpay ang iyong RocketPool unstake" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedTitle": { + "message": "Nakumpleto ang pag-unstake" + }, + "pushPlatformNotificationsSwapCompletedDescription": { + "message": "Matagumpay ang iyong MetaMask Swap" + }, + "pushPlatformNotificationsSwapCompletedTitle": { + "message": "Nakumpleto ang pag-swap" + }, "queued": { "message": "Naka-queue" }, @@ -2996,9 +3861,15 @@ "receive": { "message": "Tumanggap" }, + "receiveTokensCamelCase": { + "message": "Tumanggap ng mga token" + }, "recipientAddressPlaceholder": { "message": "Ilagay ang pampublikong address (0x) o ENS name" }, + "recipientAddressPlaceholderFlask": { + "message": "Ilagay ang pampublikong address (0x) o pangalan ng domain" + }, "recommendedGasLabel": { "message": "Nirekomenda" }, @@ -3026,6 +3897,12 @@ "recoveryPhraseReminderTitle": { "message": "Protektahan ang iyong pondo" }, + "redesignedConfirmationsEnabledToggle": { + "message": "Pinahusay na hiling sa pirma" + }, + "redesignedConfirmationsToggleDescription": { + "message": "I-on ito upang makita ang mga hiling sa pirma sa isang pinahusay na format." + }, "refreshList": { "message": "I-refresh ang listahan" }, @@ -3068,15 +3945,30 @@ "removeJWTDescription": { "message": "Sigurado ka ba na gusto mong alisin ang token na ito? Ang lahat ng account na itinalaga sa token na ito ay aalisin din mula sa extension: " }, + "removeKeyringSnap": { + "message": "Ang pag-alis ng Snap na ito ay nag-aalis sa mga account na ito sa MetaMask:" + }, + "removeKeyringSnapToolTip": { + "message": "Kinokontrol ng snap ang mga account, at sa pag-alis nito, ang mga account ay aalisin din sa MetaMask, ngunit mananatili ang mga ito sa blockchain." + }, "removeNFT": { "message": "Alisin ang NFT" }, + "removeNftErrorMessage": { + "message": "Hindi namin maalis ang NFT na ito." + }, "removeNftMessage": { "message": "Matagumpay na naalis ang NFT!" }, "removeSnap": { "message": "Alisin ang snap" }, + "removeSnapAccountDescription": { + "message": "Kung magpatuloy ka, ang account na ito ay hindi na available sa MetaMask." + }, + "removeSnapAccountTitle": { + "message": "Alisin ang account" + }, "removeSnapConfirmation": { "message": "Sigurado ka bang gusto mong alisin ang $1?", "description": "$1 represents the name of the snap" @@ -3087,12 +3979,24 @@ "replace": { "message": "palitan" }, + "reportIssue": { + "message": "Mag-ulat ng isyu" + }, "requestFlaggedAsMaliciousFallbackCopyReason": { "message": "Ang tagapagbigay ng seguridad ay hindi nagbahagi ng mga karagdagang detalye" }, "requestFlaggedAsMaliciousFallbackCopyReasonTitle": { "message": "Na-flag ang kahilingan bilang mapaminsala" }, + "requestFrom": { + "message": "Hiling mula sa" + }, + "requestFromInfo": { + "message": "Ito ang site na humihiling ng iyong pirma." + }, + "requestFromTransactionDescription": { + "message": "Ito ang site na humihiling ng iyong kumpirmasyon." + }, "requestMayNotBeSafe": { "message": "Maaaring hindi ligtas ang kahilingan" }, @@ -3114,6 +4018,9 @@ "reset": { "message": "I-reset" }, + "resetStates": { + "message": "I-reset ang Mga Estado" + }, "resetWallet": { "message": "I-reset ang wallet" }, @@ -3196,9 +4103,15 @@ "message": "Hindi ito kailanman hihilingin ng Suporta sa MetaMask.", "description": "The bolded texted in the second part of 'revealSeedWordsWarning'" }, + "revealSensitiveContent": { + "message": "Ipakita ang sensitibong content" + }, "revealTheSeedPhrase": { "message": "Ibunyag ang pariralang binhi" }, + "reviewAlerts": { + "message": "Suriin ang mga alerto" + }, "revokeAllTokensTitle": { "message": "Bawiin ang pahintulot na i-access at ilipat ang lahat ng iyong $1?", "description": "$1 is the symbol of the token for which the user is revoking approval" @@ -3249,6 +4162,9 @@ "searchAccounts": { "message": "Maghanap ng mga account" }, + "searchTokens": { + "message": "Maghanap ng mga token" + }, "secretRecoveryPhrase": { "message": "Lihim na Parirala sa Pagbawi" }, @@ -3265,7 +4181,8 @@ "message": "Mga alerto sa seguridad" }, "securityAlertsDescription": { - "message": "Ang tampok na ito ay nagbibigay ng alerto sa iyo sa mapaminsalang aktibidad sa pamamagitan ng lokal na pagsusuri sa iyong mga transaksyon at kahilingan sa paglagda. Ang iyong datos ay hindi ibinabahagi sa mga third party na nagbibigay ng serbisyong ito. Palaging gumawa ng sarili mong pagsusuri bago aprubahan ang anumang mga kahilingan. Walang garantiya na made-detect ng tampok na ito ang lahat ng mapaminsalang aktibidad." + "message": "Ang tampok na ito ay nag-aalerto sa iyo ng masamang aktibidad sa pamamagitan ng aktibong pagsusuri ng mga hiling na transaksyon at pirma. $1", + "description": "Link to learn more about security alerts" }, "securityAndPrivacy": { "message": "Seguridad at pagkapribado" @@ -3355,6 +4272,9 @@ "selectAnAccountHelp": { "message": "Piliin ang mga custodian account para gamitin sa MetaMask Institutional." }, + "selectEnableDisplayMediaPrivacyPreference": { + "message": "I-on ang Ipakita ang NFT media" + }, "selectHdPath": { "message": "Pumili ng HD Path" }, @@ -3376,18 +4296,41 @@ "send": { "message": "Magpadala" }, + "sendAToken": { + "message": "Magpadala ng token" + }, "sendBugReport": { "message": "Padalhan kami ng ulat ng bug." }, + "sendNoContactsConversionText": { + "message": "mag-click dito" + }, + "sendNoContactsDescription": { + "message": "Nagbibigay-daan sa iyo ang mga kontak na ligtas na magpadala ng mga transaksyon sa ibang account nang maraming beses. Para gumawa ng kontak, $1", + "description": "$1 represents the action text 'click here'" + }, + "sendNoContactsTitle": { + "message": "Wala ka pang anumang mga kontak" + }, + "sendSelectReceiveAsset": { + "message": "Piliin ang asset na tatanggapin" + }, + "sendSelectSendAsset": { + "message": "Piliin ang asset na ipapadala" + }, "sendSpecifiedTokens": { "message": "Magpadala ng $1", "description": "Symbol of the specified token" }, - "sendTo": { - "message": "Ipadala kay" + "sendSwapSubmissionWarning": { + "message": "Ang pag-click sa button na ito ay kaagad na magpapasimula sa iyong swap na transaksyon. Mangyaring suriin ang detalye ng iyong mga transaksyon bago magpatuloy." + }, + "sendTokenAsToken": { + "message": "Ipadala ang $1 bilang $2", + "description": "Used in the transaction display list to describe a swap and send. $1 and $2 are the symbols of tokens in involved in the swap." }, - "sendTokens": { - "message": "Magpadala ng Mga Token" + "sendingAsset": { + "message": "Ipinapadala ang $1" }, "sendingDisabled": { "message": "Ang pagpapadala ng mga asset na ERC-1155 NFT ay hindi pa suportado." @@ -3400,9 +4343,15 @@ "message": "Babala: magpapadala ka sa isang kontrata ng token na maaaring magresulta sa pagkawala ng mga pondo. $1", "description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning" }, + "sendingZeroAmount": { + "message": "Ikaw ay nagpapadala ng 0 $1." + }, "sepolia": { "message": "Sepolia test network" }, + "serviceWorkerKeepAlive": { + "message": "Service Worker Keep Alive" + }, "setAdvancedPrivacySettingsDetails": { "message": "Ginagamit ng MetaMask ang mga pinagkakatiwalaang serbisyo ng third-party na ito para mapahusay ang kakayahang magamit at kaligtasan ng produkto." }, @@ -3422,9 +4371,21 @@ "settingsSearchMatchingNotFound": { "message": "Walang nakitang katugmang resulta." }, + "settingsSubHeadingSignaturesAndTransactions": { + "message": "Lagda at hiling sa transaksyon" + }, "show": { "message": "Ipakita" }, + "showAccount": { + "message": "Ipakita ang account" + }, + "showExtensionInFullSizeView": { + "message": "Ipakit ang extension sa full-size na view" + }, + "showExtensionInFullSizeViewDescription": { + "message": "I-on ito upang gawing default ang full-size view kapag pinindot mo ang extension icon." + }, "showFiatConversionInTestnets": { "message": "Ipakita ang palitan sa mga test network" }, @@ -3444,6 +4405,9 @@ "message": "Umaasa ito sa $1 na magkakaroon ng access sa iyong Ethereum address at sa iyong IP address. $2", "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" }, + "showIncomingTransactionsExplainer": { + "message": "Ito ay umaasa sa ibang third party na API para sa bawat network, na naglalantad sa iyong address sa Ethereum at iyong IP address." + }, "showMore": { "message": "Ipakita ang iba pa" }, @@ -3483,9 +4447,46 @@ "signin": { "message": "Mag-sign In" }, + "signing": { + "message": "Pinipirmahan" + }, + "simulationDetailsFailed": { + "message": "Mayroong error sa pag-load ng iyong pagtataya." + }, + "simulationDetailsFiatNotAvailable": { + "message": "Hindi Available" + }, + "simulationDetailsIncomingHeading": { + "message": "Natanggap mo" + }, + "simulationDetailsNoBalanceChanges": { + "message": "Walang pagbabagong nahulaan para sa iyong wallet" + }, + "simulationDetailsOutgoingHeading": { + "message": "Nagpadala ka" + }, + "simulationDetailsTitle": { + "message": "Tinatayang mga pagbabago" + }, + "simulationDetailsTitleTooltip": { + "message": "Ang tinatayang mga pagbabago ay ang maaaring mangyaring kung magpapatuloy ka sa transaksyon ito. Ito ay isang prediksyon laman, hindi isang garantiya." + }, + "simulationDetailsTotalFiat": { + "message": "Kabuuan = $1", + "description": "$1 is the total amount in fiat currency on one side of the transaction" + }, + "simulationDetailsTransactionReverted": { + "message": "Ang transaksyon na ito ay malamang na mabigo" + }, "simulationErrorMessageV2": { "message": "Hindi namin nagawang tantyahin ang gas. Maaaring may error sa kontrata at maaaring mabigo ang transaksyong ito." }, + "simulationsSettingDescription": { + "message": "I-on ito para gumawa ng pagtataya sa mga pagbabago ng balanse ng mga transaksyon bago mo kumpirmahin ang mga iyon. Hindi nito iginagarantiya ang panghuling resulta ng iyong mga transaksyon. $1" + }, + "simulationsSettingSubHeader": { + "message": "Tinatayang mga pagbabago sa balanse" + }, "skip": { "message": "Laktawan" }, @@ -3498,20 +4499,99 @@ "smartContracts": { "message": "Mga smart na kontrata" }, - "smartSwapsAreHere": { - "message": "Nandito na ang mga Smart Swap!" - }, - "smartSwapsDescription": { - "message": "Mas humusay pa ang mga MetaMask Swap! Ang pag-enable sa mga Smart Swap ay magbibigay-daan sa MetaMask na i-optimize ang iyong Swap gamit ang program para makatulong na:" - }, "smartSwapsErrorNotEnoughFunds": { "message": "Hindi sapat ang pondo para sa smart swap." }, "smartSwapsErrorUnavailable": { "message": "Pansamantalang hindi available ang mga Smart Swap." }, + "smartTransactionCancelled": { + "message": "Nakansela ang transaksyon mo" + }, + "smartTransactionCancelledDescription": { + "message": "Hindi nakumpleto ang transaksyon mo, kaya kinansela ito para maiwasan mo ang pagbabayad ng mga hindi kinakailangang gas fee." + }, + "smartTransactionError": { + "message": "Nabigo ang transaksyon mo" + }, + "smartTransactionErrorDescription": { + "message": "Maaaring magdulot ng pagkabigo ang biglaang pagbabago sa merkado. Kung magpatuloy ang problema, makipag-ugnayan sa customer support ng MetaMask." + }, + "smartTransactionPending": { + "message": "Isinusumite ang iyong transaksyon" + }, + "smartTransactionSuccess": { + "message": "Nakumpleto ang transaksyon mo" + }, + "smartTransactionTakingTooLong": { + "message": "Paumanhin sa paghihintay" + }, + "smartTransactionTakingTooLongDescription": { + "message": "Kung ang transaksyon mo ay hindi natapos sa loob ng $1, ito ay kakanselahin at hindi ka sisingilin para sa gas.", + "description": "$1 is remaining time in seconds" + }, + "smartTransactions": { + "message": "Mga Smart Transaction" + }, + "smartTransactionsBenefit1": { + "message": "99.5% tiyansa ng tagumpay" + }, + "smartTransactionsBenefit2": { + "message": "Makatitipid ng pera" + }, + "smartTransactionsBenefit3": { + "message": "Mga real-time na update" + }, + "smartTransactionsDescription": { + "message": "Mag-unlock na mas mataas na tiyansa ng tagumpay, proteksyon sa frontrunning, at mas mahusay na visibility sa mga Smart Transaction." + }, + "smartTransactionsDescription2": { + "message": "Available lamang sa Ethereum. I-enable o i-disable anumang oras sa mga setting. $1", + "description": "$1 is an external link to learn more about Smart Transactions" + }, + "smartTransactionsOptItModalTitle": { + "message": "Pinahusay na Proteksyon sa Transaksyon" + }, + "snapAccountCreated": { + "message": "Nagawa ang account" + }, + "snapAccountCreatedDescription": { + "message": "Handa ng gamitin ang iyong bagong account!" + }, + "snapAccountCreationFailed": { + "message": "Nabigo ang paglikha ng account" + }, + "snapAccountCreationFailedDescription": { + "message": "Ang $1 ay hindi nagawang lumikha ng account para sa iyo.", + "description": "$1 is the snap name" + }, + "snapAccountRedirectFinishSigningTitle": { + "message": "Tapusin ang pagpirma" + }, + "snapAccountRedirectSiteDescription": { + "message": "Sundin ang mga tagubilin mula sa $1" + }, + "snapAccountRemovalFailed": { + "message": "Nabigo ang pag-alis ng account" + }, + "snapAccountRemovalFailedDescription": { + "message": "Ang $1 ay hindi nagawang alisin ng account para sa iyo.", + "description": "$1 is the snap name" + }, + "snapAccountRemoved": { + "message": "Naalis ang account" + }, + "snapAccountRemovedDescription": { + "message": "Ang account na ito ay hindi na magiging available para gamitin sa MetaMask." + }, + "snapAccounts": { + "message": "Mga Account Snap" + }, + "snapAccountsDescription": { + "message": "Mga account na kontrol lang ng mga third-party na Snap." + }, "snapConnectionWarning": { - "message": "Gustong kumonekta ng $1 sa $2. Magpatuloy lang kung pinagkakatiwalaan mo ang website na ito.", + "message": "Si $1 ay gustong gumamit ng $2", "description": "$2 is the snap and $1 is the dapp requesting connection to the snap." }, "snapContent": { @@ -3522,15 +4602,35 @@ "message": "Website" }, "snapInstallRequest": { - "message": "Ang pag-install ng $1 ay nagbibigay dito ng mga sumusunod na pahintulot. Magpatuloy lang kung pinagkakatiwalaan mo ang $1.", + "message": "Ang pag-install ng $1 ay nagbibigay ng mga sumusunod na pahintulot.", "description": "$1 is the snap name." }, "snapInstallSuccess": { "message": "Tapos na ang pag-install" }, + "snapInstallWarningCheck": { + "message": "Gusto ng $1 ng pahintulot na gawin ang mga sumusunod:", + "description": "Warning message used in popup displayed on snap install. $1 is the snap name." + }, "snapInstallWarningHeading": { "message": "Magpatuloy nang may pag-iingat" }, + "snapInstallWarningPermissionDescriptionForBip32View": { + "message": "Payagan ang $1 na tingnan ang iyong mga pambublikong key (at mga address). Hindi ito nagkakaloob ng anumang kontrol ng mga account o asset.", + "description": "An extended description for the `snap_getBip32PublicKey` permission used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionDescriptionForEntropy": { + "message": "Payagan ang $1 Snap na mamahala ng mga account at asset sa (mga) hiniling na network. Ang mga account na ito ay hinango at naka-back up gamit ang iyong lihim na parirala sa pagbawi (nang hindi ibinubunyag ito). Gamit ang kapangyarihan na maghango ng mga key, masusuportahan ng $1 ang iba't ibang blockchain protocol bukod sa Ethereum (mga EVM).", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionNameForEntropy": { + "message": "Pamahalaan ang mga $1 account", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, + "snapInstallWarningPermissionNameForViewPublicKey": { + "message": "Tingnan ang pampublikong key para sa $1", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, "snapInstallationErrorDescription": { "message": "Hindi ma-install ang $1.", "description": "Error description used when snap installation fails. $1 is the snap name." @@ -3548,6 +4648,10 @@ "snapResultSuccessDescription": { "message": "Handa nang gamitin ang $1" }, + "snapUpdateAlertDescription": { + "message": "Kunin ang pinakabagong bersyon ng $1", + "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." + }, "snapUpdateAvailable": { "message": "Available ang update" }, @@ -3559,22 +4663,40 @@ "message": "Nabigo ang pag-update", "description": "Error title used when snap update fails." }, + "snapUpdateRequest": { + "message": "Ang pag-update ng $1 ay nagbibigay ng mga sumusunod na pahintulot.", + "description": "$1 is the Snap name." + }, "snapUpdateSuccess": { "message": "Tapos na ang pag-update" }, + "snapUrlIsBlocked": { + "message": "Gusto kang dalhin ng Snap na ito sa isang naka-block na site. $1." + }, "snaps": { "message": "Mga Snap" }, - "snapsInvalidUIError": { - "message": "Ang UI na tinukoy ng snap ay hindi wasto." + "snapsConnected": { + "message": "Nakonekta ang Snaps" }, "snapsNoInsight": { "message": "Ang snap ay hindi nagbalik ng anumang insight" }, + "snapsPrivacyWarningFirstMessage": { + "message": "Kinikilala mo na anumang snap na i-install mo ay isang Serbisyong Third Party, maliban kung tinukoy, ayon sa depenisyon sa $1 ng Consensys. Ang iyong paggamit ng mga Serbisyong Third Party ay pinapamahalaan ng hiwalay na mga tuntunin at kundisyon na itinakda ng tagapagbigay ng Serbisyong Third Party. Iyong ina-access, pinagbabatayan, o ginagamit mo ang Serbisyong Third Party sa sarili mong panganib. Itinatanggi ng Consensys ang lahat ng responsibilidad at pananagutan para sa anumang pagkalugi sa account dahil sa iyong paggamit ng mga Serbisyo ng Third Party.", + "description": "First part of a message in popup modal displayed when installing a snap for the first time. $1 is terms of use link." + }, "snapsPrivacyWarningSecondMessage": { "message": "Ang anumang impormasyong ibinabahagi mo sa mga Serbisyo ng Third Party ay direktang kokolektahin ng mga Serbisyo ng Third Party na iyon alinsunod sa kanilang mga patakaran sa pagkapribado. Pakitingnan ang kanilang mga patakaran sa pagkapribado para sa higit pang impormasyon.", "description": "Second part of a message in popup modal displayed when installing a snap for the first time." }, + "snapsPrivacyWarningThirdMessage": { + "message": "Walang access ang Consensys sa impormasyong ibinabahagi mo sa mga third party na ito.", + "description": "Third part of a message in popup modal displayed when installing a snap for the first time." + }, + "snapsSettings": { + "message": "Mga settings sa Snap" + }, "snapsTermsOfUse": { "message": "Mga Tuntunin ng Paggamit" }, @@ -3588,12 +4710,19 @@ "someNetworksMayPoseSecurity": { "message": "Maaaring magdulot ang ilang network ng mga panganib sa seguridad at/o pagkapribado. Unawain ang mga panganib bago idagdag o gamitin ang isang network." }, + "somethingDoesntLookRight": { + "message": "Mayroon bang hindi tama? $1", + "description": "A false positive message for users to contact support. $1 is a link to the support page." + }, "somethingIsWrong": { "message": "May nangyaring mali. Subukang muling i-load ang pahina." }, "somethingWentWrong": { "message": "Oops! Nagkaproblema." }, + "source": { + "message": "Pinagmulan" + }, "speedUp": { "message": "Pabilisin" }, @@ -3728,6 +4857,14 @@ "stake": { "message": "Mag-stake" }, + "startYourJourney": { + "message": "Simulan ang iyong paglalakbay sa $1", + "description": "$1 is the token symbol" + }, + "startYourJourneyDescription": { + "message": "Magsimula sa web3 sa pamamagitan ng pagdagdag ng $1 sa iyong wallet.", + "description": "$1 is the token symbol" + }, "stateLogError": { "message": "Error sa pagkuha ng mga log ng estado." }, @@ -3740,6 +4877,9 @@ "stateLogsDescription": { "message": "Naglalaman ang mga log ng estado ng iyong mga address ng pampublikong account at ipinadalang transaksyon." }, + "states": { + "message": "Mga estado" + }, "status": { "message": "Katayuan" }, @@ -3783,18 +4923,6 @@ "strong": { "message": "Mahirap" }, - "stxBenefit1": { - "message": "Bawasan ang mga gastos sa transaksyon" - }, - "stxBenefit2": { - "message": "Bawasan ang mga nabigong transaksyon" - }, - "stxBenefit3": { - "message": "Alisin ang mga hindi umuusad na transaksyon" - }, - "stxBenefit4": { - "message": "Pigilan ang front-running" - }, "stxCancelled": { "message": "Nabigo sana ang pag-swap kung" }, @@ -3804,6 +4932,10 @@ "stxCancelledSubDescription": { "message": "Subukan muli ang pag-swap. Narito kami para protektahan ka sa mga katulad na panganib sa susunod." }, + "stxEstimatedCompletion": { + "message": "Tinatayang pagkumpleto sa loob ng < $1", + "description": "$1 is remeaning time in minutes and seconds, e.g. 0:10" + }, "stxFailure": { "message": "Nabigo ang pag-swap" }, @@ -3811,6 +4943,9 @@ "message": "Ang biglaang pagbabago sa merkado ay maaaring maging sanhi ng pagkabigo. Kung magpatuloy ang problema, makipag-ugnyan sa $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInDescription": { + "message": "I-on ang mga Smart Transaction para sa mas maaasahan at ligtas na mga transaksyon sa Ethereum Mainnet. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Pribadong isinusumite ang iyong Swap..." }, @@ -3849,12 +4984,21 @@ "submitted": { "message": "Naisumite" }, + "suggestedTokenSymbol": { + "message": "Iminumungkahing ticket symbol:" + }, "support": { "message": "Humingi ng Tulong" }, "supportCenter": { "message": "Bisitahin ang aming Sentro ng Suporta" }, + "surveyConversion": { + "message": "Sagutan ang aming survey" + }, + "surveyTitle": { + "message": "Hubugin ang hinaharap ng MetaMask" + }, "swap": { "message": "I-swap" }, @@ -3874,6 +5018,9 @@ "swapAmountReceivedInfo": { "message": "Ito ang minimum na halagang matatanggap mo. Maaari kang makatanggap ng mas malaki depende sa slippage." }, + "swapAndSend": { + "message": "I-swap at Ipadala" + }, "swapAnyway": { "message": "I-swap pa rin" }, @@ -3989,6 +5136,10 @@ "message": "Kasama ang $1% MetaMask fee.", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." }, + "swapIncludesMMFeeAlt": { + "message": "Kasama sa quote ang $1% bayad sa MetaMask", + "description": "Provides information about the fee that metamask takes for swaps using the latest copy. $1 is a decimal number." + }, "swapIncludesMetaMaskFeeViewAllQuotes": { "message": "Kabilang ang $1% na bayad sa MetaMask – $2", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number and $2 is a link to view all quotes." @@ -3996,6 +5147,9 @@ "swapLearnMore": { "message": "Alamin pa ang tungkol sa mga Swap" }, + "swapLiquiditySourceInfo": { + "message": "Naghahanap kami sa iba't ibang pinagmumulan ng liquidity (mga exchange, aggregator at propesyonal na market maker) upang paghambingin ang mga halaga ng palitan at bayad sa network." + }, "swapLowSlippage": { "message": "Mababang slippage" }, @@ -4268,6 +5422,9 @@ "switchEthereumChainConfirmationTitle": { "message": "Payagan ang site na ito para lumipat ng network?" }, + "switchInputCurrency": { + "message": "Palitan ang input currency" + }, "switchNetwork": { "message": "Lumipat ng network" }, @@ -4281,14 +5438,15 @@ "switchToThisAccount": { "message": "Lumipat sa account na ito" }, - "switchedTo": { - "message": "Lumipat ka sa" + "switchedNetworkToastDecline": { + "message": "Huwag ipakita muli" }, - "switcherTitle": { - "message": "Network switcher" + "switchedNetworkToastMessage": { + "message": "Ang $1 ay aktibo ngayon sa $2", + "description": "$1 represents the account name, $2 represents the network name" }, - "switcherTourDescription": { - "message": "I-click ang icon para lumipat ng network o magdagdag ng bagong network" + "switchedTo": { + "message": "Lumipat ka sa" }, "switchingNetworksCancelsPendingConfirmations": { "message": "Ang paglipat ng network ay magkakansela ng lahat ng nakabinbing kumpirmasyon" @@ -4388,6 +5546,18 @@ "toggleEthSignOn": { "message": "I-ON (Hindi inirerekomenda)" }, + "toggleRequestQueueDescription": { + "message": "Pinahihintulutan ka nitong pumili ng network para sa bawat site sa halip na iisang piniling network para sa lahat ng site. Pipigilan ka ng feature na ito na magpalit ng network nang mano-mano, na maaaring makasira sa iyong karanasan bilang user sa ilang partikular na site." + }, + "toggleRequestQueueField": { + "message": "Piliin ang mga network para sa bawat site" + }, + "toggleRequestQueueOff": { + "message": "Naka-off" + }, + "toggleRequestQueueOn": { + "message": "Naka-on" + }, "token": { "message": "Token" }, @@ -4404,7 +5574,7 @@ "message": "Address ng kontrata ng token" }, "tokenDecimalFetchFailed": { - "message": "Kailangan ng token decimal." + "message": "Kailangan ng decimal ng token. Hanapin ito sa: $1" }, "tokenDecimalTitle": { "message": "Mga Decimal ng Katumpakan:" @@ -4443,6 +5613,9 @@ "tooltipSatusConnected": { "message": "konektado" }, + "tooltipSatusConnectedUpperCase": { + "message": "Nakakonekta" + }, "tooltipSatusNotConnected": { "message": "hindi konektado" }, @@ -4583,6 +5756,39 @@ "tryAgain": { "message": "Subukan ulit" }, + "turnOff": { + "message": "I-off" + }, + "turnOffMetamaskNotificationsError": { + "message": "Nagkaroon ng error sa pag-disable ng mga notipikasyon. Pakisubukan muli mamaya." + }, + "turnOn": { + "message": "I-on" + }, + "turnOnMetamaskNotifications": { + "message": "I-on ang mga notipikasyon" + }, + "turnOnMetamaskNotificationsButton": { + "message": "I-on" + }, + "turnOnMetamaskNotificationsError": { + "message": "Nagkaroon ng error sa paglikha ng mga notipikasyon. Pakisubukan muli mamaya." + }, + "turnOnMetamaskNotificationsMessageFirst": { + "message": "Manatiling may-alam sa nangyayari sa iyong wallet gamit ang mga notipikasyon." + }, + "turnOnMetamaskNotificationsMessagePrivacyBold": { + "message": "Mga Setting > Mga notipikasyon." + }, + "turnOnMetamaskNotificationsMessagePrivacyLink": { + "message": "Matutunan kung paano namin protektahan ang iyong pagkapribado habang gamit ang tampok na ito." + }, + "turnOnMetamaskNotificationsMessageSecond": { + "message": "Para magamit ang mga notipikasyon sa wallet, gumagamit kami ng profile para i-sync ang ilang mga setting sa iyong mga device. $1" + }, + "turnOnMetamaskNotificationsMessageThird": { + "message": "Maaari mong i-off ang mga notipikasypon anumang oras sa $1" + }, "turnOnTokenDetection": { "message": "I-on ang pinahusay na pag-detect ng token" }, @@ -4614,6 +5820,10 @@ "unknownNetwork": { "message": "Hindi kilalang pribadong network" }, + "unknownNetworkForKeyEntropy": { + "message": "Hindi kilalang network", + "description": "Displayed on places like Snap install warning when regular name is not available." + }, "unknownQrCode": { "message": "Error: Hindi namin matukoy ang QR code na iyon" }, @@ -4626,6 +5836,9 @@ "unlockMessage": { "message": "Naghihintay ang desentralisadong web" }, + "unpin": { + "message": "I-unpin" + }, "unrecognizedChain": { "message": "Hindi nakikilala ang custom network na ito. Nirerekomenda namin na ikaw ay $1 bago magpatuloy", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." @@ -4643,6 +5856,9 @@ "update": { "message": "I-update" }, + "updateRequest": { + "message": "Hiling sa pag-update" + }, "updatedWithDate": { "message": "Na-update noong $1" }, @@ -4667,12 +5883,25 @@ "useNftDetection": { "message": "Awtomatikong tuklasin ang mga NFT" }, + "useNftDetectionDescriptionText": { + "message": "Hayaan ang MetaMask na magdagdag ng mga NFT na iyong pag-aari gamit ang mga third-party na serbisyo (tulad ng OpenSea). Ang awtomatikong pagtuklas ng mga NFT ay naglalantad sa iyong IP at address ng account sa mga serbisyong ito. Ang pag-enable sa tampok na ito ay maaaring mag-ugnay sa iyong IP sa iyong Ethereum address at magpakita ng pekeng NFT na in-airdrop ng mga manloloko. Maaari kang magdagdag ng token sa manwal na paraan para iwasan ang panganib na ito." + }, "usePhishingDetection": { "message": "Gumamit ng phishing detection" }, "usePhishingDetectionDescription": { "message": "Magpakita ng babala para sa mga phishing domain na nagta-target sa mga user ng Ethereum" }, + "useSafeChainsListValidation": { + "message": "Suriin ang mga Detalye ng Network" + }, + "useSafeChainsListValidationDescription": { + "message": "Ang MetaMask ay gumagamit ng serbisyong third-party na tinatawag na $1 para magpakita ng tumpak at naka-standardized na detalye ng network. Binabawasan nito ang iyong tiyansa sa pagkonekta sa malisiyoso o malitang network. Kapag ginagamit ang tampok na ito, ang iyong IP address ay nakalantad sa chainid.network." + }, + "useSafeChainsListValidationWebsite": { + "message": "chainid.network", + "description": "useSafeChainsListValidationWebsite is separated from the rest of the text so that we can bold the third party service name in the middle of them" + }, "useSiteSuggestion": { "message": "Gamitin ang mungkahi ng site" }, @@ -4685,6 +5914,9 @@ "userName": { "message": "Username" }, + "userOpContractDeployError": { + "message": "Ang paglalabas ng kontrata mula sa isang account ng smart contract ay hindi suportado" + }, "verifyContractDetails": { "message": "I-verify ang mga detalye ng third-party" }, @@ -4702,6 +5934,9 @@ "view": { "message": "Tingnan" }, + "viewActivity": { + "message": "Tingnan ang aktibidad" + }, "viewAllDetails": { "message": "Tingnan ang lahat ng detalye" }, @@ -4725,7 +5960,7 @@ }, "viewOnCustomBlockExplorer": { "message": "Tingnan ang $1 sa $2", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "Tingnan ang $1 sa Etherscan", @@ -4737,6 +5972,9 @@ "viewOnOpensea": { "message": "Tingnan sa Opensea" }, + "viewTransaction": { + "message": "Tingnan ang transaksyon" + }, "viewinCustodianApp": { "message": "Tingnan sa app custodian" }, @@ -4744,6 +5982,9 @@ "message": "Tingnan ang $1 sa Explorer", "description": "$1 is the action type. e.g (Account, Transaction, Swap)" }, + "visitSite": { + "message": "Bisitahin ang site" + }, "visitWebSite": { "message": "Bisitahin ang aming website" }, @@ -4782,6 +6023,10 @@ "warning": { "message": "Babala" }, + "warningFromSnap": { + "message": "Babala mula sa $1", + "description": "$1 represents the name of the snap" + }, "warningTooltipText": { "message": "$1 Maaaring gastusin ng third party ang iyong buong balanse ng token nang walang karagdagang abiso o pahintulot. Protektahan ang iyong sarili sa pamamagitan ng pag-customize ng mas mababang limitasyon sa paggastos.", "description": "$1 is a warning icon with text 'Be careful' in 'warning' colour" @@ -4789,6 +6034,9 @@ "weak": { "message": "Madali" }, + "web3": { + "message": "Web3" + }, "web3ShimUsageNotification": { "message": "Napansin namin na sinubukan ng kasalukuyang website na gamitin ang inalis na window.web3 API. Kung mukhang sira ang site, paki-click ang $1 para sa karagdagang impormasyon.", "description": "$1 is a clickable link." @@ -4829,10 +6077,6 @@ "whatsThis": { "message": "Ano ito?" }, - "xOfY": { - "message": "$1 ng $2", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$1 ng $2 ang nakabinbin", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" @@ -4840,6 +6084,9 @@ "yes": { "message": "Oo" }, + "you": { + "message": "Ikaw" + }, "youHaveAddedAll": { "message": "Idinagdag mo ang lahat ng sikat na network. Maaari kang makatuklas ng higit pang mga network $1 O maaari kang", "description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'" @@ -4862,6 +6109,12 @@ "yourPrivateSeedPhrase": { "message": "Ang Iyong Lihim na Parirala sa Pagbawi" }, + "yourTransactionConfirmed": { + "message": "Nakumpirma na ang transaksyon" + }, + "yourTransactionJustConfirmed": { + "message": "Hindi namin makansela ang iyong transaksyon bago ito nakumpirma sa blockchain." + }, "zeroGasPriceOnSpeedUpError": { "message": "Walang presyo ng gas sa pagpapabilis" } diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index 429d838df65d..51aafd650946 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -130,12 +130,21 @@ "account": { "message": "Hesap" }, + "accountActivity": { + "message": "Hesap aktivitesi" + }, + "accountActivityText": { + "message": "Hakkında bildirim almak istediğiniz hesapları seçin:" + }, "accountDetails": { "message": "Hesap bilgileri" }, "accountIdenticon": { "message": "Hesap Identicon" }, + "accountIsntConnectedToastText": { + "message": "$1 şuna bağlı değil: $2" + }, "accountName": { "message": "Hesap Adı" }, @@ -153,6 +162,12 @@ "accountSelectionRequired": { "message": "Bir hesap seçmeniz gerekiyor!" }, + "accounts": { + "message": "Hesaplar" + }, + "accountsConnected": { + "message": "Hesaplar bağlandı" + }, "active": { "message": "Aktif" }, @@ -243,6 +258,9 @@ "addIPFSGateway": { "message": "Tercih ettiğiniz IPFS ağ geçidini ekleyin" }, + "addImportAccount": { + "message": "Hesap veya donanım cüzdanı ekleyin" + }, "addMemo": { "message": "Not ekleyin" }, @@ -256,6 +274,9 @@ "message": "Bu ağ bağlantısı üçüncü taraflara dayalıdır. Bu bağlantı daha az güvenli olabilir veya üçüncü tarafların aktiviteleri takip etmesine olanak sağlayabilir. $1", "description": "$1 is Learn more link" }, + "addNewAccount": { + "message": "Yeni bir hesap ekleyin" + }, "addNewToken": { "message": "Yeni token ekleyin" }, @@ -265,6 +286,12 @@ "addNfts": { "message": "NFT ekleyin" }, + "addSnapAccountToggle": { + "message": "\"Snap hesabı ekle (Beta)\" özelliğini etkinleştir" + }, + "addSnapAccountsDescription": { + "message": "Bu özelliğin açılması size doğrudan hesap listenizden bir Snap hesabı ekleme seçeneği verir. Bir Snap hesabı yüklüyorsanız bunun üçüncü taraf bir hizmet olduğunu unutmayın." + }, "addSuggestedNFTs": { "message": "Önerilen NFT'leri ekleyin" }, @@ -281,6 +308,9 @@ "addingCustomNetwork": { "message": "Ağ Ekleniyor" }, + "addingTokens": { + "message": "Token'leri ekleme" + }, "address": { "message": "Adres" }, @@ -316,9 +346,27 @@ "airgapVault": { "message": "AirGap Vault" }, + "alert": { + "message": "Uyarı" + }, + "alertBannerMultipleAlertsDescription": { + "message": "Bu talebi onaylarsanız dolandırıcılıkla bilinen üçüncü bir taraf tüm varlıklarınızı çalabilir." + }, + "alertBannerMultipleAlertsTitle": { + "message": "Çoklu uyarı!" + }, "alertDisableTooltip": { "message": "\"Ayarlar > Uyarılar\" kısmında değiştirilebilir" }, + "alertModalAcknowledge": { + "message": "Riski anlıyor ve yine de ilerlemek istiyorum" + }, + "alertModalDetails": { + "message": "Uyarı Ayrıntıları" + }, + "alertModalReviewAllAlerts": { + "message": "Tüm uyarıları incele" + }, "alertSettingsUnconnectedAccount": { "message": "Bağlı olmayan bir hesap ile bir web sitesine göz atma seçildi" }, @@ -334,6 +382,9 @@ "alerts": { "message": "Uyarılar" }, + "all": { + "message": "Tümü" + }, "allCustodianAccountsConnectedSubtitle": { "message": "Zaten tüm saklayıcı kurum hesaplarını bağladınız ya da MetaMask Institutional'a bağlayabileceğiniz hesap yok." }, @@ -344,23 +395,26 @@ "message": "Sahip olduğunuz tüm $1", "description": "$1 is the symbol or name of the token that the user is approving spending" }, + "allPermissions": { + "message": "Tüm İzinler" + }, "allYourNFTsOf": { "message": "Tüm $1 NFT'leriniz", "description": "$1 is a link to contract on the block explorer when we're not able to retrieve a erc721 or erc1155 name" }, - "allowExternalExtensionTo": { - "message": "Bu harici uzantının şunu yapmasına izin ver:" + "allow": { + "message": "İzin Ver" + }, + "allowMmiToConnectToCustodian": { + "message": "MMI'nin hesaplarınızı içe aktarmak için $1 ile bağlantı kurmasına izin verir." + }, + "allowNotifications": { + "message": "Bildirimlere izin ver" }, "allowSpendToken": { "message": "$1 erişimine izin ver?", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "Bu sitenin şunu yapmasına izin ver:" - }, - "allowThisSnapTo": { - "message": "Bu snap için şuna izin verin:" - }, "allowWithdrawAndSpend": { "message": "$1 için şu tutara kadar para çekme ve harcama izni ver:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -368,6 +422,23 @@ "amount": { "message": "Tutar" }, + "amountReceived": { + "message": "Alınan Tutar" + }, + "amountSent": { + "message": "Gönderilen Tutar" + }, + "andForListItems": { + "message": "$1 ve $2", + "description": "$1 is the first item, $2 is the last item in a list of items. Used in Snap Install Warning modal." + }, + "andForTwoItems": { + "message": "$1 ve $2", + "description": "$1 is the first item, $2 is the second item. Used in Snap Install Warning modal." + }, + "announcements": { + "message": "Duyurular" + }, "appDescription": { "message": "Tarayıcında bir Ethereum Cüzdanı", "description": "The description of the application" @@ -402,6 +473,10 @@ "approveButtonText": { "message": "Onayla" }, + "approveIncreaseAllowance": { + "message": "$1 harcama üst limitini artır", + "description": "The token symbol that is being approved" + }, "approveSpendingCap": { "message": "$1 harcama üst limitini onayla", "description": "The token symbol that is being approved" @@ -427,6 +502,10 @@ "message": "$1 üzerinde onaylandı", "description": "$1 is the approval date for a permission" }, + "approvedOnForAccounts": { + "message": "$2 için $1 üzerinde onaylandı", + "description": "$1 is the approval date for a permission. $2 is the AvatarGroup component displaying account images." + }, "areYouSure": { "message": "Emin misin?" }, @@ -439,12 +518,21 @@ "attemptSendingAssets": { "message": "Varlıkları doğrudan bir ağdan diğerine göndermeye çalışırsanız bu durum kalıcı varlık kaybına neden olabilir. Bir köprü kullandığınızdan emin olun." }, + "attemptSendingAssetsWithPortfolio": { + "message": "Varlıkları doğrudan bir ağdan diğerine göndermeye çalışırsanız bu durum kalıcı varlık kaybına neden olabilir. $1 gibi bir köprü kullandığınızdan emin olun" + }, + "attemptToCancelSwapForFree": { + "message": "Swap işlemini ücretsiz iptal etme girişimi" + }, "attemptingConnect": { "message": "Blockzincirine bağlanmaya çalışılıyor." }, "attributions": { "message": "Özellikler" }, + "auroraRpcDeprecationMessage": { + "message": "Infura RPC URL adresi artık Aurora'yı desteklemiyor." + }, "authorizedPermissions": { "message": "Aşağıdaki izinleri verdiniz" }, @@ -479,6 +567,9 @@ "backupApprovalNotice": { "message": "Cüzdanınızı ve paranızı güvende tutmak için Gizli Kurtarma İfadenizi yedekleyin." }, + "backupKeyringSnapReminder": { + "message": "Snap'i kaldırmadan önce bu Snap tarafından oluşturulan tüm hesaplara kendi başınıza erişim sağlayabildiğinizden emin olun" + }, "backupNow": { "message": "Şimdi yedekle" }, @@ -486,7 +577,7 @@ "message": "Verilerini yedekle" }, "backupUserDataDescription": { - "message": "Tercihleri ve hesap adreslerini içeren kullanıcı ayarlarını JSON dosyasına yedekleyebilirsiniz." + "message": "Kişileriniz ve tercihleriniz gibi verileri yedekleyebilirsiniz." }, "balance": { "message": "Bakiye" @@ -500,6 +591,30 @@ "basic": { "message": "Temel" }, + "basicConfigurationBannerCTA": { + "message": "Temel işlevselliği aç" + }, + "basicConfigurationBannerTitle": { + "message": "Temel işlevsellik kapalı" + }, + "basicConfigurationLabel": { + "message": "Temel işlevsellik" + }, + "basicConfigurationModalCheckbox": { + "message": "Anlıyorum ve devam etmek istiyorum" + }, + "basicConfigurationModalDisclaimerOff": { + "message": "Bu, MetaMask'te zamanınızı tamamen optimize edemeyeceğiniz anlamına gelir. Temel özellikler (token bilgileri, en iyi gaz ayarları vb. gibi) sizin için sunulmayacaktır." + }, + "basicConfigurationModalDisclaimerOn": { + "message": "MetaMask'te zamanınızı tamamen optimize etmek için bu özelliği açmanız gerekecektir. Temel özellikler (token bilgileri, en iyi gaz ayarları vb. gibi) web3 deneyimi için önemlidir." + }, + "basicConfigurationModalHeadingOff": { + "message": "Temel işlevselliği kapat" + }, + "basicConfigurationModalHeadingOn": { + "message": "Temel işlevselliği aç" + }, "beCareful": { "message": "Dikkatli olun" }, @@ -571,6 +686,9 @@ "blockaidDescriptionTransferFarming": { "message": "Bu talebi onaylarsanız dolandırıcılıkla ünlü üçüncü bir taraf tüm varlıklarınızı çalar." }, + "blockaidMessage": { + "message": "Gizlilik koruması - hiçbir veri üçüncü taraflarla paylaşılmaz. Arbitrum, Avalanche, BNB chain, Ethereum Ana Ağı, Linea, Optimism, Polygon, Base ve Sepolia için sunulur." + }, "blockaidTitleDeceptive": { "message": "Bu aldatıcı bir talep" }, @@ -586,6 +704,9 @@ "bridge": { "message": "Köprü" }, + "bridgeDontSend": { + "message": "Köprü yap, gönderme" + }, "browserNotSupported": { "message": "Tarayıcınız desteklenmiyor..." }, @@ -598,6 +719,9 @@ "busy": { "message": "Meşgul" }, + "buyAndSell": { + "message": "Alın ve Satın" + }, "buyAsset": { "message": "$1 satın al", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -609,6 +733,10 @@ "buyNow": { "message": "Şimdi Satın Al" }, + "buyToken": { + "message": "$1 Al", + "description": "$1 is the token symbol" + }, "bytes": { "message": "Bayt" }, @@ -618,9 +746,6 @@ "cancel": { "message": "İptal" }, - "cancelEdit": { - "message": "Düzenlemeyi İptal Et" - }, "cancelPopoverTitle": { "message": "İşlemi iptal et" }, @@ -647,6 +772,9 @@ "chainIdExistsErrorMsg": { "message": "Bu Zincir Kimliği şu anda $1 ağı tarafından kullanılıyor." }, + "chainListReturnedDifferentTickerSymbol": { + "message": "Bu token sembolü, girilen ağ adı veya zincir kimliği ile uyumlu değil. Pek çok popüler token benzer sembolleri kullanır ve dolandırıcılar, karşılığında daha değerli bir token gönderecekleri yönünde sizi kandırmak için bunları kullanabilirler. Devam etmeden önce her şeyi doğrulayın." + }, "chooseYourNetwork": { "message": "Ağınızı seçin" }, @@ -682,14 +810,24 @@ "close": { "message": "Kapat" }, + "closeExtension": { + "message": "Uzantıyı kapat" + }, + "closeWindowAnytime": { + "message": "Dilediğiniz zaman bu pencereyi kapatabilirsiniz." + }, "coingecko": { "message": "CoinGecko" }, + "comboNoOptions": { + "message": "Hiçbir seçenek bulunamadı", + "description": "Default text shown in the combo field dropdown if no options." + }, "configureSnapPopupDescription": { - "message": "Şu anda bu snapi yapılandırmak için MetaMask'tan ayrılıyorsunuz." + "message": "Şu anda bu snapi yapılandırmak için MetaMask'ten ayrılıyorsunuz." }, "configureSnapPopupInstallDescription": { - "message": "Şu anda bu snapi yüklemek için MetaMask'tan ayrılıyorsunuz." + "message": "Şu anda bu snapi yüklemek için MetaMask'ten ayrılıyorsunuz." }, "configureSnapPopupInstallTitle": { "message": "Snapi yükle" @@ -703,12 +841,42 @@ "confirm": { "message": "Onayla" }, + "confirmAlertModalAcknowledge": { + "message": "Uyarıları kabul ediyorum ve yine de ilerlemek istiyorum" + }, + "confirmAlertModalDetails": { + "message": "Oturum açarsanız dolandırıcıklarla bilinen üçüncü bir taraf tüm varlıklarınızı ele geçirebilir. İlerlemeden önce lütfen uyarıları inceleyin." + }, + "confirmAlertModalTitle": { + "message": "Varlıklarınız risk altında olabilir" + }, + "confirmConnectCustodianRedirect": { + "message": "Devam et düğmesine tıkladığınızda sizi şuraya yönlendireceğiz: $1." + }, + "confirmConnectCustodianText": { + "message": "Hesaplarınızı bağlamak için $1 hesabınızda oturum açın ve 'MMI'ye bağlan' düğmesine tıklayın." + }, + "confirmConnectionTitle": { + "message": "$1 ile bağlantıyı onayla" + }, "confirmPassword": { "message": "Şifreyi onayla" }, "confirmRecoveryPhrase": { "message": "Gizli Kurtarma İfadesini Onayla" }, + "confirmTitleDescContractInteractionTransaction": { + "message": "Bu işlemi sadece içeriği tam olarak anlıyorsanız ve talepte bulunan siteye güveniyorsanız onaylayın." + }, + "confirmTitleDescSignature": { + "message": "Bu mesajı sadece içeriği onaylıyorsanız ve talepte bulunan siteye güveniyorsanız onaylayın." + }, + "confirmTitleSignature": { + "message": "İmza talebi" + }, + "confirmTitleTransaction": { + "message": "İşlem talebi" + }, "confirmed": { "message": "Onaylandı" }, @@ -724,9 +892,15 @@ "connect": { "message": "Bağla" }, + "connectAccount": { + "message": "Hesabı bağla" + }, "connectAccountOrCreate": { "message": "Hesabı bağla ya da yeni hesap oluştur" }, + "connectAccounts": { + "message": "Hesapları bağla" + }, "connectCustodialAccountMenu": { "message": "Saklayıcı Kurum Hesabı Bağla" }, @@ -736,36 +910,25 @@ "connectCustodialAccountTitle": { "message": "Saklayıcı Kurum Hesapları" }, + "connectCustodianAccounts": { + "message": "$1 hesaplarını bağla" + }, "connectManually": { "message": "Mevcut siteye manuel olarak bağlan" }, + "connectMoreAccounts": { + "message": "Daha fazla hesap bağla" + }, "connectSnap": { "message": "Şuna bağlanın: $1", "description": "$1 is the snap for which a connection is being requested." }, - "connectTo": { - "message": "$1 uygulamasına bağlan", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "Tümüne bağlan: $1", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "hesaplar", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "Bağlan: $1", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1 hesap", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "MetaMask ile Bağlan" }, + "connectedAccounts": { + "message": "Bağlı hesaplar" + }, "connectedAccountsDescriptionPlural": { "message": "Bu siteye bağlı $1 hesabınız var.", "description": "$1 is the number of accounts" @@ -776,6 +939,13 @@ "connectedAccountsEmptyDescription": { "message": "MetaMask bu siteye bağlı değil. Bir web3 sitesine bağlanmak için siteyi bulun ve bağlan düğmesine tıklayın." }, + "connectedAccountsListTooltip": { + "message": "$1 hesap bakiyenizi, adresinizi, aktivitenizi görebilir ve bağlı hesapları onaylamak için işlem önerebilir.", + "description": "$1 is the origin name" + }, + "connectedAccountsToast": { + "message": "Bağlı hesaplar güncellendi" + }, "connectedSites": { "message": "Bağlı siteler" }, @@ -787,12 +957,21 @@ "message": "$1 herhangi bir siteye bağlanmamış.", "description": "$1 is the account name" }, + "connectedSnapAndNoAccountDescription": { + "message": "MetaMask bu siteye bağlı ancak henüz bağlı hesap yok" + }, + "connectedWith": { + "message": "Şununla bağlanıldı:" + }, "connecting": { "message": "Bağlanıyor..." }, "connectingTo": { "message": "Şuna bağlanılıyor: $1" }, + "connectingToDeprecatedNetwork": { + "message": "'$1' aşamalı olarak devre dışı bırakılıyor ve çalışmayabilir. Başka bir ağ deneyin." + }, "connectingToGoerli": { "message": "Goerli Test Ağına Bağlanıyor" }, @@ -802,6 +981,9 @@ "connectingToLineaMainnet": { "message": "Linea Ana Ağına bağlanılıyor" }, + "connectingToLineaSepolia": { + "message": "Linea Sepolia test ağına bağlanılıyor" + }, "connectingToMainnet": { "message": "Ethereum Ana Ağına bağlanıyor" }, @@ -831,6 +1013,12 @@ "continue": { "message": "Devam et" }, + "continueMmiOnboarding": { + "message": "MetaMask Institutional katılım programına devam et" + }, + "continueToWallet": { + "message": "Cüzdana devam et" + }, "contract": { "message": "Sözleşme" }, @@ -882,6 +1070,9 @@ "copyAddress": { "message": "Adresi panoya kopyala" }, + "copyPrivateKey": { + "message": "Özel anahtarı kopyala" + }, "copyRawTransactionData": { "message": "Ham işlem verisini kopyala" }, @@ -900,6 +1091,15 @@ "createPassword": { "message": "Şifre Oluştur" }, + "createSnapAccountDescription": { + "message": "$1 MetaMask'e yeni bir hesap eklemek istiyor." + }, + "createSnapAccountTitle": { + "message": "Hesap oluştur" + }, + "crossChainSwapsLink": { + "message": "MetaMask Portfolio ile ağlar arasında swap gerçekleştirin" + }, "cryptoCompare": { "message": "CryptoCompare" }, @@ -950,10 +1150,16 @@ "message": "Saklayıcı Kurum" }, "custodianAccountAddedDesc": { - "message": "Artık saklayıcı kurum hesaplarınızı MetaMask Institutional'da kullanabilirsiniz." + "message": "Artık hesaplarınızı MetaMask Institutional'da kullanabilirsiniz." }, "custodianAccountAddedTitle": { - "message": "Seçili saklayıcı kurum hesapları ekledi." + "message": "Seçili $1 hesapları ekledi." + }, + "custodianQRCodeScan": { + "message": "$1 mobil uygulamanızla QR kodunu tarayın" + }, + "custodianQRCodeScanDescription": { + "message": "Veya $1 hesabınızda oturum açın ve \"MMI'ye Bağlan\" düğmesine tıklayın" }, "custodianReplaceRefreshTokenChangedFailed": { "message": "Hesaplarınızı tekrar MMI'ya bağlamak için lütfen $1 bölümüne gidin ve kullanıcı arayüzünde 'MMI'ya bağla' düğmesine tıklayın." @@ -1017,7 +1223,7 @@ "message": "Token algılama henüz bu ağda mevcut değil. Lütfen tokeni manuel olarak içe aktarın ve ona güvendiğinizden emin olun. $1 hakkında bilgi edinin" }, "customTokenWarningInTokenDetectionNetwork": { - "message": "Bir token'ı manuel olarak içe aktarmadan önce, ona güvendiğinden emin ol. $1 hakkında bilgi edin." + "message": "Mevcut tokenlerin sahteleri de dahil olmak üzere herkes bir token oluşturabilir. $1 hakkında bilgi edinin" }, "customTokenWarningInTokenDetectionNetworkWithTDOFF": { "message": "Bir tokeni içe aktarmadan önce ona güvendiğinizden emin olun. $1 kaçınmayı öğrenin. Ayrıca token algılamayı $2 etkinleştirebilirsiniz." @@ -1025,6 +1231,12 @@ "customerSupport": { "message": "müşteri hizmetleri" }, + "customizeYourNotifications": { + "message": "Bildirimlerinizi özelleştirin" + }, + "customizeYourNotificationsText": { + "message": "Almak istediğiniz bildirim türlerini açın:" + }, "dappRequestedSpendingCap": { "message": "Site tarafından talep edilen harcama üst limiti" }, @@ -1108,6 +1320,18 @@ "deposit": { "message": "Para Yatır" }, + "deprecatedGoerliNtwrkMsg": { + "message": "Ethereum sistemindeki güncellemelerden dolayı Goerli test ağı yakında aşamalı olarak devre dışı bırakılacaktır." + }, + "deprecatedNetwork": { + "message": "Bu ağ artık kullanılmıyor" + }, + "deprecatedNetworkButtonMsg": { + "message": "Anladım" + }, + "deprecatedNetworkDescription": { + "message": "Bağlanmaya çalıştığınız ağ artık Metamask tarafından desteklenmiyor. $1" + }, "description": { "message": "Açıklama" }, @@ -1115,110 +1339,20 @@ "message": "$1 açıklaması", "description": "$1 represents the name of the snap" }, - "desktopApp": { - "message": "Masaüstü Uygulaması" - }, - "desktopConnectionCriticalErrorDescription": { - "message": "Bu hata aralıklı olarak meydana gelebilir, bu yüzden uzantıyı yeniden başlatmayı veya MetaMask Masaüstünü devre dışı bırakmayı deneyin." - }, - "desktopConnectionCriticalErrorTitle": { - "message": "MetaMask başlatılırken sorun oluştu" - }, - "desktopConnectionLostErrorDescription": { - "message": "Lütfen masaüstü uygulamasının açık olduğundan ve çalıştığından emin olun veya MetaMask Masaüstünü devre dışı bırakın." - }, - "desktopConnectionLostErrorTitle": { - "message": "MetaMask Masaüstü bağlantısı kaybedildi" - }, - "desktopDisableButton": { - "message": "Masaüstü Uygulamasını devre dışı bırakın" - }, - "desktopDisableErrorCTA": { - "message": "MetaMask Masaüstünü devre dışı bırakın" - }, - "desktopEnableButton": { - "message": "Masaüstü Uygulamasını etkinleştirin" - }, - "desktopEnableButtonDescription": { - "message": "Arka plandaki tüm işlemleri masaüstü uygulamasında çalıştırmak için tıklayın." - }, - "desktopErrorNavigateSettingsCTA": { - "message": "Ayarlar Sayfasına geri dönün" - }, - "desktopErrorRestartMMCTA": { - "message": "MetaMask'i yeniden başlatın" - }, - "desktopNotFoundErrorCTA": { - "message": "MetaMask Masaüstü uygulamasını indirin" - }, - "desktopNotFoundErrorDescription1": { - "message": "Lütfen masaüstü uygulamasının açık olduğundan ve çalıştığından emin ol." - }, - "desktopNotFoundErrorDescription2": { - "message": "Herhangi bir masaüstü uygulaması yüklü durumda değilse lütfen MetaMask web sitesinden indirin." - }, - "desktopNotFoundErrorTitle": { - "message": "MetaMask Masaüstü bulunamadı" - }, - "desktopOpenOrDownloadCTA": { - "message": "MetaMask Masaüstünü açın" - }, - "desktopOutdatedErrorCTA": { - "message": "MetaMask Masaüstünü güncelleyin" - }, - "desktopOutdatedErrorDescription": { - "message": "MetaMask masaüstü uygulamanın yükseltilmesi gerekiyor." - }, - "desktopOutdatedErrorTitle": { - "message": "MetaMask Masaüstü güncel değil" - }, - "desktopOutdatedExtensionErrorCTA": { - "message": "MetaMask Uzantısını güncelleyin" - }, - "desktopOutdatedExtensionErrorDescription": { - "message": "MetaMask uzantının yükseltilmesi gerekiyor." - }, - "desktopOutdatedExtensionErrorTitle": { - "message": "MetaMask Uzantısı güncel değil" - }, - "desktopPageDescription": { - "message": "Eşleştirme başarılı olursa uzantı yeniden başlatılır ve şifrenizi tekrar girmeniz gerekir." - }, - "desktopPageSubTitle": { - "message": "MetaMask Masaüstü uygulamanızı açın ve bu kodu girin" - }, - "desktopPageTitle": { - "message": "Masaüstü ile eşleştirin" - }, - "desktopPairedWarningDeepLink": { - "message": "MetaMask Masaüstü uygulamasında Ayarlar kısmına gidin" - }, - "desktopPairedWarningDescription": { - "message": "Yeni bir eşleştirme başlatmak istiyorsanız lütfen mevcut bağlantıyı kaldırın." - }, - "desktopPairedWarningTitle": { - "message": "MM Masaüstü zaten eşleştirilmiş" - }, - "desktopPairingExpireMessage": { - "message": "Kod $1 içinde geçerliliğini yitirecek" - }, - "desktopRouteNotFoundErrorDescription": { - "message": "desktopRouteNotFoundErrorDescription" - }, - "desktopRouteNotFoundErrorTitle": { - "message": "desktopRouteNotFoundErrorTitle" + "details": { + "message": "Ayrıntılar" }, - "desktopUnexpectedErrorCTA": { - "message": "MetaMask Ana Sayfasına geri dönün" + "developerOptions": { + "message": "Geliştirici Seçenekleri" }, - "desktopUnexpectedErrorDescription": { - "message": "Yeniden bağlantı sağlamak için MetaMask Masaüstü uygulamanızı kontrol edin" + "developerOptionsResetStatesAnnouncementsDescription": { + "message": "Tüm duyurular için isShown boolean değerini false olarak sıfırlar. Duyurular, Yenilikler açılır penceresi modalında gösterilen bildirimlerdir." }, - "desktopUnexpectedErrorTitle": { - "message": "Bir şeyler ters gitti..." + "developerOptionsResetStatesOnboarding": { + "message": "Katılım ile ilgili çeşitli durumları sıfırlar ve \"Cüzdanınızı Koruyun\" katılım sayfasına yeniden yönlendirir." }, - "details": { - "message": "Ayrıntılar" + "developerOptionsServiceWorkerKeepAlive": { + "message": "Zaman damgasının sürekli olarak oturum depolama alanına kaydedilmesine neden olur" }, "disabledGasOptionToolTipMessage": { "message": "Orijinal gaz ücretinden minimum %10'luk bir artışı karşılamadığı için \"$1\" devre dışı bırakıldı.", @@ -1233,12 +1367,38 @@ "disconnectAllAccountsConfirmationDescription": { "message": "Bağlantıyı kesmek istediğinizden emin misiniz? Sitenin işlevselliğini kaybedebilirsiniz." }, + "disconnectAllAccountsText": { + "message": "hesaplar" + }, + "disconnectAllSnapsText": { + "message": "Snap'ler" + }, + "disconnectAllText": { + "message": "$1 ile $2 bağlantısını keserseniz onları tekrar kullanmak için tekrar bağlamanız gerekir.", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`, $2 represents the website hostname" + }, + "disconnectAllTitle": { + "message": "Tüm $1 bağlantısını kes", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`" + }, "disconnectPrompt": { "message": "$1 bağlantısını kes" }, "disconnectThisAccount": { "message": "Bu hesabın bağlantısını kes" }, + "disconnectedAllAccountsToast": { + "message": "Tüm hesapların $1 ile bağlantısı kesildi", + "description": "$1 is name of the dapp`" + }, + "disconnectedSingleAccountToast": { + "message": "$1 için $2 bağlantısı kesildi", + "description": "$1 is name of the name and $2 represents the dapp name`" + }, + "discoverSnaps": { + "message": "Snap'leri keşfedin", + "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." + }, "dismiss": { "message": "Yoksay" }, @@ -1248,9 +1408,21 @@ "dismissReminderField": { "message": "Gizli Kurtarma İfadesi yedekleme hatırlatma uyarısını yoksay" }, + "displayNftMedia": { + "message": "NFT medyasını göster" + }, + "displayNftMediaDescription": { + "message": "NFT medyasının ve verilerin gösterilmesi IP adresinizin OpenSea veya diğer üçüncü taraflarla paylaşılmasına neden olur. Bu durum, saldırganların IP adresinizi Ethereum adresinizle ilişkilendirmesini sağlayabilir. NFT otomatik algılama bu ayara dayalıdır ve bu ayar kapatıldığında kullanılamaz olur." + }, + "doNotShare": { + "message": "Bunu hiç kimseyle paylaşmayın" + }, "domain": { "message": "Alan" }, + "domainNotSupportedOnNetwork": { + "message": "Ağ alan aramasını desteklemiyor" + }, "done": { "message": "Bitti" }, @@ -1269,6 +1441,9 @@ "downloadStateLogs": { "message": "Durum Günlüklerini İndir" }, + "dragAndDropBanner": { + "message": "Yeniden sıralamak için ağları sürükleyebilirsiniz. " + }, "dropped": { "message": "Bırakıldı" }, @@ -1367,6 +1542,9 @@ "editSpeedUpEditGasFeeModalTitle": { "message": "Hızlandırma gaz ücretini düzenle" }, + "enable": { + "message": "Etkinleştir" + }, "enableAutoDetect": { "message": " Otomatik algılamayı etkinleştir" }, @@ -1397,6 +1575,18 @@ "enhancedTokenDetectionAlertMessage": { "message": "Gelişmiş token algılama şu anda $1 üzerinden kullanılabilir. $2" }, + "ensDomainsSettingDescriptionIntroduction": { + "message": "MetaMask, ENS alanlarını doğrudan tarayıcınızın adres çubuğunda görmenizi sağlar. Şöyle çalışır:" + }, + "ensDomainsSettingDescriptionOutroduction": { + "message": "Bu özelliğin kullanılmasının IP adresinizi IPFS üçüncü taraf hizmetleriyle paylaştığını unutmayın." + }, + "ensDomainsSettingDescriptionPart1": { + "message": "MetaMask, ENS adına bağlı kodu bulmak için Ethereum'un ENS sözleşmesi ile kontrol gerçekleştirir." + }, + "ensDomainsSettingDescriptionPart2": { + "message": "Kod IPFS'ye bağlanıyorsa onunla ilişkili içeriği (genellikle bir web sitesi) görebilirsiniz." + }, "ensDomainsSettingTitle": { "message": "ENS alanlarını adres çubuğunda göster" }, @@ -1438,6 +1628,9 @@ "message": "Hata ayrıntıları", "description": "Title for collapsible section that displays error details for debugging purposes" }, + "errorGettingSafeChainList": { + "message": "Güvenli zincir listesi alınırken hata oluştu, lütfen dikkatli bir şekilde devam edin." + }, "errorMessage": { "message": "Mesaj: $1", "description": "Displayed error message for debugging purposes. $1 is the error message" @@ -1469,6 +1662,9 @@ "message": "$1 ile hata oluştu", "description": "$1 represents the name of the snap" }, + "estimatedFee": { + "message": "Tahmini ücret" + }, "ethGasPriceFetchWarning": { "message": "Ana gaz tahmini hizmeti olarak sunulan yedek gaz fiyatı şu anda kullanılamıyor." }, @@ -1495,12 +1691,24 @@ "message": "Deneysel" }, "extendWalletWithSnaps": { - "message": "Cüzdan deneyimini kişiselleştirin.", + "message": "web3 deneyiminizi kişiselleştirmek için topluluk tarafından oluşturulmuş Snapleri keşfedin", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "extensionInsallCompleteDescription": { + "message": "Saklayıcı kurum veya emanete dayalı olmayan hesaplarınızı bağlamak için MetaMask Institutional ürün katılım programına geri dön." + }, + "extensionInsallCompleteTitle": { + "message": "Uzantı yükleme işlemi tamamlandı" + }, "externalExtension": { "message": "Harici uzantı" }, + "externalNameSourcesSetting": { + "message": "Önerilen takma adlar" + }, + "externalNameSourcesSettingDescription": { + "message": "Etherscan, Infura ve Lens Protocol gibi üçüncü taraf kaynaklardan etkileşimde bulunduğunuz adresler için önerilen takma adları alırız. Bu kaynaklar o adresleri ve sizin IP adresinizi görebilir. Hesap adresiniz üçüncü taraflarla paylaşılmaz." + }, "failed": { "message": "Başarısız oldu" }, @@ -1519,6 +1727,9 @@ "feeAssociatedRequest": { "message": "Bu talep ile ilişkili bir ücret mevcuttur." }, + "feeDetails": { + "message": "Ücret bilgileri" + }, "fiat": { "message": "Fiat Para", "description": "Exchange type" @@ -1551,6 +1762,9 @@ "message": "Riskleri kabul ediyorum", "description": "this text is shown on a button, which the user presses to confirm they understand the risks of using Flask" }, + "floatAmountToken": { + "message": "Token miktarı tam sayı olmalıdır" + }, "followUsOnTwitter": { "message": "Bizi Twitter'da takip edin" }, @@ -1573,6 +1787,9 @@ "fromTokenLists": { "message": "Token listelerinden: $1" }, + "function": { + "message": "İşlev: $1" + }, "functionApprove": { "message": "İşlev: Onayla" }, @@ -1582,6 +1799,13 @@ "functionType": { "message": "İşlev türü" }, + "fundYourWallet": { + "message": "Cüzdanınıza para ekleyin" + }, + "fundYourWalletDescription": { + "message": "Cüzdanınıza biraz $1 ekleyerek başlayın.", + "description": "$1 is the token symbol" + }, "gas": { "message": "Gaz" }, @@ -1592,6 +1816,9 @@ "message": "Bu gaz ücreti $1 tarafından önerilmiştir. Bu değerin başka bir değerle değiştirilmesi işleminizle ilgili bir soruna neden olabilir. Sorularınız olursa lütfen $1 ile iletişime geçin.", "description": "$1 represents the Dapp's origin" }, + "gasIsETH": { + "message": "Gaz $1 " + }, "gasLimit": { "message": "Gaz limiti" }, @@ -1636,6 +1863,9 @@ "message": "$1 sa.", "description": "$1 represents a number of hours" }, + "gasTimingLow": { + "message": "Yavaş" + }, "gasTimingMinutesShort": { "message": "$1 dk", "description": "$1 represents a number of minutes" @@ -1650,15 +1880,29 @@ "general": { "message": "Genel" }, - "globalTitle": { - "message": "Genel menü" + "generalCameraError": { + "message": "Kameranıza erişemedik. Lütfen bir defa daha deneyin." + }, + "generalCameraErrorTitle": { + "message": "Bir şeyler ters gitti...." + }, + "genericExplorerView": { + "message": "Hesabı $1 üzerinde görüntüleyin" + }, + "getStartedWithNFTs": { + "message": "NFT satın almak için $1 edinin", + "description": "$1 is the token symbol" }, - "globalTourDescription": { - "message": "Portföyünüze, bağlı sitelere, ayarlara ve daha fazlasına bakın" + "getStartedWithNFTsDescription": { + "message": "Cüzdanınıza biraz $1 ekleyerek NFT'lere başlayın.", + "description": "$1 is the token symbol" }, "goBack": { "message": "Geri git" }, + "goToSite": { + "message": "Siteye git" + }, "goerli": { "message": "Goerli test ağı" }, @@ -1700,15 +1944,24 @@ "hexData": { "message": "On altılı veri" }, + "hiddenAccounts": { + "message": "Gizli hesaplar" + }, "hide": { "message": "Gizle" }, + "hideAccount": { + "message": "Hesabı gizle" + }, "hideFullTransactionDetails": { "message": "Tam işlem bilgilerini gizle" }, "hideSeedPhrase": { "message": "Anahtar cümleyi gizle" }, + "hideSentitiveInfo": { + "message": "Hassas bilgileri gizle" + }, "hideToken": { "message": "Tokeni gizle" }, @@ -1790,6 +2043,9 @@ "ignoreTokenWarning": { "message": "Gizlediğiniz tokenler cüzdanınızda gösterilmez. Ancak, yine de onları bulup ekleyebilirsiniz." }, + "imToken": { + "message": "imToken" + }, "import": { "message": "İçe Aktar", "description": "Button to import an account from a selected file" @@ -1848,6 +2104,9 @@ "importTokensCamelCase": { "message": "Tokenleri içe aktar" }, + "importTokensError": { + "message": "Tokenleri içe aktaramadık. Lütfen daha sonra tekrar deneyin." + }, "importWithCount": { "message": "$1 tokeni içe aktar", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -1866,6 +2125,9 @@ "initialTransactionConfirmed": { "message": "İlk işleminiz ağ tarafından onaylanmıştır. Geri gitmek için Tamam düğmesine tıklayın." }, + "inlineAlert": { + "message": "Uyarı" + }, "inputLogicEmptyState": { "message": "Sadece şu anda ya da gelecekte üçüncü taraf harcaması konusunda rahat olduğunuz bir sayı girin. Harcama üst limitini daha sonra dilediğiniz zaman artırabilirsiniz." }, @@ -1876,6 +2138,27 @@ "inputLogicHigherNumber": { "message": "Bu işlem, üst limite ulaşana kadar ya da siz harcama üst limitini iptal edene kadar üçüncü tarafın tüm token bakiyenizi harcamasına izin verir. Amacınız bu değilse daha düşük bir harcama üst limiti ayarlamayı deneyin." }, + "insightWarning": { + "message": "uyarıyı" + }, + "insightWarningCheckboxMessage": { + "message": "$2 kaynaklı $1 talebi", + "description": "$1 is the action i.e. sign, confirm. $2 is the origin making the request." + }, + "insightWarningContentPlural": { + "message": "$2 öncesinde $1 inceleyin. Yapıldıktan sonra $3 geri alınamaz.", + "description": "$1 the 'insightWarnings' message (2 warnings) representing warnings, $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningContentSingular": { + "message": "$2 öncesinde $1 inceleyin. Gerçekleştikten sonra $3 geri alınamaz.", + "description": "$1 is the 'insightWarning' message (1 warning), $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningHeader": { + "message": "Bu talep riskli olabilir" + }, + "insightWarnings": { + "message": "uyarıları" + }, "insightsFromSnap": { "message": "$1 kaynaklı içgörüler", "description": "$1 represents the name of the snap" @@ -1883,9 +2166,18 @@ "install": { "message": "Yükle" }, + "installExtension": { + "message": "Uzantıyı yükle" + }, + "installExtensionDescription": { + "message": "Dünyanın lider web3 cüzdanı, MetaMask'in kurumsal uyumlu sürümü." + }, "installOrigin": { "message": "Kökeni yükle" }, + "installRequest": { + "message": "MetaMask'e ekle" + }, "installedOn": { "message": "$1 üzerinde yüklendi", "description": "$1 is the date when the snap has been installed" @@ -1914,6 +2206,12 @@ "insufficientTokens": { "message": "Token yetersiz." }, + "interactingWith": { + "message": "Etkileşimde" + }, + "interactingWithTransactionDescription": { + "message": "Bu sizin etkileşimde bulunduğunuz sözleşmedir. Bilgileri doğrulayarak kendinizi dolandırıcılardan koruyun." + }, "invalidAddress": { "message": "Adres geçersiz" }, @@ -1986,6 +2284,9 @@ "ipfsToggleModalSettings": { "message": "Ayarlar > Güvenlik ve gizlilik" }, + "isSigningOrSubmitting": { + "message": "Önceki bir işlemin imzalanması veya gönderilmesi devam ediyor" + }, "jazzAndBlockies": { "message": "Jazzicons ve Blockies, bir bakışta bir hesabı tanımlamana yardımcı olan iki farklı benzersiz simge stilidir." }, @@ -1999,6 +2300,24 @@ "message": "JSON Dosyası", "description": "format for importing an account" }, + "keyringAccountName": { + "message": "Hesap adı" + }, + "keyringAccountPublicAddress": { + "message": "Genel Adres" + }, + "keyringSnapRemovalResult1": { + "message": "$1 $2kaldırıldı", + "description": "Displays the result after removal of a keyring snap. $1 is the snap name, $2 is whether it is successful or not" + }, + "keyringSnapRemovalResultNotSuccessful": { + "message": "değil ", + "description": "Displays the `not` word in $2." + }, + "keyringSnapRemoveConfirmation": { + "message": "Bu snap'i kaldırmak istediğinizi onaylamak için $1 yazın:", + "description": "Asks user to input the name nap prior to deleting the snap. $1 is the snap name" + }, "keystone": { "message": "Ana İlke" }, @@ -2017,9 +2336,15 @@ "lastSold": { "message": "Son satış" }, + "lavaDomeCopyWarning": { + "message": "Güvenliğiniz için bu metin şu anda seçilemez." + }, "layer1Fees": { "message": "Katman 1 ücretleri" }, + "layer2Fees": { + "message": "Katman 2 ücretleri" + }, "learnCancelSpeeedup": { "message": "Nasıl $1 yapacağınızı öğrenin", "description": "$1 is link to cancel or speed up transactions" @@ -2037,9 +2362,21 @@ "learnMoreUpperCase": { "message": "Daha fazla bilgi" }, + "learnMoreUpperCaseWithDot": { + "message": "Daha fazla bilgi edinin." + }, "learnScamRisk": { "message": "dolandırıcılıklar ve güvenlik riskleri." }, + "learnToBridge": { + "message": "Köprü yapmayı öğren" + }, + "leaveMetaMask": { + "message": "MetaMask'ten ayrıl?" + }, + "leaveMetaMaskDesc": { + "message": "MetaMask'in dışında bir siteyi ziyaret etmek üzeresiniz. Devam etmeden önce URL adresini dikkatli bir şekilde kontrol edin." + }, "ledgerAccountRestriction": { "message": "Yeni bir hesap ekleyebilmeniz için önce son hesabınızı kullanmanız gerekir." }, @@ -2058,6 +2395,18 @@ "ledgerDeviceOpenFailureMessage": { "message": "Ledger cihazı açılamadı. Ledger'ınız başka bir yazılıma bağlanmış olabilir. Lütfen Ledger Live'ı ya da Ledger cihazınızla bağlantılı diğer uygulamaları kapatıp tekrar bağlanmayı deneyin." }, + "ledgerErrorConnectionIssue": { + "message": "Ledger'ınızı tekrar bağlayın, ETH uygulamasını açın ve tekrar deneyin." + }, + "ledgerErrorDevicedLocked": { + "message": "Ledger'ınız kilitli. Kilidini açın, ardından tekrar deneyin." + }, + "ledgerErrorEthAppNotOpen": { + "message": "Sorunu çözmek için cihazınızda ETH uygulamasını açın ve tekrar deneyin." + }, + "ledgerErrorTransactionDataNotPadded": { + "message": "Ethereum işleminin giriş verileri yeterli şekilde doldurulmamış." + }, "ledgerLiveApp": { "message": "Ledger Live Uygulaması" }, @@ -2077,6 +2426,9 @@ "lightTheme": { "message": "Aydınlık" }, + "likeToImportToken": { + "message": "Bu tokeni içe aktarmak ister misiniz?" + }, "likeToImportTokens": { "message": "Bu tokenleri içe aktarmak ister misiniz?" }, @@ -2086,6 +2438,9 @@ "lineaMainnet": { "message": "Linea Ana Ağı" }, + "lineaSepolia": { + "message": "Linea Sepolia test ağı" + }, "link": { "message": "Bağlantı" }, @@ -2098,8 +2453,11 @@ "loading": { "message": "Yükleniyor..." }, - "loadingNFTs": { - "message": "NFT'ler yükleniyor..." + "loadingScreenHardwareWalletMessage": { + "message": "Lütfen işlemi donanım cüzdanında tamamlayın." + }, + "loadingScreenSnapMessage": { + "message": "Lütfen işlemi Snap üzerinde tamamlayın." }, "loadingTokens": { "message": "Tokenler yükleniyor..." @@ -2146,6 +2504,9 @@ "message": "Hiç kimsenin bakmadığından emin olun", "description": "Warning to users to be care while creating and saving their new Secret Recovery Phrase" }, + "manageInSettings": { + "message": "Ayarlar kısmında yönet" + }, "max": { "message": "Maksimum" }, @@ -2180,15 +2541,34 @@ "metaMaskConnectStatusParagraphTwo": { "message": "Bağlantı durumu düğmesi ziyaret ettiğiniz web sitesinin şu anda seçilen hesabınıza bağlı olup olmadığını gösterir." }, + "metadataModalSourceTooltip": { + "message": "$1 npm'de barındırılmaktadır ve $2 bu Snap'in eşsiz tanımlayıcısıdır.", + "description": "$1 is the snap name and $2 is the snap NPM id." + }, "metamaskInstitutionalVersion": { "message": "MetaMask Institutional Sürümü" }, + "metamaskNotificationsAreOff": { + "message": "Cüzdan bildirimleri şu anda aktif değil." + }, + "metamaskPortfolio": { + "message": "MetaMask Portfolio." + }, "metamaskSwapsOfflineDescription": { "message": "MetaMask Swap İşlemleri bakımda. Lütfen daha sonra tekrar kontrol edin." }, "metamaskVersion": { "message": "MetaMask Sürümü" }, + "methodData": { + "message": "Yöntem" + }, + "methodDataTransactionDescription": { + "message": "Atılacak spesifik adım budur. Bu veriler sahte olabilir, o yüzden diğer taraftaki siteye güvendiğinizden emin olun." + }, + "methodNotSupported": { + "message": "Bu hesap ile desteklenmez." + }, "metrics": { "message": "Metrikler" }, @@ -2224,11 +2604,17 @@ "mmiBuiltAroundTheWorld": { "message": "MetaMask Institutional dünya çapında tasarlanmış ve yapılmıştır." }, + "mmiNewNFTDetectedInNFTsTabMessage": { + "message": "MetaMask Institutional'ın otomatik olarak cüzdanınızdaki NFT'leri algılayıp göstermesine izin verin." + }, + "mmiPasswordSetupDetails": { + "message": "Bu şifre sadece MetaMask Institutional uzantınızın kilidini açacaktır." + }, "more": { "message": "daha fazla" }, "multipleSnapConnectionWarning": { - "message": "$1, $2 snaplerine bağlanmak istiyor. Bu web sitesine güveniyorsanız ilerleyin.", + "message": "$1 $2 Snap kullanmak istiyor", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." }, "mustSelectOne": { @@ -2237,10 +2623,80 @@ "name": { "message": "Adı" }, + "nameAddressLabel": { + "message": "Adres", + "description": "Label above address field in name component modal." + }, + "nameInstructionsNew": { + "message": "Bu adresi biliyorsanız gelecekte tanıyabilmek için ona bir takma ad verin.", + "description": "Instruction text in name component modal when value is not recognised." + }, + "nameInstructionsRecognized": { + "message": "Bu adresin varsayılan bir takma adı var ancak onu düzenleyebilir veya diğer önerileri keşfedebilirsiniz.", + "description": "Instruction text in name component modal when value is recognized but not saved." + }, + "nameInstructionsSaved": { + "message": "Daha önce bu adres için bir takma ad eklediniz. Bu takma adı düzenleyebilir veya önerilen diğer takma adları görüntüleyebilirsiniz.", + "description": "Instruction text in name component modal when value is saved." + }, + "nameLabel": { + "message": "Takma Ad", + "description": "Label above name input field in name component modal." + }, + "nameModalMaybeProposedName": { + "message": "Belki: $1", + "description": "$1 is the proposed name" + }, + "nameModalTitleNew": { + "message": "Bilinmeyen adres", + "description": "Title of the modal created by the name component when value is not recognised." + }, + "nameModalTitleRecognized": { + "message": "Tanınan adres", + "description": "Title of the modal created by the name component when value is recognized but not saved." + }, + "nameModalTitleSaved": { + "message": "Adres kaydedildi", + "description": "Title of the modal created by the name component when value is saved." + }, + "nameProviderProposedBy": { + "message": "$1 tarafından önerilir", + "description": "$1 is the name of the provider" + }, + "nameProvider_ens": { + "message": "Ethereum İsimlendirme Hizmeti (ENS)" + }, + "nameProvider_etherscan": { + "message": "Etherscan" + }, + "nameProvider_lens": { + "message": "Lens Protocol" + }, + "nameProvider_token": { + "message": "MetaMask" + }, + "nameSetPlaceholder": { + "message": "Bir takma ad seçin...", + "description": "Placeholder text for name input field in name component modal." + }, + "nativePermissionRequestDescription": { + "message": "Bu sitenin aşağıdakileri yapmasına izin vermek istiyor musunuz?", + "description": "Description below header used on Permission Connect screen for native permissions." + }, "nativeToken": { "message": "Bu ağdaki yerli token $1. Bu gaz ücretleri için kullanılan tokendir.", "description": "$1 represents the name of the native token on the current network" }, + "nativeTokenScamWarningConversion": { + "message": "Ağ bilgilerini düzenle" + }, + "nativeTokenScamWarningDescription": { + "message": "Bu ağ, ilişkili zincir kimliği veya adı ile uyumlu değil. Pek çok popüler token $1 adını kullanarak bunu dolandırıcılar için hedef haline getirir. Dolandırıcılar, karşılığında kendilerine daha değerli para birimi göndermek üzere sizi kandırabilir. Devam etmeden önce her şeyi doğrulayın.", + "description": "$1 represents the currency name" + }, + "nativeTokenScamWarningTitle": { + "message": "Bu potansiyel bir dolandırıcılıktır" + }, "needHelp": { "message": "Yardıma mı ihtiyacınız var? $1 bölümüne ulaşın", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -2261,6 +2717,9 @@ "negativeETH": { "message": "Negatif tutarlarda ETH gönderilemez." }, + "negativeOrZeroAmountToken": { + "message": "Eksi veya sıfır tutarlarda varlık gönderilemez." + }, "network": { "message": "Ağ:" }, @@ -2291,6 +2750,9 @@ "networkNameBSC": { "message": "BSC" }, + "networkNameBase": { + "message": "Temel" + }, "networkNameDefinition": { "message": "Bu ağ ile ilişkilendirilmiş ad." }, @@ -2300,12 +2762,21 @@ "networkNameGoerli": { "message": "Goerli" }, + "networkNameLinea": { + "message": "Linea" + }, + "networkNameOpMainnet": { + "message": "OP Ana Ağı" + }, "networkNamePolygon": { "message": "Polygon" }, "networkNameTestnet": { "message": "Test ağı" }, + "networkNameZkSyncEra": { + "message": "zkSync Era" + }, "networkProvider": { "message": "Ağ sağlayıcısı" }, @@ -2358,6 +2829,19 @@ "newContract": { "message": "Yeni sözleşme" }, + "newNFTDetectedInImportNFTsMessageStrongText": { + "message": "Ayarlar > Güvenlik ve gizlilik" + }, + "newNFTDetectedInImportNFTsMsg": { + "message": "Opensea'yi kullanmak için NFT'lerinize bakın, $1 üzerinde \"NFT Medyasını göster\" seçeneğini açın.", + "description": "$1 is used for newNFTDetectedInImportNFTsMessageStrongText" + }, + "newNFTDetectedInNFTsTabMessage": { + "message": "MetaMask'ın otomatik olarak cüzdanınızdaki NFT'leri algılayıp göstermesine izin verin." + }, + "newNFTsAutodetected": { + "message": "NFT otomatik algılama" + }, "newNetworkAdded": { "message": "\"$1\" başarılı bir şekilde eklendi!" }, @@ -2367,6 +2851,12 @@ "newPassword": { "message": "Yeni Şifre (min 8 karakter)" }, + "newPrivacyPolicyActionButton": { + "message": "Daha fazlasını oku" + }, + "newPrivacyPolicyTitle": { + "message": "Gizlilik politikamızı güncelledik" + }, "newTokensImportedMessage": { "message": "$1 tokeni başarılı bir şekilde içe aktardın.", "description": "$1 is the string of symbols of all the tokens imported" @@ -2388,6 +2878,9 @@ "message": "Bu token bir NFT'dir. $1 üzerinde ekleyin", "description": "$1 is a clickable link with text defined by the 'importNFTPage' key" }, + "nftAlreadyAdded": { + "message": "NFT zaten eklenmiş." + }, "nftDisclaimer": { "message": "Sorumluluğun Reddi: MetaMask medya dosyasını kaynak url adresinden çeker. Bu url adresi bazen NFT'nin mint edildiği pazar yeri tarafından değiştirilir." }, @@ -2423,12 +2916,21 @@ "noAddressForName": { "message": "Bu isim için adres tanımlanmamış." }, + "noConnectedAccountDescription": { + "message": "Devam etmek için bu sitede kullanmak istediğiniz bir hesap seçin." + }, + "noConnectedAccountTitle": { + "message": "MetaMask bu siteye bağlı değil" + }, "noConversionDateAvailable": { "message": "Para birimi dönüşüm tarihi mevcut değil" }, "noConversionRateAvailable": { "message": "Dönüşüm oranı mevcut değil" }, + "noDomainResolution": { + "message": "Alan adı için çözümleme sunulmamış." + }, "noNFTs": { "message": "Henüz NFT yok" }, @@ -2447,6 +2949,9 @@ "noWebcamFoundTitle": { "message": "Web kamerası bulunamadı" }, + "nonCustodialAccounts": { + "message": "MetaMask Institutional, gözetimsiz hesapları kullanabilmenize olanak sağlar, bu hesapları kullanmayı planlıyorsanız Gizli Kurtarma İfadenizi yedekleyin." + }, "nonce": { "message": "Nonce" }, @@ -2477,6 +2982,111 @@ "notePlaceholder": { "message": "Onaylayan taraf saklayıcı kurumda işlemi onaylarken bu notu görecektir." }, + "notificationDetail": { + "message": "Ayrıntılar" + }, + "notificationDetailBaseFee": { + "message": "Baz ücret (GWEI)" + }, + "notificationDetailGasLimit": { + "message": "Gaz limiti (birim)" + }, + "notificationDetailGasUsed": { + "message": "Kullanılan gaz (birim)" + }, + "notificationDetailMaxFee": { + "message": "Gaz başına maks. ücret" + }, + "notificationDetailNetwork": { + "message": "Ağ" + }, + "notificationDetailNetworkFee": { + "message": "Ağ ücreti" + }, + "notificationDetailPriorityFee": { + "message": "Öncelik ücreti (GWEI)" + }, + "notificationItemCheckBlockExplorer": { + "message": "BlockExplorer üzerinde kontrol et" + }, + "notificationItemCollection": { + "message": "Tahsilat" + }, + "notificationItemConfirmed": { + "message": "Onaylandı" + }, + "notificationItemError": { + "message": "Şu anda ücretler alınamıyor" + }, + "notificationItemFrom": { + "message": "Kimden" + }, + "notificationItemLidoStakeReadyToBeWithdrawn": { + "message": "Para Çekmeye Hazır" + }, + "notificationItemLidoStakeReadyToBeWithdrawnMessage": { + "message": "Şu anda unstake $1 çekebilirsiniz" + }, + "notificationItemLidoWithdrawalRequestedMessage": { + "message": "$1 unstake etme talebiniz gönderildi" + }, + "notificationItemNFTReceivedFrom": { + "message": "NFT gönderen" + }, + "notificationItemNFTSentTo": { + "message": "NFT alıcısı" + }, + "notificationItemNetwork": { + "message": "Ağ" + }, + "notificationItemRate": { + "message": "Oran (ücret dahil)" + }, + "notificationItemReceived": { + "message": "Alınan" + }, + "notificationItemReceivedFrom": { + "message": "Gönderen" + }, + "notificationItemSent": { + "message": "Alıcı" + }, + "notificationItemSentTo": { + "message": "Stake tamamlandı" + }, + "notificationItemStakeCompleted": { + "message": "Stake edildi" + }, + "notificationItemStaked": { + "message": "Stake edildi" + }, + "notificationItemStakingProvider": { + "message": "Stake Sağlayıcısı" + }, + "notificationItemStatus": { + "message": "Durum" + }, + "notificationItemSwapped": { + "message": "Swap yapılan" + }, + "notificationItemSwappedFor": { + "message": "şununla" + }, + "notificationItemTo": { + "message": "Kime" + }, + "notificationItemTransactionId": { + "message": "İşlem Numarası" + }, + "notificationItemUnStakeCompleted": { + "message": "UnStake tamamlandı" + }, + "notificationItemUnStaked": { + "message": "Unstake edildi" + }, + "notificationItemUnStakingRequested": { + "message": "Unstake talep edildi" + }, "notificationTransactionFailedMessage": { "message": "$1 işlemi başarısız oldu! $2", "description": "Content of the browser notification that appears when a transaction fails" @@ -2504,43 +3114,6 @@ "notifications": { "message": "Bildirimler" }, - "notifications20ActionText": { - "message": "Daha fazla bilgi", - "description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a ledger page to resolve the U2F connection issue." - }, - "notifications20Description": { - "message": "Firefox'un en son sürümündeyseniz Firefox'un U2F desteğini bırakması ile ilgili sorun yaşıyor olabilirsiniz.", - "description": "Description of a notification in the 'See What's New' popup. Describes the U2F support being dropped by firefox and that it affects ledger users." - }, - "notifications20Title": { - "message": "Bağlantı Sorunları Yaşayan Ledger ve Firefox Kullanıcıları", - "description": "Title for a notification in the 'See What's New' popup. Tells users that latest firefox users using U2F may experience connection issues." - }, - "notifications24ActionText": { - "message": "Anladım" - }, - "notifications24Description": { - "message": "Gelişmiş gaz ücreti ayarları, artık kullandığınız ağa göre hatırlanıyor. Başka bir deyişle her bir ağ için belirli gelişmiş gaz ücretleri belirleyebilir ve gaz veya sıkışmış işlemler için fazla ödeme yapmaktan kaçınabilirsiniz." - }, - "notifications24Title": { - "message": "Ağa göre gelişmiş gaz ücretleri" - }, - "notifications8ActionText": { - "message": "Ayarlar / Gelişmiş kısmına git", - "description": "Description on an action button that appears in the What's New popup. Tells the user that if they click it, they will go to our Advanced settings page." - }, - "notifications8DescriptionOne": { - "message": "MetaMask 10.4.0 sürümü itibariyle Ledger cihazınızı MetaMask'e bağlamak için artık Ledger Live'e ihtiyacınız yok.", - "description": "Description of a notification in the 'See What's New' popup. Describes changes for how Ledger Live is no longer needed to connect the device." - }, - "notifications8DescriptionTwo": { - "message": "Daha kolay ve daha kararlı kayıt defteri deneyimi için Ayarlar > Gelişmiş sekmesine git ve \"Tercih Edilen Ledger Bağlantı Türü\" seçeneğini \"WebHID\" olarak değiştir.", - "description": "Description of a notification in the 'See What's New' popup. Describes how the user can turn off the Ledger Live setting." - }, - "notifications8Title": { - "message": "Ledger bağlantı iyileştirmesi", - "description": "Title for a notification in the 'See What's New' popup. Notifies ledger users that there is an improvement in how they can connect their device." - }, "notificationsDropLedgerFirefoxDescription": { "message": "Firefox artık U2F'yi desteklemiyor, bu yüzden Ledger Firefox'ta Metamask ile çalışmayacaktır. Onun yerine MetaMask'i Google Chrome'da deneyin.", "description": "Description of a notification in the 'See What's New' popup. Describes that ledger will not longer be supported for firefox users and they should use MetaMask on chrome for ledger support instead." @@ -2549,33 +3122,37 @@ "message": "Firefox için Ledger Desteğinin Bitmesi", "description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped." }, - "notificationsEmptyText": { - "message": "Burada yüklü snaplerinizden bildirimleri bulabilirsiniz." + "notificationsFeatureToggle": { + "message": "Cüzdan Bildirimleri Etkinleştir", + "description": "Experimental feature title" }, - "notificationsHeader": { - "message": "Bildirimler" - }, - "notificationsInfos": { - "message": "$1 tarihli bildirim: $2", - "description": "$1 is the date at which the notification has been dispatched and $2 is the link to the snap that dispatched the notification." + "notificationsFeatureToggleDescription": { + "message": "Bu, para veya nft gönder/al gibi cüzdan bildirimlerini veya özellik uyarılarını etkinleştirir.", + "description": "Description of the experimental notifications feature" }, "notificationsMarkAllAsRead": { "message": "Tümünü okundu olarak işaretle" }, - "notificationsOpenBetaSnapsActionText": { - "message": "Daha fazla bilgi edinin" + "notificationsPageEmptyTitle": { + "message": "Burada gösterilecek bir şey yok" + }, + "notificationsPageErrorContent": { + "message": "Lütfen bu sayfayı tekrar ziyaret etmeyi deneyin." + }, + "notificationsPageErrorTitle": { + "message": "Bir hata oluştu" }, - "notificationsOpenBetaSnapsDescriptionOne": { - "message": "MetaMask Snaps'in Açık Beta sürümünü duyurmaktan heyecan duyuyoruz!" + "notificationsPageNoNotificationsContent": { + "message": "Henüz herhangi bir bildirim almadınız." }, - "notificationsOpenBetaSnapsDescriptionThree": { - "message": "Geliştirici topluluğu tarafından oluşturulan snap'lerle cüzdanınızı kişiselleştirin!" + "notificationsSettingsBoxError": { + "message": "Bir şeyler ters gitti. Lütfen tekrar deneyin." }, - "notificationsOpenBetaSnapsDescriptionTwo": { - "message": "Snap'ler MetaMask ile daha fazla ağa bağlanma, işlem içgörülerini görme ve kişisel bildirimler alma gibi daha çok şey yapmanıza yardımcı olur." + "notificationsSettingsPageAllowNotifications": { + "message": "Bildirimler ile cüzdanınızda neler olduğundan haberdar olun. Bildirimleri kullanmak için cihazlarınızdaki bazı ayarları senkronize etmek amacıyla bir profil kullanıyoruz. $1" }, - "notificationsOpenBetaSnapsTitle": { - "message": "MetaMask Snaps tanıtımı" + "notificationsSettingsPageAllowNotificationsLink": { + "message": "Bu özelliği kullanırken gizliliğinizi nasıl koruduğumuzu öğrenin." }, "numberOfNewTokensDetectedPlural": { "message": "Bu hesapta $1 yeni token bulundu", @@ -2599,6 +3176,9 @@ "on": { "message": "Açık" }, + "onboarding": { + "message": "Katılım" + }, "onboardingAdvancedPrivacyIPFSDescription": { "message": "IPFS ağ geçidi üçüncü tarafların barındırdığı veriler için erişim ve görüntülemeyi mümkün kılar. Özel bir IPFS ağ geçidi ekleyebilir veya varsayılanı kullanmaya devam edebilirsiniz." }, @@ -2629,51 +3209,45 @@ "onboardingMetametricsAgree": { "message": "Kabul ediyorum" }, - "onboardingMetametricsAllowOptOut": { - "message": "Her zaman Ayarlar kısmından vazgeçebilmenize izin verir" - }, - "onboardingMetametricsDataTerms": { - "message": "Bu veriler toplanmıştır ve bu nedenle 2016/679 sayılı Genel Veri Koruma Tüzüğü (AB) maksadıyla isimsizdir." - }, "onboardingMetametricsDescription": { - "message": "MetaMask kullanıcılarımızn MetaMask ile nasıl etkileşimde bulunduklarını daha iyi anlamak amacıyla kullanım verilerini toplamak ister. Bu veriler, hizmeti kullanımınıza göre geliştirmek de dahil olmak üzere hizmeti sunmak için kullanılacaktır." + "message": "MetaMask'i iyileştirmek için temel kullanım ve tanılama verilerini toplamak istiyoruz. Burada sunduğunuz verileri asla satmadığımızı bilmenizi isteriz." }, "onboardingMetametricsDescription2": { - "message": "MetaMask..." + "message": "Ölçümleri toplarken bu her zaman aşağıdaki gibi olacaktır..." }, "onboardingMetametricsDisagree": { "message": "Hayır, istemiyorum" }, "onboardingMetametricsInfuraTerms": { - "message": "* MetaMask'te varsayılan RPC sağlayıcınız olarak Infura'yı kullandığınızda, siz bir işlem gönderdiğinizde Infura tarafından IP adresiniz ve Ethereum cüzdan adresiniz toplanır. Bu bilgileri sistemlerimizin bu iki veri parçasını ilişkilendirebilmesini sağlayan şekilde saklamayız. MetaMask ve Infura'nın veri toplama açısından nasıl etkileşimde bulundukları hakkında daha fazla bilgi için lütfen güncel $1 bölümümüze bakın. Genel olarak gizlilik uygulamalarımız hakkında daha fazla bilgi için $2 bölümümüze bakın.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" + "message": "Bu verileri başka amaçlar için kullanmaya karar vermemiz durumunda sizi bilgilendireceğiz. Daha fazla bilgi için $1 bölümümüzü inceleyebilirsiniz. Unutmayın, dilediğiniz zaman ayarlar kısmına giderek vazgeçebilirsiniz.", + "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, "onboardingMetametricsInfuraTermsPolicy": { - "message": "buradan Gizlilik Politikası" - }, - "onboardingMetametricsInfuraTermsPolicyLink": { - "message": "burada" + "message": "Gizlilik Politikası" }, "onboardingMetametricsModalTitle": { "message": "Özel ağ ekle" }, "onboardingMetametricsNeverCollect": { - "message": "$1 ihtiyacımız olmayan bilgileri (anahtarlar, adresler, işlem hash değerleri veya bakiyeler gibi) hizmeti sunmak için toplar", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 uygulama üzerindeki tıklamalar ve görüntülemeler depolanır ancak diğer bilgiler (genel adresiniz gibi) depolanmaz.", + "description": "$1 represents `onboardingMetametricsNeverCollectEmphasis`" + }, + "onboardingMetametricsNeverCollectEmphasis": { + "message": "Özel:" }, "onboardingMetametricsNeverCollectIP": { - "message": "$1 tam IP adresinizi toplar*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 genel bir konumu (ülkeniz veya bölgeniz gibi) algılamak için geçici olarak IP adresinizi kullanırız ancak bu bilgi asla saklanmaz.", + "description": "$1 represents `onboardingMetametricsNeverCollectIPEmphasis`" }, - "onboardingMetametricsNeverEmphasis": { - "message": "Hiçbir Zaman" + "onboardingMetametricsNeverCollectIPEmphasis": { + "message": "Genel:" }, "onboardingMetametricsNeverSellData": { - "message": "$1 verileri satmaz. Asla!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 kullanım verilerinizi paylaşmak veya silmek isteyip istemediğinize ayarlar kısmından dilediğiniz zaman siz karar verirsiniz.", + "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" }, - "onboardingMetametricsSendAnonymize": { - "message": "İsimsiz tıklama ve sayfa görüntüleme etkinlikleri gönder" + "onboardingMetametricsNeverSellDataEmphasis": { + "message": "İsteğe bağlı:" }, "onboardingMetametricsTitle": { "message": "MetaMask'i iyileştirmemize yardımcı olun" @@ -2714,15 +3288,26 @@ "onboardingPinExtensionTitle": { "message": "MetaMask kurulumunuz tamamlandı!" }, + "onboardingPinMmiExtensionLabel": { + "message": "MetaMask Institutional'ı sabitle" + }, "onboardingUsePhishingDetectionDescription": { "message": "Kimlik avı tespiti uyarıları $1 ile iletişime bağlıdır. jsDeliver IP adresinize erişim sağlayacaktır. Şunu görüntüleyin: $2.", "description": "The $1 is the word 'jsDeliver', from key 'jsDeliver' and $2 is the words Privacy Policy from key 'privacyMsg', both separated here so that it can be wrapped as a link" }, + "onekey": { + "message": "OneKey" + }, "onlyAddTrustedNetworks": { "message": "Kötü amaçlı bir ağ sağlayıcı blokzinciri durumu hakkında yalan söyleyebilir ve ağ aktivitenizi kaydedebilir. Sadece güvendiğiniz özel ağları ekleyin." }, "onlyConnectTrust": { - "message": "Sadece güvendiğiniz sitelere bağlayın." + "message": "Sadece güvendiğiniz sitelere bağlayın. $1", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." + }, + "openCustodianApp": { + "message": "$1 uygulamasını aç", + "description": "The $1 is the name of the Custodian that will be open" }, "openFullScreenForLedgerWebHid": { "message": "Ledger'ınızı bağlamak için tam ekrana gidin.", @@ -2734,6 +3319,15 @@ "openSeaNew": { "message": "OpenSea" }, + "openSeaToBlockaidBtnLabel": { + "message": "Snap'leri Keşfet" + }, + "openSeaToBlockaidDescription": { + "message": "Güvenlik uyarıları artık bu ağda mevcut değil. Bir Snap yüklemek güvenliğinizi artırabilir." + }, + "openSeaToBlockaidTitle": { + "message": "Dikkat!" + }, "operationFailed": { "message": "İşlem Başarısız Oldu" }, @@ -2777,6 +3371,9 @@ "password": { "message": "Şifre" }, + "passwordMmiTermsWarning": { + "message": "MetaMask Institutional'ın benim için bu şifreyi kurtaramayacağını anlıyorum. $1" + }, "passwordNotLongEnough": { "message": "Şifre yeterince uzun değil" }, @@ -2803,6 +3400,10 @@ "message": "Özel anahtar dizinizi buraya yapıştırın:", "description": "For importing an account from a private key" }, + "paymasterInUse": { + "message": "Bu işlemin gaz ücreti veznedar tarafından ödenecektir.", + "description": "Alert shown in transaction confirmation if paymaster in use." + }, "pending": { "message": "Bekleyen" }, @@ -2816,18 +3417,26 @@ "message": "Bekleyen (1) işleminiz var.", "description": "$1 is count of pending transactions" }, - "permissionRequest": { - "message": "İzin talebi" + "permissionDetails": { + "message": "İzin ayrıntıları" }, - "permissionRequestCapitalized": { + "permissionRequest": { "message": "İzin talebi" }, "permissionRequested": { "message": "Şimdi talep edildi" }, + "permissionRequestedForAccounts": { + "message": "Şimdi $1 için talep edildi", + "description": "Permission cell status for requested permission including accounts, rendered as AvatarGroup which is $1." + }, "permissionRevoked": { "message": "Bu güncellemede iptal edildi" }, + "permissionRevokedForAccounts": { + "message": "$1 için bu güncellemede iptal edildi", + "description": "Permission cell status for revoked permission including accounts, rendered as AvatarGroup which is $1." + }, "permission_accessNamedSnap": { "message": "$1 alanına bağlanın.", "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." @@ -2836,6 +3445,10 @@ "message": "İnternete erişim sağla.", "description": "The description of the `endowment:network-access` permission." }, + "permission_accessNetworkDescription": { + "message": "$1 adlı snap'in internete erişim sağlamasına izin verin. Üçüncü taraf sunucuları ile hem veri göndermek hem de veri almak için kullanılabilir.", + "description": "An extended description of the `endowment:network-access` permission. $1 is the snap name." + }, "permission_accessSnap": { "message": "$1 snape bağlan.", "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." @@ -2848,10 +3461,18 @@ "message": "Periyodik eylemleri planla ve gerçekleştir.", "description": "The description for the `snap_cronjob` permission" }, + "permission_cronjobDescription": { + "message": "$1 adlı snap'in sabit saat, tarih veya aralıklarda periyodik olarak çalışan eylemleri gerçekleştirmesine izin verin. Zamana duyarlı etkileşim ya da bildirimleri tetiklemek için kullanılabilir.", + "description": "An extended description for the `snap_cronjob` permission. $1 is the snap name." + }, "permission_dialog": { "message": "MetaMask'te iletişim kutusu pencerelerini göster.", "description": "The description for the `snap_dialog` permission" }, + "permission_dialogDescription": { + "message": "$1 adlı snap'in bir eylemi onaylamak ya da reddetmek için özel metin, giriş alanı ve düğmelerle MetaMask açılır pencerelerini göstermesine izin verin.\nBir snap için ör. uyarı, onay ve talep edilen akış oluşturmak için kullanılabilir.", + "description": "An extended description for the `snap_dialog` permission. $1 is the snap name." + }, "permission_ethereumAccounts": { "message": "Adrese, hesap bakiyesine, aktiviteye bakın ve işlemleri başlatın", "description": "The description for the `eth_accounts` permission" @@ -2860,30 +3481,138 @@ "message": "Ethereum sağlayıcısına ulaş.", "description": "The description for the `endowment:ethereum-provider` permission" }, + "permission_ethereumProviderDescription": { + "message": "Blok zincirinden veri okuyabilmesi ve mesaj ile işlemleri önerebilmesi için $1 adlı snap'in doğrudan MetaMask ile iletişim kurmasına izin verin.", + "description": "An extended description for the `endowment:ethereum-provider` permission. $1 is the snap name." + }, + "permission_getEntropy": { + "message": "$1 için eşsiz rastgele anahtarları türetin.", + "description": "The description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getEntropyDescription": { + "message": "$1 adlı snap'in, paylaşmadan, $1 adlı snap'e özel rastgele anahtarlar türetmesine izin verin. Bu anahtarlar MetaMask hesap veya hesaplarınızdan ayrıdır ve özel anahtarlarınızla ya da Gizli Kurtarma İfadenizle bağlantılı değildir. Diğer snap'ler bu bilgilere erişemez.", + "description": "An extended description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getLocale": { + "message": "Tercih ettiğiniz dili görüntüleyin.", + "description": "The description for the `snap_getLocale` permission" + }, + "permission_getLocaleDescription": { + "message": "$1 adlı bu snap'in MetaMask ayarlarınızdan tercih ettiğiniz dile erişim sağlamasına izin verin. $1 içeriğini dilinizi kullanarak yerelleştirmek ve görüntülemek için bu özellik kullanılabilir.", + "description": "An extended description for the `snap_getLocale` permission. $1 is the snap name." + }, + "permission_homePage": { + "message": "Özel bir ekran göster", + "description": "The description for the `endowment:page-home` permission" + }, + "permission_homePageDescription": { + "message": "$1 snap'inin MetaMask'te özel bir ana sayfa ekranı göstermesine izin verin. Bu, kullanıcı arayüzleri, yapılandırma ve kontrol panelleri için kullanılabilir.", + "description": "An extended description for the `endowment:page-home` permission. $1 is the snap name." + }, + "permission_keyring": { + "message": "Ethereum hesaplarını ekleme ve kontrol etme taleplerine izin ver", + "description": "The description for the `endowment:keyring` permission" + }, + "permission_keyringDescription": { + "message": "$1 adlı snap'in hesap ekleme ve kaldırma talepleri almasına ve ayrıca bu hesapların adına imza ve işlem gerçekleştirmesine izin verin.", + "description": "An extended description for the `endowment:keyring` permission. $1 is the snap name." + }, "permission_lifecycleHooks": { "message": "Yaşam döngüsü kancalarını kullanın.", "description": "The description for the `endowment:lifecycle-hooks` permission" }, + "permission_lifecycleHooksDescription": { + "message": "Bu yaşam döngüsü sırasında belirli zamanlarda kod çalıştırmak için $1 adlı snap'in yaşam döngüsü kancalarını kullanmasına izin verin.", + "description": "An extended description for the `endowment:lifecycle-hooks` permission. $1 is the snap name." + }, "permission_manageAccounts": { "message": "Ethereum hesaplarını ekle ve kontrol et", "description": "The description for `snap_manageAccounts` permission" }, + "permission_manageAccountsDescription": { + "message": "$1 adlı snap'in Ethereum hesabı eklemesine veya kaldırmasına izin verin, ardından bu hesaplarla işlem ve imza gerçekleştirin.", + "description": "An extended description for the `snap_manageAccounts` permission. $1 is the snap name." + }, + "permission_manageBip32Keys": { + "message": "$1 hesaplarını yönet.", + "description": "The description for the `snap_getBip32Entropy` permission. $1 is a derivation path, e.g. 'm/44'/0'/0' (secp256k1)'." + }, + "permission_manageBip44AndBip32KeysDescription": { + "message": "$1 adlı snap'in talep edilen ağ üzerinde hesap ve varlıkları yönetmesine izin verin. Bu hesaplar, gizli kurtarma ifadenizi kullanarak (açığa çıkarmadan) türetilir ve yedeklenir. $1, anahtar türetme gücü ile Ethereum (EVM'ler) ötesinde çeşitli blok zinciri protokollerini destekleyebilir.", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions. $1 is the snap name." + }, + "permission_manageBip44Keys": { + "message": "$1 hesaplarını yönetin.", + "description": "The description for the `snap_getBip44Entropy` permission. $1 is the name of a protocol, e.g. 'Filecoin'." + }, "permission_manageState": { "message": "Verilerini cihazında sakla ve yönet.", "description": "The description for the `snap_manageState` permission" }, + "permission_manageStateDescription": { + "message": "$1 adlı snap'in şifreleme ile güvenli bir şekilde veri depolamasına, güncellemesine ve almasına izin verin. Diğer snap'ler bu bilgilere erişim sağlayamaz.", + "description": "An extended description for the `snap_manageState` permission. $1 is the snap name." + }, + "permission_nameLookup": { + "message": "Alan ve adres aramalarını sunun.", + "description": "The description for the `endowment:name-lookup` permission." + }, + "permission_nameLookupDescription": { + "message": "Snap'in MetaMask Arayüzünün farklı kısımlarında adres ve alan aramalarını almasına ve göstermesine izin verin.", + "description": "An extended description for the `endowment:name-lookup` permission." + }, "permission_notifications": { "message": "Bildirimleri göster.", "description": "The description for the `snap_notify` permission" }, + "permission_notificationsDescription": { + "message": "$1 adlı snap'in MetaMask dahilinde bildirim göstermesine izin verin. Eyleme geçirilebilir ya da zamana duyarlı bilgiler için bir snap tarafından kısa bir bildirim metni tetiklenebilir.", + "description": "An extended description for the `snap_notify` permission. $1 is the snap name." + }, + "permission_rpc": { + "message": "$1 için $2 ile doğrudan iletişim kurmasına izin verin.", + "description": "The description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescription": { + "message": "$1 için $2 adlı snap'e mesaj gönderme ve $2 adlı snap'ten yanıt alma izni verin.", + "description": "An extended description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescriptionOriginList": { + "message": "$1 ve $2", + "description": "A list of allowed origins where $2 is the last origin of the list and $1 is the rest of the list separated by ','." + }, + "permission_signatureInsight": { + "message": "İmza içgörüleri kipini göster.", + "description": "The description for the `endowment:signature-insight` permission" + }, + "permission_signatureInsightDescription": { + "message": "$1 adlı snap'in onaydan önce imza taleplerinde içgörüleri içeren bir kipi göstermesine izin verin. Bu, kimlik avını önlemek ve güvenlik çözümleri için kullanılabilir.", + "description": "An extended description for the `endowment:signature-insight` permission. $1 is the snap name." + }, + "permission_signatureInsightOrigin": { + "message": "İmza talebi başlatan web sitelerinin kökenlerini gör", + "description": "The description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission" + }, + "permission_signatureInsightOriginDescription": { + "message": "$1 adlı snap'in imza talepleri başlatan web sitelerinin kökenini (URI) görmesine izin ver. Bu, kimlik avını önlemek ve güvenlik çözümleri için kullanılabilir.", + "description": "An extended description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission. $1 is the snap name." + }, "permission_transactionInsight": { "message": "İşlem içgörülerini al ve görüntüle.", "description": "The description for the `endowment:transaction-insight` permission" }, + "permission_transactionInsightDescription": { + "message": "$1 adlı snap'in işlemlerin şifresini çözmesine ve MetaMask Kullanıcı Arayüzü dahilinde içgörüleri göstermesine izin verin. Kimlik avından korunma ve güvenlik çözümleri için kullanılabilir.", + "description": "An extended description for the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_transactionInsightOrigin": { "message": "İşlem öneren web sitelerinin kökenlerini gör", "description": "The description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission" }, + "permission_transactionInsightOriginDescription": { + "message": "$1 adlı snap'in işlem öneren web sitelerinin asıl adresini (URI) görmesine izin verin. Kimlik avından korunma ve güvenlik çözümleri için kullanılabilir.", + "description": "An extended description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_unknown": { "message": "Bilinmeyen izin: $1", "description": "$1 is the name of a requested permission that is not recognized." @@ -2892,29 +3621,66 @@ "message": "$1 ($2) için genel anahtarınızı görüntüleyin.", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a derivation path, e.g. 'm/44'/0'/0''. $2 is the elliptic curve name, e.g. 'secp256k1'." }, + "permission_viewBip32PublicKeysDescription": { + "message": "$2 adlı snap'in $1 için genel anahtarları (ve adresleri) görüntülemesine izin verin. Bu eylem, herhangi bir şekilde hesapların ya da varlıkların kontrolünü vermez.", + "description": "An extended description for the `snap_getBip32PublicKey` permission. $1 is a derivation path (name). $2 is the snap name." + }, "permission_viewNamedBip32PublicKeys": { "message": "$1 için genel anahtarınızı görüntüleyin.", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a name for the derivation path, e.g., 'Ethereum accounts'." }, + "permission_walletSwitchEthereumChain": { + "message": "Şu ağa geçin ve onu kullanın", + "description": "The label for the `wallet_switchEthereumChain` permission" + }, "permission_webAssembly": { "message": "WebAssembly desteği.", "description": "The description of the `endowment:webassembly` permission." }, + "permission_webAssemblyDescription": { + "message": "$1 adlı snap'in WebAssembly aracılığıyla düşük seviye yürütme ortamlarına erişim sağlamasına izin verin.", + "description": "An extended description of the `endowment:webassembly` permission. $1 is the snap name." + }, "permissions": { "message": "İzinler" }, - "permissionsTitle": { - "message": "İzinler" + "permissionsPageEmptyContent": { + "message": "Burada gösterilecek bir şey yok" }, - "permissionsTourDescription": { - "message": "Burada bağlı hesaplarınızı bulun ve izinleri yönetin" + "permissionsPageEmptySubContent": { + "message": "Burada, yüklü Snap'lere veya bağlı sitelere verdiğiniz izinleri görebilirsiniz." + }, + "permissionsPageTourDescription": { + "message": "Burası, bağlı sitelere ve yüklü Snap'lere verilen izinleri yönetebileceğiniz kontrol panelinizdir." + }, + "permissionsPageTourTitle": { + "message": "Bağlı siteler şimdi izinler oldu" }, "personalAddressDetected": { "message": "Kişisel adres algılandı. Token sözleşme adresini girin." }, + "petnamesEnabledToggle": { + "message": "Takma adlara izin ver" + }, + "petnamesEnabledToggleDescription": { + "message": "Bu, dilediğiniz adrese takma ad atamanıza olanak sağlar. Mümkün olduğunda etkileşimde bulunduğunuz adresler için ad önerilerinde bulunacağız." + }, + "pinExtensionDescription": { + "message": "Sorunsuz erişim için uzantı menüsüne gidin ve MetaMask Institutional'ı sabitleyin." + }, + "pinExtensionTitle": { + "message": "Uzantıyı sabitle" + }, + "pinToTop": { + "message": "Yukarıya sabitle" + }, "pleaseConfirm": { "message": "Lütfen onayla" }, + "plusMore": { + "message": "+ $1 tane daha", + "description": "$1 is the number of additional items" + }, "plusXMore": { "message": "+ $1 tane daha", "description": "$1 is a number of additional but unshown items in a list- this message will be shown in place of those items" @@ -2940,6 +3706,9 @@ "primaryCurrencySettingDescription": { "message": "Değerlerin zincirin yerli para biriminde (ör. ETH) görüntülenmesini önceliklendirmek için yerli seçimi yapın. Seçtiğiniz fiat parada değerlerin gösterilmesini önceliklendirmek için Fiat Para seçin." }, + "primaryType": { + "message": "Öncelikli tür" + }, "priorityFee": { "message": "Öncelik ücreti" }, @@ -2960,6 +3729,18 @@ "message": "$1 için özel anahtar", "description": "$1 represents the account name" }, + "privateKeyHidden": { + "message": "Özel anahtar gizli", + "description": "Explains that the private key input is hidden" + }, + "privateKeyShow": { + "message": "Özel anahtar girişini göster/gizle", + "description": "Describes a toggle that is used to show or hide the private key input" + }, + "privateKeyShown": { + "message": "Özel anahtar gösteriliyor", + "description": "Explains that the private key input is being shown" + }, "privateKeyWarning": { "message": "Uyarı: Bu anahtarı kimse ile paylaşmayın. Özel anahtarlarınıza sahip herkes hesaplarınızıdaki tüm varlığınızı çalabilir." }, @@ -2969,6 +3750,21 @@ "proceedWithTransaction": { "message": "Yine de devam etmek istiyorum" }, + "productAnnouncements": { + "message": "Ürün duyuruları" + }, + "profileSync": { + "message": "Profil Senkronizasyonu" + }, + "profileSyncConfirmation": { + "message": "Profil senkronizasyonunu açarsanız bildirimleri alamayacaksınız." + }, + "profileSyncDescription": { + "message": "MetaMask'in cihazlarınız arasıonda bazı ayarları senkronize etmek için kullandığı bir profil oluşturur. Bildirim almak için bu gereklidir. $1." + }, + "profileSyncPrivacyLink": { + "message": "Gizliliğinizi nasıl koruduğumuzu öğrenin" + }, "proposedApprovalLimit": { "message": "Önerilen onay limiti" }, @@ -2978,6 +3774,78 @@ "publicAddress": { "message": "Genel adres" }, + "pushPlatformNotificationsFundsReceivedDescription": { + "message": "$1 $2 aldınız" + }, + "pushPlatformNotificationsFundsReceivedDescriptionDefault": { + "message": "Bir miktar token aldınız" + }, + "pushPlatformNotificationsFundsReceivedTitle": { + "message": "Para alındı" + }, + "pushPlatformNotificationsFundsSentDescription": { + "message": "$1 $2 gönderdiniz" + }, + "pushPlatformNotificationsFundsSentDescriptionDefault": { + "message": "Başarılı bir şekilde bir miktar token gönderdiniz" + }, + "pushPlatformNotificationsFundsSentTitle": { + "message": "Para gönderildi" + }, + "pushPlatformNotificationsNftReceivedDescription": { + "message": "Yeni NFT'ler aldınız" + }, + "pushPlatformNotificationsNftReceivedTitle": { + "message": "NFT alındı" + }, + "pushPlatformNotificationsNftSentDescription": { + "message": "Başarılı bir şekilde bir NFT gönderdiniz" + }, + "pushPlatformNotificationsNftSentTitle": { + "message": "NFT gönderildi" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedDescription": { + "message": "Lido stake işleminiz başarılı oldu" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedTitle": { + "message": "Stake tamamlandı" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnDescription": { + "message": "Lido stake işleminiz şu anda para çekme işlemine hazır" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnTitle": { + "message": "Stake para çekme işlemine hazır" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedDescription": { + "message": "Lido para çekme işleminiz başarılı oldu" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedTitle": { + "message": "Para çekme işlemi tamamlandı" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedDescription": { + "message": "Lido para çekme talebiniz gönderildi" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedTitle": { + "message": "Para çekme talep edildi" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedDescription": { + "message": "RocketPool stake işleminiz başarılı oldu" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedTitle": { + "message": "Stake tamamlandı" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedDescription": { + "message": "RocketPool unstake işleminiz başarılı oldu" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedTitle": { + "message": "Unstake tamamlandı" + }, + "pushPlatformNotificationsSwapCompletedDescription": { + "message": "MetaMask Swap işleminiz başarılı oldu" + }, + "pushPlatformNotificationsSwapCompletedTitle": { + "message": "Swap işlemi tamamlandı" + }, "queued": { "message": "Kuyruğa alındı" }, @@ -2996,9 +3864,15 @@ "receive": { "message": "Al" }, + "receiveTokensCamelCase": { + "message": "Token'leri al" + }, "recipientAddressPlaceholder": { "message": "Genel adres (0x) veya ENS adı girin" }, + "recipientAddressPlaceholderFlask": { + "message": "Genel adres (0x) veya alan adı girin" + }, "recommendedGasLabel": { "message": "Önerilen" }, @@ -3026,6 +3900,12 @@ "recoveryPhraseReminderTitle": { "message": "Paranızı koruyun" }, + "redesignedConfirmationsEnabledToggle": { + "message": "İmza talepleri iyileştirildi" + }, + "redesignedConfirmationsToggleDescription": { + "message": "İmza taleplerini geliştirilmiş bir biçimde görmek için bunu açın." + }, "refreshList": { "message": "Listeyi yenile" }, @@ -3068,15 +3948,30 @@ "removeJWTDescription": { "message": "Bu tokeni kaldırmak istediğinizden emin misiniz? Bu tokene atanan tüm hesaplar uzantıdan da kaldırılacaktır: " }, + "removeKeyringSnap": { + "message": "Bu Snap kaldırıldığında bu hesaplar MetaMask'ten kaldırılır:" + }, + "removeKeyringSnapToolTip": { + "message": "Hesapları snap kontrol eder ve snap kaldırıldığında hesaplar MetaMask'ten de kaldılır, ancak blokzincirinde kalır." + }, "removeNFT": { "message": "NFT'yi kaldır" }, + "removeNftErrorMessage": { + "message": "Bu NFT'yi kaldıramıyoruz." + }, "removeNftMessage": { "message": "NFT başarılı bir şekilde kaldırıldı!" }, "removeSnap": { "message": "Snapi kaldır" }, + "removeSnapAccountDescription": { + "message": "İlerlerseniz bu hesap artık MetaMask'te kullanılamayacak." + }, + "removeSnapAccountTitle": { + "message": "Hesabı kaldırın" + }, "removeSnapConfirmation": { "message": "$1 snapini kaldırmak istediğinizden emin misiniz?", "description": "$1 represents the name of the snap" @@ -3087,12 +3982,24 @@ "replace": { "message": "değiştir" }, + "reportIssue": { + "message": "Bir sorun bildir" + }, "requestFlaggedAsMaliciousFallbackCopyReason": { "message": "Güvenlik sağlayıcısı başka bilgi paylaşmadı" }, "requestFlaggedAsMaliciousFallbackCopyReasonTitle": { "message": "Talep kötü amaçlı olarak işaretlendi" }, + "requestFrom": { + "message": "Talebi gönderen" + }, + "requestFromInfo": { + "message": "İmzanızı isteyen site budur." + }, + "requestFromTransactionDescription": { + "message": "Bu site tarafından onayınız isteniyor." + }, "requestMayNotBeSafe": { "message": "Talep güvenli olmayabilir" }, @@ -3114,6 +4021,9 @@ "reset": { "message": "Sıfırla" }, + "resetStates": { + "message": "Durumları Sıfırla" + }, "resetWallet": { "message": "Cüzdanı sıfırla" }, @@ -3142,7 +4052,7 @@ "message": "Kullanıcı verilerini geri yükle" }, "restoreUserDataDescription": { - "message": "Tercihleri ve hesap adreslerini içeren kullanıcı ayarlarını daha önce yedeklenmiş bir JSON dosyasından geri yükleyebilirsiniz." + "message": "Kişiler ve tercihler gibi verileri yedek bir dosyadan geri yükleyebilirsiniz." }, "resultPageError": { "message": "Hata" @@ -3196,9 +4106,15 @@ "message": "MetaMask Destek bölümü bunu asla talep etmez.", "description": "The bolded texted in the second part of 'revealSeedWordsWarning'" }, + "revealSensitiveContent": { + "message": "Hassas içeriği açığa çıkar" + }, "revealTheSeedPhrase": { "message": "Anahtar cümleyi göster" }, + "reviewAlerts": { + "message": "Uyarıları incele" + }, "revokeAllTokensTitle": { "message": "Tüm $1 için izin erişim ve transfer izni geri çekilsin mi?", "description": "$1 is the symbol of the token for which the user is revoking approval" @@ -3249,6 +4165,9 @@ "searchAccounts": { "message": "Hesapları ara" }, + "searchTokens": { + "message": "Token ara" + }, "secretRecoveryPhrase": { "message": "Gizli Kurtarma İfadesi" }, @@ -3265,7 +4184,8 @@ "message": "Güvenlik uyarıları" }, "securityAlertsDescription": { - "message": "Bu özellik, işlem ve imza taleplerinizi aktif bir şekilde incelerken gizliliğinizi koruyarak Ethereum Ana Ağındaki kötü amaçlı faaliyetlere karşı sizi uyarır. Verileriniz, bu hizmeti sunan üçüncü taraf ile paylaşılmaz. Talepleri onaylamadan önce her zaman gereken özeni kendiniz gösterin. Bu özelliğin tüm kötü amaçlı faaliyetleri algılayacağına dair herhangi bir garanti bulunmamaktadır." + "message": "Bu özellik işlem ve imza taleplerini aktif bir şekilde inceleyerek kötü amaçlı aktivite konusunda sizi uyarır. $1", + "description": "Link to learn more about security alerts" }, "securityAndPrivacy": { "message": "Güvenlik ve gizlilik" @@ -3355,6 +4275,9 @@ "selectAnAccountHelp": { "message": "MetaMask Institutional'da kullanılacak saklayıcı kurum hesaplarını seçin." }, + "selectEnableDisplayMediaPrivacyPreference": { + "message": "NFT medyasını göster seçeneğini açın" + }, "selectHdPath": { "message": "HD yolunu seç" }, @@ -3376,18 +4299,41 @@ "send": { "message": "Gönder" }, + "sendAToken": { + "message": "Bir token gönder" + }, "sendBugReport": { "message": "Bize bir hata raporu gönder." }, + "sendNoContactsConversionText": { + "message": "buraya tıklayın" + }, + "sendNoContactsDescription": { + "message": "Kişiler, diğer hesaba güvenli bir şekilde birden fazla kez işlem gönderebilmenize olanak sağlar. Bir kişi oluşturmak için $1", + "description": "$1 represents the action text 'click here'" + }, + "sendNoContactsTitle": { + "message": "Henüz kişiniz yok" + }, + "sendSelectReceiveAsset": { + "message": "Alınacak varlıkları seçin" + }, + "sendSelectSendAsset": { + "message": "Gönderilecek varlıkları seçin" + }, "sendSpecifiedTokens": { "message": "$1 Gönder", "description": "Symbol of the specified token" }, - "sendTo": { - "message": "Şuraya gönder:" + "sendSwapSubmissionWarning": { + "message": "Bu düğmeye tıklandığında swap işleminiz anında başlatılır. İlerlemeden önce lütfen işlem ayrıntılarınızı inceleyin." + }, + "sendTokenAsToken": { + "message": "$2 olarak $1 gönder", + "description": "Used in the transaction display list to describe a swap and send. $1 and $2 are the symbols of tokens in involved in the swap." }, - "sendTokens": { - "message": "Token gönder" + "sendingAsset": { + "message": "$1 gönderiliyor" }, "sendingDisabled": { "message": "ERC-1155 NFT varlıklarının gönderilmesi henüz desteklenmemektedir." @@ -3400,9 +4346,15 @@ "message": "Uyarı: Para kaybı ile sonuçlanabilecek bir token sözleşmesi göndermek üzeresiniz. $1", "description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning" }, + "sendingZeroAmount": { + "message": "0 $1 gönderiyorsunuz." + }, "sepolia": { "message": "Sepolia test ağı" }, + "serviceWorkerKeepAlive": { + "message": "Service Worker'ı Canlı Tut" + }, "setAdvancedPrivacySettingsDetails": { "message": "MetaMask, ürünün kullanılabilirliğini ve güvenliğini iyileştirmek amacıyla bu güvenilir üçüncü taraf hizmetlerini kullanır." }, @@ -3422,9 +4374,21 @@ "settingsSearchMatchingNotFound": { "message": "Eşleşen sonuç bulunamadı." }, + "settingsSubHeadingSignaturesAndTransactions": { + "message": "İmza ve işlem talepleri" + }, "show": { "message": "Göster" }, + "showAccount": { + "message": "Hesabı göster" + }, + "showExtensionInFullSizeView": { + "message": "Uzantıyı tam boyut görünümde göster" + }, + "showExtensionInFullSizeViewDescription": { + "message": "Uzantı simgesine tıkladığınızda tam boyut görünümünüzü varsayılan yapmak için bunu açın." + }, "showFiatConversionInTestnets": { "message": "Test ağlarında dönüşümü göster" }, @@ -3444,6 +4408,9 @@ "message": "Etherscan'in işlemler listesinde gelecek işlemleri göstermesi için bunu seçin", "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" }, + "showIncomingTransactionsExplainer": { + "message": "Ethereum adresinizi ve IP adresinizi açığa çıkaran her ağ için farklı üçüncü taraf API'lerine güvenir." + }, "showMore": { "message": "Daha fazlasını göster" }, @@ -3483,9 +4450,46 @@ "signin": { "message": "Giriş" }, + "signing": { + "message": "İmzalanıyor" + }, + "simulationDetailsFailed": { + "message": "Tahmininiz yüklenirken bir hata oldu." + }, + "simulationDetailsFiatNotAvailable": { + "message": "Mevcut Değil" + }, + "simulationDetailsIncomingHeading": { + "message": "Aldığınız" + }, + "simulationDetailsNoBalanceChanges": { + "message": "Cüzdanınız için değişiklik öngörülmüyor" + }, + "simulationDetailsOutgoingHeading": { + "message": "Gönderdiğiniz" + }, + "simulationDetailsTitle": { + "message": "Tahmini değişiklikler" + }, + "simulationDetailsTitleTooltip": { + "message": "Tahmini değişiklikler bu işlemi gerçekleştirirseniz meydana gelebilecek değişikliklerdir. Bu bir garanti değil, sadece bir tahmindir." + }, + "simulationDetailsTotalFiat": { + "message": "Toplam = $1", + "description": "$1 is the total amount in fiat currency on one side of the transaction" + }, + "simulationDetailsTransactionReverted": { + "message": "Bu işlemin başarısız olması muhtemel" + }, "simulationErrorMessageV2": { "message": "Gaz tahmini yapamadık. Sözleşmede bir hata olabilir ve bu işlem başarısız olabilir." }, + "simulationsSettingDescription": { + "message": "Onaylamadan önce işlemlerdeki bakiye değişikliklerini tahmin etmek için bunu açın. İşlemlerinizin nihai sonucunu garanti etmez. $1" + }, + "simulationsSettingSubHeader": { + "message": "Bakiye değişikliklerini tahmin edin" + }, "skip": { "message": "Atla" }, @@ -3498,20 +4502,99 @@ "smartContracts": { "message": "Akıllı sözleşmeler" }, - "smartSwapsAreHere": { - "message": "Akıllı Swap'lar burada!" - }, - "smartSwapsDescription": { - "message": "MetaMask Swap işlemleri artık çok daha akıllı! Akıllı Swap'ları etkinleştirmek, MetaMask'in aşağıdakilere yardımcı olmak için Swap'ini programlı olarak optimize etmesine olanak tanır:" - }, "smartSwapsErrorNotEnoughFunds": { "message": "Akıllı swap için yeterli para yok." }, "smartSwapsErrorUnavailable": { "message": "Akıllı Swap'lar geçici olarak kullanılamıyor." }, + "smartTransactionCancelled": { + "message": "İşleminiz iptal edildi" + }, + "smartTransactionCancelledDescription": { + "message": "İşleminiz tamamlanamadığından gereksiz gaz ücreti ödemenizi önlemek amacıyla iptal edildi." + }, + "smartTransactionError": { + "message": "İşleminiz başarısız oldu" + }, + "smartTransactionErrorDescription": { + "message": "Ani piyasa değişimleri başarısızlıklara sebep olabilir. Sorun devam ederse MetaMask müşteri destek bölümüne ulaşın." + }, + "smartTransactionPending": { + "message": "İşleminiz gönderiliyor" + }, + "smartTransactionSuccess": { + "message": "İşleminiz tamamlandı" + }, + "smartTransactionTakingTooLong": { + "message": "Beklettiğimiz için özür dileriz" + }, + "smartTransactionTakingTooLongDescription": { + "message": "İşleminiz $1 dahilinde sonuçlanmazsa iptal edilir ve sizden gaz ücreti alınmaz.", + "description": "$1 is remaining time in seconds" + }, + "smartTransactions": { + "message": "Akıllı İşlemler" + }, + "smartTransactionsBenefit1": { + "message": "%99,5 başarı oranı" + }, + "smartTransactionsBenefit2": { + "message": "Paradan tasarruf sağlar" + }, + "smartTransactionsBenefit3": { + "message": "Gerçek zamanlı güncellemeler" + }, + "smartTransactionsDescription": { + "message": "Akıllı İşlemler ile daha yüksek başarı oranlarının, arkadan çalıştırma korumasının ve daha iyi görünürlüğün kilidini açın." + }, + "smartTransactionsDescription2": { + "message": "Sadece Ethereum'da mevcuttur. Dilediğiniz zaman ayarlar kısmında etkinleştirin veya devre dışı bırakın. $1", + "description": "$1 is an external link to learn more about Smart Transactions" + }, + "smartTransactionsOptItModalTitle": { + "message": "İyileştirilmiş İşlem Koruması" + }, + "snapAccountCreated": { + "message": "Hesap oluşturuldu" + }, + "snapAccountCreatedDescription": { + "message": "Yeni hesabınız kullanılmaya hazır!" + }, + "snapAccountCreationFailed": { + "message": "Hesap oluşturma işlemi başarısız oldu" + }, + "snapAccountCreationFailedDescription": { + "message": "$1 sizin için bir hesap oluşturamadı.", + "description": "$1 is the snap name" + }, + "snapAccountRedirectFinishSigningTitle": { + "message": "İmzalama işlemini bitir" + }, + "snapAccountRedirectSiteDescription": { + "message": "$1 talimatlarını izle" + }, + "snapAccountRemovalFailed": { + "message": "Hesap kaldırma işlemi başarısız oldu" + }, + "snapAccountRemovalFailedDescription": { + "message": "$1 sizin için bu hesabı kaldıramadı.", + "description": "$1 is the snap name" + }, + "snapAccountRemoved": { + "message": "Hesap kaldırıldı" + }, + "snapAccountRemovedDescription": { + "message": "Bu hesap artık MetaMask'te kullanılamayacak." + }, + "snapAccounts": { + "message": "Snap Hesapları" + }, + "snapAccountsDescription": { + "message": "Üçüncü taraf Snapleri tarafından kontrol edilen hesaplar." + }, "snapConnectionWarning": { - "message": "$1, $2 adlı snape bağlanmak istiyor. Bu web sitesine güveniyorsanız ilerleyin.", + "message": "$1 şunu kullanmak istiyor: $2", "description": "$2 is the snap and $1 is the dapp requesting connection to the snap." }, "snapContent": { @@ -3522,15 +4605,35 @@ "message": "Web Sitesi" }, "snapInstallRequest": { - "message": "$1 yüklendiğinde aşağıdaki izinler verilir. Sadece $1 adlı snape güveniyorsanız devam edin.", + "message": "$1 adlı snap'i yüklemek ona aşağıdaki izinleri verir.", "description": "$1 is the snap name." }, "snapInstallSuccess": { "message": "Yükleme tamamlandı" }, + "snapInstallWarningCheck": { + "message": "$1, şunları yapmak için izin istiyor:", + "description": "Warning message used in popup displayed on snap install. $1 is the snap name." + }, "snapInstallWarningHeading": { "message": "Dikkatle ilerleyin" }, + "snapInstallWarningPermissionDescriptionForBip32View": { + "message": "$1 adlı snap'in genel anahtarlarınızı (ve adreslerinizi) görüntülemesine izin verin. Bu eylem, herhangi bir şekilde hesapların ya da varlıkların kontrolünü vermez.", + "description": "An extended description for the `snap_getBip32PublicKey` permission used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionDescriptionForEntropy": { + "message": "$1 adlı Snap'in talep edilen ağlar üzerinde hesap ve varlıkları yönetmesine izin verin. Bu hesaplar, gizli kurtarma ifadenizi kullanarak (açığa çıkarmadan) türetilir ve yedeklenir. $1, anahtar türetme gücü ile Ethereum (EVM'ler) ötesinde çeşitli blok zinciri protokollerini destekleyebilir.", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionNameForEntropy": { + "message": "$1 hesaplarını yönet", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, + "snapInstallWarningPermissionNameForViewPublicKey": { + "message": "$1 için genel anahtarınızı görüntüleyin", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, "snapInstallationErrorDescription": { "message": "$1 yüklenemedi.", "description": "Error description used when snap installation fails. $1 is the snap name." @@ -3548,6 +4651,10 @@ "snapResultSuccessDescription": { "message": "$1 kullanıma hazır" }, + "snapUpdateAlertDescription": { + "message": "En son $1 güncellemesini alın", + "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." + }, "snapUpdateAvailable": { "message": "Güncelleme mevcut" }, @@ -3559,22 +4666,40 @@ "message": "Güncelleme başarısız oldu", "description": "Error title used when snap update fails." }, + "snapUpdateRequest": { + "message": "$1 adlı snap'i güncellemek ona aşağıdaki izinleri verir.", + "description": "$1 is the Snap name." + }, "snapUpdateSuccess": { "message": "Güncelleme tamamlandı" }, + "snapUrlIsBlocked": { + "message": "Bu Snap sizi bloke edilmiş bir siteye götürmek istiyor. $1." + }, "snaps": { "message": "Snapler" }, - "snapsInvalidUIError": { - "message": "Snap tarafından belirtilen kullanıcı arayüzü geçersiz." + "snapsConnected": { + "message": "Snap'ler bağlandı" }, "snapsNoInsight": { "message": "Snap herhangi bir ayrıntıya ulaşamadı" }, + "snapsPrivacyWarningFirstMessage": { + "message": "Yüklediğiniz her Snap'in Consensys $1 içinde tanımlanan şekilde, aksi belirtilmedikçe bir Üçüncü Taraf Hizmet olduğunu kabul edersiniz. Üçüncü Taraf Hizmetlerini kullanımınız Üçüncü Taraf Hizmet sağlayıcısı tarafından belirtilen ayrı şart ve koşullar tarafından yönetilir. Consensys herhangi bir Snapin herhangi belirli bir sebeple herhangi belirli bir şahıs tarafından kullanımını önermez. Üçüncü Taraf Hizmetine erişiminizin, güvenmenizin veya kullanımınızın riski size aittir. Consensys, Üçüncü Taraf Hizmetlerini kullanımınızdan kaynaklanan zararlar için her türlü sorumluluğu ve yükümlülüğü reddeder.", + "description": "First part of a message in popup modal displayed when installing a snap for the first time. $1 is terms of use link." + }, "snapsPrivacyWarningSecondMessage": { "message": "Üçüncü Taraf Hizmetleri ile paylaştığınız tüm bilgiler söz konusu Üçüncü Taraf Hizmetlerinin gizlilik politikalarına göre doğrudan üçüncü taraflar tarafından toplanacaktır. Daha fazla bilgi için lütfen üçüncü tarafların gizlilik politikalarına bakın.", "description": "Second part of a message in popup modal displayed when installing a snap for the first time." }, + "snapsPrivacyWarningThirdMessage": { + "message": "Consensys'un bu Üçüncü Taraf Hizmetler ile paylaştığınız bilgilere hiçbir erişimi bulunmamaktadır.", + "description": "Third part of a message in popup modal displayed when installing a snap for the first time." + }, + "snapsSettings": { + "message": "Snap ayarları" + }, "snapsTermsOfUse": { "message": "Kullanım Şartları" }, @@ -3588,12 +4713,19 @@ "someNetworksMayPoseSecurity": { "message": "Bazı ağlar güvenlik ve/veya gizlilik riskleri teşkil edebilir. Bir ağ eklemeden ve kullanmadan önce riskleri anlayın." }, + "somethingDoesntLookRight": { + "message": "Doğru görünmeyen bir şeyler mi var? $1", + "description": "A false positive message for users to contact support. $1 is a link to the support page." + }, "somethingIsWrong": { "message": "Bir şeyler ters gitti. Sayfayı tekrar yüklemeyi deneyin." }, "somethingWentWrong": { "message": "Eyvah! Bir şeyler ters gitti." }, + "source": { + "message": "Kaynak" + }, "speedUp": { "message": "Hızlandır" }, @@ -3728,6 +4860,14 @@ "stake": { "message": "Pay" }, + "startYourJourney": { + "message": "$1 ile yolculuğunuza başlayın", + "description": "$1 is the token symbol" + }, + "startYourJourneyDescription": { + "message": "Cüzdanınıza biraz $1 ekleyerek web3'e başlayın.", + "description": "$1 is the token symbol" + }, "stateLogError": { "message": "Durum günlükleri alınırken hata." }, @@ -3740,6 +4880,9 @@ "stateLogsDescription": { "message": "Durum günlükleri genel hesap adreslerinizi ve gönderilen işlemleri içerir." }, + "states": { + "message": "Durumlar" + }, "status": { "message": "Durum" }, @@ -3783,18 +4926,6 @@ "strong": { "message": "Güçlü" }, - "stxBenefit1": { - "message": "İşlem maliyetlerini en aza indir" - }, - "stxBenefit2": { - "message": "İşlem hatalarını azalt" - }, - "stxBenefit3": { - "message": "Sıkışmış işlemleri ortadan kaldır" - }, - "stxBenefit4": { - "message": "Önden çalıştırmayı engelle" - }, "stxCancelled": { "message": "Swap işlemi başarısız olurdu" }, @@ -3804,6 +4935,10 @@ "stxCancelledSubDescription": { "message": "Swap işlemini tekrar deneyin. Bir dahaki sefere sizi benzer risklere karşı korumak için burada olacağız." }, + "stxEstimatedCompletion": { + "message": "Tamamlanmasına kalan tahmini süre $1 altında", + "description": "$1 is remeaning time in minutes and seconds, e.g. 0:10" + }, "stxFailure": { "message": "Swap başarısız oldu" }, @@ -3811,6 +4946,9 @@ "message": "Ani piyasa değişiklikleri başarısızlıklara neden olabilir. Sorun devam ederse lütfen $1 ile iletişime geç.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInDescription": { + "message": "Daha güvenilir ve güvenli işlemler için Ethereum Ana Ağı üzerinde Akıllı İşlemleri açın. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Swap işlemin özel olarak gönderiliyor..." }, @@ -3849,12 +4987,21 @@ "submitted": { "message": "Gönderildi" }, + "suggestedTokenSymbol": { + "message": "Önerilen ticker sembolü:" + }, "support": { "message": "Destek" }, "supportCenter": { "message": "Destek Merkezi bölümümüzü ziyaret et" }, + "surveyConversion": { + "message": "Anketimize katılın" + }, + "surveyTitle": { + "message": "MetaMask'in geleceğini şekillendirin" + }, "swap": { "message": "Swap" }, @@ -3874,6 +5021,9 @@ "swapAmountReceivedInfo": { "message": "Bu, alacağınız minimum tutardır. Kaymaya bağlı olarak daha fazla alabilirsiniz." }, + "swapAndSend": { + "message": "Swap Gerçekleştir ve Gönder" + }, "swapAnyway": { "message": "Yine de swap gerçekleştir" }, @@ -3989,6 +5139,10 @@ "message": "%$1 MetaMask ücreti dahildir.", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." }, + "swapIncludesMMFeeAlt": { + "message": "Teklif $1% MetaMask ücretini yansıtır", + "description": "Provides information about the fee that metamask takes for swaps using the latest copy. $1 is a decimal number." + }, "swapIncludesMetaMaskFeeViewAllQuotes": { "message": "%$1 MetaMask ücreti - $2 dahildir", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number and $2 is a link to view all quotes." @@ -3996,6 +5150,9 @@ "swapLearnMore": { "message": "Swap işlemleri hakkında daha fazla bilgi edinin" }, + "swapLiquiditySourceInfo": { + "message": "Dönüştürme oranlarını ve ağ ücretlerini karşılaştırmak için birden fazla likidite kaynağında (borsalar, toplayıcılar ve profesyonel piyasa yapıcıları) arama yaparız." + }, "swapLowSlippage": { "message": "Düşük kayma" }, @@ -4268,6 +5425,9 @@ "switchEthereumChainConfirmationTitle": { "message": "Bu sitenin ağı değiştirmesine izin ver?" }, + "switchInputCurrency": { + "message": "Giriş para birimini değiştir" + }, "switchNetwork": { "message": "Ağı değiştir" }, @@ -4281,14 +5441,15 @@ "switchToThisAccount": { "message": "Bu hesaba geç" }, - "switchedTo": { - "message": "Şuna geçiş yaptınız:" + "switchedNetworkToastDecline": { + "message": "Tekrar gösterme" }, - "switcherTitle": { - "message": "Ağ değiştirici" + "switchedNetworkToastMessage": { + "message": "$1, $2 üzerinde aktif", + "description": "$1 represents the account name, $2 represents the network name" }, - "switcherTourDescription": { - "message": "Ağ değiştirmek veya yeni bir ağ eklemek için simgeye tıklayın" + "switchedTo": { + "message": "Şuna geçiş yaptınız:" }, "switchingNetworksCancelsPendingConfirmations": { "message": "Ağ değiştirmek bekleyen tüm onayları iptal eder" @@ -4388,6 +5549,18 @@ "toggleEthSignOn": { "message": "Açık (Önerilmez)" }, + "toggleRequestQueueDescription": { + "message": "Bu, tüm siteler için tek bir seçili ağ yerine her bir site için bir ağ seçebilmenize olanak sağlar. Bu özellik, manuel olarak ağ değiştirmenizi önleyebilir ve bu da belirli sitelerde kullanıcı deneyiminizi bozabilir." + }, + "toggleRequestQueueField": { + "message": "Her site için ağ seçin" + }, + "toggleRequestQueueOff": { + "message": "Kapalı" + }, + "toggleRequestQueueOn": { + "message": "Açık" + }, "token": { "message": "Token" }, @@ -4404,7 +5577,7 @@ "message": "Token sözleşme adresi" }, "tokenDecimalFetchFailed": { - "message": "Token ondalık değeri gerekli." + "message": "Token ondalığı gereklidir. Şurada bulabilirsiniz: $1" }, "tokenDecimalTitle": { "message": "Token ondalığı:" @@ -4443,6 +5616,9 @@ "tooltipSatusConnected": { "message": "bağlı" }, + "tooltipSatusConnectedUpperCase": { + "message": "Bağlandı" + }, "tooltipSatusNotConnected": { "message": "bağlı değil" }, @@ -4583,6 +5759,39 @@ "tryAgain": { "message": "Tekrar dene" }, + "turnOff": { + "message": "Kapat" + }, + "turnOffMetamaskNotificationsError": { + "message": "Bildirimler devre dışı bırakılırken bir hata oluştu. Lütfen daha sonra tekrar deneyin." + }, + "turnOn": { + "message": "Aç" + }, + "turnOnMetamaskNotifications": { + "message": "Bildirimleri aç" + }, + "turnOnMetamaskNotificationsButton": { + "message": "Aç" + }, + "turnOnMetamaskNotificationsError": { + "message": "Bildirimler oluşturulurken bir hata oluştu. Lütfen daha sonra tekrar deneyin." + }, + "turnOnMetamaskNotificationsMessageFirst": { + "message": "Bildirimler ile cüzdanınızda neler olduğundan haberdar olun." + }, + "turnOnMetamaskNotificationsMessagePrivacyBold": { + "message": "Ayarlar > Bildirimler." + }, + "turnOnMetamaskNotificationsMessagePrivacyLink": { + "message": "Bu özelliği kullanırken gizliliğinizi nasıl koruduğumuzu öğrenin." + }, + "turnOnMetamaskNotificationsMessageSecond": { + "message": "Cüzdan bildirimlerini kullanmak için cihazlarınız genelinde bazı ayarları senkronize etmek üzere bir profil kullanırız. $1" + }, + "turnOnMetamaskNotificationsMessageThird": { + "message": "Bildirimleri dilediğiniz zaman $1 kısmında kapatabilirsiniz" + }, "turnOnTokenDetection": { "message": "Gelişmiş token algılamayı açın" }, @@ -4614,6 +5823,10 @@ "unknownNetwork": { "message": "Bilinmeyen özel ağ" }, + "unknownNetworkForKeyEntropy": { + "message": "Bilinmeyen ağ", + "description": "Displayed on places like Snap install warning when regular name is not available." + }, "unknownQrCode": { "message": "Hata: Bu QR kodunu tanımlayamadık" }, @@ -4626,6 +5839,9 @@ "unlockMessage": { "message": "Merkeziyetsiz web sizi bekliyor" }, + "unpin": { + "message": "Sabitlemeyi kaldır" + }, "unrecognizedChain": { "message": "Bu özel ağ tanınmadı", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." @@ -4643,6 +5859,9 @@ "update": { "message": "Güncelle" }, + "updateRequest": { + "message": "Talebi güncelle" + }, "updatedWithDate": { "message": "$1 güncellendi" }, @@ -4667,12 +5886,25 @@ "useNftDetection": { "message": "NFT'leri otomatik algıla" }, + "useNftDetectionDescriptionText": { + "message": "MetaMask'in üçüncü taraf hizmetleri (OpenSea gibi) kullanarak size ait olan NFT'leri eklemesine izin verin. NFT'leri otomatik algılama, IP adresinizi ve hesap adresinizi bu hizmetlerle paylaşır. Bu özelliğin etkinleştirilmesi IP adresinizi Ethereum adresinizle ilişkilendirebilir ve dolandırıcılar tarafından airdrop'u gerçekleştirilen sahte NFT'leri gösterebilir. Bu riski önlemek için tokenleri elle ekleyebilirsiniz." + }, "usePhishingDetection": { "message": "Kimlik avı algılama kullan" }, "usePhishingDetectionDescription": { "message": "Ethereum kullanıcılarını hedefleyen kimlik avı alanları için bir uyarı görüntüler" }, + "useSafeChainsListValidation": { + "message": "Ağ bilgileri kontrolü" + }, + "useSafeChainsListValidationDescription": { + "message": "MetaMask, doğru ve standartlaştırılmış ağ bilgilerini göstermek için $1 adlı üçüncü taraf bir hizmet kullanır. Bu, kötü amaçlı veya yanlış ağa bağlanma şansınızı düşürür. Bu özelliği kullanırken IP adresiniz chainid.network ile paylaşılır." + }, + "useSafeChainsListValidationWebsite": { + "message": "chainid.network", + "description": "useSafeChainsListValidationWebsite is separated from the rest of the text so that we can bold the third party service name in the middle of them" + }, "useSiteSuggestion": { "message": "Sitenin önerisini kullanın" }, @@ -4685,6 +5917,9 @@ "userName": { "message": "Kullanıcı adı" }, + "userOpContractDeployError": { + "message": "Akıllı sözleşme hesabından sözleşme kurulumu desteklenmiyor" + }, "verifyContractDetails": { "message": "Üçüncü taraf bilgilerini doğrula" }, @@ -4702,6 +5937,9 @@ "view": { "message": "Görüntüle" }, + "viewActivity": { + "message": "Aktiviteyi görüntüle" + }, "viewAllDetails": { "message": "Tüm bilgileri görüntüle" }, @@ -4725,7 +5963,7 @@ }, "viewOnCustomBlockExplorer": { "message": "$1 ögesini $2 üzerinde görüntüle", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "Etherscan'de $1 görüntüle", @@ -4737,6 +5975,9 @@ "viewOnOpensea": { "message": "Opensea'de görüntüle" }, + "viewTransaction": { + "message": "İşlemi görüntüle" + }, "viewinCustodianApp": { "message": "Saklayıcı kurum uygulamasında görüntüle" }, @@ -4744,6 +5985,9 @@ "message": "Explorer'da $1 görüntüle", "description": "$1 is the action type. e.g (Account, Transaction, Swap)" }, + "visitSite": { + "message": "Siteyi ziyaret edin" + }, "visitWebSite": { "message": "Web sitemizi ziyaret et" }, @@ -4782,6 +6026,10 @@ "warning": { "message": "Uyarı" }, + "warningFromSnap": { + "message": "$1 uyarısı", + "description": "$1 represents the name of the snap" + }, "warningTooltipText": { "message": "$1 Üçüncü taraf, başkaca bildiri ya da rıza olmaksızın tüm token bakiyenizi harcayabilir. Düşük bir harcama limitini özelleştirerek kendinizi koruyun.", "description": "$1 is a warning icon with text 'Be careful' in 'warning' colour" @@ -4789,6 +6037,9 @@ "weak": { "message": "Zayıf" }, + "web3": { + "message": "Web3" + }, "web3ShimUsageNotification": { "message": "Mevcut web sitesinin kaldırılmış olan window.web3 API'sini kullanmaya çalıştığını fark ettik. Site bozuk görünüyorsa daha fazla bilgi için lütfen $1 bağlantısına tıklayın.", "description": "$1 is a clickable link." @@ -4829,10 +6080,6 @@ "whatsThis": { "message": "Bu nedir?" }, - "xOfY": { - "message": "$1 / $2", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$1 / $2 bekliyor", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" @@ -4840,6 +6087,9 @@ "yes": { "message": "Evet" }, + "you": { + "message": "Siz" + }, "youHaveAddedAll": { "message": "Tüm popüler ağları eklediniz. $1 daha fazla ağ gekşefedebilir veya $2 seçeneğini seçebilirsiniz", "description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'" @@ -4862,6 +6112,12 @@ "yourPrivateSeedPhrase": { "message": "Gizli Kurtarma İfadeniz" }, + "yourTransactionConfirmed": { + "message": "İşlem zaten onaylandı" + }, + "yourTransactionJustConfirmed": { + "message": "Blok zinciri üzerinde onaylanmadan işleminizi iptal edemedik." + }, "zeroGasPriceOnSpeedUpError": { "message": "Sıfır gaz fiyatı hızlandırmada" } diff --git a/app/_locales/uk/messages.json b/app/_locales/uk/messages.json index 34b90350c6d6..cadac70b7102 100644 --- a/app/_locales/uk/messages.json +++ b/app/_locales/uk/messages.json @@ -630,9 +630,6 @@ "send": { "message": "Надіслати" }, - "sendTokens": { - "message": "Надіслати токени" - }, "settings": { "message": "Налаштування" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index e0705352ea6b..6f2cba66d83b 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -130,12 +130,21 @@ "account": { "message": "Tài khoản" }, + "accountActivity": { + "message": "Hoạt động của tài khoản" + }, + "accountActivityText": { + "message": "Chọn tài khoản mà bạn muốn nhận thông báo:" + }, "accountDetails": { "message": "Chi tiết tài khoản" }, "accountIdenticon": { "message": "Biểu tượng nhận dạng tài khoản" }, + "accountIsntConnectedToastText": { + "message": "$1 không được kết nối với $2" + }, "accountName": { "message": "Tên tài khoản" }, @@ -153,6 +162,12 @@ "accountSelectionRequired": { "message": "Bạn cần chọn một tài khoản!" }, + "accounts": { + "message": "Tài khoản" + }, + "accountsConnected": { + "message": "Đã kết nối tài khoản" + }, "active": { "message": "Đang hoạt động" }, @@ -243,6 +258,9 @@ "addIPFSGateway": { "message": "Thêm cổng IPFS ưa thích của bạn" }, + "addImportAccount": { + "message": "Thêm tài khoản hoặc ví cứng" + }, "addMemo": { "message": "Thêm bản ghi nhớ" }, @@ -256,6 +274,9 @@ "message": "Kết nối mạng này dựa vào các bên thứ ba. Kết nối này có thể kém tin cậy hơn hoặc cho phép các bên thứ ba theo dõi hoạt động. $1", "description": "$1 is Learn more link" }, + "addNewAccount": { + "message": "Thêm tài khoản" + }, "addNewToken": { "message": "Thêm token mới" }, @@ -265,6 +286,12 @@ "addNfts": { "message": "Thêm NFT" }, + "addSnapAccountToggle": { + "message": "Bật \"Thêm tài khoản Snap (Beta)\"" + }, + "addSnapAccountsDescription": { + "message": "Bật tính năng này sẽ cho phép bạn thêm tài khoản Snap (Beta) mới ngay từ danh sách tài khoản của bạn. Nếu bạn cài đặt tài khoản Snap, hãy nhớ rằng đây là một dịch vụ của bên thứ ba." + }, "addSuggestedNFTs": { "message": "Thêm NFT được đề xuất" }, @@ -281,6 +308,9 @@ "addingCustomNetwork": { "message": "Thêm mạng" }, + "addingTokens": { + "message": "Đang thêm token" + }, "address": { "message": "Địa chỉ" }, @@ -316,9 +346,27 @@ "airgapVault": { "message": "AirGap Vault" }, + "alert": { + "message": "Cảnh báo" + }, + "alertBannerMultipleAlertsDescription": { + "message": "Nếu bạn chấp thuận yêu cầu này, một bên thứ ba nổi tiếng là lừa đảo có thể lấy hết tài sản của bạn." + }, + "alertBannerMultipleAlertsTitle": { + "message": "Có nhiều cảnh báo!" + }, "alertDisableTooltip": { "message": "Bạn có thể thay đổi trong phần \"Cài đặt > Cảnh báo\"" }, + "alertModalAcknowledge": { + "message": "Tôi đã nhận thức được rủi ro và vẫn muốn tiếp tục" + }, + "alertModalDetails": { + "message": "Chi tiết cảnh báo" + }, + "alertModalReviewAllAlerts": { + "message": "Xem lại tất cả cảnh báo" + }, "alertSettingsUnconnectedAccount": { "message": "Đang duyệt trang web khi chọn một tài khoản không được kết nối" }, @@ -334,6 +382,9 @@ "alerts": { "message": "Cảnh báo" }, + "all": { + "message": "Tất cả" + }, "allCustodianAccountsConnectedSubtitle": { "message": "Bạn đã kết nối tất cả các tài khoản lưu ký của mình hoặc không có bất kỳ tài khoản nào để kết nối với MetaMask Institutional." }, @@ -344,23 +395,26 @@ "message": "Tất cả $1 của bạn", "description": "$1 is the symbol or name of the token that the user is approving spending" }, + "allPermissions": { + "message": "Tất cả các quyền" + }, "allYourNFTsOf": { "message": "Tất cả NFT của bạn từ $1", "description": "$1 is a link to contract on the block explorer when we're not able to retrieve a erc721 or erc1155 name" }, - "allowExternalExtensionTo": { - "message": "Cho phép tiện ích mở rộng bên ngoài này:" + "allow": { + "message": "Cho phép" + }, + "allowMmiToConnectToCustodian": { + "message": "Điều này sẽ cho phép MMI kết nối với $1 để nhập tài khoản của bạn." + }, + "allowNotifications": { + "message": "Cho phép thông báo" }, "allowSpendToken": { "message": "Cấp quyền truy cập vào $1 của bạn?", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "Cho phép trang web này:" - }, - "allowThisSnapTo": { - "message": "Cho phép Snap này:" - }, "allowWithdrawAndSpend": { "message": "Cho phép $1 rút và chi tiêu tối đa số tiền sau đây:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -368,6 +422,23 @@ "amount": { "message": "Số tiền" }, + "amountReceived": { + "message": "Số tiền đã nhận" + }, + "amountSent": { + "message": "Số tiền đã gửi" + }, + "andForListItems": { + "message": "$1, và $2", + "description": "$1 is the first item, $2 is the last item in a list of items. Used in Snap Install Warning modal." + }, + "andForTwoItems": { + "message": "$1 và $2", + "description": "$1 is the first item, $2 is the second item. Used in Snap Install Warning modal." + }, + "announcements": { + "message": "Thông báo" + }, "appDescription": { "message": "Ví Ethereum trên trình duyệt của bạn", "description": "The description of the application" @@ -402,6 +473,10 @@ "approveButtonText": { "message": "Chấp thuận" }, + "approveIncreaseAllowance": { + "message": "Tăng hạn mức chi tiêu $1", + "description": "The token symbol that is being approved" + }, "approveSpendingCap": { "message": "Duyệt hạn mức chi tiêu $1", "description": "The token symbol that is being approved" @@ -427,6 +502,10 @@ "message": "Đã chấp thuận vào $1", "description": "$1 is the approval date for a permission" }, + "approvedOnForAccounts": { + "message": "Đã phê duyệt vào $1 cho $2", + "description": "$1 is the approval date for a permission. $2 is the AvatarGroup component displaying account images." + }, "areYouSure": { "message": "Bạn có chắc chắn không?" }, @@ -439,6 +518,12 @@ "attemptSendingAssets": { "message": "Nếu bạn cố gắng gửi tài sản trực tiếp từ mạng này sang mạng khác, bạn có thể bị mất tài sản vĩnh viễn. Hãy nhớ sử dụng cầu nối." }, + "attemptSendingAssetsWithPortfolio": { + "message": "Bạn có thể bị mất tài sản nếu cố gắng gửi tài sản từ một mạng khác. Chuyển tiền an toàn giữa các mạng bằng cách sử dụng cầu nối, chẳng hạn như $1" + }, + "attemptToCancelSwapForFree": { + "message": "Cố gắng hủy hoán đổi miễn phí" + }, "attemptingConnect": { "message": "Đang cố gắng kết nối với chuỗi khối." }, @@ -479,6 +564,9 @@ "backupApprovalNotice": { "message": "Sao lưu Cụm từ khôi phục bí mật để đảm bảo an toàn cho ví và tiền của bạn." }, + "backupKeyringSnapReminder": { + "message": "Đảm bảo bạn có thể tự mình truy cập bất kỳ tài khoản nào được tạo bởi Snap này trước khi xóa nó" + }, "backupNow": { "message": "Sao lưu ngay" }, @@ -486,7 +574,7 @@ "message": "Sao lưu dữ liệu của bạn" }, "backupUserDataDescription": { - "message": "Bạn có thể sao lưu chế độ cài đặt người dùng có chứa các tùy chọn và địa chỉ tài khoản vào một tập tin JSON." + "message": "Bạn có thể sao lưu các dữ liệu như địa chỉ liên hệ và tùy chọn của mình." }, "balance": { "message": "Số dư" @@ -500,6 +588,30 @@ "basic": { "message": "Cơ bản" }, + "basicConfigurationBannerCTA": { + "message": "Bật chức năng cơ bản" + }, + "basicConfigurationBannerTitle": { + "message": "Chức năng cơ bản đã tắt" + }, + "basicConfigurationLabel": { + "message": "Chức năng cơ bản" + }, + "basicConfigurationModalCheckbox": { + "message": "Tôi hiểu rõ và muốn tiếp tục" + }, + "basicConfigurationModalDisclaimerOff": { + "message": "Điều này có nghĩa là bạn sẽ không thể tối ưu hoàn toàn thời gian sử dụng MetaMask. Các tính năng cơ bản (chẳng hạn như chi tiết token, cài đặt gas tối ưu và các tính năng khác) sẽ không khả dụng." + }, + "basicConfigurationModalDisclaimerOn": { + "message": "Để tối ưu thời gian sử dụng MetaMask, bạn cần bật tính năng này. Các chức năng cơ bản (chẳng hạn như chi tiết token, cài đặt gas tối ưu và các chức năng khác) rất quan trọng đối với trải nghiệm web3." + }, + "basicConfigurationModalHeadingOff": { + "message": "Tắt chức năng cơ bản" + }, + "basicConfigurationModalHeadingOn": { + "message": "Bật chức năng cơ bản" + }, "beCareful": { "message": "Hãy cẩn thận" }, @@ -571,6 +683,9 @@ "blockaidDescriptionTransferFarming": { "message": "Nếu bạn chấp thuận yêu cầu này, một bên thứ ba nổi tiếng là lừa đảo sẽ lấy hết tài sản của bạn." }, + "blockaidMessage": { + "message": "Bảo vệ quyền riêng tư - không có dữ liệu nào được chia sẻ với các bên thứ ba. Có sẵn trên Arbitrum, Avalanche, BNB chain, Ethereum Mainnet, Linea, Optimism, Polygon, Base và Sepolia." + }, "blockaidTitleDeceptive": { "message": "Đây là một yêu cầu lừa đảo" }, @@ -586,6 +701,9 @@ "bridge": { "message": "Cầu nối" }, + "bridgeDontSend": { + "message": "Cầu nối, không gửi" + }, "browserNotSupported": { "message": "Trình duyệt của bạn không được hỗ trợ..." }, @@ -598,6 +716,9 @@ "busy": { "message": "Đang bận" }, + "buyAndSell": { + "message": "Mua & Bán" + }, "buyAsset": { "message": "Mua $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -609,6 +730,10 @@ "buyNow": { "message": "Mua ngay" }, + "buyToken": { + "message": "Mua $1", + "description": "$1 is the token symbol" + }, "bytes": { "message": "Byte" }, @@ -618,9 +743,6 @@ "cancel": { "message": "Hủy" }, - "cancelEdit": { - "message": "Hủy chỉnh sửa" - }, "cancelPopoverTitle": { "message": "Hủy giao dịch" }, @@ -647,6 +769,9 @@ "chainIdExistsErrorMsg": { "message": "Mạng $1 hiện đang sử dụng ID chuỗi này." }, + "chainListReturnedDifferentTickerSymbol": { + "message": "Biểu tượng token này không trùng khớp với tên mạng hoặc ID chuỗi đã nhập. Nhiều token phổ biến sử dụng các biểu tượng tương tự, do đó những kẻ lừa đảo có thể lợi dụng điều này để lừa bạn gửi cho chúng một token có giá trị hơn. Nhớ xác minh mọi thông tin trước khi tiếp tục." + }, "chooseYourNetwork": { "message": "Chọn mạng của bạn" }, @@ -682,9 +807,19 @@ "close": { "message": "Đóng" }, + "closeExtension": { + "message": "Đóng tiện ích mở rộng" + }, + "closeWindowAnytime": { + "message": "Bạn có thể đóng cửa sổ này bất kỳ lúc nào." + }, "coingecko": { "message": "CoinGecko" }, + "comboNoOptions": { + "message": "Không tìm thấy tùy chọn nào", + "description": "Default text shown in the combo field dropdown if no options." + }, "configureSnapPopupDescription": { "message": "Bây giờ bạn đang rời MetaMask để định cấu hình Snap này." }, @@ -703,12 +838,42 @@ "confirm": { "message": "Xác nhận" }, + "confirmAlertModalAcknowledge": { + "message": "Tôi đã hiểu rõ các cảnh báo và vẫn muốn tiếp tục" + }, + "confirmAlertModalDetails": { + "message": "Nếu bạn đăng nhập, một bên thứ ba nổi tiếng là lừa đảo có thể lấy tất cả tài sản của bạn. Vui lòng xem lại các cảnh báo trước khi tiếp tục." + }, + "confirmAlertModalTitle": { + "message": "Tài sản của bạn có thể gặp rủi ro" + }, + "confirmConnectCustodianRedirect": { + "message": "Chúng tôi sẽ chuyển hướng bạn đến $1 sau khi nhấn vào tiếp tục." + }, + "confirmConnectCustodianText": { + "message": "Để kết nối các tài khoản của bạn, hãy đăng nhập vào tài khoản $1 của bạn và nhấn vào nút 'kết nối với MMI'." + }, + "confirmConnectionTitle": { + "message": "Xác nhận kết nối với $1" + }, "confirmPassword": { "message": "Xác nhận mật khẩu" }, "confirmRecoveryPhrase": { "message": "Xác nhận Cụm từ khôi phục bí mật" }, + "confirmTitleDescContractInteractionTransaction": { + "message": "Chỉ xác nhận giao dịch này nếu bạn hoàn toàn hiểu nội dung và tin tưởng trang web yêu cầu." + }, + "confirmTitleDescSignature": { + "message": "Chỉ xác nhận thông báo này nếu bạn chấp thuận nội dung và tin tưởng trang web yêu cầu." + }, + "confirmTitleSignature": { + "message": "Yêu cầu chữ ký" + }, + "confirmTitleTransaction": { + "message": "Yêu cầu giao dịch" + }, "confirmed": { "message": "Đã xác nhận" }, @@ -724,9 +889,15 @@ "connect": { "message": "Kết nối" }, + "connectAccount": { + "message": "Kết nối tài khoản" + }, "connectAccountOrCreate": { "message": "Kết nối tài khoản hoặc tạo tài khoản mới" }, + "connectAccounts": { + "message": "Kết nối tài khoản" + }, "connectCustodialAccountMenu": { "message": "Kết nối tài khoản lưu ký" }, @@ -736,36 +907,25 @@ "connectCustodialAccountTitle": { "message": "Tài khoản lưu ký" }, + "connectCustodianAccounts": { + "message": "Kết nối $1 tài khoản" + }, "connectManually": { "message": "Kết nối thủ công với trang web hiện tại" }, + "connectMoreAccounts": { + "message": "Kết nối thêm tài khoản" + }, "connectSnap": { "message": "Kết nối $1", "description": "$1 is the snap for which a connection is being requested." }, - "connectTo": { - "message": "Kết nối với $1", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "Kết nối với tất cả các $1 của bạn", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "tài khoản", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "Kết nối với $1", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1 tài khoản", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "Kết nối với MetaMask" }, + "connectedAccounts": { + "message": "Tài khoản đã kết nối" + }, "connectedAccountsDescriptionPlural": { "message": "Bạn có $1 tài khoản kết nối với trang web này.", "description": "$1 is the number of accounts" @@ -776,6 +936,13 @@ "connectedAccountsEmptyDescription": { "message": "MetaMask chưa kết nối với trang web này. Để kết nối với một trang web trên web3, hãy tìm nút kết nối trên trang web của họ." }, + "connectedAccountsListTooltip": { + "message": "$1 có thể xem số dư tài khoản, địa chỉ, hoạt động và gợi ý các giao dịch cần phê duyệt cho tài khoản được kết nối.", + "description": "$1 is the origin name" + }, + "connectedAccountsToast": { + "message": "Đã cập nhật các tài khoản được kết nối" + }, "connectedSites": { "message": "Trang web đã kết nối" }, @@ -787,12 +954,21 @@ "message": "$1 chưa được kết nối với bất kỳ trang web nào.", "description": "$1 is the account name" }, + "connectedSnapAndNoAccountDescription": { + "message": "MetaMask được kết nối với trang web này, nhưng chưa có tài khoản nào được kết nối" + }, + "connectedWith": { + "message": "Đã kết nối với" + }, "connecting": { "message": "Đang kết nối..." }, "connectingTo": { "message": "Đang kết nối với $1" }, + "connectingToDeprecatedNetwork": { + "message": "\"$1\" đang được loại bỏ dần và có thể không hoạt động. Vui lòng thử một mạng khác." + }, "connectingToGoerli": { "message": "Đang kết nối với mạng thử nghiệm Goerli" }, @@ -802,6 +978,9 @@ "connectingToLineaMainnet": { "message": "Đang kết nối với mạng chính thức của Linea" }, + "connectingToLineaSepolia": { + "message": "Đang kết nối với mạng thử nghiệm Linea Sepolia" + }, "connectingToMainnet": { "message": "Đang kết nối với Ethereum Mainnet" }, @@ -831,6 +1010,12 @@ "continue": { "message": "Tiếp tục" }, + "continueMmiOnboarding": { + "message": "Tiếp tục phần giới thiệu về MetaMask Institutional" + }, + "continueToWallet": { + "message": "Tiếp tục đến ví" + }, "contract": { "message": "Hợp đồng" }, @@ -882,6 +1067,9 @@ "copyAddress": { "message": "Sao chép địa chỉ vào bộ nhớ đệm" }, + "copyPrivateKey": { + "message": "Sao chép khóa riêng tư" + }, "copyRawTransactionData": { "message": "Sao chép dữ liệu giao dịch thô" }, @@ -900,6 +1088,15 @@ "createPassword": { "message": "Tạo mật khẩu" }, + "createSnapAccountDescription": { + "message": "$1 muốn thêm một tài khoản mới vào MetaMask." + }, + "createSnapAccountTitle": { + "message": "Tạo tài khoản" + }, + "crossChainSwapsLink": { + "message": "Hoán đổi trên các mạng với MetaMask Portfolio" + }, "cryptoCompare": { "message": "CryptoCompare" }, @@ -950,10 +1147,16 @@ "message": "Lưu ký" }, "custodianAccountAddedDesc": { - "message": "Giờ đây bạn có thể sử dụng tài khoản lưu ký của mình trong MetaMask Institutional." + "message": "Giờ đây bạn có thể sử dụng các tài khoản của mình trong MetaMask Institutional." }, "custodianAccountAddedTitle": { - "message": "Các tài khoản lưu ký được chọn đã được thêm vào." + "message": "Các tài khoản $1 được chọn đã được thêm vào." + }, + "custodianQRCodeScan": { + "message": "Quét mã QR bằng ứng dụng $1 trên thiết bị di động" + }, + "custodianQRCodeScanDescription": { + "message": "Hoặc đăng nhập vào tài khoản $1 của bạn và nhấn vào nút 'Kết nối với MMI'" }, "custodianReplaceRefreshTokenChangedFailed": { "message": "Vui lòng truy cập $1 và nhấp nút \"Kết nối với MMI\" trong giao diện người dùng để kết nối lại tài khoản của bạn với MMI." @@ -1017,7 +1220,7 @@ "message": "Tính năng phát hiện token hiện chưa khả dụng trong mạng này. Vui lòng nhập token theo cách thủ công và đảm bảo bạn tin tưởng. Tìm hiểu về $1" }, "customTokenWarningInTokenDetectionNetwork": { - "message": "Đảm bảo bạn tin tưởng trước khi nhập token theo cách thủ công. Tìm hiểu về $1." + "message": "Bất kỳ ai cũng có thể tạo token, bao gồm cả việc tạo phiên bản giả mạo của token hiện có. Tìm hiểu về $1" }, "customTokenWarningInTokenDetectionNetworkWithTDOFF": { "message": "Đảm bảo bạn tin tưởng token trước khi nhập token đó. Tìm hiểu cách phòng tránh $1. Bạn cũng có thể bật tính năng phát hiện token $2." @@ -1025,6 +1228,12 @@ "customerSupport": { "message": "hỗ trợ khách hàng" }, + "customizeYourNotifications": { + "message": "Tùy chỉnh thông báo" + }, + "customizeYourNotificationsText": { + "message": "Bật các loại thông báo mà bạn muốn nhận:" + }, "dappRequestedSpendingCap": { "message": "Trang web yêu cầu hạn mức chi tiêu" }, @@ -1108,6 +1317,18 @@ "deposit": { "message": "Nạp" }, + "deprecatedGoerliNtwrkMsg": { + "message": "Do các cập nhật của hệ thống Ethereum, mạng thử nghiệm Goerli sẽ sớm được loại bỏ dần." + }, + "deprecatedNetwork": { + "message": "Mạng này đã ngừng sử dụng" + }, + "deprecatedNetworkButtonMsg": { + "message": "Đã hiểu" + }, + "deprecatedNetworkDescription": { + "message": "Mạng bạn đang cố gắng kết nối không còn được MetaMask hỗ trợ. $1" + }, "description": { "message": "Mô tả" }, @@ -1115,110 +1336,20 @@ "message": "Mô tả từ $1", "description": "$1 represents the name of the snap" }, - "desktopApp": { - "message": "Ứng dụng Máy tính để bàn" - }, - "desktopConnectionCriticalErrorDescription": { - "message": "Lỗi này có thể không xảy ra liên tục, vì vậy hãy thử khởi động lại tiện ích mở rộng hoặc tắt Metamask Desktop." - }, - "desktopConnectionCriticalErrorTitle": { - "message": "MetaMask gặp sự cố khi khởi động" - }, - "desktopConnectionLostErrorDescription": { - "message": "Đảm bảo bạn đã thiết lập và chạy ứng dụng trên máy tính hoặc tắt Metamask Desktop." - }, - "desktopConnectionLostErrorTitle": { - "message": "Đã mất kết nối với Metamask Desktop" - }, - "desktopDisableButton": { - "message": "Tắt ứng dụng trên máy tính" - }, - "desktopDisableErrorCTA": { - "message": "Tắt Metamask Desktop" - }, - "desktopEnableButton": { - "message": "Bật ứng dụng trên máy tính" - }, - "desktopEnableButtonDescription": { - "message": "Nhấp để chạy tất cả các tiến trình chạy nền trong ứng dụng trên máy tính." - }, - "desktopErrorNavigateSettingsCTA": { - "message": "Quay lại trang Cài đặt" - }, - "desktopErrorRestartMMCTA": { - "message": "Khởi động lại MetaMask" - }, - "desktopNotFoundErrorCTA": { - "message": "Tải về Metamask Desktop" - }, - "desktopNotFoundErrorDescription1": { - "message": "Đảm bảo bạn đã thiết lập và chạy ứng dụng trên máy tính." - }, - "desktopNotFoundErrorDescription2": { - "message": "Nếu bạn chưa cài đặt ứng dụng trên máy tính, hãy tải xuống trên trang web MetaMask." - }, - "desktopNotFoundErrorTitle": { - "message": "Không tìm thấy Metamask Desktop" - }, - "desktopOpenOrDownloadCTA": { - "message": "Mở Metamask Desktop" - }, - "desktopOutdatedErrorCTA": { - "message": "Cập nhật Metamask Desktop" - }, - "desktopOutdatedErrorDescription": { - "message": "Cần nâng cấp ứng dụng Metamask Desktop của bạn." - }, - "desktopOutdatedErrorTitle": { - "message": "Metamask Desktop đã cũ" - }, - "desktopOutdatedExtensionErrorCTA": { - "message": "Cập nhật Tiện ích mở rộng MetaMask" - }, - "desktopOutdatedExtensionErrorDescription": { - "message": "Cần nâng cấp Tiện ích mở rộng MetaMask của bạn." - }, - "desktopOutdatedExtensionErrorTitle": { - "message": "Tiện ích mở rộng MetaMask đã cũ" - }, - "desktopPageDescription": { - "message": "Nếu ghép nối thành công, tiện ích mở rộng sẽ khởi động lại và bạn sẽ phải nhập lại mật khẩu." - }, - "desktopPageSubTitle": { - "message": "Mở Metamask Desktop và nhập mã này" - }, - "desktopPageTitle": { - "message": "Ghép nối với Máy tính" - }, - "desktopPairedWarningDeepLink": { - "message": "Vào phần Cài đặt trong Metamask Desktop" - }, - "desktopPairedWarningDescription": { - "message": "Nếu bạn muốn bắt đầu một lần ghép nối mới, vui lòng xóa kết nối hiện tại." - }, - "desktopPairedWarningTitle": { - "message": "Metamask Desktop đã được ghép nối" - }, - "desktopPairingExpireMessage": { - "message": "Mã hết hạn sau $1 giây" - }, - "desktopRouteNotFoundErrorDescription": { - "message": "desktopRouteNotFoundErrorDescription" - }, - "desktopRouteNotFoundErrorTitle": { - "message": "desktopRouteNotFoundErrorTitle" + "details": { + "message": "Chi tiết" }, - "desktopUnexpectedErrorCTA": { - "message": "Quay lại trang chủ MetaMask" + "developerOptions": { + "message": "Tùy chọn Nhà phát triển" }, - "desktopUnexpectedErrorDescription": { - "message": "Kiểm tra Metamask Desktop để khôi phục kết nối" + "developerOptionsResetStatesAnnouncementsDescription": { + "message": "Đặt lại giá trị isShown thành \"false\" cho tất cả thông báo. Thông báo là các nội dung hiển thị trong cửa sổ bật lên \"Xem tính năng mới\"." }, - "desktopUnexpectedErrorTitle": { - "message": "Đã xảy ra sự cố..." + "developerOptionsResetStatesOnboarding": { + "message": "Đặt lại các trạng thái khác nhau liên quan đến phần giới thiệu và chuyển hướng đến trang giới thiệu \"Bảo mật ví của bạn\"." }, - "details": { - "message": "Chi tiết" + "developerOptionsServiceWorkerKeepAlive": { + "message": "Kết quả trong dấu thời gian được lưu liên tục vào session.storage" }, "disabledGasOptionToolTipMessage": { "message": "“$1” bị vô hiệu hóa vì không đạt mức tăng tối thiểu 10% so với phí gas ban đầu.", @@ -1233,12 +1364,38 @@ "disconnectAllAccountsConfirmationDescription": { "message": "Bạn có chắc chắn muốn ngắt kết nối không? Bạn có thể bị mất chức năng của trang web." }, + "disconnectAllAccountsText": { + "message": "tài khoản" + }, + "disconnectAllSnapsText": { + "message": "Snap" + }, + "disconnectAllText": { + "message": "Nếu bạn ngắt kết nối $1 khỏi $2, bạn sẽ cần kết nối lại để sử dụng lại.", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`, $2 represents the website hostname" + }, + "disconnectAllTitle": { + "message": "Ngắt kết nối tất cả $1", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`" + }, "disconnectPrompt": { "message": "Ngắt kết nối $1" }, "disconnectThisAccount": { "message": "Ngắt kết nối tài khoản này" }, + "disconnectedAllAccountsToast": { + "message": "Đã ngắt kết nối tất cả các tài khoản khỏi $1", + "description": "$1 is name of the dapp`" + }, + "disconnectedSingleAccountToast": { + "message": "Đã ngắt kết nối $1 khỏi $2", + "description": "$1 is name of the name and $2 represents the dapp name`" + }, + "discoverSnaps": { + "message": "Khám phá Snap", + "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." + }, "dismiss": { "message": "Đóng" }, @@ -1248,9 +1405,21 @@ "dismissReminderField": { "message": "Tắt lời nhắc sao lưu Cụm từ khôi phục bí mật" }, + "displayNftMedia": { + "message": "Hiển thị phương tiện NFT" + }, + "displayNftMediaDescription": { + "message": "Việc hiển thị dữ liệu và phương tiện NFT sẽ làm lộ địa chỉ IP của bạn với OpenSea hoặc các bên thứ ba khác. Điều này có thể cho phép kẻ tấn công liên kết địa chỉ IP với địa chỉ Ethereum của bạn. Tính năng tự động phát hiện NFT dựa trên chế độ cài đặt này và sẽ không khả dụng khi chế độ cài đặt này bị tắt." + }, + "doNotShare": { + "message": "Không chia sẻ thông tin này với bất kỳ ai" + }, "domain": { "message": "Tên miền" }, + "domainNotSupportedOnNetwork": { + "message": "Mạng không hỗ trợ tra cứu tên miền" + }, "done": { "message": "Hoàn tất" }, @@ -1269,6 +1438,9 @@ "downloadStateLogs": { "message": "Tải nhật ký trạng thái xuống" }, + "dragAndDropBanner": { + "message": "Bạn có thể kéo các mạng để sắp xếp lại thứ tự. " + }, "dropped": { "message": "Đã ngừng" }, @@ -1367,6 +1539,9 @@ "editSpeedUpEditGasFeeModalTitle": { "message": "Chỉnh sửa phí gas tăng tốc" }, + "enable": { + "message": "Bật" + }, "enableAutoDetect": { "message": " Bật tự động phát hiện" }, @@ -1397,6 +1572,18 @@ "enhancedTokenDetectionAlertMessage": { "message": "Tính năng phát hiện token nâng cao hiện có sẵn trên $1. $2" }, + "ensDomainsSettingDescriptionIntroduction": { + "message": "MetaMask cho phép bạn xem các tên miền ENS ngay trên thanh địa chỉ của trình duyệt. Sau đây là cách hoạt động:" + }, + "ensDomainsSettingDescriptionOutroduction": { + "message": "Lưu ý rằng việc sử dụng tính năng này sẽ làm lộ địa chỉ IP của bạn với các dịch vụ bên thứ ba IPFS." + }, + "ensDomainsSettingDescriptionPart1": { + "message": "MetaMask sẽ kiểm tra hợp đồng ENS của Ethereum để tìm mã được kết nối với tên ENS." + }, + "ensDomainsSettingDescriptionPart2": { + "message": "Nếu mã liên kết đến IPFS, bạn có thể xem nội dung được liên kết với nó (thường là một trang web)." + }, "ensDomainsSettingTitle": { "message": "Hiển thị tên miền ENS trong thanh địa chỉ" }, @@ -1438,6 +1625,9 @@ "message": "Chi tiết về lỗi", "description": "Title for collapsible section that displays error details for debugging purposes" }, + "errorGettingSafeChainList": { + "message": "Lỗi khi lấy danh sách chuỗi an toàn, vui lòng tiếp tục một cách thận trọng." + }, "errorMessage": { "message": "Thông báo: $1", "description": "Displayed error message for debugging purposes. $1 is the error message" @@ -1469,6 +1659,9 @@ "message": "Lỗi với $1", "description": "$1 represents the name of the snap" }, + "estimatedFee": { + "message": "Phí ước tính" + }, "ethGasPriceFetchWarning": { "message": "Giá gas dự phòng được cung cấp vì dịch vụ ước tính giá gas chính hiện không hoạt động." }, @@ -1495,12 +1688,24 @@ "message": "Thử nghiệm" }, "extendWalletWithSnaps": { - "message": "Tuỳ biến trải nghiệm sử dụng ví.", + "message": "Khám phá các Snap do cộng đồng xây dựng để tùy chỉnh trải nghiệm web3 của bạn", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "extensionInsallCompleteDescription": { + "message": "Quay lại phần giới thiệu sản phẩm MetaMask Institutional để kết nối tài khoản lưu ký hoặc tự lưu ký của bạn." + }, + "extensionInsallCompleteTitle": { + "message": "Cài đặt tiện ích mở rộng hoàn tất" + }, "externalExtension": { "message": "Tiện ích bên ngoài" }, + "externalNameSourcesSetting": { + "message": "Biệt danh được đề xuất" + }, + "externalNameSourcesSettingDescription": { + "message": "Chúng tôi sẽ tìm nạp những biệt danh được đề xuất cho các địa chỉ mà bạn tương tác từ các nguồn bên thứ ba như Etherscan, Infura và Lens Protocol. Các nguồn này sẽ có thể nhìn thấy các địa chỉ đó và địa chỉ IP của bạn. Địa chỉ tài khoản của bạn sẽ không bị lộ với các bên thứ ba." + }, "failed": { "message": "Không thành công" }, @@ -1519,6 +1724,9 @@ "feeAssociatedRequest": { "message": "Yêu cầu này có kèm theo một khoản phí." }, + "feeDetails": { + "message": "Chi tiết phí" + }, "fiat": { "message": "Pháp định", "description": "Exchange type" @@ -1551,6 +1759,9 @@ "message": "Tôi chấp nhận những rủi ro này", "description": "this text is shown on a button, which the user presses to confirm they understand the risks of using Flask" }, + "floatAmountToken": { + "message": "Số lượng Token phải là số nguyên" + }, "followUsOnTwitter": { "message": "Theo dõi chúng tôi trên Twitter" }, @@ -1573,6 +1784,9 @@ "fromTokenLists": { "message": "Từ danh sách token: $1" }, + "function": { + "message": "Chức năng: $1" + }, "functionApprove": { "message": "Chức năng: Chấp thuận" }, @@ -1582,6 +1796,13 @@ "functionType": { "message": "Loại chức năng" }, + "fundYourWallet": { + "message": "Nạp tiền vào ví của bạn" + }, + "fundYourWalletDescription": { + "message": "Hãy bắt đầu bằng cách nạp một ít $1 vào ví của bạn.", + "description": "$1 is the token symbol" + }, "gas": { "message": "Gas" }, @@ -1592,6 +1813,9 @@ "message": "Phí gas này đã được gợi ý bởi $1. Việc sửa đổi có thể khiến giao dịch của bạn gặp sự cố. Vui lòng liên hệ với $1 nếu bạn có câu hỏi.", "description": "$1 represents the Dapp's origin" }, + "gasIsETH": { + "message": "Gas là $1 " + }, "gasLimit": { "message": "Hạn mức phí gas" }, @@ -1636,6 +1860,9 @@ "message": "$1 giờ", "description": "$1 represents a number of hours" }, + "gasTimingLow": { + "message": "Chậm" + }, "gasTimingMinutesShort": { "message": "$1 phút", "description": "$1 represents a number of minutes" @@ -1650,15 +1877,29 @@ "general": { "message": "Chung" }, - "globalTitle": { - "message": "Trình đơn chung" + "generalCameraError": { + "message": "Chúng tôi không thể truy cập máy ảnh của bạn. Vui lòng thử lại một lần nữa." + }, + "generalCameraErrorTitle": { + "message": "Đã xảy ra sự cố..." + }, + "genericExplorerView": { + "message": "Xem tài khoản trên $1" + }, + "getStartedWithNFTs": { + "message": "Nhận $1 để mua NFT", + "description": "$1 is the token symbol" }, - "globalTourDescription": { - "message": "Xem danh mục đầu tư, trang web đã kết nối, cài đặt, v.v... của bạn" + "getStartedWithNFTsDescription": { + "message": "Hãy bắt đầu với NFT bằng cách nạp một ít $1 vào ví của bạn.", + "description": "$1 is the token symbol" }, "goBack": { "message": "Quay Lại" }, + "goToSite": { + "message": "Đến trang web" + }, "goerli": { "message": "Mạng thử nghiệm Goerli" }, @@ -1700,15 +1941,24 @@ "hexData": { "message": "Dữ liệu thập lục phân" }, + "hiddenAccounts": { + "message": "Tài khoản ẩn" + }, "hide": { "message": "Ẩn" }, + "hideAccount": { + "message": "Ẩn tài khoản" + }, "hideFullTransactionDetails": { "message": "Ẩn chi tiết giao dịch đầy đủ" }, "hideSeedPhrase": { "message": "Ẩn cụm từ khôi phục bí mật" }, + "hideSentitiveInfo": { + "message": "Ẩn thông tin nhạy cảm" + }, "hideToken": { "message": "Ẩn token" }, @@ -1790,6 +2040,9 @@ "ignoreTokenWarning": { "message": "Nếu bạn ẩn token, chúng sẽ không hiển thị trong ví của bạn. Tuy nhiên, bạn vẫn có thể thêm chúng thông qua chức năng tìm kiếm." }, + "imToken": { + "message": "imToken" + }, "import": { "message": "Nhập", "description": "Button to import an account from a selected file" @@ -1848,6 +2101,9 @@ "importTokensCamelCase": { "message": "Nhập token" }, + "importTokensError": { + "message": "Chúng tôi không thể nhập token. Vui lòng thử lại sau." + }, "importWithCount": { "message": "Nhập $1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -1866,6 +2122,9 @@ "initialTransactionConfirmed": { "message": "Mạng đã xác nhận giao dịch ban đầu của bạn. Nhấp OK để quay lại." }, + "inlineAlert": { + "message": "Cảnh báo" + }, "inputLogicEmptyState": { "message": "Chỉ nhập số mà bạn cảm thấy thoải mái đối với hạn mức chi tiêu ở hiện tại hoặc trong tương lai của bên thứ ba. Bạn luôn có thể tăng hạn mức chi tiêu sau này." }, @@ -1876,6 +2135,27 @@ "inputLogicHigherNumber": { "message": "Điều này cho phép bên thứ ba chi tiêu tất cả số dư token của bạn cho đến khi đạt hạn mức hoặc bạn hủy hạn mức chi tiêu. Nếu không có ý định này, hãy cân nhắc đặt hạn mức chi tiêu thấp hơn." }, + "insightWarning": { + "message": "cảnh báo" + }, + "insightWarningCheckboxMessage": { + "message": "$1 yêu cầu bởi $2", + "description": "$1 is the action i.e. sign, confirm. $2 is the origin making the request." + }, + "insightWarningContentPlural": { + "message": "Xem lại $1 trước khi $2. Sau khi đã thực hiện, $3 sẽ không thể đảo ngược.", + "description": "$1 the 'insightWarnings' message (2 warnings) representing warnings, $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningContentSingular": { + "message": "Xem lại $1 trước khi $2. Sau khi đã thực hiện, $3 sẽ không thể đảo ngược.", + "description": "$1 is the 'insightWarning' message (1 warning), $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningHeader": { + "message": "Yêu cầu này có thể nguy hiểm" + }, + "insightWarnings": { + "message": "cảnh báo" + }, "insightsFromSnap": { "message": "Thông tin chi tiết từ $1", "description": "$1 represents the name of the snap" @@ -1883,9 +2163,18 @@ "install": { "message": "Cài đặt" }, + "installExtension": { + "message": "Cài đặt tiện ích mở rộng" + }, + "installExtensionDescription": { + "message": "Phiên bản tuân thủ quy định của tổ chức của ví web3 hàng đầu thế giới, MetaMask." + }, "installOrigin": { "message": "Cài đặt nguồn gốc" }, + "installRequest": { + "message": "Thêm vào MetaMask" + }, "installedOn": { "message": "Đã cài đặt vào $1", "description": "$1 is the date when the snap has been installed" @@ -1914,6 +2203,12 @@ "insufficientTokens": { "message": "Không đủ token." }, + "interactingWith": { + "message": "Đang tương tác với" + }, + "interactingWithTransactionDescription": { + "message": "Đây là hợp đồng mà bạn đang tương tác. Nhớ xác minh các thông tin để bảo vệ bản thân trước những kẻ lừa đảo." + }, "invalidAddress": { "message": "Địa chỉ không hợp lệ" }, @@ -1986,6 +2281,9 @@ "ipfsToggleModalSettings": { "message": "Cài đặt > Bảo mật và quyền riêng tư" }, + "isSigningOrSubmitting": { + "message": "Giao dịch trước đó vẫn đang được ký hoặc gửi" + }, "jazzAndBlockies": { "message": "Jazzicons và Blockies là hai kiểu biểu tượng độc nhất khác nhau giúp bạn nhận ra tài khoản trong nháy mắt." }, @@ -1999,6 +2297,24 @@ "message": "Tập tin JSON", "description": "format for importing an account" }, + "keyringAccountName": { + "message": "Tên tài khoản" + }, + "keyringAccountPublicAddress": { + "message": "Địa chỉ công khai" + }, + "keyringSnapRemovalResult1": { + "message": "Đã xóa $1 $2", + "description": "Displays the result after removal of a keyring snap. $1 is the snap name, $2 is whether it is successful or not" + }, + "keyringSnapRemovalResultNotSuccessful": { + "message": "không ", + "description": "Displays the `not` word in $2." + }, + "keyringSnapRemoveConfirmation": { + "message": "Nhập $1 để xác nhận bạn muốn xóa Snap này:", + "description": "Asks user to input the name nap prior to deleting the snap. $1 is the snap name" + }, "keystone": { "message": "Keystone" }, @@ -2017,9 +2333,15 @@ "lastSold": { "message": "Đã bán gần nhất" }, + "lavaDomeCopyWarning": { + "message": "Vì sự an toàn của bạn, việc chọn văn bản này hiện không khả dụng." + }, "layer1Fees": { "message": "Phí Lớp 1" }, + "layer2Fees": { + "message": "Phí Lớp 2" + }, "learnCancelSpeeedup": { "message": "Tìm hiểu cách $1", "description": "$1 is link to cancel or speed up transactions" @@ -2037,9 +2359,21 @@ "learnMoreUpperCase": { "message": "Tìm hiểu thêm" }, + "learnMoreUpperCaseWithDot": { + "message": "Tìm hiểu thêm." + }, "learnScamRisk": { "message": "lừa đảo và nguy cơ bảo mật." }, + "learnToBridge": { + "message": "Tìm hiểu cách sử dụng cầu nối" + }, + "leaveMetaMask": { + "message": "Rời khỏi MetaMask?" + }, + "leaveMetaMaskDesc": { + "message": "Bạn sắp truy cập một trang web bên ngoài MetaMask. Hãy kiểm tra kỹ đường dẫn URL trước khi tiếp tục." + }, "ledgerAccountRestriction": { "message": "Bạn cần sử dụng tài khoản gần đây nhất thì mới có thể thêm một tài khoản mới." }, @@ -2058,6 +2392,18 @@ "ledgerDeviceOpenFailureMessage": { "message": "Mở thiết bị Ledger không thành công. Ledger của bạn có thể đã được kết nối với phần mềm khác. Vui lòng đóng Ledger Live hoặc các ứng dụng khác được kết nối với thiết bị Ledger của bạn và thử kết nối lại." }, + "ledgerErrorConnectionIssue": { + "message": "Kết nối lại với Ledger của bạn, mở ứng dụng ETH và thử lại." + }, + "ledgerErrorDevicedLocked": { + "message": "Ledger của bạn đã bị khóa. Vui lòng mở khóa rồi thử lại." + }, + "ledgerErrorEthAppNotOpen": { + "message": "Để khắc phục sự cố này, vui lòng mở ứng dụng ETH trên thiết bị của bạn và thử lại." + }, + "ledgerErrorTransactionDataNotPadded": { + "message": "Không có đủ phần đệm trong dữ liệu đầu vào của giao dịch Ethereum." + }, "ledgerLiveApp": { "message": "Ứng dụng Ledger Live" }, @@ -2077,6 +2423,9 @@ "lightTheme": { "message": "Sáng" }, + "likeToImportToken": { + "message": "Bạn có muốn nhập token này không?" + }, "likeToImportTokens": { "message": "Bạn có muốn nhập những token này không?" }, @@ -2086,6 +2435,9 @@ "lineaMainnet": { "message": "Mạng chính thức của Linea" }, + "lineaSepolia": { + "message": "Mạng thử nghiệm Linea Sepolia" + }, "link": { "message": "Liên kết" }, @@ -2098,8 +2450,11 @@ "loading": { "message": "Đang tải..." }, - "loadingNFTs": { - "message": "Đang tải NFT..." + "loadingScreenHardwareWalletMessage": { + "message": "Vui lòng hoàn tất giao dịch trên ví cứng." + }, + "loadingScreenSnapMessage": { + "message": "Vui lòng hoàn tất giao dịch trên Snap." }, "loadingTokens": { "message": "Đang tải token..." @@ -2146,6 +2501,9 @@ "message": "Đảm bảo không có ai đang nhìn", "description": "Warning to users to be care while creating and saving their new Secret Recovery Phrase" }, + "manageInSettings": { + "message": "Quản lý trong phần cài đặt" + }, "max": { "message": "Tối đa" }, @@ -2180,15 +2538,34 @@ "metaMaskConnectStatusParagraphTwo": { "message": "Nút trạng thái kết nối sẽ hiển thị nếu trang web mà bạn đang truy cập được kết nối với tài khoản bạn đang chọn." }, + "metadataModalSourceTooltip": { + "message": "$1 được lưu trữ trên npm và $2 là mã định danh duy nhất của Snap này.", + "description": "$1 is the snap name and $2 is the snap NPM id." + }, "metamaskInstitutionalVersion": { "message": "Phiên bản MetaMask Institutional" }, + "metamaskNotificationsAreOff": { + "message": "Thông báo ví hiện không hoạt động." + }, + "metamaskPortfolio": { + "message": "MetaMask Portfolio." + }, "metamaskSwapsOfflineDescription": { "message": "Tính năng Hoán đổi trên MetaMask đang được bảo trì. Vui lòng kiểm tra lại sau." }, "metamaskVersion": { "message": "Phiên bản MetaMask" }, + "methodData": { + "message": "Phương thức" + }, + "methodDataTransactionDescription": { + "message": "Đây là hành động cụ thể sẽ được thực hiện. Dữ liệu này có thể bị giả mạo, vì vậy hãy đảm bảo rằng bạn tin tưởng trang web ở đầu bên kia." + }, + "methodNotSupported": { + "message": "Không được hỗ trợ với tài khoản này." + }, "metrics": { "message": "Chỉ số" }, @@ -2224,11 +2601,17 @@ "mmiBuiltAroundTheWorld": { "message": "MetaMask Institutional được thiết kế và xây dựng trên khắp thế giới." }, + "mmiNewNFTDetectedInNFTsTabMessage": { + "message": "Cho phép MetaMask Institutional tự động phát hiện và hiển thị NFT trong ví của bạn." + }, + "mmiPasswordSetupDetails": { + "message": "Mật khẩu này sẽ chỉ mở khóa tiện ích mở rộng MetaMask Institutional của bạn." + }, "more": { "message": "thêm" }, "multipleSnapConnectionWarning": { - "message": "$1 muốn kết nối với $2 Snap. Chỉ tiến hành nếu bạn tin tưởng trang web này.", + "message": "$1 muốn sử dụng $2 Snap", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." }, "mustSelectOne": { @@ -2237,10 +2620,80 @@ "name": { "message": "Tên" }, + "nameAddressLabel": { + "message": "Địa chỉ", + "description": "Label above address field in name component modal." + }, + "nameInstructionsNew": { + "message": "Nếu bạn biết địa chỉ này, hãy đặt biệt danh để dễ nhận biết trong tương lai.", + "description": "Instruction text in name component modal when value is not recognised." + }, + "nameInstructionsRecognized": { + "message": "Địa chỉ này có một biệt danh mặc định, nhưng bạn có thể chỉnh sửa hoặc tham khảo các đề xuất khác.", + "description": "Instruction text in name component modal when value is recognized but not saved." + }, + "nameInstructionsSaved": { + "message": "Trước đây bạn đã thêm biệt danh cho địa chỉ này rồi. Bạn có thể chỉnh sửa hoặc xem các biệt danh được đề xuất khác.", + "description": "Instruction text in name component modal when value is saved." + }, + "nameLabel": { + "message": "Biệt danh", + "description": "Label above name input field in name component modal." + }, + "nameModalMaybeProposedName": { + "message": "Có thể: $1", + "description": "$1 is the proposed name" + }, + "nameModalTitleNew": { + "message": "Địa chỉ không xác định", + "description": "Title of the modal created by the name component when value is not recognised." + }, + "nameModalTitleRecognized": { + "message": "Địa chỉ đã được nhận biết", + "description": "Title of the modal created by the name component when value is recognized but not saved." + }, + "nameModalTitleSaved": { + "message": "Địa chỉ đã lưu", + "description": "Title of the modal created by the name component when value is saved." + }, + "nameProviderProposedBy": { + "message": "Được đề xuất bởi $1", + "description": "$1 is the name of the provider" + }, + "nameProvider_ens": { + "message": "Dịch vụ đăng ký tên miền trên Ethereum (ENS)" + }, + "nameProvider_etherscan": { + "message": "Etherscan" + }, + "nameProvider_lens": { + "message": "Lens Protocol" + }, + "nameProvider_token": { + "message": "MetaMask" + }, + "nameSetPlaceholder": { + "message": "Chọn một biệt danh...", + "description": "Placeholder text for name input field in name component modal." + }, + "nativePermissionRequestDescription": { + "message": "Bạn có muốn trang web này thực hiện những điều sau không?", + "description": "Description below header used on Permission Connect screen for native permissions." + }, "nativeToken": { "message": "Token gốc của mạng này là $1. Token này được dùng làm phí gas.", "description": "$1 represents the name of the native token on the current network" }, + "nativeTokenScamWarningConversion": { + "message": "Chỉnh sửa thông tin mạng" + }, + "nativeTokenScamWarningDescription": { + "message": "Mạng này không trùng khớp với tên hoặc ID chuỗi liên quan của nó. Nhiều token phổ biến sử dụng tên $1, khiến nó trở thành mục tiêu của các hành vi lừa đảo. Kẻ lừa đảo có thể lừa bạn gửi lại cho họ loại tiền tệ có giá trị hơn. Hãy xác minh mọi thứ trước khi tiếp tục.", + "description": "$1 represents the currency name" + }, + "nativeTokenScamWarningTitle": { + "message": "Đây có khả năng là một hành vi lừa đảo" + }, "needHelp": { "message": "Bạn cần trợ giúp? Liên hệ $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -2261,6 +2714,9 @@ "negativeETH": { "message": "Không thể gửi số lượng ETH âm." }, + "negativeOrZeroAmountToken": { + "message": "Không thể gửi số lượng tài sản âm hoặc bằng 0." + }, "network": { "message": "Mạng:" }, @@ -2291,6 +2747,9 @@ "networkNameBSC": { "message": "BSC" }, + "networkNameBase": { + "message": "Base" + }, "networkNameDefinition": { "message": "Tên được liên kết với mạng này." }, @@ -2300,12 +2759,21 @@ "networkNameGoerli": { "message": "Goerli" }, + "networkNameLinea": { + "message": "Linea" + }, + "networkNameOpMainnet": { + "message": "OP Mainnet" + }, "networkNamePolygon": { "message": "Polygon" }, "networkNameTestnet": { "message": "Mạng thử nghiệm" }, + "networkNameZkSyncEra": { + "message": "zkSync Era" + }, "networkProvider": { "message": "Nhà cung cấp mạng" }, @@ -2358,6 +2826,19 @@ "newContract": { "message": "Hợp đồng mới" }, + "newNFTDetectedInImportNFTsMessageStrongText": { + "message": "Cài đặt > Bảo mật và quyền riêng tư" + }, + "newNFTDetectedInImportNFTsMsg": { + "message": "Để sử dụng Opensea để xem NFT của bạn, hãy bật 'Hiển thị Phương tiện NFT' trong $1.", + "description": "$1 is used for newNFTDetectedInImportNFTsMessageStrongText" + }, + "newNFTDetectedInNFTsTabMessage": { + "message": "Cho phép MetaMask tự động phát hiện và hiển thị NFT trong ví của bạn." + }, + "newNFTsAutodetected": { + "message": "Tự động phát hiện NFT" + }, "newNetworkAdded": { "message": "“$1” đã được thêm thành công!" }, @@ -2367,6 +2848,12 @@ "newPassword": { "message": "Mật khẩu mới (tối thiểu 8 ký tự)" }, + "newPrivacyPolicyActionButton": { + "message": "Đọc thêm" + }, + "newPrivacyPolicyTitle": { + "message": "Chúng tôi đã cập nhật chính sách quyền riêng tư" + }, "newTokensImportedMessage": { "message": "Bạn đã nhập thành công $1.", "description": "$1 is the string of symbols of all the tokens imported" @@ -2388,6 +2875,9 @@ "message": "Token này là một NFT. Thêm vào $1", "description": "$1 is a clickable link with text defined by the 'importNFTPage' key" }, + "nftAlreadyAdded": { + "message": "NFT đã được thêm vào." + }, "nftDisclaimer": { "message": "Tuyên bố miễn trừ trách nhiệm: MetaMask lấy tập tin phương tiện từ URL nguồn. URL này đôi khi bị thay đổi bởi thị trường mà NFT được đào." }, @@ -2423,12 +2913,21 @@ "noAddressForName": { "message": "Chưa có địa chỉ nào được đặt cho tên này." }, + "noConnectedAccountDescription": { + "message": "Chọn tài khoản mà bạn muốn sử dụng trên trang web này để tiếp tục." + }, + "noConnectedAccountTitle": { + "message": "MetaMask không được kết nối với trang web này" + }, "noConversionDateAvailable": { "message": "Hiện không có ngày quy đổi tiền tệ nào" }, "noConversionRateAvailable": { "message": "Không có sẵn tỷ lệ quy đổi nào" }, + "noDomainResolution": { + "message": "Không có nội dung phân giải cho tên miền được cung cấp." + }, "noNFTs": { "message": "Chưa có NFT" }, @@ -2447,6 +2946,9 @@ "noWebcamFoundTitle": { "message": "Không tìm thấy webcam" }, + "nonCustodialAccounts": { + "message": "MetaMask Institutional cho phép bạn sử dụng các tài khoản không lưu ký, nếu bạn dự định sử dụng các tài khoản này, hãy sao lưu Cụm từ khôi phục bí mật." + }, "nonce": { "message": "Số nonce" }, @@ -2477,6 +2979,111 @@ "notePlaceholder": { "message": "Người chấp thuận sẽ nhìn thấy ghi chú này khi chấp thuận giao dịch tại lưu ký." }, + "notificationDetail": { + "message": "Chi tiết" + }, + "notificationDetailBaseFee": { + "message": "Phí cơ sở (GWEI)" + }, + "notificationDetailGasLimit": { + "message": "Hạn mức phí gas (đơn vị)" + }, + "notificationDetailGasUsed": { + "message": "Phí gas đã dùng (đơn vị)" + }, + "notificationDetailMaxFee": { + "message": "Mức phí tối đa mỗi gas" + }, + "notificationDetailNetwork": { + "message": "Mạng" + }, + "notificationDetailNetworkFee": { + "message": "Phí mạng" + }, + "notificationDetailPriorityFee": { + "message": "Phí ưu tiên (GWEI)" + }, + "notificationItemCheckBlockExplorer": { + "message": "Kiểm tra trên BlockExplorer" + }, + "notificationItemCollection": { + "message": "Bộ sưu tập" + }, + "notificationItemConfirmed": { + "message": "Đã xác nhận" + }, + "notificationItemError": { + "message": "Hiện không thể truy xuất phí" + }, + "notificationItemFrom": { + "message": "Từ" + }, + "notificationItemLidoStakeReadyToBeWithdrawn": { + "message": "Sẵn sàng rút tiền" + }, + "notificationItemLidoStakeReadyToBeWithdrawnMessage": { + "message": "Bây giờ bạn có thể rút $1 chưa ký gửi của bạn" + }, + "notificationItemLidoWithdrawalRequestedMessage": { + "message": "Đã gửi yêu cầu hủy ký gửi $1 của bạn" + }, + "notificationItemNFTReceivedFrom": { + "message": "Đã nhận NFT từ" + }, + "notificationItemNFTSentTo": { + "message": "Đã gửi NFT đến" + }, + "notificationItemNetwork": { + "message": "Mạng" + }, + "notificationItemRate": { + "message": "Tỷ giá (đã bao gồm phí)" + }, + "notificationItemReceived": { + "message": "Đã nhận" + }, + "notificationItemReceivedFrom": { + "message": "Đã nhận từ" + }, + "notificationItemSent": { + "message": "Đã gửi" + }, + "notificationItemSentTo": { + "message": "Đã gửi đến" + }, + "notificationItemStakeCompleted": { + "message": "Đã hoàn tất ký gửi" + }, + "notificationItemStaked": { + "message": "Đã ký gửi" + }, + "notificationItemStakingProvider": { + "message": "Nhà cung cấp dịch vụ ký gửi" + }, + "notificationItemStatus": { + "message": "Trạng thái" + }, + "notificationItemSwapped": { + "message": "Đã hoán đổi" + }, + "notificationItemSwappedFor": { + "message": "để lấy" + }, + "notificationItemTo": { + "message": "Đến" + }, + "notificationItemTransactionId": { + "message": "ID giao dịch" + }, + "notificationItemUnStakeCompleted": { + "message": "Hoàn tất hủy ký gửi" + }, + "notificationItemUnStaked": { + "message": "Đã hủy ký gửi" + }, + "notificationItemUnStakingRequested": { + "message": "Đã yêu cầu hủy ký gửi" + }, "notificationTransactionFailedMessage": { "message": "Giao dịch $1 không thành công! $2", "description": "Content of the browser notification that appears when a transaction fails" @@ -2501,45 +3108,8 @@ "message": "Xem trên $1", "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" }, - "notifications": { - "message": "Thông báo" - }, - "notifications20ActionText": { - "message": "Tìm hiểu thêm", - "description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a ledger page to resolve the U2F connection issue." - }, - "notifications20Description": { - "message": "Nếu đang sử dụng phiên bản Firefox mới nhất, bạn có thể gặp sự cố liên quan đến việc Firefox không còn hỗ trợ U2F.", - "description": "Description of a notification in the 'See What's New' popup. Describes the U2F support being dropped by firefox and that it affects ledger users." - }, - "notifications20Title": { - "message": "Người dùng Ledger và Firefox gặp sự cố kết nối", - "description": "Title for a notification in the 'See What's New' popup. Tells users that latest firefox users using U2F may experience connection issues." - }, - "notifications24ActionText": { - "message": "Đã hiểu" - }, - "notifications24Description": { - "message": "Cài đặt phí gas nâng cao hiện được ghi nhớ dựa trên mạng mà bạn đang sử dụng. Nghĩa là bạn có thể đặt các mức phí gas nâng cao cụ thể cho từng mạng và tránh phải trả quá nhiều tiền cho phí gas hoặc các giao dịch bị mắc kẹt." - }, - "notifications24Title": { - "message": "Phí gas nâng cao theo mạng" - }, - "notifications8ActionText": { - "message": "Đến Cài đặt > Nâng cao", - "description": "Description on an action button that appears in the What's New popup. Tells the user that if they click it, they will go to our Advanced settings page." - }, - "notifications8DescriptionOne": { - "message": "Kể từ phiên bản MetaMask v10.4.0, bạn không cần phần mềm Ledger Live để kết nối thiết bị Ledger của mình với MetaMask nữa.", - "description": "Description of a notification in the 'See What's New' popup. Describes changes for how Ledger Live is no longer needed to connect the device." - }, - "notifications8DescriptionTwo": { - "message": "Để có trải nghiệm sử dụng thiết bị Ledger dễ dàng và ổn định hơn, hãy đến Cài đặt > Nâng cao và chuyển \"Dạng kết nối Ledger ưu tiên\" thành \"WebHID\".", - "description": "Description of a notification in the 'See What's New' popup. Describes how the user can turn off the Ledger Live setting." - }, - "notifications8Title": { - "message": "Cải thiện kết nối Ledger", - "description": "Title for a notification in the 'See What's New' popup. Notifies ledger users that there is an improvement in how they can connect their device." + "notifications": { + "message": "Thông báo" }, "notificationsDropLedgerFirefoxDescription": { "message": "Firefox không còn hỗ trợ U2F nên Ledger sẽ không hoạt động với MetaMask trên Firefox. Thay vào đó hãy dùng thử MetaMask trên Google Chrome.", @@ -2549,33 +3119,37 @@ "message": "Bỏ Hỗ trợ Ledger cho Firefox", "description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped." }, - "notificationsEmptyText": { - "message": "Tại đây, bạn có thể tìm thấy thông báo từ các Snap đã cài đặt." - }, - "notificationsHeader": { - "message": "Thông báo" + "notificationsFeatureToggle": { + "message": "Bật thông báo ví", + "description": "Experimental feature title" }, - "notificationsInfos": { - "message": "$1 từ $2", - "description": "$1 is the date at which the notification has been dispatched and $2 is the link to the snap that dispatched the notification." + "notificationsFeatureToggleDescription": { + "message": "Điều này cho phép nhận thông báo ví khi gửi/nhận tiền hoặc NFT và khi có thông báo về các tính năng.", + "description": "Description of the experimental notifications feature" }, "notificationsMarkAllAsRead": { "message": "Đánh dấu đã đọc tất cả" }, - "notificationsOpenBetaSnapsActionText": { - "message": "Tìm hiểu thêm" + "notificationsPageEmptyTitle": { + "message": "Không có thông báo nào ở đây" + }, + "notificationsPageErrorContent": { + "message": "Vui lòng thử truy cập lại trang này." }, - "notificationsOpenBetaSnapsDescriptionOne": { - "message": "Chúng tôi vui mừng thông báo về phiên bản Open Beta của MetaMask Snaps!" + "notificationsPageErrorTitle": { + "message": "Đã xảy ra lỗi" }, - "notificationsOpenBetaSnapsDescriptionThree": { - "message": "Cá nhân hóa ví của bạn bằng các snap do cộng đồng nhà lập trình xây dựng!" + "notificationsPageNoNotificationsContent": { + "message": "Bạn chưa nhận được bất kỳ thông báo nào." }, - "notificationsOpenBetaSnapsDescriptionTwo": { - "message": "Snap giúp bạn làm được nhiều việc hơn với MetaMask — chẳng hạn như kết nối với nhiều mạng hơn, xem thông tin chuyên sâu về giao dịch và nhận thông báo tùy chỉnh." + "notificationsSettingsBoxError": { + "message": "Đã xảy ra lỗi. Vui lòng thử lại." }, - "notificationsOpenBetaSnapsTitle": { - "message": "Giới thiệu MetaMask Snaps" + "notificationsSettingsPageAllowNotifications": { + "message": "Nhận thông báo để cập nhật tình hình trong ví của bạn. Để sử dụng tính năng thông báo, chúng tôi dùng hồ sơ để đồng bộ một số chế độ cài đặt trên các thiết bị của bạn. $1" + }, + "notificationsSettingsPageAllowNotificationsLink": { + "message": "Tìm hiểu cách chúng tôi bảo vệ quyền riêng tư của bạn khi sử dụng tính năng này." }, "numberOfNewTokensDetectedPlural": { "message": "Tìm thấy $1 token mới trong tài khoản này", @@ -2599,6 +3173,9 @@ "on": { "message": "Bật" }, + "onboarding": { + "message": "Giới thiệu" + }, "onboardingAdvancedPrivacyIPFSDescription": { "message": "Cổng IPFS cho phép truy cập và xem dữ liệu do bên thứ ba lưu trữ. Bạn có thể thêm cổng IPFS tùy chỉnh hoặc tiếp tục sử dụng cổng mặc định." }, @@ -2629,51 +3206,45 @@ "onboardingMetametricsAgree": { "message": "Tôi đồng ý" }, - "onboardingMetametricsAllowOptOut": { - "message": "Luôn cho phép bạn chọn không tham gia thông qua phần Cài đặt" - }, - "onboardingMetametricsDataTerms": { - "message": "Do đó, dữ liệu này được tổng hợp và ẩn danh theo các mục đích của Quy định bảo vệ dữ liệu chung (EU) 2016/679." - }, "onboardingMetametricsDescription": { - "message": "MetaMask muốn thu thập dữ liệu sử dụng để hiểu rõ hơn cách người dùng tương tác với MetaMask. Dữ liệu này sẽ được sử dụng để cung cấp dịch vụ, bao gồm cả cải thiện dịch vụ dựa trên quá trình sử dụng của bạn." + "message": "Chúng tôi muốn thu thập dữ liệu sử dụng và chẩn đoán cơ bản để cải tiến MetaMask. Xin lưu ý, chúng tôi không bao giờ bán dữ liệu mà bạn cung cấp ở đây." }, "onboardingMetametricsDescription2": { - "message": "MetaMask sẽ..." + "message": "Khi thu thập số liệu, chúng tôi sẽ luôn cam kết điều này..." }, "onboardingMetametricsDisagree": { "message": "Không, cảm ơn" }, "onboardingMetametricsInfuraTerms": { - "message": "* Khi bạn sử dụng Infura làm nhà cung cấp RPC mặc định trong MetaMask, Infura sẽ thu thập địa chỉ IP và địa chỉ ví Ethereum của bạn khi bạn gửi giao dịch. Chúng tôi không lưu trữ thông tin này để cho phép hệ thống của chúng tôi liên kết hai loại dữ liệu đó. Để biết thêm thông tin về cách MetaMask và Infura tương tác trong việc thu thập dữ liệu, hãy xem bản cập nhật $1 của chúng tôi. Để biết thêm thông tin về các phương pháp bảo vệ quyền riêng tư của chúng tôi nói chung, hãy xem $2.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" + "message": "Chúng tôi sẽ thông báo cho bạn nếu chúng tôi quyết định sử dụng dữ liệu này cho các mục đích khác. Bạn có thể xem lại $1 của chúng tôi để biết thêm thông tin. Lưu ý, bạn có thể truy cập cài đặt và chọn không tham gia bất kỳ lúc nào.", + "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, "onboardingMetametricsInfuraTermsPolicy": { - "message": "Chính sách quyền riêng tư tại đây" - }, - "onboardingMetametricsInfuraTermsPolicyLink": { - "message": "tại đây" + "message": "Chính sách quyền riêng tư" }, "onboardingMetametricsModalTitle": { "message": "Thêm mạng tùy chỉnh" }, "onboardingMetametricsNeverCollect": { - "message": "$1 thu thập các thông tin mà chúng tôi không cần để cung cấp dịch vụ (chẳng hạn như khóa, địa chỉ, mã băm giao dịch hoặc số dư)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 chỉ lưu trữ các lượt nhấn và lượt xem trên ứng dụng, các thông tin khác (chẳng hạn như địa chỉ công khai của bạn) sẽ không được lưu trữ.", + "description": "$1 represents `onboardingMetametricsNeverCollectEmphasis`" + }, + "onboardingMetametricsNeverCollectEmphasis": { + "message": "Riêng tư:" }, "onboardingMetametricsNeverCollectIP": { - "message": "$1 thu thập địa chỉ IP đầy đủ của bạn*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 chúng tôi tạm thời sử dụng địa chỉ IP của bạn để xác định vị trí tổng quan (chẳng hạn như quốc gia hoặc khu vực của bạn), nhưng dữ liệu này sẽ không bao giờ được lưu trữ.", + "description": "$1 represents `onboardingMetametricsNeverCollectIPEmphasis`" }, - "onboardingMetametricsNeverEmphasis": { - "message": "Không bao giờ" + "onboardingMetametricsNeverCollectIPEmphasis": { + "message": "Chung:" }, "onboardingMetametricsNeverSellData": { - "message": "$1 không bao giờ bán dữ liệu!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 bạn có thể chọn chia sẻ hoặc xóa dữ liệu sử dụng của mình trong phần cài đặt bất kỳ lúc nào.", + "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" }, - "onboardingMetametricsSendAnonymize": { - "message": "Gửi các sự kiện nhấp chuột & lượt xem trang ẩn danh" + "onboardingMetametricsNeverSellDataEmphasis": { + "message": "Không bắt buộc:" }, "onboardingMetametricsTitle": { "message": "Giúp chúng tôi cải thiện MetaMask" @@ -2714,15 +3285,26 @@ "onboardingPinExtensionTitle": { "message": "Quá trình cài đặt MetaMask đã hoàn tất!" }, + "onboardingPinMmiExtensionLabel": { + "message": "Ghim MetaMask Institutional" + }, "onboardingUsePhishingDetectionDescription": { "message": "Thông báo phát hiện dấu hiệu lừa đảo tùy thuộc vào quá trình truyền tin với $1. jsDeliver sẽ có quyền truy cập vào địa chỉ IP của bạn. Xem $2.", "description": "The $1 is the word 'jsDeliver', from key 'jsDeliver' and $2 is the words Privacy Policy from key 'privacyMsg', both separated here so that it can be wrapped as a link" }, + "onekey": { + "message": "OneKey" + }, "onlyAddTrustedNetworks": { "message": "Một nhà cung cấp mạng độc hại có thể nói dối về trạng thái của chuỗi khối và ghi lại hoạt động của bạn trên mạng. Chỉ thêm các mạng tùy chỉnh mà bạn tin tưởng." }, "onlyConnectTrust": { - "message": "Chỉ kết nối với các trang web mà bạn tin tưởng." + "message": "Chỉ kết nối với các trang web mà bạn tin tưởng. $1", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." + }, + "openCustodianApp": { + "message": "Mở ứng dụng $1", + "description": "The $1 is the name of the Custodian that will be open" }, "openFullScreenForLedgerWebHid": { "message": "Bật toàn màn hình để kết nối với thiết bị Ledger của bạn.", @@ -2734,6 +3316,15 @@ "openSeaNew": { "message": "OpenSea" }, + "openSeaToBlockaidBtnLabel": { + "message": "Khám phá các Snap" + }, + "openSeaToBlockaidDescription": { + "message": "Cảnh báo bảo mật không còn khả dụng trên mạng này. Cài đặt Snap có thể cải thiện khả năng bảo mật của bạn." + }, + "openSeaToBlockaidTitle": { + "message": "Chú ý!" + }, "operationFailed": { "message": "Thao tác thất bại" }, @@ -2777,6 +3368,9 @@ "password": { "message": "Mật khẩu" }, + "passwordMmiTermsWarning": { + "message": "Tôi hiểu rằng MetaMask Institutional không thể khôi phục mật khẩu này cho tôi. $1" + }, "passwordNotLongEnough": { "message": "Mật khẩu không đủ dài" }, @@ -2803,6 +3397,10 @@ "message": "Dán chuỗi khóa riêng tư của bạn vào đây:", "description": "For importing an account from a private key" }, + "paymasterInUse": { + "message": "Phí gas cho giao dịch này sẽ được Paymaster (tài khoản hợp đồng thông minh tài trợ cho các giao dịch) thanh toán.", + "description": "Alert shown in transaction confirmation if paymaster in use." + }, "pending": { "message": "Đang chờ xử lý" }, @@ -2816,18 +3414,26 @@ "message": "Bạn có (1) giao dịch đang chờ xử lý.", "description": "$1 is count of pending transactions" }, - "permissionRequest": { - "message": "Yêu cầu cấp quyền" + "permissionDetails": { + "message": "Chi tiết Quyền" }, - "permissionRequestCapitalized": { + "permissionRequest": { "message": "Yêu cầu cấp quyền" }, "permissionRequested": { "message": "Đã yêu cầu ngay" }, + "permissionRequestedForAccounts": { + "message": "Hiện đã yêu cầu cho $1", + "description": "Permission cell status for requested permission including accounts, rendered as AvatarGroup which is $1." + }, "permissionRevoked": { "message": "Đã thu hồi trong bản cập nhật này" }, + "permissionRevokedForAccounts": { + "message": "Đã thu hồi trong bản cập nhật này cho $1", + "description": "Permission cell status for revoked permission including accounts, rendered as AvatarGroup which is $1." + }, "permission_accessNamedSnap": { "message": "Kết nối với $1.", "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." @@ -2836,6 +3442,10 @@ "message": "Truy cập Internet.", "description": "The description of the `endowment:network-access` permission." }, + "permission_accessNetworkDescription": { + "message": "Cho phép $1 truy cập Internet. Điều này có thể được sử dụng để gửi và nhận dữ liệu với máy chủ của bên thứ ba.", + "description": "An extended description of the `endowment:network-access` permission. $1 is the snap name." + }, "permission_accessSnap": { "message": "Kết nối với Snap $1.", "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." @@ -2848,10 +3458,18 @@ "message": "Lên lịch và thực hiện các hành động theo định kỳ.", "description": "The description for the `snap_cronjob` permission" }, + "permission_cronjobDescription": { + "message": "Cho phép $1 thực hiện các hành động định kỳ vào thời gian, ngày hoặc khoảng thời gian cố định. Điều này có thể được sử dụng để kích hoạt các tương tác hoặc thông báo nhạy cảm với thời gian.", + "description": "An extended description for the `snap_cronjob` permission. $1 is the snap name." + }, "permission_dialog": { "message": "Hiển thị cửa sổ hộp thoại trong MetaMask.", "description": "The description for the `snap_dialog` permission" }, + "permission_dialogDescription": { + "message": "Cho phép $1 hiển thị cửa sổ bật lên MetaMask cùng với văn bản tùy chỉnh, trường nhập thông tin và nút để chấp nhận hoặc từ chối một hành động.\nCó thể được sử dụng để tạo cảnh báo, xác nhận và quy trình đồng ý tham gia cho một Snap.", + "description": "An extended description for the `snap_dialog` permission. $1 is the snap name." + }, "permission_ethereumAccounts": { "message": "Xem địa chỉ, số dư tài khoản, hoạt động và đề xuất giao dịch để chấp thuận", "description": "The description for the `eth_accounts` permission" @@ -2860,30 +3478,138 @@ "message": "Truy cập nhà cung cấp Ethereum.", "description": "The description for the `endowment:ethereum-provider` permission" }, + "permission_ethereumProviderDescription": { + "message": "Cho phép $1 giao tiếp trực tiếp với MetaMask để đọc dữ liệu từ chuỗi khối và đề xuất các tin nhắn và giao dịch.", + "description": "An extended description for the `endowment:ethereum-provider` permission. $1 is the snap name." + }, + "permission_getEntropy": { + "message": "Lấy các khóa tùy ý duy nhất cho $1.", + "description": "The description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getEntropyDescription": { + "message": "Cho phép $1 lấy các khóa tùy ý duy nhất cho $1 mà không để lộ. Các khóa này tách biệt với tài khoản MetaMask của bạn và không liên quan đến khóa riêng tư hoặc Cụm từ khôi phục bí mật của bạn. Các Snap khác không thể truy cập thông tin này.", + "description": "An extended description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getLocale": { + "message": "Xem ngôn ngữ ưa thích của bạn.", + "description": "The description for the `snap_getLocale` permission" + }, + "permission_getLocaleDescription": { + "message": "Cho phép $1 truy cập ngôn ngữ ưa thích của bạn từ cài đặt MetaMask. Điều này có thể được sử dụng để dịch và hiển thị nội dung của $1 theo ngôn ngữ của bạn.", + "description": "An extended description for the `snap_getLocale` permission. $1 is the snap name." + }, + "permission_homePage": { + "message": "Hiển thị màn hình tùy chỉnh", + "description": "The description for the `endowment:page-home` permission" + }, + "permission_homePageDescription": { + "message": "Cho phép $1 hiển thị màn hình chính tùy chỉnh trong MetaMask. Có thể được sử dụng cho giao diện người dùng, cấu hình và trang tổng quan.", + "description": "An extended description for the `endowment:page-home` permission. $1 is the snap name." + }, + "permission_keyring": { + "message": "Cho phép các yêu cầu thêm và kiểm soát tài khoản Ethereum", + "description": "The description for the `endowment:keyring` permission" + }, + "permission_keyringDescription": { + "message": "Cho phép $1 nhận các yêu cầu thêm hoặc xóa tài khoản, cũng như ký và giao dịch thay mặt cho các tài khoản này.", + "description": "An extended description for the `endowment:keyring` permission. $1 is the snap name." + }, "permission_lifecycleHooks": { "message": "Sử dụng hook vòng đời.", "description": "The description for the `endowment:lifecycle-hooks` permission" }, + "permission_lifecycleHooksDescription": { + "message": "Cho phép $1 sử dụng hook vòng đời để chạy mã vào những thời điểm cụ thể trong vòng đời của nó.", + "description": "An extended description for the `endowment:lifecycle-hooks` permission. $1 is the snap name." + }, "permission_manageAccounts": { "message": "Thêm và kiểm soát các tài khoản Ethereum", "description": "The description for `snap_manageAccounts` permission" }, + "permission_manageAccountsDescription": { + "message": "Cho phép $1 thêm hoặc xóa tài khoản Ethereum, sau đó thực hiện giao dịch và ký bằng các tài khoản này.", + "description": "An extended description for the `snap_manageAccounts` permission. $1 is the snap name." + }, + "permission_manageBip32Keys": { + "message": "Quản lý tài khoản $1.", + "description": "The description for the `snap_getBip32Entropy` permission. $1 is a derivation path, e.g. 'm/44'/0'/0' (secp256k1)'." + }, + "permission_manageBip44AndBip32KeysDescription": { + "message": "Cho phép $1 quản lý tài khoản và tài sản trên mạng được yêu cầu. Các tài khoản này được lấy và sao lưu bằng cụm từ khôi phục bí mật của bạn (mà không để lộ). Với khả năng lấy khóa, $1 có thể hỗ trợ nhiều giao thức chuỗi khối ngoài Ethereum (EVM).", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions. $1 is the snap name." + }, + "permission_manageBip44Keys": { + "message": "Quản lý tài khoản $1.", + "description": "The description for the `snap_getBip44Entropy` permission. $1 is the name of a protocol, e.g. 'Filecoin'." + }, "permission_manageState": { "message": "Lưu trữ và quản lý dữ liệu trong thiết bị.", "description": "The description for the `snap_manageState` permission" }, + "permission_manageStateDescription": { + "message": "Cho phép $1 lưu trữ, cập nhật và truy xuất dữ liệu một cách an toàn bằng mã hóa. Các Snap khác không thể truy cập thông tin này.", + "description": "An extended description for the `snap_manageState` permission. $1 is the snap name." + }, + "permission_nameLookup": { + "message": "Cung cấp tra cứu tên miền và địa chỉ.", + "description": "The description for the `endowment:name-lookup` permission." + }, + "permission_nameLookupDescription": { + "message": "Cho phép Snap tìm nạp, hiển thị địa chỉ và tra cứu tên miền trong các phần khác nhau của Giao diện người dùng MetaMask.", + "description": "An extended description for the `endowment:name-lookup` permission." + }, "permission_notifications": { "message": "Hiển thị thông báo.", "description": "The description for the `snap_notify` permission" }, + "permission_notificationsDescription": { + "message": "Cho phép $1 hiển thị thông báo trong MetaMask. Một văn bản thông báo ngắn có thể được kích hoạt bằng Snap đối với thông tin có thể thao tác hoặc nhạy cảm với thời gian.", + "description": "An extended description for the `snap_notify` permission. $1 is the snap name." + }, + "permission_rpc": { + "message": "Cho phép $1 giao tiếp trực tiếp với $2.", + "description": "The description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescription": { + "message": "Cho phép $1 gửi tin nhắn đến $2 và nhận phản hồi từ $2.", + "description": "An extended description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescriptionOriginList": { + "message": "$1 và $2", + "description": "A list of allowed origins where $2 is the last origin of the list and $1 is the rest of the list separated by ','." + }, + "permission_signatureInsight": { + "message": "Hiển thị cửa sổ thông tin chi tiết chữ ký.", + "description": "The description for the `endowment:signature-insight` permission" + }, + "permission_signatureInsightDescription": { + "message": "Cho phép $1 hiển thị cửa sổ thông tin chi tiết về bất kỳ yêu cầu chữ ký nào trước khi phê duyệt. Điều này có thể được sử dụng cho các giải pháp bảo mật và chống lừa đảo.", + "description": "An extended description for the `endowment:signature-insight` permission. $1 is the snap name." + }, + "permission_signatureInsightOrigin": { + "message": "Xem nguồn gốc của các trang web đưa ra yêu cầu chữ ký", + "description": "The description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission" + }, + "permission_signatureInsightOriginDescription": { + "message": "Cho phép $1 xem nguồn gốc (URI) của các trang web đưa ra yêu cầu chữ ký. Điều này có thể được sử dụng cho các giải pháp bảo mật và chống lừa đảo.", + "description": "An extended description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission. $1 is the snap name." + }, "permission_transactionInsight": { "message": "Tìm nạp và hiển thị thông tin chi tiết về giao dịch.", "description": "The description for the `endowment:transaction-insight` permission" }, + "permission_transactionInsightDescription": { + "message": "Cho phép $1 giải mã các giao dịch và hiển thị thông tin chi tiết trong giao diện người dùng MetaMask. Điều này có thể được sử dụng cho các giải pháp bảo mật và chống lừa đảo.", + "description": "An extended description for the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_transactionInsightOrigin": { "message": "Xem nguồn gốc của các trang web đề xuất giao dịch", "description": "The description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission" }, + "permission_transactionInsightOriginDescription": { + "message": "Cho phép $1 xem nguồn gốc (URI) của các trang web đề xuất giao dịch. Điều này có thể được sử dụng cho các giải pháp bảo mật và chống lừa đảo.", + "description": "An extended description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_unknown": { "message": "Quyền không xác định: $1", "description": "$1 is the name of a requested permission that is not recognized." @@ -2892,29 +3618,66 @@ "message": "Xem khóa công khai của bạn cho $1 ($2).", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a derivation path, e.g. 'm/44'/0'/0''. $2 is the elliptic curve name, e.g. 'secp256k1'." }, + "permission_viewBip32PublicKeysDescription": { + "message": "Cho phép $2 xem khóa công khai (và địa chỉ) của bạn đối với $1. Điều này sẽ không cấp bất kỳ quyền kiểm soát tài khoản hoặc tài sản nào.", + "description": "An extended description for the `snap_getBip32PublicKey` permission. $1 is a derivation path (name). $2 is the snap name." + }, "permission_viewNamedBip32PublicKeys": { "message": "Xem khóa công khai của bạn cho $1.", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a name for the derivation path, e.g., 'Ethereum accounts'." }, + "permission_walletSwitchEthereumChain": { + "message": "Chuyển sang và sử dụng mạng sau", + "description": "The label for the `wallet_switchEthereumChain` permission" + }, "permission_webAssembly": { "message": "Hỗ trợ dành cho WebAssembly.", "description": "The description of the `endowment:webassembly` permission." }, + "permission_webAssemblyDescription": { + "message": "Cho phép $1 truy cập vào các môi trường thực thi cấp thấp thông qua WebAssembly.", + "description": "An extended description of the `endowment:webassembly` permission. $1 is the snap name." + }, "permissions": { "message": "Quyền" }, - "permissionsTitle": { - "message": "Quyền" + "permissionsPageEmptyContent": { + "message": "Không có gì ở đây" + }, + "permissionsPageEmptySubContent": { + "message": "Đây là nơi bạn có thể xem các quyền mà bạn đã cấp cho các Snap đã cài đặt hoặc các trang web đã kết nối." }, - "permissionsTourDescription": { - "message": "Tìm tài khoản đã kết nối của bạn và quản lý quyền tại đây" + "permissionsPageTourDescription": { + "message": "Đây là bảng điều khiển để bạn quản lý các quyền được cấp cho các trang web đã kết nối và các Snap đã cài đặt." + }, + "permissionsPageTourTitle": { + "message": "Các trang web đã kết nối hiện đã được cấp quyền" }, "personalAddressDetected": { "message": "Đã tìm thấy địa chỉ cá nhân. Nhập địa chỉ hợp đồng token." }, + "petnamesEnabledToggle": { + "message": "Cho phép biệt danh" + }, + "petnamesEnabledToggleDescription": { + "message": "Điều này cho phép bạn chỉ định biệt danh cho bất kỳ địa chỉ nào. Khi có thể, chúng tôi sẽ đề xuất biệt danh cho các địa chỉ mà bạn tương tác." + }, + "pinExtensionDescription": { + "message": "Điều hướng đến trình đơn tiện ích mở rộng và ghim MetaMask Institutional để truy cập liền mạch." + }, + "pinExtensionTitle": { + "message": "Ghim tiện ích mở rộng" + }, + "pinToTop": { + "message": "Ghim lên đầu" + }, "pleaseConfirm": { "message": "Vui lòng xác nhận" }, + "plusMore": { + "message": "+ $1 khác", + "description": "$1 is the number of additional items" + }, "plusXMore": { "message": "+ $1 khác", "description": "$1 is a number of additional but unshown items in a list- this message will be shown in place of those items" @@ -2940,6 +3703,9 @@ "primaryCurrencySettingDescription": { "message": "Chọn Gốc để ưu tiên hiển thị giá trị bằng đơn vị tiền tệ gốc của chuỗi (ví dụ: ETH). Chọn Pháp định để ưu tiên hiển thị giá trị bằng đơn vị tiền pháp định mà bạn chọn." }, + "primaryType": { + "message": "Loại chính" + }, "priorityFee": { "message": "Phí ưu tiên" }, @@ -2960,6 +3726,18 @@ "message": "Khóa riêng tư cho $1", "description": "$1 represents the account name" }, + "privateKeyHidden": { + "message": "Khóa riêng tư bị ẩn", + "description": "Explains that the private key input is hidden" + }, + "privateKeyShow": { + "message": "Hiển thị/Ẩn đầu vào khóa riêng tư", + "description": "Describes a toggle that is used to show or hide the private key input" + }, + "privateKeyShown": { + "message": "Khóa riêng tư này đang được hiển thị", + "description": "Explains that the private key input is being shown" + }, "privateKeyWarning": { "message": "Cảnh báo: Tuyệt đối không để lộ khóa này. Bất kỳ ai có khóa riêng tư cũng có thể đánh cắp tài sản được lưu giữ trong tài khoản của bạn." }, @@ -2969,6 +3747,21 @@ "proceedWithTransaction": { "message": "Tôi vẫn muốn tiếp tục" }, + "productAnnouncements": { + "message": "Thông báo về sản phẩm" + }, + "profileSync": { + "message": "Đồng bộ hồ sơ" + }, + "profileSyncConfirmation": { + "message": "Nếu tắt đồng bộ hồ sơ, bạn sẽ không nhận được thông báo." + }, + "profileSyncDescription": { + "message": "Tạo một hồ sơ mà MetaMask sử dụng để đồng bộ một số chế độ cài đặt giữa các thiết bị của bạn. Đây là thao tác cần thiết để nhận được thông báo. $1." + }, + "profileSyncPrivacyLink": { + "message": "Tìm hiểu cách chúng tôi bảo vệ quyền riêng tư của bạn" + }, "proposedApprovalLimit": { "message": "Giới hạn chấp thuận đề xuất" }, @@ -2978,6 +3771,78 @@ "publicAddress": { "message": "Địa chỉ công khai" }, + "pushPlatformNotificationsFundsReceivedDescription": { + "message": "Bạn đã nhận được $1 $2" + }, + "pushPlatformNotificationsFundsReceivedDescriptionDefault": { + "message": "Bạn đã nhận được một vài token" + }, + "pushPlatformNotificationsFundsReceivedTitle": { + "message": "Đã nhận được tiền" + }, + "pushPlatformNotificationsFundsSentDescription": { + "message": "Bạn đã gửi thành công $1 $2" + }, + "pushPlatformNotificationsFundsSentDescriptionDefault": { + "message": "Bạn đã gửi thành công một vài token" + }, + "pushPlatformNotificationsFundsSentTitle": { + "message": "Đã gửi tiền" + }, + "pushPlatformNotificationsNftReceivedDescription": { + "message": "Bạn đã nhận được NFT mới" + }, + "pushPlatformNotificationsNftReceivedTitle": { + "message": "Đã nhận được NFT" + }, + "pushPlatformNotificationsNftSentDescription": { + "message": "Bạn đã gửi thành công NFT" + }, + "pushPlatformNotificationsNftSentTitle": { + "message": "Đã gửi NFT" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedDescription": { + "message": "Ký gửi Lido của bạn đã thành công" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedTitle": { + "message": "Ký gửi hoàn tất" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnDescription": { + "message": "Ký gửi Lido của bạn hiện đã sẵn sàng để rút" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnTitle": { + "message": "Tài sản ký gửi đã sẵn sàng để rút" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedDescription": { + "message": "Rút tiền Lido của bạn đã thành công" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedTitle": { + "message": "Rút tiền đã hoàn tất" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedDescription": { + "message": "Yêu cầu rút tiền Lido của bạn đã được gửi" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedTitle": { + "message": "Đã yêu cầu rút tiền" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedDescription": { + "message": "Ký gửi RocketPool của bạn đã thành công" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedTitle": { + "message": "Ký gửi hoàn tất" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedDescription": { + "message": "Hủy ký gửi RocketPool của bạn đã thành công" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedTitle": { + "message": "Hủy ký gửi hoàn tất" + }, + "pushPlatformNotificationsSwapCompletedDescription": { + "message": "Hoán đổi MetaMask của bạn đã thành công" + }, + "pushPlatformNotificationsSwapCompletedTitle": { + "message": "Hoán đổi xong" + }, "queued": { "message": "Đã đưa vào hàng đợi" }, @@ -2996,9 +3861,15 @@ "receive": { "message": "Nhận" }, + "receiveTokensCamelCase": { + "message": "Nhận token" + }, "recipientAddressPlaceholder": { "message": "Nhập địa chỉ công khai (0x) hoặc tên ENS" }, + "recipientAddressPlaceholderFlask": { + "message": "Nhập địa chỉ công khai (0x) hoặc tên miền" + }, "recommendedGasLabel": { "message": "Được đề xuất" }, @@ -3026,6 +3897,12 @@ "recoveryPhraseReminderTitle": { "message": "Bảo vệ tiền của bạn" }, + "redesignedConfirmationsEnabledToggle": { + "message": "Yêu cầu chữ ký được cải thiện" + }, + "redesignedConfirmationsToggleDescription": { + "message": "Bật tính năng này để xem các yêu cầu chữ ký ở định dạng nâng cao." + }, "refreshList": { "message": "Làm mới danh sách" }, @@ -3068,15 +3945,30 @@ "removeJWTDescription": { "message": "Bạn có chắc chắn muốn xóa token này không? Tất cả các tài khoản được chỉ định cho token này cũng sẽ bị xóa khỏi tiện ích mở rộng: " }, + "removeKeyringSnap": { + "message": "Xóa Snap này sẽ xóa các tài khoản này khỏi MetaMask:" + }, + "removeKeyringSnapToolTip": { + "message": "Snap giúp kiểm soát các tài khoản và khi xóa Snap, các tài khoản cũng sẽ bị xóa khỏi MetaMask, nhưng chúng sẽ vẫn tồn tại trên chuỗi khối." + }, "removeNFT": { "message": "Xóa NFT" }, + "removeNftErrorMessage": { + "message": "Chúng tôi không thể xóa NFT này." + }, "removeNftMessage": { "message": "NFT đã được xóa thành công!" }, "removeSnap": { "message": "Xóa Snap" }, + "removeSnapAccountDescription": { + "message": "Nếu bạn tiếp tục, tài khoản này sẽ không còn khả dụng trong MetaMask nữa." + }, + "removeSnapAccountTitle": { + "message": "Xóa tài khoản" + }, "removeSnapConfirmation": { "message": "Bạn có chắc chắn muốn xóa $1 không?", "description": "$1 represents the name of the snap" @@ -3087,12 +3979,24 @@ "replace": { "message": "thay thế" }, + "reportIssue": { + "message": "Báo cáo sự cố" + }, "requestFlaggedAsMaliciousFallbackCopyReason": { "message": "Nhà cung cấp bảo mật chưa chia sẻ thêm thông tin chi tiết" }, "requestFlaggedAsMaliciousFallbackCopyReasonTitle": { "message": "Yêu cầu bị gắn cờ độc hại" }, + "requestFrom": { + "message": "Yêu cầu từ" + }, + "requestFromInfo": { + "message": "Đây là trang web yêu cầu chữ ký của bạn." + }, + "requestFromTransactionDescription": { + "message": "Đây là trang web yêu cầu xác nhận của bạn." + }, "requestMayNotBeSafe": { "message": "Yêu cầu có thể không an toàn" }, @@ -3114,6 +4018,9 @@ "reset": { "message": "Đặt lại" }, + "resetStates": { + "message": "Đặt lại trạng thái" + }, "resetWallet": { "message": "Đặt lại ví" }, @@ -3142,7 +4049,7 @@ "message": "Khôi phục dữ liệu người dùng" }, "restoreUserDataDescription": { - "message": "Bạn có thể khôi phục cài đặt người dùng chứa các tùy chọn và địa chỉ tài khoản từ tập tin JSON đã sao lưu trước đó." + "message": "Bạn có thể khôi phục các dữ liệu như địa chỉ liên hệ và tùy chọn từ tập tin sao lưu." }, "resultPageError": { "message": "Lỗi" @@ -3196,9 +4103,15 @@ "message": "Bộ phận Hỗ trợ của MetaMask sẽ không bao giờ yêu cầu điều này.", "description": "The bolded texted in the second part of 'revealSeedWordsWarning'" }, + "revealSensitiveContent": { + "message": "Tiết lộ nội dung nhạy cảm" + }, "revealTheSeedPhrase": { "message": "Hiển thị cụm từ khôi phục bí mật" }, + "reviewAlerts": { + "message": "Xem lại cảnh báo" + }, "revokeAllTokensTitle": { "message": "Thu hồi quyền truy cập và chuyển tất cả $1 của bạn?", "description": "$1 is the symbol of the token for which the user is revoking approval" @@ -3249,6 +4162,9 @@ "searchAccounts": { "message": "Tìm kiếm tài khoản" }, + "searchTokens": { + "message": "Tìm kiếm token" + }, "secretRecoveryPhrase": { "message": "Cụm từ khôi phục bí mật" }, @@ -3265,7 +4181,8 @@ "message": "Cảnh báo bảo mật" }, "securityAlertsDescription": { - "message": "Tính năng này sẽ cảnh báo cho bạn khi có hoạt động độc hại trên Ethereum Mainnet bằng cách chủ động xem xét các yêu cầu giao dịch và chữ ký trong khi vẫn bảo vệ quyền riêng tư của bạn. Dữ liệu của bạn sẽ không được chia sẻ với bên thứ ba cung cấp dịch vụ này. Luôn tự thẩm định trước khi chấp thuận bất kỳ yêu cầu nào. Không có gì đảm bảo rằng tính năng này sẽ phát hiện được tất cả các hoạt động độc hại." + "message": "Tính năng này sẽ cảnh báo bạn khi có hoạt động độc hại bằng cách chủ động xem xét các yêu cầu giao dịch và chữ ký. $1", + "description": "Link to learn more about security alerts" }, "securityAndPrivacy": { "message": "Bảo mật và quyền riêng tư" @@ -3355,6 +4272,9 @@ "selectAnAccountHelp": { "message": "Chọn tài khoản lưu ký để sử dụng trong MetaMask Institutional." }, + "selectEnableDisplayMediaPrivacyPreference": { + "message": "Bật Hiển thị Phương tiện NFT" + }, "selectHdPath": { "message": "Chọn đường dẫn HD" }, @@ -3376,18 +4296,41 @@ "send": { "message": "Gửi" }, + "sendAToken": { + "message": "Gửi token" + }, "sendBugReport": { "message": "Gửi báo cáo lỗi." }, + "sendNoContactsConversionText": { + "message": "nhấn vào đây" + }, + "sendNoContactsDescription": { + "message": "Địa chỉ liên hệ cho phép bạn gửi giao dịch an toàn đến tài khoản khác nhiều lần. Để tạo địa chỉ liên hệ, $1", + "description": "$1 represents the action text 'click here'" + }, + "sendNoContactsTitle": { + "message": "Bạn chưa có địa chỉ liên hệ nào" + }, + "sendSelectReceiveAsset": { + "message": "Chọn tài sản để nhận" + }, + "sendSelectSendAsset": { + "message": "Chọn tài sản để gửi" + }, "sendSpecifiedTokens": { "message": "Gửi $1", "description": "Symbol of the specified token" }, - "sendTo": { - "message": "Gửi đến" + "sendSwapSubmissionWarning": { + "message": "Bằng cách nhấp vào nút này, giao dịch hoán đổi của bạn sẽ ngay lập tức bắt đầu. Vui lòng xem lại chi tiết giao dịch của bạn trước khi tiếp tục." }, - "sendTokens": { - "message": "Gửi token" + "sendTokenAsToken": { + "message": "Gửi $1 dưới dạng $2", + "description": "Used in the transaction display list to describe a swap and send. $1 and $2 are the symbols of tokens in involved in the swap." + }, + "sendingAsset": { + "message": "Đang gửi $1" }, "sendingDisabled": { "message": "Gửi tài sản NFT ERC-1155 chưa được hỗ trợ." @@ -3400,9 +4343,15 @@ "message": "Cảnh báo: bạn sắp gửi đến một hợp đồng token và điều này có thể dẫn đến nguy cơ mất tiền. $1", "description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning" }, + "sendingZeroAmount": { + "message": "Bạn đang gửi 0 $1." + }, "sepolia": { "message": "Mạng thử nghiệm Sepolia" }, + "serviceWorkerKeepAlive": { + "message": "Duy Trì Hoạt Động Service Worker" + }, "setAdvancedPrivacySettingsDetails": { "message": "MetaMask sử dụng các dịch vụ của bên thứ ba đáng tin cậy này để nâng cao sự hữu ích và an toàn của sản phẩm." }, @@ -3422,9 +4371,21 @@ "settingsSearchMatchingNotFound": { "message": "Không tìm thấy kết quả trùng khớp." }, + "settingsSubHeadingSignaturesAndTransactions": { + "message": "Yêu cầu chữ ký và giao dịch" + }, "show": { "message": "Hiển thị" }, + "showAccount": { + "message": "Hiển thị tài khoản" + }, + "showExtensionInFullSizeView": { + "message": "Hiển thị tiện ích mở rộng ở chế độ xem kích thước đầy đủ" + }, + "showExtensionInFullSizeViewDescription": { + "message": "Bật tùy chọn này để đặt chế độ xem kích thước đầy đủ làm mặc định khi bạn nhấn vào biểu tượng tiện ích mở rộng." + }, "showFiatConversionInTestnets": { "message": "Hiển thị tỷ lệ quy đổi trên các mạng thử nghiệm" }, @@ -3444,6 +4405,9 @@ "message": "Chọn tùy chọn này nếu bạn muốn dùng Etherscan để hiển thị các giao dịch đến trong danh sách giao dịch", "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" }, + "showIncomingTransactionsExplainer": { + "message": "Điều này dựa trên các API khác nhau của bên thứ ba cho mỗi mạng, có thể làm lộ địa chỉ Ethereum và địa chỉ IP của bạn." + }, "showMore": { "message": "Hiển thị thêm" }, @@ -3483,9 +4447,46 @@ "signin": { "message": "Đăng nhập" }, + "signing": { + "message": "Đang ký" + }, + "simulationDetailsFailed": { + "message": "Đã xảy ra lỗi khi tải kết quả ước tính." + }, + "simulationDetailsFiatNotAvailable": { + "message": "Không có sẵn" + }, + "simulationDetailsIncomingHeading": { + "message": "Bạn nhận được" + }, + "simulationDetailsNoBalanceChanges": { + "message": "Ví của bạn dự kiến không có thay đổi nào" + }, + "simulationDetailsOutgoingHeading": { + "message": "Bạn gửi" + }, + "simulationDetailsTitle": { + "message": "Thay đổi ước tính" + }, + "simulationDetailsTitleTooltip": { + "message": "Thay đổi ước tính là những gì có thể xảy ra nếu bạn thực hiện giao dịch này. Đây chỉ là dự đoán, không phải là đảm bảo." + }, + "simulationDetailsTotalFiat": { + "message": "Tổng = $1", + "description": "$1 is the total amount in fiat currency on one side of the transaction" + }, + "simulationDetailsTransactionReverted": { + "message": "Giao dịch này có khả năng thất bại" + }, "simulationErrorMessageV2": { "message": "Chúng tôi không thể ước tính gas. Có thể đã xảy ra lỗi trong hợp đồng và giao dịch này có thể thất bại." }, + "simulationsSettingDescription": { + "message": "Bật tính năng này để ước tính thay đổi số dư của các giao dịch trước khi bạn xác nhận. Điều này không đảm bảo cho kết quả cuối cùng của giao dịch. $1" + }, + "simulationsSettingSubHeader": { + "message": "Ước tính thay đổi số dư" + }, "skip": { "message": "Bỏ qua" }, @@ -3498,20 +4499,99 @@ "smartContracts": { "message": "Hợp đồng thông minh" }, - "smartSwapsAreHere": { - "message": "Hoán đổi thông minh đã ra mắt!" - }, - "smartSwapsDescription": { - "message": "Tính năng Hoán đổi của MetaMask nay đã thông minh hơn rất nhiều! Kích hoạt Hoán đổi thông minh sẽ cho phép MetaMask tối ưu quy trình Hoán đổi để giúp bạn:" - }, "smartSwapsErrorNotEnoughFunds": { "message": "Không có đủ tiền để thực hiện hoán đổi thông minh." }, "smartSwapsErrorUnavailable": { "message": "Hoán đổi thông minh tạm thời không khả dụng." }, + "smartTransactionCancelled": { + "message": "Giao dịch của bạn đã bị hủy" + }, + "smartTransactionCancelledDescription": { + "message": "Giao dịch của bạn không thể hoàn tất nên nó đã bị hủy để giúp bạn không phải trả phí gas không cần thiết." + }, + "smartTransactionError": { + "message": "Giao dịch của bạn đã thất bại" + }, + "smartTransactionErrorDescription": { + "message": "Biến động đột ngột của thị trường có thể gây ra lỗi. Nếu sự cố tiếp diễn, hãy liên hệ với bộ phận hỗ trợ khách hàng của MetaMask." + }, + "smartTransactionPending": { + "message": "Gửi giao dịch của bạn" + }, + "smartTransactionSuccess": { + "message": "Giao dịch của bạn đã hoàn tất" + }, + "smartTransactionTakingTooLong": { + "message": "Xin lỗi đã để bạn đợi lâu" + }, + "smartTransactionTakingTooLongDescription": { + "message": "Nếu giao dịch của bạn không được hoàn thành trong vòng $1, thì giao dịch sẽ bị hủy và bạn sẽ không bị tính phí gas.", + "description": "$1 is remaining time in seconds" + }, + "smartTransactions": { + "message": "Giao dịch thông minh" + }, + "smartTransactionsBenefit1": { + "message": "Tỷ lệ thành công 99,5%" + }, + "smartTransactionsBenefit2": { + "message": "Tiết kiệm tiền của bạn" + }, + "smartTransactionsBenefit3": { + "message": "Cập nhật theo thời gian thực" + }, + "smartTransactionsDescription": { + "message": "Đạt tỷ lệ thành công cao hơn, bảo vệ chống hành vi lợi dụng thông tin biết trước và khả năng hiển thị tốt hơn với Giao dịch thông minh." + }, + "smartTransactionsDescription2": { + "message": "Chỉ có sẵn trên Ethereum. Có thể bật/tắt bất cứ lúc nào trong phần Cài đặt. $1", + "description": "$1 is an external link to learn more about Smart Transactions" + }, + "smartTransactionsOptItModalTitle": { + "message": "Tăng cường bảo vệ giao dịch" + }, + "snapAccountCreated": { + "message": "Tài khoản đã được tạo" + }, + "snapAccountCreatedDescription": { + "message": "Tài khoản mới của bạn đã sẵn sàng để sử dụng!" + }, + "snapAccountCreationFailed": { + "message": "Tạo tài khoản không thành công" + }, + "snapAccountCreationFailedDescription": { + "message": "$1 không thể tạo tài khoản cho bạn.", + "description": "$1 is the snap name" + }, + "snapAccountRedirectFinishSigningTitle": { + "message": "Hoàn thành ký" + }, + "snapAccountRedirectSiteDescription": { + "message": "Làm theo hướng dẫn từ $1" + }, + "snapAccountRemovalFailed": { + "message": "Xóa tài khoản không thành công" + }, + "snapAccountRemovalFailedDescription": { + "message": "$1 không thể xóa tài khoản này cho bạn.", + "description": "$1 is the snap name" + }, + "snapAccountRemoved": { + "message": "Đã xóa tài khoản" + }, + "snapAccountRemovedDescription": { + "message": "Tài khoản này sẽ không còn khả dụng để sử dụng trong MetaMask nữa." + }, + "snapAccounts": { + "message": "Tài khoản Snap" + }, + "snapAccountsDescription": { + "message": "Tài khoản được kiểm soát bởi Snap bên thứ ba." + }, "snapConnectionWarning": { - "message": "$1 muốn kết nối với $2. Chỉ tiếp tục nếu bạn tin tưởng trang web này.", + "message": "$1 muốn sử dụng $2", "description": "$2 is the snap and $1 is the dapp requesting connection to the snap." }, "snapContent": { @@ -3522,15 +4602,35 @@ "message": "Trang web" }, "snapInstallRequest": { - "message": "Cài đặt $1 để được cấp các quyền sau. Chỉ tiếp tục nếu bạn tin tưởng $1.", + "message": "Cài đặt $1 sẽ cấp cho nó các quyền sau.", "description": "$1 is the snap name." }, "snapInstallSuccess": { "message": "Cài đặt hoàn tất" }, + "snapInstallWarningCheck": { + "message": "$1 muốn được cấp quyền để thực hiện những điều sau:", + "description": "Warning message used in popup displayed on snap install. $1 is the snap name." + }, "snapInstallWarningHeading": { "message": "Hãy tiến hành thận trọng" }, + "snapInstallWarningPermissionDescriptionForBip32View": { + "message": "Cho phép $1 xem khóa công khai (và địa chỉ) của bạn. Điều này sẽ không cấp bất kỳ quyền kiểm soát tài khoản hoặc tài sản nào.", + "description": "An extended description for the `snap_getBip32PublicKey` permission used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionDescriptionForEntropy": { + "message": "Cho phép Snap $1 quản lý tài khoản và tài sản trên các mạng được yêu cầu. Các tài khoản này được lấy và sao lưu bằng cụm từ khôi phục bí mật của bạn (mà không để lộ). Với khả năng lấy khóa, $1 có thể hỗ trợ nhiều giao thức chuỗi khối ngoài Ethereum (EVM).", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionNameForEntropy": { + "message": "Quản lý tài khoản $1", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, + "snapInstallWarningPermissionNameForViewPublicKey": { + "message": "Xem khóa công khai của bạn cho $1", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, "snapInstallationErrorDescription": { "message": "Không thể cài đặt $1.", "description": "Error description used when snap installation fails. $1 is the snap name." @@ -3548,6 +4648,10 @@ "snapResultSuccessDescription": { "message": "$1 đã sẵn sàng để sử dụng" }, + "snapUpdateAlertDescription": { + "message": "Tải phiên bản mới nhất của $1", + "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." + }, "snapUpdateAvailable": { "message": "Có cập nhật mới" }, @@ -3559,22 +4663,40 @@ "message": "Cập nhật thất bại", "description": "Error title used when snap update fails." }, + "snapUpdateRequest": { + "message": "Cập nhật $1 sẽ cấp cho nó các quyền sau.", + "description": "$1 is the Snap name." + }, "snapUpdateSuccess": { "message": "Cập nhật hoàn tất" }, + "snapUrlIsBlocked": { + "message": "Snap này muốn đưa bạn đến một trang web bị chặn. $1." + }, "snaps": { "message": "Snap" }, - "snapsInvalidUIError": { - "message": "Giao diện người dùng được chỉ định bởi Snap không hợp lệ." + "snapsConnected": { + "message": "Đã kết nối Snap" }, "snapsNoInsight": { "message": "Snap không trả về bất kỳ thông tin chi tiết nào" }, + "snapsPrivacyWarningFirstMessage": { + "message": "Bạn thừa nhận rằng mọi Snap mà bạn cài đặt đều là Dịch vụ bên thứ ba, trừ khi được xác định khác, như được định nghĩa trong $1 của Consensys. Việc bạn sử dụng Dịch vụ bên thứ ba sẽ phải tuân theo các điều khoản và điều kiện riêng do nhà cung cấp Dịch vụ bên thứ ba quy định. Consensys không khuyến nghị bất kỳ cá nhân cụ thể nào sử dụng bất kỳ Snap nào vì bất kỳ lý do cụ thể nào. Bạn tự chịu rủi ro khi truy cập, tin tưởng hoặc sử dụng Dịch vụ bên thứ ba. Consensys từ chối mọi trách nhiệm và nghĩa vụ pháp lý đối với mọi tổn thất khi bạn sử dụng Dịch vụ bên thứ ba.", + "description": "First part of a message in popup modal displayed when installing a snap for the first time. $1 is terms of use link." + }, "snapsPrivacyWarningSecondMessage": { "message": "Mọi thông tin mà bạn chia sẻ với Dịch vụ bên thứ ba sẽ được Dịch vụ bên thứ ba đó thu thập trực tiếp theo chính sách quyền riêng tư của họ. Vui lòng tham khảo chính sách quyền riêng tư của họ để biết thêm thông tin.", "description": "Second part of a message in popup modal displayed when installing a snap for the first time." }, + "snapsPrivacyWarningThirdMessage": { + "message": "Consensys không có quyền truy cập vào các thông tin mà bạn chia sẻ với Dịch vụ bên thứ ba.", + "description": "Third part of a message in popup modal displayed when installing a snap for the first time." + }, + "snapsSettings": { + "message": "Cài đặt Snap" + }, "snapsTermsOfUse": { "message": "Điều khoản sử dụng" }, @@ -3588,12 +4710,19 @@ "someNetworksMayPoseSecurity": { "message": "Một số mạng có thể gây ra rủi ro về bảo mật và/hoặc quyền riêng tư. Bạn cần hiểu rõ các rủi ro này trước khi thêm và sử dụng mạng." }, + "somethingDoesntLookRight": { + "message": "Có gì đó không ổn? $1", + "description": "A false positive message for users to contact support. $1 is a link to the support page." + }, "somethingIsWrong": { "message": "Đã xảy ra lỗi. Hãy thử tải lại trang." }, "somethingWentWrong": { "message": "Rất tiếc! Đã xảy ra sự cố." }, + "source": { + "message": "Nguồn" + }, "speedUp": { "message": "Tăng tốc" }, @@ -3728,6 +4857,14 @@ "stake": { "message": "Stake" }, + "startYourJourney": { + "message": "Bắt đầu hành trình của bạn với $1", + "description": "$1 is the token symbol" + }, + "startYourJourneyDescription": { + "message": "Hãy bắt đầu với Web3 bằng cách nạp một ít $1 vào ví của bạn.", + "description": "$1 is the token symbol" + }, "stateLogError": { "message": "Lỗi khi truy xuất nhật ký trạng thái." }, @@ -3740,6 +4877,9 @@ "stateLogsDescription": { "message": "Nhật ký trạng thái có chứa các địa chỉ tài khoản công khai của bạn và các giao dịch đã gửi." }, + "states": { + "message": "Trạng thái" + }, "status": { "message": "Trạng thái" }, @@ -3783,18 +4923,6 @@ "strong": { "message": "Mạnh" }, - "stxBenefit1": { - "message": "Giảm thiểu chi phí giao dịch" - }, - "stxBenefit2": { - "message": "Giảm tỷ lệ thất bại khi giao dịch" - }, - "stxBenefit3": { - "message": "Loại bỏ các giao dịch bị mắc kẹt" - }, - "stxBenefit4": { - "message": "Ngăn chặn giao dịch chạy trước" - }, "stxCancelled": { "message": "Hoán đổi sẽ thất bại" }, @@ -3804,6 +4932,10 @@ "stxCancelledSubDescription": { "message": "Hãy thử hoán đổi lại. Chúng tôi ở đây để bảo vệ bạn trước những rủi ro tương tự trong lần tới." }, + "stxEstimatedCompletion": { + "message": "Dự kiến hoàn thành sau < $1", + "description": "$1 is remeaning time in minutes and seconds, e.g. 0:10" + }, "stxFailure": { "message": "Hoán đổi không thành công" }, @@ -3811,6 +4943,9 @@ "message": "Thị trường thay đổi đột ngột có thể gây thất bại. Nếu sự cố vẫn tiếp diễn, vui lòng liên hệ $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInDescription": { + "message": "Bật Giao dịch thông minh để có các giao dịch đáng tin cậy và an toàn hơn trên Ethereum Mainnet. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Đang bí mật gửi yêu cầu Hoán đổi của bạn..." }, @@ -3849,12 +4984,21 @@ "submitted": { "message": "Đã gửi" }, + "suggestedTokenSymbol": { + "message": "Mã chứng khoán được đề xuất:" + }, "support": { "message": "Hỗ trợ" }, "supportCenter": { "message": "Truy cập trung tâm hỗ trợ của chúng tôi" }, + "surveyConversion": { + "message": "Tham gia khảo sát của chúng tôi" + }, + "surveyTitle": { + "message": "Định hình tương lai của MetaMask" + }, "swap": { "message": "Hoán đổi" }, @@ -3874,6 +5018,9 @@ "swapAmountReceivedInfo": { "message": "Đây là số tiền tối thiểu mà bạn sẽ nhận được. Bạn sẽ nhận được nhiều hơn tùy thuộc vào mức trượt giá." }, + "swapAndSend": { + "message": "Hoán đổi và gửi" + }, "swapAnyway": { "message": "Vẫn hoán đổi" }, @@ -3989,6 +5136,10 @@ "message": "Bao gồm $1% phí của MetaMask.", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." }, + "swapIncludesMMFeeAlt": { + "message": "Báo giá thể hiện khoản phí $1% của MetaMask", + "description": "Provides information about the fee that metamask takes for swaps using the latest copy. $1 is a decimal number." + }, "swapIncludesMetaMaskFeeViewAllQuotes": { "message": "Bao gồm $1% phí của MetaMask – $2", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number and $2 is a link to view all quotes." @@ -3996,6 +5147,9 @@ "swapLearnMore": { "message": "Tìm hiểu thêm về Hoán đổi" }, + "swapLiquiditySourceInfo": { + "message": "Chúng tôi tìm kiếm nhiều nguồn thanh khoản (sàn giao dịch, nền tảng tổng hợp thanh khoản và nhà tạo lập thị trường chuyên nghiệp) để so sánh tỷ giá và phí mạng." + }, "swapLowSlippage": { "message": "Mức trượt giá thấp" }, @@ -4268,6 +5422,9 @@ "switchEthereumChainConfirmationTitle": { "message": "Cho phép trang web này chuyển mạng?" }, + "switchInputCurrency": { + "message": "Chuyển đổi loại tiền tệ đầu vào" + }, "switchNetwork": { "message": "Chuyển mạng" }, @@ -4281,14 +5438,15 @@ "switchToThisAccount": { "message": "Chuyển sang tài khoản này" }, - "switchedTo": { - "message": "Bạn đã chuyển sang" + "switchedNetworkToastDecline": { + "message": "Không hiển thị lại" }, - "switcherTitle": { - "message": "Trình chuyển mạng" + "switchedNetworkToastMessage": { + "message": "$1 hiện đang hoạt động trên $2", + "description": "$1 represents the account name, $2 represents the network name" }, - "switcherTourDescription": { - "message": "Nhấp vào biểu tượng để chuyển mạng hoặc thêm mạng mới" + "switchedTo": { + "message": "Bạn đã chuyển sang" }, "switchingNetworksCancelsPendingConfirmations": { "message": "Khi bạn chuyển mạng, mọi xác nhận đang chờ xử lý sẽ bị hủy" @@ -4388,6 +5546,18 @@ "toggleEthSignOn": { "message": "BẬT (Không khuyến khích)" }, + "toggleRequestQueueDescription": { + "message": "Tính năng này cho phép bạn chọn mạng cho từng trang web thay vì một mạng duy nhất được chọn cho tất cả các trang web. Tính năng này sẽ ngăn bạn chuyển đổi mạng theo cách thủ công, điều này có thể ảnh hưởng đến trải nghiệm người dùng của bạn trên một số trang web." + }, + "toggleRequestQueueField": { + "message": "Chọn mạng cho từng trang web" + }, + "toggleRequestQueueOff": { + "message": "Tắt" + }, + "toggleRequestQueueOn": { + "message": "Bật" + }, "token": { "message": "Token" }, @@ -4404,7 +5574,7 @@ "message": "Địa chỉ hợp đồng token" }, "tokenDecimalFetchFailed": { - "message": "Cần có số thập phân của token." + "message": "Yêu cầu số thập phân của token. Tìm trên: $1" }, "tokenDecimalTitle": { "message": "Số thập phân của token:" @@ -4443,6 +5613,9 @@ "tooltipSatusConnected": { "message": "đã kết nối" }, + "tooltipSatusConnectedUpperCase": { + "message": "Đã kết nối" + }, "tooltipSatusNotConnected": { "message": "chưa kết nối" }, @@ -4583,6 +5756,39 @@ "tryAgain": { "message": "Thử lại" }, + "turnOff": { + "message": "Tắt" + }, + "turnOffMetamaskNotificationsError": { + "message": "Đã xảy ra lỗi khi tắt thông báo. Vui lòng thử lại sau." + }, + "turnOn": { + "message": "Bật" + }, + "turnOnMetamaskNotifications": { + "message": "Bật thông báo" + }, + "turnOnMetamaskNotificationsButton": { + "message": "Bật" + }, + "turnOnMetamaskNotificationsError": { + "message": "Đã xảy ra lỗi khi tạo thông báo. Vui lòng thử lại sau." + }, + "turnOnMetamaskNotificationsMessageFirst": { + "message": "Nhận thông báo để cập nhật tình hình trong ví của bạn." + }, + "turnOnMetamaskNotificationsMessagePrivacyBold": { + "message": "Cài đặt > Thông báo." + }, + "turnOnMetamaskNotificationsMessagePrivacyLink": { + "message": "Tìm hiểu cách chúng tôi bảo vệ quyền riêng tư của bạn khi sử dụng tính năng này." + }, + "turnOnMetamaskNotificationsMessageSecond": { + "message": "Để sử dụng tính năng thông báo ví, chúng tôi dùng hồ sơ để đồng bộ một số chế độ cài đặt trên các thiết bị của bạn. $1" + }, + "turnOnMetamaskNotificationsMessageThird": { + "message": "Bạn có thể tắt thông báo bất kỳ lúc nào trong $1" + }, "turnOnTokenDetection": { "message": "Bật phát hiện token nâng cao" }, @@ -4614,6 +5820,10 @@ "unknownNetwork": { "message": "Mạng riêng không xác định" }, + "unknownNetworkForKeyEntropy": { + "message": "Mạng chưa xác định", + "description": "Displayed on places like Snap install warning when regular name is not available." + }, "unknownQrCode": { "message": "Lỗi: Chúng tôi không thể xác định mã QR đó" }, @@ -4626,6 +5836,9 @@ "unlockMessage": { "message": "Web phi tập trung đang chờ đón bạn" }, + "unpin": { + "message": "Bỏ ghim" + }, "unrecognizedChain": { "message": "Không thể nhận diện mạng tùy chỉnh này", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." @@ -4643,6 +5856,9 @@ "update": { "message": "Cập nhật" }, + "updateRequest": { + "message": "Yêu cầu cập nhật" + }, "updatedWithDate": { "message": "Đã cập nhật $1" }, @@ -4667,12 +5883,25 @@ "useNftDetection": { "message": "Tự động phát hiện NFT" }, + "useNftDetectionDescriptionText": { + "message": "Cho phép MetaMask thêm các NFT mà bạn sở hữu bằng cách sử dụng dịch vụ của bên thứ ba (như OpenSea). Tính năng Tự động phát hiện NFT sẽ làm lộ địa chỉ IP và tài khoản của bạn với các dịch vụ này. Việc bật tính năng này có thể liên kết địa chỉ IP của bạn với địa chỉ Ethereum của bạn và hiển thị các NFT giả do những kẻ lừa đảo phát tán. Bạn có thể thêm token theo cách thủ công để tránh rủi ro này." + }, "usePhishingDetection": { "message": "Sử dụng tính năng phát hiện lừa đảo" }, "usePhishingDetectionDescription": { "message": "Hiển thị cảnh báo đối với các tên miền lừa đảo nhắm đến người dùng Ethereum" }, + "useSafeChainsListValidation": { + "message": "Kiểm tra thông tin mạng" + }, + "useSafeChainsListValidationDescription": { + "message": "MetaMask sử dụng dịch vụ của bên thứ ba có tên $1 để hiển thị thông tin mạng chính xác và được tiêu chuẩn hóa. Điều này giúp hạn chế khả năng bạn kết nối với mạng độc hại hoặc mạng không chính xác. Khi sử dụng tính năng này, địa chỉ IP của bạn sẽ được hiển thị với chainid.network." + }, + "useSafeChainsListValidationWebsite": { + "message": "chainid.network", + "description": "useSafeChainsListValidationWebsite is separated from the rest of the text so that we can bold the third party service name in the middle of them" + }, "useSiteSuggestion": { "message": "Sử dụng gợi ý của trang web" }, @@ -4685,6 +5914,9 @@ "userName": { "message": "Tên người dùng" }, + "userOpContractDeployError": { + "message": "Triển khai hợp đồng từ tài khoản hợp đồng thông minh không được hỗ trợ" + }, "verifyContractDetails": { "message": "Xác minh thông tin bên thứ ba" }, @@ -4702,6 +5934,9 @@ "view": { "message": "Xem" }, + "viewActivity": { + "message": "Xem hoạt động" + }, "viewAllDetails": { "message": "Xem toàn bộ chi tiết" }, @@ -4725,7 +5960,7 @@ }, "viewOnCustomBlockExplorer": { "message": "Xem $1 tại $2", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "Xem $1 trên Etherscan", @@ -4737,6 +5972,9 @@ "viewOnOpensea": { "message": "Xem trên Opensea" }, + "viewTransaction": { + "message": "Xem giao dịch" + }, "viewinCustodianApp": { "message": "Xem trong ứng dụng lưu ký" }, @@ -4744,6 +5982,9 @@ "message": "Xem $1 trong trình khám phá", "description": "$1 is the action type. e.g (Account, Transaction, Swap)" }, + "visitSite": { + "message": "Truy cập trang web" + }, "visitWebSite": { "message": "Truy cập trang web của chúng tôi" }, @@ -4782,6 +6023,10 @@ "warning": { "message": "Cảnh báo" }, + "warningFromSnap": { + "message": "Cảnh báo từ $1", + "description": "$1 represents the name of the snap" + }, "warningTooltipText": { "message": "$1 Bên thứ ba có thể chi tiêu toàn bộ số dư token của bạn mà không cần thông báo hoặc đồng ý thêm. Hãy tự bảo vệ chính mình bằng cách điều chỉnh hạn mức chi tiêu thấp hơn.", "description": "$1 is a warning icon with text 'Be careful' in 'warning' colour" @@ -4789,6 +6034,9 @@ "weak": { "message": "Yếu" }, + "web3": { + "message": "Web3" + }, "web3ShimUsageNotification": { "message": "Chúng tôi nhận thấy rằng trang web hiện tại đã cố dùng API window.web3 đã bị xóa. Nếu trang web có vẻ như đã bị lỗi, vui lòng nhấp vào $1 để biết thêm thông tin.", "description": "$1 is a clickable link." @@ -4829,10 +6077,6 @@ "whatsThis": { "message": "Đây là gì?" }, - "xOfY": { - "message": "$1/$2", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$1/$2 đang chờ xử lý", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" @@ -4840,6 +6084,9 @@ "yes": { "message": "Có" }, + "you": { + "message": "Bạn" + }, "youHaveAddedAll": { "message": "Bạn đã thêm tất cả các mạng phổ biến. Bạn có thể khám phá thêm nhiều mạng khác $1 Hoặc bạn có thể $2", "description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'" @@ -4862,6 +6109,12 @@ "yourPrivateSeedPhrase": { "message": "Cụm từ khôi phục bí mật của bạn" }, + "yourTransactionConfirmed": { + "message": "Giao dịch đã được xác nhận" + }, + "yourTransactionJustConfirmed": { + "message": "Chúng tôi không thể hủy giao dịch của bạn trước khi nó được xác nhận trên chuỗi khối." + }, "zeroGasPriceOnSpeedUpError": { "message": "Giá gas bằng 0 khi tăng tốc" } diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index 7b336018586b..ca5b01c48545 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -130,12 +130,21 @@ "account": { "message": "账户" }, + "accountActivity": { + "message": "账户活动" + }, + "accountActivityText": { + "message": "选择您想要接收通知的账户:" + }, "accountDetails": { "message": "账户详情" }, "accountIdenticon": { "message": "账户 Identicon" }, + "accountIsntConnectedToastText": { + "message": "$1 未连接到 $2" + }, "accountName": { "message": "账户名称" }, @@ -153,6 +162,12 @@ "accountSelectionRequired": { "message": "您需要选择一个账户!" }, + "accounts": { + "message": "账户" + }, + "accountsConnected": { + "message": "账户已连接" + }, "active": { "message": "活跃" }, @@ -243,6 +258,9 @@ "addIPFSGateway": { "message": "添加您首选的IPFS网关" }, + "addImportAccount": { + "message": "添加账户或硬件钱包" + }, "addMemo": { "message": "添加备忘录" }, @@ -256,6 +274,9 @@ "message": "此网络连接依赖于第三方。此连接可能不太可靠,或使第三方可进行活动跟踪。$1", "description": "$1 is Learn more link" }, + "addNewAccount": { + "message": "添加新账户" + }, "addNewToken": { "message": "添加新代币" }, @@ -265,6 +286,12 @@ "addNfts": { "message": "添加 NFT" }, + "addSnapAccountToggle": { + "message": "启用“添加账户Snap(测试版)”" + }, + "addSnapAccountsDescription": { + "message": "启用此功能后,您可以直接使用账户列表来添加新的测试版账户Snap。如果您要安装账户Snap,请紧记,此为第三方服务。" + }, "addSuggestedNFTs": { "message": "添加推荐的 NFT" }, @@ -281,6 +308,9 @@ "addingCustomNetwork": { "message": "正在添加网络" }, + "addingTokens": { + "message": "正在添加代币" + }, "address": { "message": "地址" }, @@ -316,9 +346,27 @@ "airgapVault": { "message": "AirGap Vault" }, + "alert": { + "message": "提醒" + }, + "alertBannerMultipleAlertsDescription": { + "message": "如果您批准此请求,以欺诈闻名的第三方可能会拿走您的所有资产。" + }, + "alertBannerMultipleAlertsTitle": { + "message": "多个提醒!" + }, "alertDisableTooltip": { "message": "这可以在“设置 > 提醒”中进行更改" }, + "alertModalAcknowledge": { + "message": "我已知晓风险并仍想继续" + }, + "alertModalDetails": { + "message": "提醒详情" + }, + "alertModalReviewAllAlerts": { + "message": "查看所有提醒" + }, "alertSettingsUnconnectedAccount": { "message": "浏览网站时选择的账户未连接" }, @@ -334,6 +382,9 @@ "alerts": { "message": "提醒" }, + "all": { + "message": "所有" + }, "allCustodianAccountsConnectedSubtitle": { "message": "您或者已连接所有托管账户,或者没有任何账户可连接到 MetaMask Institutional。" }, @@ -344,23 +395,26 @@ "message": "您的所有$1", "description": "$1 is the symbol or name of the token that the user is approving spending" }, + "allPermissions": { + "message": "所有许可" + }, "allYourNFTsOf": { "message": "您所有在$1的NFT", "description": "$1 is a link to contract on the block explorer when we're not able to retrieve a erc721 or erc1155 name" }, - "allowExternalExtensionTo": { - "message": "允许此外部扩展程序:" + "allow": { + "message": "允许" + }, + "allowMmiToConnectToCustodian": { + "message": "这将允许 MMI 连接到 $1,以导入您的账户。" + }, + "allowNotifications": { + "message": "允许通知" }, "allowSpendToken": { "message": "授予访问您的 $1 的权限?", "description": "$1 is the symbol of the token that are requesting to spend" }, - "allowThisSiteTo": { - "message": "允许此网站:" - }, - "allowThisSnapTo": { - "message": "允许此 Snap:" - }, "allowWithdrawAndSpend": { "message": "允许 $1 提取和消费最高以下金额:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -368,6 +422,23 @@ "amount": { "message": "数额" }, + "amountReceived": { + "message": "已收款金额" + }, + "amountSent": { + "message": "已发送金额" + }, + "andForListItems": { + "message": "$1,和 $2", + "description": "$1 is the first item, $2 is the last item in a list of items. Used in Snap Install Warning modal." + }, + "andForTwoItems": { + "message": "$1 和 $2", + "description": "$1 is the first item, $2 is the second item. Used in Snap Install Warning modal." + }, + "announcements": { + "message": "公告" + }, "appDescription": { "message": "浏览器中的以太坊钱包", "description": "The description of the application" @@ -402,6 +473,10 @@ "approveButtonText": { "message": "批准" }, + "approveIncreaseAllowance": { + "message": "增加 $1 支出上限", + "description": "The token symbol that is being approved" + }, "approveSpendingCap": { "message": "批准 $1 支出上限", "description": "The token symbol that is being approved" @@ -427,6 +502,10 @@ "message": "于$1获得批准", "description": "$1 is the approval date for a permission" }, + "approvedOnForAccounts": { + "message": "于 $1 批准用于 $2", + "description": "$1 is the approval date for a permission. $2 is the AvatarGroup component displaying account images." + }, "areYouSure": { "message": "您确定吗?" }, @@ -439,6 +518,12 @@ "attemptSendingAssets": { "message": "如果您试图将资产从一个网络直接发送到另一个网络,这可能会导致永久的资产损失。请务必使用跨链桥进行操作。" }, + "attemptSendingAssetsWithPortfolio": { + "message": "如果您尝试将资产从一个网络发送到另一个网络,这可能会导致资产损失。请务必使用跨链桥在不同网络间安全转移资金,例如 $1" + }, + "attemptToCancelSwapForFree": { + "message": "尝试免费取消兑换" + }, "attemptingConnect": { "message": "正在尝试连接到区块链。" }, @@ -477,7 +562,10 @@ "message": "如果不慎丢失个人设备,忘记密码,需要重新安装 MetaMask,或者需在另一台设备上访问钱包,使用此助记词才能恢复您的钱包。" }, "backupApprovalNotice": { - "message": "请备份您的账户私钥助记词,保证您的钱包和资金安全。" + "message": "请备份您的私钥助记词,确保您的钱包和资金安全。" + }, + "backupKeyringSnapReminder": { + "message": "请先确保您可以自行访问此Snap创建的任何账户,才可将其去除" }, "backupNow": { "message": "立即备份" @@ -486,7 +574,7 @@ "message": "将您的数据备份" }, "backupUserDataDescription": { - "message": "您可以将包含首选项和账户地址的用户设置备份到 JSON 文件中。" + "message": "您可以备份联系人和首选项等数据。" }, "balance": { "message": "余额" @@ -500,6 +588,30 @@ "basic": { "message": "基本" }, + "basicConfigurationBannerCTA": { + "message": "开启基本功能" + }, + "basicConfigurationBannerTitle": { + "message": "基本功能已关闭" + }, + "basicConfigurationLabel": { + "message": "基本功能" + }, + "basicConfigurationModalCheckbox": { + "message": "我理解并想继续" + }, + "basicConfigurationModalDisclaimerOff": { + "message": "这意味着您不能充分优化您在 MetaMask 上的时间。您将无法使用基本功能(例如代币详情、最优燃料设置等)。" + }, + "basicConfigurationModalDisclaimerOn": { + "message": "如需优化您在 MetaMask 上的时间,您将需要开启此功能。基本功能(例如代币详情、最优燃料设置等)对于 Web3 体验至关重要。" + }, + "basicConfigurationModalHeadingOff": { + "message": "关闭基本功能" + }, + "basicConfigurationModalHeadingOn": { + "message": "开启基本功能" + }, "beCareful": { "message": "请小心" }, @@ -571,6 +683,9 @@ "blockaidDescriptionTransferFarming": { "message": "如果您批准此请求,以欺诈闻名的第三方将会拿走您的所有资产。" }, + "blockaidMessage": { + "message": "隐私保护 - 不会与第三方共享任何数据。适用于 Arbitrum、Avalanche、BNB Chain、以太坊主网、Linea、Optimism、Polygon、Base 和 Sepolia。" + }, "blockaidTitleDeceptive": { "message": "此请求属欺骗性质" }, @@ -586,6 +701,9 @@ "bridge": { "message": "跨链桥" }, + "bridgeDontSend": { + "message": "跨链桥,不要发送" + }, "browserNotSupported": { "message": "您的浏览器不受支持……" }, @@ -598,6 +716,9 @@ "busy": { "message": "忙碌中" }, + "buyAndSell": { + "message": "买入和卖出" + }, "buyAsset": { "message": "购买$1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -609,6 +730,10 @@ "buyNow": { "message": "立即购买" }, + "buyToken": { + "message": "购买 $1", + "description": "$1 is the token symbol" + }, "bytes": { "message": "字节" }, @@ -618,9 +743,6 @@ "cancel": { "message": "取消" }, - "cancelEdit": { - "message": "取消编辑" - }, "cancelPopoverTitle": { "message": "取消交易" }, @@ -647,6 +769,9 @@ "chainIdExistsErrorMsg": { "message": "此链 ID 目前已被 $1 网络使用。" }, + "chainListReturnedDifferentTickerSymbol": { + "message": "此代币符号与输入的网络名称或链 ID 不匹配。许多热门代币使用类似的符号,骗子可能会使用这些符号来欺骗您,让您向他们发送更有价值的代币作为回报。在您继续之前请先验证所有信息。" + }, "chooseYourNetwork": { "message": "选择您的网络" }, @@ -682,9 +807,19 @@ "close": { "message": "关闭" }, + "closeExtension": { + "message": "关闭扩展程序" + }, + "closeWindowAnytime": { + "message": "您可以随时关闭此窗口。" + }, "coingecko": { "message": "CoinGecko" }, + "comboNoOptions": { + "message": "找不到任何选项", + "description": "Default text shown in the combo field dropdown if no options." + }, "configureSnapPopupDescription": { "message": "您现在要离开MetaMask来配置此snap。" }, @@ -703,12 +838,42 @@ "confirm": { "message": "确认" }, + "confirmAlertModalAcknowledge": { + "message": "我已知晓提醒并仍想继续" + }, + "confirmAlertModalDetails": { + "message": "如果您登录,以欺诈闻名的第三方可能会拿走您的所有资产。在继续操作之前,请查看提醒。" + }, + "confirmAlertModalTitle": { + "message": "您的资产可能面临风险" + }, + "confirmConnectCustodianRedirect": { + "message": "点击“继续”后,我们会将您重定向到 $1。" + }, + "confirmConnectCustodianText": { + "message": "要连接您的账户,请登录您的 $1 账户,然后点击“连接到 MMI”按钮。" + }, + "confirmConnectionTitle": { + "message": "确认连接到$1" + }, "confirmPassword": { "message": "确认密码" }, "confirmRecoveryPhrase": { "message": "确认私钥助记词" }, + "confirmTitleDescContractInteractionTransaction": { + "message": "仅在您完全理解内容并信任请求网站的情况下,才能确认此交易。" + }, + "confirmTitleDescSignature": { + "message": "仅在您批准该内容并信任请求网站的情况下,才能确认此消息。" + }, + "confirmTitleSignature": { + "message": "签名请求" + }, + "confirmTitleTransaction": { + "message": "交易请求" + }, "confirmed": { "message": "已确认" }, @@ -724,9 +889,15 @@ "connect": { "message": "连接" }, + "connectAccount": { + "message": "连接账户" + }, "connectAccountOrCreate": { "message": "连接账户或创建新账户" }, + "connectAccounts": { + "message": "连接账户" + }, "connectCustodialAccountMenu": { "message": "连接托管账户" }, @@ -736,36 +907,25 @@ "connectCustodialAccountTitle": { "message": "托管账户" }, + "connectCustodianAccounts": { + "message": "连接 $1 账户" + }, "connectManually": { "message": "手动连接到当前站点" }, + "connectMoreAccounts": { + "message": "连接更多账户" + }, "connectSnap": { "message": "连接$1", "description": "$1 is the snap for which a connection is being requested." }, - "connectTo": { - "message": "连接到 $1", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "连接到您的全部 $1", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "账户", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "连接到 $1", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1 个账户", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "与 MetaMask 连接" }, + "connectedAccounts": { + "message": "已连接的账户" + }, "connectedAccountsDescriptionPlural": { "message": "您有 $1 个账户连接到了该网站。", "description": "$1 is the number of accounts" @@ -776,6 +936,13 @@ "connectedAccountsEmptyDescription": { "message": "MetaMask 没有连接到该网站。要连接到 web3 网站,请找到并点击连接按钮。" }, + "connectedAccountsListTooltip": { + "message": "$1 可以查看账户余额、地址、活动,并建议要批准的关联账户交易。", + "description": "$1 is the origin name" + }, + "connectedAccountsToast": { + "message": "已更新连接的账户" + }, "connectedSites": { "message": "已连接的网站" }, @@ -787,12 +954,21 @@ "message": "$1 还没连接到任何网站。", "description": "$1 is the account name" }, + "connectedSnapAndNoAccountDescription": { + "message": "MetaMask 已连接到此网站,但尚未连接任何账户" + }, + "connectedWith": { + "message": "已连接" + }, "connecting": { "message": "连接中……" }, "connectingTo": { "message": "正在连接 $1" }, + "connectingToDeprecatedNetwork": { + "message": "“$1” 正在逐步淘汰,可能无法使用。请尝试其他网络。" + }, "connectingToGoerli": { "message": "正在连接 Goerli 测试网络" }, @@ -802,6 +978,9 @@ "connectingToLineaMainnet": { "message": "正在连接到 Linea 主网" }, + "connectingToLineaSepolia": { + "message": "正在连接 Linea Sepolia 测试网络" + }, "connectingToMainnet": { "message": "正在连接到以太坊主网" }, @@ -831,6 +1010,12 @@ "continue": { "message": "继续" }, + "continueMmiOnboarding": { + "message": "继续MetaMask Institutional入门过程" + }, + "continueToWallet": { + "message": "继续前往钱包" + }, "contract": { "message": "合约" }, @@ -882,6 +1067,9 @@ "copyAddress": { "message": "复制地址到剪贴板" }, + "copyPrivateKey": { + "message": "复制私钥" + }, "copyRawTransactionData": { "message": "复制原始交易数据" }, @@ -900,6 +1088,15 @@ "createPassword": { "message": "创建密码" }, + "createSnapAccountDescription": { + "message": "$1 想在 MetaMask 添加一个新账户。" + }, + "createSnapAccountTitle": { + "message": "创建账户" + }, + "crossChainSwapsLink": { + "message": "使用 MetaMask Portfolio 跨网络兑换" + }, "cryptoCompare": { "message": "CryptoCompare" }, @@ -950,10 +1147,16 @@ "message": "托管人" }, "custodianAccountAddedDesc": { - "message": "您现在可以在 MetaMask Institutional 使用您的托管账户。 " + "message": "您现在可以在 MetaMask Institutional 使用您的账户。" }, "custodianAccountAddedTitle": { - "message": "已添加所选托管账户。" + "message": "已添加所选 $1 账户。" + }, + "custodianQRCodeScan": { + "message": "使用 $1 移动应用程序扫描二维码" + }, + "custodianQRCodeScanDescription": { + "message": "或者登录您的 $1 账户,然后点击“连接到 MMI” 按钮" }, "custodianReplaceRefreshTokenChangedFailed": { "message": "请转到 $1,点击其用户界面内的“连接到 MMI”按钮,再次将您的账户连接到 MMI。" @@ -1017,7 +1220,7 @@ "message": "代币检测在此网络上尚不可用。请手动导入代币并确保您信任它。了解 $1" }, "customTokenWarningInTokenDetectionNetwork": { - "message": "手动导入代币前,请确保您信任它。了解 $1" + "message": "任何人都可以创建代币,包括创建现有代币的虚假版本。了解 $1" }, "customTokenWarningInTokenDetectionNetworkWithTDOFF": { "message": "在导入代币之前,请确保该代币是您所信任的。了解如何避免$1。您还可以启用代币检测$2。" @@ -1025,6 +1228,12 @@ "customerSupport": { "message": "客户支持团队" }, + "customizeYourNotifications": { + "message": "自定义您的通知" + }, + "customizeYourNotificationsText": { + "message": "开启您想要接收的通知类型:" + }, "dappRequestedSpendingCap": { "message": "网站请求的支出上限" }, @@ -1108,6 +1317,18 @@ "deposit": { "message": "保证金" }, + "deprecatedGoerliNtwrkMsg": { + "message": "由于以太坊系统的升级,Goerli 测试网络将很快淘汰。" + }, + "deprecatedNetwork": { + "message": "该网络被弃用" + }, + "deprecatedNetworkButtonMsg": { + "message": "知道了" + }, + "deprecatedNetworkDescription": { + "message": "您尝试连接的网络不再由 Metamask 支持。$1" + }, "description": { "message": "描述" }, @@ -1115,110 +1336,20 @@ "message": "来自 $1 的描述", "description": "$1 represents the name of the snap" }, - "desktopApp": { - "message": "桌面应用程序" - }, - "desktopConnectionCriticalErrorDescription": { - "message": "此错误可能是间歇性的,因此,请尝试重新启动此扩展程序或禁用 MetaMask 桌面应用程序。" - }, - "desktopConnectionCriticalErrorTitle": { - "message": "MetaMask启动时出现问题" - }, - "desktopConnectionLostErrorDescription": { - "message": "请确保您已启动并运行桌面应用程序,或禁用MetaMask桌面应用程序。" - }, - "desktopConnectionLostErrorTitle": { - "message": "MetaMask桌面应用程序连接已断开" - }, - "desktopDisableButton": { - "message": "禁用桌面应用程序" - }, - "desktopDisableErrorCTA": { - "message": "禁用MetaMask桌面应用程序" - }, - "desktopEnableButton": { - "message": "启用桌面应用程序" - }, - "desktopEnableButtonDescription": { - "message": "点击以运行桌面应用程序中的所有后台进程。" - }, - "desktopErrorNavigateSettingsCTA": { - "message": "返回设置页面" - }, - "desktopErrorRestartMMCTA": { - "message": "重新启动MetaMask" - }, - "desktopNotFoundErrorCTA": { - "message": "下载MetaMask桌面应用程序" - }, - "desktopNotFoundErrorDescription1": { - "message": "请确保您已启动并运行桌面应用程序。" - }, - "desktopNotFoundErrorDescription2": { - "message": "如果您没有安装桌面应用程序,请到MetaMask网站下载。" - }, - "desktopNotFoundErrorTitle": { - "message": "找不到MetaMask桌面应用程序" - }, - "desktopOpenOrDownloadCTA": { - "message": "打开MetaMask桌面应用程序" - }, - "desktopOutdatedErrorCTA": { - "message": "更新MetaMask桌面应用程序" - }, - "desktopOutdatedErrorDescription": { - "message": "您的MetaMask桌面应用程序需要升级。" - }, - "desktopOutdatedErrorTitle": { - "message": "MetaMask桌面应用程序已过时" - }, - "desktopOutdatedExtensionErrorCTA": { - "message": "更新 MetaMask Extension" - }, - "desktopOutdatedExtensionErrorDescription": { - "message": "您的 MetaMask Extension 需要升级。" - }, - "desktopOutdatedExtensionErrorTitle": { - "message": "MetaMask Extension 已过时" - }, - "desktopPageDescription": { - "message": "如果配对成功,扩展程序将重新启动,您必须重新输入密码。" - }, - "desktopPageSubTitle": { - "message": "请打开MetaMask桌面应用程序并输入此代码" - }, - "desktopPageTitle": { - "message": "与桌面配对" - }, - "desktopPairedWarningDeepLink": { - "message": "转到MetaMask桌面应用程序中的设置" - }, - "desktopPairedWarningDescription": { - "message": "如果要开始新的配对,请移除当前连接。" - }, - "desktopPairedWarningTitle": { - "message": "MM桌面应用程序已配对" - }, - "desktopPairingExpireMessage": { - "message": "代码将在$1秒后过期" - }, - "desktopRouteNotFoundErrorDescription": { - "message": "desktopRouteNotFoundErrorDescription" - }, - "desktopRouteNotFoundErrorTitle": { - "message": "desktopRouteNotFoundErrorTitle" + "details": { + "message": "详细信息" }, - "desktopUnexpectedErrorCTA": { - "message": "返回MetaMask主页" + "developerOptions": { + "message": "开发者选项" }, - "desktopUnexpectedErrorDescription": { - "message": "请检查MetaMask桌面应用程序以恢复连接" + "developerOptionsResetStatesAnnouncementsDescription": { + "message": "将所有公告的布尔值显示重设为 false。公告是显示在“最新资讯”(What's New)弹出模式中的通知。" }, - "desktopUnexpectedErrorTitle": { - "message": "出错了......" + "developerOptionsResetStatesOnboarding": { + "message": "重设与入门相关的各种状态,并重定向到“保护您的钱包”入门页面。" }, - "details": { - "message": "详细信息" + "developerOptionsServiceWorkerKeepAlive": { + "message": "导致时间戳持续保存到 session.storage" }, "disabledGasOptionToolTipMessage": { "message": "“$1”已被禁用,因为它不满足在原来的燃料费用基础上至少增加10%的要求。", @@ -1233,12 +1364,38 @@ "disconnectAllAccountsConfirmationDescription": { "message": "您确定要断开连接吗?您可能会失去网站功能。" }, + "disconnectAllAccountsText": { + "message": "账户" + }, + "disconnectAllSnapsText": { + "message": "Snap" + }, + "disconnectAllText": { + "message": "如果您将 $1 与 $2 断开连接,则需要重新连接才能再次使用。", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`, $2 represents the website hostname" + }, + "disconnectAllTitle": { + "message": "断开连接所有 $1", + "description": "$1 will map to `disconnectAllAccountsText` or `disconnectAllSnapsText`" + }, "disconnectPrompt": { "message": "断开连接 $1" }, "disconnectThisAccount": { "message": "断开此账户的连接" }, + "disconnectedAllAccountsToast": { + "message": "所有账户已与 $1 断开连接", + "description": "$1 is name of the dapp`" + }, + "disconnectedSingleAccountToast": { + "message": "$1 已与 $2 断开连接", + "description": "$1 is name of the name and $2 represents the dapp name`" + }, + "discoverSnaps": { + "message": "探索 Snap", + "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." + }, "dismiss": { "message": "关闭" }, @@ -1248,9 +1405,21 @@ "dismissReminderField": { "message": "关闭账户私钥助记词备份提醒" }, + "displayNftMedia": { + "message": "显示 NFT 媒体" + }, + "displayNftMediaDescription": { + "message": "显示 NFT 媒体和数据会将您的 IP 地址暴露给 OpenSea 或其他第三方。这可以让攻击者将您的 IP 地址与您的以太坊地址相关联。NFT 自动检测依赖于此设置,当此设置关闭时将无法使用。" + }, + "doNotShare": { + "message": "请勿与任何人分享此信息" + }, "domain": { "message": "域" }, + "domainNotSupportedOnNetwork": { + "message": "网络不支持域查找" + }, "done": { "message": "完成" }, @@ -1269,6 +1438,9 @@ "downloadStateLogs": { "message": "下载状态日志" }, + "dragAndDropBanner": { + "message": "您可以拖动网络以对其进行重新排序。 " + }, "dropped": { "message": "失败" }, @@ -1367,6 +1539,9 @@ "editSpeedUpEditGasFeeModalTitle": { "message": "编辑加速燃料费用" }, + "enable": { + "message": "启用" + }, "enableAutoDetect": { "message": " 启用自动检测" }, @@ -1397,6 +1572,18 @@ "enhancedTokenDetectionAlertMessage": { "message": "$1. $2目前提供增强型代币检测" }, + "ensDomainsSettingDescriptionIntroduction": { + "message": "MetaMask 让您可以直接在浏览器地址栏中看到 ENS(Ethereum 域名服务)域。其工作原理如下:" + }, + "ensDomainsSettingDescriptionOutroduction": { + "message": "请谨记,使用此功能时,IPFS 第三方服务可以看到您的 IP 地址。" + }, + "ensDomainsSettingDescriptionPart1": { + "message": "MetaMask 会检查以太坊的 ENS(Ethereum 域名服务)合约,以查找与 ENS 名称相关的代码。" + }, + "ensDomainsSettingDescriptionPart2": { + "message": "如果代码与 IPFS 关联,您就可以看到与之相关的内容(通常是网站)。" + }, "ensDomainsSettingTitle": { "message": "在地址栏中显示ENS域" }, @@ -1438,6 +1625,9 @@ "message": "错误详情", "description": "Title for collapsible section that displays error details for debugging purposes" }, + "errorGettingSafeChainList": { + "message": "获取安全链列表时出错,请谨慎继续。" + }, "errorMessage": { "message": "信息:$1", "description": "Displayed error message for debugging purposes. $1 is the error message" @@ -1469,6 +1659,9 @@ "message": "$1出错", "description": "$1 represents the name of the snap" }, + "estimatedFee": { + "message": "预估费用" + }, "ethGasPriceFetchWarning": { "message": "由于目前主要的燃料估算服务不可用,因此提供了备用燃料价格。" }, @@ -1495,12 +1688,24 @@ "message": "实验性" }, "extendWalletWithSnaps": { - "message": "扩展钱包体验。", + "message": "探索社区构建的 Snap,定制您的 Web3 体验", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "extensionInsallCompleteDescription": { + "message": "返回MetaMask Institutional产品的入门页面,以连接您的托管或自托管账户。" + }, + "extensionInsallCompleteTitle": { + "message": "扩展程序安装完成" + }, "externalExtension": { "message": "外部扩展程序" }, + "externalNameSourcesSetting": { + "message": "建议的昵称" + }, + "externalNameSourcesSettingDescription": { + "message": "我们将从 Etherscan、Infura 和 Lens 协议等第三方来源为您与之交互的地址获取建议的昵称。这些来源将能够看到这些地址和您的 IP 地址。您的账户地址不会暴露给第三方。" + }, "failed": { "message": "失败" }, @@ -1519,6 +1724,9 @@ "feeAssociatedRequest": { "message": "此请求需要支付一定的费用。" }, + "feeDetails": { + "message": "费用详情" + }, "fiat": { "message": "法币", "description": "Exchange type" @@ -1551,6 +1759,9 @@ "message": "我接受风险", "description": "this text is shown on a button, which the user presses to confirm they understand the risks of using Flask" }, + "floatAmountToken": { + "message": "代币金额必须是整数" + }, "followUsOnTwitter": { "message": "在 Twitter 上关注我们" }, @@ -1573,6 +1784,9 @@ "fromTokenLists": { "message": "从代币列表:$1" }, + "function": { + "message": "功能:$1" + }, "functionApprove": { "message": "功能:批准" }, @@ -1582,6 +1796,13 @@ "functionType": { "message": "功能类型" }, + "fundYourWallet": { + "message": "向您的钱包存入资金" + }, + "fundYourWalletDescription": { + "message": "将一些 $1 添加到您的钱包并开始使用", + "description": "$1 is the token symbol" + }, "gas": { "message": "燃料" }, @@ -1592,6 +1813,9 @@ "message": "这笔燃料费是由 $1 建议的。忽略它可能会导致您的交易出现问题。如果您有疑问,请联系 $1。", "description": "$1 represents the Dapp's origin" }, + "gasIsETH": { + "message": "燃料是 $1 " + }, "gasLimit": { "message": "燃料限制" }, @@ -1636,6 +1860,9 @@ "message": "$1 小时", "description": "$1 represents a number of hours" }, + "gasTimingLow": { + "message": "慢" + }, "gasTimingMinutesShort": { "message": "$1 分钟", "description": "$1 represents a number of minutes" @@ -1650,15 +1877,29 @@ "general": { "message": "通用" }, - "globalTitle": { - "message": "全局菜单" + "generalCameraError": { + "message": "我们无法访问您的摄像头。请再试一次。" }, - "globalTourDescription": { - "message": "查看您的投资组合、已连接的网站、设置等等" + "generalCameraErrorTitle": { + "message": "出错了..." + }, + "genericExplorerView": { + "message": "在$1查看账户" + }, + "getStartedWithNFTs": { + "message": "获取 $1 以购买 NFT", + "description": "$1 is the token symbol" + }, + "getStartedWithNFTsDescription": { + "message": "将一些 $1 添加到您的钱包并开始使用 NFT", + "description": "$1 is the token symbol" }, "goBack": { "message": "返回" }, + "goToSite": { + "message": "转到网站" + }, "goerli": { "message": "Goerli 测试网络" }, @@ -1700,15 +1941,24 @@ "hexData": { "message": "十六进制数据" }, + "hiddenAccounts": { + "message": "隐藏账户" + }, "hide": { "message": "隐藏" }, + "hideAccount": { + "message": "隐藏账户" + }, "hideFullTransactionDetails": { "message": "隐藏完整的交易细节" }, "hideSeedPhrase": { "message": "隐藏助记词" }, + "hideSentitiveInfo": { + "message": "隐藏敏感信息" + }, "hideToken": { "message": "隐藏代币" }, @@ -1790,6 +2040,9 @@ "ignoreTokenWarning": { "message": "如果您隐藏代币,它们将不会在您的钱包中显示。但您仍然可以通过搜索代币来添加它们。" }, + "imToken": { + "message": "imToken" + }, "import": { "message": "导入", "description": "Button to import an account from a selected file" @@ -1848,6 +2101,9 @@ "importTokensCamelCase": { "message": "添加代币" }, + "importTokensError": { + "message": "我们无法导入代币。请稍后再试。" + }, "importWithCount": { "message": "导入$1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -1866,6 +2122,9 @@ "initialTransactionConfirmed": { "message": "您的初始交易已被网络确认。请点击“确定”返回。" }, + "inlineAlert": { + "message": "提醒" + }, "inputLogicEmptyState": { "message": "仅需输入一个您觉得比较恰当的现在或将来第三方支出的数字。以后您可以随时提高支出上限。" }, @@ -1876,6 +2135,27 @@ "inputLogicHigherNumber": { "message": "此操作允许第三方支出您所有的代币余额,直到达到上限或您撤销支出上限为止。如果不是有意为之,请考虑设置较低的支出上限。" }, + "insightWarning": { + "message": "警告" + }, + "insightWarningCheckboxMessage": { + "message": "$1 $2 的请求", + "description": "$1 is the action i.e. sign, confirm. $2 is the origin making the request." + }, + "insightWarningContentPlural": { + "message": "在 $2 之前先查看 $1。操作后,$3 将不可逆转。", + "description": "$1 the 'insightWarnings' message (2 warnings) representing warnings, $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningContentSingular": { + "message": "在 $2 之前先查看 $1。操作后,$3 将不可逆转。", + "description": "$1 is the 'insightWarning' message (1 warning), $2 is the action (i.e. signing) and $3 is the result (i.e. signature, transaction)" + }, + "insightWarningHeader": { + "message": "此请求可能有危险" + }, + "insightWarnings": { + "message": "警告" + }, "insightsFromSnap": { "message": "来自$1的见解", "description": "$1 represents the name of the snap" @@ -1883,9 +2163,18 @@ "install": { "message": "安装" }, + "installExtension": { + "message": "安装扩展程序" + }, + "installExtensionDescription": { + "message": "世界领先的web3钱包MetaMask的符合机构标准的版本。" + }, "installOrigin": { "message": "安装源" }, + "installRequest": { + "message": "添加到 MetaMask" + }, "installedOn": { "message": "已在 $1 上安装", "description": "$1 is the date when the snap has been installed" @@ -1914,6 +2203,12 @@ "insufficientTokens": { "message": "代币不足。" }, + "interactingWith": { + "message": "正在与下述内容交互:" + }, + "interactingWithTransactionDescription": { + "message": "这是您与之交互的合约。通过验证详细信息来保护自己免受诈骗。" + }, "invalidAddress": { "message": "地址无效" }, @@ -1986,6 +2281,9 @@ "ipfsToggleModalSettings": { "message": "设置 > 安全和隐私" }, + "isSigningOrSubmitting": { + "message": "先前的交易仍在签署或提交中" + }, "jazzAndBlockies": { "message": "哈希头像是帮助您一眼识别账户的独特图标,有 Jazzicons 和 Blockies 两种不同风格。" }, @@ -1999,6 +2297,24 @@ "message": "JSON 文件", "description": "format for importing an account" }, + "keyringAccountName": { + "message": "账户名称" + }, + "keyringAccountPublicAddress": { + "message": "公钥" + }, + "keyringSnapRemovalResult1": { + "message": "$1 $2去除", + "description": "Displays the result after removal of a keyring snap. $1 is the snap name, $2 is whether it is successful or not" + }, + "keyringSnapRemovalResultNotSuccessful": { + "message": "未能 ", + "description": "Displays the `not` word in $2." + }, + "keyringSnapRemoveConfirmation": { + "message": "键入$1以确认您要去除此Snap:", + "description": "Asks user to input the name nap prior to deleting the snap. $1 is the snap name" + }, "keystone": { "message": "Keystone" }, @@ -2017,9 +2333,15 @@ "lastSold": { "message": "最后售出" }, + "lavaDomeCopyWarning": { + "message": "为了您的安全,现在无法选择此文本。" + }, "layer1Fees": { "message": "一层公链费用" }, + "layer2Fees": { + "message": "二层公链费用" + }, "learnCancelSpeeedup": { "message": "学习如何 $1", "description": "$1 is link to cancel or speed up transactions" @@ -2037,9 +2359,21 @@ "learnMoreUpperCase": { "message": "了解更多" }, + "learnMoreUpperCaseWithDot": { + "message": "了解更多。" + }, "learnScamRisk": { "message": "欺诈和安全风险信息。" }, + "learnToBridge": { + "message": "了解跨链桥" + }, + "leaveMetaMask": { + "message": "要离开 MetaMask?" + }, + "leaveMetaMaskDesc": { + "message": "您即将访问 MetaMask 之外的网站。继续之前请仔细检查 URL。" + }, "ledgerAccountRestriction": { "message": "您需要先使用最后一个账户,然后才能添加新账户。" }, @@ -2058,6 +2392,18 @@ "ledgerDeviceOpenFailureMessage": { "message": "Ledger 设备打开失败。您的 Ledger 可能已连接到其他软件。请关闭 Ledger Live 或其他连接到您的 Ledger 设备的应用程序,并尝试再次连接。" }, + "ledgerErrorConnectionIssue": { + "message": "请重新连接Ledger,打开ETH应用程序,然后重试。" + }, + "ledgerErrorDevicedLocked": { + "message": "您的Ledger已锁定。请在解锁后重试。" + }, + "ledgerErrorEthAppNotOpen": { + "message": "要解决此问题,请在您的设备上打开ETH应用程序,然后重试。" + }, + "ledgerErrorTransactionDataNotPadded": { + "message": "以太坊交易输入数据填充不足。" + }, "ledgerLiveApp": { "message": "Ledger Live 应用程序" }, @@ -2077,6 +2423,9 @@ "lightTheme": { "message": "浅色" }, + "likeToImportToken": { + "message": "您想导入此代币吗?" + }, "likeToImportTokens": { "message": "您想导入这些代币吗?" }, @@ -2086,6 +2435,9 @@ "lineaMainnet": { "message": "Linea 主网" }, + "lineaSepolia": { + "message": "Linea Sepolia 测试网络" + }, "link": { "message": "链接" }, @@ -2098,8 +2450,11 @@ "loading": { "message": "正在加载..." }, - "loadingNFTs": { - "message": "正在加载NFT......" + "loadingScreenHardwareWalletMessage": { + "message": "请在硬件钱包上完成交易。" + }, + "loadingScreenSnapMessage": { + "message": "请在Snap上完成交易。" }, "loadingTokens": { "message": "加载代币中……" @@ -2146,6 +2501,9 @@ "message": "请确保没有人在看您的屏幕", "description": "Warning to users to be care while creating and saving their new Secret Recovery Phrase" }, + "manageInSettings": { + "message": "在设置中管理" + }, "max": { "message": "最大" }, @@ -2180,15 +2538,34 @@ "metaMaskConnectStatusParagraphTwo": { "message": "连接状态按钮显示所访问的网站是否与您当前选择的账户连接。" }, + "metadataModalSourceTooltip": { + "message": "$1 托管于 npm 上,$2 是此 Snap 的唯一标识符。", + "description": "$1 is the snap name and $2 is the snap NPM id." + }, "metamaskInstitutionalVersion": { "message": "MetaMask Institutional 版本" }, + "metamaskNotificationsAreOff": { + "message": "钱包通知目前未开启。" + }, + "metamaskPortfolio": { + "message": "MetaMask Portfolio。" + }, "metamaskSwapsOfflineDescription": { "message": "MetaMask Swaps 正在进行维护。请稍后再查看。" }, "metamaskVersion": { "message": "MetaMask 版本" }, + "methodData": { + "message": "方法" + }, + "methodDataTransactionDescription": { + "message": "这是将要采取的具体行动。该数据可能是伪造的,因此请确保您信任另一端的网站。" + }, + "methodNotSupported": { + "message": "不支持此账户。" + }, "metrics": { "message": "指标" }, @@ -2224,11 +2601,17 @@ "mmiBuiltAroundTheWorld": { "message": "MetaMask Institutional 面向全球各地设计并建立。" }, + "mmiNewNFTDetectedInNFTsTabMessage": { + "message": "让 MetaMask Institutional 自动检测您钱包中的 NFT,并在检测到时显示那些 NFT。" + }, + "mmiPasswordSetupDetails": { + "message": "此密码仅会解锁您的MetaMask Institutional扩展程序。" + }, "more": { "message": "更多" }, "multipleSnapConnectionWarning": { - "message": "$1 想连接 $2 个 snap。只有在您信任此网站的情况下才能继续。", + "message": "$1 想连接 $2 个 snap。", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." }, "mustSelectOne": { @@ -2237,10 +2620,80 @@ "name": { "message": "名称" }, + "nameAddressLabel": { + "message": "地址", + "description": "Label above address field in name component modal." + }, + "nameInstructionsNew": { + "message": "如果您知道此地址,则为其添加昵称,以便将来识别。", + "description": "Instruction text in name component modal when value is not recognised." + }, + "nameInstructionsRecognized": { + "message": "此地址有默认昵称,但您可以对其进行编辑或了解其他建议。", + "description": "Instruction text in name component modal when value is recognized but not saved." + }, + "nameInstructionsSaved": { + "message": "您以前为此地址添加过昵称。您可以编辑或查看其他建议的昵称。", + "description": "Instruction text in name component modal when value is saved." + }, + "nameLabel": { + "message": "昵称", + "description": "Label above name input field in name component modal." + }, + "nameModalMaybeProposedName": { + "message": "可能:$1", + "description": "$1 is the proposed name" + }, + "nameModalTitleNew": { + "message": "未知地址", + "description": "Title of the modal created by the name component when value is not recognised." + }, + "nameModalTitleRecognized": { + "message": "已识别的地址", + "description": "Title of the modal created by the name component when value is recognized but not saved." + }, + "nameModalTitleSaved": { + "message": "已保存的地址", + "description": "Title of the modal created by the name component when value is saved." + }, + "nameProviderProposedBy": { + "message": "由 $1 提议", + "description": "$1 is the name of the provider" + }, + "nameProvider_ens": { + "message": "以太坊域名服务(ENS)" + }, + "nameProvider_etherscan": { + "message": "Etherscan" + }, + "nameProvider_lens": { + "message": "Lens 协议" + }, + "nameProvider_token": { + "message": "MetaMask" + }, + "nameSetPlaceholder": { + "message": "选择昵称......", + "description": "Placeholder text for name input field in name component modal." + }, + "nativePermissionRequestDescription": { + "message": "您希望此网站执行以下操作吗?", + "description": "Description below header used on Permission Connect screen for native permissions." + }, "nativeToken": { "message": "此网络上的原生代币为$1。它是用于燃料费的代币。", "description": "$1 represents the name of the native token on the current network" }, + "nativeTokenScamWarningConversion": { + "message": "编辑网络详情" + }, + "nativeTokenScamWarningDescription": { + "message": "此网络与其关联的链 ID 或名称不匹配。多种常用代币均使用名称 $1,使其成为欺诈目标。欺诈方可能会诱骗您向其发送更有价值的货币作为回报。在继续之前,请验证所有内容。", + "description": "$1 represents the currency name" + }, + "nativeTokenScamWarningTitle": { + "message": "这可能是欺诈" + }, "needHelp": { "message": "需要帮助?请联系 $1", "description": "$1 represents `needHelpLinkText`, the text which goes in the help link" @@ -2261,6 +2714,9 @@ "negativeETH": { "message": "不能发负值的 ETH。" }, + "negativeOrZeroAmountToken": { + "message": "发送的资产金额不能为负数或零。" + }, "network": { "message": "网络: " }, @@ -2291,6 +2747,9 @@ "networkNameBSC": { "message": "BSC" }, + "networkNameBase": { + "message": "基础" + }, "networkNameDefinition": { "message": "与此网络关联的名称。" }, @@ -2300,12 +2759,21 @@ "networkNameGoerli": { "message": "Goerli" }, + "networkNameLinea": { + "message": "Linea" + }, + "networkNameOpMainnet": { + "message": "OP主网" + }, "networkNamePolygon": { "message": "Polygon" }, "networkNameTestnet": { "message": "Testnet" }, + "networkNameZkSyncEra": { + "message": "zkSync Era" + }, "networkProvider": { "message": "网络提供商" }, @@ -2358,6 +2826,19 @@ "newContract": { "message": "新合约" }, + "newNFTDetectedInImportNFTsMessageStrongText": { + "message": "设置 > 安全和隐私" + }, + "newNFTDetectedInImportNFTsMsg": { + "message": "要使用 Opensea 来查看您的 NFT,请在 $1 中打开“显示 NFT 媒体”。", + "description": "$1 is used for newNFTDetectedInImportNFTsMessageStrongText" + }, + "newNFTDetectedInNFTsTabMessage": { + "message": "让 MetaMask 自动检测您钱包中的 NFT,并在检测到时显示那些 NFT。" + }, + "newNFTsAutodetected": { + "message": "NFT 自动检测" + }, "newNetworkAdded": { "message": "成功添加了 “$1”!" }, @@ -2367,6 +2848,12 @@ "newPassword": { "message": "新密码(至少 8 个字符)" }, + "newPrivacyPolicyActionButton": { + "message": "了解更多" + }, + "newPrivacyPolicyTitle": { + "message": "我们已经更新了隐私政策" + }, "newTokensImportedMessage": { "message": "您已成功导入$1。", "description": "$1 is the string of symbols of all the tokens imported" @@ -2388,6 +2875,9 @@ "message": "此代币是NFT。另加上$1", "description": "$1 is a clickable link with text defined by the 'importNFTPage' key" }, + "nftAlreadyAdded": { + "message": "此NFT已添加。" + }, "nftDisclaimer": { "message": "免责声明:MetaMask 从源网址中提取媒体文件。该网址有时会因铸造 NFT 的市场而改变。" }, @@ -2423,12 +2913,21 @@ "noAddressForName": { "message": "此名称尚未设置地址。" }, + "noConnectedAccountDescription": { + "message": "选择要在此站点上使用的账户以继续。" + }, + "noConnectedAccountTitle": { + "message": "MetaMask 未连接到此站点" + }, "noConversionDateAvailable": { "message": "没有可用的货币转换日期" }, "noConversionRateAvailable": { "message": "无可用汇率" }, + "noDomainResolution": { + "message": "没有提供域名解析。" + }, "noNFTs": { "message": "尚无 NFT" }, @@ -2447,6 +2946,9 @@ "noWebcamFoundTitle": { "message": "未找到网络摄像头" }, + "nonCustodialAccounts": { + "message": "MetaMask Institutional 允许您使用非托管账户,如果您计划使用这些账户,请备份私钥助记词。" + }, "nonce": { "message": "Nonce" }, @@ -2477,6 +2979,111 @@ "notePlaceholder": { "message": "审批人在托管人处审批交易时会看到此单据。" }, + "notificationDetail": { + "message": "详情" + }, + "notificationDetailBaseFee": { + "message": "基础费用(GWEI)" + }, + "notificationDetailGasLimit": { + "message": "燃料限制(单位)" + }, + "notificationDetailGasUsed": { + "message": "已使用燃料(单位)" + }, + "notificationDetailMaxFee": { + "message": "每单位燃料的最大费用" + }, + "notificationDetailNetwork": { + "message": "网络" + }, + "notificationDetailNetworkFee": { + "message": "网络费" + }, + "notificationDetailPriorityFee": { + "message": "优先费用(GWEI)" + }, + "notificationItemCheckBlockExplorer": { + "message": "在 BlockExplorer 中查看" + }, + "notificationItemCollection": { + "message": "收藏品" + }, + "notificationItemConfirmed": { + "message": "已确认" + }, + "notificationItemError": { + "message": "目前无法检索费用" + }, + "notificationItemFrom": { + "message": "从" + }, + "notificationItemLidoStakeReadyToBeWithdrawn": { + "message": "提取已就绪" + }, + "notificationItemLidoStakeReadyToBeWithdrawnMessage": { + "message": "您现在可以提取已解除质押的 $1" + }, + "notificationItemLidoWithdrawalRequestedMessage": { + "message": "您解除质押 $1 的请求已发送" + }, + "notificationItemNFTReceivedFrom": { + "message": "已从下列地址收到 NFT:" + }, + "notificationItemNFTSentTo": { + "message": "已发送 NFT 至" + }, + "notificationItemNetwork": { + "message": "网络" + }, + "notificationItemRate": { + "message": "价格(包括费用)" + }, + "notificationItemReceived": { + "message": "已收到" + }, + "notificationItemReceivedFrom": { + "message": "已从下列地址收到:" + }, + "notificationItemSent": { + "message": "已发送" + }, + "notificationItemSentTo": { + "message": "已发送至" + }, + "notificationItemStakeCompleted": { + "message": "质押已完成" + }, + "notificationItemStaked": { + "message": "已质押" + }, + "notificationItemStakingProvider": { + "message": "质押提供商" + }, + "notificationItemStatus": { + "message": "状态" + }, + "notificationItemSwapped": { + "message": "已兑换" + }, + "notificationItemSwappedFor": { + "message": "用于" + }, + "notificationItemTo": { + "message": "至" + }, + "notificationItemTransactionId": { + "message": "交易 ID" + }, + "notificationItemUnStakeCompleted": { + "message": "解除质押完成" + }, + "notificationItemUnStaked": { + "message": "已解除质押" + }, + "notificationItemUnStakingRequested": { + "message": "已请求解除质押" + }, "notificationTransactionFailedMessage": { "message": "交易 $1 失败!$2", "description": "Content of the browser notification that appears when a transaction fails" @@ -2494,52 +3101,15 @@ "description": "Content of the browser notification that appears when a transaction is confirmed" }, "notificationTransactionSuccessTitle": { - "message": "已确认交易", - "description": "Title of the browser notification that appears when a transaction is confirmed" - }, - "notificationTransactionSuccessView": { - "message": "在 $1 上查看", - "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" - }, - "notifications": { - "message": "通知" - }, - "notifications20ActionText": { - "message": "了解更多", - "description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a ledger page to resolve the U2F connection issue." - }, - "notifications20Description": { - "message": "如果您使用的是最新版本的 Firefox,您可能会遇到 Firefox 放弃 U2F(通用第二因素)支持的相关问题。", - "description": "Description of a notification in the 'See What's New' popup. Describes the U2F support being dropped by firefox and that it affects ledger users." - }, - "notifications20Title": { - "message": "Ledger 和 Firefox 用户遇到连接问题", - "description": "Title for a notification in the 'See What's New' popup. Tells users that latest firefox users using U2F may experience connection issues." - }, - "notifications24ActionText": { - "message": "知道了" - }, - "notifications24Description": { - "message": "现在,会根据您使用的网络记住高级燃料费设置。这意味着您可以为每个网络设置特定的高级燃料费,以避免多付燃料费或交易被卡住。" - }, - "notifications24Title": { - "message": "各网络的高级燃料费" - }, - "notifications8ActionText": { - "message": "转到“设置 > 高级”", - "description": "Description on an action button that appears in the What's New popup. Tells the user that if they click it, they will go to our Advanced settings page." - }, - "notifications8DescriptionOne": { - "message": "从 MetaMask v10.4.0 开始,您不再需要 Ledger Live 即可将您的 Ledger 设备连接到 MetaMask。", - "description": "Description of a notification in the 'See What's New' popup. Describes changes for how Ledger Live is no longer needed to connect the device." + "message": "已确认交易", + "description": "Title of the browser notification that appears when a transaction is confirmed" }, - "notifications8DescriptionTwo": { - "message": "为了更轻松和更稳定的 ledger 体验,请转到设置中的“高级”选项卡,将“首选 Ledger 连接类型”切换为“WebHID”。", - "description": "Description of a notification in the 'See What's New' popup. Describes how the user can turn off the Ledger Live setting." + "notificationTransactionSuccessView": { + "message": "在 $1 上查看", + "description": "Additional content in browser notification that appears when a transaction is confirmed and has a block explorer URL" }, - "notifications8Title": { - "message": "Ledger 连接改进", - "description": "Title for a notification in the 'See What's New' popup. Notifies ledger users that there is an improvement in how they can connect their device." + "notifications": { + "message": "通知" }, "notificationsDropLedgerFirefoxDescription": { "message": "Firefox 不再支持 U2F,因此在 Firefox 上,MetaMask 无法使用 Ledger。请尝试在 Google Chrome 上使用 MetaMask。", @@ -2549,33 +3119,37 @@ "message": "放弃在 Firefox 上支持 Ledger", "description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped." }, - "notificationsEmptyText": { - "message": "此处您可以从已安装的 snap 中查找通知。" - }, - "notificationsHeader": { - "message": "通知" + "notificationsFeatureToggle": { + "message": "启用钱包通知", + "description": "Experimental feature title" }, - "notificationsInfos": { - "message": "$1,来自$2", - "description": "$1 is the date at which the notification has been dispatched and $2 is the link to the snap that dispatched the notification." + "notificationsFeatureToggleDescription": { + "message": "这可以启用钱包通知,例如发送/接收资金或 NFT 和功能公告。", + "description": "Description of the experimental notifications feature" }, "notificationsMarkAllAsRead": { "message": "将所有标记为已读" }, - "notificationsOpenBetaSnapsActionText": { - "message": "了解详情" + "notificationsPageEmptyTitle": { + "message": "此处无内容" + }, + "notificationsPageErrorContent": { + "message": "请尝试再次访问此页面。" }, - "notificationsOpenBetaSnapsDescriptionOne": { - "message": "🎉 我们很高兴宣布推出 MetaMask Snaps 公开测试版!" + "notificationsPageErrorTitle": { + "message": "出错了" }, - "notificationsOpenBetaSnapsDescriptionThree": { - "message": "使用开发者社群构建的 snap,个性化您的钱包!" + "notificationsPageNoNotificationsContent": { + "message": "您尚未收到任何通知。" }, - "notificationsOpenBetaSnapsDescriptionTwo": { - "message": "Snaps 可以帮助您利用 MetaMask 做更多事情,例如连接到更多网络、查看交易见解,以及获取自定义通知。" + "notificationsSettingsBoxError": { + "message": "出错了。请重试。" }, - "notificationsOpenBetaSnapsTitle": { - "message": "介绍 MetaMask Snaps" + "notificationsSettingsPageAllowNotifications": { + "message": "通过通知随时了解您的钱包动态。为了使用通知,我们使用配置文件在您的不同设备上同步某些设置。$1" + }, + "notificationsSettingsPageAllowNotificationsLink": { + "message": "了解我们如何在使用此功能时保护您的隐私。" }, "numberOfNewTokensDetectedPlural": { "message": "在此账户中找到$1枚新代币", @@ -2599,6 +3173,9 @@ "on": { "message": "开" }, + "onboarding": { + "message": "入门" + }, "onboardingAdvancedPrivacyIPFSDescription": { "message": "IPFS 网关使访问和查看第三方托管的数据成为可能。您可以添加自定义 IPFS 网关或继续使用默认网关。" }, @@ -2629,51 +3206,45 @@ "onboardingMetametricsAgree": { "message": "我同意" }, - "onboardingMetametricsAllowOptOut": { - "message": "始终允许您通过设置选择退出" - }, - "onboardingMetametricsDataTerms": { - "message": "此数据是汇总数据,因而可以保持匿名,以遵守《通用数据保护条例》(欧盟)2016/679。" - }, "onboardingMetametricsDescription": { - "message": "MetaMask 希望收集使用数据,以更好地了解我们的用户如何与 MetaMask 交互。这些数据将用于提供服务,包括根据您的使用情况改进服务。" + "message": "我们希望收集基本的使用和诊断数据,以改进 MetaMask。请注意,我们绝不会出卖您在此处提供的数据。" }, "onboardingMetametricsDescription2": { - "message": "MetaMask 将会......" + "message": "当我们收集指标时,总是..." }, "onboardingMetametricsDisagree": { "message": "不,谢谢" }, "onboardingMetametricsInfuraTerms": { - "message": "* 如您在 MetaMask中 使用 Infura 作为默认的 RPC 提供商,Infura 将在您发送交易时收集您的 IP 地址和以太坊钱包地址。我们不会以允许系统将这两项数据关联起来的方式存储这些信息。如需从数据收集角度进一步了解 MetaMask 和 Infura 如何进行交互,请参阅我们的更新版 $1。如需进一步了解我们的一般隐私准则,请参阅我们的 $2。", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" + "message": "如果我们决定将这些数据用于其他目的,我们会通知您。您可以查看我们的 $1 以了解更多信息。请记住,您可以随时转到设置并选择退出。", + "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, "onboardingMetametricsInfuraTermsPolicy": { - "message": "隐私政策在此处" - }, - "onboardingMetametricsInfuraTermsPolicyLink": { - "message": "此处" + "message": "隐私政策" }, "onboardingMetametricsModalTitle": { "message": "添加自定义网络" }, "onboardingMetametricsNeverCollect": { - "message": "$1 收集我们不需要提供服务的信息(如私钥、地址、交易散列或余额)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 会存储点击量和应用程序的浏览量,但不会存储其他详情(如您的公钥)。", + "description": "$1 represents `onboardingMetametricsNeverCollectEmphasis`" + }, + "onboardingMetametricsNeverCollectEmphasis": { + "message": "私密:" }, "onboardingMetametricsNeverCollectIP": { - "message": "$1收集您的完整 IP 地址*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 我们暂时使用您的 IP 地址来检测一般位置(如您的国家或地区),但从来不会进行存储。", + "description": "$1 represents `onboardingMetametricsNeverCollectIPEmphasis`" }, - "onboardingMetametricsNeverEmphasis": { - "message": "永远不会发生" + "onboardingMetametricsNeverCollectIPEmphasis": { + "message": "通用:" }, "onboardingMetametricsNeverSellData": { - "message": "$1 出售数据。永远不会!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" + "message": "$1 您可以随时决定是否通过设置共享或删除您的使用数据。", + "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" }, - "onboardingMetametricsSendAnonymize": { - "message": "发送匿名的点击和页面浏览事件" + "onboardingMetametricsNeverSellDataEmphasis": { + "message": "可选:" }, "onboardingMetametricsTitle": { "message": "请帮助我们改进 MetaMask" @@ -2714,15 +3285,26 @@ "onboardingPinExtensionTitle": { "message": "您的 MetaMask 安装完成!" }, + "onboardingPinMmiExtensionLabel": { + "message": "将MetaMask Institutional置顶" + }, "onboardingUsePhishingDetectionDescription": { "message": "网络钓鱼检测提醒依赖于与 $1 的通信。jsDeliver 将有权访问您的 IP 地址。查看 $2。", "description": "The $1 is the word 'jsDeliver', from key 'jsDeliver' and $2 is the words Privacy Policy from key 'privacyMsg', both separated here so that it can be wrapped as a link" }, + "onekey": { + "message": "OneKey" + }, "onlyAddTrustedNetworks": { "message": "恶意网络提供商可能会谎报区块链的状态并记录您的网络活动。只添加您信任的自定义网络。" }, "onlyConnectTrust": { - "message": "只连接您信任的网站。" + "message": "仅连接您信任的网站。$1", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." + }, + "openCustodianApp": { + "message": "打开$1应用程序", + "description": "The $1 is the name of the Custodian that will be open" }, "openFullScreenForLedgerWebHid": { "message": "全屏打开以连接您的 Ledger。", @@ -2734,6 +3316,15 @@ "openSeaNew": { "message": "OpenSea" }, + "openSeaToBlockaidBtnLabel": { + "message": "探索 Snap" + }, + "openSeaToBlockaidDescription": { + "message": "此网络不再提供安全提醒。安装 Snap 可能提高安全性。" + }, + "openSeaToBlockaidTitle": { + "message": "注意!" + }, "operationFailed": { "message": "操作失败" }, @@ -2777,6 +3368,9 @@ "password": { "message": "密码" }, + "passwordMmiTermsWarning": { + "message": "我明白MetaMask Institutional无法为我恢复此密码。$1" + }, "passwordNotLongEnough": { "message": "密码长度不足" }, @@ -2803,6 +3397,10 @@ "message": "请粘贴您的私钥:", "description": "For importing an account from a private key" }, + "paymasterInUse": { + "message": "这笔交易的燃料费将由代付者支付。", + "description": "Alert shown in transaction confirmation if paymaster in use." + }, "pending": { "message": "待处理" }, @@ -2816,18 +3414,26 @@ "message": "您有 (1) 笔待处理的交易。", "description": "$1 is count of pending transactions" }, - "permissionRequest": { - "message": "权限请求" + "permissionDetails": { + "message": "许可详情" }, - "permissionRequestCapitalized": { + "permissionRequest": { "message": "权限请求" }, "permissionRequested": { "message": "立即请求" }, + "permissionRequestedForAccounts": { + "message": "现在为 $1 请求", + "description": "Permission cell status for requested permission including accounts, rendered as AvatarGroup which is $1." + }, "permissionRevoked": { "message": "在此更新中已撤销" }, + "permissionRevokedForAccounts": { + "message": "此更新中已为 $1 撤销", + "description": "Permission cell status for revoked permission including accounts, rendered as AvatarGroup which is $1." + }, "permission_accessNamedSnap": { "message": "连接至$1。", "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." @@ -2836,6 +3442,10 @@ "message": "访问互联网。", "description": "The description of the `endowment:network-access` permission." }, + "permission_accessNetworkDescription": { + "message": "允许 $1 访问互联网。这可用于通过第三方服务器发送和接收数据。", + "description": "An extended description of the `endowment:network-access` permission. $1 is the snap name." + }, "permission_accessSnap": { "message": "连接到$1 Snap。", "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." @@ -2848,10 +3458,18 @@ "message": "规划并执行定期操作。", "description": "The description for the `snap_cronjob` permission" }, + "permission_cronjobDescription": { + "message": "允许 $1 执行按固定时间、日期或间隔定期运行的操作。这可用于触发对时间敏感的交互或通知。", + "description": "An extended description for the `snap_cronjob` permission. $1 is the snap name." + }, "permission_dialog": { "message": "在 MetaMask 中显示对话框窗口。", "description": "The description for the `snap_dialog` permission" }, + "permission_dialogDescription": { + "message": "允许 $1 显示带有以下内容的 MetaMask 弹出窗口:自定义文本、输入字段以及用于批准或拒绝操作的按钮。\n这适用于创建 snap 的提醒、确认和流程加入选项等。", + "description": "An extended description for the `snap_dialog` permission. $1 is the snap name." + }, "permission_ethereumAccounts": { "message": "查看您允许的账户的地址(必填)", "description": "The description for the `eth_accounts` permission" @@ -2860,30 +3478,138 @@ "message": "访问以太坊提供商。", "description": "The description for the `endowment:ethereum-provider` permission" }, + "permission_ethereumProviderDescription": { + "message": "允许 $1 直接与 MetaMask 通信,使其可以从区块链中读取数据,并提供消息和交易建议。", + "description": "An extended description for the `endowment:ethereum-provider` permission. $1 is the snap name." + }, + "permission_getEntropy": { + "message": "派生 $1 独有的任意私钥。", + "description": "The description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getEntropyDescription": { + "message": "允许 $1 派生 $1 独有的任意私钥,但不公开私钥。这些私钥与您的 MetaMask 账户是分开的,与您的私钥或私钥助记词无关。其他 snap 无法访问此信息。", + "description": "An extended description for the `snap_getEntropy` permission. $1 is the snap name." + }, + "permission_getLocale": { + "message": "查看您的首选语言。", + "description": "The description for the `snap_getLocale` permission" + }, + "permission_getLocaleDescription": { + "message": "允许 $1 访问您的 MetaMask 首选语言设置。这可用于进行本地化,以及使用您的语言显示$1的内容。", + "description": "An extended description for the `snap_getLocale` permission. $1 is the snap name." + }, + "permission_homePage": { + "message": "显示自定义屏幕", + "description": "The description for the `endowment:page-home` permission" + }, + "permission_homePageDescription": { + "message": "让 $1 在 MetaMask 中显示自定义主屏幕。这可以用于用户界面、配置和控制面板。", + "description": "An extended description for the `endowment:page-home` permission. $1 is the snap name." + }, + "permission_keyring": { + "message": "允许添加和控制以太坊账户的请求", + "description": "The description for the `endowment:keyring` permission" + }, + "permission_keyringDescription": { + "message": "允许 $1 接收添加或删除账户的请求,并代表这些账户进行签名和交易。", + "description": "An extended description for the `endowment:keyring` permission. $1 is the snap name." + }, "permission_lifecycleHooks": { "message": "使用生命周期挂钩。", "description": "The description for the `endowment:lifecycle-hooks` permission" }, + "permission_lifecycleHooksDescription": { + "message": "允许 $1 使用生命周期挂钩,在其生命周期的特定时间运行代码。", + "description": "An extended description for the `endowment:lifecycle-hooks` permission. $1 is the snap name." + }, "permission_manageAccounts": { "message": "添加并控制以太坊账户", "description": "The description for `snap_manageAccounts` permission" }, + "permission_manageAccountsDescription": { + "message": "允许 $1 添加或删除以太坊账户,然后使用添加的账户来进行交易和签名。", + "description": "An extended description for the `snap_manageAccounts` permission. $1 is the snap name." + }, + "permission_manageBip32Keys": { + "message": "管理 $1 账户。", + "description": "The description for the `snap_getBip32Entropy` permission. $1 is a derivation path, e.g. 'm/44'/0'/0' (secp256k1)'." + }, + "permission_manageBip44AndBip32KeysDescription": { + "message": "允许 $1 在所请求的网络上管理账户和资产。这些账户使用您的私钥助记词(不会披露)进行派生和备份。$1 具有派生私钥的能力,因此可以支持以太坊(EVM)以外的多种区块链协议。", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions. $1 is the snap name." + }, + "permission_manageBip44Keys": { + "message": "管理 $1 账户。", + "description": "The description for the `snap_getBip44Entropy` permission. $1 is the name of a protocol, e.g. 'Filecoin'." + }, "permission_manageState": { "message": "在您的设备上存储和管理其数据。", "description": "The description for the `snap_manageState` permission" }, + "permission_manageStateDescription": { + "message": "允许 $1 通过加密安全地存储、更新和检索数据。其他 snap 无法访问此信息。", + "description": "An extended description for the `snap_manageState` permission. $1 is the snap name." + }, + "permission_nameLookup": { + "message": "提供域和地址查找。", + "description": "The description for the `endowment:name-lookup` permission." + }, + "permission_nameLookupDescription": { + "message": "允许 Snap 在 MetaMask UI 的不同部分中获取和显示地址并进行域查找。", + "description": "An extended description for the `endowment:name-lookup` permission." + }, "permission_notifications": { "message": "显示通知。", "description": "The description for the `snap_notify` permission" }, + "permission_notificationsDescription": { + "message": "允许 $1 在 MetaMask 中显示通知。snap 可以触发简短的通知文本,以提供可操作或对时间敏感的信息。", + "description": "An extended description for the `snap_notify` permission. $1 is the snap name." + }, + "permission_rpc": { + "message": "允许 $1 直接与 $2 通信。", + "description": "The description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescription": { + "message": "允许 $1 向 $2 发送消息,以及接收来自$2的响应。", + "description": "An extended description for the `endowment:rpc` permission. $1 is 'other snaps' or 'websites', $2 is the snap name." + }, + "permission_rpcDescriptionOriginList": { + "message": "$1 和 $2", + "description": "A list of allowed origins where $2 is the last origin of the list and $1 is the rest of the list separated by ','." + }, + "permission_signatureInsight": { + "message": "显示签名见解模式。", + "description": "The description for the `endowment:signature-insight` permission" + }, + "permission_signatureInsightDescription": { + "message": "在批准之前,允许 $1 显示一个模式,其中包含对任何签名请求的见解。这可用于反网络钓鱼和采取安全措施。", + "description": "An extended description for the `endowment:signature-insight` permission. $1 is the snap name." + }, + "permission_signatureInsightOrigin": { + "message": "查看发起签名请求的网站来源", + "description": "The description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission" + }, + "permission_signatureInsightOriginDescription": { + "message": "允许 $1 查看发起签名请求的网站来源(URI)。这可用于防止网络钓鱼和采取安全措施。", + "description": "An extended description for the `signatureOrigin` caveat, to be used with the `endowment:signature-insight` permission. $1 is the snap name." + }, "permission_transactionInsight": { "message": "获取并显示交易洞察。", "description": "The description for the `endowment:transaction-insight` permission" }, + "permission_transactionInsightDescription": { + "message": "允许 $1 在 MetaMask UI 中对交易进行解码,并显示见解。这可用于防止网络钓鱼和采取安全措施。", + "description": "An extended description for the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_transactionInsightOrigin": { "message": "查看建议交易的网站来源", "description": "The description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission" }, + "permission_transactionInsightOriginDescription": { + "message": "允许 $1 查看建议交易的网站的来源(URI)。这可用于防止网络钓鱼和采取安全措施。", + "description": "An extended description for the `transactionOrigin` caveat, to be used with the `endowment:transaction-insight` permission. $1 is the snap name." + }, "permission_unknown": { "message": "未知权限:$1", "description": "$1 is the name of a requested permission that is not recognized." @@ -2892,29 +3618,66 @@ "message": "查看您的$1 ($2)公钥。", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a derivation path, e.g. 'm/44'/0'/0''. $2 is the elliptic curve name, e.g. 'secp256k1'." }, + "permission_viewBip32PublicKeysDescription": { + "message": "允许 $2 查看您的 $1 公钥(和地址)。这并不会授予对账户或资产的任何控制权。", + "description": "An extended description for the `snap_getBip32PublicKey` permission. $1 is a derivation path (name). $2 is the snap name." + }, "permission_viewNamedBip32PublicKeys": { "message": "查看您的$1公钥。", "description": "The description for the `snap_getBip32PublicKey` permission. $1 is a name for the derivation path, e.g., 'Ethereum accounts'." }, + "permission_walletSwitchEthereumChain": { + "message": "切换并使用以下网络", + "description": "The label for the `wallet_switchEthereumChain` permission" + }, "permission_webAssembly": { "message": "支持WebAssembly。", "description": "The description of the `endowment:webassembly` permission." }, + "permission_webAssemblyDescription": { + "message": "允许 $1 通过 WebAssembly 访问低级执行环境。", + "description": "An extended description of the `endowment:webassembly` permission. $1 is the snap name." + }, "permissions": { "message": "权限" }, - "permissionsTitle": { - "message": "权限" + "permissionsPageEmptyContent": { + "message": "此处无内容" }, - "permissionsTourDescription": { - "message": "在此处查看您的已连接账户并管理权限" + "permissionsPageEmptySubContent": { + "message": "您可以在此处查看您授予已安装 Snap 或已连接站点的许可。" + }, + "permissionsPageTourDescription": { + "message": "这是您的控制面板,用于管理授予已连接站点和已安装 Snap 的许可。" + }, + "permissionsPageTourTitle": { + "message": "已连接的站点现已获得许可" }, "personalAddressDetected": { "message": "检测到个人地址。请输入代币合约地址。" }, + "petnamesEnabledToggle": { + "message": "允许昵称" + }, + "petnamesEnabledToggleDescription": { + "message": "这样可以协助您为任何地址添加昵称。我们将在可能的情况下为您与之交互的地址提供名称建议。" + }, + "pinExtensionDescription": { + "message": "前往扩展程序菜单,将MetaMask Institutional置顶,以实现无缝访问。" + }, + "pinExtensionTitle": { + "message": "将扩展程序置顶" + }, + "pinToTop": { + "message": "置顶" + }, "pleaseConfirm": { "message": "请确认" }, + "plusMore": { + "message": "另外 $1 项", + "description": "$1 is the number of additional items" + }, "plusXMore": { "message": "另外 $1 项", "description": "$1 is a number of additional but unshown items in a list- this message will be shown in place of those items" @@ -2940,6 +3703,9 @@ "primaryCurrencySettingDescription": { "message": "选择原生以优先显示链的原生货币(例如 ETH)的值。选择法币以优先显示以您所选法币显示的值。" }, + "primaryType": { + "message": "主要类型" + }, "priorityFee": { "message": "优先费用" }, @@ -2960,6 +3726,18 @@ "message": "$1 的私钥", "description": "$1 represents the account name" }, + "privateKeyHidden": { + "message": "私钥已隐藏", + "description": "Explains that the private key input is hidden" + }, + "privateKeyShow": { + "message": "显示/隐藏私钥输入", + "description": "Describes a toggle that is used to show or hide the private key input" + }, + "privateKeyShown": { + "message": "正在显示此私钥", + "description": "Explains that the private key input is being shown" + }, "privateKeyWarning": { "message": "警告:切勿泄露此私钥。任何拥有您私钥的人都可以窃取您账户中持有的任何资产。" }, @@ -2969,6 +3747,21 @@ "proceedWithTransaction": { "message": "我仍然想继续" }, + "productAnnouncements": { + "message": "产品公告" + }, + "profileSync": { + "message": "配置文件同步" + }, + "profileSyncConfirmation": { + "message": "如果您关闭配置文件同步,您将无法收到通知。" + }, + "profileSyncDescription": { + "message": "创建配置文件,MetaMask 用以在您的不同设备之间同步某些设置。这是获取通知的必需条件。$1。" + }, + "profileSyncPrivacyLink": { + "message": "了解我们如何保护您的隐私" + }, "proposedApprovalLimit": { "message": "拟议的审批上限" }, @@ -2978,6 +3771,78 @@ "publicAddress": { "message": "公钥" }, + "pushPlatformNotificationsFundsReceivedDescription": { + "message": "您收到了 $1 $2" + }, + "pushPlatformNotificationsFundsReceivedDescriptionDefault": { + "message": "您收到了一些代币" + }, + "pushPlatformNotificationsFundsReceivedTitle": { + "message": "已收到资金" + }, + "pushPlatformNotificationsFundsSentDescription": { + "message": "您已成功发送 $1 $2" + }, + "pushPlatformNotificationsFundsSentDescriptionDefault": { + "message": "您已成功发送了一些代币" + }, + "pushPlatformNotificationsFundsSentTitle": { + "message": "资金已发送" + }, + "pushPlatformNotificationsNftReceivedDescription": { + "message": "您收到了新的 NFT" + }, + "pushPlatformNotificationsNftReceivedTitle": { + "message": "已收到 NFT" + }, + "pushPlatformNotificationsNftSentDescription": { + "message": "您已成功发送一个 NFT" + }, + "pushPlatformNotificationsNftSentTitle": { + "message": "NFT 已发送" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedDescription": { + "message": "您的 Lido 质押已成功" + }, + "pushPlatformNotificationsStakingLidoStakeCompletedTitle": { + "message": "质押完成" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnDescription": { + "message": "您的 Lido 质押现已可以提取" + }, + "pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnTitle": { + "message": "质押已可提取" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedDescription": { + "message": "您的 Lido 提取成功" + }, + "pushPlatformNotificationsStakingLidoWithdrawalCompletedTitle": { + "message": "提取已完成" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedDescription": { + "message": "您的 Lido 提取请求已提交" + }, + "pushPlatformNotificationsStakingLidoWithdrawalRequestedTitle": { + "message": "已请求提取" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedDescription": { + "message": "您的 RocketPool 质押已成功" + }, + "pushPlatformNotificationsStakingRocketpoolStakeCompletedTitle": { + "message": "质押完成" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedDescription": { + "message": "您的 RocketPool 解除质押已成功" + }, + "pushPlatformNotificationsStakingRocketpoolUnstakeCompletedTitle": { + "message": "解除质押完成" + }, + "pushPlatformNotificationsSwapCompletedDescription": { + "message": "您的 MetaMask 兑换已成功" + }, + "pushPlatformNotificationsSwapCompletedTitle": { + "message": "兑换已完成" + }, "queued": { "message": "队列中" }, @@ -2996,9 +3861,15 @@ "receive": { "message": "收款" }, + "receiveTokensCamelCase": { + "message": "收取代币" + }, "recipientAddressPlaceholder": { "message": "输入公钥 (0x) 或 ENS 名称" }, + "recipientAddressPlaceholderFlask": { + "message": "输入公钥 (0x) 或域名" + }, "recommendedGasLabel": { "message": "建议" }, @@ -3026,6 +3897,12 @@ "recoveryPhraseReminderTitle": { "message": "保护您的资金" }, + "redesignedConfirmationsEnabledToggle": { + "message": "批准的签名请求" + }, + "redesignedConfirmationsToggleDescription": { + "message": "开启此选项以查看增强格式的签名请求。" + }, "refreshList": { "message": "刷新列表" }, @@ -3068,14 +3945,29 @@ "removeJWTDescription": { "message": "您确定要删除此代币吗?分配给此代币的所有账户也将从扩展中删除: " }, + "removeKeyringSnap": { + "message": "去除此Snap,会同时将以下账户从MetaMask中去除:" + }, + "removeKeyringSnapToolTip": { + "message": "Snap控制这些账户,去除此Snap,会同时将这些账户从MetaMask中去除,但账户将保留在区块链中。" + }, "removeNFT": { "message": "删除 NFT" }, + "removeNftErrorMessage": { + "message": "我们无法去除此 NFT。" + }, "removeNftMessage": { "message": "NFT已成功移除!" }, "removeSnap": { - "message": "移除Snap" + "message": "移除 Snap" + }, + "removeSnapAccountDescription": { + "message": "如果您继续,此账户将不可在 MetaMask 中使用。" + }, + "removeSnapAccountTitle": { + "message": "去除账户" }, "removeSnapConfirmation": { "message": "您确定要移除$1吗?", @@ -3087,12 +3979,24 @@ "replace": { "message": "替换" }, + "reportIssue": { + "message": "报告问题" + }, "requestFlaggedAsMaliciousFallbackCopyReason": { "message": "安全提供商没有分享其他详情" }, "requestFlaggedAsMaliciousFallbackCopyReasonTitle": { "message": "请求被标记为恶意" }, + "requestFrom": { + "message": "请求来自" + }, + "requestFromInfo": { + "message": "这是要求您签名的站点。" + }, + "requestFromTransactionDescription": { + "message": "这是要求您确认的网站。" + }, "requestMayNotBeSafe": { "message": "请求可能不安全" }, @@ -3114,6 +4018,9 @@ "reset": { "message": "重置" }, + "resetStates": { + "message": "重设状态" + }, "resetWallet": { "message": "重置钱包" }, @@ -3142,7 +4049,7 @@ "message": "恢复用户数据" }, "restoreUserDataDescription": { - "message": "您可以使用以前备份的 JSON 文件来恢复包含首选项和账户地址的用户设置。" + "message": "您可以从备份文件中恢复联系人和首选项等数据。" }, "resultPageError": { "message": "错误" @@ -3196,9 +4103,15 @@ "message": "MetaMask 支持团队绝对不会要求提供此项信息。", "description": "The bolded texted in the second part of 'revealSeedWordsWarning'" }, + "revealSensitiveContent": { + "message": "显示敏感内容" + }, "revealTheSeedPhrase": { "message": "显示助记词" }, + "reviewAlerts": { + "message": "查看提醒" + }, "revokeAllTokensTitle": { "message": "撤销访问和转移您的所有 $1 的权限?", "description": "$1 is the symbol of the token for which the user is revoking approval" @@ -3249,6 +4162,9 @@ "searchAccounts": { "message": "搜索账户" }, + "searchTokens": { + "message": "搜索代币" + }, "secretRecoveryPhrase": { "message": "私钥助记词" }, @@ -3265,7 +4181,8 @@ "message": "安全提醒" }, "securityAlertsDescription": { - "message": "此功能会主动审查交易和签名请求,如发现以太坊主网上有恶意活动,就会向您发出警报,与此同时也会保护您的隐私。您的数据不会与提供此服务的第三方共享。在批准任何请求之前,均务必自行作出审慎调查。不保证此功能可检测到所有恶意活动。" + "message": "此功能通过主动审查交易和签名请求向您发出恶意活动提醒。$1", + "description": "Link to learn more about security alerts" }, "securityAndPrivacy": { "message": "安全和隐私" @@ -3355,6 +4272,9 @@ "selectAnAccountHelp": { "message": "选择要在 MetaMask Institutional 使用的托管账户。" }, + "selectEnableDisplayMediaPrivacyPreference": { + "message": "打开\"显示 NFT 媒体\"" + }, "selectHdPath": { "message": "选择 HD 路径" }, @@ -3376,18 +4296,41 @@ "send": { "message": "发送" }, + "sendAToken": { + "message": "发送代币" + }, "sendBugReport": { "message": "向我们发送错误报告。" }, + "sendNoContactsConversionText": { + "message": "点击此处" + }, + "sendNoContactsDescription": { + "message": "联系人允许您多次将交易安全地发送到另一个账户。要创建联系人,$1", + "description": "$1 represents the action text 'click here'" + }, + "sendNoContactsTitle": { + "message": "您还没有任何联系人" + }, + "sendSelectReceiveAsset": { + "message": "选择要接收的资产" + }, + "sendSelectSendAsset": { + "message": "选择要发送的资产" + }, "sendSpecifiedTokens": { "message": "发送 $1", "description": "Symbol of the specified token" }, - "sendTo": { - "message": "发送到" + "sendSwapSubmissionWarning": { + "message": "点击此按钮将立即启动您的兑换交易。在继续操作之前,请查看您的交易详情。" }, - "sendTokens": { - "message": "发送代币" + "sendTokenAsToken": { + "message": "将 $1 作为 $2 发送", + "description": "Used in the transaction display list to describe a swap and send. $1 and $2 are the symbols of tokens in involved in the swap." + }, + "sendingAsset": { + "message": "正在发送 $1" }, "sendingDisabled": { "message": "尚不支持发送ERC-1155 NFT资产。" @@ -3400,9 +4343,15 @@ "message": "警告:您将要发送到代币合约,这可能会导致资金损失。$1", "description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning" }, + "sendingZeroAmount": { + "message": "您发送的是0 $1。" + }, "sepolia": { "message": "Sepolia测试网络" }, + "serviceWorkerKeepAlive": { + "message": "Service Worker 保持活跃" + }, "setAdvancedPrivacySettingsDetails": { "message": "MetaMask 使用这些可信的第三方服务来提高产品可用性和安全性。" }, @@ -3414,7 +4363,7 @@ "description": "The token symbol that is being approved" }, "settingAddSnapAccount": { - "message": "添加snap账户" + "message": "添加账户 Snap" }, "settings": { "message": "设置" @@ -3422,9 +4371,21 @@ "settingsSearchMatchingNotFound": { "message": "没有找到匹配的结果." }, + "settingsSubHeadingSignaturesAndTransactions": { + "message": "签名和交易请求" + }, "show": { "message": "显示" }, + "showAccount": { + "message": "显示账户" + }, + "showExtensionInFullSizeView": { + "message": "以全尺寸视图显示扩展程序" + }, + "showExtensionInFullSizeViewDescription": { + "message": "开启此选项,以便当您点击扩展程序图标时默认为全尺寸视图。" + }, "showFiatConversionInTestnets": { "message": "在测试网络上显示转换" }, @@ -3444,6 +4405,9 @@ "message": "这取决于$1,即可以访问您的以太坊地址和 IP 地址的网络。$2", "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" }, + "showIncomingTransactionsExplainer": { + "message": "这依赖于每个网络的不同第三方 API,这些 API 会导致您的以太坊地址和 IP 地址被获悉。" + }, "showMore": { "message": "展开" }, @@ -3483,9 +4447,46 @@ "signin": { "message": "登录" }, + "signing": { + "message": "签名" + }, + "simulationDetailsFailed": { + "message": "加载估算时出错。" + }, + "simulationDetailsFiatNotAvailable": { + "message": "不可用" + }, + "simulationDetailsIncomingHeading": { + "message": "您收到" + }, + "simulationDetailsNoBalanceChanges": { + "message": "预计您的钱包不会发生变化" + }, + "simulationDetailsOutgoingHeading": { + "message": "您发送" + }, + "simulationDetailsTitle": { + "message": "预计变化" + }, + "simulationDetailsTitleTooltip": { + "message": "预计变化是指您完成该交易可能发生的变化。这只是一个预测,而不是保证。" + }, + "simulationDetailsTotalFiat": { + "message": "总计 = $1", + "description": "$1 is the total amount in fiat currency on one side of the transaction" + }, + "simulationDetailsTransactionReverted": { + "message": "这笔交易可能会失败" + }, "simulationErrorMessageV2": { "message": "我们无法估算燃料。合约中可能存在错误,这笔交易可能会失败。" }, + "simulationsSettingDescription": { + "message": "开启此选项,以便在确认交易之前估计交易余额的变化。这并不能保证交易的最终结果。$1" + }, + "simulationsSettingSubHeader": { + "message": "预计余额变化" + }, "skip": { "message": "跳过" }, @@ -3498,20 +4499,99 @@ "smartContracts": { "message": "智能合约" }, - "smartSwapsAreHere": { - "message": "智能兑换已推出!" - }, - "smartSwapsDescription": { - "message": "MetaMask Swaps 变得更加智能!启用智能兑换使得 MetaMask 在编程方面让您的兑换体验更加优化,有助于:" - }, "smartSwapsErrorNotEnoughFunds": { "message": "没有足够的资金进行智能兑换。" }, "smartSwapsErrorUnavailable": { "message": "智能兑换暂时不可用。" }, + "smartTransactionCancelled": { + "message": "您的交易已取消" + }, + "smartTransactionCancelledDescription": { + "message": "您的交易无法完成,因此已取消,以避免您支付不必要的燃料费。" + }, + "smartTransactionError": { + "message": "您的交易失败" + }, + "smartTransactionErrorDescription": { + "message": "市场的突然变化可导致失败。如果问题仍然存在,请联系 MetaMask 客户支持团队。" + }, + "smartTransactionPending": { + "message": "正在提交您的交易" + }, + "smartTransactionSuccess": { + "message": "您的交易已完成" + }, + "smartTransactionTakingTooLong": { + "message": "抱歉让您久等" + }, + "smartTransactionTakingTooLongDescription": { + "message": "如果您的交易在 $1 内未完成,则会取消,您无需支付燃料费。", + "description": "$1 is remaining time in seconds" + }, + "smartTransactions": { + "message": "智能交易" + }, + "smartTransactionsBenefit1": { + "message": "99.5%的成功率" + }, + "smartTransactionsBenefit2": { + "message": "为您省钱" + }, + "smartTransactionsBenefit3": { + "message": "实时更新" + }, + "smartTransactionsDescription": { + "message": "通过智能交易解锁更高的成功率、抢先交易保护和更高的透明度。" + }, + "smartTransactionsDescription2": { + "message": "仅适用于以太坊。可随时在设置中启用或禁用。$1", + "description": "$1 is an external link to learn more about Smart Transactions" + }, + "smartTransactionsOptItModalTitle": { + "message": "增强型交易保护" + }, + "snapAccountCreated": { + "message": "账户已创建" + }, + "snapAccountCreatedDescription": { + "message": "您的新账户已经可以使用了!" + }, + "snapAccountCreationFailed": { + "message": "账户创建失败" + }, + "snapAccountCreationFailedDescription": { + "message": "$1 未能为您创建账户。", + "description": "$1 is the snap name" + }, + "snapAccountRedirectFinishSigningTitle": { + "message": "完成签名" + }, + "snapAccountRedirectSiteDescription": { + "message": "按照$1的说明操作" + }, + "snapAccountRemovalFailed": { + "message": "去除账户失败" + }, + "snapAccountRemovalFailedDescription": { + "message": "$1 未能为您去除此账户。", + "description": "$1 is the snap name" + }, + "snapAccountRemoved": { + "message": "账户已去除" + }, + "snapAccountRemovedDescription": { + "message": "此账户将在 MetaMask 中不再可用。" + }, + "snapAccounts": { + "message": "账户Snap" + }, + "snapAccountsDescription": { + "message": "由第三方 Snap 控制的账户。" + }, "snapConnectionWarning": { - "message": "$1想连接$2。只有在您信任此网站的情况下才能继续。", + "message": "$1想连接$2。", "description": "$2 is the snap and $1 is the dapp requesting connection to the snap." }, "snapContent": { @@ -3522,15 +4602,35 @@ "message": "网站" }, "snapInstallRequest": { - "message": "安装$1,将向其授予以下权限。只有在您信任$1的情况下才能继续。", + "message": "安装 $1 即赋予其以下许可。", "description": "$1 is the snap name." }, "snapInstallSuccess": { "message": "安装完成" }, + "snapInstallWarningCheck": { + "message": "$1 需要以下权限:", + "description": "Warning message used in popup displayed on snap install. $1 is the snap name." + }, "snapInstallWarningHeading": { "message": "请谨慎行事" }, + "snapInstallWarningPermissionDescriptionForBip32View": { + "message": "允许 $1 查看您的公钥(和地址)。这并不会授予对账户或资产的任何控制权。", + "description": "An extended description for the `snap_getBip32PublicKey` permission used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionDescriptionForEntropy": { + "message": "允许 $1 Snap 在所请求的网络上管理账户和资产。这些账户使用您的私钥助记词(不会披露)进行派生和备份。$1 具有派生私钥的能力,因此可以支持以太坊(EVM)以外的多种区块链协议。", + "description": "An extended description for the `snap_getBip44Entropy` and `snap_getBip44Entropy` permissions used for tooltip on Snap Install Warning screen (popup/modal). $1 is the snap name." + }, + "snapInstallWarningPermissionNameForEntropy": { + "message": "管理 $1 账户", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, + "snapInstallWarningPermissionNameForViewPublicKey": { + "message": "查看您的 $1 公钥", + "description": "Permission name used for the Permission Cell component displayed on warning popup when installing a Snap. $1 is list of account types." + }, "snapInstallationErrorDescription": { "message": "无法安装$1。", "description": "Error description used when snap installation fails. $1 is the snap name." @@ -3548,6 +4648,10 @@ "snapResultSuccessDescription": { "message": "$1已可以使用" }, + "snapUpdateAlertDescription": { + "message": "获取 $1 的最新版本", + "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." + }, "snapUpdateAvailable": { "message": "有更新" }, @@ -3559,22 +4663,40 @@ "message": "更新失败", "description": "Error title used when snap update fails." }, + "snapUpdateRequest": { + "message": "更新 $1 即赋予其以下许可。", + "description": "$1 is the Snap name." + }, "snapUpdateSuccess": { "message": "更新完成" }, + "snapUrlIsBlocked": { + "message": "此Snap想将您带到一个被封锁的网站。$1" + }, "snaps": { "message": "Snaps" }, - "snapsInvalidUIError": { - "message": "Snap 指定的用户界面无效。" + "snapsConnected": { + "message": "Snap 已连接" }, "snapsNoInsight": { "message": "Snap 没有返回任何洞察" }, + "snapsPrivacyWarningFirstMessage": { + "message": "您确认,除非另有说明,否则您安装的任何 Snap 均是第三方服务(如 Consensys $1 中所定义)。您对第三方服务的使用,受第三方服务提供商规定的单独条款与条件约束。Consensys 不建议任何特定人员出于任何特定原因使用任何 Snap。您访问、依赖或使用第三方服务的风险由您自行承担。对于您因使用第三方服务而造成的任何损失,Consensys 概不承担任何责任。", + "description": "First part of a message in popup modal displayed when installing a snap for the first time. $1 is terms of use link." + }, "snapsPrivacyWarningSecondMessage": { "message": "您与第三方服务分享的任何信息,将由这些第三方服务根据其隐私政策直接收集。请参阅其隐私政策以了解更多信息。", "description": "Second part of a message in popup modal displayed when installing a snap for the first time." }, + "snapsPrivacyWarningThirdMessage": { + "message": "Consensys 无权访问您与第三方服务共享的信息。", + "description": "Third part of a message in popup modal displayed when installing a snap for the first time." + }, + "snapsSettings": { + "message": "Snap 设置" + }, "snapsTermsOfUse": { "message": "使用条款" }, @@ -3588,12 +4710,19 @@ "someNetworksMayPoseSecurity": { "message": "某些网络可能会带来安全和/或隐私风险。在添加和使用网络之前,请先了解风险。" }, + "somethingDoesntLookRight": { + "message": "有什么不对劲吗?$1", + "description": "A false positive message for users to contact support. $1 is a link to the support page." + }, "somethingIsWrong": { "message": "出错了。尝试重新加载页面。" }, "somethingWentWrong": { "message": "哎呀!出了点问题。" }, + "source": { + "message": "来源" + }, "speedUp": { "message": "加速" }, @@ -3728,6 +4857,14 @@ "stake": { "message": "质押" }, + "startYourJourney": { + "message": "从 $1 开始您的旅程", + "description": "$1 is the token symbol" + }, + "startYourJourneyDescription": { + "message": "将一些 $1 添加到您的钱包并开始使用 Web3", + "description": "$1 is the token symbol" + }, "stateLogError": { "message": "检索状态日志时出错。" }, @@ -3740,6 +4877,9 @@ "stateLogsDescription": { "message": "状态日志包含您的公共账户地址和已发送的交易。" }, + "states": { + "message": "状态" + }, "status": { "message": "状态" }, @@ -3783,18 +4923,6 @@ "strong": { "message": "强" }, - "stxBenefit1": { - "message": "将交易成本减至最低" - }, - "stxBenefit2": { - "message": "减少交易失败" - }, - "stxBenefit3": { - "message": "消除卡住的交易" - }, - "stxBenefit4": { - "message": "防止抢先交易" - }, "stxCancelled": { "message": "交换就会失败" }, @@ -3804,6 +4932,10 @@ "stxCancelledSubDescription": { "message": "再次尝试进行交换。下次我们会在这里保护您免受类似风险。 " }, + "stxEstimatedCompletion": { + "message": "预计将在 $1 内完成", + "description": "$1 is remeaning time in minutes and seconds, e.g. 0:10" + }, "stxFailure": { "message": "交换失败" }, @@ -3811,6 +4943,9 @@ "message": "突然的市场变化可能导致失败。如果问题仍然存在,请联系$1。", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInDescription": { + "message": "开启智能交易,以便在以太坊主网上实现更加安全可靠的交易。$1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "正在秘密提交您的Swap..." }, @@ -3849,12 +4984,21 @@ "submitted": { "message": "已提交" }, + "suggestedTokenSymbol": { + "message": "建议的股票代码:" + }, "support": { "message": "获取帮助" }, "supportCenter": { "message": "访问我们的支持中心" }, + "surveyConversion": { + "message": "参与我们的调查" + }, + "surveyTitle": { + "message": "塑造MetaMask的未来" + }, "swap": { "message": "兑换" }, @@ -3874,6 +5018,9 @@ "swapAmountReceivedInfo": { "message": "这是您将收到的最低金额。根据滑点值,您可能会收到更多。" }, + "swapAndSend": { + "message": "兑换并发送" + }, "swapAnyway": { "message": "仍然兑换" }, @@ -3989,6 +5136,10 @@ "message": "包括 $1% 的 MetaMask 费用。", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." }, + "swapIncludesMMFeeAlt": { + "message": "报价反映了 $1% MetaMask 费用", + "description": "Provides information about the fee that metamask takes for swaps using the latest copy. $1 is a decimal number." + }, "swapIncludesMetaMaskFeeViewAllQuotes": { "message": "包含$1%的MetaMask费用 – $2", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number and $2 is a link to view all quotes." @@ -3996,6 +5147,9 @@ "swapLearnMore": { "message": "了解有关 Swaps 的更多信息" }, + "swapLiquiditySourceInfo": { + "message": "我们搜索多种流动性来源(交易所、聚合器和专业做市商),以比较汇率和网络费用。" + }, "swapLowSlippage": { "message": "低滑点" }, @@ -4268,6 +5422,9 @@ "switchEthereumChainConfirmationTitle": { "message": "允许此网站切换网络?" }, + "switchInputCurrency": { + "message": "切换输入货币" + }, "switchNetwork": { "message": "切换网络" }, @@ -4281,14 +5438,15 @@ "switchToThisAccount": { "message": "切换到该账户" }, - "switchedTo": { - "message": "您已切换到" + "switchedNetworkToastDecline": { + "message": "不再显示此内容" }, - "switcherTitle": { - "message": "网络切换工具" + "switchedNetworkToastMessage": { + "message": "$1 现已在 $2 上激活", + "description": "$1 represents the account name, $2 represents the network name" }, - "switcherTourDescription": { - "message": "点击此图标以切换网络或添加新网络" + "switchedTo": { + "message": "您已切换到" }, "switchingNetworksCancelsPendingConfirmations": { "message": "切换网络将取消所有待处理的确认" @@ -4388,6 +5546,18 @@ "toggleEthSignOn": { "message": "开启(不推荐)" }, + "toggleRequestQueueDescription": { + "message": "这使您可以为每个网站选择网络,而不是为所有网站选择同一个网络。此功能将阻止您手动切换网络,这可能会破坏您在某些网站上的用户体验。" + }, + "toggleRequestQueueField": { + "message": "为每个网站选择网络" + }, + "toggleRequestQueueOff": { + "message": "关" + }, + "toggleRequestQueueOn": { + "message": "开" + }, "token": { "message": "代币" }, @@ -4404,7 +5574,7 @@ "message": "代币合约地址" }, "tokenDecimalFetchFailed": { - "message": "需要代币小数。" + "message": "需要代币小数位。请在下方查找:$1" }, "tokenDecimalTitle": { "message": "代币小数:" @@ -4443,6 +5613,9 @@ "tooltipSatusConnected": { "message": "已连接" }, + "tooltipSatusConnectedUpperCase": { + "message": "已连接" + }, "tooltipSatusNotConnected": { "message": "未连接" }, @@ -4583,6 +5756,39 @@ "tryAgain": { "message": "重试" }, + "turnOff": { + "message": "关闭" + }, + "turnOffMetamaskNotificationsError": { + "message": "禁用通知时出错了。请稍后再试。" + }, + "turnOn": { + "message": "开启" + }, + "turnOnMetamaskNotifications": { + "message": "开启通知" + }, + "turnOnMetamaskNotificationsButton": { + "message": "开启" + }, + "turnOnMetamaskNotificationsError": { + "message": "创建通知时出错了。请稍后再试。" + }, + "turnOnMetamaskNotificationsMessageFirst": { + "message": "通过通知随时了解您的钱包动态。" + }, + "turnOnMetamaskNotificationsMessagePrivacyBold": { + "message": "设置 > 通知。" + }, + "turnOnMetamaskNotificationsMessagePrivacyLink": { + "message": "了解我们如何在使用此功能时保护您的隐私。" + }, + "turnOnMetamaskNotificationsMessageSecond": { + "message": "为了使用钱包通知,我们使用配置文件在您的不同设备上同步某些设置。$1" + }, + "turnOnMetamaskNotificationsMessageThird": { + "message": "您可以随时在 $1 中关闭通知" + }, "turnOnTokenDetection": { "message": "开启增强型代币检测" }, @@ -4614,6 +5820,10 @@ "unknownNetwork": { "message": "未知的私有网络" }, + "unknownNetworkForKeyEntropy": { + "message": "未知网络", + "description": "Displayed on places like Snap install warning when regular name is not available." + }, "unknownQrCode": { "message": "错误:我们无法识别该二维码" }, @@ -4626,6 +5836,9 @@ "unlockMessage": { "message": "即将进入去中心化网络" }, + "unpin": { + "message": "取消置顶" + }, "unrecognizedChain": { "message": "该自定义网络无法识别", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." @@ -4643,6 +5856,9 @@ "update": { "message": "更新" }, + "updateRequest": { + "message": "更新请求" + }, "updatedWithDate": { "message": "已于 $1 更新" }, @@ -4667,12 +5883,25 @@ "useNftDetection": { "message": "自动检测NFT" }, + "useNftDetectionDescriptionText": { + "message": "让 MetaMask 使用第三方服务(如 OpenSea)来添加您所拥有的 NFT。打开自动检测 NFT 功能后,这些服务就可以看到您的 IP 地址和账户地址。启用此功能可能会将您的 IP 地址与以太坊地址关联起来,并显示骗子空投的虚假 NFT。您可以手动添加代币以避免此风险。" + }, "usePhishingDetection": { "message": "使用网络钓鱼检测" }, "usePhishingDetectionDescription": { "message": "显示针对以太坊用户的网络钓鱼域名警告" }, + "useSafeChainsListValidation": { + "message": "网络详细信息检查" + }, + "useSafeChainsListValidationDescription": { + "message": "MetaMask 使用名为$1的第三方服务来显示标准化网络的准确详细信息。这可减少您连接到恶意或不正确网络的机会。使用此功能时,chainid.network 可以看到您的 IP 地址。" + }, + "useSafeChainsListValidationWebsite": { + "message": "chainid.network", + "description": "useSafeChainsListValidationWebsite is separated from the rest of the text so that we can bold the third party service name in the middle of them" + }, "useSiteSuggestion": { "message": "使用网站建议" }, @@ -4685,6 +5914,9 @@ "userName": { "message": "用户名" }, + "userOpContractDeployError": { + "message": "不支持从智能合约账户进行合约部署" + }, "verifyContractDetails": { "message": "验证第三方详情" }, @@ -4702,6 +5934,9 @@ "view": { "message": "查看" }, + "viewActivity": { + "message": "查看活动" + }, "viewAllDetails": { "message": "查看所有详情" }, @@ -4725,7 +5960,7 @@ }, "viewOnCustomBlockExplorer": { "message": "在 $2 上查看 $1", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "在 Etherscan 上查看 $1", @@ -4737,6 +5972,9 @@ "viewOnOpensea": { "message": "在 Opensea 上查看" }, + "viewTransaction": { + "message": "查看交易" + }, "viewinCustodianApp": { "message": "在托管应用程序中查看" }, @@ -4744,6 +5982,9 @@ "message": "在 Explorer 中查看 $1", "description": "$1 is the action type. e.g (Account, Transaction, Swap)" }, + "visitSite": { + "message": "访问网站" + }, "visitWebSite": { "message": "访问我们的网站" }, @@ -4782,6 +6023,10 @@ "warning": { "message": "警告" }, + "warningFromSnap": { + "message": "来自$1的警告", + "description": "$1 represents the name of the snap" + }, "warningTooltipText": { "message": "$1 第三方可能会支出您的全部代币余额,无需进一步通知或同意。请自定义较低的支出上限以保护自己。", "description": "$1 is a warning icon with text 'Be careful' in 'warning' colour" @@ -4789,6 +6034,9 @@ "weak": { "message": "弱" }, + "web3": { + "message": "Web3" + }, "web3ShimUsageNotification": { "message": "我们发现当前的网站尝试使用已经删除的 window.web3 API。如果这个网站出现故障,请点击 $1 以获取更多信息。", "description": "$1 is a clickable link." @@ -4829,10 +6077,6 @@ "whatsThis": { "message": "这是什么?" }, - "xOfY": { - "message": "$1 / $2", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$1 / $2 待处理", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" @@ -4840,6 +6084,9 @@ "yes": { "message": "是" }, + "you": { + "message": "您" + }, "youHaveAddedAll": { "message": "您已经添加了所有热门网络。您可以探索更多网络$1,或者您可以$2", "description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'" @@ -4862,6 +6109,12 @@ "yourPrivateSeedPhrase": { "message": "您的个人账户私钥助记词" }, + "yourTransactionConfirmed": { + "message": "交易已确认" + }, + "yourTransactionJustConfirmed": { + "message": "在区块链上确认之前,我们无法取消您的交易。" + }, "zeroGasPriceOnSpeedUpError": { "message": "加速时零燃料价格" } diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index ce0fc3d38a96..26f086433a96 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -92,12 +92,6 @@ "alerts": { "message": "提醒" }, - "allowExternalExtensionTo": { - "message": "允許這個外部擴充功能:" - }, - "allowThisSiteTo": { - "message": "允許這個網站:" - }, "allowWithdrawAndSpend": { "message": "允許 $1 提款或最多花費以下額度:", "description": "The url of the site that requested permission to 'withdraw and spend'" @@ -197,9 +191,6 @@ "cancel": { "message": "取消" }, - "cancelEdit": { - "message": "Cancel Edit" - }, "cancelSpeedUp": { "message": "cancel or speed up a tranaction." }, @@ -245,26 +236,6 @@ "connectManually": { "message": "手動連結到目前的網站" }, - "connectTo": { - "message": "連結到 $1", - "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask" - }, - "connectToAll": { - "message": "連結到您的全部$1", - "description": "$1 will be replaced by the translation of connectToAllAccounts" - }, - "connectToAllAccounts": { - "message": "帳戶", - "description": "will replace $1 in connectToAll, completing the sentence 'connect to all of your accounts', will be text that shows list of accounts on hover" - }, - "connectToMultiple": { - "message": "連結到 $1", - "description": "$1 will be replaced by the translation of connectToMultipleNumberOfAccounts" - }, - "connectToMultipleNumberOfAccounts": { - "message": "$1 個帳戶", - "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple" - }, "connectWithMetaMask": { "message": "連結到 MetaMask" }, @@ -959,7 +930,8 @@ "message": "惡意的網路提供者可以欺騙您區塊鏈上的狀態或記錄您的網路活動。請只新增您信任的自訂網路。" }, "onlyConnectTrust": { - "message": "記住,只連線到您信任的網站。" + "message": "記住,只連線到您信任的網站。", + "description": "Text displayed above the buttons for connection confirmation. $1 is the link to the learn more web page." }, "origin": { "message": "來源" @@ -1185,9 +1157,6 @@ "message": "發送 $1", "description": "Symbol of the specified token" }, - "sendTokens": { - "message": "發送代幣" - }, "settings": { "message": "設定" }, @@ -1483,7 +1452,7 @@ }, "viewOnCustomBlockExplorer": { "message": "在 $1 瀏覽", - "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Exporer URL" + "description": "$1 is the action type. e.g (Account, Transaction, Swap) and $2 is the Custom Block Explorer URL" }, "viewOnEtherscan": { "message": "在 Etherscan 上瀏覽", @@ -1509,10 +1478,6 @@ "whatsThis": { "message": "這是什麼?" }, - "xOfY": { - "message": "$1 之 $2", - "description": "$1 and $2 are intended to be two numbers, where $2 is a total, and $1 is a count towards that total" - }, "xOfYPending": { "message": "$1 之 $2 等待中", "description": "$1 and $2 are intended to be two numbers, where $2 is a total number of pending confirmations, and $1 is a count towards that total" diff --git a/app/background.html b/app/background.html index 148842e8f868..c0068295d730 100644 --- a/app/background.html +++ b/app/background.html @@ -4,7 +4,7 @@ - - + + diff --git a/app/build-types/desktop/images/desktop-mascot.json b/app/build-types/desktop/images/desktop-mascot.json deleted file mode 100644 index 43b200544f06..000000000000 --- a/app/build-types/desktop/images/desktop-mascot.json +++ /dev/null @@ -1,824 +0,0 @@ -{ - "chunks": [ - { - "faces": [ - [0, 1, 2], - [2, 3, 0], - [4, 5, 2], - [6, 3, 2], - [2, 5, 6], - [7, 8, 9], - [10, 3, 6], - [10, 50, 7], - [7, 3, 10], - [7, 9, 3], - [49, 0, 9], - [3, 9, 0], - [2, 1, 4] - ], - "name": "left ear", - "gradient": "left-ear-gradient" - }, - { - "faces": [ - [53, 54, 55], - [55, 56, 53], - [57, 56, 55], - [58, 59, 55], - [55, 54, 58], - [60, 61, 62], - [63, 58, 54], - [63, 60, 89], - [60, 63, 54], - [60, 54, 61], - [88, 61, 53], - [54, 53, 61], - [55, 59, 57] - ], - "name": "right ear", - "gradient": "right-ear-gradient" - }, - { - "color": [22, 22, 22], - "faces": [[11, 12, 13]], - "name": "left eye" - }, - { - "color": [22, 22, 22], - "faces": [[64, 65, 66]], - "name": "right eye" - }, - { - "faces": [ - [14, 15, 11], - [11, 16, 14] - ], - "name": "left inner eye", - "gradient": "left-inner-eye-gradient" - }, - { - "faces": [[17, 12, 18]], - "name": "left outer eye", - "gradient": "left-outer-eye-gradient" - }, - { - "faces": [[41, 64, 37]], - "name": "right lower inner eye", - "gradient": "right-inner-eye-gradient" - }, - { - "faces": [[67, 68, 66]], - "name": "right outer eye", - "gradient": "right-outer-eye-gradient" - }, - { - "color": [223, 117, 84], - "faces": [ - [19, 20, 21], - [21, 22, 19], - [20, 19, 23], - [23, 24, 20], - [23, 25, 24], - [19, 22, 26], - [26, 27, 19], - [23, 28, 29], - [23, 29, 30], - [25, 23, 30], - [29, 51, 52], - [52, 30, 29], - [27, 26, 69], - [69, 70, 27], - [70, 71, 72], - [72, 27, 70], - [72, 71, 73], - [51, 74, 72], - [52, 51, 72], - [73, 52, 72], - [19, 27, 74], - [74, 28, 19], - [51, 29, 28], - [28, 74, 51], - [74, 27, 72], - [28, 23, 19] - ], - "name": "lower chin" - }, - { - "color": [255, 159, 90], - "faces": [ - [21, 20, 24], - [24, 31, 21] - ], - "name": "left lower snout" - }, - { - "color": [255, 159, 90], - "faces": [ - [69, 71, 70], - [71, 69, 75] - ], - "name": "right lower snout" - }, - { - "color": [147, 131, 250], - "faces": [[31, 24, 18]], - "name": "left upper snout" - }, - { - "faces": [ - [6, 5, 16], - [16, 17, 6] - ], - "name": "left forehead", - "gradient": "left-forehead-gradient" - }, - { - "faces": [ - [24, 32, 33], - [33, 34, 24] - ], - "name": "left lower cheek", - "gradient": "left-lower-cheek-gradient" - }, - { - "faces": [[5, 4, 35]], - "name": "left top ear", - "gradient": "left-top-ear-gradient" - }, - { - "color": [147, 131, 250], - "faces": [[75, 68, 71]], - "name": "right upper snout" - }, - { - "faces": [ - [58, 67, 40], - [40, 59, 58] - ], - "name": "right forhead", - "gradient": "right-forehead-gradient" - }, - { - "faces": [ - [71, 76, 77], - [77, 78, 71] - ], - "name": "right lower cheek", - "gradient": "right-lower-cheek-gradient" - }, - { - "faces": [[24, 34, 18]], - "name": "left middle cheek", - "gradient": "left-middle-cheek-gradient" - }, - { - "color": [156, 90, 221], - "faces": [ - [16, 13, 12], - [12, 17, 16], - [13, 16, 11] - ], - "name": "left above eye" - }, - { - "faces": [[71, 68, 76]], - "name": "right middle cheek", - "gradient": "right-middle-cheek-gradient" - }, - { - "color": [156, 90, 221], - "faces": [ - [40, 67, 66], - [66, 65, 40], - [65, 64, 40] - ], - "name": "right above eye" - }, - { - "color": [22, 22, 22], - "faces": [ - [36, 15, 37], - [37, 38, 36], - [31, 39, 22], - [22, 21, 31], - [31, 15, 36], - [36, 39, 31], - [75, 69, 26], - [26, 80, 75], - [75, 80, 38], - [38, 37, 75], - [38, 80, 39], - [39, 36, 38], - [39, 80, 26], - [26, 22, 39] - ], - "name": "nose" - }, - { - "faces": [ - [17, 33, 10], - [17, 18, 34], - [34, 33, 17], - [10, 6, 17] - ], - "name": "left upper cheek", - "gradient": "left-upper-cheek-gradient" - }, - { - "faces": [ - [11, 15, 31], - [31, 18, 11], - [18, 12, 11] - ], - "name": "left below eye", - "gradient": "left-below-eye-gradient" - }, - { - "faces": [ - [14, 16, 40], - [40, 41, 14], - [59, 5, 35], - [35, 79, 59], - [14, 41, 37], - [37, 15, 14], - [5, 59, 40], - [40, 16, 5] - ], - "name": "forehead", - "gradient": "forehead-gradient" - }, - { - "faces": [ - [67, 63, 77], - [67, 77, 76], - [76, 68, 67], - [63, 67, 58] - ], - "name": "right upper cheek", - "gradient": "right-upper-cheek-gradient" - }, - { - "faces": [ - [64, 68, 75], - [75, 37, 64], - [68, 64, 66] - ], - "name": "right below eye", - "gradient": "right-below-eye-gradient" - }, - { - "faces": [ - [35, 4, 42], - [4, 1, 42], - [42, 43, 44], - [44, 35, 42], - [45, 43, 42], - [42, 10, 45], - [30, 32, 24], - [24, 25, 30], - [30, 33, 32], - [33, 30, 10], - [44, 43, 46], - [43, 45, 47], - [47, 46, 43], - [48, 47, 45], - [45, 30, 48], - [30, 45, 10], - [49, 42, 0], - [8, 7, 42], - [50, 42, 7], - [50, 10, 42], - [1, 0, 42], - [42, 9, 8], - [42, 49, 9], - [79, 81, 57], - [57, 81, 56], - [82, 79, 35], - [35, 44, 82], - [81, 79, 82], - [82, 83, 81], - [84, 63, 81], - [81, 83, 84], - [44, 46, 85], - [85, 82, 44], - [52, 73, 71], - [71, 78, 52], - [52, 78, 77], - [77, 63, 52], - [82, 85, 83], - [83, 85, 86], - [86, 84, 83], - [87, 52, 84], - [84, 86, 87], - [52, 63, 84], - [88, 53, 81], - [62, 81, 60], - [89, 60, 81], - [89, 81, 63], - [56, 81, 53], - [81, 62, 61], - [81, 61, 88], - [48, 87, 86], - [86, 47, 48], - [47, 86, 85], - [85, 46, 47], - [48, 30, 52], - [52, 87, 48] - ], - "name": "back", - "gradient": "back-gradient" - }, - { - "faces": [[57, 59, 79]], - "name": "right top ear", - "gradient": "right-top-ear-gradient" - }, - { - "faces": [[64, 41, 40]], - "name": "right inner upper eye", - "gradient": "right-inner-eye-gradient" - } - ], - "gradients": { - "left-inner-eye-gradient": { - "type": "linear", - "x1": "41.97721822541966%", - "y1": "67.79239690721649%", - "x2": "44.56654676258992%", - "y2": "67.79239690721649%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#BA86F3" - }, - { - "offset": "0.5281", - "stop-color": "#B786F4" - }, - { - "offset": "0.8987", - "stop-color": "#AE86F5" - }, - { - "offset": "1", - "stop-color": "#AA86F6" - } - ] - }, - "right-inner-eye-gradient": { - "type": "linear", - "x1": "56.72805755395684%", - "y1": "81.08904639175258%", - "x2": "56.72805755395684%", - "y2": "54.49574742268041%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#BA86F3" - }, - { - "offset": "0.5281", - "stop-color": "#B786F4" - }, - { - "offset": "0.8987", - "stop-color": "#AE86F5" - }, - { - "offset": "1", - "stop-color": "#AA86F6" - } - ] - }, - "left-middle-cheek-gradient": { - "type": "linear", - "x1": "25.107913669064747%", - "y1": "72.68865979381442%", - "x2": "25.107913669064747%", - "y2": "89.44690721649484%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#6848BA" - }, - { - "offset": "0.3363", - "stop-color": "#6356D5" - } - ] - }, - "right-middle-cheek-gradient": { - "type": "linear", - "x1": "74.89208633093526%", - "y1": "51.32938144329896%", - "x2": "74.89208633093526%", - "y2": "94.76301546391753%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#6848BA" - }, - { - "offset": "0.3363", - "stop-color": "#6356D5" - } - ] - }, - "right-forehead-gradient": { - "type": "linear", - "x1": "67.00671462829736%", - "y1": "30.13930412371134%", - "x2": "67.00671462829736%", - "y2": "54.49561855670103%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#DC69E6" - }, - { - "offset": "1", - "stop-color": "#C289F3" - } - ] - }, - "left-forehead-gradient": { - "type": "linear", - "x1": "32.99340527577938%", - "y1": "30.13930412371134%", - "x2": "32.99340527577938%", - "y2": "54.49561855670103%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#DC69E6" - }, - { - "offset": "1", - "stop-color": "#C289F3" - } - ] - }, - "right-top-ear-gradient": { - "type": "linear", - "x1": "95.056858513189448%", - "y1": "15.06958762886598%", - "x2": "57.31654676258992%", - "y2": "15.06958762886598%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#BB65ED" - }, - { - "offset": "1", - "stop-color": "#E560E3" - } - ] - }, - "left-top-ear-gradient": { - "type": "linear", - "x1": "4.943141486810552%", - "y1": "15.06958762886598%", - "x2": "42.68345323741008%", - "y2": "15.06958762886598%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#BB65ED" - }, - { - "offset": "1", - "stop-color": "#E560E3" - } - ] - }, - "left-lower-cheek-gradient": { - "type": "linear", - "x1": "15.103956834532372%", - "y1": "72.6889175257732%", - "x2": "15.103956834532372%", - "y2": "96.03221649484537%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#906EF7" - }, - { - "offset": "1", - "stop-color": "#575ADE" - } - ] - }, - "right-lower-cheek-gradient": { - "type": "linear", - "x1": "84.91570743405276%", - "y1": "72.6889175257732%", - "x2": "84.91570743405276%", - "y2": "96.03221649484537%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#906EF7" - }, - { - "offset": "1", - "stop-color": "#575ADE" - } - ] - }, - "right-outer-eye-gradient": { - "type": "linear", - "x1": "68.7720623501199%", - "y1": "63.14909793814433%", - "x2": "78.03057553956835%", - "y2": "63.14909793814433%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#BA86F3" - }, - { - "offset": "0.5281", - "stop-color": "#B786F4" - }, - { - "offset": "0.8987", - "stop-color": "#AE86F5" - }, - { - "offset": "1", - "stop-color": "#AA86F6" - } - ] - }, - "left-outer-eye-gradient": { - "type": "linear", - "x1": "21.969424460431654%", - "y1": "63.14909793814433%", - "x2": "31.227937649880094%", - "y2": "63.14909793814433%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#BA86F3" - }, - { - "offset": "0.5281", - "stop-color": "#B786F4" - }, - { - "offset": "0.8987", - "stop-color": "#AE86F5" - }, - { - "offset": "1", - "stop-color": "#AA86F6" - } - ] - }, - "left-ear-gradient": { - "type": "linear", - "x1": "50%", - "y1": "30%", - "x2": "4%", - "y2": "4%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#541758" - }, - { - "offset": "0.4286", - "stop-color": "#4F206C" - }, - { - "offset": "0.62", - "stop-color": "#4D2577" - }, - { - "offset": "1", - "stop-color": "#8B45B6" - } - ] - }, - "right-ear-gradient": { - "type": "linear", - "x1": "50%", - "y1": "30%", - "x2": "96%", - "y2": "4%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#541758" - }, - { - "offset": "0.4286", - "stop-color": "#4F206C" - }, - { - "offset": "0.62", - "stop-color": "#4D2577" - }, - { - "offset": "1", - "stop-color": "#8B45B6" - } - ] - }, - "left-below-eye-gradient": { - "type": "linear", - "x1": "30.914028776978412%", - "y1": "72.83646907216496%", - "x2": "44.56654676258992%", - "y2": "72.83646907216496%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#C8A8F7" - }, - { - "offset": "1", - "stop-color": "#BAAAFB" - } - ] - }, - "right-below-eye-gradient": { - "type": "linear", - "x1": "55.43345323741007%", - "y1": "72.83646907216496%", - "x2": "69.12517985611511%", - "y2": "72.83646907216496%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#C8A8F7" - }, - { - "offset": "1", - "stop-color": "#BAAAFB" - } - ] - }, - "left-upper-cheek-gradient": { - "type": "linear", - "x1": "16.02589928057554%", - "y1": "43.35154639175258%", - "x2": "16.02589928057554%", - "y2": "72.85773195876288%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#B65FE5" - }, - { - "offset": "1", - "stop-color": "#ADA2FC" - } - ] - }, - "right-upper-cheek-gradient": { - "type": "linear", - "x1": "83.99364508393285%", - "y1": "43.35154639175258%", - "x2": "83.99364508393285%", - "y2": "72.85773195876288%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#B65FE5" - }, - { - "offset": "1", - "stop-color": "#ADA2FC" - } - ] - }, - "forehead-gradient": { - "type": "linear", - "x1": "50%", - "y1": "12.790180412371136%", - "x2": "50%", - "y2": "81.08904639175258%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#FB7FE4" - }, - { - "offset": "1", - "stop-color": "#BCABFB" - } - ] - }, - "back-gradient": { - "type": "linear", - "x1": "50%", - "y1": "12.790180412371136%", - "x2": "50%", - "y2": "81.08904639175258%", - "gradientUnits": "userSpaceOnUse", - "stops": [ - { - "stop-color": "#FB7FE4" - }, - { - "offset": "1", - "stop-color": "#5C5CE0" - } - ] - } - }, - "positions": [ - [111.024597, 52.604599, 46.225899], - [114.025002, 87.673302, 58.9818], - [66.192001, 80.898003, 55.394299], - [72.113297, 35.491798, 30.871401], - [97.804497, 116.560997, 73.978798], - [16.7623, 58.010899, 58.078201], - [52.608898, 30.3641, 42.556099], - [106.881401, 31.945499, 46.9133], - [113.484596, 38.6049, 49.121498], - [108.6633, 43.2332, 46.315399], - [101.216599, 15.9822, 46.308201], - [16.6605, -16.2883, 93.618698], - [40.775002, -10.2288, 85.276398], - [23.926901, -2.5103, 86.736504], - [11.1691, -7.0037, 99.377602], - [9.5692, -34.393902, 141.671997], - [12.596, 7.1655, 88.740997], - [61.180901, 8.8142, 76.996803], - [39.719501, -28.927099, 88.963799], - [13.7962, -68.575699, 132.057007], - [15.2674, -62.32, 129.688004], - [14.8446, -52.6096, 140.113007], - [12.8917, -49.771599, 144.740997], - [35.604198, -71.758003, 81.063904], - [47.462502, -68.606102, 63.369701], - [38.2486, -64.730202, 38.909901], - [-12.8917, -49.771599, 144.740997], - [-13.7962, -68.575699, 132.057007], - [17.802099, -71.758003, 81.063904], - [19.1243, -69.0168, 49.420101], - [38.2486, -66.275597, 17.776199], - [12.8928, -36.703499, 141.671997], - [109.283997, -93.589897, 27.824301], - [122.117996, -36.8894, 35.025002], - [67.7668, -30.197001, 78.417801], - [33.180698, 101.851997, 25.3186], - [9.4063, -35.589802, 150.722], - [-9.5692, -34.393902, 141.671997], - [-9.4063, -35.589802, 150.722], - [11.4565, -37.899399, 150.722], - [-12.596, 7.1655, 88.740997], - [-11.1691, -7.0037, 99.377602], - [70.236504, 62.836201, -3.9475], - [47.263401, 54.293999, -27.414801], - [28.7302, 91.731102, -24.972601], - [69.167603, 6.5862, -12.7757], - [28.7302, 49.1003, -48.3596], - [31.903, 5.692, -47.821999], - [35.075802, -34.432899, -16.280899], - [115.284103, 48.681499, 48.684101], - [110.842796, 28.4821, 49.176201], - [-19.1243, -69.0168, 49.420101], - [-38.2486, -66.275597, 17.776199], - [-111.024597, 52.604599, 46.225899], - [-72.113297, 35.491798, 30.871401], - [-66.192001, 80.898003, 55.394299], - [-114.025002, 87.673302, 58.9818], - [-97.804497, 116.560997, 73.978798], - [-52.608898, 30.3641, 42.556099], - [-16.7623, 58.010899, 58.078201], - [-106.881401, 31.945499, 46.9133], - [-108.6633, 43.2332, 46.315399], - [-113.484596, 38.6049, 49.121498], - [-101.216599, 15.9822, 46.308201], - [-16.6605, -16.2883, 93.618698], - [-23.926901, -2.5103, 86.736504], - [-40.775002, -10.2288, 85.276398], - [-61.180901, 8.8142, 76.996803], - [-39.719501, -28.927099, 88.963799], - [-14.8446, -52.6096, 140.113007], - [-15.2674, -62.32, 129.688004], - [-47.462502, -68.606102, 63.369701], - [-35.604198, -71.758003, 81.063904], - [-38.2486, -64.730202, 38.909901], - [-17.802099, -71.758003, 81.063904], - [-12.8928, -36.703499, 141.671997], - [-67.7668, -30.197001, 78.417801], - [-122.117996, -36.8894, 35.025002], - [-109.283997, -93.589897, 27.824301], - [-33.180698, 101.851997, 25.3186], - [-11.4565, -37.899399, 150.722], - [-70.236504, 62.836201, -3.9475], - [-28.7302, 91.731102, -24.972601], - [-47.263401, 54.293999, -27.414801], - [-69.167603, 6.5862, -12.7757], - [-28.7302, 49.1003, -48.3596], - [-31.903, 5.692, -47.821999], - [-35.075802, -34.432899, -16.280899], - [-115.284103, 48.681499, 48.684101], - [-110.842796, 28.4821, 49.176201] - ] -} diff --git a/app/build-types/desktop/images/icon-128.png b/app/build-types/desktop/images/icon-128.png deleted file mode 100644 index 4dddd86c3fcb..000000000000 Binary files a/app/build-types/desktop/images/icon-128.png and /dev/null differ diff --git a/app/build-types/desktop/images/icon-16.png b/app/build-types/desktop/images/icon-16.png deleted file mode 100644 index f67228dbc10c..000000000000 Binary files a/app/build-types/desktop/images/icon-16.png and /dev/null differ diff --git a/app/build-types/desktop/images/icon-19.png b/app/build-types/desktop/images/icon-19.png deleted file mode 100644 index 40ff28ba7b0c..000000000000 Binary files a/app/build-types/desktop/images/icon-19.png and /dev/null differ diff --git a/app/build-types/desktop/images/icon-32.png b/app/build-types/desktop/images/icon-32.png deleted file mode 100644 index 79918f98ff0b..000000000000 Binary files a/app/build-types/desktop/images/icon-32.png and /dev/null differ diff --git a/app/build-types/desktop/images/icon-38.png b/app/build-types/desktop/images/icon-38.png deleted file mode 100644 index 05f0b4b51b3e..000000000000 Binary files a/app/build-types/desktop/images/icon-38.png and /dev/null differ diff --git a/app/build-types/desktop/images/icon-48.png b/app/build-types/desktop/images/icon-48.png deleted file mode 100644 index 5e280b4e07be..000000000000 Binary files a/app/build-types/desktop/images/icon-48.png and /dev/null differ diff --git a/app/build-types/desktop/images/icon-512.png b/app/build-types/desktop/images/icon-512.png deleted file mode 100644 index eae504a57c24..000000000000 Binary files a/app/build-types/desktop/images/icon-512.png and /dev/null differ diff --git a/app/build-types/desktop/images/icon-64.png b/app/build-types/desktop/images/icon-64.png deleted file mode 100644 index 680a96b10f0e..000000000000 Binary files a/app/build-types/desktop/images/icon-64.png and /dev/null differ diff --git a/app/build-types/desktop/images/logo/metamask-fox.svg b/app/build-types/desktop/images/logo/metamask-fox.svg deleted file mode 100644 index 094aebc36408..000000000000 --- a/app/build-types/desktop/images/logo/metamask-fox.svg +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/build-types/desktop/manifest/_base.json b/app/build-types/desktop/manifest/_base.json deleted file mode 100644 index bc43d646a9bc..000000000000 --- a/app/build-types/desktop/manifest/_base.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "browser_action": { - "default_icon": { - "16": "images/icon-16.png", - "19": "images/icon-19.png", - "32": "images/icon-32.png", - "38": "images/icon-38.png", - "64": "images/icon-64.png", - "128": "images/icon-128.png", - "512": "images/icon-512.png" - }, - "default_title": "MetaMask Flask" - }, - "icons": { - "16": "images/icon-16.png", - "19": "images/icon-19.png", - "32": "images/icon-32.png", - "38": "images/icon-38.png", - "48": "images/icon-48.png", - "64": "images/icon-64.png", - "128": "images/icon-128.png", - "512": "images/icon-512.png" - }, - "name": "__MSG_appNameFlask__", - "short_name": "__MSG_appNameFlask__" -} diff --git a/app/build-types/desktop/manifest/chrome.json b/app/build-types/desktop/manifest/chrome.json deleted file mode 100644 index 8f13762233bc..000000000000 --- a/app/build-types/desktop/manifest/chrome.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "description": "THIS IS THE CANARY DISTRIBUTION OF THE METAMASK EXTENSION, INTENDED FOR DEVELOPERS.", - "name": "MetaMask Desktop DEVELOPMENT BUILD" -} diff --git a/app/build-types/desktop/manifest/firefox.json b/app/build-types/desktop/manifest/firefox.json deleted file mode 100644 index b925bb98d70f..000000000000 --- a/app/build-types/desktop/manifest/firefox.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "applications": { - "gecko": { - "id": "webextension-desktop@metamask.io" - } - } -} diff --git a/app/home.html b/app/home.html index 3210c30475c9..b94800b13d78 100644 --- a/app/home.html +++ b/app/home.html @@ -8,7 +8,7 @@ <% } else { %> MetaMask <% } %> - +
@@ -16,6 +16,6 @@
- + diff --git a/app/images/arbitrum.svg b/app/images/arbitrum.svg index 8863afe882c8..9c19a48f2d72 100644 --- a/app/images/arbitrum.svg +++ b/app/images/arbitrum.svg @@ -1,12 +1,40 @@ - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/images/bitcoin-logo.svg b/app/images/bitcoin-logo.svg new file mode 100644 index 000000000000..4306787921c7 --- /dev/null +++ b/app/images/bitcoin-logo.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/images/blockaid-whats-new-theme-dark.svg b/app/images/blockaid-whats-new-theme-dark.svg deleted file mode 100644 index 8960d6f1d93f..000000000000 --- a/app/images/blockaid-whats-new-theme-dark.svg +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/images/blockaid-whats-new.svg b/app/images/blockaid-whats-new.svg deleted file mode 100644 index 723431869fc3..000000000000 --- a/app/images/blockaid-whats-new.svg +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/images/chart.webp b/app/images/chart.webp deleted file mode 100644 index 5fce765663c6..000000000000 Binary files a/app/images/chart.webp and /dev/null differ diff --git a/app/images/eth_logo.svg b/app/images/eth_logo.svg index 356b8e8779f2..4b6ceacffc19 100644 --- a/app/images/eth_logo.svg +++ b/app/images/eth_logo.svg @@ -5,4 +5,4 @@ - + \ No newline at end of file diff --git a/app/images/filecoin.svg b/app/images/filecoin.svg new file mode 100644 index 000000000000..0dacb5b294ad --- /dev/null +++ b/app/images/filecoin.svg @@ -0,0 +1,22 @@ + + + +Created with Fabric.js 5.2.4 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/images/fuse-mainnet.jpeg b/app/images/fuse-mainnet.jpeg deleted file mode 100644 index 5c8d583b2889..000000000000 Binary files a/app/images/fuse-mainnet.jpeg and /dev/null differ diff --git a/app/images/fuse-mainnet.jpg b/app/images/fuse-mainnet.jpg new file mode 100644 index 000000000000..2a3e91aefaba Binary files /dev/null and b/app/images/fuse-mainnet.jpg differ diff --git a/app/images/icons/customize.svg b/app/images/icons/customize.svg new file mode 100644 index 000000000000..4219d0c89f7b --- /dev/null +++ b/app/images/icons/customize.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/images/introducing-snaps.svg b/app/images/introducing-snaps.svg deleted file mode 100644 index 84b0d5918f10..000000000000 --- a/app/images/introducing-snaps.svg +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/images/logo/metamask-smart-transactions.png b/app/images/logo/metamask-smart-transactions.png deleted file mode 100644 index 6eed753120bf..000000000000 Binary files a/app/images/logo/metamask-smart-transactions.png and /dev/null differ diff --git a/app/images/numbers-mainnet.svg b/app/images/numbers-mainnet.svg new file mode 100644 index 000000000000..704a74329e26 --- /dev/null +++ b/app/images/numbers-mainnet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/images/numbers-token.png b/app/images/numbers-token.png new file mode 100644 index 000000000000..5cde0226fc4b Binary files /dev/null and b/app/images/numbers-token.png differ diff --git a/app/images/petnames-whatsnew-banner.svg b/app/images/petnames-whatsnew-banner.svg deleted file mode 100644 index 3341bac312ea..000000000000 --- a/app/images/petnames-whatsnew-banner.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/app/images/portfolio-v2-whatsnew-banner.png b/app/images/portfolio-v2-whatsnew-banner.png deleted file mode 100644 index 2abc407b6d13..000000000000 Binary files a/app/images/portfolio-v2-whatsnew-banner.png and /dev/null differ diff --git a/app/images/product-announcement-logo.svg b/app/images/product-announcement-logo.svg new file mode 100644 index 000000000000..fc10362e71fc --- /dev/null +++ b/app/images/product-announcement-logo.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/images/ramps-card-activity-illustration.png b/app/images/ramps-card-activity-illustration.png new file mode 100644 index 000000000000..0a0d839e8fc8 Binary files /dev/null and b/app/images/ramps-card-activity-illustration.png differ diff --git a/app/images/ramps-card-nft-illustration.png b/app/images/ramps-card-nft-illustration.png new file mode 100644 index 000000000000..1cbc824592f8 Binary files /dev/null and b/app/images/ramps-card-nft-illustration.png differ diff --git a/app/images/ramps-card-token-illustration.png b/app/images/ramps-card-token-illustration.png new file mode 100644 index 000000000000..7a226ede84db Binary files /dev/null and b/app/images/ramps-card-token-illustration.png differ diff --git a/app/images/scroll.svg b/app/images/scroll.svg new file mode 100644 index 000000000000..456c75922ac5 --- /dev/null +++ b/app/images/scroll.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/app/images/sei.svg b/app/images/sei.svg new file mode 100644 index 000000000000..ae103a00d11f --- /dev/null +++ b/app/images/sei.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/images/sell_button_whatsnew.png b/app/images/sell_button_whatsnew.png deleted file mode 100644 index fea8c079cf7a..000000000000 Binary files a/app/images/sell_button_whatsnew.png and /dev/null differ diff --git a/app/images/smart-transactions/smart-transactions-opt-in-background.svg b/app/images/smart-transactions/smart-transactions-opt-in-background.svg new file mode 100644 index 000000000000..965a348c487a --- /dev/null +++ b/app/images/smart-transactions/smart-transactions-opt-in-background.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/images/staking-light-mode-preview.png b/app/images/staking-light-mode-preview.png deleted file mode 100644 index 21081dc68fb0..000000000000 Binary files a/app/images/staking-light-mode-preview.png and /dev/null differ diff --git a/app/images/turn-on-metamask-notifications.png b/app/images/turn-on-metamask-notifications.png new file mode 100644 index 000000000000..79cd54f03b2a Binary files /dev/null and b/app/images/turn-on-metamask-notifications.png differ diff --git a/app/images/wallet-alpha.png b/app/images/wallet-alpha.png new file mode 100644 index 000000000000..bc88bcfb5f2d Binary files /dev/null and b/app/images/wallet-alpha.png differ diff --git a/app/loading.html b/app/loading.html index dd5902a09a39..1c85bd296cc6 100644 --- a/app/loading.html +++ b/app/loading.html @@ -1,9 +1,11 @@ - - + <% if (it.shouldIncludeSnow) { %> + + + <% } %> MetaMask Loading diff --git a/app/manifest/v2/_base.json b/app/manifest/v2/_base.json index c0b25efeeb94..4197c535972e 100644 --- a/app/manifest/v2/_base.json +++ b/app/manifest/v2/_base.json @@ -31,12 +31,12 @@ { "matches": ["file://*/*", "http://*/*", "https://*/*"], "js": [ - "disable-console.js", - "lockdown-install.js", - "lockdown-run.js", - "lockdown-more.js", - "contentscript.js", - "inpage.js" + "scripts/disable-console.js", + "scripts/lockdown-install.js", + "scripts/lockdown-run.js", + "scripts/lockdown-more.js", + "scripts/contentscript.js", + "scripts/inpage.js" ], "run_at": "document_start", "all_frames": true @@ -67,6 +67,7 @@ "http://localhost:8545/", "https://*.infura.io/", "https://*.codefi.network/", + "https://*.cx.metamask.io/", "https://chainid.network/chains.json", "https://lattice.gridplus.io/*", "activeTab", diff --git a/app/manifest/v3/_base.json b/app/manifest/v3/_base.json index 42df2d437671..f3ffbf07c173 100644 --- a/app/manifest/v3/_base.json +++ b/app/manifest/v3/_base.json @@ -14,7 +14,7 @@ }, "author": "https://metamask.io", "background": { - "service_worker": "app-init.js" + "service_worker": "scripts/app-init.js" }, "commands": { "_execute_browser_action": { @@ -30,11 +30,11 @@ { "matches": ["file://*/*", "http://*/*", "https://*/*"], "js": [ - "disable-console.js", - "lockdown-install.js", - "lockdown-run.js", - "lockdown-more.js", - "contentscript.js" + "scripts/disable-console.js", + "scripts/lockdown-install.js", + "scripts/lockdown-run.js", + "scripts/lockdown-more.js", + "scripts/contentscript.js" ], "run_at": "document_start", "all_frames": true @@ -75,5 +75,8 @@ "webRequest", "offscreen" ], + "sandbox": { + "pages": ["snaps/index.html"] + }, "short_name": "__MSG_appName__" } diff --git a/app/manifest/v3/chrome.json b/app/manifest/v3/chrome.json index e056267926d5..2308cc912b55 100644 --- a/app/manifest/v3/chrome.json +++ b/app/manifest/v3/chrome.json @@ -1,6 +1,7 @@ { "content_security_policy": { - "extension_pages": "script-src 'self'; object-src 'none'; frame-ancestors 'none';" + "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'none'; frame-ancestors 'none';", + "sandbox": "sandbox allow-scripts; script-src 'self' 'unsafe-inline' 'unsafe-eval'; object-src 'none'; default-src 'none'; connect-src *;" }, "externally_connectable": { "matches": ["https://metamask.io/*"], diff --git a/app/notification.html b/app/notification.html index a0e0f6dcf5a7..70f02e9ab421 100644 --- a/app/notification.html +++ b/app/notification.html @@ -32,7 +32,7 @@ margin-top: 1rem; } - +
@@ -50,11 +50,6 @@ />
- + diff --git a/app/popup.html b/app/popup.html index c27442faa6af..296b0ceae711 100644 --- a/app/popup.html +++ b/app/popup.html @@ -4,7 +4,7 @@ MetaMask - +
@@ -12,6 +12,6 @@
- + diff --git a/app/scripts/app-init.js b/app/scripts/app-init.js index 579f2b96bdca..766ba15e2d0d 100644 --- a/app/scripts/app-init.js +++ b/app/scripts/app-init.js @@ -1,14 +1,12 @@ -/* global chrome */ // This file is used only for manifest version 3 // Represents if importAllScripts has been run // eslint-disable-next-line let scriptsLoadInitiated = false; - +const { chrome } = globalThis; const testMode = process.env.IN_TEST; const loadTimeLogs = []; - // eslint-disable-next-line import/unambiguous function tryImport(...fileNames) { try { @@ -51,33 +49,41 @@ function importAllScripts() { const startImportScriptsTime = Date.now(); + // value of useSnow below is dynamically replaced at build time with actual value + const useSnow = process.env.USE_SNOW; + if (typeof useSnow !== 'boolean') { + throw new Error('Missing USE_SNOW environment variable'); + } + // value of applyLavaMoat below is dynamically replaced at build time with actual value const applyLavaMoat = process.env.APPLY_LAVAMOAT; if (typeof applyLavaMoat !== 'boolean') { throw new Error('Missing APPLY_LAVAMOAT environment variable'); } - loadFile('./sentry-install.js'); + loadFile('../scripts/sentry-install.js'); - // eslint-disable-next-line no-undef - const isWorker = !self.document; - if (!isWorker) { - loadFile('./snow.js'); - } + if (useSnow) { + // eslint-disable-next-line no-undef + const isWorker = !self.document; + if (!isWorker) { + loadFile('../scripts/snow.js'); + } - loadFile('./use-snow.js'); + loadFile('../scripts/use-snow.js'); + } // Always apply LavaMoat in e2e test builds, so that we can capture initialization stats if (testMode || applyLavaMoat) { - loadFile('./runtime-lavamoat.js'); - loadFile('./lockdown-more.js'); - loadFile('./policy-load.js'); + loadFile('../scripts/runtime-lavamoat.js'); + loadFile('../scripts/lockdown-more.js'); + loadFile('../scripts/policy-load.js'); } else { - loadFile('./init-globals.js'); - loadFile('./lockdown-install.js'); - loadFile('./lockdown-run.js'); - loadFile('./lockdown-more.js'); - loadFile('./runtime-cjs.js'); + loadFile('../scripts/init-globals.js'); + loadFile('../scripts/lockdown-install.js'); + loadFile('../scripts/lockdown-run.js'); + loadFile('../scripts/lockdown-more.js'); + loadFile('../scripts/runtime-cjs.js'); } // This environment variable is set to a string of comma-separated relative file paths. @@ -134,6 +140,21 @@ chrome.runtime.onMessage.addListener(() => { return false; }); +/* + * If the service worker is stopped and restarted, then the 'install' event will not occur + * and the chrome.runtime.onMessage will only occur if it was a message that restarted the + * the service worker. To ensure that importAllScripts is called, we need to call it in module + * scope as below. To avoid having `importAllScripts()` called before installation, we only + * call it if the serviceWorker state is 'activated'. More on service worker states here: + * https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/state. Testing also shows + * that whenever the already installed service worker is stopped and then restarted, the state + * is 'activated'. + */ +// eslint-disable-next-line no-undef +if (self.serviceWorker.state === 'activated') { + importAllScripts(); +} + /* * This content script is injected programmatically because * MAIN world injection does not work properly via manifest @@ -145,9 +166,10 @@ const registerInPageContentScript = async () => { { id: 'inpage', matches: ['file://*/*', 'http://*/*', 'https://*/*'], - js: ['inpage.js'], + js: ['scripts/inpage.js'], runAt: 'document_start', world: 'MAIN', + allFrames: true, }, ]); } catch (err) { @@ -163,27 +185,3 @@ const registerInPageContentScript = async () => { }; registerInPageContentScript(); - -/** - * Creates an offscreen document that can be used to load additional scripts - * and iframes that can communicate with the extension through the chrome - * runtime API. Only one offscreen document may exist, so any iframes required - * by extension can be embedded in the offscreen.html file. See the offscreen - * folder for more details. - */ -async function createOffscreen() { - if (await chrome.offscreen.hasDocument()) { - return; - } - - await chrome.offscreen.createDocument({ - url: './offscreen.html', - reasons: ['IFRAME_SCRIPTING'], - justification: - 'Used for Hardware Wallet and Snaps scripts to communicate with the extension.', - }); - - console.debug('Offscreen iframe loaded'); -} - -createOffscreen(); diff --git a/app/scripts/background.js b/app/scripts/background.js index 38c0d1ccba64..263fc5c86c63 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -9,8 +9,7 @@ import './lib/setup-initial-state-hooks'; import EventEmitter from 'events'; -import endOfStream from 'end-of-stream'; -import pump from 'pump'; +import { finished, pipeline } from 'readable-stream'; import debounce from 'debounce-stream'; import log from 'loglevel'; import browser from 'webextension-polyfill'; @@ -43,6 +42,7 @@ import { import { checkForLastErrorAndLog } from '../../shared/modules/browser-runtime.utils'; import { isManifestV3 } from '../../shared/modules/mv3.utils'; import { maskObject } from '../../shared/modules/object.utils'; +import { FIXTURE_STATE_METADATA_VERSION } from '../../test/e2e/default-fixture'; import migrations from './migrations'; import Migrator from './lib/migrator'; import ExtensionPlatform from './platforms/extension'; @@ -61,19 +61,24 @@ import rawFirstTimeState from './first-time-state'; import getFirstPreferredLangCode from './lib/get-first-preferred-lang-code'; import getObjStructure from './lib/getObjStructure'; import setupEnsIpfsResolver from './lib/ens-ipfs/setup'; -import { deferredPromise, getPlatform } from './lib/util'; +import { + deferredPromise, + getPlatform, + shouldEmitDappViewedEvent, +} from './lib/util'; +import { generateSkipOnboardingState } from './skip-onboarding'; +import { createOffscreen } from './offscreen'; /* eslint-enable import/first */ -/* eslint-disable import/order */ -///: BEGIN:ONLY_INCLUDE_IF(desktop) -import { - CONNECTION_TYPE_EXTERNAL, - CONNECTION_TYPE_INTERNAL, -} from '@metamask/desktop/dist/constants'; -import DesktopManager from '@metamask/desktop/dist/desktop-manager'; -///: END:ONLY_INCLUDE_IF -/* eslint-enable import/order */ +import { TRIGGER_TYPES } from './controllers/metamask-notifications/constants/notification-schema'; + +// eslint-disable-next-line @metamask/design-tokens/color-no-hex +const BADGE_COLOR_APPROVAL = '#0376C9'; +// eslint-disable-next-line @metamask/design-tokens/color-no-hex +const BADGE_COLOR_NOTIFICATION = '#D73847'; +const BADGE_LABEL_APPROVAL = '\u22EF'; // unicode ellipsis +const BADGE_MAX_NOTIFICATION_COUNT = 9; // Setup global hook for improved Sentry state snapshots during initialization const inTest = process.env.IN_TEST; @@ -82,7 +87,7 @@ global.stateHooks.getMostRecentPersistedState = () => localStore.mostRecentRetrievedState; const { sentry } = global; -const firstTimeState = { ...rawFirstTimeState }; +let firstTimeState = { ...rawFirstTimeState }; const metamaskInternalProcessHash = { [ENVIRONMENT_TYPE_POPUP]: true, @@ -97,7 +102,7 @@ log.setLevel(process.env.METAMASK_DEBUG ? 'debug' : 'info', false); const platform = new ExtensionPlatform(); const notificationManager = new NotificationManager(); -let popupIsOpen = false; +let openPopupCount = 0; let notificationIsOpen = false; let uiIsTriggering = false; const openMetamaskTabsIDs = {}; @@ -116,13 +121,6 @@ const ONE_SECOND_IN_MILLISECONDS = 1_000; // Timeout for initializing phishing warning page. const PHISHING_WARNING_PAGE_TIMEOUT = ONE_SECOND_IN_MILLISECONDS; -///: BEGIN:ONLY_INCLUDE_IF(desktop) -const OVERRIDE_ORIGIN = { - EXTENSION: 'EXTENSION', - DESKTOP: 'DESKTOP_APP', -}; -///: END:ONLY_INCLUDE_IF - // Event emitter for state persistence export const statePersistenceEvents = new EventEmitter(); @@ -227,8 +225,7 @@ function saveTimestamp() { * @property {object} identities - An object matching lower-case hex addresses to Identity objects with "address" and "name" (nickname) keys. * @property {object} networkConfigurations - A list of network configurations, containing RPC provider details (eg chainId, rpcUrl, rpcPreferences). * @property {Array} addressBook - A list of previously sent to addresses. - * @property {object} contractExchangeRatesByChainId - Info about current token prices keyed by chainId. - * @property {object} contractExchangeRates - Info about current token prices on current chain. + * @property {object} marketData - A map from chain ID -> contract address -> an object containing the token's market data. * @property {Array} tokens - Tokens held by the current user, including their balances. * @property {object} send - TODO: Document * @property {boolean} useBlockie - Indicates preferred user identicon format. True for blockie, false for Jazzicon. @@ -274,22 +271,24 @@ function saveTimestamp() { */ async function initialize() { try { + const offscreenPromise = isManifestV3 ? createOffscreen() : null; + const initData = await loadStateFromPersistence(); + const initState = initData.data; const initLangCode = await getFirstPreferredLangCode(); - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - await DesktopManager.init(platform.getVersion()); - ///: END:ONLY_INCLUDE_IF - let isFirstMetaMaskControllerSetup; + if (isManifestV3) { // Save the timestamp immediately and then every `SAVE_TIMESTAMP_INTERVAL` // miliseconds. This keeps the service worker alive. - const SAVE_TIMESTAMP_INTERVAL_MS = 2 * 1000; + if (initState.PreferencesController?.enableMV3TimestampSave !== false) { + const SAVE_TIMESTAMP_INTERVAL_MS = 2 * 1000; - saveTimestamp(); - setInterval(saveTimestamp, SAVE_TIMESTAMP_INTERVAL_MS); + saveTimestamp(); + setInterval(saveTimestamp, SAVE_TIMESTAMP_INTERVAL_MS); + } const sessionData = await browser.storage.session.get([ 'isFirstMetaMaskControllerSetup', @@ -306,6 +305,7 @@ async function initialize() { {}, isFirstMetaMaskControllerSetup, initData.meta, + offscreenPromise, ); if (!isManifestV3) { await loadPhishingWarningPage(); @@ -397,9 +397,19 @@ async function loadPhishingWarningPage() { */ export async function loadStateFromPersistence() { // migrations - const migrator = new Migrator({ migrations }); + const migrator = new Migrator({ + migrations, + defaultVersion: process.env.SKIP_ONBOARDING + ? FIXTURE_STATE_METADATA_VERSION + : null, + }); migrator.on('error', console.warn); + if (process.env.SKIP_ONBOARDING) { + const skipOnboardingStateOverrides = await generateSkipOnboardingState(); + firstTimeState = { ...firstTimeState, ...skipOnboardingStateOverrides }; + } + // read from disk // first from preferred, async API: versionedData = @@ -466,6 +476,11 @@ function emitDappViewedMetricEvent( connectSitePermissions, preferencesController, ) { + const { metaMetricsId } = controller.metaMetricsController.state; + if (!shouldEmitDappViewedEvent(metaMetricsId)) { + return; + } + // A dapp may have other permissions than eth_accounts. // Since we are only interested in dapps that use Ethereum accounts, we bail out otherwise. if (!hasProperty(connectSitePermissions.permissions, 'eth_accounts')) { @@ -502,9 +517,10 @@ function emitDappViewedMetricEvent( * * @param {object} initState - The initial state to start the controller with, matches the state that is emitted from the controller. * @param {string} initLangCode - The region code for the language preferred by the current user. - * @param {object} overrides - object with callbacks that are allowed to override the setup controller logic (usefull for desktop app) + * @param {object} overrides - object with callbacks that are allowed to override the setup controller logic * @param isFirstMetaMaskControllerSetup * @param {object} stateMetadata - Metadata about the initial state and migrations, including the most recent migration version + * @param {Promise} offscreenPromise - A promise that resolves when the offscreen document has finished initialization. */ export function setupController( initState, @@ -512,6 +528,7 @@ export function setupController( overrides, isFirstMetaMaskControllerSetup, stateMetadata, + offscreenPromise, ) { // // MetaMask Controller @@ -540,6 +557,7 @@ export function setupController( isFirstMetaMaskControllerSetup, currentMigrationVersion: stateMetadata.version, featureFlags: {}, + offscreenPromise, }); setupEnsIpfsResolver({ @@ -555,7 +573,7 @@ export function setupController( }); // setup state persistence - pump( + pipeline( storeAsStream(controller.store), debounce(1000), createStreamSink(async (state) => { @@ -571,7 +589,7 @@ export function setupController( const isClientOpenStatus = () => { return ( - popupIsOpen || + openPopupCount > 0 || Boolean(Object.keys(openMetamaskTabsIDs).length) || notificationIsOpen ); @@ -610,26 +628,6 @@ export function setupController( * @param {Port} remotePort - The port provided by a new context. */ connectRemote = async (remotePort) => { - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - if ( - DesktopManager.isDesktopEnabled() && - OVERRIDE_ORIGIN.DESKTOP !== overrides?.getOrigin?.() - ) { - DesktopManager.createStream(remotePort, CONNECTION_TYPE_INTERNAL).then( - () => { - // When in Desktop Mode the responsibility to send CONNECTION_READY is on the desktop app side - if (isManifestV3) { - // Message below if captured by UI code in app/scripts/ui.js which will trigger UI initialisation - // This ensures that UI is initialised only after background is ready - // It fixes the issue of blank screen coming when extension is loaded, the issue is very frequent in MV3 - remotePort.postMessage({ name: 'CONNECTION_READY' }); - } - }, - ); - return; - } - ///: END:ONLY_INCLUDE_IF - const processName = remotePort.name; if (metamaskBlockedPorts.includes(remotePort.name)) { @@ -657,9 +655,9 @@ export function setupController( controller.setupTrustedCommunication(portStream, remotePort.sender); if (processName === ENVIRONMENT_TYPE_POPUP) { - popupIsOpen = true; - endOfStream(portStream, () => { - popupIsOpen = false; + openPopupCount += 1; + finished(portStream, () => { + openPopupCount -= 1; const isClientOpen = isClientOpenStatus(); controller.isClientOpen = isClientOpen; onCloseEnvironmentInstances(isClientOpen, ENVIRONMENT_TYPE_POPUP); @@ -669,7 +667,7 @@ export function setupController( if (processName === ENVIRONMENT_TYPE_NOTIFICATION) { notificationIsOpen = true; - endOfStream(portStream, () => { + finished(portStream, () => { notificationIsOpen = false; const isClientOpen = isClientOpenStatus(); controller.isClientOpen = isClientOpen; @@ -684,7 +682,7 @@ export function setupController( const tabId = remotePort.sender.tab.id; openMetamaskTabsIDs[tabId] = true; - endOfStream(portStream, () => { + finished(portStream, () => { delete openMetamaskTabsIDs[tabId]; const isClientOpen = isClientOpenStatus(); controller.isClientOpen = isClientOpen; @@ -748,16 +746,6 @@ export function setupController( // communication with page or other extension connectExternal = (remotePort) => { - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - if ( - DesktopManager.isDesktopEnabled() && - OVERRIDE_ORIGIN.DESKTOP !== overrides?.getOrigin?.() - ) { - DesktopManager.createStream(remotePort, CONNECTION_TYPE_EXTERNAL); - return; - } - ///: END:ONLY_INCLUDE_IF - const portStream = overrides?.getPortStream?.(remotePort) || new PortStream(remotePort); controller.setupUntrustedCommunication({ @@ -797,6 +785,26 @@ export function setupController( updateBadge, ); + controller.controllerMessenger.subscribe( + METAMASK_CONTROLLER_EVENTS.QUEUED_REQUEST_STATE_CHANGE, + updateBadge, + ); + + controller.controllerMessenger.subscribe( + METAMASK_CONTROLLER_EVENTS.METAMASK_NOTIFICATIONS_LIST_UPDATED, + updateBadge, + ); + + controller.controllerMessenger.subscribe( + METAMASK_CONTROLLER_EVENTS.METAMASK_NOTIFICATIONS_MARK_AS_READ, + updateBadge, + ); + + controller.controllerMessenger.subscribe( + METAMASK_CONTROLLER_EVENTS.NOTIFICATIONS_STATE_CHANGE, + updateBadge, + ); + controller.txController.initApprovals(); /** @@ -804,54 +812,98 @@ export function setupController( * The number reflects the current number of pending transactions or message signatures needing user approval. */ function updateBadge() { + const pendingApprovalCount = getPendingApprovalCount(); + const unreadNotificationsCount = getUnreadNotificationsCount(); + let label = ''; - const count = getUnapprovedTransactionCount(); - if (count) { - label = String(count); + let badgeColor = BADGE_COLOR_APPROVAL; + + if (pendingApprovalCount) { + label = BADGE_LABEL_APPROVAL; + } else if (unreadNotificationsCount > 0) { + label = + unreadNotificationsCount > BADGE_MAX_NOTIFICATION_COUNT + ? `${BADGE_MAX_NOTIFICATION_COUNT}+` + : String(unreadNotificationsCount); + badgeColor = BADGE_COLOR_NOTIFICATION; } - // browserAction has been replaced by action in MV3 - if (isManifestV3) { - browser.action.setBadgeText({ text: label }); - browser.action.setBadgeBackgroundColor({ color: '#037DD6' }); - } else { - browser.browserAction.setBadgeText({ text: label }); - browser.browserAction.setBadgeBackgroundColor({ color: '#037DD6' }); + + try { + const badgeText = { text: label }; + const badgeBackgroundColor = { color: badgeColor }; + + if (isManifestV3) { + browser.action.setBadgeText(badgeText); + browser.action.setBadgeBackgroundColor(badgeBackgroundColor); + } else { + browser.browserAction.setBadgeText(badgeText); + browser.browserAction.setBadgeBackgroundColor(badgeBackgroundColor); + } + } catch (error) { + console.error('Error updating browser badge:', error); } } - function getUnapprovedTransactionCount() { - let count = controller.appStateController.waitingForUnlock.length; - if (controller.preferencesController.getUseRequestQueue()) { - count += controller.queuedRequestController.length(); - } else { - count += controller.approvalController.getTotalApprovalCount(); + function getPendingApprovalCount() { + try { + let pendingApprovalCount = + controller.appStateController.waitingForUnlock.length + + controller.approvalController.getTotalApprovalCount(); + + if (controller.preferencesController.getUseRequestQueue()) { + pendingApprovalCount += + controller.queuedRequestController.state.queuedRequestCount; + } + return pendingApprovalCount; + } catch (error) { + console.error('Failed to get pending approval count:', error); + return 0; } - return count; } - controller.controllerMessenger.subscribe( - 'QueuedRequestController:countChanged', - (count) => { - updateBadge(); - if (count > 0) { - triggerUi(); - } - }, - ); + function getUnreadNotificationsCount() { + try { + const { isMetamaskNotificationsEnabled, isFeatureAnnouncementsEnabled } = + controller.metamaskNotificationsController.state; + + const snapNotificationCount = Object.values( + controller.notificationController.state.notifications, + ).filter((notification) => notification.readDate === null).length; + + const featureAnnouncementCount = isFeatureAnnouncementsEnabled + ? controller.metamaskNotificationsController.state.metamaskNotificationsList.filter( + (notification) => + !notification.isRead && + notification.type === TRIGGER_TYPES.FEATURES_ANNOUNCEMENT, + ).length + : 0; + + const walletNotificationCount = isMetamaskNotificationsEnabled + ? controller.metamaskNotificationsController.state.metamaskNotificationsList.filter( + (notification) => + !notification.isRead && + notification.type !== TRIGGER_TYPES.FEATURES_ANNOUNCEMENT, + ).length + : 0; + + const unreadNotificationsCount = + snapNotificationCount + + featureAnnouncementCount + + walletNotificationCount; + + return unreadNotificationsCount; + } catch (error) { + console.error('Failed to get unread notifications count:', error); + return 0; + } + } notificationManager.on( NOTIFICATION_MANAGER_EVENTS.POPUP_CLOSED, ({ automaticallyClosed }) => { - if (controller.preferencesController.getUseRequestQueue()) { - // when the feature flag is on, rejecting unnapproved notifications in this way does nothing (since the controllers havent seen the requests yet) - // Also, the updating of badge / triggering of UI happens from the countChanged event when the feature flag is on, so we dont need that here either. - // The only thing that we might want to add here is possibly calling a method to empty the queue / do the same thing as rejecting all confirmed? - return; - } - if (!automaticallyClosed) { rejectUnapprovedNotifications(); - } else if (getUnapprovedTransactionCount() > 0) { + } else if (getPendingApprovalCount() > 0) { triggerUi(); } @@ -901,14 +953,6 @@ export function setupController( ); } - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - if (OVERRIDE_ORIGIN.DESKTOP !== overrides?.getOrigin?.()) { - controller.store.subscribe((state) => { - DesktopManager.setState(state); - }); - } - ///: END:ONLY_INCLUDE_IF - ///: BEGIN:ONLY_INCLUDE_IF(snaps) // Updates the snaps registry and check for newly blocked snaps to block if the user has at least one snap installed that isn't preinstalled. if ( @@ -933,7 +977,7 @@ async function triggerUi() { const currentlyActiveMetamaskTab = Boolean( tabs.find((tab) => openMetamaskTabsIDs[tab.id]), ); - // Vivaldi is not closing port connection on popup close, so popupIsOpen does not work correctly + // Vivaldi is not closing port connection on popup close, so openPopupCount does not work correctly // To be reviewed in the future if this behaviour is fixed - also the way we determine isVivaldi variable might change at some point const isVivaldi = tabs.length > 0 && @@ -941,7 +985,7 @@ async function triggerUi() { tabs[0].extData.indexOf('vivaldi_tab') > -1; if ( !uiIsTriggering && - (isVivaldi || !popupIsOpen) && + (isVivaldi || openPopupCount === 0) && !currentlyActiveMetamaskTab ) { uiIsTriggering = true; @@ -976,7 +1020,7 @@ const addAppInstalledEvent = () => { setTimeout(() => { // If the controller is not set yet, we wait and try to add the "App Installed" event again. addAppInstalledEvent(); - }, 1000); + }, 500); }; // On first install, open a new tab with MetaMask diff --git a/app/scripts/constants/contracts.ts b/app/scripts/constants/contracts.ts index 27fa0606dfba..bc27be31d95c 100644 --- a/app/scripts/constants/contracts.ts +++ b/app/scripts/constants/contracts.ts @@ -12,4 +12,9 @@ export const SINGLE_CALL_BALANCES_ADDRESSES = { [CHAIN_IDS.FANTOM]: '0x07f697424ABe762bB808c109860c04eA488ff92B', [CHAIN_IDS.ARBITRUM]: '0x151E24A486D7258dd7C33Fb67E4bB01919B7B32c', [CHAIN_IDS.BLAST]: '0xfd5730e96f9dffae40d99b77015bd42816280998', + [CHAIN_IDS.LINEA_GOERLI]: '0x10dAd7Ca3921471f616db788D9300DC97Db01783', + [CHAIN_IDS.LINEA_MAINNET]: '0xF62e6a41561b3650a69Bb03199C735e3E3328c0D', + [CHAIN_IDS.AURORA]: '0x1286415D333855237f89Df27D388127181448538', + [CHAIN_IDS.BASE]: '0x6AA75276052D96696134252587894ef5FFA520af', + [CHAIN_IDS.ZKSYNC_ERA]: '0x458fEd3144680a5b8bcfaa0F9594aa19B4Ea2D34', }; diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index 8d63ec70ac5e..ab2483c9f9a3 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -1,12 +1,13 @@ import { WindowPostMessageStream } from '@metamask/post-message-stream'; import PortStream from 'extension-port-stream'; -import ObjectMultiplex from 'obj-multiplex'; -import pump from 'pump'; -import { obj as createThoughStream } from 'through2'; +import ObjectMultiplex from '@metamask/object-multiplex'; +import { pipeline, Transform } from 'readable-stream'; import browser from 'webextension-polyfill'; import { EXTENSION_MESSAGES } from '../../shared/constants/app'; -import { checkForLastError } from '../../shared/modules/browser-runtime.utils'; -import { isManifestV3 } from '../../shared/modules/mv3.utils'; +import { + checkForLastError, + getIsBrowserPrerenderBroken, +} from '../../shared/modules/browser-runtime.utils'; import shouldInjectProvider from '../../shared/modules/provider-injection'; // contexts @@ -67,7 +68,7 @@ function setupPhishingPageStreams() { phishingPageMux = new ObjectMultiplex(); phishingPageMux.setMaxListeners(25); - pump(phishingPageMux, phishingPageStream, phishingPageMux, (err) => + pipeline(phishingPageMux, phishingPageStream, phishingPageMux, (err) => logStreamDisconnectWarning('MetaMask Inpage Multiplex', err), ); @@ -85,14 +86,14 @@ const setupPhishingExtStreams = () => { phishingExtMux = new ObjectMultiplex(); phishingExtMux.setMaxListeners(25); - pump(phishingExtMux, phishingExtStream, phishingExtMux, (err) => { + pipeline(phishingExtMux, phishingExtStream, phishingExtMux, (err) => { logStreamDisconnectWarning('MetaMask Background Multiplex', err); window.postMessage( { target: PHISHING_WARNING_PAGE, // the post-message-stream "target" data: { - // this object gets passed to obj-multiplex - name: PHISHING_SAFELIST, // the obj-multiplex channel name + // this object gets passed to @metamask/object-multiplex + name: PHISHING_SAFELIST, // the @metamask/object-multiplex channel name data: { jsonrpc: '2.0', method: 'METAMASK_STREAM_FAILURE', @@ -105,11 +106,15 @@ const setupPhishingExtStreams = () => { // forward communication across inpage-background for these channels only phishingExtChannel = phishingExtMux.createStream(PHISHING_SAFELIST); - pump(phishingPageChannel, phishingExtChannel, phishingPageChannel, (error) => - console.debug( - `MetaMask: Muxed traffic for channel "${PHISHING_SAFELIST}" failed.`, - error, - ), + pipeline( + phishingPageChannel, + phishingExtChannel, + phishingPageChannel, + (error) => + console.debug( + `MetaMask: Muxed traffic for channel "${PHISHING_SAFELIST}" failed.`, + error, + ), ); // eslint-disable-next-line no-use-before-define @@ -203,7 +208,7 @@ const setupPageStreams = () => { pageMux = new ObjectMultiplex(); pageMux.setMaxListeners(25); - pump(pageMux, pageStream, pageMux, (err) => + pipeline(pageMux, pageStream, pageMux, (err) => logStreamDisconnectWarning('MetaMask Inpage Multiplex', err), ); @@ -225,14 +230,14 @@ const setupExtensionStreams = () => { extensionMux.setMaxListeners(25); extensionMux.ignoreStream(LEGACY_PUBLIC_CONFIG); // TODO:LegacyProvider: Delete - pump(extensionMux, extensionStream, extensionMux, (err) => { + pipeline(extensionMux, extensionStream, extensionMux, (err) => { logStreamDisconnectWarning('MetaMask Background Multiplex', err); notifyInpageOfStreamFailure(); }); // forward communication across inpage-background for these channels only extensionChannel = extensionMux.createStream(PROVIDER); - pump(pageChannel, extensionChannel, pageChannel, (error) => + pipeline(pageChannel, extensionChannel, pageChannel, (error) => console.debug( `MetaMask: Muxed traffic for channel "${PROVIDER}" failed.`, error, @@ -275,7 +280,7 @@ const setupLegacyPageStreams = () => { legacyPageMux = new ObjectMultiplex(); legacyPageMux.setMaxListeners(25); - pump(legacyPageMux, legacyPageStream, legacyPageMux, (err) => + pipeline(legacyPageMux, legacyPageStream, legacyPageMux, (err) => logStreamDisconnectWarning('MetaMask Legacy Inpage Multiplex', err), ); @@ -291,7 +296,7 @@ const setupLegacyExtensionStreams = () => { legacyExtMux.setMaxListeners(25); notificationTransformStream = getNotificationTransformStream(); - pump( + pipeline( legacyExtMux, extensionStream, notificationTransformStream, @@ -303,7 +308,7 @@ const setupLegacyExtensionStreams = () => { ); legacyExtChannel = legacyExtMux.createStream(PROVIDER); - pump( + pipeline( legacyPageMuxLegacyProviderChannel, legacyExtChannel, legacyPageMuxLegacyProviderChannel, @@ -316,7 +321,7 @@ const setupLegacyExtensionStreams = () => { legacyExtPublicConfigChannel = legacyExtMux.createStream(LEGACY_PUBLIC_CONFIG); - pump( + pipeline( legacyPagePublicConfigChannel, legacyExtPublicConfigChannel, legacyPagePublicConfigChannel, @@ -409,16 +414,21 @@ const initStreams = () => { // TODO:LegacyProvider: Delete function getNotificationTransformStream() { - return createThoughStream((chunk, _, cb) => { - if (chunk?.name === PROVIDER) { - if (chunk.data?.method === 'metamask_accountsChanged') { - chunk.data.method = 'wallet_accountsChanged'; - chunk.data.result = chunk.data.params; - delete chunk.data.params; + const stream = new Transform({ + highWaterMark: 16, + objectMode: true, + transform: (chunk, _, cb) => { + if (chunk?.name === PROVIDER) { + if (chunk.data?.method === 'metamask_accountsChanged') { + chunk.data.method = 'wallet_accountsChanged'; + chunk.data.result = chunk.data.params; + delete chunk.data.params; + } } - } - cb(null, chunk); + cb(null, chunk); + }, }); + return stream; } /** @@ -445,7 +455,6 @@ function logStreamDisconnectWarning(remoteLabel, error) { function extensionStreamMessageListener(msg) { if ( METAMASK_EXTENSION_CONNECT_SENT && - isManifestV3 && msg.data.method === 'metamask_chainChanged' ) { METAMASK_EXTENSION_CONNECT_SENT = false; @@ -453,8 +462,8 @@ function extensionStreamMessageListener(msg) { { target: INPAGE, // the post-message-stream "target" data: { - // this object gets passed to obj-multiplex - name: PROVIDER, // the obj-multiplex channel name + // this object gets passed to @metamask/object-multiplex + name: PROVIDER, // the @metamask/object-multiplex channel name data: { jsonrpc: '2.0', method: 'METAMASK_EXTENSION_CONNECT_CAN_RETRY', @@ -467,17 +476,17 @@ function extensionStreamMessageListener(msg) { } /** - * This function must ONLY be called in pump destruction/close callbacks. + * This function must ONLY be called in pipeline destruction/close callbacks. * Notifies the inpage context that streams have failed, via window.postMessage. - * Relies on obj-multiplex and post-message-stream implementation details. + * Relies on @metamask/object-multiplex and post-message-stream implementation details. */ function notifyInpageOfStreamFailure() { window.postMessage( { target: INPAGE, // the post-message-stream "target" data: { - // this object gets passed to obj-multiplex - name: PROVIDER, // the obj-multiplex channel name + // this object gets passed to @metamask/object-multiplex + name: PROVIDER, // the @metamask/object-multiplex channel name data: { jsonrpc: '2.0', method: 'METAMASK_STREAM_FAILURE', @@ -519,11 +528,7 @@ const start = () => { if (shouldInjectProvider()) { initStreams(); - // https://bugs.chromium.org/p/chromium/issues/detail?id=1457040 - // Temporary workaround for chromium bug that breaks the content script <=> background connection - // for prerendered pages. This resets potentially broken extension streams if a page transitions - // from the prerendered state to the active state. - if (document.prerendering) { + if (document.prerendering && getIsBrowserPrerenderBroken()) { document.addEventListener('prerenderingchange', () => { onDisconnectDestroyStreams( new Error('Prerendered page has become active.'), diff --git a/app/scripts/controllers/app-metadata.test.ts b/app/scripts/controllers/app-metadata.test.ts index 890811ee212c..c5041aad623a 100644 --- a/app/scripts/controllers/app-metadata.test.ts +++ b/app/scripts/controllers/app-metadata.test.ts @@ -1,4 +1,3 @@ -import assert from 'assert'; import AppMetadataController from './app-metadata'; const EXPECTED_DEFAULT_STATE = { @@ -6,6 +5,7 @@ const EXPECTED_DEFAULT_STATE = { previousAppVersion: '', previousMigrationVersion: 0, currentMigrationVersion: 0, + showTokenAutodetectModalOnUpgrade: false, }; describe('AppMetadataController', () => { @@ -16,21 +16,21 @@ describe('AppMetadataController', () => { previousAppVersion: '1', previousMigrationVersion: 1, currentMigrationVersion: 1, + showTokenAutodetectModalOnUpgrade: false, }; const appMetadataController = new AppMetadataController({ state: initState, currentMigrationVersion: 1, currentAppVersion: '1', }); - assert.deepStrictEqual(appMetadataController.store.getState(), initState); + expect(appMetadataController.store.getState()).toStrictEqual(initState); }); it('sets default state and does not modify it', async () => { const appMetadataController = new AppMetadataController({ state: {}, }); - assert.deepStrictEqual( - appMetadataController.store.getState(), + expect(appMetadataController.store.getState()).toStrictEqual( EXPECTED_DEFAULT_STATE, ); }); @@ -41,8 +41,7 @@ describe('AppMetadataController', () => { currentMigrationVersion: 0, currentAppVersion: '', }); - assert.deepStrictEqual( - appMetadataController.store.getState(), + expect(appMetadataController.store.getState()).toStrictEqual( EXPECTED_DEFAULT_STATE, ); }); @@ -53,9 +52,10 @@ describe('AppMetadataController', () => { currentMigrationVersion: 0, currentAppVersion: '1', }); - assert.deepStrictEqual(appMetadataController.store.getState(), { + expect(appMetadataController.store.getState()).toStrictEqual({ ...EXPECTED_DEFAULT_STATE, currentAppVersion: '1', + showTokenAutodetectModalOnUpgrade: null, }); }); @@ -68,10 +68,11 @@ describe('AppMetadataController', () => { currentAppVersion: '3', currentMigrationVersion: 0, }); - assert.deepStrictEqual(appMetadataController.store.getState(), { + expect(appMetadataController.store.getState()).toStrictEqual({ ...EXPECTED_DEFAULT_STATE, currentAppVersion: '3', previousAppVersion: '2', + showTokenAutodetectModalOnUpgrade: null, }); }); @@ -80,7 +81,7 @@ describe('AppMetadataController', () => { state: {}, currentMigrationVersion: 1, }); - assert.deepStrictEqual(appMetadataController.store.getState(), { + expect(appMetadataController.store.getState()).toStrictEqual({ ...EXPECTED_DEFAULT_STATE, currentMigrationVersion: 1, }); @@ -94,7 +95,7 @@ describe('AppMetadataController', () => { }, currentMigrationVersion: 3, }); - assert.deepStrictEqual(appMetadataController.store.getState(), { + expect(appMetadataController.store.getState()).toStrictEqual({ ...EXPECTED_DEFAULT_STATE, currentMigrationVersion: 3, previousMigrationVersion: 2, diff --git a/app/scripts/controllers/app-metadata.ts b/app/scripts/controllers/app-metadata.ts index 0d745730d0c0..79d346c8412d 100644 --- a/app/scripts/controllers/app-metadata.ts +++ b/app/scripts/controllers/app-metadata.ts @@ -9,6 +9,7 @@ export type AppMetadataControllerState = { previousAppVersion: string; previousMigrationVersion: number; currentMigrationVersion: number; + showTokenAutodetectModalOnUpgrade: boolean | null; }; /** @@ -25,6 +26,7 @@ const defaultState: AppMetadataControllerState = { previousAppVersion: '', previousMigrationVersion: 0, currentMigrationVersion: 0, + showTokenAutodetectModalOnUpgrade: false, }; /** @@ -76,6 +78,7 @@ export default class AppMetadataController extends EventEmitter { this.store.updateState({ currentAppVersion: maybeNewAppVersion, previousAppVersion: oldCurrentAppVersion, + showTokenAutodetectModalOnUpgrade: null, }); } } @@ -96,4 +99,13 @@ export default class AppMetadataController extends EventEmitter { }); } } + + /** + * Setter for the `showTokenAutodetectModalOnUpgrade` property + * + * @param val - Indicates the value of showTokenAutodetectModalOnUpgrade + */ + setShowTokenAutodetectModalOnUpgrade(val: boolean): void { + this.store.updateState({ showTokenAutodetectModalOnUpgrade: val }); + } } diff --git a/app/scripts/controllers/app-state.d.ts b/app/scripts/controllers/app-state.d.ts new file mode 100644 index 000000000000..aa7ffc92eb3c --- /dev/null +++ b/app/scripts/controllers/app-state.d.ts @@ -0,0 +1,24 @@ +import { SecurityAlertResponse } from '../lib/ppom/types'; + +export type AppStateController = { + addSignatureSecurityAlertResponse( + securityAlertResponse: SecurityAlertResponse, + ): void; + getUnlockPromise(shouldShowUnlockRequest: boolean): Promise; + ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) + setCustodianDeepLink({ + fromAddress, + custodyId, + }: { + fromAddress: string; + custodyId: string; + }): void; + showInteractiveReplacementTokenBanner({ + oldRefreshToken, + url, + }: { + oldRefreshToken: string; + url: string; + }): void; + ///: END:ONLY_INCLUDE_IF +}; diff --git a/app/scripts/controllers/app-state.js b/app/scripts/controllers/app-state.js index 44d1a367362e..256dfba38438 100644 --- a/app/scripts/controllers/app-state.js +++ b/app/scripts/controllers/app-state.js @@ -48,11 +48,13 @@ export default class AppStateController extends EventEmitter { showTestnetMessageInDropdown: true, showBetaHeader: isBeta(), showPermissionsTour: true, - showProductTour: true, showNetworkBanner: true, showAccountBanner: true, trezorModel: null, currentPopupId: undefined, + onboardingDate: null, + newPrivacyPolicyToastClickedOrClosed: null, + newPrivacyPolicyToastShownDate: null, // This key is only used for checking if the user had set advancedGasFee // prior to Migration 92.3 where we split out the setting to support // multiple networks. @@ -67,6 +69,10 @@ export default class AppStateController extends EventEmitter { }, surveyLinkLastClickedOrClosed: null, signatureSecurityAlertResponses: {}, + // States used for displaying the changed network toast + switchedNetworkDetails: null, + switchedNetworkNeverShowMessage: false, + currentExtensionPopupId: 0, }); this.timer = null; @@ -181,6 +187,24 @@ export default class AppStateController extends EventEmitter { }); } + setOnboardingDate() { + this.store.updateState({ + onboardingDate: Date.now(), + }); + } + + setNewPrivacyPolicyToastClickedOrClosed() { + this.store.updateState({ + newPrivacyPolicyToastClickedOrClosed: true, + }); + } + + setNewPrivacyPolicyToastShownDate(time) { + this.store.updateState({ + newPrivacyPolicyToastShownDate: time, + }); + } + /** * Record the timestamp of the last time the user has seen the recovery phrase reminder * @@ -271,10 +295,19 @@ export default class AppStateController extends EventEmitter { return; } + // This is a temporary fix until we add a state migration. + // Due to a bug in ui/pages/settings/advanced-tab/advanced-tab.component.js, + // it was possible for timeoutMinutes to be saved as a string, as explained + // in PR 25109. `alarms.create` will fail in that case. We are + // converting this to a number here to prevent that failure. Once + // we add a migration to update the malformed state to the right type, + // we will remove this conversion. + const timeoutToSet = Number(timeoutMinutes); + if (isManifestV3) { this.extension.alarms.create(AUTO_LOCK_TIMEOUT_ALARM, { - delayInMinutes: timeoutMinutes, - periodInMinutes: timeoutMinutes, + delayInMinutes: timeoutToSet, + periodInMinutes: timeoutToSet, }); this.extension.alarms.onAlarm.addListener((alarmInfo) => { if (alarmInfo.name === AUTO_LOCK_TIMEOUT_ALARM) { @@ -285,7 +318,7 @@ export default class AppStateController extends EventEmitter { } else { this.timer = setTimeout( () => this.onInactiveTimeout(), - timeoutMinutes * MINUTE, + timeoutToSet * MINUTE, ); } } @@ -374,15 +407,6 @@ export default class AppStateController extends EventEmitter { this.store.updateState({ showPermissionsTour }); } - /** - * Sets whether the product tour should be shown - * - * @param showProductTour - */ - setShowProductTour(showProductTour) { - this.store.updateState({ showProductTour }); - } - /** * Sets whether the Network Banner should be shown * @@ -401,6 +425,45 @@ export default class AppStateController extends EventEmitter { this.store.updateState({ showAccountBanner }); } + /** + * Sets a unique ID for the current extension popup + * + * @param currentExtensionPopupId + */ + setCurrentExtensionPopupId(currentExtensionPopupId) { + this.store.updateState({ currentExtensionPopupId }); + } + + /** + * Sets an object with networkName and appName + * or `null` if the message is meant to be cleared + * + * @param {{ origin: string, networkClientId: string } | null} switchedNetworkDetails - Details about the network that MetaMask just switched to. + */ + setSwitchedNetworkDetails(switchedNetworkDetails) { + this.store.updateState({ switchedNetworkDetails }); + } + + /** + * Clears the switched network details in state + */ + clearSwitchedNetworkDetails() { + this.store.updateState({ switchedNetworkDetails: null }); + } + + /** + * Remembers if the user prefers to never see the + * network switched message again + * + * @param {boolean} switchedNetworkNeverShowMessage + */ + setSwitchedNetworkNeverShowMessage(switchedNetworkNeverShowMessage) { + this.store.updateState({ + switchedNetworkDetails: null, + switchedNetworkNeverShowMessage, + }); + } + /** * Sets a property indicating the model of the user's Trezor hardware wallet * diff --git a/app/scripts/controllers/authentication/auth-snap-requests.ts b/app/scripts/controllers/authentication/auth-snap-requests.ts new file mode 100644 index 000000000000..81c8beaafd40 --- /dev/null +++ b/app/scripts/controllers/authentication/auth-snap-requests.ts @@ -0,0 +1,32 @@ +import type { SnapId } from '@metamask/snaps-sdk'; +import type { HandleSnapRequest } from '@metamask/snaps-controllers'; +import { HandlerType } from '@metamask/snaps-utils'; + +type SnapRPCRequest = Parameters[0]; + +const snapId = 'npm:@metamask/message-signing-snap' as SnapId; + +export function createSnapPublicKeyRequest(): SnapRPCRequest { + return { + snapId, + origin: '', + handler: HandlerType.OnRpcRequest, + request: { + method: 'getPublicKey', + }, + }; +} + +export function createSnapSignMessageRequest( + message: `metamask:${string}`, +): SnapRPCRequest { + return { + snapId, + origin: '', + handler: HandlerType.OnRpcRequest, + request: { + method: 'signMessage', + params: { message }, + }, + }; +} diff --git a/app/scripts/controllers/authentication/authentication-controller.test.ts b/app/scripts/controllers/authentication/authentication-controller.test.ts new file mode 100644 index 000000000000..e13b999de517 --- /dev/null +++ b/app/scripts/controllers/authentication/authentication-controller.test.ts @@ -0,0 +1,318 @@ +import { ControllerMessenger } from '@metamask/base-controller'; +import AuthenticationController, { + AllowedActions, + AuthenticationControllerState, +} from './authentication-controller'; +import { + mockEndpointAccessToken, + mockEndpointGetNonce, + mockEndpointLogin, +} from './mocks/mockServices'; +import { MOCK_ACCESS_TOKEN, MOCK_LOGIN_RESPONSE } from './mocks/mockResponses'; + +const mockSignedInState = (): AuthenticationControllerState => ({ + isSignedIn: true, + sessionData: { + accessToken: 'MOCK_ACCESS_TOKEN', + expiresIn: new Date().toString(), + profile: { + identifierId: MOCK_LOGIN_RESPONSE.profile.identifier_id, + profileId: MOCK_LOGIN_RESPONSE.profile.profile_id, + }, + }, +}); + +describe('authentication/authentication-controller - constructor() tests', () => { + test('should initialize with default state', () => { + const metametrics = createMockAuthMetaMetrics(); + const controller = new AuthenticationController({ + messenger: createAuthenticationMessenger(), + metametrics, + }); + + expect(controller.state.isSignedIn).toBe(false); + expect(controller.state.sessionData).toBeUndefined(); + }); + + test('should initialize with override state', () => { + const metametrics = createMockAuthMetaMetrics(); + const controller = new AuthenticationController({ + messenger: createAuthenticationMessenger(), + state: mockSignedInState(), + metametrics, + }); + + expect(controller.state.isSignedIn).toBe(true); + expect(controller.state.sessionData).toBeDefined(); + }); +}); + +describe('authentication/authentication-controller - performSignIn() tests', () => { + test('Should create access token and update state', async () => { + const metametrics = createMockAuthMetaMetrics(); + const mockEndpoints = mockAuthenticationFlowEndpoints(); + const { messenger, mockSnapGetPublicKey, mockSnapSignMessage } = + createMockAuthenticationMessenger(); + + const controller = new AuthenticationController({ messenger, metametrics }); + + const result = await controller.performSignIn(); + expect(mockSnapGetPublicKey).toBeCalled(); + expect(mockSnapSignMessage).toBeCalled(); + mockEndpoints.mockGetNonceEndpoint.done(); + mockEndpoints.mockLoginEndpoint.done(); + mockEndpoints.mockAccessTokenEndpoint.done(); + expect(result).toBe(MOCK_ACCESS_TOKEN); + + // Assert - state shows user is logged in + expect(controller.state.isSignedIn).toBe(true); + expect(controller.state.sessionData).toBeDefined(); + }); + + test('Should error when nonce endpoint fails', async () => { + await testAndAssertFailingEndpoints('nonce'); + }); + + test('Should error when login endpoint fails', async () => { + await testAndAssertFailingEndpoints('login'); + }); + + test('Should error when tokens endpoint fails', async () => { + await testAndAssertFailingEndpoints('token'); + }); + + async function testAndAssertFailingEndpoints( + endpointFail: 'nonce' | 'login' | 'token', + ) { + const mockEndpoints = mockAuthenticationFlowEndpoints({ + endpointFail, + }); + const { messenger } = createMockAuthenticationMessenger(); + const metametrics = createMockAuthMetaMetrics(); + const controller = new AuthenticationController({ messenger, metametrics }); + + await expect(controller.performSignIn()).rejects.toThrow(); + expect(controller.state.isSignedIn).toBe(false); + + const endpointsCalled = [ + mockEndpoints.mockGetNonceEndpoint.isDone(), + mockEndpoints.mockLoginEndpoint.isDone(), + mockEndpoints.mockAccessTokenEndpoint.isDone(), + ]; + if (endpointFail === 'nonce') { + expect(endpointsCalled).toEqual([true, false, false]); + } + + if (endpointFail === 'login') { + expect(endpointsCalled).toEqual([true, true, false]); + } + + if (endpointFail === 'token') { + expect(endpointsCalled).toEqual([true, true, true]); + } + } +}); + +describe('authentication/authentication-controller - performSignOut() tests', () => { + test('Should remove signed in user and any access tokens', () => { + const metametrics = createMockAuthMetaMetrics(); + const { messenger } = createMockAuthenticationMessenger(); + const controller = new AuthenticationController({ + messenger, + state: mockSignedInState(), + metametrics, + }); + + controller.performSignOut(); + expect(controller.state.isSignedIn).toBe(false); + expect(controller.state.sessionData).toBeUndefined(); + }); + + test('Should throw error if attempting to sign out when user is not logged in', () => { + const metametrics = createMockAuthMetaMetrics(); + const { messenger } = createMockAuthenticationMessenger(); + const controller = new AuthenticationController({ + messenger, + state: { isSignedIn: false }, + metametrics, + }); + + expect(() => controller.performSignOut()).toThrow(); + }); +}); + +describe('authentication/authentication-controller - getBearerToken() tests', () => { + test('Should throw error if not logged in', async () => { + const metametrics = createMockAuthMetaMetrics(); + const { messenger } = createMockAuthenticationMessenger(); + const controller = new AuthenticationController({ + messenger, + state: { isSignedIn: false }, + metametrics, + }); + + await expect(controller.getBearerToken()).rejects.toThrow(); + }); + + test('Should return original access token in state', async () => { + const metametrics = createMockAuthMetaMetrics(); + const { messenger } = createMockAuthenticationMessenger(); + const originalState = mockSignedInState(); + const controller = new AuthenticationController({ + messenger, + state: originalState, + metametrics, + }); + + const result = await controller.getBearerToken(); + expect(result).toBeDefined(); + expect(result).toBe(originalState.sessionData?.accessToken); + }); + + test('Should return new access token if state is invalid', async () => { + const metametrics = createMockAuthMetaMetrics(); + const { messenger } = createMockAuthenticationMessenger(); + mockAuthenticationFlowEndpoints(); + const originalState = mockSignedInState(); + if (originalState.sessionData) { + originalState.sessionData.accessToken = 'ACCESS_TOKEN_1'; + + const d = new Date(); + d.setMinutes(d.getMinutes() - 31); // expires at 30 mins + originalState.sessionData.expiresIn = d.toString(); + } + + const controller = new AuthenticationController({ + messenger, + state: originalState, + metametrics, + }); + + const result = await controller.getBearerToken(); + expect(result).toBeDefined(); + expect(result).toBe(MOCK_ACCESS_TOKEN); + }); +}); + +describe('authentication/authentication-controller - getSessionProfile() tests', () => { + test('Should throw error if not logged in', async () => { + const metametrics = createMockAuthMetaMetrics(); + const { messenger } = createMockAuthenticationMessenger(); + const controller = new AuthenticationController({ + messenger, + state: { isSignedIn: false }, + metametrics, + }); + + await expect(controller.getSessionProfile()).rejects.toThrow(); + }); + + test('Should return original access token in state', async () => { + const metametrics = createMockAuthMetaMetrics(); + const { messenger } = createMockAuthenticationMessenger(); + const originalState = mockSignedInState(); + const controller = new AuthenticationController({ + messenger, + state: originalState, + metametrics, + }); + + const result = await controller.getSessionProfile(); + expect(result).toBeDefined(); + expect(result).toEqual(originalState.sessionData?.profile); + }); + + test('Should return new access token if state is invalid', async () => { + const metametrics = createMockAuthMetaMetrics(); + const { messenger } = createMockAuthenticationMessenger(); + mockAuthenticationFlowEndpoints(); + const originalState = mockSignedInState(); + if (originalState.sessionData) { + originalState.sessionData.profile.identifierId = 'ID_1'; + + const d = new Date(); + d.setMinutes(d.getMinutes() - 31); // expires at 30 mins + originalState.sessionData.expiresIn = d.toString(); + } + + const controller = new AuthenticationController({ + messenger, + state: originalState, + metametrics, + }); + + const result = await controller.getSessionProfile(); + expect(result).toBeDefined(); + expect(result.identifierId).toBe(MOCK_LOGIN_RESPONSE.profile.identifier_id); + expect(result.profileId).toBe(MOCK_LOGIN_RESPONSE.profile.profile_id); + }); +}); + +function createAuthenticationMessenger() { + const messenger = new ControllerMessenger(); + return messenger.getRestricted({ + name: 'AuthenticationController', + allowedActions: [`SnapController:handleRequest`], + allowedEvents: [], + }); +} + +function createMockAuthenticationMessenger() { + const messenger = createAuthenticationMessenger(); + const mockCall = jest.spyOn(messenger, 'call'); + const mockSnapGetPublicKey = jest.fn().mockResolvedValue('MOCK_PUBLIC_KEY'); + const mockSnapSignMessage = jest + .fn() + .mockResolvedValue('MOCK_SIGNED_MESSAGE'); + + mockCall.mockImplementation((...args) => { + const [actionType, params] = args; + if (actionType === 'SnapController:handleRequest') { + if (params?.request.method === 'getPublicKey') { + return mockSnapGetPublicKey(); + } + + if (params?.request.method === 'signMessage') { + return mockSnapSignMessage(); + } + + throw new Error( + `MOCK_FAIL - unsupported SnapController:handleRequest call: ${params?.request.method}`, + ); + } + + function exhaustedMessengerMocks(action: never) { + throw new Error(`MOCK_FAIL - unsupported messenger call: ${action}`); + } + + return exhaustedMessengerMocks(actionType); + }); + + return { messenger, mockSnapGetPublicKey, mockSnapSignMessage }; +} + +function mockAuthenticationFlowEndpoints(params?: { + endpointFail: 'nonce' | 'login' | 'token'; +}) { + const mockGetNonceEndpoint = mockEndpointGetNonce( + params?.endpointFail === 'nonce' ? { status: 500 } : undefined, + ); + const mockLoginEndpoint = mockEndpointLogin( + params?.endpointFail === 'login' ? { status: 500 } : undefined, + ); + const mockAccessTokenEndpoint = mockEndpointAccessToken( + params?.endpointFail === 'token' ? { status: 500 } : undefined, + ); + + return { + mockGetNonceEndpoint, + mockLoginEndpoint, + mockAccessTokenEndpoint, + }; +} + +function createMockAuthMetaMetrics() { + const getMetaMetricsId = jest.fn().mockReturnValue('MOCK_METAMETRICS_ID'); + + return { getMetaMetricsId }; +} diff --git a/app/scripts/controllers/authentication/authentication-controller.ts b/app/scripts/controllers/authentication/authentication-controller.ts new file mode 100644 index 000000000000..24da63bd58bf --- /dev/null +++ b/app/scripts/controllers/authentication/authentication-controller.ts @@ -0,0 +1,326 @@ +import { + BaseController, + RestrictedControllerMessenger, + StateMetadata, +} from '@metamask/base-controller'; +import { HandleSnapRequest } from '@metamask/snaps-controllers'; +import { UserStorageControllerDisableProfileSyncing } from '../user-storage/user-storage-controller'; +import { + createSnapPublicKeyRequest, + createSnapSignMessageRequest, +} from './auth-snap-requests'; +import { + createLoginRawMessage, + getAccessToken, + getNonce, + login, +} from './services'; + +const THIRTY_MIN_MS = 1000 * 60 * 30; + +const controllerName = 'AuthenticationController'; + +// State +type SessionProfile = { + identifierId: string; + profileId: string; +}; + +type SessionData = { + /** profile - anonymous profile data for the given logged in user */ + profile: SessionProfile; + /** accessToken - used to make requests authorized endpoints */ + accessToken: string; + /** expiresIn - string date to determine if new access token is required */ + expiresIn: string; +}; + +type MetaMetricsAuth = { + getMetaMetricsId: () => string; +}; + +export type AuthenticationControllerState = { + /** + * Global isSignedIn state. + * Can be used to determine if "Profile Syncing" is enabled. + */ + isSignedIn: boolean; + sessionData?: SessionData; +}; +const defaultState: AuthenticationControllerState = { isSignedIn: false }; +const metadata: StateMetadata = { + isSignedIn: { + persist: true, + anonymous: true, + }, + sessionData: { + persist: true, + anonymous: false, + }, +}; + +// Messenger Actions +type CreateActionsObj = { + [K in T]: { + type: `${typeof controllerName}:${K}`; + handler: AuthenticationController[K]; + }; +}; +type ActionsObj = CreateActionsObj< + | 'performSignIn' + | 'performSignOut' + | 'getBearerToken' + | 'getSessionProfile' + | 'isSignedIn' +>; +export type Actions = ActionsObj[keyof ActionsObj]; +export type AuthenticationControllerPerformSignIn = ActionsObj['performSignIn']; +export type AuthenticationControllerPerformSignOut = + ActionsObj['performSignOut']; +export type AuthenticationControllerGetBearerToken = + ActionsObj['getBearerToken']; +export type AuthenticationControllerGetSessionProfile = + ActionsObj['getSessionProfile']; +export type AuthenticationControllerIsSignedIn = ActionsObj['isSignedIn']; + +// Allowed Actions +export type AllowedActions = + | HandleSnapRequest + | UserStorageControllerDisableProfileSyncing; + +// Messenger +export type AuthenticationControllerMessenger = RestrictedControllerMessenger< + typeof controllerName, + Actions | AllowedActions, + never, + AllowedActions['type'], + never +>; + +/** + * Controller that enables authentication for restricted endpoints. + * Used for Global Profile Syncing and Notifications + */ +export default class AuthenticationController extends BaseController< + typeof controllerName, + AuthenticationControllerState, + AuthenticationControllerMessenger +> { + #metametrics: MetaMetricsAuth; + + constructor({ + messenger, + state, + metametrics, + }: { + messenger: AuthenticationControllerMessenger; + state?: AuthenticationControllerState; + /** + * Not using the Messaging System as we + * do not want to tie this strictly to extension + */ + metametrics: MetaMetricsAuth; + }) { + super({ + messenger, + metadata, + name: controllerName, + state: { ...defaultState, ...state }, + }); + + this.#metametrics = metametrics; + + this.#registerMessageHandlers(); + } + + /** + * Constructor helper for registering this controller's messaging system + * actions. + */ + #registerMessageHandlers(): void { + this.messagingSystem.registerActionHandler( + 'AuthenticationController:getBearerToken', + this.getBearerToken.bind(this), + ); + + this.messagingSystem.registerActionHandler( + 'AuthenticationController:getSessionProfile', + this.getSessionProfile.bind(this), + ); + + this.messagingSystem.registerActionHandler( + 'AuthenticationController:isSignedIn', + this.isSignedIn.bind(this), + ); + + this.messagingSystem.registerActionHandler( + 'AuthenticationController:performSignIn', + this.performSignIn.bind(this), + ); + + this.messagingSystem.registerActionHandler( + 'AuthenticationController:performSignOut', + this.performSignOut.bind(this), + ); + } + + public async performSignIn(): Promise { + const { accessToken } = await this.#performAuthenticationFlow(); + return accessToken; + } + + public performSignOut(): void { + this.#assertLoggedIn(); + + this.update((state) => { + state.isSignedIn = false; + state.sessionData = undefined; + }); + } + + public async getBearerToken(): Promise { + this.#assertLoggedIn(); + + if (this.#hasValidSession(this.state.sessionData)) { + return this.state.sessionData.accessToken; + } + + const { accessToken } = await this.#performAuthenticationFlow(); + return accessToken; + } + + /** + * Will return a session profile. + * Throws if a user is not logged in. + * + * @returns profile for the session. + */ + public async getSessionProfile(): Promise { + this.#assertLoggedIn(); + + if (this.#hasValidSession(this.state.sessionData)) { + return this.state.sessionData.profile; + } + + const { profile } = await this.#performAuthenticationFlow(); + return profile; + } + + public isSignedIn(): boolean { + return this.state.isSignedIn; + } + + #assertLoggedIn(): void { + if (!this.state.isSignedIn) { + throw new Error( + `${controllerName}: Unable to call method, user is not authenticated`, + ); + } + } + + async #performAuthenticationFlow(): Promise<{ + profile: SessionProfile; + accessToken: string; + }> { + try { + // 1. Nonce + const publicKey = await this.#snapGetPublicKey(); + const nonce = await getNonce(publicKey); + if (!nonce) { + throw new Error(`Unable to get nonce`); + } + + // 2. Login + const rawMessage = createLoginRawMessage(nonce, publicKey); + const signature = await this.#snapSignMessage(rawMessage); + const loginResponse = await login( + rawMessage, + signature, + this.#metametrics.getMetaMetricsId(), + ); + if (!loginResponse?.token) { + throw new Error(`Unable to login`); + } + + const profile: SessionProfile = { + identifierId: loginResponse.profile.identifier_id, + profileId: loginResponse.profile.profile_id, + }; + + // 3. Trade for Access Token + const accessToken = await getAccessToken(loginResponse.token); + if (!accessToken) { + throw new Error(`Unable to get Access Token`); + } + + // Update Internal State + this.update((state) => { + state.isSignedIn = true; + const expiresIn = new Date(); + expiresIn.setTime(expiresIn.getTime() + THIRTY_MIN_MS); + state.sessionData = { + profile, + accessToken, + expiresIn: expiresIn.toString(), + }; + }); + + return { + profile, + accessToken, + }; + } catch (e) { + console.error('Failed to authenticate', e); + // Disable Profile Syncing + this.messagingSystem.call('UserStorageController:disableProfileSyncing'); + const errorMessage = + e instanceof Error ? e.message : JSON.stringify(e ?? ''); + throw new Error( + `${controllerName}: Failed to authenticate - ${errorMessage}`, + ); + } + } + + #hasValidSession( + sessionData: SessionData | undefined, + ): sessionData is SessionData { + if (!sessionData) { + return false; + } + + const prevDate = Date.parse(sessionData.expiresIn); + if (isNaN(prevDate)) { + return false; + } + + const currentDate = new Date(); + const diffMs = Math.abs(currentDate.getTime() - prevDate); + + return THIRTY_MIN_MS > diffMs; + } + + /** + * Returns the auth snap public key. + * + * @returns The snap public key. + */ + #snapGetPublicKey(): Promise { + return this.messagingSystem.call( + 'SnapController:handleRequest', + createSnapPublicKeyRequest(), + ) as Promise; + } + + /** + * Signs a specific message using an underlying auth snap. + * + * @param message - A specific tagged message to sign. + * @returns A Signature created by the snap. + */ + #snapSignMessage(message: `metamask:${string}`): Promise { + return this.messagingSystem.call( + 'SnapController:handleRequest', + createSnapSignMessageRequest(message), + ) as Promise; + } +} diff --git a/app/scripts/controllers/authentication/mocks/mockResponses.ts b/app/scripts/controllers/authentication/mocks/mockResponses.ts new file mode 100644 index 000000000000..4882bd81d812 --- /dev/null +++ b/app/scripts/controllers/authentication/mocks/mockResponses.ts @@ -0,0 +1,60 @@ +import { + AUTH_LOGIN_ENDPOINT, + AUTH_NONCE_ENDPOINT, + LoginResponse, + NonceResponse, + OAuthTokenResponse, + OIDC_TOKENS_ENDPOINT, +} from '../services'; + +type MockResponse = { + url: string; + requestMethod: 'GET' | 'POST' | 'PUT'; + response: unknown; +}; + +export const MOCK_NONCE = '4cbfqzoQpcNxVImGv'; +export const MOCK_NONCE_RESPONSE: NonceResponse = { + nonce: MOCK_NONCE, +}; + +export function getMockAuthNonceResponse() { + return { + url: AUTH_NONCE_ENDPOINT, + requestMethod: 'GET', + response: MOCK_NONCE_RESPONSE, + } satisfies MockResponse; +} + +export const MOCK_JWT = + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; +export const MOCK_LOGIN_RESPONSE: LoginResponse = { + token: MOCK_JWT, + expires_in: new Date().toString(), + profile: { + identifier_id: 'MOCK_IDENTIFIER', + profile_id: 'MOCK_PROFILE_ID', + }, +}; + +export function getMockAuthLoginResponse() { + return { + url: AUTH_LOGIN_ENDPOINT, + requestMethod: 'POST', + response: MOCK_LOGIN_RESPONSE, + } satisfies MockResponse; +} + +export const MOCK_ACCESS_TOKEN = `MOCK_ACCESS_TOKEN-${MOCK_JWT}`; +export const MOCK_OATH_TOKEN_RESPONSE: OAuthTokenResponse = { + access_token: MOCK_ACCESS_TOKEN, + expires_in: new Date().getTime(), +}; + +export function getMockAuthAccessTokenResponse() { + return { + url: OIDC_TOKENS_ENDPOINT, + requestMethod: 'POST', + response: MOCK_OATH_TOKEN_RESPONSE, + } satisfies MockResponse; +} diff --git a/app/scripts/controllers/authentication/mocks/mockServices.ts b/app/scripts/controllers/authentication/mocks/mockServices.ts new file mode 100644 index 000000000000..69d3cf56c5d5 --- /dev/null +++ b/app/scripts/controllers/authentication/mocks/mockServices.ts @@ -0,0 +1,42 @@ +import nock from 'nock'; +import { + getMockAuthAccessTokenResponse, + getMockAuthLoginResponse, + getMockAuthNonceResponse, +} from './mockResponses'; + +type MockReply = { + status: nock.StatusCode; + body?: nock.Body; +}; + +export function mockEndpointGetNonce(mockReply?: MockReply) { + const mockResponse = getMockAuthNonceResponse(); + const reply = mockReply ?? { status: 200, body: mockResponse.response }; + const mockNonceEndpoint = nock(mockResponse.url) + .get('') + .query(true) + .reply(reply.status, reply.body); + + return mockNonceEndpoint; +} + +export function mockEndpointLogin(mockReply?: MockReply) { + const mockResponse = getMockAuthLoginResponse(); + const reply = mockReply ?? { status: 200, body: mockResponse.response }; + const mockLoginEndpoint = nock(mockResponse.url) + .post('') + .reply(reply.status, reply.body); + + return mockLoginEndpoint; +} + +export function mockEndpointAccessToken(mockReply?: MockReply) { + const mockResponse = getMockAuthAccessTokenResponse(); + const reply = mockReply ?? { status: 200, body: mockResponse.response }; + const mockOidcTokensEndpoint = nock(mockResponse.url) + .post('') + .reply(reply.status, reply.body); + + return mockOidcTokensEndpoint; +} diff --git a/app/scripts/controllers/authentication/services.test.ts b/app/scripts/controllers/authentication/services.test.ts new file mode 100644 index 000000000000..759b3c535936 --- /dev/null +++ b/app/scripts/controllers/authentication/services.test.ts @@ -0,0 +1,108 @@ +import { MOCK_ACCESS_TOKEN, MOCK_JWT, MOCK_NONCE } from './mocks/mockResponses'; +import { + mockEndpointAccessToken, + mockEndpointGetNonce, + mockEndpointLogin, +} from './mocks/mockServices'; +import { + createLoginRawMessage, + getAccessToken, + getNonce, + login, +} from './services'; + +const MOCK_METAMETRICS_ID = '0x123'; + +describe('authentication/services.ts - getNonce() tests', () => { + test('returns nonce on valid request', async () => { + const mockNonceEndpoint = mockEndpointGetNonce(); + const response = await getNonce('MOCK_PUBLIC_KEY'); + + mockNonceEndpoint.done(); + expect(response).toBe(MOCK_NONCE); + }); + + test('returns null if request is invalid', async () => { + async function testInvalidResponse( + status: number, + body: Record, + ) { + const mockNonceEndpoint = mockEndpointGetNonce({ status, body }); + const response = await getNonce('MOCK_PUBLIC_KEY'); + + mockNonceEndpoint.done(); + expect(response).toBe(null); + } + + await testInvalidResponse(500, { error: 'mock server error' }); + await testInvalidResponse(400, { error: 'mock bad request' }); + }); +}); + +describe('authentication/services.ts - login() tests', () => { + test('returns single-use jwt if successful login', async () => { + const mockLoginEndpoint = mockEndpointLogin(); + const response = await login( + 'mock raw message', + 'mock signature', + MOCK_METAMETRICS_ID, + ); + + mockLoginEndpoint.done(); + expect(response?.token).toBe(MOCK_JWT); + expect(response?.profile).toBeDefined(); + }); + + test('returns null if request is invalid', async () => { + async function testInvalidResponse( + status: number, + body: Record, + ) { + const mockLoginEndpoint = mockEndpointLogin({ status, body }); + const response = await login( + 'mock raw message', + 'mock signature', + MOCK_METAMETRICS_ID, + ); + + mockLoginEndpoint.done(); + expect(response).toBe(null); + } + + await testInvalidResponse(500, { error: 'mock server error' }); + await testInvalidResponse(400, { error: 'mock bad request' }); + }); +}); + +describe('authentication/services.ts - getAccessToken() tests', () => { + test('returns access token jwt if successful OIDC token request', async () => { + const mockLoginEndpoint = mockEndpointAccessToken(); + const response = await getAccessToken('mock single-use jwt'); + + mockLoginEndpoint.done(); + expect(response).toBe(MOCK_ACCESS_TOKEN); + }); + + test('returns null if request is invalid', async () => { + async function testInvalidResponse( + status: number, + body: Record, + ) { + const mockLoginEndpoint = mockEndpointAccessToken({ status, body }); + const response = await getAccessToken('mock single-use jwt'); + + mockLoginEndpoint.done(); + expect(response).toBe(null); + } + + await testInvalidResponse(500, { error: 'mock server error' }); + await testInvalidResponse(400, { error: 'mock bad request' }); + }); +}); + +describe('authentication/services.ts - createLoginRawMessage() tests', () => { + test('creates the raw message format for login request', () => { + const message = createLoginRawMessage('NONCE', 'PUBLIC_KEY'); + expect(message).toBe('metamask:NONCE:PUBLIC_KEY'); + }); +}); diff --git a/app/scripts/controllers/authentication/services.ts b/app/scripts/controllers/authentication/services.ts new file mode 100644 index 000000000000..a4bbbf2f11cb --- /dev/null +++ b/app/scripts/controllers/authentication/services.ts @@ -0,0 +1,120 @@ +const AUTH_ENDPOINT = process.env.AUTH_API || ''; +export const AUTH_NONCE_ENDPOINT = `${AUTH_ENDPOINT}/api/v2/nonce`; +export const AUTH_LOGIN_ENDPOINT = `${AUTH_ENDPOINT}/api/v2/srp/login`; + +const OIDC_ENDPOINT = process.env.OIDC_API || ''; +export const OIDC_TOKENS_ENDPOINT = `${OIDC_ENDPOINT}/oauth2/token`; +const OIDC_CLIENT_ID = process.env.OIDC_CLIENT_ID || ''; +const OIDC_GRANT_TYPE = process.env.OIDC_GRANT_TYPE || ''; + +export type NonceResponse = { + nonce: string; +}; +export async function getNonce(publicKey: string): Promise { + const nonceUrl = new URL(AUTH_NONCE_ENDPOINT); + nonceUrl.searchParams.set('identifier', publicKey); + + try { + const nonceResponse = await fetch(nonceUrl.toString()); + if (!nonceResponse.ok) { + return null; + } + + const nonceJson: NonceResponse = await nonceResponse.json(); + return nonceJson?.nonce ?? null; + } catch (e) { + console.error('authentication-controller/services: unable to get nonce', e); + return null; + } +} + +export type LoginResponse = { + token: string; + expires_in: string; + /** + * Contains anonymous information about the logged in profile. + * + * @property identifier_id - a deterministic unique identifier on the method used to sign in + * @property profile_id - a unique id for a given profile + * @property metametrics_id - an anonymous server id + */ + profile: { + identifier_id: string; + profile_id: string; + }; +}; +export async function login( + rawMessage: string, + signature: string, + clientMetaMetricsId: string, +): Promise { + try { + const response = await fetch(AUTH_LOGIN_ENDPOINT, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + signature, + raw_message: rawMessage, + metametrics: { + metametrics_id: clientMetaMetricsId, + agent: 'extension', + }, + }), + }); + + if (!response.ok) { + return null; + } + + const loginResponse: LoginResponse = await response.json(); + return loginResponse ?? null; + } catch (e) { + console.error('authentication-controller/services: unable to login', e); + return null; + } +} + +export type OAuthTokenResponse = { + access_token: string; + expires_in: number; +}; +export async function getAccessToken(jwtToken: string): Promise { + const headers = new Headers({ + 'Content-Type': 'application/x-www-form-urlencoded', + }); + + const urlEncodedBody = new URLSearchParams(); + urlEncodedBody.append('grant_type', OIDC_GRANT_TYPE); + urlEncodedBody.append('client_id', OIDC_CLIENT_ID); + urlEncodedBody.append('assertion', jwtToken); + + try { + const response = await fetch(OIDC_TOKENS_ENDPOINT, { + method: 'POST', + headers, + body: urlEncodedBody.toString(), + }); + + if (!response.ok) { + return null; + } + + const accessTokenResponse: OAuthTokenResponse = await response.json(); + return accessTokenResponse?.access_token ?? null; + } catch (e) { + console.error( + 'authentication-controller/services: unable to get access token', + e, + ); + return null; + } +} + +export function createLoginRawMessage( + nonce: string, + publicKey: string, +): `metamask:${string}:${string}` { + return `metamask:${nonce}:${publicKey}` as const; +} diff --git a/app/scripts/controllers/decrypt-message.test.ts b/app/scripts/controllers/decrypt-message.test.ts index a1cb0a58f037..848fe3f9986d 100644 --- a/app/scripts/controllers/decrypt-message.test.ts +++ b/app/scripts/controllers/decrypt-message.test.ts @@ -38,6 +38,8 @@ const createMessengerMock = () => registerInitialEventPayload: jest.fn(), publish: jest.fn(), call: jest.fn(), + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any as jest.Mocked); const createDecryptMessageManagerMock = () => @@ -57,6 +59,8 @@ const createDecryptMessageManagerMock = () => hub: { on: jest.fn(), }, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any as jest.Mocked); describe('DecryptMessageController', () => { @@ -81,6 +85,8 @@ describe('DecryptMessageController', () => { const mockMessengerAction = ( action: string, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any callback: (actionName: string, ...args: any[]) => any, ) => { messengerMock.call.mockImplementation((actionName, ...rest) => { @@ -100,9 +106,17 @@ describe('DecryptMessageController', () => { ); decryptMessageController = new MockDecryptMessageController({ + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any getState: getStateMock as any, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any keyringController: keyringControllerMock as any, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any messenger: messengerMock as any, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any metricsEvent: metricsEventMock as any, } as DecryptMessageControllerOptions); }); @@ -116,6 +130,8 @@ describe('DecryptMessageController', () => { decryptMessageController.update(() => ({ unapprovedDecryptMsgs: { [messageIdMock]: messageMock, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any, unapprovedDecryptMsgCount: 1, })); @@ -131,6 +147,8 @@ describe('DecryptMessageController', () => { it('should add unapproved messages', async () => { await decryptMessageController.newRequestDecryptMessage( messageMock, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any undefined as any, ); @@ -220,6 +238,8 @@ describe('DecryptMessageController', () => { const messageToDecrypt = { ...messageMock, data: messageDataMock, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any; decryptMessageManagerMock.getMessage.mockReturnValue(messageToDecrypt); mockMessengerAction( @@ -271,6 +291,8 @@ describe('DecryptMessageController', () => { it('should be able to reject all unapproved messages', async () => { decryptMessageManagerMock.getUnapprovedMessages.mockReturnValue({ [messageIdMock]: messageMock, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any); await decryptMessageController.rejectUnapproved('reason to cancel'); diff --git a/app/scripts/controllers/decrypt-message.ts b/app/scripts/controllers/decrypt-message.ts index 5dbb4d8b43c6..51bf9c4b1250 100644 --- a/app/scripts/controllers/decrypt-message.ts +++ b/app/scripts/controllers/decrypt-message.ts @@ -117,8 +117,12 @@ export type DecryptMessageControllerMessenger = RestrictedControllerMessenger< >; export type DecryptMessageControllerOptions = { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any getState: () => any; messenger: DecryptMessageControllerMessenger; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any metricsEvent: (payload: any, options?: any) => void; }; @@ -132,8 +136,12 @@ export default class DecryptMessageController extends BaseController< > { hub: EventEmitter; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any private _getState: () => any; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any private _metricsEvent: (payload: any, options?: any) => void; private _decryptMessageManager: DecryptMessageManager; @@ -363,6 +371,8 @@ export default class DecryptMessageController extends BaseController< ) { messageManager.subscribe((state: MessageManagerState) => { const newMessages = this._migrateMessages( + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any state.unapprovedMessages as any, ); this.update((draftState) => { diff --git a/app/scripts/controllers/encryption-public-key.test.ts b/app/scripts/controllers/encryption-public-key.test.ts index c36418abffb1..ee59c771d3e6 100644 --- a/app/scripts/controllers/encryption-public-key.test.ts +++ b/app/scripts/controllers/encryption-public-key.test.ts @@ -34,6 +34,8 @@ const messageMock = { status: 'unapproved', type: 'testType', rawSig: undefined, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any as AbstractMessage; const coreMessageMock = { @@ -56,6 +58,9 @@ const createMessengerMock = () => registerActionHandler: jest.fn(), publish: jest.fn(), call: jest.fn(), + registerInitialEventPayload: jest.fn(), + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any as jest.Mocked); const createEncryptionPublicKeyManagerMock = () => @@ -71,6 +76,8 @@ const createEncryptionPublicKeyManagerMock = () => hub: { on: jest.fn(), }, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any as jest.Mocked); describe('EncryptionPublicKeyController', () => { @@ -96,10 +103,20 @@ describe('EncryptionPublicKeyController', () => { ); encryptionPublicKeyController = new EncryptionPublicKeyController({ + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any messenger: messengerMock as any, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any getEncryptionPublicKey: getEncryptionPublicKeyMock as any, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any getAccountKeyringType: getAccountKeyringTypeMock as any, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any getState: getStateMock as any, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any metricsEvent: metricsEventMock as any, } as EncryptionPublicKeyControllerOptions); }); @@ -120,6 +137,8 @@ describe('EncryptionPublicKeyController', () => { encryptionPublicKeyController.update(() => ({ unapprovedEncryptionPublicKeyMsgs: { [messageIdMock]: messageMock, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any, unapprovedEncryptionPublicKeyMsgCount: 1, })); @@ -140,11 +159,15 @@ describe('EncryptionPublicKeyController', () => { [messageIdMock2]: messageMock, }; encryptionPublicKeyManagerMock.getUnapprovedMessages.mockReturnValueOnce( + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any messages as any, ); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore encryptionPublicKeyController.update(() => ({ + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any unapprovedEncryptionPublicKeyMsgs: messages as any, })); }); @@ -192,6 +215,7 @@ describe('EncryptionPublicKeyController', () => { }); describe('newRequestEncryptionPublicKey', () => { + // @ts-expect-error This function is missing from the Mocha type definitions it.each([ ['Ledger', KeyringType.ledger], ['Trezor', KeyringType.trezor], @@ -199,7 +223,10 @@ describe('EncryptionPublicKeyController', () => { ['QR hardware', KeyringType.qr], ])( 'throws if keyring is not supported', - async (keyringName, keyringType) => { + async ( + keyringName: string, + keyringType: (typeof KeyringType)[keyof typeof KeyringType], + ) => { getAccountKeyringTypeMock.mockResolvedValueOnce(keyringType); await expect( @@ -353,6 +380,8 @@ describe('EncryptionPublicKeyController', () => { const mockListener = jest.fn(); encryptionPublicKeyController.hub.on('updateBadge', mockListener); + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any (encryptionPublicKeyManagerMock.hub.on as any).mock.calls[0][1](); expect(mockListener).toHaveBeenCalledTimes(1); @@ -361,6 +390,8 @@ describe('EncryptionPublicKeyController', () => { it('requires approval on unapproved message event from EncryptionPublicKeyManager', () => { messengerMock.call.mockResolvedValueOnce({}); + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any (encryptionPublicKeyManagerMock.hub.on as any).mock.calls[1][1]( messageParamsMock, ); @@ -379,12 +410,16 @@ describe('EncryptionPublicKeyController', () => { it('updates state on EncryptionPublicKeyManager state change', async () => { await encryptionPublicKeyManagerMock.subscribe.mock.calls[0][0]({ + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any unapprovedMessages: { [messageIdMock]: coreMessageMock as any }, unapprovedMessagesCount: 3, }); expect(encryptionPublicKeyController.state).toEqual({ unapprovedEncryptionPublicKeyMsgs: { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any [messageIdMock]: stateMessageMock as any, }, unapprovedEncryptionPublicKeyMsgCount: 3, diff --git a/app/scripts/controllers/encryption-public-key.ts b/app/scripts/controllers/encryption-public-key.ts index 4bb019a10b72..2864bab34600 100644 --- a/app/scripts/controllers/encryption-public-key.ts +++ b/app/scripts/controllers/encryption-public-key.ts @@ -87,7 +87,11 @@ export type EncryptionPublicKeyControllerOptions = { messenger: EncryptionPublicKeyControllerMessenger; getEncryptionPublicKey: (address: string) => Promise; getAccountKeyringType: (account: string) => Promise; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any getState: () => any; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any metricsEvent: (payload: any, options?: any) => void; }; @@ -105,10 +109,14 @@ export default class EncryptionPublicKeyController extends BaseController< private _getAccountKeyringType: (account: string) => Promise; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any private _getState: () => any; private _encryptionPublicKeyManager: EncryptionPublicKeyManager; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any private _metricsEvent: (payload: any, options?: any) => void; /** @@ -352,6 +360,8 @@ export default class EncryptionPublicKeyController extends BaseController< ) { messageManager.subscribe((state: MessageManagerState) => { const newMessages = this._migrateMessages( + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any state.unapprovedMessages as any, ); this.update((draftState) => { diff --git a/app/scripts/controllers/metamask-notifications/constants/constants.ts b/app/scripts/controllers/metamask-notifications/constants/constants.ts new file mode 100644 index 000000000000..516b63b96fe3 --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/constants/constants.ts @@ -0,0 +1,4 @@ +export const USER_STORAGE_VERSION = '1'; + +// Force cast. We don't really care about the type here since we treat it as a unique symbol +export const USER_STORAGE_VERSION_KEY: unique symbol = 'v' as never; diff --git a/app/scripts/controllers/metamask-notifications/constants/notification-schema.ts b/app/scripts/controllers/metamask-notifications/constants/notification-schema.ts new file mode 100644 index 000000000000..eac0d4891980 --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/constants/notification-schema.ts @@ -0,0 +1,172 @@ +export enum TRIGGER_TYPES { + FEATURES_ANNOUNCEMENT = 'features_announcement', + METAMASK_SWAP_COMPLETED = 'metamask_swap_completed', + ERC20_SENT = 'erc20_sent', + ERC20_RECEIVED = 'erc20_received', + ETH_SENT = 'eth_sent', + ETH_RECEIVED = 'eth_received', + ROCKETPOOL_STAKE_COMPLETED = 'rocketpool_stake_completed', + ROCKETPOOL_UNSTAKE_COMPLETED = 'rocketpool_unstake_completed', + LIDO_STAKE_COMPLETED = 'lido_stake_completed', + LIDO_WITHDRAWAL_REQUESTED = 'lido_withdrawal_requested', + LIDO_WITHDRAWAL_COMPLETED = 'lido_withdrawal_completed', + LIDO_STAKE_READY_TO_BE_WITHDRAWN = 'lido_stake_ready_to_be_withdrawn', + ERC721_SENT = 'erc721_sent', + ERC721_RECEIVED = 'erc721_received', + ERC1155_SENT = 'erc1155_sent', + ERC1155_RECEIVED = 'erc1155_received', +} + +export const TRIGGER_TYPES_WALLET_SET: Set = new Set([ + TRIGGER_TYPES.METAMASK_SWAP_COMPLETED, + TRIGGER_TYPES.ERC20_SENT, + TRIGGER_TYPES.ERC20_RECEIVED, + TRIGGER_TYPES.ETH_SENT, + TRIGGER_TYPES.ETH_RECEIVED, + TRIGGER_TYPES.ROCKETPOOL_STAKE_COMPLETED, + TRIGGER_TYPES.ROCKETPOOL_UNSTAKE_COMPLETED, + TRIGGER_TYPES.LIDO_STAKE_COMPLETED, + TRIGGER_TYPES.LIDO_WITHDRAWAL_REQUESTED, + TRIGGER_TYPES.LIDO_WITHDRAWAL_COMPLETED, + TRIGGER_TYPES.LIDO_STAKE_READY_TO_BE_WITHDRAWN, + TRIGGER_TYPES.ERC721_SENT, + TRIGGER_TYPES.ERC721_RECEIVED, + TRIGGER_TYPES.ERC1155_SENT, + TRIGGER_TYPES.ERC1155_RECEIVED, +]) satisfies Set>; + +export enum TRIGGER_TYPES_GROUPS { + RECEIVED = 'received', + SENT = 'sent', + DEFI = 'defi', +} + +export const NOTIFICATION_CHAINS = { + ETHEREUM: '1', + OPTIMISM: '10', + BSC: '56', + POLYGON: '137', + ARBITRUM: '42161', + AVALANCHE: '43114', + LINEA: '59144', +}; + +export const CHAIN_SYMBOLS = { + [NOTIFICATION_CHAINS.ETHEREUM]: 'ETH', + [NOTIFICATION_CHAINS.OPTIMISM]: 'ETH', + [NOTIFICATION_CHAINS.BSC]: 'BNB', + [NOTIFICATION_CHAINS.POLYGON]: 'MATIC', + [NOTIFICATION_CHAINS.ARBITRUM]: 'ETH', + [NOTIFICATION_CHAINS.AVALANCHE]: 'AVAX', + [NOTIFICATION_CHAINS.LINEA]: 'ETH', +}; + +export const SUPPORTED_CHAINS = [ + NOTIFICATION_CHAINS.ETHEREUM, + NOTIFICATION_CHAINS.OPTIMISM, + NOTIFICATION_CHAINS.BSC, + NOTIFICATION_CHAINS.POLYGON, + NOTIFICATION_CHAINS.ARBITRUM, + NOTIFICATION_CHAINS.AVALANCHE, + NOTIFICATION_CHAINS.LINEA, +]; + +export type Trigger = { + supported_chains: (typeof SUPPORTED_CHAINS)[number][]; +}; + +export const TRIGGERS: Partial> = { + [TRIGGER_TYPES.METAMASK_SWAP_COMPLETED]: { + supported_chains: [ + NOTIFICATION_CHAINS.ETHEREUM, + NOTIFICATION_CHAINS.OPTIMISM, + NOTIFICATION_CHAINS.BSC, + NOTIFICATION_CHAINS.POLYGON, + NOTIFICATION_CHAINS.ARBITRUM, + NOTIFICATION_CHAINS.AVALANCHE, + ], + }, + [TRIGGER_TYPES.ERC20_SENT]: { + supported_chains: [ + NOTIFICATION_CHAINS.ETHEREUM, + NOTIFICATION_CHAINS.OPTIMISM, + NOTIFICATION_CHAINS.BSC, + NOTIFICATION_CHAINS.POLYGON, + NOTIFICATION_CHAINS.ARBITRUM, + NOTIFICATION_CHAINS.AVALANCHE, + NOTIFICATION_CHAINS.LINEA, + ], + }, + [TRIGGER_TYPES.ERC20_RECEIVED]: { + supported_chains: [ + NOTIFICATION_CHAINS.ETHEREUM, + NOTIFICATION_CHAINS.OPTIMISM, + NOTIFICATION_CHAINS.BSC, + NOTIFICATION_CHAINS.POLYGON, + NOTIFICATION_CHAINS.ARBITRUM, + NOTIFICATION_CHAINS.AVALANCHE, + NOTIFICATION_CHAINS.LINEA, + ], + }, + [TRIGGER_TYPES.ERC721_SENT]: { + supported_chains: [ + NOTIFICATION_CHAINS.ETHEREUM, + NOTIFICATION_CHAINS.POLYGON, + ], + }, + [TRIGGER_TYPES.ERC721_RECEIVED]: { + supported_chains: [ + NOTIFICATION_CHAINS.ETHEREUM, + NOTIFICATION_CHAINS.POLYGON, + ], + }, + [TRIGGER_TYPES.ERC1155_SENT]: { + supported_chains: [ + NOTIFICATION_CHAINS.ETHEREUM, + NOTIFICATION_CHAINS.POLYGON, + ], + }, + [TRIGGER_TYPES.ERC1155_RECEIVED]: { + supported_chains: [ + NOTIFICATION_CHAINS.ETHEREUM, + NOTIFICATION_CHAINS.POLYGON, + ], + }, + [TRIGGER_TYPES.ETH_SENT]: { + supported_chains: [ + NOTIFICATION_CHAINS.ETHEREUM, + NOTIFICATION_CHAINS.OPTIMISM, + NOTIFICATION_CHAINS.BSC, + NOTIFICATION_CHAINS.POLYGON, + NOTIFICATION_CHAINS.ARBITRUM, + NOTIFICATION_CHAINS.AVALANCHE, + NOTIFICATION_CHAINS.LINEA, + ], + }, + [TRIGGER_TYPES.ETH_RECEIVED]: { + supported_chains: [ + NOTIFICATION_CHAINS.ETHEREUM, + NOTIFICATION_CHAINS.OPTIMISM, + NOTIFICATION_CHAINS.BSC, + NOTIFICATION_CHAINS.POLYGON, + NOTIFICATION_CHAINS.ARBITRUM, + NOTIFICATION_CHAINS.AVALANCHE, + NOTIFICATION_CHAINS.LINEA, + ], + }, + [TRIGGER_TYPES.ROCKETPOOL_STAKE_COMPLETED]: { + supported_chains: [NOTIFICATION_CHAINS.ETHEREUM], + }, + [TRIGGER_TYPES.ROCKETPOOL_UNSTAKE_COMPLETED]: { + supported_chains: [NOTIFICATION_CHAINS.ETHEREUM], + }, + [TRIGGER_TYPES.LIDO_STAKE_COMPLETED]: { + supported_chains: [NOTIFICATION_CHAINS.ETHEREUM], + }, + [TRIGGER_TYPES.LIDO_WITHDRAWAL_REQUESTED]: { + supported_chains: [NOTIFICATION_CHAINS.ETHEREUM], + }, + [TRIGGER_TYPES.LIDO_WITHDRAWAL_COMPLETED]: { + supported_chains: [NOTIFICATION_CHAINS.ETHEREUM], + }, +}; diff --git a/app/scripts/controllers/metamask-notifications/metamask-notifications.test.ts b/app/scripts/controllers/metamask-notifications/metamask-notifications.test.ts new file mode 100644 index 000000000000..d93d48536c13 --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/metamask-notifications.test.ts @@ -0,0 +1,804 @@ +import { ControllerMessenger } from '@metamask/base-controller'; +import * as ControllerUtils from '@metamask/controller-utils'; +import { + KeyringControllerGetAccountsAction, + KeyringControllerState, + KeyringControllerStateChangeEvent, +} from '@metamask/keyring-controller'; +import { waitFor } from '@testing-library/react'; +import { + AuthenticationControllerGetBearerToken, + AuthenticationControllerIsSignedIn, +} from '../authentication/authentication-controller'; +import { MOCK_ACCESS_TOKEN } from '../authentication/mocks/mockResponses'; +import { + UserStorageControllerGetStorageKey, + UserStorageControllerPerformGetStorage, + UserStorageControllerPerformSetStorage, + UserStorageControllerEnableProfileSyncing, +} from '../user-storage/user-storage-controller'; +import { + PushPlatformNotificationsControllerEnablePushNotifications, + PushPlatformNotificationsControllerDisablePushNotifications, + PushPlatformNotificationsControllerUpdateTriggerPushNotifications, +} from '../push-platform-notifications/push-platform-notifications'; +import { + AllowedActions, + AllowedEvents, + MetamaskNotificationsController, + defaultState, +} from './metamask-notifications'; +import { + createMockFeatureAnnouncementAPIResult, + createMockFeatureAnnouncementRaw, +} from './mocks/mock-feature-announcements'; +import { + MOCK_USER_STORAGE_ACCOUNT, + createMockFullUserStorage, + createMockUserStorageWithTriggers, +} from './mocks/mock-notification-user-storage'; +import { + mockFetchFeatureAnnouncementNotifications, + mockBatchCreateTriggers, + mockBatchDeleteTriggers, + mockListNotifications, + mockMarkNotificationsAsRead, +} from './mocks/mockServices'; +import { createMockNotificationEthSent } from './mocks/mock-raw-notifications'; +import { processNotification } from './processors/process-notifications'; +import * as OnChainNotifications from './services/onchain-notifications'; +import { UserStorage } from './types/user-storage/user-storage'; +import * as MetamaskNotificationsUtils from './utils/utils'; + +describe('metamask-notifications - constructor()', () => { + test('initializes state & override state', () => { + const controller1 = new MetamaskNotificationsController({ + messenger: mockNotificationMessenger().messenger, + }); + expect(controller1.state).toEqual(defaultState); + + const controller2 = new MetamaskNotificationsController({ + messenger: mockNotificationMessenger().messenger, + state: { + ...defaultState, + isFeatureAnnouncementsEnabled: true, + isMetamaskNotificationsEnabled: true, + }, + }); + expect(controller2.state.isFeatureAnnouncementsEnabled).toBe(true); + expect(controller2.state.isMetamaskNotificationsEnabled).toBe(true); + }); + + test('Keyring Change Event but feature not enabled will not add or remove triggers', async () => { + const { messenger, globalMessenger, mockListAccounts } = arrangeMocks(); + + // initialize controller with 1 address + mockListAccounts.mockResolvedValueOnce(['addr1']); + const controller = new MetamaskNotificationsController({ messenger }); + + const mockUpdate = jest + .spyOn(controller, 'updateOnChainTriggersByAccount') + .mockResolvedValue({} as UserStorage); + const mockDelete = jest + .spyOn(controller, 'deleteOnChainTriggersByAccount') + .mockResolvedValue({} as UserStorage); + + // listAccounts has a new address + mockListAccounts.mockResolvedValueOnce(['addr1', 'addr2']); + await actPublishKeyringStateChange(globalMessenger); + + expect(mockUpdate).not.toBeCalled(); + expect(mockDelete).not.toBeCalled(); + }); + + test('Keyring Change Event with new triggers will update triggers correctly', async () => { + const { messenger, globalMessenger, mockListAccounts } = arrangeMocks(); + + // initialize controller with 1 address + const controller = new MetamaskNotificationsController({ + messenger, + state: { + isMetamaskNotificationsEnabled: true, + subscriptionAccountsSeen: ['addr1'], + }, + }); + + const mockUpdate = jest + .spyOn(controller, 'updateOnChainTriggersByAccount') + .mockResolvedValue({} as UserStorage); + const mockDelete = jest + .spyOn(controller, 'deleteOnChainTriggersByAccount') + .mockResolvedValue({} as UserStorage); + + async function act( + addresses: string[], + assertion: () => Promise | void, + ) { + mockListAccounts.mockResolvedValueOnce(addresses); + await actPublishKeyringStateChange(globalMessenger); + await assertion(); + + // Clear mocks for next act/assert + mockUpdate.mockClear(); + mockDelete.mockClear(); + } + + // Act - if list accounts has been seen, then will not update + await act(['addr1'], () => { + expect(mockUpdate).not.toBeCalled(); + expect(mockDelete).not.toBeCalled(); + }); + + // Act - if a new address in list, then will update + await act(['addr1', 'addr2'], () => { + expect(mockUpdate).toBeCalled(); + expect(mockDelete).not.toBeCalled(); + }); + + // Act - if the list doesn't have an address, then we need to delete + await act(['addr2'], () => { + expect(mockUpdate).not.toBeCalled(); + expect(mockDelete).toBeCalled(); + }); + + // If the address is added back to the list, because it is seen we won't update + await act(['addr1', 'addr2'], () => { + expect(mockUpdate).not.toBeCalled(); + expect(mockDelete).not.toBeCalled(); + }); + }); + + test('Initializes push notifications', async () => { + const { messenger, mockEnablePushNotifications } = arrangeMocks(); + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const _controller = new MetamaskNotificationsController({ + messenger, + state: { isMetamaskNotificationsEnabled: true }, + }); + + await waitFor(() => { + expect(mockEnablePushNotifications).toBeCalled(); + }); + }); + + test('Fails to initialize push notifications', async () => { + const { messenger, mockPerformGetStorage, mockEnablePushNotifications } = + arrangeMocks(); + + // test when user storage is empty + mockPerformGetStorage.mockResolvedValue(null); + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const _controller = new MetamaskNotificationsController({ + messenger, + state: { isMetamaskNotificationsEnabled: true }, + }); + + await waitFor(() => { + expect(mockPerformGetStorage).toBeCalled(); + }); + + expect(mockEnablePushNotifications).not.toBeCalled(); + }); + + function arrangeMocks() { + const messengerMocks = mockNotificationMessenger(); + jest + .spyOn(ControllerUtils, 'toChecksumHexAddress') + .mockImplementation((x) => x); + + return messengerMocks; + } + + async function actPublishKeyringStateChange( + messenger: ControllerMessenger, + ) { + await messenger.publish( + 'KeyringController:stateChange', + {} as KeyringControllerState, + [], + ); + } +}); + +// See /utils for more in-depth testing +describe('metamask-notifications - checkAccountsPresence()', () => { + test('Returns Record with accounts that have notifications enabled', async () => { + const { messenger, mockPerformGetStorage } = mockNotificationMessenger(); + mockPerformGetStorage.mockResolvedValue( + JSON.stringify(createMockFullUserStorage()), + ); + + const controller = new MetamaskNotificationsController({ messenger }); + const result = await controller.checkAccountsPresence([ + MOCK_USER_STORAGE_ACCOUNT, + 'fake_account', + ]); + expect(result).toEqual({ + [MOCK_USER_STORAGE_ACCOUNT]: true, + fake_account: false, + }); + }); +}); + +describe('metamask-notifications - setFeatureAnnouncementsEnabled()', () => { + test('flips state when the method is called', async () => { + const { messenger, mockIsSignedIn } = mockNotificationMessenger(); + mockIsSignedIn.mockReturnValue(true); + + const controller = new MetamaskNotificationsController({ + messenger, + state: { ...defaultState, isFeatureAnnouncementsEnabled: false }, + }); + + await controller.setFeatureAnnouncementsEnabled(true); + + expect(controller.state.isFeatureAnnouncementsEnabled).toBe(true); + }); +}); + +describe('metamask-notifications - createOnChainTriggers()', () => { + test('Create new triggers and push notifications if there is no User Storage (login for new user)', async () => { + const { + messenger, + mockInitializeUserStorage, + mockEnablePushNotifications, + mockCreateOnChainTriggers, + mockPerformGetStorage, + } = arrangeMocks(); + const controller = new MetamaskNotificationsController({ messenger }); + mockPerformGetStorage.mockResolvedValue(null); // Mock no storage found. + + const result = await controller.createOnChainTriggers(); + expect(result).toBeDefined(); + expect(mockInitializeUserStorage).toBeCalled(); // called since no user storage (this is an existing user) + expect(mockCreateOnChainTriggers).toBeCalled(); + expect(mockEnablePushNotifications).toBeCalled(); + }); + + test('Throws if not given a valid auth & storage key', async () => { + const mocks = arrangeMocks(); + const controller = new MetamaskNotificationsController({ + messenger: mocks.messenger, + }); + + const testScenarios = { + ...arrangeFailureAuthAssertions(mocks), + ...arrangeFailureUserStorageKeyAssertions(mocks), + }; + + for (const mockFailureAction of Object.values(testScenarios)) { + mockFailureAction(); + await expect(controller.createOnChainTriggers()).rejects.toThrow(); + } + }); + + function arrangeMocks() { + const messengerMocks = mockNotificationMessenger(); + const mockCreateOnChainTriggers = jest + .spyOn(OnChainNotifications, 'createOnChainTriggers') + .mockResolvedValue(); + const mockInitializeUserStorage = jest + .spyOn(MetamaskNotificationsUtils, 'initializeUserStorage') + .mockReturnValue(createMockUserStorageWithTriggers(['t1', 't2'])); + return { + ...messengerMocks, + mockCreateOnChainTriggers, + mockInitializeUserStorage, + }; + } +}); + +describe('metamask-notifications - deleteOnChainTriggersByAccount', () => { + test('Deletes and disables push notifications for a given account', async () => { + const { + messenger, + nockMockDeleteTriggersAPI, + mockDisablePushNotifications, + } = arrangeMocks(); + const controller = new MetamaskNotificationsController({ messenger }); + const result = await controller.deleteOnChainTriggersByAccount([ + MOCK_USER_STORAGE_ACCOUNT, + ]); + expect( + MetamaskNotificationsUtils.traverseUserStorageTriggers(result).length, + ).toBe(0); + expect(nockMockDeleteTriggersAPI.isDone()).toBe(true); + expect(mockDisablePushNotifications).toBeCalled(); + }); + + test('Does nothing if account does not exist in storage', async () => { + const { messenger, mockDisablePushNotifications } = arrangeMocks(); + const controller = new MetamaskNotificationsController({ messenger }); + const result = await controller.deleteOnChainTriggersByAccount([ + 'UNKNOWN_ACCOUNT', + ]); + expect( + MetamaskNotificationsUtils.traverseUserStorageTriggers(result).length, + ).not.toBe(0); + + expect(mockDisablePushNotifications).not.toBeCalled(); + }); + + test('Throws errors when invalid auth and storage', async () => { + const mocks = arrangeMocks(); + const controller = new MetamaskNotificationsController({ + messenger: mocks.messenger, + }); + + const testScenarios = { + ...arrangeFailureAuthAssertions(mocks), + ...arrangeFailureUserStorageKeyAssertions(mocks), + ...arrangeFailureUserStorageAssertions(mocks), + }; + + for (const mockFailureAction of Object.values(testScenarios)) { + mockFailureAction(); + await expect( + controller.deleteOnChainTriggersByAccount([MOCK_USER_STORAGE_ACCOUNT]), + ).rejects.toThrow(); + } + }); + + function arrangeMocks() { + const messengerMocks = mockNotificationMessenger(); + const nockMockDeleteTriggersAPI = mockBatchDeleteTriggers(); + return { ...messengerMocks, nockMockDeleteTriggersAPI }; + } +}); + +describe('metamask-notifications - updateOnChainTriggersByAccount()', () => { + test('Creates Triggers and Push Notification Links for a new account', async () => { + const { + messenger, + mockUpdateTriggerPushNotifications, + mockPerformSetStorage, + } = arrangeMocks(); + const MOCK_ACCOUNT = 'MOCK_ACCOUNT2'; + const controller = new MetamaskNotificationsController({ messenger }); + + const result = await controller.updateOnChainTriggersByAccount([ + MOCK_ACCOUNT, + ]); + expect( + MetamaskNotificationsUtils.traverseUserStorageTriggers(result, { + address: MOCK_ACCOUNT.toLowerCase(), + }).length > 0, + ).toBe(true); + + expect(mockUpdateTriggerPushNotifications).toBeCalled(); + expect(mockPerformSetStorage).toBeCalled(); + }); + + test('Throws errors when invalid auth and storage', async () => { + const mocks = arrangeMocks(); + const controller = new MetamaskNotificationsController({ + messenger: mocks.messenger, + }); + + const testScenarios = { + ...arrangeFailureAuthAssertions(mocks), + ...arrangeFailureUserStorageKeyAssertions(mocks), + ...arrangeFailureUserStorageAssertions(mocks), + }; + + for (const mockFailureAction of Object.values(testScenarios)) { + mockFailureAction(); + await expect( + controller.deleteOnChainTriggersByAccount([MOCK_USER_STORAGE_ACCOUNT]), + ).rejects.toThrow(); + } + }); + + function arrangeMocks() { + const messengerMocks = mockNotificationMessenger(); + const mockBatchTriggersAPI = mockBatchCreateTriggers(); + return { ...messengerMocks, mockBatchTriggersAPI }; + } +}); + +describe('metamask-notifications - fetchAndUpdateMetamaskNotifications()', () => { + test('Processes and shows feature announcements and wallet notifications', async () => { + const { + messenger, + mockFeatureAnnouncementAPIResult, + mockListNotificationsAPIResult, + } = arrangeMocks(); + + const controller = new MetamaskNotificationsController({ + messenger, + state: { ...defaultState, isFeatureAnnouncementsEnabled: true }, + }); + + const result = await controller.fetchAndUpdateMetamaskNotifications(); + + // Should have 1 feature announcement and 1 wallet notification + expect(result.length).toBe(2); + expect( + result.find( + (n) => n.id === mockFeatureAnnouncementAPIResult.items?.[0].fields.id, + ), + ).toBeDefined(); + expect(result.find((n) => n.id === mockListNotificationsAPIResult[0].id)); + + // State is also updated + expect(controller.state.metamaskNotificationsList.length).toBe(2); + }); + + test('Only fetches and processes feature announcements if not authenticated', async () => { + const { messenger, mockGetBearerToken, mockFeatureAnnouncementAPIResult } = + arrangeMocks(); + mockGetBearerToken.mockRejectedValue( + new Error('MOCK - failed to get access token'), + ); + + const controller = new MetamaskNotificationsController({ + messenger, + state: { ...defaultState, isFeatureAnnouncementsEnabled: true }, + }); + + // Should only have feature announcement + const result = await controller.fetchAndUpdateMetamaskNotifications(); + expect(result.length).toBe(1); + expect( + result.find( + (n) => n.id === mockFeatureAnnouncementAPIResult.items?.[0].fields.id, + ), + ).toBeDefined(); + + // State is also updated + expect(controller.state.metamaskNotificationsList.length).toBe(1); + }); + + function arrangeMocks() { + const messengerMocks = mockNotificationMessenger(); + + const mockFeatureAnnouncementAPIResult = + createMockFeatureAnnouncementAPIResult(); + const mockFeatureAnnouncementsAPI = + mockFetchFeatureAnnouncementNotifications({ + status: 200, + body: mockFeatureAnnouncementAPIResult, + }); + + const mockListNotificationsAPIResult = [createMockNotificationEthSent()]; + const mockListNotificationsAPI = mockListNotifications({ + status: 200, + body: mockListNotificationsAPIResult, + }); + return { + ...messengerMocks, + mockFeatureAnnouncementAPIResult, + mockFeatureAnnouncementsAPI, + mockListNotificationsAPIResult, + mockListNotificationsAPI, + }; + } +}); + +describe('metamask-notifications - markMetamaskNotificationsAsRead()', () => { + test('updates feature announcements as read', async () => { + const { messenger } = arrangeMocks(); + const controller = new MetamaskNotificationsController({ messenger }); + + await controller.markMetamaskNotificationsAsRead([ + processNotification(createMockFeatureAnnouncementRaw()), + processNotification(createMockNotificationEthSent()), + ]); + + // Should see 2 items in controller read state + expect(controller.state.metamaskNotificationsReadList.length).toBe(1); + }); + + test('should at least mark feature announcements locally if external updates fail', async () => { + const { messenger } = arrangeMocks({ onChainMarkAsReadFails: true }); + const controller = new MetamaskNotificationsController({ messenger }); + + await controller.markMetamaskNotificationsAsRead([ + processNotification(createMockFeatureAnnouncementRaw()), + processNotification(createMockNotificationEthSent()), + ]); + + // Should see 1 item in controller read state. + // This is because on-chain failed. + // We can debate & change implementation if it makes sense to mark as read locally if external APIs fail. + expect(controller.state.metamaskNotificationsReadList.length).toBe(1); + }); + + function arrangeMocks(options?: { onChainMarkAsReadFails: boolean }) { + const messengerMocks = mockNotificationMessenger(); + + const mockMarkAsReadAPI = mockMarkNotificationsAsRead({ + status: options?.onChainMarkAsReadFails ? 500 : 200, + }); + + return { + ...messengerMocks, + mockMarkAsReadAPI, + }; + } +}); + +describe('metamask-notifications - enableMetamaskNotifications()', () => { + it('create new notifications when switched on and no new notifications', async () => { + const mocks = arrangeMocks(); + mocks.mockListAccounts.mockResolvedValue(['0xAddr1']); + const controller = new MetamaskNotificationsController({ + messenger: mocks.messenger, + }); + + const promise = controller.enableMetamaskNotifications(); + + // Act - intermediate state + expect(controller.state.isUpdatingMetamaskNotifications).toBe(true); + + await promise; + + // Act - final state + expect(controller.state.isUpdatingMetamaskNotifications).toBe(false); + expect(controller.state.isMetamaskNotificationsEnabled).toBe(true); + + // Act - services called + expect(mocks.mockCreateOnChainTriggers).toBeCalled(); + }); + + it('not create new notifications when enabling an account already in storage', async () => { + const mocks = arrangeMocks(); + mocks.mockListAccounts.mockResolvedValue(['0xAddr1']); + const userStorage = createMockFullUserStorage({ address: '0xAddr1' }); + mocks.mockPerformGetStorage.mockResolvedValue(JSON.stringify(userStorage)); + const controller = new MetamaskNotificationsController({ + messenger: mocks.messenger, + }); + + await controller.enableMetamaskNotifications(); + + const existingTriggers = + MetamaskNotificationsUtils.getAllUUIDs(userStorage); + const upsertedTriggers = + mocks.mockCreateOnChainTriggers.mock.calls[0][3].map((t) => t.id); + + expect(existingTriggers).toEqual(upsertedTriggers); + }); + + function arrangeMocks() { + const messengerMocks = mockNotificationMessenger(); + + const mockCreateOnChainTriggers = jest + .spyOn(OnChainNotifications, 'createOnChainTriggers') + .mockResolvedValue(); + + return { ...messengerMocks, mockCreateOnChainTriggers }; + } +}); + +describe('metamask-notifications - disableMetamaskNotifications()', () => { + it('disable notifications and turn off push notifications', async () => { + const mocks = arrangeMocks(); + const controller = new MetamaskNotificationsController({ + messenger: mocks.messenger, + state: { isMetamaskNotificationsEnabled: true }, + }); + + const promise = controller.disableMetamaskNotifications(); + + // Act - intermediate state + expect(controller.state.isUpdatingMetamaskNotifications).toBe(true); + + await promise; + + // Act - final state + expect(controller.state.isUpdatingMetamaskNotifications).toBe(false); + expect(controller.state.isMetamaskNotificationsEnabled).toBe(false); + + expect(mocks.mockDisablePushNotifications).toBeCalled(); + + // We do not delete triggers when disabling notifications + // As other devices might be using those triggers to receive notifications + expect(mocks.mockDeleteOnChainTriggers).not.toBeCalled(); + }); + + function arrangeMocks() { + const messengerMocks = mockNotificationMessenger(); + + const mockDeleteOnChainTriggers = jest + .spyOn(OnChainNotifications, 'deleteOnChainTriggers') + .mockResolvedValue({} as UserStorage); + + return { ...messengerMocks, mockDeleteOnChainTriggers }; + } +}); + +// Type-Computation - we are extracting args and parameters from a generic type utility +// Thus this `AnyFunc` can be used to help constrain the generic parameters correctly +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type AnyFunc = (...args: any[]) => any; +const typedMockAction = () => + jest.fn, Parameters>(); + +function mockNotificationMessenger() { + const globalMessenger = new ControllerMessenger< + AllowedActions, + AllowedEvents + >(); + + const messenger = globalMessenger.getRestricted({ + name: 'MetamaskNotificationsController', + allowedActions: [ + 'KeyringController:getAccounts', + 'AuthenticationController:getBearerToken', + 'AuthenticationController:isSignedIn', + 'PushPlatformNotificationsController:disablePushNotifications', + 'PushPlatformNotificationsController:enablePushNotifications', + 'PushPlatformNotificationsController:updateTriggerPushNotifications', + 'UserStorageController:getStorageKey', + 'UserStorageController:performGetStorage', + 'UserStorageController:performSetStorage', + 'UserStorageController:enableProfileSyncing', + ], + allowedEvents: [ + 'KeyringController:stateChange', + 'PushPlatformNotificationsController:onNewNotifications', + ], + }); + + const mockListAccounts = + typedMockAction().mockResolvedValue([]); + + const mockGetBearerToken = + typedMockAction().mockResolvedValue( + MOCK_ACCESS_TOKEN, + ); + + const mockIsSignedIn = + typedMockAction().mockReturnValue(true); + + const mockDisablePushNotifications = + typedMockAction(); + + const mockEnablePushNotifications = + typedMockAction(); + + const mockUpdateTriggerPushNotifications = + typedMockAction(); + + const mockGetStorageKey = + typedMockAction().mockResolvedValue( + 'MOCK_STORAGE_KEY', + ); + + const mockEnableProfileSyncing = + typedMockAction(); + + const mockPerformGetStorage = + typedMockAction().mockResolvedValue( + JSON.stringify(createMockFullUserStorage()), + ); + + const mockPerformSetStorage = + typedMockAction(); + + jest.spyOn(messenger, 'call').mockImplementation((...args) => { + const [actionType] = args; + + // This mock implementation does not have a nice discriminate union where types/parameters can be correctly inferred + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const [, ...params]: any[] = args; + + if (actionType === 'KeyringController:getAccounts') { + return mockListAccounts(); + } + + if (actionType === 'AuthenticationController:getBearerToken') { + return mockGetBearerToken(); + } + + if (actionType === 'AuthenticationController:isSignedIn') { + return mockIsSignedIn(); + } + + if ( + actionType === + 'PushPlatformNotificationsController:disablePushNotifications' + ) { + return mockDisablePushNotifications(params[0]); + } + + if ( + actionType === + 'PushPlatformNotificationsController:enablePushNotifications' + ) { + return mockEnablePushNotifications(params[0]); + } + + if ( + actionType === + 'PushPlatformNotificationsController:updateTriggerPushNotifications' + ) { + return mockUpdateTriggerPushNotifications(params[0]); + } + + if (actionType === 'UserStorageController:getStorageKey') { + return mockGetStorageKey(); + } + + if (actionType === 'UserStorageController:enableProfileSyncing') { + return mockEnableProfileSyncing(); + } + + if (actionType === 'UserStorageController:performGetStorage') { + return mockPerformGetStorage(params[0]); + } + + if (actionType === 'UserStorageController:performSetStorage') { + return mockPerformSetStorage(params[0], params[1]); + } + + function exhaustedMessengerMocks(action: never) { + return new Error(`MOCK_FAIL - unsupported messenger call: ${action}`); + } + throw exhaustedMessengerMocks(actionType); + }); + + return { + globalMessenger, + messenger, + mockListAccounts, + mockGetBearerToken, + mockIsSignedIn, + mockDisablePushNotifications, + mockEnablePushNotifications, + mockUpdateTriggerPushNotifications, + mockGetStorageKey, + mockPerformGetStorage, + mockPerformSetStorage, + }; +} + +function arrangeFailureAuthAssertions( + mocks: ReturnType, +) { + const testScenarios = { + NotLoggedIn: () => mocks.mockIsSignedIn.mockReturnValue(false), + + // unlikely, but in case it returns null + NoBearerToken: () => + mocks.mockGetBearerToken.mockResolvedValueOnce(null as unknown as string), + + RejectedBearerToken: () => + mocks.mockGetBearerToken.mockRejectedValueOnce( + new Error('MOCK - no bearer token'), + ), + }; + + return testScenarios; +} + +function arrangeFailureUserStorageKeyAssertions( + mocks: ReturnType, +) { + const testScenarios = { + NoStorageKey: () => + mocks.mockGetStorageKey.mockResolvedValueOnce(null as unknown as string), // unlikely but in case it returns null + RejectedStorageKey: () => + mocks.mockGetStorageKey.mockRejectedValueOnce( + new Error('MOCK - no storage key'), + ), + }; + return testScenarios; +} + +function arrangeFailureUserStorageAssertions( + mocks: ReturnType, +) { + const testScenarios = { + NoUserStorage: () => + mocks.mockPerformGetStorage.mockResolvedValueOnce(null), + ThrowUserStorage: () => + mocks.mockPerformGetStorage.mockRejectedValueOnce( + new Error('MOCK - Unable to call storage api'), + ), + }; + return testScenarios; +} diff --git a/app/scripts/controllers/metamask-notifications/metamask-notifications.ts b/app/scripts/controllers/metamask-notifications/metamask-notifications.ts new file mode 100644 index 000000000000..b9ad4572742b --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/metamask-notifications.ts @@ -0,0 +1,1167 @@ +import { + BaseController, + RestrictedControllerMessenger, + ControllerGetStateAction, + ControllerStateChangeEvent, + StateMetadata, +} from '@metamask/base-controller'; +import log from 'loglevel'; +import { toChecksumHexAddress } from '@metamask/controller-utils'; +import { + KeyringControllerGetAccountsAction, + KeyringControllerStateChangeEvent, +} from '@metamask/keyring-controller'; +import { + AuthenticationControllerGetBearerToken, + AuthenticationControllerIsSignedIn, +} from '../authentication/authentication-controller'; +import { + PushPlatformNotificationsControllerEnablePushNotifications, + PushPlatformNotificationsControllerDisablePushNotifications, + PushPlatformNotificationsControllerUpdateTriggerPushNotifications, + PushPlatformNotificationsControllerOnNewNotificationEvent, +} from '../push-platform-notifications/push-platform-notifications'; +import { + UserStorageControllerEnableProfileSyncing, + UserStorageControllerGetStorageKey, + UserStorageControllerPerformGetStorage, + UserStorageControllerPerformSetStorage, +} from '../user-storage/user-storage-controller'; +import { + TRIGGER_TYPES, + TRIGGER_TYPES_GROUPS, +} from './constants/notification-schema'; +import { USER_STORAGE_VERSION_KEY } from './constants/constants'; +import type { UserStorage } from './types/user-storage/user-storage'; +import * as FeatureNotifications from './services/feature-announcements'; +import * as OnChainNotifications from './services/onchain-notifications'; +import type { + Notification, + MarkAsReadNotificationsParam, +} from './types/notification/notification'; +import { OnChainRawNotification } from './types/on-chain-notification/on-chain-notification'; +import { processNotification } from './processors/process-notifications'; +import * as MetamaskNotificationsUtils from './utils/utils'; +import type { NotificationUnion } from './types/types'; + +// Unique name for the controller +const controllerName = 'MetamaskNotificationsController'; + +/** + * State shape for MetamaskNotificationsController + */ +export type MetamaskNotificationsControllerState = { + /** + * We store and manage accounts that have been seen/visted through the + * account subscription. This allows us to track and add notifications for new accounts and not previous accounts added. + */ + subscriptionAccountsSeen: string[]; + + /** + * Flag that indicates if the metamask notifications feature has been seen + */ + isMetamaskNotificationsFeatureSeen: boolean; + + /** + * Flag that indicates if the metamask notifications are enabled + */ + isMetamaskNotificationsEnabled: boolean; + + /** + * Flag that indicates if the feature announcements are enabled + */ + isFeatureAnnouncementsEnabled: boolean; + + /** + * List of metamask notifications + */ + metamaskNotificationsList: Notification[]; + + /** + * List of read metamask notifications + */ + metamaskNotificationsReadList: string[]; + /** + * Flag that indicates that the creating notifications is in progress + */ + isUpdatingMetamaskNotifications: boolean; + /** + * Flag that indicates that the fetching notifications is in progress + * This is used to show a loading spinner in the UI + * when fetching notifications + */ + isFetchingMetamaskNotifications: boolean; + /** + * Flag that indicates that the updating notifications for a specific address is in progress + */ + isUpdatingMetamaskNotificationsAccount: string[]; + /** + * Flag that indicates that the checking accounts presence is in progress + */ + isCheckingAccountsPresence: boolean; +}; + +const metadata: StateMetadata = { + subscriptionAccountsSeen: { + persist: true, + anonymous: true, + }, + + isMetamaskNotificationsFeatureSeen: { + persist: true, + anonymous: false, + }, + isMetamaskNotificationsEnabled: { + persist: true, + anonymous: false, + }, + isFeatureAnnouncementsEnabled: { + persist: true, + anonymous: false, + }, + metamaskNotificationsList: { + persist: true, + anonymous: true, + }, + metamaskNotificationsReadList: { + persist: true, + anonymous: true, + }, + isUpdatingMetamaskNotifications: { + persist: false, + anonymous: false, + }, + isFetchingMetamaskNotifications: { + persist: false, + anonymous: false, + }, + isUpdatingMetamaskNotificationsAccount: { + persist: false, + anonymous: false, + }, + isCheckingAccountsPresence: { + persist: false, + anonymous: false, + }, +}; +export const defaultState: MetamaskNotificationsControllerState = { + subscriptionAccountsSeen: [], + isMetamaskNotificationsFeatureSeen: false, + isMetamaskNotificationsEnabled: false, + isFeatureAnnouncementsEnabled: false, + metamaskNotificationsList: [], + metamaskNotificationsReadList: [], + isUpdatingMetamaskNotifications: false, + isFetchingMetamaskNotifications: false, + isUpdatingMetamaskNotificationsAccount: [], + isCheckingAccountsPresence: false, +}; + +export declare type MetamaskNotificationsControllerUpdateMetamaskNotificationsList = + { + type: `${typeof controllerName}:updateMetamaskNotificationsList`; + handler: MetamaskNotificationsController['updateMetamaskNotificationsList']; + }; + +export declare type MetamaskNotificationsControllerDisableMetamaskNotifications = + { + type: `${typeof controllerName}:disableMetamaskNotifications`; + handler: MetamaskNotificationsController['disableMetamaskNotifications']; + }; + +export declare type MetamaskNotificationsControllerSelectIsMetamaskNotificationsEnabled = + { + type: `${typeof controllerName}:selectIsMetamaskNotificationsEnabled`; + handler: MetamaskNotificationsController['selectIsMetamaskNotificationsEnabled']; + }; + +export type MetamaskNotificationsControllerNotificationsListUpdatedEvent = { + type: `${typeof controllerName}:notificationsListUpdated`; + payload: [Notification[]]; +}; + +export type MetamaskNotificationsControllerMarkNotificationsAsRead = { + type: `${typeof controllerName}:markNotificationsAsRead`; + payload: [Notification[]]; +}; + +// Messenger Actions +export type Actions = + | MetamaskNotificationsControllerUpdateMetamaskNotificationsList + | MetamaskNotificationsControllerDisableMetamaskNotifications + | MetamaskNotificationsControllerSelectIsMetamaskNotificationsEnabled + | ControllerGetStateAction<'state', MetamaskNotificationsControllerState>; + +// Allowed Actions +export type AllowedActions = + // Keyring Controller Requests + | KeyringControllerGetAccountsAction + // Auth Controller Requests + | AuthenticationControllerGetBearerToken + | AuthenticationControllerIsSignedIn + // User Storage Controller Requests + | UserStorageControllerEnableProfileSyncing + | UserStorageControllerGetStorageKey + | UserStorageControllerPerformGetStorage + | UserStorageControllerPerformSetStorage + // Push Notifications Controller Requests + | PushPlatformNotificationsControllerEnablePushNotifications + | PushPlatformNotificationsControllerDisablePushNotifications + | PushPlatformNotificationsControllerUpdateTriggerPushNotifications; + +// Events +export type MetamaskNotificationsControllerMessengerEvents = + ControllerStateChangeEvent< + typeof controllerName, + MetamaskNotificationsControllerState + >; + +// Allowed Events +export type AllowedEvents = + | KeyringControllerStateChangeEvent + | PushPlatformNotificationsControllerOnNewNotificationEvent + | MetamaskNotificationsControllerNotificationsListUpdatedEvent + | MetamaskNotificationsControllerMarkNotificationsAsRead; + +// Type for the messenger of MetamaskNotificationsController +export type MetamaskNotificationsControllerMessenger = + RestrictedControllerMessenger< + typeof controllerName, + Actions | AllowedActions, + AllowedEvents, + AllowedActions['type'], + AllowedEvents['type'] + >; + +/** + * Controller that enables wallet notifications and feature announcements + */ +export class MetamaskNotificationsController extends BaseController< + typeof controllerName, + MetamaskNotificationsControllerState, + MetamaskNotificationsControllerMessenger +> { + #auth = { + getBearerToken: async () => { + return await this.messagingSystem.call( + 'AuthenticationController:getBearerToken', + ); + }, + isSignedIn: () => { + return this.messagingSystem.call('AuthenticationController:isSignedIn'); + }, + }; + + #storage = { + enableProfileSyncing: async () => { + return await this.messagingSystem.call( + 'UserStorageController:enableProfileSyncing', + ); + }, + getStorageKey: () => { + return this.messagingSystem.call('UserStorageController:getStorageKey'); + }, + getNotificationStorage: async () => { + return await this.messagingSystem.call( + 'UserStorageController:performGetStorage', + 'notification_settings', + ); + }, + setNotificationStorage: async (state: string) => { + return await this.messagingSystem.call( + 'UserStorageController:performSetStorage', + 'notification_settings', + state, + ); + }, + }; + + #pushNotifications = { + enablePushNotifications: async (UUIDs: string[]) => { + return await this.messagingSystem.call( + 'PushPlatformNotificationsController:enablePushNotifications', + UUIDs, + ); + }, + disablePushNotifications: async (UUIDs: string[]) => { + return await this.messagingSystem.call( + 'PushPlatformNotificationsController:disablePushNotifications', + UUIDs, + ); + }, + updatePushNotifications: async (UUIDs: string[]) => { + return await this.messagingSystem.call( + 'PushPlatformNotificationsController:updateTriggerPushNotifications', + UUIDs, + ); + }, + subscribe: () => { + this.messagingSystem.subscribe( + 'PushPlatformNotificationsController:onNewNotifications', + (notification) => { + this.updateMetamaskNotificationsList(notification); + }, + ); + }, + initializePushNotifications: async () => { + if (!this.state.isMetamaskNotificationsEnabled) { + return; + } + + const storage = await this.#getUserStorage(); + if (!storage) { + return; + } + + const uuids = MetamaskNotificationsUtils.getAllUUIDs(storage); + await this.#pushNotifications.enablePushNotifications(uuids); + }, + }; + + #accounts = { + /** + * Used to get list of addresses from keyring (wallet addresses) + * + * @returns addresses removed, added, and latest list of addresses + */ + listAccounts: async () => { + // Get previous and current account sets + const nonChecksumAccounts = await this.messagingSystem.call( + 'KeyringController:getAccounts', + ); + const accounts = nonChecksumAccounts.map((a) => toChecksumHexAddress(a)); + const currentAccountsSet = new Set(accounts); + const prevAccountsSet = new Set(this.state.subscriptionAccountsSeen); + + // Invalid value you cannot have zero accounts + // Only occurs when the Accounts controller is initializing. + if (accounts.length === 0) { + return { + accountsAdded: [], + accountsRemoved: [], + accounts: [], + }; + } + + // Calculate added and removed addresses + const accountsAdded = accounts.filter((a) => !prevAccountsSet.has(a)); + const accountsRemoved = [...prevAccountsSet.values()].filter( + (a) => !currentAccountsSet.has(a), + ); + + // Update accounts seen + this.update((state) => { + state.subscriptionAccountsSeen = [...prevAccountsSet, ...accountsAdded]; + }); + + return { + accountsAdded, + accountsRemoved, + accounts, + }; + }, + + /** + * Initializes the cache/previous list. This is handy so we have an accurate in-mem state of the previous list of accounts. + * + * @returns result from list accounts + */ + initialize: () => { + return this.#accounts.listAccounts(); + }, + + /** + * Subscription to any state change in the keyring controller (aka wallet accounts). + * We can call the `listAccounts` defined above to find out about any accounts added, removed + * And call effects to subscribe/unsubscribe to notifications. + */ + subscribe: () => { + this.messagingSystem.subscribe( + 'KeyringController:stateChange', + async () => { + if (!this.state.isMetamaskNotificationsEnabled) { + return; + } + + const { accountsAdded, accountsRemoved } = + await this.#accounts.listAccounts(); + + const promises: Promise[] = []; + if (accountsAdded.length > 0) { + promises.push(this.updateOnChainTriggersByAccount(accountsAdded)); + } + if (accountsRemoved.length > 0) { + promises.push(this.deleteOnChainTriggersByAccount(accountsRemoved)); + } + await Promise.all(promises); + }, + ); + }, + }; + + /** + * Creates a MetamaskNotificationsController instance. + * + * @param args - The arguments to this function. + * @param args.messenger - Messenger used to communicate with BaseV2 controller. + * @param args.state - Initial state to set on this controller. + */ + constructor({ + messenger, + state, + }: { + messenger: MetamaskNotificationsControllerMessenger; + state?: Partial; + }) { + super({ + messenger, + metadata, + name: controllerName, + state: { ...defaultState, ...state }, + }); + + this.#registerMessageHandlers(); + this.#clearLoadingStates(); + this.#accounts.initialize(); + this.#pushNotifications.initializePushNotifications(); + this.#accounts.subscribe(); + this.#pushNotifications.subscribe(); + } + + #registerMessageHandlers(): void { + this.messagingSystem.registerActionHandler( + `${controllerName}:updateMetamaskNotificationsList`, + this.updateMetamaskNotificationsList.bind(this), + ); + + this.messagingSystem.registerActionHandler( + `${controllerName}:disableMetamaskNotifications`, + this.disableMetamaskNotifications.bind(this), + ); + + this.messagingSystem.registerActionHandler( + `${controllerName}:selectIsMetamaskNotificationsEnabled`, + this.selectIsMetamaskNotificationsEnabled.bind(this), + ); + } + + #clearLoadingStates(): void { + this.update((state) => { + state.isUpdatingMetamaskNotifications = false; + state.isCheckingAccountsPresence = false; + state.isFetchingMetamaskNotifications = false; + state.isUpdatingMetamaskNotificationsAccount = []; + }); + } + + #assertAuthEnabled() { + if (!this.#auth.isSignedIn()) { + this.update((state) => { + state.isMetamaskNotificationsEnabled = false; + }); + throw new Error('User is not signed in.'); + } + } + + async #getValidStorageKeyAndBearerToken() { + this.#assertAuthEnabled(); + + const bearerToken = await this.#auth.getBearerToken(); + const storageKey = await this.#storage.getStorageKey(); + + if (!bearerToken || !storageKey) { + throw new Error('Missing BearerToken or storage key'); + } + + return { bearerToken, storageKey }; + } + + #performEnableProfileSyncing = async () => { + try { + await this.#storage.enableProfileSyncing(); + } catch (e) { + log.error('Failed to enable profile syncing', e); + throw new Error('Failed to enable profile syncing'); + } + }; + + #assertUserStorage( + storage: UserStorage | null, + ): asserts storage is UserStorage { + if (!storage) { + throw new Error('User Storage does not exist'); + } + } + + /** + * Retrieves and parses the user storage from the storage key. + * + * This method attempts to retrieve the user storage using the specified storage key, + * then parses the JSON string to an object. If the storage is not found or cannot be parsed, + * it throws an error. + * + * @returns The parsed user storage object or null + */ + async #getUserStorage(): Promise { + const userStorageString: string | null = + await this.#storage.getNotificationStorage(); + + if (!userStorageString) { + return null; + } + + try { + const userStorage: UserStorage = JSON.parse(userStorageString); + return userStorage; + } catch (error) { + log.error('Unable to parse User Storage'); + return null; + } + } + + /** + * @deprecated - This needs rework for it to be feasible. Currently this is a half-baked solution, as it fails once we add new triggers (introspection for filters is difficult). + * + * Checks for the complete presence of trigger types by group across all addresses in user storage. + * + * This method retrieves the user storage and uses `MetamaskNotificationsUtils` to verify if all expected trigger types for each group are present for every address. + * @returns A record indicating whether all expected trigger types for each group are present for every address. + * @throws {Error} If user storage does not exist. + */ + public async checkTriggersPresenceByGroup(): Promise< + Record + > { + const userStorage = await this.#getUserStorage(); + this.#assertUserStorage(userStorage); + + // Use MetamaskNotificationsUtils to check the presence of triggers + return MetamaskNotificationsUtils.checkTriggersPresenceByGroup(userStorage); + } + + /** + * Retrieves the current enabled state of MetaMask notifications. + * + * This method directly returns the boolean value of `isMetamaskNotificationsEnabled` + * from the controller's state, indicating whether MetaMask notifications are currently enabled. + * + * @returns The enabled state of MetaMask notifications. + */ + public selectIsMetamaskNotificationsEnabled(): boolean { + return this.state.isMetamaskNotificationsEnabled; + } + + /** + * Sets the state of notification creation process. + * + * This method updates the `isUpdatingMetamaskNotifications` state, which can be used to indicate + * whether the notification creation process is currently active or not. This is useful + * for UI elements that need to reflect the state of ongoing operations, such as loading + * indicators or disabled buttons during processing. + * + * @param isUpdatingMetamaskNotifications - A boolean value representing the new state of the notification creation process. + */ + #setIsUpdatingMetamaskNotifications( + isUpdatingMetamaskNotifications: boolean, + ) { + this.update((state) => { + state.isUpdatingMetamaskNotifications = isUpdatingMetamaskNotifications; + }); + } + + /** + * Updates the state to indicate whether fetching of MetaMask notifications is in progress. + * + * This method is used to set the `isFetchingMetamaskNotifications` state, which can be utilized + * to show or hide loading indicators in the UI when notifications are being fetched. + * + * @param isFetchingMetamaskNotifications - A boolean value representing the fetching state. + */ + #setIsFetchingMetamaskNotifications( + isFetchingMetamaskNotifications: boolean, + ) { + this.update((state) => { + state.isFetchingMetamaskNotifications = isFetchingMetamaskNotifications; + }); + } + + /** + * Updates the state to indicate that the checking of accounts presence is in progress. + * + * This method modifies the `isCheckingAccountsPresence` state, which can be used to manage UI elements + * that depend on the status of account presence checks, such as displaying loading indicators or disabling + * buttons while the check is ongoing. + * + * @param isCheckingAccountsPresence - A boolean value indicating whether the account presence check is currently active. + */ + #setIsCheckingAccountsPresence(isCheckingAccountsPresence: boolean) { + this.update((state) => { + state.isCheckingAccountsPresence = isCheckingAccountsPresence; + }); + } + + /** + * Updates the state to indicate that account updates are in progress. + * Removes duplicate accounts before updating the state. + * + * @param accounts - The accounts being updated. + */ + #updateUpdatingAccountsState(accounts: string[]) { + this.update((state) => { + const uniqueAccounts = new Set([ + ...state.isUpdatingMetamaskNotificationsAccount, + ...accounts, + ]); + state.isUpdatingMetamaskNotificationsAccount = Array.from(uniqueAccounts); + }); + } + + /** + * Clears the state indicating that account updates are complete. + * + * @param accounts - The accounts that have finished updating. + */ + #clearUpdatingAccountsState(accounts: string[]) { + this.update((state) => { + state.isUpdatingMetamaskNotificationsAccount = + state.isUpdatingMetamaskNotificationsAccount.filter( + (existingAccount) => !accounts.includes(existingAccount), + ); + }); + } + + public async checkAccountsPresence( + accounts: string[], + ): Promise> { + try { + this.#setIsCheckingAccountsPresence(true); + + // Retrieve user storage + const userStorage = await this.#getUserStorage(); + this.#assertUserStorage(userStorage); + + const presence = MetamaskNotificationsUtils.checkAccountsPresence( + userStorage, + accounts, + ); + return presence; + } catch (error) { + log.error('Failed to check accounts presence', error); + throw error; + } finally { + this.#setIsCheckingAccountsPresence(false); + } + } + + /** + * Sets the enabled state of feature announcements. + * + * **Action** - used in the notification settings to enable/disable feature announcements. + * + * @param featureAnnouncementsEnabled - A boolean value indicating the desired enabled state of the feature announcements. + * @async + * @throws {Error} If fails to update + */ + public async setFeatureAnnouncementsEnabled( + featureAnnouncementsEnabled: boolean, + ) { + try { + this.update((s) => { + s.isFeatureAnnouncementsEnabled = featureAnnouncementsEnabled; + }); + } catch (e) { + log.error('Unable to toggle feature announcements', e); + throw new Error('Unable to toggle feature announcements'); + } + } + + /** + * This creates/re-creates on-chain triggers defined in User Storage. + * + * **Action** - Used during Sign In / Enabling of notifications. + * + * @returns The updated or newly created user storage. + * @throws {Error} Throws an error if unauthenticated or from other operations. + */ + public async createOnChainTriggers(): Promise { + try { + this.#setIsUpdatingMetamaskNotifications(true); + + await this.#performEnableProfileSyncing(); + + const { bearerToken, storageKey } = + await this.#getValidStorageKeyAndBearerToken(); + + const { accounts } = await this.#accounts.listAccounts(); + + let userStorage = await this.#getUserStorage(); + + // If userStorage does not exist, create a new one + // All the triggers created are set as: "disabled" + if (userStorage?.[USER_STORAGE_VERSION_KEY] === undefined) { + userStorage = MetamaskNotificationsUtils.initializeUserStorage( + accounts.map((account) => ({ address: account })), + false, + ); + + // Write the userStorage + await this.#storage.setNotificationStorage(JSON.stringify(userStorage)); + } + + // Create the triggers + const triggers = + MetamaskNotificationsUtils.traverseUserStorageTriggers(userStorage); + await OnChainNotifications.createOnChainTriggers( + userStorage, + storageKey, + bearerToken, + triggers, + ); + + // Create push notifications triggers + const allUUIDS = MetamaskNotificationsUtils.getAllUUIDs(userStorage); + await this.#pushNotifications.enablePushNotifications(allUUIDS); + + // Write the new userStorage (triggers are now "enabled") + await this.#storage.setNotificationStorage(JSON.stringify(userStorage)); + + // Update the state of the controller + this.update((state) => { + state.isMetamaskNotificationsEnabled = true; + state.isFeatureAnnouncementsEnabled = true; + state.isMetamaskNotificationsFeatureSeen = true; + }); + + return userStorage; + } catch (err) { + log.error('Failed to create On Chain triggers', err); + throw new Error('Failed to create On Chain triggers'); + } finally { + this.#setIsUpdatingMetamaskNotifications(false); + } + } + + /** + * Enables all MetaMask notifications for the user. + * This is identical flow when initializing notifications for the first time. + * 1. Enable Profile Syncing + * 2. Get or Create Notification User Storage + * 3. Upsert Triggers + * 4. Update Push notifications + * + * @throws {Error} If there is an error during the process of enabling notifications. + */ + public async enableMetamaskNotifications() { + try { + this.#setIsUpdatingMetamaskNotifications(true); + await this.createOnChainTriggers(); + } catch (e) { + log.error('Unable to enable notifications', e); + throw new Error('Unable to enable notifications'); + } finally { + this.#setIsUpdatingMetamaskNotifications(false); + } + } + + /** + * Disables all MetaMask notifications for the user. + * This method ensures that the user is authenticated, retrieves all linked accounts, + * and disables on-chain triggers for each account. It also sets the global notification + * settings for MetaMask, feature announcements to false. + * + * @throws {Error} If the user is not authenticated or if there is an error during the process. + */ + public async disableMetamaskNotifications() { + try { + this.#setIsUpdatingMetamaskNotifications(true); + + // Disable Push Notifications + const userStorage = await this.#getUserStorage(); + this.#assertUserStorage(userStorage); + const UUIDs = MetamaskNotificationsUtils.getAllUUIDs(userStorage); + await this.#pushNotifications.disablePushNotifications(UUIDs); + + // Clear Notification States (toggles and list) + this.update((state) => { + state.isMetamaskNotificationsEnabled = false; + state.isFeatureAnnouncementsEnabled = false; + state.metamaskNotificationsList = []; + }); + } catch (e) { + log.error('Unable to disable notifications', e); + throw new Error('Unable to disable notifications'); + } finally { + this.#setIsUpdatingMetamaskNotifications(false); + } + } + + /** + * Deletes on-chain triggers associated with a specific account. + * This method performs several key operations: + * 1. Validates Auth & Storage + * 2. Finds and deletes all triggers associated with the account + * 3. Disables any related push notifications + * 4. Updates Storage to reflect new state. + * + * **Action** - When a user disables notifications for a given account in settings. + * + * @param accounts - The account for which on-chain triggers are to be deleted. + * @returns A promise that resolves to void or an object containing a success message. + * @throws {Error} Throws an error if unauthenticated or from other operations. + */ + public async deleteOnChainTriggersByAccount( + accounts: string[], + ): Promise { + try { + this.#updateUpdatingAccountsState(accounts); + // Get and Validate BearerToken and User Storage Key + const { bearerToken, storageKey } = + await this.#getValidStorageKeyAndBearerToken(); + + // Get & Validate User Storage + const userStorage = await this.#getUserStorage(); + this.#assertUserStorage(userStorage); + + // Get the UUIDs to delete + const UUIDs = accounts + .map((a) => + MetamaskNotificationsUtils.getUUIDsForAccount( + userStorage, + a.toLowerCase(), + ), + ) + .flat(); + + if (UUIDs.length === 0) { + return userStorage; + } + + // Delete these UUIDs (Mutates User Storage) + await OnChainNotifications.deleteOnChainTriggers( + userStorage, + storageKey, + bearerToken, + UUIDs, + ); + + // Delete these UUIDs from the push notifications + await this.#pushNotifications.disablePushNotifications(UUIDs); + + // Update User Storage + await this.#storage.setNotificationStorage(JSON.stringify(userStorage)); + return userStorage; + } catch (err) { + log.error('Failed to delete OnChain triggers', err); + throw new Error('Failed to delete OnChain triggers'); + } finally { + this.#clearUpdatingAccountsState(accounts); + } + } + + /** + * Updates/Creates on-chain triggers for a specific account. + * + * This method performs several key operations: + * 1. Validates Auth & Storage + * 2. Finds and creates any missing triggers associated with the account + * 3. Enables any related push notifications + * 4. Updates Storage to reflect new state. + * + * **Action** - When a user enables notifications for an account + * + * @param accounts - List of accounts you want to update. + * @returns A promise that resolves to the updated user storage. + * @throws {Error} Throws an error if unauthenticated or from other operations. + */ + public async updateOnChainTriggersByAccount( + accounts: string[], + ): Promise { + try { + this.#updateUpdatingAccountsState(accounts); + // Get and Validate BearerToken and User Storage Key + const { bearerToken, storageKey } = + await this.#getValidStorageKeyAndBearerToken(); + + // Get & Validate User Storage + const userStorage = await this.#getUserStorage(); + this.#assertUserStorage(userStorage); + + // Add any missing triggers + accounts.forEach((a) => + MetamaskNotificationsUtils.upsertAddressTriggers(a, userStorage), + ); + + const newTriggers = + MetamaskNotificationsUtils.traverseUserStorageTriggers(userStorage, { + mapTrigger: (t) => { + if (t.enabled === false) { + return t; + } + return undefined; + }, + }); + + // Create any missing triggers. + if (newTriggers.length > 0) { + // Write te updated userStorage (where triggers are disabled) + await this.#storage.setNotificationStorage(JSON.stringify(userStorage)); + + // Create the triggers + const triggers = MetamaskNotificationsUtils.traverseUserStorageTriggers( + userStorage, + { + mapTrigger: (t) => { + if ( + accounts.some( + (a) => a.toLowerCase() === t.address.toLowerCase(), + ) + ) { + return t; + } + return undefined; + }, + }, + ); + await OnChainNotifications.createOnChainTriggers( + userStorage, + storageKey, + bearerToken, + triggers, + ); + } + + // Update Push Notifications Triggers + const UUIDs = MetamaskNotificationsUtils.getAllUUIDs(userStorage); + await this.#pushNotifications.updatePushNotifications(UUIDs); + + // Update the userStorage (where triggers are enabled) + await this.#storage.setNotificationStorage(JSON.stringify(userStorage)); + return userStorage; + } catch (err) { + log.error('Failed to update OnChain triggers', err); + throw new Error('Failed to update OnChain triggers'); + } finally { + this.#clearUpdatingAccountsState(accounts); + } + } + + /** + * Fetches the list of metamask notifications. + * This includes OnChain notifications and Feature Announcements. + * + * **Action** - When a user views the notification list page/dropdown + * + * @throws {Error} Throws an error if unauthenticated or from other operations. + */ + public async fetchAndUpdateMetamaskNotifications(): Promise { + try { + this.#setIsFetchingMetamaskNotifications(true); + + // Raw Feature Notifications + const rawFeatureAnnouncementNotifications = this.state + .isFeatureAnnouncementsEnabled + ? await FeatureNotifications.getFeatureAnnouncementNotifications().catch( + () => [], + ) + : []; + + // Raw On Chain Notifications + const rawOnChainNotifications: OnChainRawNotification[] = []; + const userStorage = await this.#storage + .getNotificationStorage() + .then((s) => s && (JSON.parse(s) as UserStorage)) + .catch(() => null); + const bearerToken = await this.#auth.getBearerToken().catch(() => null); + if (userStorage && bearerToken) { + const notifications = + await OnChainNotifications.getOnChainNotifications( + userStorage, + bearerToken, + ).catch(() => []); + + rawOnChainNotifications.push(...notifications); + } + + const readIds = this.state.metamaskNotificationsReadList; + + // Combined Notifications + const isNotUndefined = (t?: T): t is T => Boolean(t); + const processAndFilter = (ns: NotificationUnion[]) => + ns + .map((n) => { + try { + return processNotification(n, readIds); + } catch { + // So we don't throw and show no notifications + return undefined; + } + }) + .filter(isNotUndefined); + + const featureAnnouncementNotifications = processAndFilter( + rawFeatureAnnouncementNotifications, + ); + const onChainNotifications = processAndFilter(rawOnChainNotifications); + + const metamaskNotifications: Notification[] = [ + ...featureAnnouncementNotifications, + ...onChainNotifications, + ]; + metamaskNotifications.sort( + (a, b) => + new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), + ); + + // Update State + this.update((state) => { + state.metamaskNotificationsList = metamaskNotifications; + }); + + this.messagingSystem.publish( + `${controllerName}:notificationsListUpdated`, + this.state.metamaskNotificationsList, + ); + + this.#setIsFetchingMetamaskNotifications(false); + return metamaskNotifications; + } catch (err) { + this.#setIsFetchingMetamaskNotifications(false); + log.error('Failed to fetch notifications', err); + throw new Error('Failed to fetch notifications'); + } + } + + /** + * Marks specified metamask notifications as read. + * + * @param notifications - An array of notifications to be marked as read. Each notification should include its type and read status. + * @returns A promise that resolves when the operation is complete. + */ + public async markMetamaskNotificationsAsRead( + notifications: MarkAsReadNotificationsParam, + ): Promise { + let onchainNotificationIds: string[] = []; + let featureAnnouncementNotificationIds: string[] = []; + + try { + // Filter unread on/off chain notifications + const onChainNotifications = notifications.filter( + (notification) => + notification.type !== TRIGGER_TYPES.FEATURES_ANNOUNCEMENT && + !notification.isRead, + ); + + const featureAnnouncementNotifications = notifications.filter( + (notification) => + notification.type === TRIGGER_TYPES.FEATURES_ANNOUNCEMENT && + !notification.isRead, + ); + + // Mark On-Chain Notifications as Read + if (onChainNotifications.length > 0) { + const bearerToken = await this.#auth.getBearerToken(); + + if (bearerToken) { + onchainNotificationIds = onChainNotifications.map( + (notification) => notification.id, + ); + await OnChainNotifications.markNotificationsAsRead( + bearerToken, + onchainNotificationIds, + ).catch(() => { + onchainNotificationIds = []; + log.warn('Unable to mark onchain notifications as read'); + }); + } + } + + // Mark Off-Chain notifications as Read + if (featureAnnouncementNotifications.length > 0) { + featureAnnouncementNotificationIds = + featureAnnouncementNotifications.map( + (notification) => notification.id, + ); + } + } catch (err) { + log.warn('Something failed when marking notifications as read', err); + } + + // Update the state + this.update((state) => { + const currentReadList = state.metamaskNotificationsReadList; + const newReadIds = [...featureAnnouncementNotificationIds]; + state.metamaskNotificationsReadList = [ + ...new Set([...currentReadList, ...newReadIds]), + ]; + + state.metamaskNotificationsList = state.metamaskNotificationsList.map( + (notification: Notification) => { + if ( + newReadIds.includes(notification.id) || + onchainNotificationIds.includes(notification.id) + ) { + return { ...notification, isRead: true }; + } + return notification; + }, + ); + }); + + // Publish the event + this.messagingSystem.publish( + `${controllerName}:markNotificationsAsRead`, + this.state.metamaskNotificationsList, + ); + } + + /** + * Updates the list of MetaMask notifications by adding a new notification at the beginning of the list. + * This method ensures that the most recent notification is displayed first in the UI. + * + * @param notification - The new notification object to be added to the list. + * @returns A promise that resolves when the notification list has been successfully updated. + */ + public async updateMetamaskNotificationsList( + notification: Notification, + ): Promise { + if ( + this.state.metamaskNotificationsList.some((n) => n.id === notification.id) + ) { + return; + } + + const processedNotification = + processAndFilterSingleNotification(notification); + + if (processedNotification) { + this.update((state) => { + const existingNotificationIds = new Set( + state.metamaskNotificationsList.map((n) => n.id), + ); + // Add the new notification only if its ID is not already present in the list + if (!existingNotificationIds.has(notification.id)) { + state.metamaskNotificationsList = [ + notification, + ...state.metamaskNotificationsList, + ]; + this.messagingSystem.publish( + `${controllerName}:notificationsListUpdated`, + state.metamaskNotificationsList, + ); + } + }); + } + } +} + +const isNotUndefined = (t?: T): t is T => Boolean(t); +function processAndFilterSingleNotification(n: NotificationUnion) { + try { + const processedNotification = processNotification(n); + if (isNotUndefined(processedNotification)) { + return processedNotification; + } + } catch { + return undefined; + } + return undefined; +} diff --git a/app/scripts/controllers/metamask-notifications/mocks/mock-feature-announcements.ts b/app/scripts/controllers/metamask-notifications/mocks/mock-feature-announcements.ts new file mode 100644 index 000000000000..71e2b637e5bb --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/mocks/mock-feature-announcements.ts @@ -0,0 +1,201 @@ +import { ContentfulResult } from '../services/feature-announcements'; +import { FeatureAnnouncementRawNotification } from '../types/feature-announcement/feature-announcement'; +import { TRIGGER_TYPES } from '../constants/notification-schema'; + +export function createMockFeatureAnnouncementAPIResult(): ContentfulResult { + return { + sys: { + type: 'Array', + }, + total: 17, + skip: 0, + limit: 1, + items: [ + { + metadata: { + tags: [], + }, + sys: { + space: { + sys: { + type: 'Link', + linkType: 'Space', + id: 'jdkgyfmyd9sw', + }, + }, + id: '1ABRmHaNCgmxROKXXLXsMu', + type: 'Entry', + createdAt: '2024-04-09T13:24:01.872Z', + updatedAt: '2024-04-09T13:24:01.872Z', + environment: { + sys: { + id: 'master', + type: 'Link', + linkType: 'Environment', + }, + }, + revision: 1, + contentType: { + sys: { + type: 'Link', + linkType: 'ContentType', + id: 'productAnnouncement', + }, + }, + locale: 'en-US', + }, + fields: { + title: 'Don’t miss out on airdrops and new NFT mints!', + id: 'dont-miss-out-on-airdrops-and-new-nft-mints', + category: 'ANNOUNCEMENT', + shortDescription: + 'Check your airdrop eligibility and see trending NFT drops. Head over to the Explore tab to get started. ', + image: { + sys: { + type: 'Link', + linkType: 'Asset', + id: '5jqq8sFeLc6XEoeWlpI3aB', + }, + }, + longDescription: { + data: {}, + content: [ + { + data: {}, + content: [ + { + data: {}, + marks: [], + value: + 'You can now verify if any of your connected addresses are eligible for airdrops and other ERC-20 claims in a secure and convenient way. We’ve also added trending NFT mints based on creators you’ve minted from before or other tokens you hold. Head over to the Explore tab to get started. \n', + nodeType: 'text', + }, + ], + nodeType: 'paragraph', + }, + ], + nodeType: 'document', + }, + link: { + sys: { + type: 'Link', + linkType: 'Entry', + id: '62xKYM2ydo4F1mS5q97K5q', + }, + }, + }, + }, + ], + includes: { + Entry: [ + { + metadata: { + tags: [], + }, + sys: { + space: { + sys: { + type: 'Link', + linkType: 'Space', + id: 'jdkgyfmyd9sw', + }, + }, + id: '62xKYM2ydo4F1mS5q97K5q', + type: 'Entry', + createdAt: '2024-04-09T13:23:03.636Z', + updatedAt: '2024-04-09T13:23:03.636Z', + environment: { + sys: { + id: 'master', + type: 'Link', + linkType: 'Environment', + }, + }, + revision: 1, + contentType: { + sys: { + type: 'Link', + linkType: 'ContentType', + id: 'link', + }, + }, + locale: 'en-US', + }, + fields: { + extensionLinkText: 'Try now', + extensionLinkRoute: 'home.html', + }, + }, + ], + Asset: [ + { + metadata: { + tags: [], + }, + sys: { + space: { + sys: { + type: 'Link', + linkType: 'Space', + id: 'jdkgyfmyd9sw', + }, + }, + id: '5jqq8sFeLc6XEoeWlpI3aB', + type: 'Asset', + createdAt: '2024-04-09T13:23:13.327Z', + updatedAt: '2024-04-09T13:23:13.327Z', + environment: { + sys: { + id: 'master', + type: 'Link', + linkType: 'Environment', + }, + }, + revision: 1, + locale: 'en-US', + }, + fields: { + title: 'PDAPP notification image Airdrops & NFT mints', + description: '', + file: { + url: '//images.ctfassets.net/jdkgyfmyd9sw/5jqq8sFeLc6XEoeWlpI3aB/73ee0f1afa9916c3a7538b0bbee09c26/PDAPP_notification_image_Airdrops___NFT_mints.png', + details: { + size: 797731, + image: { + width: 2880, + height: 1921, + }, + }, + fileName: 'PDAPP notification image_Airdrops & NFT mints.png', + contentType: 'image/png', + }, + }, + }, + ], + }, + } as unknown as ContentfulResult; +} + +export function createMockFeatureAnnouncementRaw(): FeatureAnnouncementRawNotification { + return { + type: TRIGGER_TYPES.FEATURES_ANNOUNCEMENT, + createdAt: '2999-04-09T13:24:01.872Z', + data: { + id: 'dont-miss-out-on-airdrops-and-new-nft-mints', + category: 'ANNOUNCEMENT', + title: 'Don’t miss out on airdrops and new NFT mints!', + longDescription: `

You can now verify if any of your connected addresses are eligible for airdrops and other ERC-20 claims in a secure and convenient way. We’ve also added trending NFT mints based on creators you’ve minted from before or other tokens you hold. Head over to the Explore tab to get started.

`, + shortDescription: + 'Check your airdrop eligibility and see trending NFT drops. Head over to the Explore tab to get started.', + image: { + title: 'PDAPP notification image Airdrops & NFT mints', + description: '', + url: '//images.ctfassets.net/jdkgyfmyd9sw/5jqq8sFeLc6XEoeWlpI3aB/73ee0f1afa9916c3a7538b0bbee09c26/PDAPP_notification_image_Airdrops___NFT_mints.png', + }, + extensionLink: { + extensionLinkText: 'Try now', + extensionLinkRoute: 'home.html', + }, + }, + }; +} diff --git a/app/scripts/controllers/metamask-notifications/mocks/mock-notification-trigger.ts b/app/scripts/controllers/metamask-notifications/mocks/mock-notification-trigger.ts new file mode 100644 index 000000000000..d4ce4a61114f --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/mocks/mock-notification-trigger.ts @@ -0,0 +1,15 @@ +import { v4 as uuidv4 } from 'uuid'; +import { NotificationTrigger } from '../utils/utils'; + +export function createMockNotificationTrigger( + override?: Partial, +): NotificationTrigger { + return { + id: uuidv4(), + address: '0xFAKE_ADDRESS', + chainId: '1', + kind: 'eth_sent', + enabled: true, + ...override, + }; +} diff --git a/app/scripts/controllers/metamask-notifications/mocks/mock-notification-user-storage.ts b/app/scripts/controllers/metamask-notifications/mocks/mock-notification-user-storage.ts new file mode 100644 index 000000000000..a799a8d35b52 --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/mocks/mock-notification-user-storage.ts @@ -0,0 +1,72 @@ +import { TRIGGER_TYPES } from '../constants/notification-schema'; +import { USER_STORAGE_VERSION_KEY } from '../constants/constants'; +import { UserStorage } from '../types/user-storage/user-storage'; +import { initializeUserStorage } from '../utils/utils'; + +export const MOCK_USER_STORAGE_ACCOUNT = + '0x0000000000000000000000000000000000000000'; +export const MOCK_USER_STORAGE_CHAIN = '1'; + +export function createMockUserStorage( + override?: Partial, +): UserStorage { + return { + [USER_STORAGE_VERSION_KEY]: '1', + [MOCK_USER_STORAGE_ACCOUNT]: { + [MOCK_USER_STORAGE_CHAIN]: { + '111-111-111-111': { + k: TRIGGER_TYPES.ERC20_RECEIVED, + e: true, + }, + '222-222-222-222': { + k: TRIGGER_TYPES.ERC20_SENT, + e: true, + }, + }, + }, + ...override, + }; +} + +export function createMockUserStorageWithTriggers( + triggers: string[] | { id: string; e: boolean; k?: TRIGGER_TYPES }[], +): UserStorage { + const userStorage: UserStorage = { + [USER_STORAGE_VERSION_KEY]: '1', + [MOCK_USER_STORAGE_ACCOUNT]: { + [MOCK_USER_STORAGE_CHAIN]: {}, + }, + }; + + // insert triggerIds + triggers.forEach((t) => { + let tId: string; + let e: boolean; + let k: TRIGGER_TYPES; + if (typeof t === 'string') { + tId = t; + e = true; + k = TRIGGER_TYPES.ERC20_RECEIVED; + } else { + tId = t.id; + e = t.e; + k = t.k ?? TRIGGER_TYPES.ERC20_RECEIVED; + } + + userStorage[MOCK_USER_STORAGE_ACCOUNT][MOCK_USER_STORAGE_CHAIN][tId] = { + k, + e, + }; + }); + + return userStorage; +} + +export function createMockFullUserStorage( + props: { triggersEnabled?: boolean; address?: string } = {}, +): UserStorage { + return initializeUserStorage( + [{ address: props.address ?? MOCK_USER_STORAGE_ACCOUNT }], + props.triggersEnabled ?? true, + ); +} diff --git a/app/scripts/controllers/metamask-notifications/mocks/mock-raw-notifications.ts b/app/scripts/controllers/metamask-notifications/mocks/mock-raw-notifications.ts new file mode 100644 index 000000000000..f78b4a53a21f --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/mocks/mock-raw-notifications.ts @@ -0,0 +1,609 @@ +import { TRIGGER_TYPES } from '../constants/notification-schema'; +import type { OnChainRawNotification } from '../types/on-chain-notification/on-chain-notification'; + +export function createMockNotificationEthSent() { + const mockNotification: OnChainRawNotification = { + type: TRIGGER_TYPES.ETH_SENT, + id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + trigger_id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + chain_id: 1, + block_number: 17485840, + block_timestamp: '2022-03-01T00:00:00Z', + tx_hash: '0x881D40237659C251811CEC9c364ef91dC08D300C', + unread: true, + created_at: '2022-03-01T00:00:00Z', + address: '0x881D40237659C251811CEC9c364ef91dC08D300C', + data: { + kind: 'eth_sent', + network_fee: { + gas_price: '207806259583', + native_token_price_in_usd: '0.83', + }, + from: '0x881D40237659C251811CEC9c364ef91dC08D300C', + to: '0x881D40237659C251811CEC9c364ef91dC08D300D', + amount: { + usd: '670.64', + eth: '0.005', + }, + }, + }; + + return mockNotification; +} + +export function createMockNotificationEthReceived() { + const mockNotification: OnChainRawNotification = { + type: TRIGGER_TYPES.ETH_RECEIVED, + id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + trigger_id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + chain_id: 1, + block_number: 17485840, + block_timestamp: '2022-03-01T00:00:00Z', + tx_hash: '0x881D40237659C251811CEC9c364ef91dC08D300C', + unread: true, + created_at: '2022-03-01T00:00:00Z', + address: '0x881D40237659C251811CEC9c364ef91dC08D300C', + data: { + kind: 'eth_received', + network_fee: { + gas_price: '207806259583', + native_token_price_in_usd: '0.83', + }, + from: '0x881D40237659C251811CEC9c364ef91dC08D300C', + to: '0x881D40237659C251811CEC9c364ef91dC08D300D', + amount: { + usd: '670.64', + eth: '808.000000000000000000', + }, + }, + }; + + return mockNotification; +} + +export function createMockNotificationERC20Sent() { + const mockNotification: OnChainRawNotification = { + type: TRIGGER_TYPES.ERC20_SENT, + id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + trigger_id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + chain_id: 1, + block_number: 17485840, + block_timestamp: '2022-03-01T00:00:00Z', + tx_hash: '0x881D40237659C251811CEC9c364ef91dC08D300C', + unread: true, + created_at: '2022-03-01T00:00:00Z', + address: '0x881D40237659C251811CEC9c364ef91dC08D300C', + data: { + kind: 'erc20_sent', + network_fee: { + gas_price: '207806259583', + native_token_price_in_usd: '0.83', + }, + to: '0xecc19e177d24551aa7ed6bc6fe566eca726cc8a9', + from: '0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae', + token: { + usd: '1.00', + name: 'USDC', + image: + 'https://raw.githubusercontent.com/MetaMask/contract-metadata/master/images/usdc.svg', + amount: '4956250000', + symbol: 'USDC', + address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + decimals: '6', + }, + }, + }; + + return mockNotification; +} + +export function createMockNotificationERC20Received() { + const mockNotification: OnChainRawNotification = { + type: TRIGGER_TYPES.ERC20_RECEIVED, + id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + trigger_id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + chain_id: 1, + block_number: 17485840, + block_timestamp: '2022-03-01T00:00:00Z', + tx_hash: '0x881D40237659C251811CEC9c364ef91dC08D300C', + unread: true, + created_at: '2022-03-01T00:00:00Z', + address: '0x881D40237659C251811CEC9c364ef91dC08D300C', + data: { + kind: 'erc20_received', + network_fee: { + gas_price: '207806259583', + native_token_price_in_usd: '0.83', + }, + to: '0xeae7380dd4cef6fbd1144f49e4d1e6964258a4f4', + from: '0x51c72848c68a965f66fa7a88855f9f7784502a7f', + token: { + usd: '0.00', + name: 'SHIBA INU', + image: + 'https://raw.githubusercontent.com/MetaMask/contract-metadata/master/images/shib.svg', + amount: '8382798736999999457296646144', + symbol: 'SHIB', + address: '0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce', + decimals: '18', + }, + }, + }; + + return mockNotification; +} + +export function createMockNotificationERC721Sent() { + const mockNotification: OnChainRawNotification = { + type: TRIGGER_TYPES.ERC721_SENT, + block_number: 18576643, + block_timestamp: '1700043467', + chain_id: 1, + created_at: '2023-11-15T11:08:17.895407Z', + address: '0x881D40237659C251811CEC9c364ef91dC08D300C', + data: { + to: '0xf47f628fe3bd2595e9ab384bfffc3859b448e451', + nft: { + // This is not a hex color + // eslint-disable-next-line @metamask/design-tokens/color-no-hex + name: 'Captainz #8680', + image: + 'https://i.seadn.io/s/raw/files/ae0fc06714ff7fb40217340d8a242c0e.gif?w=500&auto=format', + token_id: '8680', + collection: { + name: 'The Captainz', + image: + 'https://i.seadn.io/gcs/files/6df4d75778066bce740050615bc84e21.png?w=500&auto=format', + symbol: 'Captainz', + address: '0x769272677fab02575e84945f03eca517acc544cc', + }, + }, + from: '0x24a0bb54b7e7a8e406e9b28058a9fd6c49e6df4f', + kind: 'erc721_sent', + network_fee: { + gas_price: '24550653274', + native_token_price_in_usd: '1986.61', + }, + }, + id: 'a4193058-9814-537e-9df4-79dcac727fb6', + trigger_id: '028485be-b994-422b-a93b-03fcc01ab715', + tx_hash: + '0x0833c69fb41cf972a0f031fceca242939bc3fcf82b964b74606649abcad371bd', + unread: true, + }; + + return mockNotification; +} + +export function createMockNotificationERC721Received() { + const mockNotification: OnChainRawNotification = { + type: TRIGGER_TYPES.ERC721_RECEIVED, + block_number: 18571446, + block_timestamp: '1699980623', + chain_id: 1, + created_at: '2023-11-14T17:40:52.319281Z', + address: '0x881D40237659C251811CEC9c364ef91dC08D300C', + data: { + to: '0xba7f3daa8adfdad686574406ab9bd5d2f0a49d2e', + nft: { + // This is not a hex color + // eslint-disable-next-line @metamask/design-tokens/color-no-hex + name: 'The Plague #2722', + image: + 'https://i.seadn.io/s/raw/files/a96f90ec8ebf55a2300c66a0c46d6a16.png?w=500&auto=format', + token_id: '2722', + collection: { + name: 'The Plague NFT', + image: + 'https://i.seadn.io/gcs/files/4577987a5ca45ca5118b2e31559ee4d1.jpg?w=500&auto=format', + symbol: 'FROG', + address: '0xc379e535caff250a01caa6c3724ed1359fe5c29b', + }, + }, + from: '0x24a0bb54b7e7a8e406e9b28058a9fd6c49e6df4f', + kind: 'erc721_received', + network_fee: { + gas_price: '53701898538', + native_token_price_in_usd: '2047.01', + }, + }, + id: '00a79d24-befa-57ed-a55a-9eb8696e1654', + trigger_id: 'd24ac26a-8579-49ec-9947-d04d63592ebd', + tx_hash: + '0xe554c9e29e6eeca8ba94da4d047334ba08b8eb9ca3b801dd69cec08dfdd4ae43', + unread: true, + }; + + return mockNotification; +} + +export function createMockNotificationERC1155Sent() { + const mockNotification: OnChainRawNotification = { + type: TRIGGER_TYPES.ERC1155_SENT, + block_number: 18615206, + block_timestamp: '1700510003', + chain_id: 1, + created_at: '2023-11-20T20:44:10.110706Z', + address: '0x881D40237659C251811CEC9c364ef91dC08D300C', + data: { + to: '0x15bd77ccacf2da39b84f0c31fee2e451225bb190', + nft: { + name: 'IlluminatiNFT DAO', + image: + 'https://i.seadn.io/gcs/files/79a77cb37c7b2f1069f752645d29fea7.jpg?w=500&auto=format', + token_id: '1', + collection: { + name: 'IlluminatiNFT DAO', + image: + 'https://i.seadn.io/gae/LTKz3om2eCQfn3M6PkqEmY7KhLtdMCOm0QVch2318KJq7-KyToCH7NBTMo4UuJ0AZI-oaBh1HcgrAEIEWYbXY3uMcYpuGXunaXEh?w=500&auto=format', + symbol: 'TRUTH', + address: '0xe25f0fe686477f9df3c2876c4902d3b85f75f33a', + }, + }, + from: '0x0000000000000000000000000000000000000000', + kind: 'erc1155_sent', + network_fee: { + gas_price: '33571446596', + native_token_price_in_usd: '2038.88', + }, + }, + id: 'a09ff9d1-623a-52ab-a3d4-c7c8c9a58362', + trigger_id: 'e2130f7d-78b8-4c34-999a-3f3d3bb5b03c', + tx_hash: + '0x03381aba290facbaf71c123e263c8dc3dd550aac00ef589cce395182eaeff76f', + unread: true, + }; + + return mockNotification; +} + +export function createMockNotificationERC1155Received() { + const mockNotification: OnChainRawNotification = { + type: TRIGGER_TYPES.ERC1155_RECEIVED, + block_number: 18615206, + block_timestamp: '1700510003', + chain_id: 1, + created_at: '2023-11-20T20:44:10.110706Z', + address: '0x881D40237659C251811CEC9c364ef91dC08D300C', + data: { + to: '0x15bd77ccacf2da39b84f0c31fee2e451225bb190', + nft: { + name: 'IlluminatiNFT DAO', + image: + 'https://i.seadn.io/gcs/files/79a77cb37c7b2f1069f752645d29fea7.jpg?w=500&auto=format', + token_id: '1', + collection: { + name: 'IlluminatiNFT DAO', + image: + 'https://i.seadn.io/gae/LTKz3om2eCQfn3M6PkqEmY7KhLtdMCOm0QVch2318KJq7-KyToCH7NBTMo4UuJ0AZI-oaBh1HcgrAEIEWYbXY3uMcYpuGXunaXEh?w=500&auto=format', + symbol: 'TRUTH', + address: '0xe25f0fe686477f9df3c2876c4902d3b85f75f33a', + }, + }, + from: '0x0000000000000000000000000000000000000000', + kind: 'erc1155_received', + network_fee: { + gas_price: '33571446596', + native_token_price_in_usd: '2038.88', + }, + }, + id: 'b6b93c84-e8dc-54ed-9396-7ea50474843a', + trigger_id: '710c8abb-43a9-42a5-9d86-9dd258726c82', + tx_hash: + '0x03381aba290facbaf71c123e263c8dc3dd550aac00ef589cce395182eaeff76f', + unread: true, + }; + + return mockNotification; +} + +export function createMockNotificationMetaMaskSwapsCompleted() { + const mockNotification: OnChainRawNotification = { + type: TRIGGER_TYPES.METAMASK_SWAP_COMPLETED, + block_number: 18377666, + block_timestamp: '1697637275', + chain_id: 1, + created_at: '2023-10-18T13:58:49.854596Z', + address: '0x881D40237659C251811CEC9c364ef91dC08D300C', + data: { + kind: 'metamask_swap_completed', + rate: '1558.27', + token_in: { + usd: '1576.73', + image: + 'https://token.api.cx.metamask.io/assets/nativeCurrencyLogos/ethereum.svg', + amount: '9000000000000000', + symbol: 'ETH', + address: '0x0000000000000000000000000000000000000000', + decimals: '18', + name: 'Ethereum', + }, + token_out: { + usd: '1.00', + image: + 'https://raw.githubusercontent.com/MetaMask/contract-metadata/master/images/usdt.svg', + amount: '14024419', + symbol: 'USDT', + address: '0xdac17f958d2ee523a2206206994597c13d831ec7', + decimals: '6', + name: 'USDT', + }, + network_fee: { + gas_price: '15406129273', + native_token_price_in_usd: '1576.73', + }, + }, + id: '7ddfe6a1-ac52-5ffe-aa40-f04242db4b8b', + trigger_id: 'd2eaa2eb-2e6e-4fd5-8763-b70ea571b46c', + tx_hash: + '0xf69074290f3aa11bce567aabc9ca0df7a12559dfae1b80ba1a124e9dfe19ecc5', + unread: true, + }; + + return mockNotification; +} + +export function createMockNotificationRocketPoolStakeCompleted() { + const mockNotification: OnChainRawNotification = { + type: TRIGGER_TYPES.ROCKETPOOL_STAKE_COMPLETED, + block_number: 18585057, + block_timestamp: '1700145059', + chain_id: 1, + created_at: '2023-11-20T12:02:48.796824Z', + address: '0x881D40237659C251811CEC9c364ef91dC08D300C', + data: { + kind: 'rocketpool_stake_completed', + stake_in: { + usd: '2031.86', + name: 'Ethereum', + image: + 'https://token.api.cx.metamask.io/assets/nativeCurrencyLogos/ethereum.svg', + amount: '190690478063438272', + symbol: 'ETH', + address: '0x0000000000000000000000000000000000000000', + decimals: '18', + }, + stake_out: { + usd: '2226.49', + name: 'Rocket Pool ETH', + image: + 'https://raw.githubusercontent.com/MetaMask/contract-metadata/master/images/rETH.svg', + amount: '175024360778165879', + symbol: 'RETH', + address: '0xae78736Cd615f374D3085123A210448E74Fc6393', + decimals: '18', + }, + network_fee: { + gas_price: '36000000000', + native_token_price_in_usd: '2031.86', + }, + }, + id: 'c2a2f225-b2fb-5d6c-ba56-e27a5c71ffb9', + trigger_id: '5110ff97-acff-40c0-83b4-11d487b8c7b0', + tx_hash: + '0xcfc0693bf47995907b0f46ef0644cf16dd9a0de797099b2e00fd481e1b2117d3', + unread: true, + }; + + return mockNotification; +} + +export function createMockNotificationRocketPoolUnStakeCompleted() { + const mockNotification: OnChainRawNotification = { + type: TRIGGER_TYPES.ROCKETPOOL_UNSTAKE_COMPLETED, + block_number: 18384336, + block_timestamp: '1697718011', + chain_id: 1, + created_at: '2023-10-19T13:11:10.623042Z', + address: '0x881D40237659C251811CEC9c364ef91dC08D300C', + data: { + kind: 'rocketpool_unstake_completed', + stake_in: { + usd: '1686.34', + image: + 'https://raw.githubusercontent.com/MetaMask/contract-metadata/master/images/rETH.svg', + amount: '66608041413696770', + symbol: 'RETH', + address: '0xae78736Cd615f374D3085123A210448E74Fc6393', + decimals: '18', + name: 'Rocketpool Eth', + }, + stake_out: { + usd: '1553.75', + image: + 'https://token.api.cx.metamask.io/assets/nativeCurrencyLogos/ethereum.svg', + amount: '72387843427700824', + symbol: 'ETH', + address: '0x0000000000000000000000000000000000000000', + decimals: '18', + name: 'Ethereum', + }, + network_fee: { + gas_price: '5656322987', + native_token_price_in_usd: '1553.75', + }, + }, + id: 'd8c246e7-a0a4-5f1d-b079-2b1707665fbc', + trigger_id: '291ec897-f569-4837-b6c0-21001b198dff', + tx_hash: + '0xc7972a7e409abfc62590ec90e633acd70b9b74e76ad02305be8bf133a0e22d5f', + unread: true, + }; + + return mockNotification; +} + +export function createMockNotificationLidoStakeCompleted() { + const mockNotification: OnChainRawNotification = { + type: TRIGGER_TYPES.LIDO_STAKE_COMPLETED, + block_number: 18487118, + block_timestamp: '1698961091', + chain_id: 1, + created_at: '2023-11-02T22:28:49.970865Z', + address: '0x881D40237659C251811CEC9c364ef91dC08D300C', + data: { + kind: 'lido_stake_completed', + stake_in: { + usd: '1806.33', + name: 'Ethereum', + image: + 'https://token.api.cx.metamask.io/assets/nativeCurrencyLogos/ethereum.svg', + amount: '330303634023928032', + symbol: 'ETH', + address: '0x0000000000000000000000000000000000000000', + decimals: '18', + }, + stake_out: { + usd: '1801.30', + name: 'Liquid staked Ether 2.0', + image: + 'https://raw.githubusercontent.com/MetaMask/contract-metadata/master/images/stETH.svg', + amount: '330303634023928032', + symbol: 'STETH', + address: '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84', + decimals: '18', + }, + network_fee: { + gas_price: '26536359866', + native_token_price_in_usd: '1806.33', + }, + }, + id: '9d9b1467-b3ee-5492-8ca2-22382657b690', + trigger_id: 'ec10d66a-f78f-461f-83c9-609aada8cc50', + tx_hash: + '0x8cc0fa805f7c3b1743b14f3b91c6b824113b094f26d4ccaf6a71ad8547ce6a0f', + unread: true, + }; + + return mockNotification; +} + +export function createMockNotificationLidoWithdrawalRequested() { + const mockNotification: OnChainRawNotification = { + type: TRIGGER_TYPES.LIDO_WITHDRAWAL_REQUESTED, + block_number: 18377760, + block_timestamp: '1697638415', + chain_id: 1, + created_at: '2023-10-18T15:04:02.482526Z', + address: '0x881D40237659C251811CEC9c364ef91dC08D300C', + data: { + kind: 'lido_withdrawal_requested', + stake_in: { + usd: '1568.54', + image: + 'https://raw.githubusercontent.com/MetaMask/contract-metadata/master/images/stETH.svg', + amount: '97180668792218669859', + symbol: 'STETH', + address: '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84', + decimals: '18', + name: 'Staked Eth', + }, + stake_out: { + usd: '1576.73', + image: + 'https://token.api.cx.metamask.io/assets/nativeCurrencyLogos/ethereum.svg', + amount: '97180668792218669859', + symbol: 'ETH', + address: '0x0000000000000000000000000000000000000000', + decimals: '18', + name: 'Ethereum', + }, + network_fee: { + gas_price: '11658906980', + native_token_price_in_usd: '1576.73', + }, + }, + id: '29ddc718-78c6-5f91-936f-2bef13a605f0', + trigger_id: 'ef003925-3379-4ba7-9e2d-8218690cadc8', + tx_hash: + '0x58b5f82e084cb750ea174e02b20fbdfd2ba8d78053deac787f34fc38e5d427aa', + unread: true, + }; + + return mockNotification; +} + +export function createMockNotificationLidoWithdrawalCompleted() { + const mockNotification: OnChainRawNotification = { + type: TRIGGER_TYPES.LIDO_WITHDRAWAL_COMPLETED, + block_number: 18378208, + block_timestamp: '1697643851', + chain_id: 1, + created_at: '2023-10-18T16:35:03.147606Z', + address: '0x881D40237659C251811CEC9c364ef91dC08D300C', + data: { + kind: 'lido_withdrawal_completed', + stake_in: { + usd: '1570.23', + image: + 'https://raw.githubusercontent.com/MetaMask/contract-metadata/master/images/stETH.svg', + amount: '35081997661451346', + symbol: 'STETH', + address: '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84', + decimals: '18', + name: 'Staked Eth', + }, + stake_out: { + usd: '1571.74', + image: + 'https://token.api.cx.metamask.io/assets/nativeCurrencyLogos/ethereum.svg', + amount: '35081997661451346', + symbol: 'ETH', + address: '0x0000000000000000000000000000000000000000', + decimals: '18', + name: 'Ethereum', + }, + network_fee: { + gas_price: '12699495150', + native_token_price_in_usd: '1571.74', + }, + }, + id: 'f4ef0b7f-5612-537f-9144-0b5c63ae5391', + trigger_id: 'd73df14d-ce73-4f38-bad3-ab028154042c', + tx_hash: + '0xe6d210d2e601ef3dd1075c48e71452cf35f2daae3886911e964e3babad8ac657', + unread: true, + }; + + return mockNotification; +} + +export function createMockNotificationLidoReadyToBeWithdrawn() { + const mockNotification: OnChainRawNotification = { + type: TRIGGER_TYPES.LIDO_STAKE_READY_TO_BE_WITHDRAWN, + block_number: 18378208, + block_timestamp: '1697643851', + chain_id: 1, + created_at: '2023-10-18T16:35:03.147606Z', + address: '0x881D40237659C251811CEC9c364ef91dC08D300C', + data: { + kind: 'lido_stake_ready_to_be_withdrawn', + request_id: '123456789', + staked_eth: { + address: '0x881D40237659C251811CEC9c364ef91dC08D300F', + symbol: 'ETH', + name: 'Ethereum', + amount: '2.5', + decimals: '18', + image: + 'https://token.api.cx.metamask.io/assets/nativeCurrencyLogos/ethereum.svg', + usd: '10000.00', + }, + }, + id: 'f4ef0b7f-5612-537f-9144-0b5c63ae5391', + trigger_id: 'd73df14d-ce73-4f38-bad3-ab028154042c', + tx_hash: + '0xe6d210d2e601ef3dd1075c48e71452cf35f2daae3886911e964e3babad8ac657', + unread: true, + }; + + return mockNotification; +} + +export function createMockRawOnChainNotifications(): OnChainRawNotification[] { + return [1, 2, 3].map((id) => { + const notification = createMockNotificationEthSent(); + notification.id += `-${id}`; + return notification; + }); +} diff --git a/app/scripts/controllers/metamask-notifications/mocks/mockResponses.ts b/app/scripts/controllers/metamask-notifications/mocks/mockResponses.ts new file mode 100644 index 000000000000..940646c10640 --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/mocks/mockResponses.ts @@ -0,0 +1,59 @@ +import { FEATURE_ANNOUNCEMENT_API } from '../services/feature-announcements'; +import { + NOTIFICATION_API_LIST_ENDPOINT, + NOTIFICATION_API_MARK_ALL_AS_READ_ENDPOINT, + TRIGGER_API_BATCH_ENDPOINT, +} from '../services/onchain-notifications'; +import { createMockFeatureAnnouncementAPIResult } from './mock-feature-announcements'; +import { createMockRawOnChainNotifications } from './mock-raw-notifications'; + +type MockResponse = { + url: string; + requestMethod: 'GET' | 'POST' | 'PUT' | 'DELETE'; + response: unknown; +}; + +export const CONTENTFUL_RESPONSE = createMockFeatureAnnouncementAPIResult(); + +export function getMockFeatureAnnouncementResponse() { + return { + url: FEATURE_ANNOUNCEMENT_API, + requestMethod: 'GET', + response: CONTENTFUL_RESPONSE, + } satisfies MockResponse; +} + +export function getMockBatchCreateTriggersResponse() { + return { + url: TRIGGER_API_BATCH_ENDPOINT, + requestMethod: 'POST', + response: null, + } satisfies MockResponse; +} + +export function getMockBatchDeleteTriggersResponse() { + return { + url: TRIGGER_API_BATCH_ENDPOINT, + requestMethod: 'DELETE', + response: null, + } satisfies MockResponse; +} + +export const MOCK_RAW_ON_CHAIN_NOTIFICATIONS = + createMockRawOnChainNotifications(); + +export function getMockListNotificationsResponse() { + return { + url: NOTIFICATION_API_LIST_ENDPOINT, + requestMethod: 'POST', + response: MOCK_RAW_ON_CHAIN_NOTIFICATIONS, + } satisfies MockResponse; +} + +export function getMockMarkNotificationsAsReadResponse() { + return { + url: NOTIFICATION_API_MARK_ALL_AS_READ_ENDPOINT, + requestMethod: 'POST', + response: null, + } satisfies MockResponse; +} diff --git a/app/scripts/controllers/metamask-notifications/mocks/mockServices.ts b/app/scripts/controllers/metamask-notifications/mocks/mockServices.ts new file mode 100644 index 000000000000..84de50ec8555 --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/mocks/mockServices.ts @@ -0,0 +1,71 @@ +import nock from 'nock'; +import { + getMockBatchCreateTriggersResponse, + getMockBatchDeleteTriggersResponse, + getMockFeatureAnnouncementResponse, + getMockListNotificationsResponse, + getMockMarkNotificationsAsReadResponse, +} from './mockResponses'; + +type MockReply = { + status: nock.StatusCode; + body?: nock.Body; +}; + +export function mockFetchFeatureAnnouncementNotifications( + mockReply?: MockReply, +) { + const mockResponse = getMockFeatureAnnouncementResponse(); + const reply = mockReply ?? { status: 200, body: mockResponse.response }; + const mockEndpoint = nock(mockResponse.url) + .get('') + .query(true) + .reply(reply.status, reply.body); + + return mockEndpoint; +} + +export function mockBatchCreateTriggers(mockReply?: MockReply) { + const mockResponse = getMockBatchCreateTriggersResponse(); + const reply = mockReply ?? { status: 204 }; + + const mockEndpoint = nock(mockResponse.url) + .post('') + .reply(reply.status, reply.body); + + return mockEndpoint; +} + +export function mockBatchDeleteTriggers(mockReply?: MockReply) { + const mockResponse = getMockBatchDeleteTriggersResponse(); + const reply = mockReply ?? { status: 204 }; + + const mockEndpoint = nock(mockResponse.url) + .delete('') + .reply(reply.status, reply.body); + + return mockEndpoint; +} + +export function mockListNotifications(mockReply?: MockReply) { + const mockResponse = getMockListNotificationsResponse(); + const reply = mockReply ?? { status: 200, body: mockResponse.response }; + + const mockEndpoint = nock(mockResponse.url) + .post('') + .query(true) + .reply(reply.status, reply.body); + + return mockEndpoint; +} + +export function mockMarkNotificationsAsRead(mockReply?: MockReply) { + const mockResponse = getMockMarkNotificationsAsReadResponse(); + const reply = mockReply ?? { status: 200 }; + + const mockEndpoint = nock(mockResponse.url) + .post('') + .reply(reply.status, reply.body); + + return mockEndpoint; +} diff --git a/app/scripts/controllers/metamask-notifications/processors/process-feature-announcement.test.ts b/app/scripts/controllers/metamask-notifications/processors/process-feature-announcement.test.ts new file mode 100644 index 000000000000..8785ad47197a --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/processors/process-feature-announcement.test.ts @@ -0,0 +1,52 @@ +import { TRIGGER_TYPES } from '../constants/notification-schema'; +import { createMockFeatureAnnouncementRaw } from '../mocks/mock-feature-announcements'; +import { + isFeatureAnnouncementRead, + processFeatureAnnouncement, +} from './process-feature-announcement'; + +describe('process-feature-announcement - isFeatureAnnouncementRead()', () => { + const MOCK_NOTIFICATION_ID = 'MOCK_NOTIFICATION_ID'; + + test('Returns true if a given notificationId is within list of read platform notifications', () => { + const notification = { + id: MOCK_NOTIFICATION_ID, + createdAt: new Date().toString(), + }; + + const result1 = isFeatureAnnouncementRead(notification, [ + 'id-1', + 'id-2', + MOCK_NOTIFICATION_ID, + ]); + expect(result1).toBe(true); + + const result2 = isFeatureAnnouncementRead(notification, ['id-1', 'id-2']); + expect(result2).toBe(false); + }); + + test('Returns isRead if notification is older than 90 days', () => { + const mockDate = new Date(); + mockDate.setDate(mockDate.getDate() - 100); + + const notification = { + id: MOCK_NOTIFICATION_ID, + createdAt: mockDate.toString(), + }; + + const result = isFeatureAnnouncementRead(notification, []); + expect(result).toBe(true); + }); +}); + +describe('process-feature-announcement - processFeatureAnnouncement()', () => { + test('Processes a Raw Feature Announcement to a shared Notification Type', () => { + const rawNotification = createMockFeatureAnnouncementRaw(); + const result = processFeatureAnnouncement(rawNotification); + + expect(result.id).toBe(rawNotification.data.id); + expect(result.type).toBe(TRIGGER_TYPES.FEATURES_ANNOUNCEMENT); + expect(result.isRead).toBe(false); + expect(result.data).toBeDefined(); + }); +}); diff --git a/app/scripts/controllers/metamask-notifications/processors/process-feature-announcement.ts b/app/scripts/controllers/metamask-notifications/processors/process-feature-announcement.ts new file mode 100644 index 000000000000..260cd8b33a60 --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/processors/process-feature-announcement.ts @@ -0,0 +1,32 @@ +import type { FeatureAnnouncementRawNotification } from '../types/feature-announcement/feature-announcement'; +import type { Notification } from '../types/notification/notification'; + +const ONE_DAY_MS = 1000 * 60 * 60 * 24; + +function shouldAutoExpire(oldDate: Date) { + const differenceInTime = Date.now() - oldDate.getTime(); + const differenceInDays = differenceInTime / ONE_DAY_MS; + return differenceInDays >= 90; +} + +export function isFeatureAnnouncementRead( + notification: Pick, + readPlatformNotificationsList: string[], +): boolean { + if (readPlatformNotificationsList.includes(notification.id)) { + return true; + } + return shouldAutoExpire(new Date(notification.createdAt)); +} + +export function processFeatureAnnouncement( + notification: FeatureAnnouncementRawNotification, +): Notification { + return { + type: notification.type, + id: notification.data.id, + createdAt: new Date(notification.createdAt).toISOString(), + data: notification.data, + isRead: false, + }; +} diff --git a/app/scripts/controllers/metamask-notifications/processors/process-notifications.test.ts b/app/scripts/controllers/metamask-notifications/processors/process-notifications.test.ts new file mode 100644 index 000000000000..c1ed0c03b67e --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/processors/process-notifications.test.ts @@ -0,0 +1,27 @@ +import { TRIGGER_TYPES } from '../constants/notification-schema'; +import { createMockFeatureAnnouncementRaw } from '../mocks/mock-feature-announcements'; +import { createMockNotificationEthSent } from '../mocks/mock-raw-notifications'; +import { processNotification } from './process-notifications'; + +describe('process-notifications - processNotification()', () => { + // More thorough tests are found in the specific process + test('Maps Feature Announcement to shared Notification Type', () => { + const result = processNotification(createMockFeatureAnnouncementRaw()); + expect(result).toBeDefined(); + }); + + // More thorough tests are found in the specific process + test('Maps On Chain Notification to shared Notification Type', () => { + const result = processNotification(createMockNotificationEthSent()); + expect(result).toBeDefined(); + }); + + test('Throws on invalid notification to process', () => { + const rawNotification = createMockNotificationEthSent(); + + // Testing Mock with invalid notification type + rawNotification.type = 'FAKE_NOTIFICATION_TYPE' as TRIGGER_TYPES.ETH_SENT; + + expect(() => processNotification(rawNotification)).toThrow(); + }); +}); diff --git a/app/scripts/controllers/metamask-notifications/processors/process-notifications.ts b/app/scripts/controllers/metamask-notifications/processors/process-notifications.ts new file mode 100644 index 000000000000..ee09cd232e83 --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/processors/process-notifications.ts @@ -0,0 +1,44 @@ +import type { Notification } from '../types/notification/notification'; +import type { OnChainRawNotification } from '../types/on-chain-notification/on-chain-notification'; +import type { FeatureAnnouncementRawNotification } from '../types/feature-announcement/feature-announcement'; +import { TRIGGER_TYPES } from '../constants/notification-schema'; +import type { NotificationUnion } from '../types/types'; +import { processOnChainNotification } from './process-onchain-notifications'; +import { + isFeatureAnnouncementRead, + processFeatureAnnouncement, +} from './process-feature-announcement'; + +const isOnChainNotification = ( + n: NotificationUnion, +): n is OnChainRawNotification => Object.values(TRIGGER_TYPES).includes(n.type); + +const isFeatureAnnouncement = ( + n: NotificationUnion, +): n is FeatureAnnouncementRawNotification => + n.type === TRIGGER_TYPES.FEATURES_ANNOUNCEMENT; + +export function processNotification( + notification: NotificationUnion, + readNotifications: string[] = [], +): Notification { + const exhaustedAllCases = (_: never) => { + throw new Error( + `No processor found for notification kind ${notification.type}`, + ); + }; + + if (isFeatureAnnouncement(notification)) { + const n = processFeatureAnnouncement( + notification as FeatureAnnouncementRawNotification, + ); + n.isRead = isFeatureAnnouncementRead(n, readNotifications); + return n; + } + + if (isOnChainNotification(notification)) { + return processOnChainNotification(notification as OnChainRawNotification); + } + + return exhaustedAllCases(notification as never); +} diff --git a/app/scripts/controllers/metamask-notifications/processors/process-onchain-notifications.test.ts b/app/scripts/controllers/metamask-notifications/processors/process-onchain-notifications.test.ts new file mode 100644 index 000000000000..8c703c0bedda --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/processors/process-onchain-notifications.test.ts @@ -0,0 +1,53 @@ +import { + createMockNotificationEthSent, + createMockNotificationEthReceived, + createMockNotificationERC20Sent, + createMockNotificationERC20Received, + createMockNotificationERC721Sent, + createMockNotificationERC721Received, + createMockNotificationERC1155Sent, + createMockNotificationERC1155Received, + createMockNotificationMetaMaskSwapsCompleted, + createMockNotificationRocketPoolStakeCompleted, + createMockNotificationRocketPoolUnStakeCompleted, + createMockNotificationLidoStakeCompleted, + createMockNotificationLidoWithdrawalRequested, + createMockNotificationLidoWithdrawalCompleted, + createMockNotificationLidoReadyToBeWithdrawn, +} from '../mocks/mock-raw-notifications'; +import { OnChainRawNotification } from '../types/on-chain-notification/on-chain-notification'; +import { processOnChainNotification } from './process-onchain-notifications'; + +const rawNotifications = [ + createMockNotificationEthSent(), + createMockNotificationEthReceived(), + createMockNotificationERC20Sent(), + createMockNotificationERC20Received(), + createMockNotificationERC721Sent(), + createMockNotificationERC721Received(), + createMockNotificationERC1155Sent(), + createMockNotificationERC1155Received(), + createMockNotificationMetaMaskSwapsCompleted(), + createMockNotificationRocketPoolStakeCompleted(), + createMockNotificationRocketPoolUnStakeCompleted(), + createMockNotificationLidoStakeCompleted(), + createMockNotificationLidoWithdrawalRequested(), + createMockNotificationLidoWithdrawalCompleted(), + createMockNotificationLidoReadyToBeWithdrawn(), +]; + +const rawNotificationTestSuite = rawNotifications.map( + (n): [string, OnChainRawNotification] => [n.type, n], +); + +describe('process-onchain-notifications - processOnChainNotification()', () => { + // @ts-expect-error This is missing from the Mocha type definitions + test.each(rawNotificationTestSuite)( + 'Converts Raw On-Chain Notification (%s) to a shared Notification Type', + (_: string, rawNotification: OnChainRawNotification) => { + const result = processOnChainNotification(rawNotification); + expect(result.id).toBe(rawNotification.id); + expect(result.type).toBe(rawNotification.type); + }, + ); +}); diff --git a/app/scripts/controllers/metamask-notifications/processors/process-onchain-notifications.ts b/app/scripts/controllers/metamask-notifications/processors/process-onchain-notifications.ts new file mode 100644 index 000000000000..793bfb1b1f6f --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/processors/process-onchain-notifications.ts @@ -0,0 +1,13 @@ +import type { OnChainRawNotification } from '../types/on-chain-notification/on-chain-notification'; +import type { Notification } from '../types/notification/notification'; + +export function processOnChainNotification( + notification: OnChainRawNotification, +): Notification { + return { + ...notification, + id: notification.id, + createdAt: new Date(notification.created_at).toISOString(), + isRead: !notification.unread, + }; +} diff --git a/app/scripts/controllers/metamask-notifications/services/feature-announcements.test.ts b/app/scripts/controllers/metamask-notifications/services/feature-announcements.test.ts new file mode 100644 index 000000000000..d8a178d065c5 --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/services/feature-announcements.test.ts @@ -0,0 +1,60 @@ +import { TRIGGER_TYPES } from '../constants/notification-schema'; +import { createMockFeatureAnnouncementAPIResult } from '../mocks/mock-feature-announcements'; +import { mockFetchFeatureAnnouncementNotifications } from '../mocks/mockServices'; +import { getFeatureAnnouncementNotifications } from './feature-announcements'; + +jest.mock('@contentful/rich-text-html-renderer', () => ({ + documentToHtmlString: jest + .fn() + .mockImplementation((richText) => `

${richText}

`), +})); + +describe('Feature Announcement Notifications', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should return an empty array if fetch fails', async () => { + const mockEndpoint = mockFetchFeatureAnnouncementNotifications({ + status: 500, + }); + + const notifications = await getFeatureAnnouncementNotifications(); + mockEndpoint.done(); + expect(notifications).toEqual([]); + }); + + it('should return an empty array if data is not available', async () => { + const mockEndpoint = mockFetchFeatureAnnouncementNotifications({ + status: 200, + body: { items: [] }, + }); + + const notifications = await getFeatureAnnouncementNotifications(); + mockEndpoint.done(); + expect(notifications).toEqual([]); + }); + + it('should fetch entries from Contentful and return formatted notifications', async () => { + const mockEndpoint = mockFetchFeatureAnnouncementNotifications({ + status: 200, + body: createMockFeatureAnnouncementAPIResult(), + }); + + const notifications = await getFeatureAnnouncementNotifications(); + expect(notifications).toHaveLength(1); + mockEndpoint.done(); + + const resultNotification = notifications[0]; + expect(resultNotification).toEqual( + expect.objectContaining({ + id: 'dont-miss-out-on-airdrops-and-new-nft-mints', + type: TRIGGER_TYPES.FEATURES_ANNOUNCEMENT, + createdAt: expect.any(String), + isRead: expect.any(Boolean), + }), + ); + + expect(resultNotification.data).toBeDefined(); + }); +}); diff --git a/app/scripts/controllers/metamask-notifications/services/feature-announcements.ts b/app/scripts/controllers/metamask-notifications/services/feature-announcements.ts new file mode 100644 index 000000000000..0fb911497cd7 --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/services/feature-announcements.ts @@ -0,0 +1,122 @@ +import { documentToHtmlString } from '@contentful/rich-text-html-renderer'; +import log from 'loglevel'; +import type { Entry, Asset } from 'contentful'; +import type { + FeatureAnnouncementRawNotification, + TypeFeatureAnnouncement, +} from '../types/feature-announcement/feature-announcement'; +import type { Notification } from '../types/notification/notification'; +import { processFeatureAnnouncement } from '../processors/process-feature-announcement'; +import { TRIGGER_TYPES } from '../constants/notification-schema'; +import { ImageFields } from '../types/feature-announcement/type-feature-announcement'; +import { TypeExtensionLinkFields } from '../types/feature-announcement/type-extension-link'; + +const spaceId = process.env.CONTENTFUL_ACCESS_SPACE_ID || ':space_id'; +const accessToken = process.env.CONTENTFUL_ACCESS_TOKEN || ''; +export const FEATURE_ANNOUNCEMENT_API = `https://cdn.contentful.com/spaces/${spaceId}/environments/master/entries`; +export const FEATURE_ANNOUNCEMENT_URL = `${FEATURE_ANNOUNCEMENT_API}?access_token=${accessToken}&content_type=productAnnouncement&include=10&fields.clients=extension`; + +export type ContentfulResult = { + includes?: { + Entry?: Entry[]; + Asset?: Asset[]; + }; + items?: TypeFeatureAnnouncement[]; +}; + +async function fetchFromContentful( + url: string, + retries = 3, + retryDelay = 1000, +): Promise { + let lastError: Error | null = null; + + for (let i = 0; i < retries; i++) { + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Fetch failed with status: ${response.status}`); + } + return await response.json(); + } catch (error) { + if (error instanceof Error) { + lastError = error; + } + if (i < retries - 1) { + await new Promise((resolve) => setTimeout(resolve, retryDelay)); + } + } + } + + log.error( + `Error fetching from Contentful after ${retries} retries: ${lastError}`, + ); + return null; +} + +async function fetchFeatureAnnouncementNotifications(): Promise< + FeatureAnnouncementRawNotification[] +> { + const data = await fetchFromContentful(FEATURE_ANNOUNCEMENT_URL); + + if (!data) { + return []; + } + + const findIncludedItem = (sysId: string) => { + const item = + data?.includes?.Entry?.find((i: Entry) => i?.sys?.id === sysId) || + data?.includes?.Asset?.find((i: Asset) => i?.sys?.id === sysId); + return item ? item?.fields : null; + }; + + const contentfulNotifications = data?.items ?? []; + const rawNotifications: FeatureAnnouncementRawNotification[] = + contentfulNotifications.map((n: TypeFeatureAnnouncement) => { + const { fields } = n; + const imageFields = fields.image + ? (findIncludedItem(fields.image.sys.id) as ImageFields['fields']) + : undefined; + const extensionLinkFields = fields.extensionLink + ? (findIncludedItem( + fields.extensionLink.sys.id, + ) as TypeExtensionLinkFields['fields']) + : undefined; + + const notification: FeatureAnnouncementRawNotification = { + type: TRIGGER_TYPES.FEATURES_ANNOUNCEMENT, + createdAt: new Date(n.sys.createdAt).toString(), + data: { + id: fields.id, + category: fields.category, + title: fields.title, + longDescription: documentToHtmlString(fields.longDescription), + shortDescription: fields.shortDescription, + image: { + title: imageFields?.title, + description: imageFields?.description, + url: imageFields?.file?.url ?? '', + }, + extensionLink: extensionLinkFields && { + extensionLinkText: extensionLinkFields?.extensionLinkText, + extensionLinkRoute: extensionLinkFields?.extensionLinkRoute, + }, + }, + }; + + return notification; + }); + + return rawNotifications; +} + +export async function getFeatureAnnouncementNotifications(): Promise< + Notification[] +> { + const rawNotifications = await fetchFeatureAnnouncementNotifications(); + const notifications = rawNotifications.map((notification) => + processFeatureAnnouncement(notification), + ); + + return notifications; +} diff --git a/app/scripts/controllers/metamask-notifications/services/onchain-notifications.test.ts b/app/scripts/controllers/metamask-notifications/services/onchain-notifications.test.ts new file mode 100644 index 000000000000..eb205c7e52aa --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/services/onchain-notifications.test.ts @@ -0,0 +1,278 @@ +import { TRIGGER_TYPES } from '../constants/notification-schema'; +import { + mockBatchCreateTriggers, + mockBatchDeleteTriggers, + mockListNotifications, + mockMarkNotificationsAsRead, +} from '../mocks/mockServices'; +import { + MOCK_USER_STORAGE_ACCOUNT, + MOCK_USER_STORAGE_CHAIN, + createMockUserStorageWithTriggers, +} from '../mocks/mock-notification-user-storage'; +import { UserStorage } from '../types/user-storage/user-storage'; +import * as MetamaskNotificationsUtils from '../utils/utils'; +import * as OnChainNotifications from './onchain-notifications'; + +const MOCK_STORAGE_KEY = 'MOCK_USER_STORAGE_KEY'; +const MOCK_BEARER_TOKEN = 'MOCK_BEARER_TOKEN'; +const MOCK_TRIGGER_ID = 'TRIGGER_ID_1'; + +describe('On Chain Notifications - createOnChainTriggers()', () => { + test('Should create new triggers', async () => { + const mocks = arrangeMocks(); + + // The initial trigger to create should not be enabled + assertUserStorageTriggerStatus(mocks.mockUserStorage, false); + + await OnChainNotifications.createOnChainTriggers( + mocks.mockUserStorage, + MOCK_STORAGE_KEY, + MOCK_BEARER_TOKEN, + mocks.triggers, + ); + + mocks.mockEndpoint.done(); + + // once we created triggers, we expect the trigger to be enabled + assertUserStorageTriggerStatus(mocks.mockUserStorage, true); + }); + + test('Does not call endpoint if there are no triggers to create', async () => { + const mocks = arrangeMocks(); + await OnChainNotifications.createOnChainTriggers( + mocks.mockUserStorage, + MOCK_STORAGE_KEY, + MOCK_BEARER_TOKEN, + [], // there are no triggers we've provided that need to be created + ); + + expect(mocks.mockEndpoint.isDone()).toBe(false); + }); + + test('Should throw error if endpoint fails', async () => { + const mockUserStorage = createMockUserStorageWithTriggers([ + { id: MOCK_TRIGGER_ID, k: TRIGGER_TYPES.ETH_SENT, e: false }, + ]); + const triggers = + MetamaskNotificationsUtils.traverseUserStorageTriggers(mockUserStorage); + const mockBadEndpoint = mockBatchCreateTriggers({ + status: 500, + body: { error: 'mock api failure' }, + }); + + // The initial trigger to create should not be enabled + assertUserStorageTriggerStatus(mockUserStorage, false); + + await expect( + OnChainNotifications.createOnChainTriggers( + mockUserStorage, + MOCK_STORAGE_KEY, + MOCK_BEARER_TOKEN, + triggers, + ), + ).rejects.toThrow(); + + mockBadEndpoint.done(); + + // since failed, expect triggers to not be enabled + assertUserStorageTriggerStatus(mockUserStorage, false); + }); + + function assertUserStorageTriggerStatus( + userStorage: UserStorage, + enabled: boolean, + ) { + expect( + userStorage[MOCK_USER_STORAGE_ACCOUNT][MOCK_USER_STORAGE_CHAIN][ + MOCK_TRIGGER_ID + ].e, + ).toBe(enabled); + } + + function arrangeMocks() { + const mockUserStorage = createMockUserStorageWithTriggers([ + { id: MOCK_TRIGGER_ID, k: TRIGGER_TYPES.ETH_SENT, e: false }, + ]); + const triggers = + MetamaskNotificationsUtils.traverseUserStorageTriggers(mockUserStorage); + const mockEndpoint = mockBatchCreateTriggers(); + + return { + mockUserStorage, + triggers, + mockEndpoint, + }; + } +}); + +describe('On Chain Notifications - deleteOnChainTriggers()', () => { + test('Should delete a trigger from API and in user storage', async () => { + const { mockUserStorage, triggerId1, triggerId2 } = arrangeUserStorage(); + const mockEndpoint = mockBatchDeleteTriggers(); + + // Assert that triggers exists + [triggerId1, triggerId2].forEach((t) => { + expect(getTriggerFromUserStorage(mockUserStorage, t)).toBeDefined(); + }); + + await OnChainNotifications.deleteOnChainTriggers( + mockUserStorage, + MOCK_STORAGE_KEY, + MOCK_BEARER_TOKEN, + [triggerId2], + ); + + mockEndpoint.done(); + + // Assert trigger deletion + expect( + getTriggerFromUserStorage(mockUserStorage, triggerId1), + ).toBeDefined(); + expect( + getTriggerFromUserStorage(mockUserStorage, triggerId2), + ).toBeUndefined(); + }); + + test('Should delete all triggers and account in user storage', async () => { + const { mockUserStorage, triggerId1, triggerId2 } = arrangeUserStorage(); + const mockEndpoint = mockBatchDeleteTriggers(); + + await OnChainNotifications.deleteOnChainTriggers( + mockUserStorage, + MOCK_STORAGE_KEY, + MOCK_BEARER_TOKEN, + [triggerId1, triggerId2], // delete all triggers for an account + ); + + mockEndpoint.done(); + + // assert that the underlying user is also deleted since all underlying triggers are deleted + expect(mockUserStorage[MOCK_USER_STORAGE_ACCOUNT]).toBeUndefined(); + }); + + test('Should throw error if endpoint fails to delete', async () => { + const { mockUserStorage, triggerId1, triggerId2 } = arrangeUserStorage(); + const mockBadEndpoint = mockBatchDeleteTriggers({ + status: 500, + body: { error: 'mock api failure' }, + }); + + await expect( + OnChainNotifications.deleteOnChainTriggers( + mockUserStorage, + MOCK_STORAGE_KEY, + MOCK_BEARER_TOKEN, + [triggerId1, triggerId2], + ), + ).rejects.toThrow(); + + mockBadEndpoint.done(); + + // Assert that triggers were not deleted from user storage + [triggerId1, triggerId2].forEach((t) => { + expect(getTriggerFromUserStorage(mockUserStorage, t)).toBeDefined(); + }); + }); + + function getTriggerFromUserStorage( + userStorage: UserStorage, + triggerId: string, + ) { + return userStorage[MOCK_USER_STORAGE_ACCOUNT][MOCK_USER_STORAGE_CHAIN][ + triggerId + ]; + } + + function arrangeUserStorage() { + const triggerId1 = 'TRIGGER_ID_1'; + const triggerId2 = 'TRIGGER_ID_2'; + const mockUserStorage = createMockUserStorageWithTriggers([ + triggerId1, + triggerId2, + ]); + + return { + mockUserStorage, + triggerId1, + triggerId2, + }; + } +}); + +describe('On Chain Notifications - getOnChainNotifications()', () => { + test('Should return a list of notifications', async () => { + const mockEndpoint = mockListNotifications(); + const mockUserStorage = createMockUserStorageWithTriggers([ + 'trigger_1', + 'trigger_2', + ]); + + const result = await OnChainNotifications.getOnChainNotifications( + mockUserStorage, + MOCK_BEARER_TOKEN, + ); + + mockEndpoint.done(); + expect(result.length > 0).toBe(true); + }); + + test('Should return an empty list if not triggers found in user storage', async () => { + const mockEndpoint = mockListNotifications(); + const mockUserStorage = createMockUserStorageWithTriggers([]); // no triggers + + const result = await OnChainNotifications.getOnChainNotifications( + mockUserStorage, + MOCK_BEARER_TOKEN, + ); + + expect(mockEndpoint.isDone()).toBe(false); + expect(result.length === 0).toBe(true); + }); + + test('Should return an empty list of notifications if endpoint fails to fetch triggers', async () => { + const mockEndpoint = mockListNotifications({ + status: 500, + body: { error: 'mock api failure' }, + }); + const mockUserStorage = createMockUserStorageWithTriggers([ + 'trigger_1', + 'trigger_2', + ]); + + const result = await OnChainNotifications.getOnChainNotifications( + mockUserStorage, + MOCK_BEARER_TOKEN, + ); + + mockEndpoint.done(); + expect(result.length === 0).toBe(true); + }); +}); + +describe('On Chain Notifications - markNotificationsAsRead()', () => { + test('Should successfully call endpoint to mark notifications as read', async () => { + const mockEndpoint = mockMarkNotificationsAsRead(); + await OnChainNotifications.markNotificationsAsRead(MOCK_BEARER_TOKEN, [ + 'notification_1', + 'notification_2', + ]); + + mockEndpoint.done(); + }); + + test('Should throw error if fails to call endpoint to mark notifications as read', async () => { + const mockBadEndpoint = mockMarkNotificationsAsRead({ + status: 500, + body: { error: 'mock api failure' }, + }); + await expect( + OnChainNotifications.markNotificationsAsRead(MOCK_BEARER_TOKEN, [ + 'notification_1', + 'notification_2', + ]), + ).rejects.toThrow(); + + mockBadEndpoint.done(); + }); +}); diff --git a/app/scripts/controllers/metamask-notifications/services/onchain-notifications.ts b/app/scripts/controllers/metamask-notifications/services/onchain-notifications.ts new file mode 100644 index 000000000000..a43e678ac798 --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/services/onchain-notifications.ts @@ -0,0 +1,288 @@ +import log from 'loglevel'; +import type { UserStorage } from '../types/user-storage/user-storage'; +import type { OnChainRawNotification } from '../types/on-chain-notification/on-chain-notification'; +import { + traverseUserStorageTriggers, + toggleUserStorageTriggerStatus, + makeApiCall, +} from '../utils/utils'; +import { TRIGGER_TYPES } from '../constants/notification-schema'; +import type { components } from '../types/on-chain-notification/schema'; +import { createSHA256Hash } from '../../user-storage/encryption'; + +export type NotificationTrigger = { + id: string; + chainId: string; + kind: string; + address: string; +}; + +export const TRIGGER_API = process.env.TRIGGERS_SERVICE_URL; +export const NOTIFICATION_API = process.env.NOTIFICATIONS_SERVICE_URL; +export const TRIGGER_API_BATCH_ENDPOINT = `${TRIGGER_API}/api/v1/triggers/batch`; +export const NOTIFICATION_API_LIST_ENDPOINT = `${NOTIFICATION_API}/api/v1/notifications`; +export const NOTIFICATION_API_LIST_ENDPOINT_PAGE_QUERY = (page: number) => + `${NOTIFICATION_API_LIST_ENDPOINT}?page=${page}&per_page=100`; +export const NOTIFICATION_API_MARK_ALL_AS_READ_ENDPOINT = `${NOTIFICATION_API}/api/v1/notifications/mark-as-read`; + +/** + * Creates on-chain triggers based on the provided notification triggers. + * This method generates a unique token for each trigger using the trigger ID and storage key, + * proving ownership of the trigger being updated. It then makes an API call to create these triggers. + * Upon successful creation, it updates the userStorage to reflect the new trigger status. + * + * @param userStorage - The user's storage object where triggers and their statuses are stored. + * @param storageKey - A key used along with the trigger ID to generate a unique token for each trigger. + * @param bearerToken - The JSON Web Token used for authentication in the API call. + * @param triggers - An array of notification triggers to be created. Each trigger includes an ID, chain ID, kind, and address. + * @returns A promise that resolves to void. Throws an error if the API call fails or if there's an issue creating the triggers. + */ +export async function createOnChainTriggers( + userStorage: UserStorage, + storageKey: string, + bearerToken: string, + triggers: NotificationTrigger[], +): Promise { + type RequestPayloadTrigger = { + id: string; + // this is the trigger token, generated by using the uuid + storage key. It proves you own the trigger you are updating + token: string; + config: { + kind: string; + chain_id: number; + address: string; + }; + }; + const triggersToCreate: RequestPayloadTrigger[] = triggers.map((t) => ({ + id: t.id, + token: createSHA256Hash(t.id + storageKey), + config: { + kind: t.kind, + chain_id: Number(t.chainId), + address: t.address, + }, + })); + + if (triggersToCreate.length === 0) { + return; + } + + const response = await makeApiCall( + bearerToken, + TRIGGER_API_BATCH_ENDPOINT, + 'POST', + triggersToCreate, + ); + + if (!response.ok) { + const errorData = await response.json().catch(() => undefined); + log.error('Error creating triggers:', errorData); + throw new Error('OnChain Notifications - unable to create triggers'); + } + + // If the trigger creation was fine + // then update the userStorage + for (const trigger of triggersToCreate) { + toggleUserStorageTriggerStatus( + userStorage, + trigger.config.address, + String(trigger.config.chain_id), + trigger.id, + true, + ); + } +} + +/** + * Deletes on-chain triggers based on the provided UUIDs. + * This method generates a unique token for each trigger using the UUID and storage key, + * proving ownership of the trigger being deleted. It then makes an API call to delete these triggers. + * Upon successful deletion, it updates the userStorage to remove the deleted trigger statuses. + * + * @param userStorage - The user's storage object where triggers and their statuses are stored. + * @param storageKey - A key used along with the UUID to generate a unique token for each trigger. + * @param bearerToken - The JSON Web Token used for authentication in the API call. + * @param uuids - An array of UUIDs representing the triggers to be deleted. + * @returns A promise that resolves to the updated UserStorage object. Throws an error if the API call fails or if there's an issue deleting the triggers. + */ +export async function deleteOnChainTriggers( + userStorage: UserStorage, + storageKey: string, + bearerToken: string, + uuids: string[], +): Promise { + const triggersToDelete = uuids.map((uuid) => ({ + id: uuid, + token: createSHA256Hash(uuid + storageKey), + })); + + try { + const response = await makeApiCall( + bearerToken, + TRIGGER_API_BATCH_ENDPOINT, + 'DELETE', + triggersToDelete, + ); + + if (!response.ok) { + throw new Error( + `Failed to delete on-chain notifications for uuids ${uuids.join(', ')}`, + ); + } + + // Update the state of the deleted trigger to false + for (const uuid of uuids) { + for (const address in userStorage) { + if (Object.hasOwn(userStorage, address)) { + for (const chainId in userStorage[address]) { + if (userStorage?.[address]?.[chainId]?.[uuid]) { + delete userStorage[address][chainId][uuid]; + } + } + } + } + } + + // Follow-up cleanup, if an address had no triggers whatsoever, then we can delete the address + const isEmpty = (obj = {}) => Object.keys(obj).length === 0; + for (const address in userStorage) { + if (Object.hasOwn(userStorage, address)) { + for (const chainId in userStorage[address]) { + // Chain isEmpty Check + if (isEmpty(userStorage?.[address]?.[chainId])) { + delete userStorage[address][chainId]; + } + } + + // Address isEmpty Check + if (isEmpty(userStorage?.[address])) { + delete userStorage[address]; + } + } + } + } catch (err) { + log.error( + `Error deleting on-chain notifications for uuids ${uuids.join(', ')}:`, + err, + ); + throw err; + } + + return userStorage; +} + +/** + * Fetches on-chain notifications for the given user storage and BearerToken. + * This method iterates through the userStorage to find enabled triggers and fetches notifications for those triggers. + * It makes paginated API calls to the notifications service, transforming and aggregating the notifications into a single array. + * The process stops either when all pages have been fetched or when a page has less than 100 notifications, indicating the end of the data. + * + * @param userStorage - The user's storage object containing trigger information. + * @param bearerToken - The JSON Web Token used for authentication in the API call. + * @returns A promise that resolves to an array of OnChainRawNotification objects. If no triggers are enabled or an error occurs, it may return an empty array. + */ +export async function getOnChainNotifications( + userStorage: UserStorage, + bearerToken: string, +): Promise { + const triggerIds = traverseUserStorageTriggers(userStorage, { + mapTrigger: (t) => { + if (!t.enabled) { + return undefined; + } + return t.id; + }, + }); + + if (triggerIds.length === 0) { + return []; + } + + const onChainNotifications: OnChainRawNotification[] = []; + const PAGE_LIMIT = 2; + for (let page = 1; page <= PAGE_LIMIT; page++) { + try { + const response = await makeApiCall( + bearerToken, + NOTIFICATION_API_LIST_ENDPOINT_PAGE_QUERY(page), + 'POST', + { trigger_ids: triggerIds }, + ); + + const notifications = (await response.json()) as OnChainRawNotification[]; + + // Transform and sort notifications + const transformedNotifications = notifications + .map( + ( + n: components['schemas']['Notification'], + ): OnChainRawNotification | undefined => { + if (!n.data?.kind) { + return undefined; + } + + return { + ...n, + type: n.data.kind as TRIGGER_TYPES, + } as OnChainRawNotification; + }, + ) + .filter((n): n is OnChainRawNotification => Boolean(n)); + + onChainNotifications.push(...transformedNotifications); + + // if less than 100 notifications on page, then means we reached end + if (notifications.length < 100) { + page = PAGE_LIMIT + 1; + break; + } + } catch (err) { + log.error( + `Error fetching on-chain notifications for trigger IDs ${triggerIds.join( + ', ', + )}:`, + err, + ); + // do nothing + } + } + + return onChainNotifications; +} + +/** + * Marks the specified notifications as read. + * This method sends a POST request to the notifications service to mark the provided notification IDs as read. + * If the operation is successful, it completes without error. If the operation fails, it throws an error with details. + * + * @param bearerToken - The JSON Web Token used for authentication in the API call. + * @param notificationIds - An array of notification IDs to be marked as read. + * @returns A promise that resolves to void. The promise will reject if there's an error during the API call or if the response status is not 200. + */ +export async function markNotificationsAsRead( + bearerToken: string, + notificationIds: string[], +): Promise { + if (notificationIds.length === 0) { + return; + } + + try { + const response = await makeApiCall( + bearerToken, + NOTIFICATION_API_MARK_ALL_AS_READ_ENDPOINT, + 'POST', + { ids: notificationIds }, + ); + + if (response.status !== 200) { + const errorData = await response.json().catch(() => undefined); + throw new Error( + `Error marking notifications as read: ${errorData?.message}`, + ); + } + } catch (err) { + log.error('Error marking notifications as read:', err); + throw err; + } +} diff --git a/app/scripts/controllers/metamask-notifications/types/feature-announcement/feature-announcement.ts b/app/scripts/controllers/metamask-notifications/types/feature-announcement/feature-announcement.ts new file mode 100644 index 000000000000..6155c9dcd156 --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/types/feature-announcement/feature-announcement.ts @@ -0,0 +1,27 @@ +import type { TRIGGER_TYPES } from '../../constants/notification-schema'; +import type { TypeFeatureAnnouncement } from './type-feature-announcement'; + +export type { TypeFeatureAnnouncement }; +export type { TypeFeatureAnnouncementFields } from './type-feature-announcement'; + +export type FeatureAnnouncementRawNotificationData = Omit< + TypeFeatureAnnouncement['fields'], + 'image' | 'longDescription' | 'extensionLink' +> & { + longDescription: string; + image: { + title?: string; + description?: string; + url: string; + }; + extensionLink?: { + extensionLinkText: string; + extensionLinkRoute: string; + }; +}; + +export type FeatureAnnouncementRawNotification = { + type: TRIGGER_TYPES.FEATURES_ANNOUNCEMENT; + createdAt: string; + data: FeatureAnnouncementRawNotificationData; +}; diff --git a/app/scripts/controllers/metamask-notifications/types/feature-announcement/type-extension-link.ts b/app/scripts/controllers/metamask-notifications/types/feature-announcement/type-extension-link.ts new file mode 100644 index 000000000000..bfc3d40267ae --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/types/feature-announcement/type-extension-link.ts @@ -0,0 +1,14 @@ +import type { Entry } from 'contentful'; + +export type TypeExtensionLinkFields = { + fields: { + extensionLinkText: string; + extensionLinkRoute: string; + }; + contentTypeId: 'extensionLink'; +}; + +export type TypeExtensionLink = Entry< + TypeExtensionLinkFields, + 'WITHOUT_UNRESOLVABLE_LINKS' +>; diff --git a/app/scripts/controllers/metamask-notifications/types/feature-announcement/type-feature-announcement.ts b/app/scripts/controllers/metamask-notifications/types/feature-announcement/type-feature-announcement.ts new file mode 100644 index 000000000000..8cff6cbd7d9d --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/types/feature-announcement/type-feature-announcement.ts @@ -0,0 +1,41 @@ +import type { Entry, EntryFieldTypes } from 'contentful'; +import type { TypeExtensionLinkFields } from './type-extension-link'; + +export type ImageFields = { + fields: { + title?: string; + description?: string; + file?: { + url: string; + fileName: string; + contentType: string; + details: { + size: number; + image?: { + width: number; + height: number; + }; + }; + }; + }; + contentTypeId: 'Image'; +}; + +export type TypeFeatureAnnouncementFields = { + fields: { + title: EntryFieldTypes.Text; + id: EntryFieldTypes.Symbol; + category: EntryFieldTypes.Text; // E.g. Announcement, etc. + shortDescription: EntryFieldTypes.Text; + image: EntryFieldTypes.EntryLink; + longDescription: EntryFieldTypes.RichText; + extensionLink?: EntryFieldTypes.EntryLink; + clients?: EntryFieldTypes.Text<'extension' | 'mobile' | 'portfolio'>; + }; + contentTypeId: 'productAnnouncement'; +}; + +export type TypeFeatureAnnouncement = Entry< + TypeFeatureAnnouncementFields, + 'WITHOUT_UNRESOLVABLE_LINKS' +>; diff --git a/app/scripts/controllers/metamask-notifications/types/notification/notification.ts b/app/scripts/controllers/metamask-notifications/types/notification/notification.ts new file mode 100644 index 000000000000..3c556ab30191 --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/types/notification/notification.ts @@ -0,0 +1,18 @@ +import type { Notification } from '../types'; + +export type { Notification } from '../types'; + +// NFT +export type NFT = { + token_id: string; + image: string; + collection?: { + name: string; + image: string; + }; +}; + +export type MarkAsReadNotificationsParam = Pick< + Notification, + 'id' | 'type' | 'isRead' +>[]; diff --git a/app/scripts/controllers/metamask-notifications/types/on-chain-notification/on-chain-notification.ts b/app/scripts/controllers/metamask-notifications/types/on-chain-notification/on-chain-notification.ts new file mode 100644 index 000000000000..022702933bea --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/types/on-chain-notification/on-chain-notification.ts @@ -0,0 +1,50 @@ +import type { TRIGGER_TYPES } from '../../constants/notification-schema'; +import type { Compute } from '../type-utils'; +import type { components } from './schema'; + +export type Data_MetamaskSwapCompleted = + components['schemas']['Data_MetamaskSwapCompleted']; +export type Data_LidoStakeReadyToBeWithdrawn = + components['schemas']['Data_LidoStakeReadyToBeWithdrawn']; +export type Data_LidoStakeCompleted = + components['schemas']['Data_LidoStakeCompleted']; +export type Data_LidoWithdrawalRequested = + components['schemas']['Data_LidoWithdrawalRequested']; +export type Data_LidoWithdrawalCompleted = + components['schemas']['Data_LidoWithdrawalCompleted']; +export type Data_RocketPoolStakeCompleted = + components['schemas']['Data_RocketPoolStakeCompleted']; +export type Data_RocketPoolUnstakeCompleted = + components['schemas']['Data_RocketPoolUnstakeCompleted']; +export type Data_ETHSent = components['schemas']['Data_ETHSent']; +export type Data_ETHReceived = components['schemas']['Data_ETHReceived']; +export type Data_ERC20Sent = components['schemas']['Data_ERC20Sent']; +export type Data_ERC20Received = components['schemas']['Data_ERC20Received']; +export type Data_ERC721Sent = components['schemas']['Data_ERC721Sent']; +export type Data_ERC721Received = components['schemas']['Data_ERC721Received']; + +type Notification = components['schemas']['Notification']; +type NotificationDataKinds = NonNullable['kind']; +type ConvertToEnum = { + [K in TRIGGER_TYPES]: Kind extends `${K}` ? K : never; +}[TRIGGER_TYPES]; + +/** + * Type-Computation. + * 1. Adds a `type` field to the notification, it converts the schema type into the ENUM we use. + * 2. It ensures that the `data` field is the correct Notification data for this `type` + * - The `Compute` utility merges the intersections (`&`) for a prettier type. + */ +export type OnChainRawNotification = { + [K in NotificationDataKinds]: Compute< + Omit & { + type: ConvertToEnum; + data: Extract; + } + >; +}[NotificationDataKinds]; + +export type OnChainRawNotificationsWithNetworkFields = Extract< + OnChainRawNotification, + { data: { network_fee: unknown } } +>; diff --git a/app/scripts/controllers/metamask-notifications/types/on-chain-notification/schema.d.ts b/app/scripts/controllers/metamask-notifications/types/on-chain-notification/schema.d.ts new file mode 100644 index 000000000000..05c725e3690d --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/types/on-chain-notification/schema.d.ts @@ -0,0 +1,303 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + * Script: `npx openapi-typescript -o ./schema.d.ts` + */ + +export type paths = { + '/api/v1/notifications': { + /** List all notifications ordered by most recent */ + post: { + parameters: { + query?: { + /** @description Page number for pagination */ + page?: number; + /** @description Number of notifications per page for pagination */ + per_page?: number; + }; + }; + requestBody?: { + content: { + 'application/json': { + trigger_ids: string[]; + chain_ids?: number[]; + kinds?: string[]; + unread?: boolean; + }; + }; + }; + responses: { + /** @description Successfully fetched a list of notifications */ + 200: { + content: { + 'application/json': components['schemas']['Notification'][]; + }; + }; + }; + }; + }; + '/api/v1/notifications/mark-as-read': { + /** Mark notifications as read */ + post: { + requestBody: { + content: { + 'application/json': { + ids?: string[]; + }; + }; + }; + responses: { + /** @description Successfully marked notifications as read */ + 200: { + content: never; + }; + }; + }; + }; +}; + +export type webhooks = Record; + +export type components = { + schemas: { + Notification: { + /** Format: uuid */ + id: string; + /** Format: uuid */ + trigger_id: string; + /** @example 1 */ + chain_id: number; + /** @example 17485840 */ + block_number: number; + block_timestamp: string; + /** + * Format: address + * + * @example 0x881D40237659C251811CEC9c364ef91dC08D300C + */ + tx_hash: string; + /** @example false */ + unread: boolean; + /** Format: date-time */ + created_at: string; + /** Format: address */ + address: string; + data?: + | components['schemas']['Data_MetamaskSwapCompleted'] + | components['schemas']['Data_LidoStakeReadyToBeWithdrawn'] + | components['schemas']['Data_LidoStakeCompleted'] + | components['schemas']['Data_LidoWithdrawalRequested'] + | components['schemas']['Data_LidoWithdrawalCompleted'] + | components['schemas']['Data_RocketPoolStakeCompleted'] + | components['schemas']['Data_RocketPoolUnstakeCompleted'] + | components['schemas']['Data_ETHSent'] + | components['schemas']['Data_ETHReceived'] + | components['schemas']['Data_ERC20Sent'] + | components['schemas']['Data_ERC20Received'] + | components['schemas']['Data_ERC721Sent'] + | components['schemas']['Data_ERC721Received'] + | components['schemas']['Data_ERC1155Sent'] + | components['schemas']['Data_ERC1155Received']; + }; + Data_MetamaskSwapCompleted: { + /** @enum {string} */ + kind: 'metamask_swap_completed'; + network_fee: components['schemas']['NetworkFee']; + /** Format: decimal */ + rate: string; + token_in: components['schemas']['Token']; + token_out: components['schemas']['Token']; + }; + Data_LidoStakeCompleted: { + /** @enum {string} */ + kind: 'lido_stake_completed'; + network_fee: components['schemas']['NetworkFee']; + stake_in: components['schemas']['Stake']; + stake_out: components['schemas']['Stake']; + }; + Data_LidoWithdrawalRequested: { + /** @enum {string} */ + kind: 'lido_withdrawal_requested'; + network_fee: components['schemas']['NetworkFee']; + stake_in: components['schemas']['Stake']; + stake_out: components['schemas']['Stake']; + }; + Data_LidoStakeReadyToBeWithdrawn: { + /** @enum {string} */ + kind: 'lido_stake_ready_to_be_withdrawn'; + /** Format: decimal */ + request_id: string; + staked_eth: components['schemas']['Stake']; + }; + Data_LidoWithdrawalCompleted: { + /** @enum {string} */ + kind: 'lido_withdrawal_completed'; + network_fee: components['schemas']['NetworkFee']; + stake_in: components['schemas']['Stake']; + stake_out: components['schemas']['Stake']; + }; + Data_RocketPoolStakeCompleted: { + /** @enum {string} */ + kind: 'rocketpool_stake_completed'; + network_fee: components['schemas']['NetworkFee']; + stake_in: components['schemas']['Stake']; + stake_out: components['schemas']['Stake']; + }; + Data_RocketPoolUnstakeCompleted: { + /** @enum {string} */ + kind: 'rocketpool_unstake_completed'; + network_fee: components['schemas']['NetworkFee']; + stake_in: components['schemas']['Stake']; + stake_out: components['schemas']['Stake']; + }; + Data_ETHSent: { + /** @enum {string} */ + kind: 'eth_sent'; + network_fee: components['schemas']['NetworkFee']; + /** Format: address */ + from: string; + /** Format: address */ + to: string; + amount: { + /** Format: decimal */ + usd: string; + /** Format: decimal */ + eth: string; + }; + }; + Data_ETHReceived: { + /** @enum {string} */ + kind: 'eth_received'; + network_fee: components['schemas']['NetworkFee']; + /** Format: address */ + from: string; + /** Format: address */ + to: string; + amount: { + /** Format: decimal */ + usd: string; + /** Format: decimal */ + eth: string; + }; + }; + Data_ERC20Sent: { + /** @enum {string} */ + kind: 'erc20_sent'; + network_fee: components['schemas']['NetworkFee']; + /** Format: address */ + from: string; + /** Format: address */ + to: string; + token: components['schemas']['Token']; + }; + Data_ERC20Received: { + /** @enum {string} */ + kind: 'erc20_received'; + network_fee: components['schemas']['NetworkFee']; + /** Format: address */ + from: string; + /** Format: address */ + to: string; + token: components['schemas']['Token']; + }; + Data_ERC721Sent: { + /** @enum {string} */ + kind: 'erc721_sent'; + network_fee: components['schemas']['NetworkFee']; + /** Format: address */ + from: string; + /** Format: address */ + to: string; + nft: components['schemas']['NFT']; + }; + Data_ERC721Received: { + /** @enum {string} */ + kind: 'erc721_received'; + network_fee: components['schemas']['NetworkFee']; + /** Format: address */ + from: string; + /** Format: address */ + to: string; + nft: components['schemas']['NFT']; + }; + Data_ERC1155Sent: { + /** @enum {string} */ + kind: 'erc1155_sent'; + network_fee: components['schemas']['NetworkFee']; + /** Format: address */ + from: string; + /** Format: address */ + to: string; + nft?: components['schemas']['NFT']; + }; + Data_ERC1155Received: { + /** @enum {string} */ + kind: 'erc1155_received'; + network_fee: components['schemas']['NetworkFee']; + /** Format: address */ + from: string; + /** Format: address */ + to: string; + nft?: components['schemas']['NFT']; + }; + NetworkFee: { + /** Format: decimal */ + gas_price: string; + /** Format: decimal */ + native_token_price_in_usd: string; + }; + Token: { + /** Format: address */ + address: string; + symbol: string; + name: string; + /** Format: decimal */ + amount: string; + /** Format: int32 */ + decimals: string; + /** Format: uri */ + image: string; + /** Format: decimal */ + usd: string; + }; + NFT: { + name: string; + token_id: string; + /** Format: uri */ + image: string; + collection: { + /** Format: address */ + address: string; + name: string; + symbol: string; + /** Format: uri */ + image: string; + }; + }; + Stake: { + /** Format: address */ + address: string; + symbol: string; + name: string; + /** Format: decimal */ + amount: string; + /** Format: int32 */ + decimals: string; + /** Format: uri */ + image: string; + /** Format: decimal */ + usd: string; + }; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +}; + +export type $defs = Record; + +export type external = Record; + +export type operations = Record; diff --git a/app/scripts/controllers/metamask-notifications/types/type-utils.ts b/app/scripts/controllers/metamask-notifications/types/type-utils.ts new file mode 100644 index 000000000000..f05a763f5d2c --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/types/type-utils.ts @@ -0,0 +1,4 @@ +/** + * Computes and combines intersection types for a more "prettier" type (more human readable) + */ +export type Compute = T extends T ? { [K in keyof T]: T[K] } : never; diff --git a/app/scripts/controllers/metamask-notifications/types/types.ts b/app/scripts/controllers/metamask-notifications/types/types.ts new file mode 100644 index 000000000000..1d0d7026a430 --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/types/types.ts @@ -0,0 +1,21 @@ +import type { FeatureAnnouncementRawNotification } from './feature-announcement/feature-announcement'; +import type { Compute } from './type-utils'; +import type { OnChainRawNotification } from './on-chain-notification/on-chain-notification'; + +export type NotificationUnion = + | FeatureAnnouncementRawNotification + | OnChainRawNotification; + +/** + * The shape of a "generic" notification. + * Other than the fields listed below, tt will also contain: + * - `type` field (declared in the Raw shapes) + * - `data` field (declared in the Raw shapes) + */ +export type Notification = Compute< + NotificationUnion & { + id: string; + createdAt: string; + isRead: boolean; + } +>; diff --git a/app/scripts/controllers/metamask-notifications/types/user-storage/user-storage.ts b/app/scripts/controllers/metamask-notifications/types/user-storage/user-storage.ts new file mode 100644 index 000000000000..086d4cc7e4d4 --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/types/user-storage/user-storage.ts @@ -0,0 +1,32 @@ +import type { + SUPPORTED_CHAINS, + TRIGGER_TYPES, +} from '../../constants/notification-schema'; +import type { + USER_STORAGE_VERSION_KEY, + USER_STORAGE_VERSION, +} from '../../constants/constants'; + +export type UserStorage = { + /** + * The Version 'v' of the User Storage. + * NOTE - will allow us to support upgrade/downgrades in the future + */ + [USER_STORAGE_VERSION_KEY]: typeof USER_STORAGE_VERSION; + [address: string]: { + [chain in (typeof SUPPORTED_CHAINS)[number]]: { + [uuid: string]: { + /** Trigger Kind 'k' */ + k: TRIGGER_TYPES; + /** + * Trigger Enabled 'e' + * This is mostly an 'acknowledgement' to determine if a trigger has been made + * For example if we fail to create a trigger, we can set to false & retry (on re-log in, or elsewhere) + * + * Most of the time this is 'true', as triggers when deleted are also removed from User Storage + */ + e: boolean; + }; + }; + }; +}; diff --git a/app/scripts/controllers/metamask-notifications/utils/utils.test.ts b/app/scripts/controllers/metamask-notifications/utils/utils.test.ts new file mode 100644 index 000000000000..b533f6c4559b --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/utils/utils.test.ts @@ -0,0 +1,314 @@ +import { USER_STORAGE_VERSION_KEY } from '../constants/constants'; +import { + NOTIFICATION_CHAINS, + TRIGGER_TYPES, +} from '../constants/notification-schema'; +import { + MOCK_USER_STORAGE_ACCOUNT, + MOCK_USER_STORAGE_CHAIN, + createMockFullUserStorage, + createMockUserStorageWithTriggers, +} from '../mocks/mock-notification-user-storage'; +import { UserStorage } from '../types/user-storage/user-storage'; +import * as MetamaskNotificationsUtils from './utils'; + +describe('metamask-notifications/utils - initializeUserStorage()', () => { + test('Creates a new user storage object based on the accounts provided', () => { + const mockAddress = 'MOCK_ADDRESS'; + const userStorage = MetamaskNotificationsUtils.initializeUserStorage( + [{ address: mockAddress }], + true, + ); + + // Addresses in User Storage are lowercase to prevent multiple entries of same address + const userStorageAddress = mockAddress.toLowerCase(); + expect(userStorage[userStorageAddress]).toBeDefined(); + }); + + test('Returns User Storage with no addresses if none provided', () => { + function assertEmptyStorage(storage: UserStorage) { + expect(Object.keys(storage).length === 1).toBe(true); + expect(USER_STORAGE_VERSION_KEY in storage).toBe(true); + } + + const userStorageTest1 = MetamaskNotificationsUtils.initializeUserStorage( + [], + true, + ); + assertEmptyStorage(userStorageTest1); + + const userStorageTest2 = MetamaskNotificationsUtils.initializeUserStorage( + [{ address: undefined }], + true, + ); + assertEmptyStorage(userStorageTest2); + }); +}); + +describe('metamask-notifications/utils - traverseUserStorageTriggers()', () => { + test('Traverses User Storage to return triggers', () => { + const storage = createMockFullUserStorage(); + const triggersObjArray = + MetamaskNotificationsUtils.traverseUserStorageTriggers(storage); + expect(triggersObjArray.length > 0).toBe(true); + expect(typeof triggersObjArray[0] === 'object').toBe(true); + }); + + test('Traverses and maps User Storage using mapper', () => { + const storage = createMockFullUserStorage(); + + // as the type suggests, the mapper returns a string, so expect this to be a string + const triggersStrArray = + MetamaskNotificationsUtils.traverseUserStorageTriggers(storage, { + mapTrigger: (t) => t.id, + }); + expect(triggersStrArray.length > 0).toBe(true); + expect(typeof triggersStrArray[0] === 'string').toBe(true); + + // if the mapper returns a falsy value, it is filtered out + const emptyTriggersArray = + MetamaskNotificationsUtils.traverseUserStorageTriggers(storage, { + mapTrigger: (_t): string | undefined => undefined, + }); + expect(emptyTriggersArray.length === 0).toBe(true); + }); +}); + +describe('metamask-notifications/utils - checkAccountsPresence()', () => { + test('Returns record of addresses that are in storage', () => { + const storage = createMockFullUserStorage(); + const result = MetamaskNotificationsUtils.checkAccountsPresence(storage, [ + MOCK_USER_STORAGE_ACCOUNT, + ]); + expect(result).toEqual({ + [MOCK_USER_STORAGE_ACCOUNT.toLowerCase()]: true, + }); + }); + + test('Returns record of addresses in storage and not fully in storage', () => { + const storage = createMockFullUserStorage(); + const MOCK_MISSING_ADDRESS = '0x2'; + const result = MetamaskNotificationsUtils.checkAccountsPresence(storage, [ + MOCK_USER_STORAGE_ACCOUNT, + MOCK_MISSING_ADDRESS, + ]); + expect(result).toEqual({ + [MOCK_USER_STORAGE_ACCOUNT.toLowerCase()]: true, + [MOCK_MISSING_ADDRESS.toLowerCase()]: false, + }); + }); + + test('Returns record where accounts are not fully present, due to missing chains', () => { + const storage = createMockFullUserStorage(); + delete storage[MOCK_USER_STORAGE_ACCOUNT][NOTIFICATION_CHAINS.ETHEREUM]; + + const result = MetamaskNotificationsUtils.checkAccountsPresence(storage, [ + MOCK_USER_STORAGE_ACCOUNT, + ]); + expect(result).toEqual({ + [MOCK_USER_STORAGE_ACCOUNT.toLowerCase()]: false, // false due to missing chains + }); + }); + + test('Returns record where accounts are not fully present, due to missing triggers', () => { + const storage = createMockFullUserStorage(); + const MOCK_TRIGGER_TO_DELETE = Object.keys( + storage[MOCK_USER_STORAGE_ACCOUNT][NOTIFICATION_CHAINS.ETHEREUM], + )[0]; + delete storage[MOCK_USER_STORAGE_ACCOUNT][NOTIFICATION_CHAINS.ETHEREUM][ + MOCK_TRIGGER_TO_DELETE + ]; + + const result = MetamaskNotificationsUtils.checkAccountsPresence(storage, [ + MOCK_USER_STORAGE_ACCOUNT, + ]); + expect(result).toEqual({ + [MOCK_USER_STORAGE_ACCOUNT.toLowerCase()]: false, // false due to missing triggers + }); + }); +}); + +describe('metamask-notifications/utils - inferEnabledKinds()', () => { + test('Returns all kinds from a User Storage Obj', () => { + const partialStorage = createMockUserStorageWithTriggers([ + { id: '1', e: true, k: TRIGGER_TYPES.ERC1155_RECEIVED }, + { id: '2', e: true, k: TRIGGER_TYPES.ERC1155_SENT }, + { id: '3', e: true, k: TRIGGER_TYPES.ERC1155_SENT }, // should remove duplicates + ]); + + const result = MetamaskNotificationsUtils.inferEnabledKinds(partialStorage); + expect(result.length).toBe(2); + expect(result.includes(TRIGGER_TYPES.ERC1155_RECEIVED)).toBe(true); + expect(result.includes(TRIGGER_TYPES.ERC1155_SENT)).toBe(true); + }); +}); + +describe('metamask-notifications/utils - getUUIDsForAccount()', () => { + test('Returns all trigger IDs in user storage from a given address', () => { + const partialStorage = createMockUserStorageWithTriggers(['t1', 't2']); + + const result = MetamaskNotificationsUtils.getUUIDsForAccount( + partialStorage, + MOCK_USER_STORAGE_ACCOUNT, + ); + expect(result.length).toBe(2); + expect(result.includes('t1')).toBe(true); + expect(result.includes('t2')).toBe(true); + }); + test('Returns an empty array if the address does not exist or has any triggers', () => { + const partialStorage = createMockUserStorageWithTriggers(['t1', 't2']); + const result = MetamaskNotificationsUtils.getUUIDsForAccount( + partialStorage, + 'ACCOUNT_THAT_DOES_NOT_EXIST_IN_STORAGE', + ); + expect(result.length).toBe(0); + }); +}); + +describe('metamask-notifications/utils - getAllUUIDs()', () => { + test('Returns all triggerIds in User Storage', () => { + const partialStorage = createMockUserStorageWithTriggers(['t1', 't2']); + const result1 = MetamaskNotificationsUtils.getAllUUIDs(partialStorage); + expect(result1.length).toBe(2); + expect(result1.includes('t1')).toBe(true); + expect(result1.includes('t2')).toBe(true); + + const fullStorage = createMockFullUserStorage(); + const result2 = MetamaskNotificationsUtils.getAllUUIDs(fullStorage); + expect(result2.length).toBeGreaterThan(2); // we expect there to be more than 2 triggers. We have multiple chains to there should be quite a few UUIDs. + }); +}); + +describe('metamask-notifications/utils - getUUIDsForKinds()', () => { + test('Returns all triggerIds that match the kind', () => { + const partialStorage = createMockUserStorageWithTriggers([ + { id: 't1', e: true, k: TRIGGER_TYPES.ERC1155_RECEIVED }, + { id: 't2', e: true, k: TRIGGER_TYPES.ERC1155_SENT }, + ]); + const result = MetamaskNotificationsUtils.getUUIDsForKinds(partialStorage, [ + TRIGGER_TYPES.ERC1155_RECEIVED, + ]); + expect(result).toEqual(['t1']); + }); + + test('Returns empty list if no triggers are found matching the kinds', () => { + const partialStorage = createMockUserStorageWithTriggers([ + { id: 't1', e: true, k: TRIGGER_TYPES.ERC1155_RECEIVED }, + { id: 't2', e: true, k: TRIGGER_TYPES.ERC1155_SENT }, + ]); + const result = MetamaskNotificationsUtils.getUUIDsForKinds(partialStorage, [ + TRIGGER_TYPES.ETH_SENT, // A kind we have not created a trigger for + ]); + expect(result.length).toBe(0); + }); +}); + +describe('metamask-notifications/utils - getUUIDsForAccountByKinds()', () => { + const createPartialStorage = () => + createMockUserStorageWithTriggers([ + { id: 't1', e: true, k: TRIGGER_TYPES.ERC1155_RECEIVED }, + { id: 't2', e: true, k: TRIGGER_TYPES.ERC1155_SENT }, + ]); + + test('Returns triggers with correct account and matching kinds', () => { + const partialStorage = createPartialStorage(); + const result = MetamaskNotificationsUtils.getUUIDsForAccountByKinds( + partialStorage, + MOCK_USER_STORAGE_ACCOUNT, + [TRIGGER_TYPES.ERC1155_RECEIVED], + ); + expect(result.length).toBe(1); + }); + + test('Returns empty when using incorrect account', () => { + const partialStorage = createPartialStorage(); + const result = MetamaskNotificationsUtils.getUUIDsForAccountByKinds( + partialStorage, + 'ACCOUNT_THAT_DOES_NOT_EXIST_IN_STORAGE', + [TRIGGER_TYPES.ERC1155_RECEIVED], + ); + expect(result.length).toBe(0); + }); + + test('Returns empty when using incorrect kind', () => { + const partialStorage = createPartialStorage(); + const result = MetamaskNotificationsUtils.getUUIDsForAccountByKinds( + partialStorage, + MOCK_USER_STORAGE_ACCOUNT, + [TRIGGER_TYPES.ETH_SENT], // this trigger was not created in partial storage + ); + expect(result.length).toBe(0); + }); +}); + +describe('metamask-notifications/utils - upsertAddressTriggers()', () => { + test('Updates and adds new triggers for a new address', () => { + const MOCK_NEW_ADDRESS = 'MOCK_NEW_ADDRESS'.toLowerCase(); // addresses stored in user storage are lower-case + const storage = createMockFullUserStorage(); + + // Before + expect(storage[MOCK_NEW_ADDRESS]).toBeUndefined(); + + MetamaskNotificationsUtils.upsertAddressTriggers(MOCK_NEW_ADDRESS, storage); + + // After + expect(storage[MOCK_NEW_ADDRESS]).toBeDefined(); + const newTriggers = MetamaskNotificationsUtils.getUUIDsForAccount( + storage, + MOCK_NEW_ADDRESS, + ); + expect(newTriggers.length > 0).toBe(true); + }); +}); + +describe('metamask-notifications/utils - upsertTriggerTypeTriggers()', () => { + test('Updates and adds a new trigger to an address', () => { + const partialStorage = createMockUserStorageWithTriggers([ + { id: 't1', e: true, k: TRIGGER_TYPES.ERC1155_RECEIVED }, + { id: 't2', e: true, k: TRIGGER_TYPES.ERC1155_SENT }, + ]); + + // Before + expect( + MetamaskNotificationsUtils.getUUIDsForAccount( + partialStorage, + MOCK_USER_STORAGE_ACCOUNT, + ).length, + ).toBe(2); + + MetamaskNotificationsUtils.upsertTriggerTypeTriggers( + TRIGGER_TYPES.ETH_SENT, + partialStorage, + ); + + // After + expect( + MetamaskNotificationsUtils.getUUIDsForAccount( + partialStorage, + MOCK_USER_STORAGE_ACCOUNT, + ).length, + ).toBe(3); + }); +}); + +describe('metamask-notifications/utils - toggleUserStorageTriggerStatus()', () => { + test('Updates Triggers from disabled to enabled', () => { + // Triggers are initially set to false false. + const partialStorage = createMockUserStorageWithTriggers([ + { id: 't1', k: TRIGGER_TYPES.ERC1155_RECEIVED, e: false }, + { id: 't2', k: TRIGGER_TYPES.ERC1155_SENT, e: false }, + ]); + + MetamaskNotificationsUtils.toggleUserStorageTriggerStatus( + partialStorage, + MOCK_USER_STORAGE_ACCOUNT, + MOCK_USER_STORAGE_CHAIN, + 't1', + true, + ); + + expect( + partialStorage[MOCK_USER_STORAGE_ACCOUNT][MOCK_USER_STORAGE_CHAIN].t1.e, + ).toBe(true); + }); +}); diff --git a/app/scripts/controllers/metamask-notifications/utils/utils.ts b/app/scripts/controllers/metamask-notifications/utils/utils.ts new file mode 100644 index 000000000000..f71f9e568dcd --- /dev/null +++ b/app/scripts/controllers/metamask-notifications/utils/utils.ts @@ -0,0 +1,619 @@ +import log from 'loglevel'; +import { v4 as uuidv4 } from 'uuid'; +import type { UserStorage } from '../types/user-storage/user-storage'; +import { + USER_STORAGE_VERSION_KEY, + USER_STORAGE_VERSION, +} from '../constants/constants'; +import { + TRIGGER_TYPES, + TRIGGER_TYPES_GROUPS, + TRIGGERS, +} from '../constants/notification-schema'; + +export type NotificationTrigger = { + id: string; + chainId: string; + kind: string; + address: string; + enabled: boolean; +}; + +type MapTriggerFn = ( + trigger: NotificationTrigger, +) => Result | undefined; + +type TraverseTriggerOpts = { + address?: string; + mapTrigger?: MapTriggerFn; +}; + +/** + * Extracts and returns the ID from a notification trigger. + * This utility function is primarily used as a mapping function in `traverseUserStorageTriggers` + * to convert a full trigger object into its ID string. + * + * @param trigger - The notification trigger from which the ID is extracted. + * @returns The ID of the provided notification trigger. + */ +const triggerToId = (trigger: NotificationTrigger): string => trigger.id; + +/** + * A utility function that returns the input trigger without any transformation. + * This function is used as the default mapping function in `traverseUserStorageTriggers` + * when no custom mapping function is provided. + * + * @param trigger - The notification trigger to be returned as is. + * @returns The same notification trigger that was passed in. + */ +const triggerIdentity = (trigger: NotificationTrigger): NotificationTrigger => + trigger; + +/** + * Maps a given trigger type to its corresponding trigger group. + * + * This method categorizes each trigger type into one of the predefined groups: + * RECEIVED, SENT, or DEFI. These groups help in organizing triggers based on their nature. + * For instance, triggers related to receiving assets are categorized under RECEIVED, + * triggers for sending assets under SENT, and triggers related to decentralized finance (DeFi) + * operations under DEFI. This categorization aids in managing and responding to different types + * of notifications more effectively. + * + * @param type - The trigger type to be categorized. + * @returns The group to which the trigger type belongs. + */ +const groupTriggerTypes = (type: TRIGGER_TYPES): TRIGGER_TYPES_GROUPS => { + switch (type) { + case TRIGGER_TYPES.ERC20_RECEIVED: + case TRIGGER_TYPES.ETH_RECEIVED: + case TRIGGER_TYPES.ERC721_RECEIVED: + case TRIGGER_TYPES.ERC1155_RECEIVED: + return TRIGGER_TYPES_GROUPS.RECEIVED; + case TRIGGER_TYPES.ERC20_SENT: + case TRIGGER_TYPES.ETH_SENT: + case TRIGGER_TYPES.ERC721_SENT: + case TRIGGER_TYPES.ERC1155_SENT: + return TRIGGER_TYPES_GROUPS.SENT; + case TRIGGER_TYPES.METAMASK_SWAP_COMPLETED: + case TRIGGER_TYPES.ROCKETPOOL_STAKE_COMPLETED: + case TRIGGER_TYPES.ROCKETPOOL_UNSTAKE_COMPLETED: + case TRIGGER_TYPES.LIDO_STAKE_COMPLETED: + case TRIGGER_TYPES.LIDO_WITHDRAWAL_REQUESTED: + case TRIGGER_TYPES.LIDO_WITHDRAWAL_COMPLETED: + default: + return TRIGGER_TYPES_GROUPS.DEFI; + } +}; + +/** + * Create a completely new user storage object with the given accounts and state. + * This method initializes the user storage with a version key and iterates over each account to populate it with triggers. + * Each trigger is associated with supported chains, and for each chain, a unique identifier (UUID) is generated. + * The trigger object contains a kind (`k`) indicating the type of trigger and an enabled state (`e`). + * The kind and enabled state are stored with abbreviated keys to reduce the JSON size. + * + * This is used primarily for creating a new user storage (e.g. when first signing in/enabling notification profile syncing), + * caution is needed in case you need to remove triggers that you don't want (due to notification setting filters) + * + * @param accounts - An array of account objects, each optionally containing an address. + * @param state - A boolean indicating the initial enabled state for all triggers in the user storage. + * @returns A `UserStorage` object populated with triggers for each account and chain. + */ +export function initializeUserStorage( + accounts: { address?: string }[], + state: boolean, +): UserStorage { + const userStorage: UserStorage = { + [USER_STORAGE_VERSION_KEY]: USER_STORAGE_VERSION, + }; + + accounts.forEach((account) => { + const address = account.address?.toLowerCase(); + if (!address) { + return; + } + if (!userStorage[address]) { + userStorage[address] = {}; + } + + Object.entries(TRIGGERS).forEach( + ([trigger, { supported_chains: supportedChains }]) => { + supportedChains.forEach((chain) => { + if (!userStorage[address]?.[chain]) { + userStorage[address][chain] = {}; + } + + userStorage[address][chain][uuidv4()] = { + k: trigger as TRIGGER_TYPES, // use 'k' instead of 'kind' to reduce the json weight + e: state, // use 'e' instead of 'enabled' to reduce the json weight + }; + }); + }, + ); + }); + + return userStorage; +} + +/** + * Iterates over user storage to find and optionally transform notification triggers. + * This method allows for flexible retrieval and transformation of triggers based on provided options. + * + * @param userStorage - The user storage object containing notification triggers. + * @param options - Optional parameters to filter and map triggers: + * - `address`: If provided, only triggers for this address are considered. + * - `mapTrigger`: A function to transform each trigger. If not provided, triggers are returned as is. + * @returns An array of triggers, potentially transformed by the `mapTrigger` function. + */ +export function traverseUserStorageTriggers< + ResultTriggers = NotificationTrigger, +>( + userStorage: UserStorage, + options?: TraverseTriggerOpts, +): ResultTriggers[] { + const triggers: ResultTriggers[] = []; + const mapTrigger = + options?.mapTrigger ?? (triggerIdentity as MapTriggerFn); + + for (const address in userStorage) { + if (address === (USER_STORAGE_VERSION_KEY as unknown as string)) { + continue; + } + if (options?.address && address !== options.address) { + continue; + } + + for (const chainId in userStorage[address]) { + if (Object.hasOwn(userStorage[address], chainId)) { + for (const uuid in userStorage[address][chainId]) { + if (uuid) { + const mappedTrigger = mapTrigger({ + id: uuid, + kind: userStorage[address]?.[chainId]?.[uuid]?.k, + chainId, + address, + enabled: userStorage[address]?.[chainId]?.[uuid]?.e ?? false, + }); + if (mappedTrigger) { + triggers.push(mappedTrigger); + } + } + } + } + } + } + + return triggers; +} + +/** + * @deprecated - This needs rework for it to be feasible. Currently this is a half-baked solution, as it fails once we add new triggers (introspection for filters is difficult). + * + * Checks for the complete presence of trigger types by group across all addresses in the user storage. + * This method ensures that each address has at least one trigger of each type expected for every group. + * It leverages `traverseUserStorageTriggers` to iterate over triggers and check their presence. + * @param userStorage - The user storage object containing notification triggers. + * @returns A record indicating whether all expected trigger types for each group are present for every address. + */ +export function checkTriggersPresenceByGroup( + userStorage: UserStorage, +): Record { + // Initialize a record to track the complete presence of triggers for each group + const completeGroupPresence: Record = { + [TRIGGER_TYPES_GROUPS.RECEIVED]: true, + [TRIGGER_TYPES_GROUPS.SENT]: true, + [TRIGGER_TYPES_GROUPS.DEFI]: true, + }; + + // Map to track the required trigger types for each group + const requiredTriggersByGroup: Record< + TRIGGER_TYPES_GROUPS, + Set + > = { + [TRIGGER_TYPES_GROUPS.RECEIVED]: new Set([ + TRIGGER_TYPES.ERC20_RECEIVED, + TRIGGER_TYPES.ETH_RECEIVED, + TRIGGER_TYPES.ERC721_RECEIVED, + TRIGGER_TYPES.ERC1155_RECEIVED, + ]), + [TRIGGER_TYPES_GROUPS.SENT]: new Set([ + TRIGGER_TYPES.ERC20_SENT, + TRIGGER_TYPES.ETH_SENT, + TRIGGER_TYPES.ERC721_SENT, + TRIGGER_TYPES.ERC1155_SENT, + ]), + [TRIGGER_TYPES_GROUPS.DEFI]: new Set([ + TRIGGER_TYPES.METAMASK_SWAP_COMPLETED, + TRIGGER_TYPES.ROCKETPOOL_STAKE_COMPLETED, + TRIGGER_TYPES.ROCKETPOOL_UNSTAKE_COMPLETED, + TRIGGER_TYPES.LIDO_STAKE_COMPLETED, + TRIGGER_TYPES.LIDO_WITHDRAWAL_REQUESTED, + TRIGGER_TYPES.LIDO_WITHDRAWAL_COMPLETED, + TRIGGER_TYPES.LIDO_STAKE_READY_TO_BE_WITHDRAWN, + ]), + }; + + // Object to keep track of encountered triggers for each group by address + const encounteredTriggers: Record< + string, + Record> + > = {}; + + // Use traverseUserStorageTriggers to iterate over all triggers + traverseUserStorageTriggers(userStorage, { + mapTrigger: (trigger) => { + const group = groupTriggerTypes(trigger.kind as TRIGGER_TYPES); + if (!encounteredTriggers[trigger.address]) { + encounteredTriggers[trigger.address] = { + [TRIGGER_TYPES_GROUPS.RECEIVED]: new Set(), + [TRIGGER_TYPES_GROUPS.SENT]: new Set(), + [TRIGGER_TYPES_GROUPS.DEFI]: new Set(), + }; + } + encounteredTriggers[trigger.address][group].add( + trigger.kind as TRIGGER_TYPES, + ); + return undefined; // We don't need to transform the trigger, just record its presence + }, + }); + + // Check if all required triggers for each group are present for every address + Object.keys(encounteredTriggers).forEach((address) => { + Object.entries(requiredTriggersByGroup).forEach( + ([group, requiredTriggers]) => { + const hasAllTriggers = Array.from(requiredTriggers).every( + (triggerType) => + encounteredTriggers[address][group as TRIGGER_TYPES_GROUPS].has( + triggerType, + ), + ); + if (!hasAllTriggers) { + completeGroupPresence[group as TRIGGER_TYPES_GROUPS] = false; + } + }, + ); + }); + + return completeGroupPresence; +} + +/** + * Verifies the presence of specified accounts and their chains in the user storage. + * This method checks if each provided account exists in the user storage and if all its supported chains are present. + * + * @param userStorage - The user storage object containing notification triggers. + * @param accounts - An array of account addresses to check for presence. + * @returns A record where each key is an account address and each value is a boolean indicating whether the account and all its supported chains are present in the user storage. + */ +export function checkAccountsPresence( + userStorage: UserStorage, + accounts: string[], +): Record { + const presenceRecord: Record = {}; + + // Initialize presence record for all accounts as false + accounts.forEach((account) => { + presenceRecord[account.toLowerCase()] = isAccountEnabled( + account, + userStorage, + ); + }); + + return presenceRecord; +} + +function isAccountEnabled( + accountAddress: string, + userStorage: UserStorage, +): boolean { + const accountObject = userStorage[accountAddress?.toLowerCase()]; + + // If the account address is not present in the userStorage, return true + if (!accountObject) { + return false; + } + + // Check if all available chains are present + for (const [triggerKind, triggerConfig] of Object.entries(TRIGGERS)) { + for (const chain of triggerConfig.supported_chains) { + if (!accountObject[chain]) { + return false; + } + + const triggerExists = Object.values(accountObject[chain]).some( + (obj) => obj.k === triggerKind, + ); + if (!triggerExists) { + return false; + } + + // Check if any trigger is disabled + for (const uuid in accountObject[chain]) { + if (!accountObject[chain][uuid].e) { + return false; + } + } + } + } + + return true; +} + +/** + * Infers and returns an array of enabled notification trigger kinds from the user storage. + * This method counts the occurrences of each kind of trigger and returns the kinds that are present. + * + * @param userStorage - The user storage object containing notification triggers. + * @returns An array of trigger kinds (`TRIGGER_TYPES`) that are enabled in the user storage. + */ +export function inferEnabledKinds(userStorage: UserStorage): TRIGGER_TYPES[] { + const allSupportedKinds = new Set(); + + traverseUserStorageTriggers(userStorage, { + mapTrigger: (t) => { + allSupportedKinds.add(t.kind as TRIGGER_TYPES); + }, + }); + + return Array.from(allSupportedKinds); +} + +/** + * Retrieves all UUIDs associated with a specific account address from the user storage. + * This function utilizes `traverseUserStorageTriggers` with a mapping function to extract + * just the UUIDs of the notification triggers for the given address. + * + * @param userStorage - The user storage object containing notification triggers. + * @param address - The specific account address to retrieve UUIDs for. + * @returns An array of UUID strings associated with the given account address. + */ +export function getUUIDsForAccount( + userStorage: UserStorage, + address: string, +): string[] { + return traverseUserStorageTriggers(userStorage, { + address, + mapTrigger: triggerToId, + }); +} + +/** + * Retrieves all UUIDs from the user storage, regardless of the account address or chain ID. + * This method leverages `traverseUserStorageTriggers` with a specific mapping function (`triggerToId`) + * to extract only the UUIDs from all notification triggers present in the user storage. + * + * @param userStorage - The user storage object containing notification triggers. + * @returns An array of UUID strings from all notification triggers in the user storage. + */ +export function getAllUUIDs(userStorage: UserStorage): string[] { + return traverseUserStorageTriggers(userStorage, { + mapTrigger: triggerToId, + }); +} + +/** + * Retrieves UUIDs for notification triggers that match any of the specified kinds. + * This method filters triggers based on their kind and returns an array of UUIDs for those that match the allowed kinds. + * It utilizes `traverseUserStorageTriggers` with a custom mapping function that checks if a trigger's kind is in the allowed list. + * + * @param userStorage - The user storage object containing notification triggers. + * @param allowedKinds - An array of kinds (as strings) to filter the triggers by. + * @returns An array of UUID strings for triggers that match the allowed kinds. + */ +export function getUUIDsForKinds( + userStorage: UserStorage, + allowedKinds: string[], +): string[] { + const kindsSet = new Set(allowedKinds); + + return traverseUserStorageTriggers(userStorage, { + mapTrigger: (t) => (kindsSet.has(t.kind) ? t.id : undefined), + }); +} + +/** + * Retrieves notification triggers for a specific account address that match any of the specified kinds. + * This method filters triggers both by the account address and their kind, returning triggers that match the allowed kinds for the specified address. + * It leverages `traverseUserStorageTriggers` with a custom mapping function to filter and return only the relevant triggers. + * + * @param userStorage - The user storage object containing notification triggers. + * @param address - The specific account address for which to retrieve triggers. + * @param allowedKinds - An array of trigger kinds (`TRIGGER_TYPES`) to filter the triggers by. + * @returns An array of `NotificationTrigger` objects that match the allowed kinds for the specified account address. + */ +export function getUUIDsForAccountByKinds( + userStorage: UserStorage, + address: string, + allowedKinds: TRIGGER_TYPES[], +): NotificationTrigger[] { + const allowedKindsSet = new Set(allowedKinds); + return traverseUserStorageTriggers(userStorage, { + address, + mapTrigger: (trigger) => { + if (allowedKindsSet.has(trigger.kind as TRIGGER_TYPES)) { + return trigger; + } + return undefined; + }, + }); +} + +/** + * Upserts (updates or inserts) notification triggers for a given account across all supported chains. + * This method ensures that each supported trigger type exists for each chain associated with the account. + * If a trigger type does not exist for a chain, it creates a new trigger with a unique UUID. + * + * @param _account - The account address for which to upsert triggers. The address is normalized to lowercase. + * @param userStorage - The user storage object to be updated with new or existing triggers. + * @returns The updated user storage object with upserted triggers for the specified account. + */ +export function upsertAddressTriggers( + _account: string, + userStorage: UserStorage, +): UserStorage { + // Ensure the account exists in userStorage + const account = _account.toLowerCase(); + userStorage[account] = userStorage[account] || {}; + + // Iterate over each trigger and its supported chains + for (const [trigger, { supported_chains: supportedChains }] of Object.entries( + TRIGGERS, + )) { + for (const chain of supportedChains) { + // Ensure the chain exists for the account + userStorage[account][chain] = userStorage[account][chain] || {}; + + // Check if the trigger exists for the chain + const existingTrigger = Object.values(userStorage[account][chain]).find( + (obj) => obj.k === trigger, + ); + + if (!existingTrigger) { + // If the trigger doesn't exist, create a new one with a new UUID + const uuid = uuidv4(); + userStorage[account][chain][uuid] = { + k: trigger as TRIGGER_TYPES, + e: false, + }; + } + } + } + + return userStorage; +} + +/** + * Upserts (updates or inserts) notification triggers of a specific type across all accounts and chains in user storage. + * This method ensures that a trigger of the specified type exists for each account and chain. If a trigger of the specified type + * does not exist for an account and chain, it creates a new trigger with a unique UUID. + * + * @param triggerType - The type of trigger to upsert across all accounts and chains. + * @param userStorage - The user storage object to be updated with new or existing triggers of the specified type. + * @returns The updated user storage object with upserted triggers of the specified type for all accounts and chains. + */ +export function upsertTriggerTypeTriggers( + triggerType: TRIGGER_TYPES, + userStorage: UserStorage, +): UserStorage { + // Iterate over each account in userStorage + Object.entries(userStorage).forEach(([account, chains]) => { + if (account === (USER_STORAGE_VERSION_KEY as unknown as string)) { + return; + } + + // Iterate over each chain for the account + Object.entries(chains).forEach(([chain, triggers]) => { + // Check if the trigger type exists for the chain + const existingTrigger = Object.values(triggers).find( + (obj) => obj.k === triggerType, + ); + + if (!existingTrigger) { + // If the trigger type doesn't exist, create a new one with a new UUID + const uuid = uuidv4(); + userStorage[account][chain][uuid] = { + k: triggerType, + e: false, + }; + } + }); + }); + + return userStorage; +} + +/** + * Toggles the enabled status of a user storage trigger. + * + * @param userStorage - The user storage object. + * @param address - The user's address. + * @param chainId - The chain ID. + * @param uuid - The unique identifier for the trigger. + * @param enabled - The new enabled status. + * @returns The updated user storage object. + */ +export function toggleUserStorageTriggerStatus( + userStorage: UserStorage, + address: string, + chainId: string, + uuid: string, + enabled: boolean, +): UserStorage { + if (userStorage?.[address]?.[chainId]?.[uuid]) { + userStorage[address][chainId][uuid].e = enabled; + } + + return userStorage; +} + +/** + * Attempts to fetch a resource from the network, retrying the request up to a specified number of times + * in case of failure, with a delay between attempts. + * + * @param url - The resource URL. + * @param options - The options for the fetch request. + * @param retries - Maximum number of retry attempts. Defaults to 3. + * @param retryDelay - Delay between retry attempts in milliseconds. Defaults to 1000. + * @returns A Promise resolving to the Response object. + * @throws Will throw an error if the request fails after the specified number of retries. + */ +async function fetchWithRetry( + url: string, + options: RequestInit, + retries = 3, + retryDelay = 1000, +): Promise { + for (let attempt = 1; attempt <= retries; attempt++) { + try { + const response = await fetch(url, options); + if (!response.ok) { + throw new Error(`Fetch failed with status: ${response.status}`); + } + return response; + } catch (error) { + log.error(`Attempt ${attempt} failed for fetch:`, error); + if (attempt < retries) { + await new Promise((resolve) => setTimeout(resolve, retryDelay)); + } else { + throw new Error( + `Fetching failed after ${retries} retries. Last error: ${ + error instanceof Error ? error.message : 'Unknown error' + }`, + ); + } + } + } + + throw new Error('Unexpected error in fetchWithRetry'); +} + +/** + * Performs an API call with automatic retries on failure. + * + * @param bearerToken - The JSON Web Token for authorization. + * @param endpoint - The URL of the API endpoint to call. + * @param method - The HTTP method ('POST' or 'DELETE'). + * @param body - The body of the request. It should be an object that can be serialized to JSON. + * @param retries - The number of retry attempts in case of failure (default is 3). + * @param retryDelay - The delay between retries in milliseconds (default is 1000). + * @returns A Promise that resolves to the response of the fetch request. + */ +export async function makeApiCall( + bearerToken: string, + endpoint: string, + method: 'POST' | 'DELETE', + body: T, + retries = 3, + retryDelay = 1000, +): Promise { + const options: RequestInit = { + method, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${bearerToken}`, + }, + body: JSON.stringify(body), + }; + + return fetchWithRetry(endpoint, options, retries, retryDelay); +} diff --git a/app/scripts/controllers/metametrics.js b/app/scripts/controllers/metametrics.js index c8e46a5283b1..c7bd148e62d3 100644 --- a/app/scripts/controllers/metametrics.js +++ b/app/scripts/controllers/metametrics.js @@ -154,6 +154,7 @@ export default class MetaMetricsController { this.store = new ObservableStore({ participateInMetaMetrics: null, metaMetricsId: null, + dataCollectionForMarketing: null, eventsBeforeMetricsOptIn: [], traits: {}, previousUserTraits: {}, @@ -188,7 +189,11 @@ export default class MetaMetricsController { // Code below submits any pending segmentApiCalls to Segment if/when the controller is re-instantiated if (isManifestV3) { Object.values(segmentApiCalls).forEach(({ eventType, payload }) => { - this._submitSegmentAPICall(eventType, payload); + try { + this._submitSegmentAPICall(eventType, payload); + } catch (error) { + this._captureException(error); + } }); } @@ -471,6 +476,12 @@ export default class MetaMetricsController { return metaMetricsId; } + setDataCollectionForMarketing(dataCollectionForMarketing) { + const { metaMetricsId } = this.state; + this.store.updateState({ dataCollectionForMarketing }); + return metaMetricsId; + } + get state() { return this.store.getState(); } @@ -652,6 +663,16 @@ export default class MetaMetricsController { }); } + // Retrieve (or generate if doesn't exist) the client metametrics id + getMetaMetricsId() { + let { metaMetricsId } = this.state; + if (!metaMetricsId) { + metaMetricsId = this.generateMetaMetricsId(); + this.store.updateState({ metaMetricsId }); + } + return metaMetricsId; + } + /** PRIVATE METHODS */ /** @@ -764,13 +785,7 @@ export default class MetaMetricsController { : null; ///: END:ONLY_INCLUDE_IF const { traits, previousUserTraits } = this.store.getState(); - let securityProvider; - if (metamaskState.securityAlertsEnabled) { - securityProvider = 'blockaid'; - } - if (metamaskState.transactionSecurityCheckEnabled) { - securityProvider = 'opensea'; - } + /** @type {MetaMetricsTraits} */ const currentTraits = { [MetaMetricsUserTrait.AddressBookEntries]: sum( @@ -807,20 +822,19 @@ export default class MetaMetricsController { metamaskState.useTokenDetection, [MetaMetricsUserTrait.UseNativeCurrencyAsPrimaryCurrency]: metamaskState.useNativeCurrencyAsPrimaryCurrency, - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - [MetaMetricsUserTrait.DesktopEnabled]: - metamaskState.desktopEnabled || false, - ///: END:ONLY_INCLUDE_IF ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) [MetaMetricsUserTrait.MmiExtensionId]: this.extension?.runtime?.id, [MetaMetricsUserTrait.MmiAccountAddress]: mmiAccountAddress, [MetaMetricsUserTrait.MmiIsCustodian]: Boolean(mmiAccountAddress), ///: END:ONLY_INCLUDE_IF - [MetaMetricsUserTrait.SecurityProviders]: securityProvider - ? [securityProvider] - : [], + [MetaMetricsUserTrait.SecurityProviders]: + metamaskState.securityAlertsEnabled ? ['blockaid'] : [], [MetaMetricsUserTrait.PetnameAddressCount]: this._getPetnameAddressCount(metamaskState), + [MetaMetricsUserTrait.IsMetricsOptedIn]: + metamaskState.participateInMetaMetrics, + [MetaMetricsUserTrait.HasMarketingConsent]: + metamaskState.dataCollectionForMarketing, }; if (!previousUserTraits) { diff --git a/app/scripts/controllers/metametrics.test.js b/app/scripts/controllers/metametrics.test.js index 9a7540c078f4..43834f01a4b9 100644 --- a/app/scripts/controllers/metametrics.test.js +++ b/app/scripts/controllers/metametrics.test.js @@ -1,5 +1,3 @@ -import { strict as assert } from 'assert'; -import sinon from 'sinon'; import { toHex } from '@metamask/controller-utils'; import { NameType } from '@metamask/name-controller'; import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../shared/constants/app'; @@ -9,7 +7,6 @@ import { METAMETRICS_BACKGROUND_PAGE_OBJECT, MetaMetricsUserTrait, } from '../../../shared/constants/metametrics'; -import waitUntilCalled from '../../../test/lib/wait-until-called'; import { CHAIN_IDS, CURRENCY_SYMBOLS } from '../../../shared/constants/network'; import * as Utils from '../lib/util'; import MetaMetricsController from './metametrics'; @@ -78,13 +75,13 @@ function getMockPreferencesStore({ currentLocale = LOCALE } = {}) { let preferencesStore = { currentLocale, }; - const subscribe = sinon.stub(); + const subscribe = jest.fn(); const updateState = (newState) => { preferencesStore = { ...preferencesStore, ...newState }; - subscribe.getCall(0).args[0](preferencesStore); + subscribe.mock.calls[0][0](preferencesStore); }; return { - getState: sinon.stub().returns(preferencesStore), + getState: jest.fn().mockReturnValue(preferencesStore), updateState, subscribe, }; @@ -145,27 +142,36 @@ function getMetaMetricsController({ describe('MetaMetricsController', function () { const now = new Date(); - let clock; beforeEach(function () { globalThis.sentry = { - startSession: sinon.fake(() => { - /** NOOP */ - }), - endSession: sinon.fake(() => { - /** NOOP */ - }), + startSession: jest.fn(), + endSession: jest.fn(), }; - clock = sinon.useFakeTimers(now.getTime()); - sinon.stub(Utils, 'generateRandomId').returns('DUMMY_RANDOM_ID'); + jest.useFakeTimers().setSystemTime(now.getTime()); + jest.spyOn(Utils, 'generateRandomId').mockReturnValue('DUMMY_RANDOM_ID'); }); describe('constructor', function () { it('should properly initialize', function () { - const mock = sinon.mock(segment); - mock - .expects('track') - .once() - .withArgs({ + const spy = jest.spyOn(segment, 'track'); + const metaMetricsController = getMetaMetricsController(); + expect(metaMetricsController.version).toStrictEqual(VERSION); + expect(metaMetricsController.chainId).toStrictEqual(FAKE_CHAIN_ID); + expect( + metaMetricsController.state.participateInMetaMetrics, + ).toStrictEqual(true); + expect(metaMetricsController.state.metaMetricsId).toStrictEqual( + TEST_META_METRICS_ID, + ); + expect(metaMetricsController.locale).toStrictEqual( + LOCALE.replace('_', '-'), + ); + expect(metaMetricsController.state.fragments).toStrictEqual({ + testid: SAMPLE_PERSISTED_EVENT, + }); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith( + { event: 'sample non-persisted event failure', userId: TEST_META_METRICS_ID, context: DEFAULT_TEST_CONTEXT, @@ -175,26 +181,9 @@ describe('MetaMetricsController', function () { }, messageId: 'sample-non-persisted-event-failure', timestamp: new Date(), - }); - const metaMetricsController = getMetaMetricsController(); - assert.strictEqual(metaMetricsController.version, VERSION); - assert.strictEqual(metaMetricsController.chainId, FAKE_CHAIN_ID); - assert.strictEqual( - metaMetricsController.state.participateInMetaMetrics, - true, - ); - assert.strictEqual( - metaMetricsController.state.metaMetricsId, - TEST_META_METRICS_ID, - ); - assert.strictEqual( - metaMetricsController.locale, - LOCALE.replace('_', '-'), + }, + spy.mock.calls[0][1], ); - assert.deepStrictEqual(metaMetricsController.state.fragments, { - testid: SAMPLE_PERSISTED_EVENT, - }); - mock.verify(); }); it('should update when network changes', function () { @@ -211,7 +200,7 @@ describe('MetaMetricsController', function () { chainId = '0x222'; networkDidChangeListener(); - assert.strictEqual(metaMetricsController.chainId, '0x222'); + expect(metaMetricsController.chainId).toStrictEqual('0x222'); }); it('should update when preferences changes', function () { @@ -219,97 +208,101 @@ describe('MetaMetricsController', function () { const metaMetricsController = getMetaMetricsController({ preferencesStore, }); - preferencesStore.updateState({ - currentLocale: 'en_UK', - }); - assert.strictEqual(metaMetricsController.locale, 'en-UK'); + preferencesStore.updateState({ currentLocale: 'en_UK' }); + expect(metaMetricsController.locale).toStrictEqual('en-UK'); }); }); describe('generateMetaMetricsId', function () { it('should generate an 0x prefixed hex string', function () { const metaMetricsController = getMetaMetricsController(); - assert.equal( + expect( metaMetricsController.generateMetaMetricsId().startsWith('0x'), - true, - ); + ).toStrictEqual(true); }); }); - describe('identify', function () { - it('should call segment.identify for valid traits if user is participating in metametrics', async function () { + describe('getMetaMetricsId', function () { + it('should generate or return the metametrics id', function () { const metaMetricsController = getMetaMetricsController({ participateInMetaMetrics: true, - metaMetricsId: TEST_META_METRICS_ID, + metaMetricsId: null, }); - const mock = sinon.mock(segment); - mock.expects('identify').once().withArgs({ - userId: TEST_META_METRICS_ID, - traits: MOCK_TRAITS, - messageId: Utils.generateRandomId(), - timestamp: new Date(), - }); + // Starts off being empty. + expect(metaMetricsController.state.metaMetricsId).toStrictEqual(null); + + // Create a new metametrics id. + const clientMetaMetricsId = metaMetricsController.getMetaMetricsId(); + expect(clientMetaMetricsId.startsWith('0x')).toStrictEqual(true); + + // Return same metametrics id. + const sameMetaMetricsId = metaMetricsController.getMetaMetricsId(); + expect(clientMetaMetricsId).toStrictEqual(sameMetaMetricsId); + }); + }); + describe('identify', function () { + it('should call segment.identify for valid traits if user is participating in metametrics', function () { + const spy = jest.spyOn(segment, 'identify'); + const metaMetricsController = getMetaMetricsController({ + participateInMetaMetrics: true, + metaMetricsId: TEST_META_METRICS_ID, + }); metaMetricsController.identify({ ...MOCK_TRAITS, ...MOCK_INVALID_TRAITS, }); - - mock.verify(); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith( + { + userId: TEST_META_METRICS_ID, + traits: MOCK_TRAITS, + messageId: Utils.generateRandomId(), + timestamp: new Date(), + }, + spy.mock.calls[0][1], + ); }); - it('should transform date type traits into ISO-8601 timestamp strings', async function () { + it('should transform date type traits into ISO-8601 timestamp strings', function () { + const spy = jest.spyOn(segment, 'identify'); const metaMetricsController = getMetaMetricsController({ participateInMetaMetrics: true, metaMetricsId: TEST_META_METRICS_ID, }); - const mock = sinon.mock(segment); - - const mockDate = new Date(); - const mockDateISOString = mockDate.toISOString(); - - mock - .expects('identify') - .once() - .withArgs({ + metaMetricsController.identify({ test_date: new Date().toISOString() }); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith( + { userId: TEST_META_METRICS_ID, traits: { - test_date: mockDateISOString, + test_date: new Date().toISOString(), }, messageId: Utils.generateRandomId(), timestamp: new Date(), - }); - - metaMetricsController.identify({ - test_date: mockDate, - }); - mock.verify(); + }, + spy.mock.calls[0][1], + ); }); it('should not call segment.identify if user is not participating in metametrics', function () { + const spy = jest.spyOn(segment, 'identify'); const metaMetricsController = getMetaMetricsController({ participateInMetaMetrics: false, }); - const mock = sinon.mock(segment); - - mock.expects('identify').never(); - metaMetricsController.identify(MOCK_TRAITS); - mock.verify(); + expect(spy).toHaveBeenCalledTimes(0); }); - it('should not call segment.identify if there are no valid traits to identify', async function () { + it('should not call segment.identify if there are no valid traits to identify', function () { + const spy = jest.spyOn(segment, 'identify'); const metaMetricsController = getMetaMetricsController({ participateInMetaMetrics: true, metaMetricsId: TEST_META_METRICS_ID, }); - const mock = sinon.mock(segment); - - mock.expects('identify').never(); - metaMetricsController.identify(MOCK_INVALID_TRAITS); - mock.verify(); + expect(spy).toHaveBeenCalledTimes(0); }); }); @@ -319,28 +312,35 @@ describe('MetaMetricsController', function () { participateInMetaMetrics: null, metaMetricsId: null, }); - assert.equal(metaMetricsController.state.participateInMetaMetrics, null); + expect( + metaMetricsController.state.participateInMetaMetrics, + ).toStrictEqual(null); await metaMetricsController.setParticipateInMetaMetrics(true); - assert.ok(globalThis.sentry.startSession.calledOnce); - assert.equal(metaMetricsController.state.participateInMetaMetrics, true); + expect(globalThis.sentry.startSession).toHaveBeenCalledTimes(1); + expect( + metaMetricsController.state.participateInMetaMetrics, + ).toStrictEqual(true); await metaMetricsController.setParticipateInMetaMetrics(false); - assert.equal(metaMetricsController.state.participateInMetaMetrics, false); + expect( + metaMetricsController.state.participateInMetaMetrics, + ).toStrictEqual(false); }); it('should generate and update the metaMetricsId when set to true', async function () { const metaMetricsController = getMetaMetricsController({ participateInMetaMetrics: null, metaMetricsId: null, }); - assert.equal(metaMetricsController.state.metaMetricsId, null); + expect(metaMetricsController.state.metaMetricsId).toStrictEqual(null); await metaMetricsController.setParticipateInMetaMetrics(true); - assert.equal(typeof metaMetricsController.state.metaMetricsId, 'string'); + expect(typeof metaMetricsController.state.metaMetricsId).toStrictEqual( + 'string', + ); }); it('should not nullify the metaMetricsId when set to false', async function () { const metaMetricsController = getMetaMetricsController(); await metaMetricsController.setParticipateInMetaMetrics(false); - assert.ok(globalThis.sentry.endSession.calledOnce); - assert.equal( - metaMetricsController.state.metaMetricsId, + expect(globalThis.sentry.endSession).toHaveBeenCalledTimes(1); + expect(metaMetricsController.state.metaMetricsId).toStrictEqual( TEST_META_METRICS_ID, ); }); @@ -348,11 +348,10 @@ describe('MetaMetricsController', function () { describe('submitEvent', function () { it('should not track an event if user is not participating in metametrics', function () { - const mock = sinon.mock(segment); + const spy = jest.spyOn(segment, 'track'); const metaMetricsController = getMetaMetricsController({ participateInMetaMetrics: false, }); - mock.expects('track').never(); metaMetricsController.submitEvent({ event: 'Fake Event', category: 'Unit Test', @@ -360,18 +359,27 @@ describe('MetaMetricsController', function () { test: 1, }, }); - mock.verify(); + expect(spy).toHaveBeenCalledTimes(0); }); it('should track an event if user has not opted in, but isOptIn is true', function () { - const mock = sinon.mock(segment); const metaMetricsController = getMetaMetricsController({ participateInMetaMetrics: true, }); - mock - .expects('track') - .once() - .withArgs({ + const spy = jest.spyOn(segment, 'track'); + metaMetricsController.submitEvent( + { + event: 'Fake Event', + category: 'Unit Test', + properties: { + test: 1, + }, + }, + { isOptIn: true }, + ); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith( + { event: 'Fake Event', anonymousId: METAMETRICS_ANONYMOUS_ID, context: DEFAULT_TEST_CONTEXT, @@ -381,7 +389,16 @@ describe('MetaMetricsController', function () { }, messageId: Utils.generateRandomId(), timestamp: new Date(), - }); + }, + spy.mock.calls[0][1], + ); + }); + + it('should track an event during optin and allow for metaMetricsId override', function () { + const metaMetricsController = getMetaMetricsController({ + participateInMetaMetrics: true, + }); + const spy = jest.spyOn(segment, 'track'); metaMetricsController.submitEvent( { event: 'Fake Event', @@ -390,20 +407,11 @@ describe('MetaMetricsController', function () { test: 1, }, }, - { isOptIn: true }, + { isOptIn: true, metaMetricsId: 'TESTID' }, ); - mock.verify(); - }); - - it('should track an event during optin and allow for metaMetricsId override', function () { - const mock = sinon.mock(segment); - const metaMetricsController = getMetaMetricsController({ - participateInMetaMetrics: true, - }); - mock - .expects('track') - .once() - .withArgs({ + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith( + { event: 'Fake Event', userId: 'TESTID', context: DEFAULT_TEST_CONTEXT, @@ -413,7 +421,14 @@ describe('MetaMetricsController', function () { }, messageId: Utils.generateRandomId(), timestamp: new Date(), - }); + }, + spy.mock.calls[0][1], + ); + }); + + it('should track a legacy event', function () { + const metaMetricsController = getMetaMetricsController(); + const spy = jest.spyOn(segment, 'track'); metaMetricsController.submitEvent( { event: 'Fake Event', @@ -422,18 +437,11 @@ describe('MetaMetricsController', function () { test: 1, }, }, - { isOptIn: true, metaMetricsId: 'TESTID' }, + { matomoEvent: true }, ); - mock.verify(); - }); - - it('should track a legacy event', function () { - const mock = sinon.mock(segment); - const metaMetricsController = getMetaMetricsController(); - mock - .expects('track') - .once() - .withArgs({ + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith( + { event: 'Fake Event', userId: TEST_META_METRICS_ID, context: DEFAULT_TEST_CONTEXT, @@ -444,27 +452,24 @@ describe('MetaMetricsController', function () { }, messageId: Utils.generateRandomId(), timestamp: new Date(), - }); - metaMetricsController.submitEvent( - { - event: 'Fake Event', - category: 'Unit Test', - properties: { - test: 1, - }, }, - { matomoEvent: true }, + spy.mock.calls[0][1], ); - mock.verify(); }); it('should track a non legacy event', function () { - const mock = sinon.mock(segment); const metaMetricsController = getMetaMetricsController(); - mock - .expects('track') - .once() - .withArgs({ + const spy = jest.spyOn(segment, 'track'); + metaMetricsController.submitEvent({ + event: 'Fake Event', + category: 'Unit Test', + properties: { + test: 1, + }, + }); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith( + { event: 'Fake Event', properties: { test: 1, @@ -474,21 +479,14 @@ describe('MetaMetricsController', function () { userId: TEST_META_METRICS_ID, messageId: Utils.generateRandomId(), timestamp: new Date(), - }); - metaMetricsController.submitEvent({ - event: 'Fake Event', - category: 'Unit Test', - properties: { - test: 1, }, - }); - mock.verify(); + spy.mock.calls[0][1], + ); }); - it('should immediately flush queue if flushImmediately set to true', async function () { + it('should immediately flush queue if flushImmediately set to true', function () { const metaMetricsController = getMetaMetricsController(); - const flushStub = sinon.stub(segment, 'flush'); - const flushCalled = waitUntilCalled(flushStub, segment); + const spy = jest.spyOn(segment, 'flush'); metaMetricsController.submitEvent( { event: 'Fake Event', @@ -496,51 +494,48 @@ describe('MetaMetricsController', function () { }, { flushImmediately: true }, ); - assert.doesNotReject(flushCalled()); + expect(spy).not.toThrow(); }); - it('should throw if event or category not provided', function () { + it('should throw if event or category not provided', async function () { const metaMetricsController = getMetaMetricsController(); - assert.rejects( - () => metaMetricsController.submitEvent({ event: 'test' }), - /Must specify event and category\./u, - 'must specify category', - ); - assert.rejects( - () => metaMetricsController.submitEvent({ category: 'test' }), - /Must specify event and category\./u, - 'must specify event', - ); + await expect( + metaMetricsController.submitEvent({ event: 'test' }), + ).rejects.toThrow(/Must specify event and category\./u); + + await expect( + metaMetricsController.submitEvent({ category: 'test' }), + ).rejects.toThrow(/Must specify event and category\./u); }); - it('should throw if provided sensitiveProperties, when excludeMetaMetricsId is true', function () { + it('should throw if provided sensitiveProperties, when excludeMetaMetricsId is true', async function () { const metaMetricsController = getMetaMetricsController(); - assert.rejects( - () => - metaMetricsController.submitEvent( - { - event: 'Fake Event', - category: 'Unit Test', - sensitiveProperties: { foo: 'bar' }, - }, - { excludeMetaMetricsId: true }, - ), + await expect( + metaMetricsController.submitEvent( + { + event: 'Fake Event', + category: 'Unit Test', + sensitiveProperties: { foo: 'bar' }, + }, + { excludeMetaMetricsId: true }, + ), + ).rejects.toThrow( /sensitiveProperties was specified in an event payload that also set the excludeMetaMetricsId flag/u, ); }); it('should track sensitiveProperties in a separate, anonymous event', function () { const metaMetricsController = getMetaMetricsController(); - const spy = sinon.spy(segment, 'track'); + const spy = jest.spyOn(segment, 'track'); metaMetricsController.submitEvent({ event: 'Fake Event', category: 'Unit Test', sensitiveProperties: { foo: 'bar' }, }); - assert.ok(spy.calledTwice); - assert.ok( - spy.calledWith({ + expect(spy).toHaveBeenCalledTimes(2); + expect(spy).toHaveBeenCalledWith( + { event: 'Fake Event', anonymousId: METAMETRICS_ANONYMOUS_ID, context: DEFAULT_TEST_CONTEXT, @@ -550,17 +545,19 @@ describe('MetaMetricsController', function () { }, messageId: Utils.generateRandomId(), timestamp: new Date(), - }), + }, + spy.mock.calls[0][1], ); - assert.ok( - spy.calledWith({ + expect(spy).toHaveBeenCalledWith( + { event: 'Fake Event', userId: TEST_META_METRICS_ID, context: DEFAULT_TEST_CONTEXT, properties: DEFAULT_EVENT_PROPERTIES, messageId: Utils.generateRandomId(), timestamp: new Date(), - }), + }, + spy.mock.calls[1][1], ); }); }); @@ -568,15 +565,15 @@ describe('MetaMetricsController', function () { describe('Change Transaction XXX anonymous event namnes', function () { it('should change "Transaction Added" anonymous event names to "Transaction Added Anon"', function () { const metaMetricsController = getMetaMetricsController(); - const spy = sinon.spy(segment, 'track'); + const spy = jest.spyOn(segment, 'track'); metaMetricsController.submitEvent({ event: 'Transaction Added', category: 'Unit Test', sensitiveProperties: { foo: 'bar' }, }); - assert.ok(spy.calledTwice); - assert.ok( - spy.calledWith({ + expect(spy).toHaveBeenCalledTimes(2); + expect(spy).toHaveBeenCalledWith( + { event: `Transaction Added Anon`, anonymousId: METAMETRICS_ANONYMOUS_ID, context: DEFAULT_TEST_CONTEXT, @@ -586,21 +583,22 @@ describe('MetaMetricsController', function () { }, messageId: Utils.generateRandomId(), timestamp: new Date(), - }), + }, + spy.mock.calls[0][1], ); }); it('should change "Transaction Submitted" anonymous event names to "Transaction Added Anon"', function () { const metaMetricsController = getMetaMetricsController(); - const spy = sinon.spy(segment, 'track'); + const spy = jest.spyOn(segment, 'track'); metaMetricsController.submitEvent({ event: 'Transaction Submitted', category: 'Unit Test', sensitiveProperties: { foo: 'bar' }, }); - assert.ok(spy.calledTwice); - assert.ok( - spy.calledWith({ + expect(spy).toHaveBeenCalledTimes(2); + expect(spy).toHaveBeenCalledWith( + { event: `Transaction Submitted Anon`, anonymousId: METAMETRICS_ANONYMOUS_ID, context: DEFAULT_TEST_CONTEXT, @@ -610,21 +608,22 @@ describe('MetaMetricsController', function () { }, messageId: Utils.generateRandomId(), timestamp: new Date(), - }), + }, + spy.mock.calls[0][1], ); }); it('should change "Transaction Finalized" anonymous event names to "Transaction Added Anon"', function () { const metaMetricsController = getMetaMetricsController(); - const spy = sinon.spy(segment, 'track'); + const spy = jest.spyOn(segment, 'track'); metaMetricsController.submitEvent({ event: 'Transaction Finalized', category: 'Unit Test', sensitiveProperties: { foo: 'bar' }, }); - assert.ok(spy.calledTwice); - assert.ok( - spy.calledWith({ + expect(spy).toHaveBeenCalledTimes(2); + expect(spy).toHaveBeenCalledWith( + { event: `Transaction Finalized Anon`, anonymousId: METAMETRICS_ANONYMOUS_ID, context: DEFAULT_TEST_CONTEXT, @@ -634,19 +633,25 @@ describe('MetaMetricsController', function () { }, messageId: Utils.generateRandomId(), timestamp: new Date(), - }), + }, + spy.mock.calls[0][1], ); }); }); describe('trackPage', function () { it('should track a page view', function () { - const mock = sinon.mock(segment); const metaMetricsController = getMetaMetricsController(); - mock - .expects('page') - .once() - .withArgs({ + const spy = jest.spyOn(segment, 'page'); + metaMetricsController.trackPage({ + name: 'home', + params: null, + environmentType: ENVIRONMENT_TYPE_BACKGROUND, + page: METAMETRICS_BACKGROUND_PAGE_OBJECT, + }); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith( + { name: 'home', userId: TEST_META_METRICS_ID, context: DEFAULT_TEST_CONTEXT, @@ -656,42 +661,44 @@ describe('MetaMetricsController', function () { }, messageId: Utils.generateRandomId(), timestamp: new Date(), - }); - metaMetricsController.trackPage({ - name: 'home', - params: null, - environmentType: ENVIRONMENT_TYPE_BACKGROUND, - page: METAMETRICS_BACKGROUND_PAGE_OBJECT, - }); - mock.verify(); + }, + spy.mock.calls[0][1], + ); }); it('should not track a page view if user is not participating in metametrics', function () { - const mock = sinon.mock(segment); const metaMetricsController = getMetaMetricsController({ participateInMetaMetrics: false, }); - mock.expects('page').never(); + const spy = jest.spyOn(segment, 'page'); metaMetricsController.trackPage({ name: 'home', params: null, environmentType: ENVIRONMENT_TYPE_BACKGROUND, page: METAMETRICS_BACKGROUND_PAGE_OBJECT, }); - mock.verify(); + expect(spy).toHaveBeenCalledTimes(0); }); it('should track a page view if isOptInPath is true and user not yet opted in', function () { - const mock = sinon.mock(segment); const metaMetricsController = getMetaMetricsController({ preferencesStore: getMockPreferencesStore({ participateInMetaMetrics: null, }), }); - mock - .expects('page') - .once() - .withArgs({ + const spy = jest.spyOn(segment, 'page'); + metaMetricsController.trackPage( + { + name: 'home', + params: null, + environmentType: ENVIRONMENT_TYPE_BACKGROUND, + page: METAMETRICS_BACKGROUND_PAGE_OBJECT, + }, + { isOptInPath: true }, + ); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith( + { name: 'home', userId: TEST_META_METRICS_ID, context: DEFAULT_TEST_CONTEXT, @@ -701,40 +708,18 @@ describe('MetaMetricsController', function () { }, messageId: Utils.generateRandomId(), timestamp: new Date(), - }); - metaMetricsController.trackPage( - { - name: 'home', - params: null, - environmentType: ENVIRONMENT_TYPE_BACKGROUND, - page: METAMETRICS_BACKGROUND_PAGE_OBJECT, }, - { isOptInPath: true }, + spy.mock.calls[0][1], ); - mock.verify(); }); it('multiple trackPage call with same actionId should result in same messageId being sent to segment', function () { - const mock = sinon.mock(segment); const metaMetricsController = getMetaMetricsController({ preferencesStore: getMockPreferencesStore({ participateInMetaMetrics: null, }), }); - mock - .expects('page') - .twice() - .withArgs({ - name: 'home', - userId: TEST_META_METRICS_ID, - context: DEFAULT_TEST_CONTEXT, - properties: { - params: null, - ...DEFAULT_PAGE_PROPERTIES, - }, - messageId: DUMMY_ACTION_ID, - timestamp: new Date(), - }); + const spy = jest.spyOn(segment, 'page'); metaMetricsController.trackPage( { name: 'home', @@ -755,23 +740,37 @@ describe('MetaMetricsController', function () { }, { isOptInPath: true }, ); - mock.verify(); + expect(spy).toHaveBeenCalledTimes(2); + expect(spy).toHaveBeenCalledWith( + { + name: 'home', + userId: TEST_META_METRICS_ID, + context: DEFAULT_TEST_CONTEXT, + properties: { + params: null, + ...DEFAULT_PAGE_PROPERTIES, + }, + messageId: DUMMY_ACTION_ID, + timestamp: new Date(), + }, + spy.mock.calls[0][1], + ); }); }); describe('deterministic messageId', function () { it('should use the actionId as messageId when provided', function () { const metaMetricsController = getMetaMetricsController(); - const spy = sinon.spy(segment, 'track'); + const spy = jest.spyOn(segment, 'track'); metaMetricsController.submitEvent({ event: 'Fake Event', category: 'Unit Test', properties: { foo: 'bar' }, actionId: '0x001', }); - assert.ok(spy.calledOnce); - assert.ok( - spy.calledWith({ + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith( + { event: 'Fake Event', userId: TEST_META_METRICS_ID, context: DEFAULT_TEST_CONTEXT, @@ -781,23 +780,23 @@ describe('MetaMetricsController', function () { }, messageId: '0x001', timestamp: new Date(), - }), + }, + spy.mock.calls[0][1], ); }); it('should append 0x000 to the actionId of anonymized event when tracking sensitiveProperties', function () { const metaMetricsController = getMetaMetricsController(); - const spy = sinon.spy(segment, 'track'); + const spy = jest.spyOn(segment, 'track'); metaMetricsController.submitEvent({ event: 'Fake Event', category: 'Unit Test', sensitiveProperties: { foo: 'bar' }, actionId: '0x001', }); - assert.ok(spy.calledTwice); - - assert.ok( - spy.calledWith({ + expect(spy).toHaveBeenCalledTimes(2); + expect(spy).toHaveBeenCalledWith( + { event: 'Fake Event', anonymousId: METAMETRICS_ANONYMOUS_ID, context: DEFAULT_TEST_CONTEXT, @@ -807,10 +806,11 @@ describe('MetaMetricsController', function () { }, messageId: '0x001-0x000', timestamp: new Date(), - }), + }, + spy.mock.calls[0][1], ); - assert.ok( - spy.calledWith({ + expect(spy).toHaveBeenCalledWith( + { event: 'Fake Event', userId: TEST_META_METRICS_ID, context: DEFAULT_TEST_CONTEXT, @@ -819,22 +819,23 @@ describe('MetaMetricsController', function () { }, messageId: '0x001', timestamp: new Date(), - }), + }, + spy.mock.calls[1][1], ); }); it('should use the uniqueIdentifier as messageId when provided', function () { const metaMetricsController = getMetaMetricsController(); - const spy = sinon.spy(segment, 'track'); + const spy = jest.spyOn(segment, 'track'); metaMetricsController.submitEvent({ event: 'Fake Event', category: 'Unit Test', properties: { foo: 'bar' }, uniqueIdentifier: 'transaction-submitted-0000', }); - assert.ok(spy.calledOnce); - assert.ok( - spy.calledWith({ + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith( + { event: 'Fake Event', userId: TEST_META_METRICS_ID, context: DEFAULT_TEST_CONTEXT, @@ -844,22 +845,23 @@ describe('MetaMetricsController', function () { }, messageId: 'transaction-submitted-0000', timestamp: new Date(), - }), + }, + spy.mock.calls[0][1], ); }); it('should append 0x000 to the uniqueIdentifier of anonymized event when tracking sensitiveProperties', function () { const metaMetricsController = getMetaMetricsController(); - const spy = sinon.spy(segment, 'track'); + const spy = jest.spyOn(segment, 'track'); metaMetricsController.submitEvent({ event: 'Fake Event', category: 'Unit Test', sensitiveProperties: { foo: 'bar' }, uniqueIdentifier: 'transaction-submitted-0000', }); - assert.ok(spy.calledTwice); - assert.ok( - spy.calledWith({ + expect(spy).toHaveBeenCalledTimes(2); + expect(spy).toHaveBeenCalledWith( + { event: 'Fake Event', anonymousId: METAMETRICS_ANONYMOUS_ID, context: DEFAULT_TEST_CONTEXT, @@ -869,10 +871,11 @@ describe('MetaMetricsController', function () { }, messageId: 'transaction-submitted-0000-0x000', timestamp: new Date(), - }), + }, + spy.mock.calls[0][1], ); - assert.ok( - spy.calledWith({ + expect(spy).toHaveBeenCalledWith( + { event: 'Fake Event', userId: TEST_META_METRICS_ID, context: DEFAULT_TEST_CONTEXT, @@ -881,13 +884,14 @@ describe('MetaMetricsController', function () { }, messageId: 'transaction-submitted-0000', timestamp: new Date(), - }), + }, + spy.mock.calls[1][1], ); }); it('should combine the uniqueIdentifier and actionId as messageId when both provided', function () { const metaMetricsController = getMetaMetricsController(); - const spy = sinon.spy(segment, 'track'); + const spy = jest.spyOn(segment, 'track'); metaMetricsController.submitEvent({ event: 'Fake Event', category: 'Unit Test', @@ -895,9 +899,9 @@ describe('MetaMetricsController', function () { actionId: '0x001', uniqueIdentifier: 'transaction-submitted-0000', }); - assert.ok(spy.calledOnce); - assert.ok( - spy.calledWith({ + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith( + { event: 'Fake Event', userId: TEST_META_METRICS_ID, context: DEFAULT_TEST_CONTEXT, @@ -907,13 +911,14 @@ describe('MetaMetricsController', function () { }, messageId: 'transaction-submitted-0000-0x001', timestamp: new Date(), - }), + }, + spy.mock.calls[0][1], ); }); it('should append 0x000 to the combined uniqueIdentifier and actionId of anonymized event when tracking sensitiveProperties', function () { const metaMetricsController = getMetaMetricsController(); - const spy = sinon.spy(segment, 'track'); + const spy = jest.spyOn(segment, 'track'); metaMetricsController.submitEvent({ event: 'Fake Event', category: 'Unit Test', @@ -921,9 +926,9 @@ describe('MetaMetricsController', function () { actionId: '0x001', uniqueIdentifier: 'transaction-submitted-0000', }); - assert.ok(spy.calledTwice); - assert.ok( - spy.calledWith({ + expect(spy).toHaveBeenCalledTimes(2); + expect(spy).toHaveBeenCalledWith( + { event: 'Fake Event', anonymousId: METAMETRICS_ANONYMOUS_ID, context: DEFAULT_TEST_CONTEXT, @@ -933,10 +938,11 @@ describe('MetaMetricsController', function () { }, messageId: 'transaction-submitted-0000-0x001-0x000', timestamp: new Date(), - }), + }, + spy.mock.calls[0][1], ); - assert.ok( - spy.calledWith({ + expect(spy).toHaveBeenCalledWith( + { event: 'Fake Event', userId: TEST_META_METRICS_ID, context: DEFAULT_TEST_CONTEXT, @@ -945,7 +951,8 @@ describe('MetaMetricsController', function () { }, messageId: 'transaction-submitted-0000-0x001', timestamp: new Date(), - }), + }, + spy.mock.calls[1][1], ); }); }); @@ -1038,7 +1045,6 @@ describe('MetaMetricsController', function () { theme: 'default', useTokenDetection: true, useNativeCurrencyAsPrimaryCurrency: true, - desktopEnabled: false, security_providers: [], names: { [NameType.ETHEREUM_ADDRESS]: { @@ -1074,7 +1080,7 @@ describe('MetaMetricsController', function () { }, }); - assert.deepEqual(traits, { + expect(traits).toStrictEqual({ [MetaMetricsUserTrait.AddressBookEntries]: 3, [MetaMetricsUserTrait.InstallDateExt]: '', [MetaMetricsUserTrait.LedgerConnectionType]: 'web-hid', @@ -1094,7 +1100,6 @@ describe('MetaMetricsController', function () { [MetaMetricsUserTrait.Theme]: 'default', [MetaMetricsUserTrait.TokenDetectionEnabled]: true, [MetaMetricsUserTrait.UseNativeCurrencyAsPrimaryCurrency]: true, - [MetaMetricsUserTrait.DesktopEnabled]: false, [MetaMetricsUserTrait.SecurityProviders]: ['blockaid'], ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) [MetaMetricsUserTrait.MmiExtensionId]: 'testid', @@ -1132,7 +1137,6 @@ describe('MetaMetricsController', function () { theme: 'default', useTokenDetection: true, useNativeCurrencyAsPrimaryCurrency: true, - desktopEnabled: false, }); const updatedTraits = metaMetricsController._buildUserTraitsObject({ @@ -1163,10 +1167,9 @@ describe('MetaMetricsController', function () { theme: 'default', useTokenDetection: true, useNativeCurrencyAsPrimaryCurrency: false, - desktopEnabled: false, }); - assert.deepEqual(updatedTraits, { + expect(updatedTraits).toStrictEqual({ [MetaMetricsUserTrait.AddressBookEntries]: 4, [MetaMetricsUserTrait.NumberOfAccounts]: 3, [MetaMetricsUserTrait.NumberOfTokens]: 1, @@ -1200,7 +1203,6 @@ describe('MetaMetricsController', function () { theme: 'default', useTokenDetection: true, useNativeCurrencyAsPrimaryCurrency: true, - desktopEnabled: false, }); const updatedTraits = metaMetricsController._buildUserTraitsObject({ @@ -1226,10 +1228,8 @@ describe('MetaMetricsController', function () { theme: 'default', useTokenDetection: true, useNativeCurrencyAsPrimaryCurrency: true, - desktopEnabled: false, }); - - assert.equal(updatedTraits, null); + expect(updatedTraits).toStrictEqual(null); }); }); @@ -1238,7 +1238,7 @@ describe('MetaMetricsController', function () { const metaMetricsController = getMetaMetricsController({}); metaMetricsController.trackPage({}, { isOptIn: true }); const { segmentApiCalls } = metaMetricsController.store.getState(); - assert(Object.keys(segmentApiCalls).length > 0); + expect(Object.keys(segmentApiCalls).length > 0).toStrictEqual(true); }); it('should remove event from store when callback is invoked', function () { @@ -1246,22 +1246,22 @@ describe('MetaMetricsController', function () { const stubFn = (_, cb) => { cb(); }; - sinon.stub(segmentInstance, 'track').callsFake(stubFn); - sinon.stub(segmentInstance, 'page').callsFake(stubFn); + jest.spyOn(segmentInstance, 'track').mockImplementation(stubFn); + jest.spyOn(segmentInstance, 'page').mockImplementation(stubFn); const metaMetricsController = getMetaMetricsController({ segmentInstance, }); metaMetricsController.trackPage({}, { isOptIn: true }); const { segmentApiCalls } = metaMetricsController.store.getState(); - assert(Object.keys(segmentApiCalls).length === 0); + expect(Object.keys(segmentApiCalls).length === 0).toStrictEqual(true); }); }); afterEach(function () { // flush the queues manually after each test segment.flush(); - clock.restore(); - sinon.restore(); + jest.useRealTimers(); + jest.restoreAllMocks(); }); }); diff --git a/app/scripts/controllers/mmi-controller.test.ts b/app/scripts/controllers/mmi-controller.test.ts index d47802de4536..102cd63d52f3 100644 --- a/app/scripts/controllers/mmi-controller.test.ts +++ b/app/scripts/controllers/mmi-controller.test.ts @@ -7,31 +7,29 @@ import { } from '@metamask-institutional/custody-keyring'; import { TransactionUpdateController } from '@metamask-institutional/transaction-update'; import { SignatureController } from '@metamask/signature-controller'; - import { NetworkController } from '@metamask/network-controller'; import { AccountsController } from '@metamask/accounts-controller'; -import { EthAccountType, EthMethod } from '@metamask/keyring-api'; - +import { EthAccountType } from '@metamask/keyring-api'; import { CustodyController } from '@metamask-institutional/custody-controller'; +import * as PortfolioDashboard from '@metamask-institutional/portfolio-dashboard'; import { CHAIN_IDS, NETWORK_TYPES, TEST_NETWORK_TICKER_MAP, } from '../../../shared/constants/network'; - import MMIController from './mmi-controller'; import AppStateController from './app-state'; import { ControllerMessenger } from '@metamask/base-controller'; import { mmiKeyringBuilderFactory } from '../mmi-keyring-builder-factory'; import MetaMetricsController from './metametrics'; +import { ETH_EOA_METHODS } from '../../../shared/constants/eth-methods'; jest.mock('@metamask-institutional/portfolio-dashboard', () => ({ handleMmiPortfolio: jest.fn(), })); -import * as PortfolioDashboard from '@metamask-institutional/portfolio-dashboard'; - jest.mock('./permissions', () => ({ + ...jest.requireActual('./permissions'), getPermissionBackgroundApiMethods: jest.fn().mockImplementation(() => { return { addPermittedAccount: jest.fn(), @@ -49,7 +47,7 @@ const mockAccount = { }, }, options: {}, - methods: [...Object.values(EthMethod)], + methods: ETH_EOA_METHODS, type: EthAccountType.Eoa, }; const mockAccount2 = { @@ -62,7 +60,7 @@ const mockAccount2 = { }, }, options: {}, - methods: [...Object.values(EthMethod)], + methods: ETH_EOA_METHODS, type: EthAccountType.Eoa, }; @@ -77,7 +75,6 @@ describe('MMIController', function () { keyringController, metaMetricsController, custodyController; - let handleMmiPortfolioSpy, controllerMessengerSpy; beforeEach(async function () { const mockMessenger = { @@ -201,10 +198,10 @@ describe('MMIController', function () { initState: { custodyAccountDetails: { [mockAccount.address]: { - custodyType: 'Custody - Jupiter', + custodyType: 'Custody - ECA3', }, [mockAccount2.address]: { - custodyType: 'Custody - Jupiter', + custodyType: 'Custody - ECA3', }, }, }, @@ -245,7 +242,6 @@ describe('MMIController', function () { }), isEthSignEnabled: jest.fn(), getAllState: jest.fn(), - securityProviderRequest: jest.fn(), getCurrentChainId: jest.fn(), }), appStateController: new AppStateController({ @@ -279,6 +275,10 @@ describe('MMIController', function () { extension: { runtime: { id: 'mock-extension-id' } }, }); + mmiController.getState = jest.fn(); + mmiController.captureException = jest.fn(); + mmiController.accountTracker = { syncWithAddresses: jest.fn() }; + jest.spyOn(metaMetricsController.store, 'getState').mockReturnValue({ metaMetricsId: mockMetaMetricsId, }); @@ -288,69 +288,397 @@ describe('MMIController', function () { jest.clearAllMocks(); }); - describe('mmiController constructor', function () { - it('should instantiate correctly', function () { - expect(mmiController).toBeInstanceOf(MMIController); + describe('addKeyringIfNotExists', () => { + it('should add a new keyring if it does not exist', async () => { + const type = 'mock-keyring-type'; + mmiController.keyringController.getKeyringsByType = jest + .fn() + .mockReturnValue([]); + mmiController.keyringController.addNewKeyring = jest + .fn() + .mockResolvedValue('new-keyring'); + + const result = await mmiController.addKeyringIfNotExists(type); + + expect( + mmiController.keyringController.getKeyringsByType, + ).toHaveBeenCalledWith(type); + expect( + mmiController.keyringController.addNewKeyring, + ).toHaveBeenCalledWith(type); + expect(result).toBe('new-keyring'); }); - it('should have all required properties', function () { - expect(mmiController.opts).toBeDefined(); - expect(mmiController.mmiConfigurationController).toBeDefined(); - expect(mmiController.transactionUpdateController).toBeDefined(); + it('should return existing keyring if it exists', async () => { + const type = 'mock-keyring-type'; + const existingKeyring = 'existing-keyring'; + mmiController.keyringController.getKeyringsByType = jest + .fn() + .mockReturnValue([existingKeyring]); + mmiController.keyringController.addNewKeyring = jest.fn(); + + const result = await mmiController.addKeyringIfNotExists(type); + + expect( + mmiController.keyringController.getKeyringsByType, + ).toHaveBeenCalledWith(type); + expect( + mmiController.keyringController.addNewKeyring, + ).not.toHaveBeenCalled(); + expect(result).toBe(existingKeyring); }); }); - describe('persistKeyringsAfterRefreshTokenChange', function () { - it('should call keyringController.persistAllKeyrings', async function () { - mmiController.keyringController.persistAllKeyrings = jest.fn(); + describe('onSubmitPassword', () => { + it('should add keyrings and handle refresh tokens and events', async () => { + mmiController.custodyController.getAllCustodyTypes = jest + .fn() + .mockReturnValue(['mock-custody-type']); + mmiController.addKeyringIfNotExists = jest.fn().mockResolvedValue({ + on: jest.fn(), + getAccounts: jest.fn().mockResolvedValue(['0x1']), + getSupportedChains: jest.fn().mockResolvedValue({}), + }); + mmiController.storeCustodianSupportedChains = jest.fn(); + mmiController.txStateManager = { + getTransactions: jest.fn().mockReturnValue([]), + }; + mmiController.transactionUpdateController.subscribeToEvents = jest.fn(); + mmiController.mmiConfigurationController.storeConfiguration = jest.fn(); + mmiController.transactionUpdateController.getCustomerProofForAddresses = + jest.fn(); + + await mmiController.onSubmitPassword(); + + expect(mmiController.addKeyringIfNotExists).toHaveBeenCalled(); + expect(mmiController.storeCustodianSupportedChains).toHaveBeenCalled(); + expect( + mmiController.transactionUpdateController.subscribeToEvents, + ).toHaveBeenCalled(); + expect( + mmiController.mmiConfigurationController.storeConfiguration, + ).toHaveBeenCalled(); + }); + }); - await mmiController.persistKeyringsAfterRefreshTokenChange(); + describe('connectCustodyAddresses', () => { + it('should connect new addresses to custodian', async () => { + const custodianType = 'mock-custodian-type'; + const custodianName = 'mock-custodian-name'; + const accounts = { + '0x1': { + name: 'Account 1', + custodianDetails: {}, + labels: [], + token: 'token', + chainId: 1, + }, + }; + CUSTODIAN_TYPES['MOCK-CUSTODIAN-TYPE'] = { + keyringClass: { type: 'mock-keyring-class' }, + }; + mmiController.addKeyringIfNotExists = jest.fn().mockResolvedValue({ + on: jest.fn(), + setSelectedAddresses: jest.fn(), + addAccounts: jest.fn(), + addNewAccountForKeyring: jest.fn(), + getStatusMap: jest.fn(), + }); + mmiController.keyringController.getAccounts = jest + .fn() + .mockResolvedValue(['0x2']); + mmiController.keyringController.addNewAccountForKeyring = jest.fn(); + + mmiController.custodyController.setAccountDetails = jest.fn(); + mmiController.accountTracker.syncWithAddresses = jest.fn(); + mmiController.storeCustodianSupportedChains = jest.fn(); + mmiController.custodyController.storeCustodyStatusMap = jest.fn(); + const result = await mmiController.connectCustodyAddresses( + custodianType, + custodianName, + accounts, + ); + + expect(mmiController.addKeyringIfNotExists).toHaveBeenCalled(); + expect(mmiController.keyringController.getAccounts).toHaveBeenCalled(); + expect( + mmiController.custodyController.setAccountDetails, + ).toHaveBeenCalled(); + expect(mmiController.accountTracker.syncWithAddresses).toHaveBeenCalled(); + expect(mmiController.storeCustodianSupportedChains).toHaveBeenCalled(); expect( - mmiController.keyringController.persistAllKeyrings, + mmiController.custodyController.storeCustodyStatusMap, ).toHaveBeenCalled(); + expect(result).toEqual(['0x1']); }); }); - describe('trackTransactionEventFromCustodianEvent', function () { - it('should call trackTransactionEvents', function () { - const event = 'event'; + describe('getCustodianAccounts', () => { + it('should return custodian accounts', async () => { + CUSTODIAN_TYPES['MOCK-CUSTODIAN-TYPE'] = { + keyringClass: { type: 'mock-keyring-class' }, + }; + mmiController.addKeyringIfNotExists = jest.fn().mockResolvedValue({ + getCustodianAccounts: jest.fn().mockResolvedValue(['account1']), + }); + + const result = await mmiController.getCustodianAccounts( + 'token', + 'neptune-custody', + 'ECA3', + true, + ); - mmiController.trackTransactionEventFromCustodianEvent({}, event); + expect(result).toEqual(['account1']); + }); - expect(mmiController.trackTransactionEvents).toHaveBeenCalledWith( - { - transactionMeta: {}, - }, - event, + it('should return custodian accounts when custodianType is not provided', async () => { + CUSTODIAN_TYPES['CUSTODIAN-TYPE'] = { + keyringClass: { type: 'mock-keyring-class' }, + }; + mmiController.messenger.call = jest + .fn() + .mockReturnValue({ address: '0x1' }); + mmiController.custodyController.getCustodyTypeByAddress = jest + .fn() + .mockReturnValue('custodian-type'); + mmiController.addKeyringIfNotExists = jest.fn().mockResolvedValue({ + getCustodianAccounts: jest.fn().mockResolvedValue(['account1']), + }); + + const result = await mmiController.getCustodianAccounts( + 'token', + 'neptune-custody', ); + + expect(result).toEqual(['account1']); }); }); - describe('custodianEventHandlerFactory', function () { - it('should call custodianEventHandlerFactory', async function () { - mmiController.custodianEventHandlerFactory = jest.fn(); + describe('getCustodianAccountsByAddress', () => { + it('should return custodian accounts by address', async () => { + CUSTODIAN_TYPES['MOCK-CUSTODIAN-TYPE'] = { + keyringClass: { type: 'mock-keyring-class' }, + }; + mmiController.addKeyringIfNotExists = jest.fn().mockResolvedValue({ + getCustodianAccounts: jest.fn().mockResolvedValue(['account1']), + }); + + const result = await mmiController.getCustodianAccountsByAddress( + 'token', + 'envName', + 'address', + 'mock-custodian-type', + ); + + expect(result).toEqual(['account1']); + }); + }); - mmiController.custodianEventHandlerFactory(); + describe('getCustodianTransactionDeepLink', () => { + it('should return a transaction deep link', async () => { + mmiController.custodyController.getCustodyTypeByAddress = jest + .fn() + .mockReturnValue('custodyType'); + mmiController.addKeyringIfNotExists = jest.fn().mockResolvedValue({ + getTransactionDeepLink: jest + .fn() + .mockResolvedValue('transactionDeepLink'), + }); + + const result = await mmiController.getCustodianTransactionDeepLink( + 'address', + 'txId', + ); - expect(mmiController.custodianEventHandlerFactory).toHaveBeenCalled(); + expect(result).toEqual('transactionDeepLink'); }); }); - describe('storeCustodianSupportedChains', function () { - it('should call storeCustodianSupportedChains', async function () { - mmiController.storeCustodianSupportedChains = jest.fn(); + describe('getCustodianConfirmDeepLink', () => { + it('should return a confirmation deep link', async () => { + mmiController.txStateManager = { + getTransactions: jest.fn().mockReturnValue([ + { + id: 'txId', + txParams: { from: '0x1' }, + custodyId: 'custodyId', + }, + ]), + }; + mmiController.custodyController.getCustodyTypeByAddress = jest + .fn() + .mockReturnValue('custodyType'); + mmiController.addKeyringIfNotExists = jest.fn().mockResolvedValue({ + getTransactionDeepLink: jest + .fn() + .mockResolvedValue('transactionDeepLink'), + }); + + const result = await mmiController.getCustodianConfirmDeepLink('txId'); + + expect(result).toEqual({ + deepLink: 'transactionDeepLink', + custodyId: 'custodyId', + }); + }); + }); - mmiController.storeCustodianSupportedChains('0x1'); + describe('getCustodianSignMessageDeepLink', () => { + it('should return a sign message deep link', async () => { + mmiController.custodyController.getCustodyTypeByAddress = jest + .fn() + .mockReturnValue('custodyType'); + mmiController.addKeyringIfNotExists = jest.fn().mockResolvedValue({ + getTransactionDeepLink: jest + .fn() + .mockResolvedValue('transactionDeepLink'), + }); + + const result = await mmiController.getCustodianSignMessageDeepLink( + 'address', + 'custodyTxId', + ); - expect(mmiController.storeCustodianSupportedChains).toHaveBeenCalledWith( - '0x1', + expect(result).toEqual('transactionDeepLink'); + }); + }); + + describe('getCustodianToken', () => { + it('should return a custodian token', async () => { + mmiController.keyringController.getKeyringForAccount = jest + .fn() + .mockResolvedValue({ + getAccountDetails: jest.fn().mockReturnValue({ + authDetails: { jwt: 'jwtToken' }, + }), + }); + + const result = await mmiController.getCustodianToken('address'); + + expect(result).toEqual('jwtToken'); + }); + + it('should return an empty string if authDetails are undefined', async () => { + mmiController.keyringController.getKeyringForAccount = jest + .fn() + .mockResolvedValue({ + getAccountDetails: jest.fn().mockReturnValue({}), + }); + + const result = await mmiController.getCustodianToken('address'); + + expect(result).toEqual(''); + }); + }); + + describe('getCustodianJWTList', () => { + it('should return a list of JWTs for a custodian', async () => { + mmiController.custodyController.getAccountDetails = jest + .fn() + .mockReturnValue({}); + mmiController.messenger.call = jest + .fn() + .mockReturnValue([mockAccount, mockAccount2]); + mmiController.mmiConfigurationController.store.getState = jest + .fn() + .mockReturnValue({ + mmiConfiguration: { + custodians: [{ envName: 'custodianEnvName', type: 'ECA3' }], + }, + }); + mmiController.keyringController.getKeyringsByType = jest + .fn() + .mockReturnValue([ + { + getAccountDetails: jest.fn().mockReturnValue({ + authDetails: { jwt: 'jwtToken' }, + }), + }, + ]); + + const result = await mmiController.getCustodianJWTList( + 'custodianEnvName', ); + + expect(result).toEqual([]); }); }); describe('getAllCustodianAccountsWithToken', () => { - it('should return custodian accounts with tokens', async () => {}); + it('should return all custodian accounts with a token', async () => { + mmiController.keyringController.getKeyringsByType = jest + .fn() + .mockReturnValue([ + { + getAllAccountsWithToken: jest.fn().mockReturnValue(['account1']), + }, + ]); + + const result = await mmiController.getAllCustodianAccountsWithToken( + 'custodyType', + 'token', + ); + + expect(result).toEqual(['account1']); + }); + }); + + describe('setCustodianNewRefreshToken', () => { + it('should set a new refresh token for a custodian account', async () => { + mmiController.custodyController.getCustodyTypeByAddress = jest + .fn() + .mockReturnValue('custodyType'); + const keyringMock = { + replaceRefreshTokenAuthDetails: jest.fn(), + }; + mmiController.addKeyringIfNotExists = jest + .fn() + .mockResolvedValue(keyringMock); + + await mmiController.setCustodianNewRefreshToken({ + address: 'address', + refreshToken: 'refreshToken', + }); + + expect(keyringMock.replaceRefreshTokenAuthDetails).toHaveBeenCalledWith( + 'address', + 'refreshToken', + ); + }); + }); + + describe('handleMmiCheckIfTokenIsPresent', () => { + it('should check if a token is present', async () => { + mmiController.messenger.call = jest + .fn() + .mockReturnValue({ address: '0x1' }); + mmiController.custodyController.getCustodyTypeByAddress = jest + .fn() + .mockReturnValue('custodyType'); + mmiController.addKeyringIfNotExists = jest + .fn() + .mockResolvedValue('keyring'); + mmiController.appStateController.getUnlockPromise = jest.fn(); + mmiController.custodyController.handleMmiCheckIfTokenIsPresent = + jest.fn(); + + await mmiController.handleMmiCheckIfTokenIsPresent({ + params: { + token: 'token', + envName: 'envName', + address: 'address', + }, + }); + + expect( + mmiController.appStateController.getUnlockPromise, + ).toHaveBeenCalled(); + expect( + mmiController.custodyController.handleMmiCheckIfTokenIsPresent, + ).toHaveBeenCalled(); + }); }); describe('handleMmiDashboardData', () => { @@ -380,23 +708,58 @@ describe('MMIController', function () { }); }); - describe('getCustodianJWTList', () => { - it('should call the controller messenger to get internalAccounts', async () => { - const controllerMessengerSpy = jest.spyOn(controllerMessenger, 'call'); - await mmiController.getCustodianJWTList(); + describe('newUnsignedMessage', () => { + it('should create a new unsigned message', async () => { + mmiController.custodyController.getAccountDetails = jest + .fn() + .mockReturnValue({}); - expect(controllerMessengerSpy).toHaveBeenCalledWith( - 'AccountsController:listAccounts', + const message = { from: '0x1' }; + const request = { method: 'eth_signTypedData' }; + + mmiController.signatureController.newUnsignedTypedMessage = jest + .fn() + .mockResolvedValue('unsignedTypedMessage'); + + const result = await mmiController.newUnsignedMessage( + message, + request, + 'v4', ); - expect(controllerMessengerSpy).toHaveReturnedWith([ - mockAccount, - mockAccount2, - ]); + expect(result).toEqual('unsignedTypedMessage'); }); }); - describe('setAccountAndNetwork', function () { + describe('handleSigningEvents', () => { + it('should handle signing events', async () => { + mmiController.transactionUpdateController.addTransactionToWatchList = jest + .fn() + .mockResolvedValue('added'); + mmiController.signatureController.setMessageMetadata = jest.fn(); + + const signature = { + custodian_transactionId: 'custodianTxId', + from: '0x1', + }; + const messageId = 'messageId'; + + await mmiController.handleSigningEvents( + signature, + messageId, + 'signOperation', + ); + + expect( + mmiController.transactionUpdateController.addTransactionToWatchList, + ).toHaveBeenCalledWith('custodianTxId', '0x1', 'signOperation', true); + expect( + mmiController.signatureController.setMessageMetadata, + ).toHaveBeenCalledWith(messageId, signature); + }); + }); + + describe('setAccountAndNetwork', () => { it('should set a new selected account if the selectedAddress and the address from the arguments is different', async () => { const selectedAccountSpy = jest.spyOn(controllerMessenger, 'call'); await mmiController.setAccountAndNetwork( @@ -422,48 +785,26 @@ describe('MMIController', function () { mockAccount.address, '0x1', ); - // only getSelectedAccount + expect(selectedAccountSpy).toHaveBeenCalledTimes(1); const selectedAccount = accountsController.getSelectedAccount(); expect(selectedAccount.id).toBe(mockAccount.id); }); }); - describe('getCustodianAccounts', () => { - const mockCustodialKeyring = jest.fn(); - it('returns custodian accounts', async () => { - const selectedAccountSpy = jest.spyOn(controllerMessenger, 'call'); - const keyringControllerSpy = jest - .spyOn(keyringController, 'addNewKeyring') - .mockReturnValue({ - getCustodianAccounts: mockCustodialKeyring, - }); - - await mmiController.getCustodianAccounts('token', 'mock url', 'JUPITER'); - - expect(selectedAccountSpy).toHaveBeenCalledTimes(0); - - expect(keyringControllerSpy).toHaveBeenCalledWith('Custody - Jupiter'); - expect(mockCustodialKeyring).toHaveBeenCalled(); - }); - - it("returns custodian accounts when custodyType isn't set", async () => { - const selectedAccountSpy = jest.spyOn(controllerMessenger, 'call'); - const keyringControllerSpy = jest - .spyOn(keyringController, 'addNewKeyring') - .mockReturnValue({ - getCustodianAccounts: mockCustodialKeyring, - }); + describe('handleMmiOpenAddHardwareWallet', () => { + it('should open add hardware wallet interface', async () => { + mmiController.appStateController.getUnlockPromise = jest.fn(); + mmiController.platform = { openExtensionInBrowser: jest.fn() }; - await mmiController.getCustodianAccounts('token', 'mock url'); + await mmiController.handleMmiOpenAddHardwareWallet(); - expect(selectedAccountSpy).toHaveBeenCalledWith( - 'AccountsController:getSelectedAccount', - ); - expect(selectedAccountSpy).toHaveReturnedWith(mockAccount); - - expect(keyringControllerSpy).toHaveBeenCalledWith('Custody - Jupiter'); - expect(mockCustodialKeyring).toHaveBeenCalled(); + expect( + mmiController.appStateController.getUnlockPromise, + ).toHaveBeenCalled(); + expect( + mmiController.platform.openExtensionInBrowser, + ).toHaveBeenCalledWith('/new-account/connect'); }); }); }); diff --git a/app/scripts/controllers/mmi-controller.ts b/app/scripts/controllers/mmi-controller.ts index b2d66f36afdf..755cab0f8fbf 100644 --- a/app/scripts/controllers/mmi-controller.ts +++ b/app/scripts/controllers/mmi-controller.ts @@ -35,12 +35,13 @@ import { IInteractiveRefreshTokenChangeEvent, Label, Signature, + ConnectionRequest, } from '../../../shared/constants/mmi-controller'; import AccountTracker from '../lib/account-tracker'; -import AppStateController from './app-state'; import MetaMetricsController from './metametrics'; import { getPermissionBackgroundApiMethods } from './permissions'; import { PreferencesController } from './preferences'; +import { AppStateController } from './app-state'; type UpdateCustodianTransactionsParameters = { keyring: CustodyKeyring; @@ -48,6 +49,8 @@ type UpdateCustodianTransactionsParameters = { txList: string[]; custodyController: CustodyController; transactionUpdateController: TransactionUpdateController; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any txStateManager: any; getPendingNonce: (address: string) => Promise; setTxHash: (txId: string, txHash: string) => void; @@ -58,6 +61,8 @@ export default class MMIController extends EventEmitter { public mmiConfigurationController: MmiConfigurationController; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any public keyringController: any; public preferencesController: PreferencesController; @@ -68,8 +73,12 @@ export default class MMIController extends EventEmitter { private custodyController: CustodyController; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any private getState: () => any; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any private getPendingNonce: (address: string) => Promise; private accountTracker: AccountTracker; @@ -78,28 +87,46 @@ export default class MMIController extends EventEmitter { private networkController: NetworkController; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any private permissionController: any; private signatureController: SignatureController; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any private messenger: any; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any private platform: any; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any private extension: any; private updateTransactionHash: (txId: string, txHash: string) => void; + private setChannelId: (channelId: string) => void; + + private setConnectionRequest: (payload: ConnectionRequest | null) => void; + public trackTransactionEvents: ( args: { transactionMeta: TransactionMeta }, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any event: any, ) => void; private txStateManager: { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any getTransactions: (query?: any, opts?: any, fullTx?: boolean) => any[]; setTxStatusSigned: (txId: string) => void; setTxStatusSubmitted: (txId: string) => void; setTxStatusFailed: (txId: string) => void; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any updateTransaction: (txMeta: any) => void; }; @@ -125,6 +152,8 @@ export default class MMIController extends EventEmitter { this.extension = opts.extension; this.updateTransactionHash = opts.updateTransactionHash; + this.setChannelId = opts.setChannelId; + this.setConnectionRequest = opts.setConnectionRequest; this.trackTransactionEvents = opts.trackTransactionEvents; this.txStateManager = { @@ -163,6 +192,20 @@ export default class MMIController extends EventEmitter { await this.handleSigningEvents(signature, messageId, 'v4'); }, ); + + this.transactionUpdateController.on( + 'handshake', + async ({ channelId }: { channelId: string }) => { + this.setChannelId(channelId); + }, + ); + + this.transactionUpdateController.on( + 'connection.request', + async (payload: ConnectionRequest) => { + this.setConnectionRequest(payload); + }, + ); } // End of constructor async persistKeyringsAfterRefreshTokenChange() { @@ -171,6 +214,8 @@ export default class MMIController extends EventEmitter { async trackTransactionEventFromCustodianEvent( txMeta: TransactionMeta, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any event: any, ) { // transactionMetricsRequest parameter is already bound in the constructor @@ -322,6 +367,8 @@ export default class MMIController extends EventEmitter { string, { name: string; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any custodianDetails: any; labels: Label[]; token: string; @@ -594,7 +641,9 @@ export default class MMIController extends EventEmitter { async getCustodianToken(address: string) { const keyring = await this.keyringController.getKeyringForAccount(address); const { authDetails } = keyring.getAccountDetails(address); - return keyring ? authDetails.jwt || authDetails.refreshToken : ''; + return keyring + ? (authDetails && (authDetails.jwt || authDetails.refreshToken)) || '' + : ''; } // Based on a custodian name, get all the tokens associated with that custodian diff --git a/app/scripts/controllers/onboarding.js b/app/scripts/controllers/onboarding.js deleted file mode 100644 index b52a9b87e7f9..000000000000 --- a/app/scripts/controllers/onboarding.js +++ /dev/null @@ -1,85 +0,0 @@ -import { ObservableStore } from '@metamask/obs-store'; -import log from 'loglevel'; - -/** - * @typedef {object} InitState - * @property {boolean} seedPhraseBackedUp Indicates whether the user has completed the seed phrase backup challenge - * @property {boolean} completedOnboarding Indicates whether the user has completed the onboarding flow - */ - -/** - * @typedef {object} OnboardingOptions - * @property {InitState} initState The initial controller state - */ - -/** - * Controller responsible for maintaining - * state related to onboarding - */ -export default class OnboardingController { - /** - * Creates a new controller instance - * - * @param {OnboardingOptions} [opts] - Controller configuration parameters - */ - constructor(opts = {}) { - const initialTransientState = { - onboardingTabs: {}, - }; - const initState = { - seedPhraseBackedUp: null, - firstTimeFlowType: null, - completedOnboarding: false, - ...opts.initState, - ...initialTransientState, - }; - this.store = new ObservableStore(initState); - } - - setSeedPhraseBackedUp(newSeedPhraseBackUpState) { - this.store.updateState({ - seedPhraseBackedUp: newSeedPhraseBackUpState, - }); - } - - // /** - // * Sets the completedOnboarding state to true, indicating that the user has completed the - // * onboarding process. - // */ - async completeOnboarding() { - this.store.updateState({ - completedOnboarding: true, - }); - return true; - } - - /** - * Setter for the `firstTimeFlowType` property - * - * @param {string} type - Indicates the type of first time flow - create or import - the user wishes to follow - */ - setFirstTimeFlowType(type) { - this.store.updateState({ firstTimeFlowType: type }); - } - - /** - * Registering a site as having initiated onboarding - * - * @param {string} location - The location of the site registering - * @param {string} tabId - The id of the tab registering - */ - registerOnboarding = async (location, tabId) => { - if (this.store.getState().completedOnboarding) { - log.debug('Ignoring registerOnboarding; user already onboarded'); - return; - } - const onboardingTabs = { ...this.store.getState().onboardingTabs }; - if (!onboardingTabs[location] || onboardingTabs[location] !== tabId) { - log.debug( - `Registering onboarding tab at location '${location}' with tabId '${tabId}'`, - ); - onboardingTabs[location] = tabId; - this.store.updateState({ onboardingTabs }); - } - }; -} diff --git a/app/scripts/controllers/onboarding.test.ts b/app/scripts/controllers/onboarding.test.ts new file mode 100644 index 000000000000..61b9cf8de589 --- /dev/null +++ b/app/scripts/controllers/onboarding.test.ts @@ -0,0 +1,57 @@ +import { FirstTimeFlowType } from '../../../shared/constants/onboarding'; +import OnboardingController, { OnboardingControllerState } from './onboarding'; + +describe('OnboardingController', () => { + let onboardingController: OnboardingController; + + beforeEach(() => { + onboardingController = new OnboardingController({ + initState: { + seedPhraseBackedUp: null, + firstTimeFlowType: null, + completedOnboarding: false, + onboardingTabs: {}, + }, + }); + }); + + it('should set the seedPhraseBackedUp property', () => { + const newSeedPhraseBackUpState = true; + onboardingController.setSeedPhraseBackedUp(newSeedPhraseBackUpState); + const state: OnboardingControllerState = + onboardingController.store.getState(); + expect(state.seedPhraseBackedUp).toBe(newSeedPhraseBackUpState); + }); + + it('should set the firstTimeFlowType property', () => { + const type: FirstTimeFlowType = FirstTimeFlowType.create; + onboardingController.setFirstTimeFlowType(type); + const state: OnboardingControllerState = + onboardingController.store.getState(); + expect(state.firstTimeFlowType).toBe(type); + }); + + it('should register a site for onboarding', async () => { + const location = 'example.com'; + const tabId = '123'; + await onboardingController.registerOnboarding(location, tabId); + const state: OnboardingControllerState = + onboardingController.store.getState(); + expect(state.onboardingTabs?.[location]).toBe(tabId); + }); + + it('should skip update state if the location is already onboard', async () => { + const location = 'example.com'; + const tabId = '123'; + await onboardingController.registerOnboarding(location, tabId); + const state: OnboardingControllerState = + onboardingController.store.getState(); + const updateStateSpy = jest.spyOn( + onboardingController.store, + 'updateState', + ); + + expect(state.onboardingTabs?.[location]).toBe(tabId); + expect(updateStateSpy).not.toHaveBeenCalled(); + }); +}); diff --git a/app/scripts/controllers/onboarding.ts b/app/scripts/controllers/onboarding.ts new file mode 100644 index 000000000000..f64172b35ec8 --- /dev/null +++ b/app/scripts/controllers/onboarding.ts @@ -0,0 +1,112 @@ +import { ObservableStore } from '@metamask/obs-store'; +import log from 'loglevel'; +import { FirstTimeFlowType } from '../../../shared/constants/onboarding'; + +/** + * The state of the OnboardingController + */ +export type OnboardingControllerState = { + seedPhraseBackedUp: boolean | null; + firstTimeFlowType: FirstTimeFlowType | null; + completedOnboarding: boolean; + onboardingTabs?: Record; +}; + +const defaultTransientState = { + onboardingTabs: {}, +} satisfies Pick; + +const defaultState = { + seedPhraseBackedUp: null, + firstTimeFlowType: null, + completedOnboarding: false, +} satisfies OnboardingControllerState; + +/** + * Controller responsible for maintaining + * state related to onboarding + */ +export default class OnboardingController { + /** + * Observable store containing controller data. + */ + store: ObservableStore; + + /** + * Constructs a Onboarding controller. + * + * @param options - the controller options + * @param options.initState - Initial controller state. + */ + constructor({ + initState, + }: { + initState: Partial; + }) { + this.store = new ObservableStore({ + ...defaultState, + ...initState, + ...defaultTransientState, + }); + } + + /** + * Setter for the `seedPhraseBackedUp` property + * + * @param newSeedPhraseBackUpState - Indicates if the seedphrase is backup by the user or not + */ + setSeedPhraseBackedUp(newSeedPhraseBackUpState: boolean): void { + this.store.updateState({ + seedPhraseBackedUp: newSeedPhraseBackUpState, + }); + } + + /** + * Sets the completedOnboarding state to true, indicating that the user has completed the + * onboarding process. + */ + async completeOnboarding(): Promise { + this.store.updateState({ + completedOnboarding: true, + }); + return true; + } + + /** + * Setter for the `firstTimeFlowType` property + * + * @param type - Indicates the type of first time flow - create or import - the user wishes to follow + */ + setFirstTimeFlowType(type: FirstTimeFlowType): void { + this.store.updateState({ firstTimeFlowType: type }); + } + + /** + * Registering a site as having initiated onboarding + * + * @param location - The location of the site registering + * @param tabId - The id of the tab registering + */ + registerOnboarding = async ( + location: string, + tabId: string, + ): Promise => { + if (this.store.getState().completedOnboarding) { + log.debug('Ignoring registerOnboarding; user already onboarded'); + return; + } + const { onboardingTabs } = { ...(this.store.getState() ?? {}) }; + + if (!onboardingTabs) { + return; + } + + if (!onboardingTabs[location] || onboardingTabs[location] !== tabId) { + log.debug( + `Registering onboarding tab at location '${location}' with tabId '${tabId}'`, + ); + onboardingTabs[location] = tabId; + this.store.updateState({ onboardingTabs }); + } + }; +} diff --git a/app/scripts/controllers/permissions/background-api.js b/app/scripts/controllers/permissions/background-api.js index fe5ee6c755b1..d3a29f129379 100644 --- a/app/scripts/controllers/permissions/background-api.js +++ b/app/scripts/controllers/permissions/background-api.js @@ -3,59 +3,45 @@ import { CaveatTypes, RestrictedMethods, } from '../../../../shared/constants/permissions'; +import { CaveatFactories } from './specifications'; export function getPermissionBackgroundApiMethods(permissionController) { - return { - addPermittedAccount: (origin, account) => { - const existing = permissionController.getCaveat( - origin, - RestrictedMethods.eth_accounts, - CaveatTypes.restrictReturnedAccounts, - ); + const addMoreAccounts = (origin, accountOrAccounts) => { + const accounts = Array.isArray(accountOrAccounts) + ? accountOrAccounts + : [accountOrAccounts]; + const caveat = CaveatFactories.restrictReturnedAccounts(accounts); - if (existing.value.includes(account)) { - return; - } + permissionController.grantPermissionsIncremental({ + subject: { origin }, + approvedPermissions: { + [RestrictedMethods.eth_accounts]: { caveats: [caveat] }, + }, + }); + }; - permissionController.updateCaveat( - origin, - RestrictedMethods.eth_accounts, - CaveatTypes.restrictReturnedAccounts, - [...existing.value, account], - ); - }, + return { + addPermittedAccount: (origin, account) => addMoreAccounts(origin, account), - // To add more than one accounts when already connected to the dapp - addMorePermittedAccounts: (origin, accounts) => { - const existing = permissionController.getCaveat( - origin, - RestrictedMethods.eth_accounts, - CaveatTypes.restrictReturnedAccounts, - ); - // Since this function will be called for unconnected accounts, we dodn't need an extra check - permissionController.updateCaveat( - origin, - RestrictedMethods.eth_accounts, - CaveatTypes.restrictReturnedAccounts, - [...existing.value, ...accounts], - ); - }, + // To add more than one account when already connected to the dapp + addMorePermittedAccounts: (origin, accounts) => + addMoreAccounts(origin, accounts), removePermittedAccount: (origin, account) => { - const existing = permissionController.getCaveat( + const { value: existingAccounts } = permissionController.getCaveat( origin, RestrictedMethods.eth_accounts, CaveatTypes.restrictReturnedAccounts, ); - if (!existing.value.includes(account)) { - return; - } - - const remainingAccounts = existing.value.filter( + const remainingAccounts = existingAccounts.filter( (existingAccount) => existingAccount !== account, ); + if (remainingAccounts.length === existingAccounts.length) { + return; + } + if (remainingAccounts.length === 0) { permissionController.revokePermission( origin, diff --git a/app/scripts/controllers/permissions/background-api.test.js b/app/scripts/controllers/permissions/background-api.test.js index a7f433eb1d25..b6ba493ba7df 100644 --- a/app/scripts/controllers/permissions/background-api.test.js +++ b/app/scripts/controllers/permissions/background-api.test.js @@ -3,56 +3,76 @@ import { RestrictedMethods, } from '../../../../shared/constants/permissions'; import { getPermissionBackgroundApiMethods } from './background-api'; +import { CaveatFactories } from './specifications'; describe('permission background API methods', () => { + const getApprovedPermissions = (accounts) => ({ + [RestrictedMethods.eth_accounts]: { + caveats: [CaveatFactories.restrictReturnedAccounts(accounts)], + }, + }); + describe('addPermittedAccount', () => { - it('adds a permitted account', () => { + it('calls grantPermissionsIncremental with expected parameters', () => { const permissionController = { - getCaveat: jest.fn().mockImplementationOnce(() => { - return { type: CaveatTypes.restrictReturnedAccounts, value: ['0x1'] }; - }), - updateCaveat: jest.fn(), + grantPermissionsIncremental: jest.fn(), }; getPermissionBackgroundApiMethods( permissionController, - ).addPermittedAccount('foo.com', '0x2'); - - expect(permissionController.getCaveat).toHaveBeenCalledTimes(1); - expect(permissionController.getCaveat).toHaveBeenCalledWith( - 'foo.com', - RestrictedMethods.eth_accounts, - CaveatTypes.restrictReturnedAccounts, - ); + ).addPermittedAccount('foo.com', '0x1'); - expect(permissionController.updateCaveat).toHaveBeenCalledTimes(1); - expect(permissionController.updateCaveat).toHaveBeenCalledWith( - 'foo.com', - RestrictedMethods.eth_accounts, - CaveatTypes.restrictReturnedAccounts, - ['0x1', '0x2'], - ); + expect( + permissionController.grantPermissionsIncremental, + ).toHaveBeenCalledTimes(1); + expect( + permissionController.grantPermissionsIncremental, + ).toHaveBeenCalledWith({ + subject: { origin: 'foo.com' }, + approvedPermissions: getApprovedPermissions(['0x1']), + }); }); + }); - it('does not add a permitted account', () => { + describe('addMorePermittedAccounts', () => { + it('calls grantPermissionsIncremental with expected parameters for single account', () => { const permissionController = { - getCaveat: jest.fn().mockImplementationOnce(() => { - return { type: CaveatTypes.restrictReturnedAccounts, value: ['0x1'] }; - }), - updateCaveat: jest.fn(), + grantPermissionsIncremental: jest.fn(), }; getPermissionBackgroundApiMethods( permissionController, - ).addPermittedAccount('foo.com', '0x1'); - expect(permissionController.getCaveat).toHaveBeenCalledTimes(1); - expect(permissionController.getCaveat).toHaveBeenCalledWith( - 'foo.com', - RestrictedMethods.eth_accounts, - CaveatTypes.restrictReturnedAccounts, - ); + ).addMorePermittedAccounts('foo.com', ['0x1']); + + expect( + permissionController.grantPermissionsIncremental, + ).toHaveBeenCalledTimes(1); + expect( + permissionController.grantPermissionsIncremental, + ).toHaveBeenCalledWith({ + subject: { origin: 'foo.com' }, + approvedPermissions: getApprovedPermissions(['0x1']), + }); + }); - expect(permissionController.updateCaveat).not.toHaveBeenCalled(); + it('calls grantPermissionsIncremental with expected parameters with multiple accounts', () => { + const permissionController = { + grantPermissionsIncremental: jest.fn(), + }; + + getPermissionBackgroundApiMethods( + permissionController, + ).addMorePermittedAccounts('foo.com', ['0x1', '0x2']); + + expect( + permissionController.grantPermissionsIncremental, + ).toHaveBeenCalledTimes(1); + expect( + permissionController.grantPermissionsIncremental, + ).toHaveBeenCalledWith({ + subject: { origin: 'foo.com' }, + approvedPermissions: getApprovedPermissions(['0x1', '0x2']), + }); }); }); diff --git a/app/scripts/controllers/permissions/caveat-mutators.js b/app/scripts/controllers/permissions/caveat-mutators.js index 3786b22d925e..d712a681e1e3 100644 --- a/app/scripts/controllers/permissions/caveat-mutators.js +++ b/app/scripts/controllers/permissions/caveat-mutators.js @@ -10,6 +10,9 @@ export const CaveatMutatorFactories = { [CaveatTypes.restrictReturnedAccounts]: { removeAccount, }, + [CaveatTypes.restrictNetworkSwitching]: { + removeChainId, + }, }; /** @@ -39,3 +42,30 @@ function removeAccount(targetAccount, existingAccounts) { } return { operation: CaveatMutatorOperation.revokePermission }; } + +/** + * Removes the target chain ID from the value arrays of all + * `restrictNetworkSwitching` caveats. No-ops if the target chain ID is not in + * the array, and revokes the parent permission if it's the only chain ID in + * the array. + * + * @param {string} targetChainId - The chain ID to remove from + * all network switching permissions. + * @param {string[]} existingChainIds - The chain ID array from the + * network switching permissions. + */ +function removeChainId(targetChainId, existingChainIds) { + const newChainIds = existingChainIds.filter( + (chainId) => chainId !== targetChainId, + ); + + if (newChainIds.length === existingChainIds.length) { + return { operation: CaveatMutatorOperation.noop }; + } else if (newChainIds.length > 0) { + return { + operation: CaveatMutatorOperation.updateValue, + value: newChainIds, + }; + } + return { operation: CaveatMutatorOperation.revokePermission }; +} diff --git a/app/scripts/controllers/permissions/enums.js b/app/scripts/controllers/permissions/enums.js deleted file mode 100644 index 4ede66f22cb9..000000000000 --- a/app/scripts/controllers/permissions/enums.js +++ /dev/null @@ -1,5 +0,0 @@ -export const NOTIFICATION_NAMES = { - accountsChanged: 'metamask_accountsChanged', - unlockStateChanged: 'metamask_unlockStateChanged', - chainChanged: 'metamask_chainChanged', -}; diff --git a/app/scripts/controllers/permissions/enums.ts b/app/scripts/controllers/permissions/enums.ts new file mode 100644 index 000000000000..c170bd78aa67 --- /dev/null +++ b/app/scripts/controllers/permissions/enums.ts @@ -0,0 +1,5 @@ +export enum NOTIFICATION_NAMES { + accountsChanged = 'metamask_accountsChanged', + unlockStateChanged = 'metamask_unlockStateChanged', + chainChanged = 'metamask_chainChanged', +} diff --git a/app/scripts/controllers/permissions/specifications.js b/app/scripts/controllers/permissions/specifications.js index 8d5b8ec8a789..1caacf7d1cfd 100644 --- a/app/scripts/controllers/permissions/specifications.js +++ b/app/scripts/controllers/permissions/specifications.js @@ -1,6 +1,7 @@ import { constructPermission, PermissionType, + SubjectType, } from '@metamask/permission-controller'; ///: BEGIN:ONLY_INCLUDE_IF(snaps) import { @@ -8,6 +9,7 @@ import { endowmentCaveatSpecifications as snapsEndowmentCaveatSpecifications, } from '@metamask/snaps-rpc-methods'; ///: END:ONLY_INCLUDE_IF +import { isValidHexAddress } from '@metamask/utils'; import { CaveatTypes, RestrictedMethods, @@ -23,18 +25,23 @@ import { * The "keys" of all of permissions recognized by the PermissionController. * Permission keys and names have distinct meanings in the permission system. */ -const PermissionNames = Object.freeze({ +export const PermissionNames = Object.freeze({ ...RestrictedMethods, + permittedChains: 'permittedChains', }); /** * Factory functions for all caveat types recognized by the * PermissionController. */ -const CaveatFactories = Object.freeze({ +export const CaveatFactories = Object.freeze({ [CaveatTypes.restrictReturnedAccounts]: (accounts) => { return { type: CaveatTypes.restrictReturnedAccounts, value: accounts }; }, + + [CaveatTypes.restrictNetworkSwitching]: (chainIds) => { + return { type: CaveatTypes.restrictNetworkSwitching, value: chainIds }; + }, }); /** @@ -45,7 +52,10 @@ const CaveatFactories = Object.freeze({ * getInternalAccounts: () => Record, * }} options - Options bag. */ -export const getCaveatSpecifications = ({ getInternalAccounts }) => { +export const getCaveatSpecifications = ({ + getInternalAccounts, + findNetworkClientIdByChainId, +}) => { return { [CaveatTypes.restrictReturnedAccounts]: { type: CaveatTypes.restrictReturnedAccounts, @@ -59,6 +69,17 @@ export const getCaveatSpecifications = ({ getInternalAccounts }) => { validator: (caveat, _origin, _target) => validateCaveatAccounts(caveat.value, getInternalAccounts), + + merger: (leftValue, rightValue) => { + const newValue = Array.from(new Set([...leftValue, ...rightValue])); + const diff = newValue.filter((value) => !leftValue.includes(value)); + return [newValue, diff]; + }, + }, + [CaveatTypes.restrictNetworkSwitching]: { + type: CaveatTypes.restrictNetworkSwitching, + validator: (caveat, _origin, _target) => + validateCaveatNetworks(caveat.value, findNetworkClientIdByChainId), }, ///: BEGIN:ONLY_INCLUDE_IF(snaps) @@ -97,13 +118,14 @@ export const getPermissionSpecifications = ({ allowedCaveats: [CaveatTypes.restrictReturnedAccounts], factory: (permissionOptions, requestData) => { - if (Array.isArray(permissionOptions.caveats)) { - throw new Error( - `${PermissionNames.eth_accounts} error: Received unexpected caveats. Any permitted caveats will be added automatically.`, - ); + // This occurs when we use PermissionController.grantPermissions(). + if (requestData === undefined) { + return constructPermission({ + ...permissionOptions, + }); } - // This value will be further validated as part of the caveat. + // The approved accounts will be further validated as part of the caveat. if (!requestData.approvedAccounts) { throw new Error( `${PermissionNames.eth_accounts} error: No approved accounts specified.`, @@ -119,9 +141,9 @@ export const getPermissionSpecifications = ({ ], }); }, - methodImplementation: async (_args) => { - const accounts = await getAllAccounts(); + // We only consider EVM addresses here, hence the filtering: + const accounts = (await getAllAccounts()).filter(isValidHexAddress); const internalAccounts = getInternalAccounts(); return accounts.sort((firstAddress, secondAddress) => { @@ -168,7 +190,6 @@ export const getPermissionSpecifications = ({ ); }); }, - validator: (permission, _origin, _target) => { const { caveats } = permission; if ( @@ -182,6 +203,43 @@ export const getPermissionSpecifications = ({ } }, }, + + [PermissionNames.permittedChains]: { + permissionType: PermissionType.Endowment, + targetName: PermissionNames.permittedChains, + allowedCaveats: [CaveatTypes.restrictNetworkSwitching], + subjectTypes: [SubjectType.Website], + + factory: (permissionOptions, requestData) => { + if (!requestData.approvedChainIds) { + throw new Error( + `${PermissionNames.permittedChains}: No approved networks specified.`, + ); + } + + return constructPermission({ + ...permissionOptions, + caveats: [ + CaveatFactories[CaveatTypes.restrictNetworkSwitching]( + requestData.approvedChainIds, + ), + ], + }); + }, + endowmentGetter: async (_getterOptions) => undefined, + validator: (permission, _origin, _target) => { + const { caveats } = permission; + if ( + !caveats || + caveats.length !== 1 || + caveats[0].type !== CaveatTypes.restrictNetworkSwitching + ) { + throw new Error( + `${PermissionNames.permittedChains} error: Invalid caveats. There must be a single caveat of type "${CaveatTypes.restrictNetworkSwitching}".`, + ); + } + }, + }, }; }; @@ -222,6 +280,49 @@ function validateCaveatAccounts(accounts, getInternalAccounts) { }); } +/** + * Validates the networks associated with a caveat. Ensures that + * the networks value is an array of valid chain IDs. + * + * @param {string[]} chainIdsForCaveat - The list of chain IDs to validate. + * @param {function(string): string} findNetworkClientIdByChainId - Function to find network client ID by chain ID. + * @throws {Error} If the chainIdsForCaveat is not a non-empty array of valid chain IDs. + */ +function validateCaveatNetworks( + chainIdsForCaveat, + findNetworkClientIdByChainId, +) { + if (!Array.isArray(chainIdsForCaveat) || chainIdsForCaveat.length === 0) { + throw new Error( + `${PermissionNames.permittedChains} error: Expected non-empty array of chainIds.`, + ); + } + + chainIdsForCaveat.forEach((chainId) => { + try { + findNetworkClientIdByChainId(chainId); + } catch (e) { + console.error(e); + throw new Error( + `${PermissionNames.permittedChains} error: Received unrecognized chainId: "${chainId}". Please try adding the network first via wallet_addEthereumChain.`, + ); + } + }); +} + +/** + * Unrestricted methods for Ethereum, see {@link unrestrictedMethods} for more details. + */ +export const unrestrictedEthSigningMethods = Object.freeze([ + 'eth_sendRawTransaction', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', +]); + /** * All unrestricted methods recognized by the PermissionController. * Unrestricted methods are ignored by the permission system, but every @@ -266,6 +367,7 @@ export const unrestrictedMethods = Object.freeze([ 'eth_newFilter', 'eth_newPendingTransactionFilter', 'eth_protocolVersion', + 'eth_requestAccounts', 'eth_sendRawTransaction', 'eth_sendTransaction', 'eth_sign', @@ -275,16 +377,49 @@ export const unrestrictedMethods = Object.freeze([ 'eth_signTypedData_v4', 'eth_submitHashrate', 'eth_submitWork', + 'eth_subscribe', 'eth_syncing', 'eth_uninstallFilter', + 'eth_unsubscribe', 'metamask_getProviderState', + 'metamask_logWeb3ShimUsage', + 'metamask_sendDomainMetadata', 'metamask_watchAsset', 'net_listening', 'net_peerCount', 'net_version', 'personal_ecRecover', 'personal_sign', + 'wallet_addEthereumChain', + 'wallet_getPermissions', + 'wallet_requestPermissions', + 'wallet_revokePermissions', + 'wallet_registerOnboarding', + 'wallet_switchEthereumChain', 'wallet_watchAsset', 'web3_clientVersion', 'web3_sha3', + ///: BEGIN:ONLY_INCLUDE_IF(snaps) + 'wallet_getAllSnaps', + 'wallet_getSnaps', + 'wallet_requestSnaps', + 'wallet_invokeSnap', + 'wallet_invokeKeyring', + 'snap_getClientStatus', + 'snap_getFile', + 'snap_createInterface', + 'snap_updateInterface', + 'snap_getInterfaceState', + ///: END:ONLY_INCLUDE_IF + ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) + 'metamaskinstitutional_authenticate', + 'metamaskinstitutional_reauthenticate', + 'metamaskinstitutional_refresh_token', + 'metamaskinstitutional_supported', + 'metamaskinstitutional_portfolio', + 'metamaskinstitutional_open_swaps', + 'metamaskinstitutional_checkIfTokenIsPresent', + 'metamaskinstitutional_setAccountAndNetwork', + 'metamaskinstitutional_openAddHardwareWallet', + ///: END:ONLY_INCLUDE_IF ]); diff --git a/app/scripts/controllers/permissions/specifications.test.js b/app/scripts/controllers/permissions/specifications.test.js index a90ac4e87e63..29f9f4f1b8ce 100644 --- a/app/scripts/controllers/permissions/specifications.test.js +++ b/app/scripts/controllers/permissions/specifications.test.js @@ -1,10 +1,12 @@ -import { EthMethod, EthAccountType } from '@metamask/keyring-api'; +import { EthAccountType } from '@metamask/keyring-api'; import { SnapCaveatType } from '@metamask/snaps-rpc-methods'; import { CaveatTypes, RestrictedMethods, } from '../../../../shared/constants/permissions'; +import { ETH_EOA_METHODS } from '../../../../shared/constants/eth-methods'; import { + CaveatFactories, getCaveatSpecifications, getPermissionSpecifications, unrestrictedMethods, @@ -17,10 +19,13 @@ describe('PermissionController specifications', () => { describe('caveat specifications', () => { it('getCaveatSpecifications returns the expected specifications object', () => { const caveatSpecifications = getCaveatSpecifications({}); - expect(Object.keys(caveatSpecifications)).toHaveLength(12); + expect(Object.keys(caveatSpecifications)).toHaveLength(13); expect( caveatSpecifications[CaveatTypes.restrictReturnedAccounts].type, ).toStrictEqual(CaveatTypes.restrictReturnedAccounts); + expect( + caveatSpecifications[CaveatTypes.restrictNetworkSwitching].type, + ).toStrictEqual(CaveatTypes.restrictNetworkSwitching); expect(caveatSpecifications.permittedDerivationPaths.type).toStrictEqual( SnapCaveatType.PermittedDerivationPaths, @@ -146,7 +151,7 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [...Object.values(EthMethod)], + methods: ETH_EOA_METHODS, type: EthAccountType.Eoa, }, { @@ -160,7 +165,7 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [...Object.values(EthMethod)], + methods: ETH_EOA_METHODS, type: EthAccountType.Eoa, }, ]; @@ -175,21 +180,103 @@ describe('PermissionController specifications', () => { ); }); }); + + describe('merger', () => { + it.each([ + { + left: [], + right: [], + expected: [[], []], + }, + { + left: ['0x1'], + right: [], + expected: [['0x1'], []], + }, + { + left: [], + right: ['0x1'], + expected: [['0x1'], ['0x1']], + }, + { + left: ['0x1', '0x2'], + right: ['0x1', '0x2'], + expected: [['0x1', '0x2'], []], + }, + { + left: ['0x1', '0x2'], + right: ['0x2', '0x3'], + expected: [['0x1', '0x2', '0x3'], ['0x3']], + }, + { + left: ['0x1', '0x2'], + right: ['0x3', '0x4'], + expected: [ + ['0x1', '0x2', '0x3', '0x4'], + ['0x3', '0x4'], + ], + }, + { + left: [{ a: 1 }, { b: 2 }], + right: [{ a: 1 }], + expected: [[{ a: 1 }, { b: 2 }, { a: 1 }], [{ a: 1 }]], + }, + ])('merges arrays as expected', ({ left, right, expected }) => { + const { merger } = getCaveatSpecifications({})[ + CaveatTypes.restrictReturnedAccounts + ]; + + expect(merger(left, right)).toStrictEqual(expected); + }); + }); }); }); describe('permission specifications', () => { it('getPermissionSpecifications returns the expected specifications object', () => { const permissionSpecifications = getPermissionSpecifications({}); - expect(Object.keys(permissionSpecifications)).toHaveLength(1); + expect(Object.keys(permissionSpecifications)).toHaveLength(2); expect( permissionSpecifications[RestrictedMethods.eth_accounts].targetName, ).toStrictEqual(RestrictedMethods.eth_accounts); + expect(permissionSpecifications.permittedChains.targetName).toStrictEqual( + 'permittedChains', + ); }); describe('eth_accounts', () => { describe('factory', () => { - it('constructs a valid eth_accounts permission', () => { + it('constructs a valid eth_accounts permission, using permissionOptions', () => { + const getInternalAccounts = jest.fn(); + const getAllAccounts = jest.fn(); + const { factory } = getPermissionSpecifications({ + getInternalAccounts, + getAllAccounts, + })[RestrictedMethods.eth_accounts]; + + expect( + factory({ + invoker: 'foo.bar', + target: 'eth_accounts', + caveats: [ + CaveatFactories[CaveatTypes.restrictReturnedAccounts](['0x1']), + ], + }), + ).toStrictEqual({ + caveats: [ + { + type: CaveatTypes.restrictReturnedAccounts, + value: ['0x1'], + }, + ], + date: 1, + id: expect.any(String), + invoker: 'foo.bar', + parentCapability: 'eth_accounts', + }); + }); + + it('constructs a valid eth_accounts permission, using requestData.approvedAccounts', () => { const getInternalAccounts = jest.fn(); const getAllAccounts = jest.fn(); const { factory } = getPermissionSpecifications({ @@ -216,7 +303,7 @@ describe('PermissionController specifications', () => { }); }); - it('throws an error if no approvedAccounts are specified', () => { + it('throws if requestData is defined but approvedAccounts is not specified', () => { const getInternalAccounts = jest.fn(); const getAllAccounts = jest.fn(); const { factory } = getPermissionSpecifications({ @@ -232,7 +319,7 @@ describe('PermissionController specifications', () => { ).toThrow(/No approved accounts specified\.$/u); }); - it('throws an error if any caveats are specified directly', () => { + it('prefers requestData.approvedAccounts over a specified caveat', () => { const getInternalAccounts = jest.fn(); const getAllAccounts = jest.fn(); const { factory } = getPermissionSpecifications({ @@ -240,21 +327,32 @@ describe('PermissionController specifications', () => { getAllAccounts, })[RestrictedMethods.eth_accounts]; - expect(() => + expect( factory( { caveats: [ - { - type: CaveatTypes.restrictReturnedAccounts, - value: ['0x1', '0x2'], - }, + CaveatFactories[CaveatTypes.restrictReturnedAccounts]([ + '0x1', + '0x2', + ]), ], invoker: 'foo.bar', target: 'eth_accounts', }, - { approvedAccounts: ['0x1'] }, + { approvedAccounts: ['0x1', '0x3'] }, ), - ).toThrow(/Received unexpected caveats./u); + ).toStrictEqual({ + caveats: [ + { + type: CaveatTypes.restrictReturnedAccounts, + value: ['0x1', '0x3'], + }, + ], + date: 1, + id: expect.any(String), + invoker: 'foo.bar', + parentCapability: 'eth_accounts', + }); }); }); @@ -263,7 +361,7 @@ describe('PermissionController specifications', () => { const getInternalAccounts = jest.fn().mockImplementationOnce(() => { return [ { - address: '0x1', + address: '0x7A2Bd22810088523516737b4Dc238A4bC37c23F2', id: '21066553-d8c8-4cdc-af33-efc921cd3ca9', metadata: { name: 'Test Account', @@ -273,11 +371,11 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [...Object.values(EthMethod)], + methods: ETH_EOA_METHODS, type: EthAccountType.Eoa, }, { - address: '0x2', + address: '0x7152f909e5EB3EF198f17e5Cb087c5Ced88294e3', id: '0bd7348e-bdfe-4f67-875c-de831a583857', metadata: { name: 'Test Account', @@ -286,11 +384,11 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [...Object.values(EthMethod)], + methods: ETH_EOA_METHODS, type: EthAccountType.Eoa, }, { - address: '0x3', + address: '0xDe70d2FF1995DC03EF1a3b584e3ae14da020C616', id: 'ff8fda69-d416-4d25-80a2-efb77bc7d4ad', metadata: { name: 'Test Account', @@ -300,11 +398,11 @@ describe('PermissionController specifications', () => { lastSelected: 3, }, options: {}, - methods: [...Object.values(EthMethod)], + methods: ETH_EOA_METHODS, type: EthAccountType.Eoa, }, { - address: '0x4', + address: '0x04eBa9B766477d8eCA77F5f0e67AE1863C95a7E3', id: '0bd7348e-bdfe-4f67-875c-de831a583857', metadata: { name: 'Test Account', @@ -314,14 +412,19 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [...Object.values(EthMethod)], + methods: ETH_EOA_METHODS, type: EthAccountType.Eoa, }, ]; }); const getAllAccounts = jest .fn() - .mockImplementationOnce(() => ['0x1', '0x2', '0x3', '0x4']); + .mockImplementationOnce(() => [ + '0x7A2Bd22810088523516737b4Dc238A4bC37c23F2', + '0x7152f909e5EB3EF198f17e5Cb087c5Ced88294e3', + '0xDe70d2FF1995DC03EF1a3b584e3ae14da020C616', + '0x04eBa9B766477d8eCA77F5f0e67AE1863C95a7E3', + ]); const { methodImplementation } = getPermissionSpecifications({ getInternalAccounts, @@ -329,10 +432,10 @@ describe('PermissionController specifications', () => { })[RestrictedMethods.eth_accounts]; expect(await methodImplementation()).toStrictEqual([ - '0x3', - '0x4', - '0x1', - '0x2', + '0xDe70d2FF1995DC03EF1a3b584e3ae14da020C616', + '0x04eBa9B766477d8eCA77F5f0e67AE1863C95a7E3', + '0x7A2Bd22810088523516737b4Dc238A4bC37c23F2', + '0x7152f909e5EB3EF198f17e5Cb087c5Ced88294e3', ]); }); @@ -340,7 +443,7 @@ describe('PermissionController specifications', () => { const getInternalAccounts = jest.fn().mockImplementationOnce(() => { return [ { - address: '0x2', + address: '0x7152f909e5EB3EF198f17e5Cb087c5Ced88294e3', id: '0bd7348e-bdfe-4f67-875c-de831a583857', metadata: { name: 'Test Account', @@ -350,11 +453,11 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [...Object.values(EthMethod)], + methods: ETH_EOA_METHODS, type: EthAccountType.Eoa, }, { - address: '0x3', + address: '0xDe70d2FF1995DC03EF1a3b584e3ae14da020C616', id: 'ff8fda69-d416-4d25-80a2-efb77bc7d4ad', metadata: { name: 'Test Account', @@ -364,14 +467,18 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [...Object.values(EthMethod)], + methods: ETH_EOA_METHODS, type: EthAccountType.Eoa, }, ]; }); const getAllAccounts = jest .fn() - .mockImplementationOnce(() => ['0x1', '0x2', '0x3']); + .mockImplementationOnce(() => [ + '0x7A2Bd22810088523516737b4Dc238A4bC37c23F2', + '0x7152f909e5EB3EF198f17e5Cb087c5Ced88294e3', + '0xDe70d2FF1995DC03EF1a3b584e3ae14da020C616', + ]); const { methodImplementation } = getPermissionSpecifications({ getInternalAccounts, @@ -380,7 +487,7 @@ describe('PermissionController specifications', () => { })[RestrictedMethods.eth_accounts]; await expect(() => methodImplementation()).rejects.toThrow( - 'Missing identity for address: "0x1".', + 'Missing identity for address: "0x7A2Bd22810088523516737b4Dc238A4bC37c23F2".', ); }); @@ -388,7 +495,7 @@ describe('PermissionController specifications', () => { const getInternalAccounts = jest.fn().mockImplementationOnce(() => { return [ { - address: '0x1', + address: '0x7A2Bd22810088523516737b4Dc238A4bC37c23F2', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { name: 'Test Account', @@ -398,11 +505,11 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [...Object.values(EthMethod)], + methods: ETH_EOA_METHODS, type: EthAccountType.Eoa, }, { - address: '0x3', + address: '0xDe70d2FF1995DC03EF1a3b584e3ae14da020C616', id: 'ff8fda69-d416-4d25-80a2-efb77bc7d4ad', metadata: { name: 'Test Account', @@ -412,14 +519,18 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [...Object.values(EthMethod)], + methods: ETH_EOA_METHODS, type: EthAccountType.Eoa, }, ]; }); const getAllAccounts = jest .fn() - .mockImplementationOnce(() => ['0x1', '0x2', '0x3']); + .mockImplementationOnce(() => [ + '0x7A2Bd22810088523516737b4Dc238A4bC37c23F2', + '0x7152f909e5EB3EF198f17e5Cb087c5Ced88294e3', + '0xDe70d2FF1995DC03EF1a3b584e3ae14da020C616', + ]); const { methodImplementation } = getPermissionSpecifications({ getInternalAccounts, @@ -428,7 +539,7 @@ describe('PermissionController specifications', () => { })[RestrictedMethods.eth_accounts]; await expect(() => methodImplementation()).rejects.toThrow( - 'Missing identity for address: "0x2".', + 'Missing identity for address: "0x7152f909e5EB3EF198f17e5Cb087c5Ced88294e3".', ); }); }); diff --git a/app/scripts/controllers/preferences.d.ts b/app/scripts/controllers/preferences.d.ts index 563c7e822f4a..cc6a99af3671 100644 --- a/app/scripts/controllers/preferences.d.ts +++ b/app/scripts/controllers/preferences.d.ts @@ -12,7 +12,6 @@ export type PreferencesController = { setSelectedAddress(addressToLowerCase: string): void; getSelectedAddress(): string; setAccountLabel(address: string, label: string): void; - setAddresses(allAccounts: string[]): void; store: { getState: () => PreferencesControllerState; subscribe: (callback: (state: PreferencesControllerState) => void) => void; diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 0d8f8268abb5..771f164b7b4c 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -1,12 +1,10 @@ import { ObservableStore } from '@metamask/obs-store'; -import { normalize as normalizeAddress } from '@metamask/eth-sig-util'; import { CHAIN_IDS, IPFS_DEFAULT_GATEWAY_URL, } from '../../../shared/constants/network'; import { LedgerTransportTypes } from '../../../shared/constants/hardware-wallets'; import { ThemeType } from '../../../shared/constants/preferences'; -import { shouldShowLineaMainnet } from '../../../shared/modules/network.utils'; const mainNetworks = { [CHAIN_IDS.MAINNET]: true, @@ -16,7 +14,7 @@ const mainNetworks = { const testNetworks = { [CHAIN_IDS.GOERLI]: true, [CHAIN_IDS.SEPOLIA]: true, - [CHAIN_IDS.LINEA_GOERLI]: true, + [CHAIN_IDS.LINEA_SEPOLIA]: true, }; export default class PreferencesController { @@ -53,15 +51,16 @@ export default class PreferencesController { eth_sign: false, }, useMultiAccountBalanceChecker: true, + hasDismissedOpenSeaToBlockaidBanner: false, useSafeChainsListValidation: true, // set to true means the dynamic list from the API is being used // set to false will be using the static list from contract-metadata - useTokenDetection: false, - useNftDetection: false, + useTokenDetection: opts?.initState?.useTokenDetection ?? true, + useNftDetection: opts?.initState?.useTokenDetection ?? true, use4ByteResolution: true, useCurrencyRateCheck: true, - useRequestQueue: false, - openSeaEnabled: false, + useRequestQueue: true, + openSeaEnabled: true, // todo set this to true ///: BEGIN:ONLY_INCLUDE_IF(blockaid) securityAlertsEnabled: true, ///: END:ONLY_INCLUDE_IF @@ -90,9 +89,14 @@ export default class PreferencesController { showExtensionInFullSizeView: false, showFiatInTestnets: false, showTestNetworks: false, + smartTransactionsOptInStatus: null, // null means we will show the Smart Transactions opt-in modal to a user if they are eligible useNativeCurrencyAsPrimaryCurrency: true, hideZeroBalanceTokens: false, petnamesEnabled: true, + redesignedConfirmationsEnabled: true, + featureNotificationsEnabled: false, + showTokenAutodetectModal: null, + showNftAutodetectModal: null, // null because we want to show the modal only the first time }, // ENS decentralized website resolution ipfsGateway: IPFS_DEFAULT_GATEWAY_URL, @@ -104,13 +108,17 @@ export default class PreferencesController { ? LedgerTransportTypes.webhid : LedgerTransportTypes.u2f, snapRegistryList: {}, - transactionSecurityCheckEnabled: false, theme: ThemeType.os, ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) snapsAddSnapAccountModalDismissed: false, ///: END:ONLY_INCLUDE_IF - isLineaMainnetReleased: false, useExternalNameSources: true, + useTransactionSimulations: true, + enableMV3TimestampSave: true, + // Turning OFF basic functionality toggle means turning OFF this useExternalServices flag. + // Whenever useExternalServices is false, certain features will be disabled. + // The flag is true by Default, meaning the toggle is ON by default. + useExternalServices: true, ...opts.initState, }; @@ -118,19 +126,6 @@ export default class PreferencesController { this.store = new ObservableStore(initState); this.store.setMaxListeners(13); - this.tokenListController = opts.tokenListController; - - opts.onKeyringStateChange((state) => { - const accounts = new Set(); - for (const keyring of state.keyrings) { - for (const address of keyring.accounts) { - accounts.add(address); - } - } - if (accounts.size > 0) { - this.syncAddresses(Array.from(accounts)); - } - }); this.messagingSystem = opts.messenger; this.messagingSystem?.registerActionHandler( @@ -142,11 +137,14 @@ export default class PreferencesController { getPayload: () => [this.store.getState(), []], }); + this.messagingSystem?.subscribe( + 'AccountsController:stateChange', + this.#handleAccountsControllerSync.bind(this), + ); + global.setPreference = (key, value) => { return this.setFeatureFlag(key, value); }; - - this._showShouldLineaMainnetNetwork(); } // PUBLIC METHODS @@ -195,6 +193,14 @@ export default class PreferencesController { this.store.updateState({ useMultiAccountBalanceChecker: val }); } + /** + * Setter for the `dismissOpenSeaToBlockaidBanner` property + * + */ + dismissOpenSeaToBlockaidBanner() { + this.store.updateState({ hasDismissedOpenSeaToBlockaidBanner: true }); + } + /** * Setter for the `useSafeChainsListValidation` property * @@ -204,6 +210,16 @@ export default class PreferencesController { this.store.updateState({ useSafeChainsListValidation: val }); } + toggleExternalServices(useExternalServices) { + this.store.updateState({ useExternalServices }); + this.setUseTokenDetection(useExternalServices); + this.setUseCurrencyRateCheck(useExternalServices); + this.setUsePhishDetect(useExternalServices); + this.setUseAddressBarEnsResolution(useExternalServices); + this.setOpenSeaEnabled(useExternalServices); + this.setUseNftDetection(useExternalServices); + } + /** * Setter for the `useTokenDetection` property * @@ -211,13 +227,6 @@ export default class PreferencesController { */ setUseTokenDetection(val) { this.store.updateState({ useTokenDetection: val }); - this.tokenListController.updatePreventPollingOnNetworkRestart(!val); - if (val) { - this.tokenListController.start(); - } else { - this.tokenListController.clearingTokenListData(); - this.tokenListController.stop(); - } } /** @@ -305,6 +314,17 @@ export default class PreferencesController { }); } + /** + * Setter for the `useTransactionSimulations` property + * + * @param {boolean} useTransactionSimulations - Whether or not to use simulations in the transaction confirmations. + */ + setUseTransactionSimulations(useTransactionSimulations) { + this.store.updateState({ + useTransactionSimulations, + }); + } + /** * Setter for the `advancedGasFee` property * @@ -331,17 +351,6 @@ export default class PreferencesController { this.store.updateState({ theme: val }); } - /** - * Setter for the `transactionSecurityCheckEnabled` property - * - * @param transactionSecurityCheckEnabled - */ - setTransactionSecurityCheckEnabled(transactionSecurityCheckEnabled) { - this.store.updateState({ - transactionSecurityCheckEnabled, - }); - } - /** * Add new methodData to state, to avoid requesting this information again through Infura * @@ -370,138 +379,39 @@ export default class PreferencesController { return textDirection; } - /** - * Updates identities to only include specified addresses. Removes identities - * not included in addresses array - * - * @param {string[]} addresses - An array of hex addresses - */ - setAddresses(addresses) { - const oldIdentities = this.store.getState().identities; - - const identities = addresses.reduce((ids, address, index) => { - const oldId = oldIdentities[address] || {}; - ids[address] = { name: `Account ${index + 1}`, address, ...oldId }; - return ids; - }, {}); - - this.store.updateState({ identities }); - } - - /** - * Removes an address from state - * - * @param {string} address - A hex address - * @returns {string} the address that was removed - */ - removeAddress(address) { - const { identities } = this.store.getState(); - - if (!identities[address]) { - throw new Error(`${address} can't be deleted cause it was not found`); - } - delete identities[address]; - this.store.updateState({ identities }); - - // If the selected account is no longer valid, - // select an arbitrary other account: - if (address === this.getSelectedAddress()) { - const [selected] = Object.keys(identities); - this.setSelectedAddress(selected); - } - - return address; - } - - /** - * Adds addresses to the identities object without removing identities - * - * @param {string[]} addresses - An array of hex addresses - */ - addAddresses(addresses) { - const { identities } = this.store.getState(); - addresses.forEach((address) => { - // skip if already exists - if (identities[address]) { - return; - } - // add missing identity - const identityCount = Object.keys(identities).length; - - identities[address] = { name: `Account ${identityCount + 1}`, address }; - }); - this.store.updateState({ identities }); - } - - /** - * Synchronizes identity entries with known accounts. - * Removes any unknown identities, and returns the resulting selected address. - * - * @param {Array} addresses - known to the vault. - * @returns {string} selectedAddress the selected address. - */ - syncAddresses(addresses) { - if (!Array.isArray(addresses) || addresses.length === 0) { - throw new Error('Expected non-empty array of addresses. Error #11201'); - } - - const { identities, lostIdentities } = this.store.getState(); - - const newlyLost = {}; - Object.keys(identities).forEach((identity) => { - if (!addresses.includes(identity)) { - newlyLost[identity] = identities[identity]; - delete identities[identity]; - } - }); - - // Identities are no longer present. - if (Object.keys(newlyLost).length > 0) { - // store lost accounts - Object.keys(newlyLost).forEach((key) => { - lostIdentities[key] = newlyLost[key]; - }); - } - - this.store.updateState({ identities, lostIdentities }); - this.addAddresses(addresses); - - // If the selected account is no longer valid, - // select an arbitrary other account: - let selected = this.getSelectedAddress(); - if (!addresses.includes(selected)) { - [selected] = addresses; - this.setSelectedAddress(selected); - } - - return selected; - } - /** * Setter for the `selectedAddress` property * - * @param {string} _address - A new hex address for an account + * @deprecated - Use setSelectedAccount from the AccountsController + * @param {string} address - A new hex address for an account */ - setSelectedAddress(_address) { - const address = normalizeAddress(_address); - - const { identities } = this.store.getState(); - const selectedIdentity = identities[address]; - if (!selectedIdentity) { + setSelectedAddress(address) { + const account = this.messagingSystem.call( + 'AccountsController:getAccountByAddress', + address, + ); + if (!account) { throw new Error(`Identity for '${address} not found`); } - selectedIdentity.lastSelected = Date.now(); - this.store.updateState({ identities, selectedAddress: address }); + this.messagingSystem.call( + 'AccountsController:setSelectedAccount', + account.id, + ); } /** * Getter for the `selectedAddress` property * + * @deprecated - Use the getSelectedAccount from the AccountsController * @returns {string} The hex address for the currently selected account */ getSelectedAddress() { - return this.store.getState().selectedAddress; + const selectedAccount = this.messagingSystem.call( + 'AccountsController:getSelectedAccount', + ); + + return selectedAccount.address; } /** @@ -516,21 +426,28 @@ export default class PreferencesController { /** * Sets a custom label for an account * - * @param {string} account - the account to set a label for + * @deprecated - Use setAccountName from the AccountsController + * @param {string} address - the account to set a label for * @param {string} label - the custom label for the account * @returns {Promise} */ - async setAccountLabel(account, label) { - if (!account) { + async setAccountLabel(address, label) { + const account = this.messagingSystem.call( + 'AccountsController:getAccountByAddress', + address, + ); + if (!address) { throw new Error( - `setAccountLabel requires a valid address, got ${String(account)}`, + `setAccountLabel requires a valid address, got ${String(address)}`, ); } - const address = normalizeAddress(account); - const { identities } = this.store.getState(); - identities[address] = identities[address] || {}; - identities[address].name = label; - this.store.updateState({ identities }); + + this.messagingSystem.call( + 'AccountsController:setAccountName', + account.id, + label, + ); + return label; } @@ -674,6 +591,10 @@ export default class PreferencesController { this.store.updateState({ incomingTransactionsPreferences: updatedValue }); } + setServiceWorkerKeepAlivePreference(value) { + this.store.updateState({ enableMV3TimestampSave: value }); + } + getRpcMethodPreferences() { return this.store.getState().disabledRpcMethodPreferences; } @@ -684,11 +605,40 @@ export default class PreferencesController { } ///: END:ONLY_INCLUDE_IF - /** - * A method to check is the linea mainnet network should be displayed - */ - _showShouldLineaMainnetNetwork() { - const showLineaMainnet = shouldShowLineaMainnet(); - this.store.updateState({ isLineaMainnetReleased: showLineaMainnet }); + #handleAccountsControllerSync(newAccountsControllerState) { + const { accounts, selectedAccount: selectedAccountId } = + newAccountsControllerState.internalAccounts; + + const selectedAccount = accounts[selectedAccountId]; + + const { identities, lostIdentities } = this.store.getState(); + + const addresses = Object.values(accounts).map((account) => + account.address.toLowerCase(), + ); + Object.keys(identities).forEach((identity) => { + if (addresses.includes(identity.toLowerCase())) { + lostIdentities[identity] = identities[identity]; + } + }); + + const updatedIdentities = Object.values(accounts).reduce( + (identitiesMap, account) => { + identitiesMap[account.address] = { + address: account.address, + name: account.metadata.name, + lastSelected: account.metadata.lastSelected, + }; + + return identitiesMap; + }, + {}, + ); + + this.store.updateState({ + identities: updatedIdentities, + lostIdentities, + selectedAddress: selectedAccount?.address || '', // it will be an empty string during onboarding + }); } } diff --git a/app/scripts/controllers/preferences.test.js b/app/scripts/controllers/preferences.test.js index 78e51c951402..fc344ada1264 100644 --- a/app/scripts/controllers/preferences.test.js +++ b/app/scripts/controllers/preferences.test.js @@ -3,6 +3,7 @@ */ import { ControllerMessenger } from '@metamask/base-controller'; import { TokenListController } from '@metamask/assets-controllers'; +import { AccountsController } from '@metamask/accounts-controller'; import { CHAIN_IDS } from '../../../shared/constants/network'; import PreferencesController from './preferences'; @@ -21,13 +22,35 @@ const NETWORK_CONFIGURATION_DATA = { rpcPrefs: {}, }, }; + describe('preferences controller', () => { + let controllerMessenger; let preferencesController; + let accountsController; let tokenListController; - let onKeyringStateChangeListener; beforeEach(() => { - const tokenListMessenger = new ControllerMessenger().getRestricted({ + controllerMessenger = new ControllerMessenger(); + + const accountsControllerMessenger = controllerMessenger.getRestricted({ + name: 'AccountsController', + allowedEvents: [ + 'SnapController:stateChange', + 'KeyringController:accountRemoved', + 'KeyringController:stateChange', + ], + allowedActions: [ + 'KeyringController:getAccounts', + 'KeyringController:getKeyringsByType', + 'KeyringController:getKeyringForAccount', + ], + }); + + accountsController = new AccountsController({ + messenger: accountsControllerMessenger, + }); + + const tokenListMessenger = controllerMessenger.getRestricted({ name: 'TokenListController', }); tokenListController = new TokenListController({ @@ -38,13 +61,21 @@ describe('preferences controller', () => { messenger: tokenListMessenger, }); + const preferencesMessenger = controllerMessenger.getRestricted({ + name: 'PreferencesController', + allowedActions: [ + `AccountsController:setSelectedAccount`, + `AccountsController:getAccountByAddress`, + `AccountsController:setAccountName`, + ], + allowedEvents: [`AccountsController:stateChange`], + }); + preferencesController = new PreferencesController({ initLangCode: 'en_US', tokenListController, networkConfigurations: NETWORK_CONFIGURATION_DATA, - onKeyringStateChange: (listener) => { - onKeyringStateChangeListener = listener; - }, + messenger: preferencesMessenger, }); }); @@ -76,81 +107,159 @@ describe('preferences controller', () => { }); }); - describe('setAddresses', () => { - it('should keep a map of addresses to names and addresses in the store', () => { - preferencesController.setAddresses(['0xda22le', '0x7e57e2']); + describe('setAccountLabel', () => { + const mockName = 'mockName'; + const firstAddress = '0x1f9090aaE28b8a3dCeaDf281B0F12828e676c326'; + const secondAddress = '0x0affb0a96fbefaa97dce488dfd97512346cf3ab8'; - const { identities } = preferencesController.store.getState(); - expect(identities).toStrictEqual({ - '0xda22le': { - name: 'Account 1', - address: '0xda22le', - }, - '0x7e57e2': { - name: 'Account 2', - address: '0x7e57e2', - }, + it('updating name from preference controller will update the name in accounts controller and preferences controller', () => { + controllerMessenger.publish('KeyringController:stateChange', { + isUnlocked: true, + keyrings: [ + { + type: 'HD Key Tree', + accounts: [firstAddress, secondAddress], + }, + ], }); - }); - it('should replace its list of addresses', () => { - preferencesController.setAddresses(['0xda22le', '0x7e57e2']); - preferencesController.setAddresses(['0xda22le77', '0x7e57e277']); + let [firstAccount, secondAccount] = accountsController.listAccounts(); const { identities } = preferencesController.store.getState(); - expect(identities).toStrictEqual({ - '0xda22le77': { - name: 'Account 1', - address: '0xda22le77', - }, - '0x7e57e277': { - name: 'Account 2', - address: '0x7e57e277', - }, - }); - }); - }); - describe('removeAddress', () => { - it('should remove an address from state', () => { - preferencesController.setAddresses(['0xda22le', '0x7e57e2']); + const firstPreferenceAccount = identities[firstAccount.address]; + const secondPreferenceAccount = identities[secondAccount.address]; - preferencesController.removeAddress('0xda22le'); + expect(firstAccount.metadata.name).toBe(firstPreferenceAccount.name); + expect(secondAccount.metadata.name).toBe(secondPreferenceAccount.name); - expect( - preferencesController.store.getState().identities['0xda22le'], - ).toStrictEqual(undefined); + preferencesController.setAccountLabel(firstAccount.address, mockName); + + // refresh state after state changed + + [firstAccount, secondAccount] = accountsController.listAccounts(); + + const { identities: updatedIdentities } = + preferencesController.store.getState(); + + const updatedFirstPreferenceAccount = + updatedIdentities[firstAccount.address]; + const updatedSecondPreferenceAccount = + updatedIdentities[secondAccount.address]; + + expect(firstAccount.metadata.name).toBe( + updatedFirstPreferenceAccount.name, + ); + expect(updatedFirstPreferenceAccount.name).toBe(mockName); + expect(secondAccount.metadata.name).toBe( + updatedSecondPreferenceAccount.name, + ); }); - it('should switch accounts if the selected address is removed', () => { - preferencesController.setAddresses(['0xda22le', '0x7e57e2']); + it('updating name from accounts controller updates the name in preferences controller', () => { + controllerMessenger.publish('KeyringController:stateChange', { + isUnlocked: true, + keyrings: [ + { + type: 'HD Key Tree', + accounts: [firstAddress, secondAddress], + }, + ], + }); + + let [firstAccount, secondAccount] = accountsController.listAccounts(); + + const { identities } = preferencesController.store.getState(); + + const firstPreferenceAccount = identities[firstAccount.address]; + const secondPreferenceAccount = identities[secondAccount.address]; - preferencesController.setSelectedAddress('0x7e57e2'); - preferencesController.removeAddress('0x7e57e2'); - expect(preferencesController.getSelectedAddress()).toStrictEqual( - '0xda22le', + expect(firstAccount.metadata.name).toBe(firstPreferenceAccount.name); + expect(secondAccount.metadata.name).toBe(secondPreferenceAccount.name); + + accountsController.setAccountName(firstAccount.id, mockName); + // refresh state after state changed + + [firstAccount, secondAccount] = accountsController.listAccounts(); + + const { identities: updatedIdentities } = + preferencesController.store.getState(); + + const updatedFirstPreferenceAccount = + updatedIdentities[firstAccount.address]; + const updatedSecondPreferenceAccount = + updatedIdentities[secondAccount.address]; + + expect(firstAccount.metadata.name).toBe( + updatedFirstPreferenceAccount.name, + ); + expect(updatedFirstPreferenceAccount.name).toBe(mockName); + expect(secondAccount.metadata.name).toBe( + updatedSecondPreferenceAccount.name, ); }); }); - describe('setAccountLabel', () => { - it('should update a label for the given account', () => { - preferencesController.setAddresses(['0xda22le', '0x7e57e2']); - - expect( - preferencesController.store.getState().identities['0xda22le'], - ).toStrictEqual({ - name: 'Account 1', - address: '0xda22le', + describe('setSelectedAddress', () => { + it('updating selectedAddress from preferences controller updates the selectedAccount in accounts controller and preferences controller', () => { + const firstAddress = '0x1f9090aaE28b8a3dCeaDf281B0F12828e676c326'; + const secondAddress = '0x0affb0a96fbefaa97dce488dfd97512346cf3ab8'; + controllerMessenger.publish('KeyringController:stateChange', { + isUnlocked: true, + keyrings: [ + { + type: 'HD Key Tree', + accounts: [firstAddress, secondAddress], + }, + ], }); - preferencesController.setAccountLabel('0xda22le', 'Dazzle'); - expect( - preferencesController.store.getState().identities['0xda22le'], - ).toStrictEqual({ - name: 'Dazzle', - address: '0xda22le', + const selectedAccount = accountsController.getSelectedAccount(); + + const { selectedAddress } = preferencesController.store.getState(); + + expect(selectedAddress).toBe(selectedAccount.address); + + preferencesController.setSelectedAddress(secondAddress); + // refresh state after state changed + + const { selectedAddress: updatedSelectedAddress } = + preferencesController.store.getState(); + + const updatedSelectedAccount = accountsController.getSelectedAccount(); + + expect(updatedSelectedAddress).toBe(updatedSelectedAccount.address); + }); + + it('updating selectedAccount from accounts controller updates the selectedAddress in preferences controller', () => { + const firstAddress = '0x1f9090aaE28b8a3dCeaDf281B0F12828e676c326'; + const secondAddress = '0x0affb0a96fbefaa97dce488dfd97512346cf3ab8'; + controllerMessenger.publish('KeyringController:stateChange', { + isUnlocked: true, + keyrings: [ + { + type: 'HD Key Tree', + accounts: [firstAddress, secondAddress], + }, + ], }); + + const selectedAccount = accountsController.getSelectedAccount(); + const accounts = accountsController.listAccounts(); + + const { selectedAddress } = preferencesController.store.getState(); + + expect(selectedAddress).toBe(selectedAccount.address); + + accountsController.setSelectedAccount(accounts[1].id); + // refresh state after state changed + + const { selectedAddress: updatedSelectedAddress } = + preferencesController.store.getState(); + + const updatedSelectedAccount = accountsController.getSelectedAccount(); + + expect(updatedSelectedAddress).toBe(updatedSelectedAccount.address); }); }); @@ -199,6 +308,23 @@ describe('preferences controller', () => { }); }); + describe('dismissOpenSeaToBlockaidBanner', () => { + it('hasDismissedOpenSeaToBlockaidBanner should default to false', () => { + expect( + preferencesController.store.getState() + .hasDismissedOpenSeaToBlockaidBanner, + ).toStrictEqual(false); + }); + + it('should set the hasDismissedOpenSeaToBlockaidBanner property in state', () => { + preferencesController.dismissOpenSeaToBlockaidBanner(); + expect( + preferencesController.store.getState() + .hasDismissedOpenSeaToBlockaidBanner, + ).toStrictEqual(true); + }); + }); + describe('setUseSafeChainsListValidation', function () { it('should default to true', function () { const state = preferencesController.store.getState(); @@ -220,10 +346,10 @@ describe('preferences controller', () => { }); describe('setUseTokenDetection', function () { - it('should default to false', function () { + it('should default to true for new users', function () { const state = preferencesController.store.getState(); - expect(state.useTokenDetection).toStrictEqual(false); + expect(state.useTokenDetection).toStrictEqual(true); }); it('should set the useTokenDetection property in state', () => { @@ -232,13 +358,26 @@ describe('preferences controller', () => { preferencesController.store.getState().useTokenDetection, ).toStrictEqual(true); }); + + it('should keep initial value of useTokenDetection for existing users', function () { + const preferencesControllerExistingUser = new PreferencesController({ + initLangCode: 'en_US', + tokenListController, + initState: { + useTokenDetection: false, + }, + networkConfigurations: NETWORK_CONFIGURATION_DATA, + }); + const state = preferencesControllerExistingUser.store.getState(); + expect(state.useTokenDetection).toStrictEqual(false); + }); }); describe('setUseNftDetection', () => { - it('should default to false', () => { + it('should default to true', () => { expect( preferencesController.store.getState().useNftDetection, - ).toStrictEqual(false); + ).toStrictEqual(true); }); it('should set the useNftDetection property in state', () => { @@ -266,10 +405,10 @@ describe('preferences controller', () => { }); describe('setOpenSeaEnabled', () => { - it('should default to false', () => { + it('should default to true', () => { expect( preferencesController.store.getState().openSeaEnabled, - ).toStrictEqual(false); + ).toStrictEqual(true); }); it('should set the openSeaEnabled property in state', () => { @@ -346,7 +485,7 @@ describe('preferences controller', () => { [NETWORK_CONFIGURATION_DATA[addedNonTestNetworks[1]].chainId]: true, [CHAIN_IDS.GOERLI]: true, [CHAIN_IDS.SEPOLIA]: true, - [CHAIN_IDS.LINEA_GOERLI]: true, + [CHAIN_IDS.LINEA_SEPOLIA]: true, }); }); @@ -363,26 +502,32 @@ describe('preferences controller', () => { [NETWORK_CONFIGURATION_DATA[addedNonTestNetworks[1]].chainId]: true, [CHAIN_IDS.GOERLI]: true, [CHAIN_IDS.SEPOLIA]: true, - [CHAIN_IDS.LINEA_GOERLI]: true, + [CHAIN_IDS.LINEA_SEPOLIA]: true, }); }); }); - describe('onKeyringStateChange', () => { - it('should sync the identities with the keyring', () => { - const mockKeyringControllerState = { + describe('AccountsController:stateChange subscription', () => { + it('sync the identities with the accounts in the accounts controller', () => { + const firstAddress = '0x1f9090aaE28b8a3dCeaDf281B0F12828e676c326'; + const secondAddress = '0x0affb0a96fbefaa97dce488dfd97512346cf3ab8'; + controllerMessenger.publish('KeyringController:stateChange', { + isUnlocked: true, keyrings: [ { - accounts: ['0x1', '0x2', '0x3', '0x4'], + type: 'HD Key Tree', + accounts: [firstAddress, secondAddress], }, ], - }; + }); - onKeyringStateChangeListener(mockKeyringControllerState); + const accounts = accountsController.listAccounts(); - expect( - Object.keys(preferencesController.store.getState().identities), - ).toStrictEqual(mockKeyringControllerState.keyrings[0].accounts); + const { identities } = preferencesController.store.getState(); + + expect(accounts.map((account) => account.address)).toStrictEqual( + Object.keys(identities), + ); }); }); @@ -402,4 +547,34 @@ describe('preferences controller', () => { }); }); ///: END:ONLY_INCLUDE_IF + + describe('setUseTransactionSimulations', () => { + it('should default to true', () => { + expect( + preferencesController.store.getState().useExternalNameSources, + ).toStrictEqual(true); + }); + + it('should set the setUseTransactionSimulations property in state', () => { + preferencesController.setUseTransactionSimulations(false); + expect( + preferencesController.store.getState().useTransactionSimulations, + ).toStrictEqual(false); + }); + }); + + describe('setServiceWorkerKeepAlivePreference', () => { + it('should default to true', () => { + expect( + preferencesController.store.getState().enableMV3TimestampSave, + ).toStrictEqual(true); + }); + + it('should set the setServiceWorkerKeepAlivePreference property in state', () => { + preferencesController.setServiceWorkerKeepAlivePreference(false); + expect( + preferencesController.store.getState().enableMV3TimestampSave, + ).toStrictEqual(false); + }); + }); }); diff --git a/app/scripts/controllers/push-platform-notifications/mocks/mockResponse.ts b/app/scripts/controllers/push-platform-notifications/mocks/mockResponse.ts new file mode 100644 index 000000000000..3ff965b3444f --- /dev/null +++ b/app/scripts/controllers/push-platform-notifications/mocks/mockResponse.ts @@ -0,0 +1,60 @@ +import { REGISTRATION_TOKENS_ENDPOINT } from '../services/endpoints'; +import { LinksResult } from '../services/services'; + +type MockResponse = { + url: string | RegExp; + requestMethod: 'GET' | 'POST' | 'PUT'; + response: unknown; +}; + +export const MOCK_REG_TOKEN = 'REG_TOKEN'; +export const MOCK_LINKS_RESPONSE: LinksResult = { + trigger_ids: ['1', '2', '3'], + registration_tokens: [ + { token: 'reg_token_1', platform: 'portfolio' }, + { token: 'reg_token_2', platform: 'extension' }, + ], +}; + +export function getMockRetrievePushNotificationLinksResponse() { + return { + url: REGISTRATION_TOKENS_ENDPOINT, + requestMethod: 'GET', + response: MOCK_LINKS_RESPONSE, + } satisfies MockResponse; +} + +export function getMockUpdatePushNotificationLinksResponse() { + return { + url: REGISTRATION_TOKENS_ENDPOINT, + requestMethod: 'POST', + response: null, + } satisfies MockResponse; +} + +export const MOCK_FCM_RESPONSE = { + name: '', + token: 'fcm-token', + web: { + endpoint: '', + p256dh: '', + auth: '', + applicationPubKey: '', + }, +}; + +export function getMockCreateFCMRegistrationTokenResponse() { + return { + url: /^https:\/\/fcmregistrations\.googleapis\.com\/v1\/projects\/.*$/u, + requestMethod: 'POST', + response: MOCK_FCM_RESPONSE, + } satisfies MockResponse; +} + +export function getMockDeleteFCMRegistrationTokenResponse() { + return { + url: /^https:\/\/fcmregistrations\.googleapis\.com\/v1\/projects\/.*$/u, + requestMethod: 'POST', + response: {}, + } satisfies MockResponse; +} diff --git a/app/scripts/controllers/push-platform-notifications/mocks/mockServices.ts b/app/scripts/controllers/push-platform-notifications/mocks/mockServices.ts new file mode 100644 index 000000000000..e0c3cb98d0c2 --- /dev/null +++ b/app/scripts/controllers/push-platform-notifications/mocks/mockServices.ts @@ -0,0 +1,36 @@ +import nock from 'nock'; +import { + getMockRetrievePushNotificationLinksResponse, + getMockUpdatePushNotificationLinksResponse, +} from './mockResponse'; + +type MockReply = { + status: nock.StatusCode; + body?: nock.Body; +}; + +export function mockEndpointGetPushNotificationLinks(mockReply?: MockReply) { + const mockResponse = getMockRetrievePushNotificationLinksResponse(); + const reply = mockReply ?? { + status: 200, + body: mockResponse.response, + }; + + const mockEndpoint = nock(mockResponse.url) + .get('') + .reply(reply.status, reply.body); + + return mockEndpoint; +} + +export function mockEndpointUpdatePushNotificationLinks(mockReply?: MockReply) { + const mockResponse = getMockUpdatePushNotificationLinksResponse(); + const reply = mockReply ?? { + status: 200, + body: mockResponse.response, + }; + + const mockEndpoint = nock(mockResponse.url).post('').reply(reply.status); + + return mockEndpoint; +} diff --git a/app/scripts/controllers/push-platform-notifications/push-platform-notifications.test.ts b/app/scripts/controllers/push-platform-notifications/push-platform-notifications.test.ts new file mode 100644 index 000000000000..0b596fdb4992 --- /dev/null +++ b/app/scripts/controllers/push-platform-notifications/push-platform-notifications.test.ts @@ -0,0 +1,174 @@ +import { ControllerMessenger } from '@metamask/base-controller'; +import type { AuthenticationControllerGetBearerToken } from '../authentication/authentication-controller'; +import { PushPlatformNotificationsController } from './push-platform-notifications'; + +import * as services from './services/services'; +import type { + PushPlatformNotificationsControllerMessenger, + PushPlatformNotificationsControllerState, +} from './push-platform-notifications'; + +const MOCK_JWT = 'mockJwt'; +const MOCK_FCM_TOKEN = 'mockFcmToken'; +const MOCK_TRIGGERS = ['uuid1', 'uuid2']; + +describe('PushPlatformNotificationsController', () => { + if (!process.env.ENABLE_MV3) { + it('No MV2 tests, this functionality is not enabled', () => { + expect(true).toBe(true); + }); + } + + if (process.env.ENABLE_MV3) { + describe('enablePushNotifications', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should update the state with the fcmToken', async () => { + await withController(async ({ controller, messenger }) => { + mockAuthBearerTokenCall(messenger); + jest + .spyOn(services, 'activatePushNotifications') + .mockResolvedValue(MOCK_FCM_TOKEN); + + const unsubscribeMock = jest.fn(); + jest + .spyOn(services, 'listenToPushNotifications') + .mockResolvedValue(unsubscribeMock); + + await controller.enablePushNotifications(MOCK_TRIGGERS); + expect(controller.state.fcmToken).toBe(MOCK_FCM_TOKEN); + + expect(services.listenToPushNotifications).toHaveBeenCalled(); + }); + }); + + it('should fail if a jwt token is not provided', async () => { + await withController(async ({ messenger, controller }) => { + mockAuthBearerTokenCall(messenger).mockResolvedValue( + null as unknown as string, + ); + await expect( + controller.enablePushNotifications([]), + ).rejects.toThrow(); + }); + }); + }); + + describe('disablePushNotifications', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should update the state removing the fcmToken', async () => { + await withController(async ({ messenger, controller }) => { + mockAuthBearerTokenCall(messenger); + await controller.disablePushNotifications(MOCK_TRIGGERS); + expect(controller.state.fcmToken).toBe(''); + }); + }); + + it('should fail if a jwt token is not provided', async () => { + await withController(async ({ messenger, controller }) => { + mockAuthBearerTokenCall(messenger).mockResolvedValue( + null as unknown as string, + ); + await expect( + controller.disablePushNotifications([]), + ).rejects.toThrow(); + }); + }); + }); + + describe('updateTriggerPushNotifications', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should call updateTriggerPushNotifications with the correct parameters', async () => { + await withController(async ({ messenger, controller }) => { + mockAuthBearerTokenCall(messenger); + const spy = jest + .spyOn(services, 'updateTriggerPushNotifications') + .mockResolvedValue({ + isTriggersLinkedToPushNotifications: true, + }); + + await controller.updateTriggerPushNotifications(MOCK_TRIGGERS); + + expect(spy).toHaveBeenCalledWith( + controller.state.fcmToken, + MOCK_JWT, + MOCK_TRIGGERS, + ); + }); + }); + }); + } +}); + +// Test helper functions + +type WithControllerCallback = ({ + controller, + initialState, + messenger, +}: { + controller: PushPlatformNotificationsController; + initialState: PushPlatformNotificationsControllerState; + messenger: PushPlatformNotificationsControllerMessenger; +}) => Promise | ReturnValue; + +function buildMessenger() { + return new ControllerMessenger< + AuthenticationControllerGetBearerToken, + never + >(); +} + +function buildPushPlatformNotificationsControllerMessenger( + messenger = buildMessenger(), +) { + return messenger.getRestricted({ + name: 'PushPlatformNotificationsController', + allowedActions: ['AuthenticationController:getBearerToken'], + allowedEvents: [], + }) as PushPlatformNotificationsControllerMessenger; +} + +async function withController( + fn: WithControllerCallback, +): Promise { + const messenger = buildPushPlatformNotificationsControllerMessenger(); + const controller = new PushPlatformNotificationsController({ + messenger, + state: { fcmToken: '' }, + }); + + return await fn({ + controller, + initialState: controller.state, + messenger, + }); +} + +function mockAuthBearerTokenCall( + messenger: PushPlatformNotificationsControllerMessenger, +) { + type Fn = AuthenticationControllerGetBearerToken['handler']; + const mockAuthGetBearerToken = jest + .fn, Parameters>() + .mockResolvedValue(MOCK_JWT); + + jest.spyOn(messenger, 'call').mockImplementation((...args) => { + const [actionType] = args; + if (actionType === 'AuthenticationController:getBearerToken') { + return mockAuthGetBearerToken(); + } + + throw new Error('MOCK - unsupported messenger call mock'); + }); + + return mockAuthGetBearerToken; +} diff --git a/app/scripts/controllers/push-platform-notifications/push-platform-notifications.ts b/app/scripts/controllers/push-platform-notifications/push-platform-notifications.ts new file mode 100644 index 000000000000..fa28505bb55d --- /dev/null +++ b/app/scripts/controllers/push-platform-notifications/push-platform-notifications.ts @@ -0,0 +1,276 @@ +import { + BaseController, + RestrictedControllerMessenger, + ControllerGetStateAction, +} from '@metamask/base-controller'; +import log from 'loglevel'; + +import type { AuthenticationControllerGetBearerToken } from '../authentication/authentication-controller'; +import type { Notification } from '../metamask-notifications/types/notification/notification'; +import { + activatePushNotifications, + deactivatePushNotifications, + listenToPushNotifications, + updateTriggerPushNotifications, +} from './services/services'; + +const controllerName = 'PushPlatformNotificationsController'; + +export type PushPlatformNotificationsControllerState = { + fcmToken: string; +}; + +export declare type PushPlatformNotificationsControllerEnablePushNotifications = + { + type: `${typeof controllerName}:enablePushNotifications`; + handler: PushPlatformNotificationsController['enablePushNotifications']; + }; + +export declare type PushPlatformNotificationsControllerDisablePushNotifications = + { + type: `${typeof controllerName}:disablePushNotifications`; + handler: PushPlatformNotificationsController['disablePushNotifications']; + }; +export declare type PushPlatformNotificationsControllerUpdateTriggerPushNotifications = + { + type: `${typeof controllerName}:updateTriggerPushNotifications`; + handler: PushPlatformNotificationsController['updateTriggerPushNotifications']; + }; + +export type PushPlatformNotificationsControllerMessengerActions = + | PushPlatformNotificationsControllerEnablePushNotifications + | PushPlatformNotificationsControllerDisablePushNotifications + | PushPlatformNotificationsControllerUpdateTriggerPushNotifications + | ControllerGetStateAction<'state', PushPlatformNotificationsControllerState>; + +type AllowedActions = AuthenticationControllerGetBearerToken; + +export type PushPlatformNotificationsControllerOnNewNotificationEvent = { + type: `${typeof controllerName}:onNewNotifications`; + payload: [Notification]; +}; + +export type PushPlatformNotificationsControllerPushNotificationClicked = { + type: `${typeof controllerName}:pushNotificationClicked`; + payload: [Notification]; +}; + +type AllowedEvents = + | PushPlatformNotificationsControllerOnNewNotificationEvent + | PushPlatformNotificationsControllerPushNotificationClicked; + +export type PushPlatformNotificationsControllerMessenger = + RestrictedControllerMessenger< + typeof controllerName, + PushPlatformNotificationsControllerMessengerActions | AllowedActions, + AllowedEvents, + AllowedActions['type'], + AllowedEvents['type'] + >; + +const metadata = { + fcmToken: { + persist: true, + anonymous: true, + }, +}; + +/** + * Manages push notifications for the application, including enabling, disabling, and updating triggers for push notifications. + * This controller integrates with Firebase Cloud Messaging (FCM) to handle the registration and management of push notifications. + * It is responsible for registering and unregistering the service worker that listens for push notifications, + * managing the FCM token, and communicating with the server to register or unregister the device for push notifications. + * Additionally, it provides functionality to update the server with new UUIDs that should trigger push notifications. + * + * @augments {BaseController} + */ +export class PushPlatformNotificationsController extends BaseController< + typeof controllerName, + PushPlatformNotificationsControllerState, + PushPlatformNotificationsControllerMessenger +> { + #pushListenerUnsubscribe: (() => void) | undefined = undefined; + + constructor({ + messenger, + state, + }: { + messenger: PushPlatformNotificationsControllerMessenger; + state: PushPlatformNotificationsControllerState; + }) { + super({ + messenger, + metadata, + name: controllerName, + state: { + fcmToken: state?.fcmToken || '', + }, + }); + + this.#registerMessageHandlers(); + } + + #registerMessageHandlers(): void { + this.messagingSystem.registerActionHandler( + 'PushPlatformNotificationsController:enablePushNotifications', + this.enablePushNotifications.bind(this), + ); + this.messagingSystem.registerActionHandler( + 'PushPlatformNotificationsController:disablePushNotifications', + this.disablePushNotifications.bind(this), + ); + this.messagingSystem.registerActionHandler( + 'PushPlatformNotificationsController:updateTriggerPushNotifications', + this.updateTriggerPushNotifications.bind(this), + ); + } + + async #getAndAssertBearerToken() { + const bearerToken = await this.messagingSystem.call( + 'AuthenticationController:getBearerToken', + ); + if (!bearerToken) { + log.error( + 'Failed to enable push notifications: BearerToken token is missing.', + ); + throw new Error('BearerToken token is missing'); + } + + return bearerToken; + } + + /** + * Enables push notifications for the application. + * + * This method sets up the necessary infrastructure for handling push notifications by: + * 1. Registering the service worker to listen for messages. + * 2. Fetching the Firebase Cloud Messaging (FCM) token from Firebase. + * 3. Sending the FCM token to the server responsible for sending notifications, to register the device. + * + * @param UUIDs - An array of UUIDs to enable push notifications for. + */ + public async enablePushNotifications(UUIDs: string[]) { + // TEMP: disabling push notifications if browser does not support MV3. + // Will need work to support firefox on MV2 + if (!process.env.ENABLE_MV3) { + return; + } + + const bearerToken = await this.#getAndAssertBearerToken(); + + try { + // Activate Push Notifications + const regToken = await activatePushNotifications(bearerToken, UUIDs); + + if (!regToken) { + return; + } + + // Listen to push notifications + this.#pushListenerUnsubscribe ??= await listenToPushNotifications( + (n) => + this.messagingSystem.publish( + 'PushPlatformNotificationsController:onNewNotifications', + n, + ), + (n) => + this.messagingSystem.publish( + 'PushPlatformNotificationsController:pushNotificationClicked', + n, + ), + ); + + // Update state + this.update((state) => { + state.fcmToken = regToken; + }); + } catch (error) { + log.error('Failed to enable push notifications:', error); + throw new Error('Failed to enable push notifications'); + } + } + + /** + * Disables push notifications for the application. + * This method handles the process of disabling push notifications by: + * 1. Unregistering the service worker to stop listening for messages. + * 2. Sending a request to the server to unregister the device using the FCM token. + * 3. Removing the FCM token from the state to complete the process. + * + * @param UUIDs - An array of UUIDs for which push notifications should be disabled. + */ + public async disablePushNotifications(UUIDs: string[]) { + // TEMP: disabling push notifications if browser does not support MV3. + // Will need work to support firefox on MV2 + if (!process.env.ENABLE_MV3) { + return; + } + + const bearerToken = await this.#getAndAssertBearerToken(); + let isPushNotificationsDisabled: boolean; + + try { + // Send a request to the server to unregister the token/device + isPushNotificationsDisabled = await deactivatePushNotifications( + this.state.fcmToken, + bearerToken, + UUIDs, + ); + } catch (error) { + const errorMessage = `Failed to disable push notifications: ${error}`; + log.error(errorMessage); + throw new Error(errorMessage); + } + + // Remove the FCM token from the state + if (!isPushNotificationsDisabled) { + return; + } + + // Unsubscribe from push notifications + this.#pushListenerUnsubscribe?.(); + + // Update State + if (isPushNotificationsDisabled) { + this.update((state) => { + state.fcmToken = ''; + }); + } + } + + /** + * Updates the triggers for push notifications. + * This method is responsible for updating the server with the new set of UUIDs that should trigger push notifications. + * It uses the current FCM token and a BearerToken for authentication. + * + * @param UUIDs - An array of UUIDs that should trigger push notifications. + */ + public async updateTriggerPushNotifications(UUIDs: string[]) { + // TEMP: disabling push notifications if browser does not support MV3. + // Will need work to support firefox on MV2 + if (!process.env.ENABLE_MV3) { + return; + } + + const bearerToken = await this.#getAndAssertBearerToken(); + + try { + const { fcmToken } = await updateTriggerPushNotifications( + this.state.fcmToken, + bearerToken, + UUIDs, + ); + + // update the state with the new FCM token + if (fcmToken) { + this.update((state) => { + state.fcmToken = fcmToken; + }); + } + } catch (error) { + const errorMessage = `Failed to update triggers for push notifications: ${error}`; + log.error(errorMessage); + throw new Error(errorMessage); + } + } +} diff --git a/app/scripts/controllers/push-platform-notifications/services/endpoints.ts b/app/scripts/controllers/push-platform-notifications/services/endpoints.ts new file mode 100644 index 000000000000..ff6520eb03a5 --- /dev/null +++ b/app/scripts/controllers/push-platform-notifications/services/endpoints.ts @@ -0,0 +1,2 @@ +const url = process.env.PUSH_NOTIFICATIONS_SERVICE_URL; +export const REGISTRATION_TOKENS_ENDPOINT = `${url}/v1/link`; diff --git a/app/scripts/controllers/push-platform-notifications/services/services.test.ts b/app/scripts/controllers/push-platform-notifications/services/services.test.ts new file mode 100644 index 000000000000..413c2d28caf8 --- /dev/null +++ b/app/scripts/controllers/push-platform-notifications/services/services.test.ts @@ -0,0 +1,232 @@ +import * as FirebaseApp from 'firebase/app'; +import * as FirebaseMessaging from 'firebase/messaging'; +import * as FirebaseMessagingSW from 'firebase/messaging/sw'; +import { + mockEndpointGetPushNotificationLinks, + mockEndpointUpdatePushNotificationLinks, +} from '../mocks/mockServices'; +import * as services from './services'; + +jest.mock('firebase/app'); +jest.mock('firebase/messaging'); +jest.mock('firebase/messaging/sw'); + +const MOCK_REG_TOKEN = 'REG_TOKEN'; +const MOCK_NEW_REG_TOKEN = 'NEW_REG_TOKEN'; +const MOCK_TRIGGERS = ['1', '2', '3']; +const MOCK_JWT = 'MOCK_JWT'; + +describe('PushPlatformNotificationsServices', () => { + describe('getPushNotificationLinks', () => { + it('Should return reg token links', async () => { + const mockGetLinksEndpoint = mockEndpointGetPushNotificationLinks(); + const res = await services.getPushNotificationLinks(MOCK_JWT); + + expect(mockGetLinksEndpoint.isDone()).toBe(true); + expect(res).toBeDefined(); + expect(res?.trigger_ids).toBeDefined(); + expect(res?.registration_tokens).toBeDefined(); + }); + + it('Should return null if api call fails', async () => { + const mockGetLinksEndpoint = mockEndpointGetPushNotificationLinks({ + status: 500, + }); + const res = await services.getPushNotificationLinks(MOCK_JWT); + + expect(mockGetLinksEndpoint.isDone()).toBe(true); + expect(res).toBeNull(); + }); + }); + + describe('updateLinksAPI', () => { + it('Should return true if links are updated', async () => { + const mockUpdateLinksEndpoint = mockEndpointUpdatePushNotificationLinks(); + + const res = await services.updateLinksAPI(MOCK_JWT, MOCK_TRIGGERS, [ + { token: MOCK_NEW_REG_TOKEN, platform: 'extension' }, + ]); + + expect(mockUpdateLinksEndpoint.isDone()).toBe(true); + expect(res).toBe(true); + }); + + it('Should return false if links are not updated', async () => { + mockEndpointUpdatePushNotificationLinks({ status: 500 }); + + const res = await services.updateLinksAPI(MOCK_JWT, MOCK_TRIGGERS, [ + { token: MOCK_NEW_REG_TOKEN, platform: 'extension' }, + ]); + + expect(res).toBe(false); + }); + }); + + describe('activatePushNotifications()', () => { + it('should append registration token when enabling push', async () => { + arrangeEndpoints(); + arrangeFCMMocks(); + + const res = await services.activatePushNotifications( + MOCK_JWT, + MOCK_TRIGGERS, + ); + + expect(res).toBe(MOCK_NEW_REG_TOKEN); + }); + + it('should fail if unable to get existing notification links', async () => { + mockEndpointGetPushNotificationLinks({ status: 500 }); + + const res = await services.activatePushNotifications( + MOCK_JWT, + MOCK_TRIGGERS, + ); + expect(res).toBeNull(); + }); + + it('should fail if unable to create new reg token', async () => { + arrangeEndpoints(); + const fcmMocks = arrangeFCMMocks(); + fcmMocks.getToken.mockRejectedValue(new Error('MOCK ERROR')); + const res = await services.activatePushNotifications( + MOCK_JWT, + MOCK_TRIGGERS, + ); + expect(res).toBeNull(); + }); + + it('should silently fail and return if failed to activate push notifications', async () => { + mockEndpointGetPushNotificationLinks(); + mockEndpointUpdatePushNotificationLinks({ status: 500 }); + arrangeFCMMocks(); + const res = await services.activatePushNotifications( + MOCK_JWT, + MOCK_TRIGGERS, + ); + + // We return the registration token, but we haven't updating the links. + // This can be redone at a later invocation (e.g. when the extension is re-initialized or notification setting changes) + expect(res).toBe(MOCK_NEW_REG_TOKEN); + }); + }); + + describe('deactivatePushNotifications()', () => { + it('should fail if unable to get existing notification links', async () => { + mockEndpointGetPushNotificationLinks({ status: 500 }); + + const res = await services.deactivatePushNotifications( + MOCK_REG_TOKEN, + MOCK_JWT, + MOCK_TRIGGERS, + ); + + expect(res).toBe(false); + }); + + it('should fail if unable to update links', async () => { + mockEndpointGetPushNotificationLinks(); + mockEndpointUpdatePushNotificationLinks({ status: 500 }); + + const res = await services.deactivatePushNotifications( + MOCK_REG_TOKEN, + MOCK_JWT, + MOCK_TRIGGERS, + ); + + expect(res).toBe(false); + }); + + it('should fail if unable to delete reg token', async () => { + arrangeEndpoints(); + const fcmMocks = arrangeFCMMocks(); + fcmMocks.deleteToken.mockRejectedValue(new Error('MOCK FAIL')); + + const res = await services.deactivatePushNotifications( + MOCK_REG_TOKEN, + MOCK_JWT, + MOCK_TRIGGERS, + ); + + expect(res).toBe(false); + }); + }); + + describe('updateTriggerPushNotifications()', () => { + it('should update triggers for push notifications', async () => { + arrangeEndpoints(); + + const res = await services.updateTriggerPushNotifications( + MOCK_REG_TOKEN, + MOCK_JWT, + MOCK_TRIGGERS, + ); + + expect(res).toEqual({ + isTriggersLinkedToPushNotifications: true, + fcmToken: expect.any(String), + }); + }); + + it('should fail if unable to update triggers', async () => { + mockEndpointGetPushNotificationLinks(); + mockEndpointUpdatePushNotificationLinks({ status: 500 }); + + const res = await services.updateTriggerPushNotifications( + MOCK_REG_TOKEN, + MOCK_JWT, + MOCK_TRIGGERS, + ); + + expect(res).toEqual({ + isTriggersLinkedToPushNotifications: false, + fcmToken: expect.any(String), + }); + }); + }); + + function arrangeEndpoints() { + const mockGetLinksEndpoint = mockEndpointGetPushNotificationLinks(); + const mockUpdateLinksEndpoint = mockEndpointUpdatePushNotificationLinks(); + + return { + mockGetLinksEndpoint, + mockUpdateLinksEndpoint, + }; + } + + function arrangeFCMMocks() { + const mockFirebaseApp: FirebaseApp.FirebaseApp = { + name: '', + automaticDataCollectionEnabled: false, + options: {}, + }; + const mockFirebaseMessaging: FirebaseMessagingSW.Messaging = { + app: mockFirebaseApp, + }; + + jest.spyOn(FirebaseApp, 'getApp').mockReturnValue(mockFirebaseApp); + jest.spyOn(FirebaseApp, 'initializeApp').mockReturnValue(mockFirebaseApp); + + const getMessaging = jest + .spyOn(FirebaseMessagingSW, 'getMessaging') + .mockReturnValue(mockFirebaseMessaging); + const onBackgroundMessage = jest + .spyOn(FirebaseMessagingSW, 'onBackgroundMessage') + .mockReturnValue(() => jest.fn()); + + const getToken = jest + .spyOn(FirebaseMessaging, 'getToken') + .mockResolvedValue(MOCK_NEW_REG_TOKEN); + const deleteToken = jest + .spyOn(FirebaseMessaging, 'deleteToken') + .mockResolvedValue(true); + + return { + getMessaging, + onBackgroundMessage, + getToken, + deleteToken, + }; + } +}); diff --git a/app/scripts/controllers/push-platform-notifications/services/services.ts b/app/scripts/controllers/push-platform-notifications/services/services.ts new file mode 100644 index 000000000000..392cd22ad051 --- /dev/null +++ b/app/scripts/controllers/push-platform-notifications/services/services.ts @@ -0,0 +1,345 @@ +import { getToken, deleteToken } from 'firebase/messaging'; +import type { FirebaseApp } from 'firebase/app'; +import { getApp, initializeApp } from 'firebase/app'; +import { getMessaging, onBackgroundMessage } from 'firebase/messaging/sw'; +import type { Messaging, MessagePayload } from 'firebase/messaging/sw'; +import log from 'loglevel'; +import { + onNotificationClick, + onPushNotification, +} from '../utils/get-notification-message'; +import { + Notification, + NotificationUnion, +} from '../../metamask-notifications/types/types'; +import { processNotification } from '../../metamask-notifications/processors/process-notifications'; +import { REGISTRATION_TOKENS_ENDPOINT } from './endpoints'; + +const sw = self as unknown as ServiceWorkerGlobalScope; + +export type RegToken = { + token: string; + platform: 'extension' | 'mobile' | 'portfolio'; +}; + +export type LinksResult = { + trigger_ids: string[]; + registration_tokens: RegToken[]; +}; + +/** + * Attempts to retrieve an existing Firebase app instance. If no instance exists, it initializes a new app with the provided configuration. + * + * @returns The Firebase app instance. + */ +async function createFirebaseApp(): Promise { + try { + return getApp(); + } catch { + const firebaseConfig = { + apiKey: process.env.FIREBASE_API_KEY, + authDomain: process.env.FIREBASE_AUTH_DOMAIN, + storageBucket: process.env.FIREBASE_STORAGE_BUCKET, + projectId: process.env.FIREBASE_PROJECT_ID, + messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID, + appId: process.env.FIREBASE_APP_ID, + measurementId: process.env.FIREBASE_MEASUREMENT_ID, + }; + return initializeApp(firebaseConfig); + } +} + +/** + * Retrieves the Firebase Messaging service instance. + * + * This function first ensures a Firebase app instance is created or retrieved by calling `createFirebaseApp`. + * It then initializes and returns the Firebase Messaging service associated with the Firebase app. + * + * @returns A promise that resolves with the Firebase Messaging service instance. + */ +async function getFirebaseMessaging(): Promise { + const app = await createFirebaseApp(); + return getMessaging(app); +} + +/** + * Creates a registration token for Firebase Cloud Messaging. + * + * @returns A promise that resolves with the registration token or null if an error occurs. + */ +async function createRegToken(): Promise { + try { + const messaging = await getFirebaseMessaging(); + const token = await getToken(messaging, { + serviceWorkerRegistration: sw.registration, + vapidKey: process.env.VAPID_KEY, + }); + return token; + } catch { + return null; + } +} + +/** + * Deletes the Firebase Cloud Messaging registration token. + * + * @returns A promise that resolves with true if the token was successfully deleted, false otherwise. + */ +async function deleteRegToken(): Promise { + try { + const messaging = await getFirebaseMessaging(); + await deleteToken(messaging); + return true; + } catch (error) { + return false; + } +} + +/** + * Fetches push notification links from a remote endpoint using a BearerToken for authorization. + * + * @param bearerToken - The JSON Web Token used for authorization. + * @returns A promise that resolves with the links result or null if an error occurs. + */ +export async function getPushNotificationLinks( + bearerToken: string, +): Promise { + try { + const response = await fetch(REGISTRATION_TOKENS_ENDPOINT, { + headers: { Authorization: `Bearer ${bearerToken}` }, + }); + if (!response.ok) { + log.error('Failed to fetch the push notification links'); + throw new Error('Failed to fetch the push notification links'); + } + return response.json() as Promise; + } catch (error) { + log.error('Failed to fetch the push notification links', error); + return null; + } +} + +/** + * Updates the push notification links on a remote API. + * + * @param bearerToken - The JSON Web Token used for authorization. + * @param triggers - An array of trigger identifiers. + * @param regTokens - An array of registration tokens. + * @returns A promise that resolves with true if the update was successful, false otherwise. + */ +export async function updateLinksAPI( + bearerToken: string, + triggers: string[], + regTokens: RegToken[], +): Promise { + try { + const body: LinksResult = { + trigger_ids: triggers, + registration_tokens: regTokens, + }; + const response = await fetch(REGISTRATION_TOKENS_ENDPOINT, { + method: 'POST', + headers: { + Authorization: `Bearer ${bearerToken}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(body), + }); + return response.status === 200; + } catch { + return false; + } +} + +/** + * Enables push notifications by registering the device and linking triggers. + * + * @param bearerToken - The JSON Web Token used for authorization. + * @param triggers - An array of trigger identifiers. + * @returns A promise that resolves with an object containing the success status and the BearerToken token. + */ +export async function activatePushNotifications( + bearerToken: string, + triggers: string[], +): Promise { + const notificationLinks = await getPushNotificationLinks(bearerToken); + + if (!notificationLinks) { + return null; + } + + const regToken = await createRegToken().catch(() => null); + if (!regToken) { + return null; + } + + const newRegTokens = new Set(notificationLinks.registration_tokens); + newRegTokens.add({ token: regToken, platform: 'extension' }); + + await updateLinksAPI(bearerToken, triggers, Array.from(newRegTokens)); + return regToken; +} + +export async function listenToPushNotifications( + onNewNotification: (notification: Notification) => void, + onNotificationClicked: (notification: Notification) => void, +): Promise<() => void> { + /* + Push notifications require 2 listeners that need tracking (when creating and for tearing down): + 1. handling receiving a push notification (and the content we want to display) + 2. handling when a user clicks on a push notification + */ + + // Firebase + const messaging = await getFirebaseMessaging(); + const unsubscribePushNotifications = onBackgroundMessage( + messaging, + async (payload: MessagePayload): Promise => { + try { + const data = payload?.data?.data + ? JSON.parse(payload?.data?.data) + : undefined; + + // if the payload does not contain data, do nothing + if (!data) { + return; + } + + const notificationData = { + ...data, + type: data?.type ?? data?.data?.kind, + } as NotificationUnion; + + const notification = processNotification(notificationData); + onNewNotification(notification); + + await onPushNotification(notification); + } catch (error) { + // Do Nothing, cannot parse a bad notification + log.error('Unable to send push notification:', { + notification: payload?.data?.data, + error, + }); + throw new Error('Unable to send push notification'); + } + }, + ); + + // Notification Click Listener + const notificationClickHandler = (event: NotificationEvent) => { + onNotificationClick(event, onNotificationClicked); + }; + sw.addEventListener('notificationclick', notificationClickHandler); + const unsubscribeNotificationClicks = () => + sw.removeEventListener('notificationclick', notificationClickHandler); + + const unsubscribe = () => { + unsubscribePushNotifications(); + unsubscribeNotificationClicks(); + }; + + return unsubscribe; +} + +/** + * Handle Clicking Notifications. + */ + +/** + * Disables push notifications by removing the registration token and unlinking triggers. + * + * @param regToken - The registration token to be removed. + * @param bearerToken - The JSON Web Token used for authorization. + * @param triggers - An array of trigger identifiers to be unlinked. + * @returns A promise that resolves with true if notifications were successfully disabled, false otherwise. + */ +export async function deactivatePushNotifications( + regToken: string, + bearerToken: string, + triggers: string[], +): Promise { + // if we don't have a reg token, then we can early return + if (!regToken) { + return true; + } + + const notificationLinks = await getPushNotificationLinks(bearerToken); + if (!notificationLinks) { + return false; + } + + const filteredRegTokens = notificationLinks.registration_tokens.filter( + (r) => r.token !== regToken, + ); + + const isTokenRemovedFromAPI = await updateLinksAPI( + bearerToken, + triggers, + filteredRegTokens, + ); + if (!isTokenRemovedFromAPI) { + return false; + } + + const isTokenRemovedFromFCM = await deleteRegToken(); + if (!isTokenRemovedFromFCM) { + return false; + } + + return true; +} + +/** + * Updates the triggers linked to push notifications for a given registration token. + * If the provided registration token does not exist or is not in the current set of registration tokens, + * a new registration token is created and used for the update. + * + * @param regToken - The registration token to update triggers for. If null or not found, a new token will be created. + * @param bearerToken - The JSON Web Token used for authorization. + * @param triggers - An array of new trigger identifiers to link. + * @returns A promise that resolves with an object containing: + * - isTriggersLinkedToPushNotifications: boolean indicating if the triggers were successfully updated. + * - fcmToken: the new or existing Firebase Cloud Messaging token used for the update, if applicable. + */ +export async function updateTriggerPushNotifications( + regToken: string, + bearerToken: string, + triggers: string[], +): Promise<{ + isTriggersLinkedToPushNotifications: boolean; + fcmToken?: string | null; +}> { + const notificationLinks = await getPushNotificationLinks(bearerToken); + if (!notificationLinks) { + return { isTriggersLinkedToPushNotifications: false }; + } + // Create new registration token if doesn't exist + const hasRegToken = Boolean( + regToken && + notificationLinks.registration_tokens.some((r) => r.token === regToken), + ); + + let newRegToken: string | null = null; + if (!hasRegToken) { + await deleteRegToken(); + newRegToken = await createRegToken(); + if (!newRegToken) { + throw new Error('Failed to create a new registration token'); + } + notificationLinks.registration_tokens.push({ + token: newRegToken, + platform: 'extension', + }); + } + + const isTriggersLinkedToPushNotifications = await updateLinksAPI( + bearerToken, + triggers, + notificationLinks.registration_tokens, + ); + + return { + isTriggersLinkedToPushNotifications, + fcmToken: newRegToken ?? null, + }; +} diff --git a/app/scripts/controllers/push-platform-notifications/types/firebase.ts b/app/scripts/controllers/push-platform-notifications/types/firebase.ts new file mode 100644 index 000000000000..91dc2c2e4d6f --- /dev/null +++ b/app/scripts/controllers/push-platform-notifications/types/firebase.ts @@ -0,0 +1,46 @@ +export declare type Messaging = { + app: FirebaseApp; +}; + +export declare type FirebaseApp = { + readonly name: string; + readonly options: FirebaseOptions; + automaticDataCollectionEnabled: boolean; +}; + +export declare type FirebaseOptions = { + apiKey?: string; + authDomain?: string; + databaseURL?: string; + projectId?: string; + storageBucket?: string; + messagingSenderId?: string; + appId?: string; + measurementId?: string; +}; + +export type NotificationPayload = { + title?: string; + body?: string; + image?: string; + icon?: string; +}; + +export type FcmOptions = { + link?: string; + analyticsLabel?: string; +}; + +export type MessagePayload = { + notification?: NotificationPayload; + data?: { [key: string]: string }; + fcmOptions?: FcmOptions; + from: string; + collapseKey: string; + messageId: string; +}; + +export type GetTokenOptions = { + vapidKey?: string; + serviceWorkerRegistration?: ServiceWorkerRegistration; +}; diff --git a/app/scripts/controllers/push-platform-notifications/utils/get-notification-data.test.ts b/app/scripts/controllers/push-platform-notifications/utils/get-notification-data.test.ts new file mode 100644 index 000000000000..2ffbe89fdd9e --- /dev/null +++ b/app/scripts/controllers/push-platform-notifications/utils/get-notification-data.test.ts @@ -0,0 +1,80 @@ +import { + formatAmount, + getAmount, + getLeadingZeroCount, +} from './get-notification-data'; + +describe('getNotificationData - formatAmount() tests', () => { + test('Should format large numbers', () => { + expect(formatAmount(1000)).toBe('1K'); + expect(formatAmount(1500)).toBe('1.5K'); + expect(formatAmount(1000000)).toBe('1M'); + expect(formatAmount(1000000000)).toBe('1B'); + expect(formatAmount(1000000000000)).toBe('1T'); + expect(formatAmount(1234567)).toBe('1.23M'); + }); + + test('Should format smaller numbers (<1000) with custom decimal place', () => { + const formatOptions = { decimalPlaces: 18 }; + expect(formatAmount(100.0012, formatOptions)).toBe('100.0012'); + expect(formatAmount(100.001200001, formatOptions)).toBe('100.001200001'); + expect(formatAmount(1e-18, formatOptions)).toBe('0.000000000000000001'); + expect(formatAmount(1e-19, formatOptions)).toBe('0'); // number is smaller than decimals given, hence 0 + }); + + test('Should format small numbers (<1000) up to 4 decimals otherwise uses ellipses', () => { + const formatOptions = { shouldEllipse: true }; + expect(formatAmount(100.1, formatOptions)).toBe('100.1'); + expect(formatAmount(100.01, formatOptions)).toBe('100.01'); + expect(formatAmount(100.001, formatOptions)).toBe('100.001'); + expect(formatAmount(100.0001, formatOptions)).toBe('100.0001'); + expect(formatAmount(100.00001, formatOptions)).toBe('100.0000...'); // since number is has >4 decimals, it will be truncated + expect(formatAmount(0.00001, formatOptions)).toBe('0.0000...'); // since number is has >4 decimals, it will be truncated + }); + + test('Should format small numbers (<1000) to custom decimal places and ellipse', () => { + const formatOptions = { decimalPlaces: 2, shouldEllipse: true }; + expect(formatAmount(100.1, formatOptions)).toBe('100.1'); + expect(formatAmount(100.01, formatOptions)).toBe('100.01'); + expect(formatAmount(100.001, formatOptions)).toBe('100.00...'); + expect(formatAmount(100.0001, formatOptions)).toBe('100.00...'); + expect(formatAmount(100.00001, formatOptions)).toBe('100.00...'); // since number is has >2 decimals, it will be truncated + expect(formatAmount(0.00001, formatOptions)).toBe('0.00...'); // since number is has >2 decimals, it will be truncated + }); +}); + +describe('getNotificationData - getAmount() tests', () => { + test('Should get formatted amount for larger numbers', () => { + expect(getAmount('1', '2')).toBe('0.01'); + expect(getAmount('10', '2')).toBe('0.1'); + expect(getAmount('100', '2')).toBe('1'); + expect(getAmount('1000', '2')).toBe('10'); + expect(getAmount('10000', '2')).toBe('100'); + expect(getAmount('100000', '2')).toBe('1K'); + expect(getAmount('1000000', '2')).toBe('10K'); + }); + test('Should get formatted amount for small/decimal numbers', () => { + const formatOptions = { shouldEllipse: true }; + expect(getAmount('100000', '5', formatOptions)).toBe('1'); + expect(getAmount('100001', '5', formatOptions)).toBe('1.0000...'); + expect(getAmount('10000', '5', formatOptions)).toBe('0.1'); + expect(getAmount('1000', '5', formatOptions)).toBe('0.01'); + expect(getAmount('100', '5', formatOptions)).toBe('0.001'); + expect(getAmount('10', '5', formatOptions)).toBe('0.0001'); + expect(getAmount('1', '5', formatOptions)).toBe('0.0000...'); + }); +}); + +describe('getNotificationData - getLeadingZeroCount() tests', () => { + test('Should handle all test cases', () => { + expect(getLeadingZeroCount(0)).toBe(0); + expect(getLeadingZeroCount(-1)).toBe(0); + expect(getLeadingZeroCount(1e-1)).toBe(0); + + expect(getLeadingZeroCount('1.01')).toBe(1); + expect(getLeadingZeroCount('3e-2')).toBe(1); + expect(getLeadingZeroCount('100.001e1')).toBe(1); + + expect(getLeadingZeroCount('0.00120043')).toBe(2); + }); +}); diff --git a/app/scripts/controllers/push-platform-notifications/utils/get-notification-data.ts b/app/scripts/controllers/push-platform-notifications/utils/get-notification-data.ts new file mode 100644 index 000000000000..f95149c54c19 --- /dev/null +++ b/app/scripts/controllers/push-platform-notifications/utils/get-notification-data.ts @@ -0,0 +1,90 @@ +import { BigNumber } from 'bignumber.js'; +import { calcTokenAmount } from '../../../../../shared/lib/transactions-controller-utils'; + +type FormatOptions = { + decimalPlaces?: number; + shouldEllipse?: boolean; +}; +const defaultFormatOptions = { + decimalPlaces: 4, +}; + +/** + * Calculates the number of leading zeros in the fractional part of a number. + * + * This function converts a number or a string representation of a number into + * its decimal form and then counts the number of leading zeros present in the + * fractional part of the number. This is useful for determining the precision + * of very small numbers. + * + * @param num - The number to analyze, which can be in the form + * of a number or a string. + * @returns The count of leading zeros in the fractional part of the number. + */ +export const getLeadingZeroCount = (num: number | string) => { + const numToString = new BigNumber(num, 10).toString(10); + const fractionalPart = numToString.split('.')[1] ?? ''; + return fractionalPart.match(/^0*/u)?.[0]?.length || 0; +}; + +/** + * This formats a number using Intl + * It abbreviates large numbers (using K, M, B, T) + * And abbreviates small numbers in 2 ways: + * - Will format to the given number of decimal places + * - Will format up to 4 decimal places + * - Will ellipse the number if longer than given decimal places + * + * @param numericAmount - The number to format + * @param opts - The options to use when formatting + * @returns The formatted number + */ +export const formatAmount = (numericAmount: number, opts?: FormatOptions) => { + // create options with defaults + const options = { ...defaultFormatOptions, ...opts }; + + const leadingZeros = getLeadingZeroCount(numericAmount); + const isDecimal = numericAmount.toString().includes('.') || leadingZeros > 0; + const isLargeNumber = numericAmount > 999; + + const handleShouldEllipse = (decimalPlaces: number) => + Boolean(options?.shouldEllipse) && leadingZeros >= decimalPlaces; + + if (isLargeNumber) { + return Intl.NumberFormat('en-US', { + notation: 'compact', + compactDisplay: 'short', + maximumFractionDigits: 2, + }).format(numericAmount); + } + + if (isDecimal) { + const ellipse = handleShouldEllipse(options.decimalPlaces); + const formattedValue = Intl.NumberFormat('en-US', { + minimumFractionDigits: ellipse ? options.decimalPlaces : undefined, + maximumFractionDigits: options.decimalPlaces, + }).format(numericAmount); + + return ellipse ? `${formattedValue}...` : formattedValue; + } + + // Default to showing the raw amount + return numericAmount.toString(); +}; + +export const getAmount = ( + amount: string, + decimals: string, + options?: FormatOptions, +) => { + if (!amount || !decimals) { + return ''; + } + + const numericAmount = calcTokenAmount( + amount, + parseFloat(decimals), + ).toNumber(); + + return formatAmount(numericAmount, options); +}; diff --git a/app/scripts/controllers/push-platform-notifications/utils/get-notification-image.ts b/app/scripts/controllers/push-platform-notifications/utils/get-notification-image.ts new file mode 100644 index 000000000000..3dbaf951b3d0 --- /dev/null +++ b/app/scripts/controllers/push-platform-notifications/utils/get-notification-image.ts @@ -0,0 +1,6 @@ +import browser from 'webextension-polyfill'; + +export async function getNotificationImage() { + const iconUrl = await browser.runtime.getURL('../../images/icon-64.png'); + return iconUrl; +} diff --git a/app/scripts/controllers/push-platform-notifications/utils/get-notification-message.test.ts b/app/scripts/controllers/push-platform-notifications/utils/get-notification-message.test.ts new file mode 100644 index 000000000000..fdbe7e345104 --- /dev/null +++ b/app/scripts/controllers/push-platform-notifications/utils/get-notification-message.test.ts @@ -0,0 +1,177 @@ +import { + createMockNotificationERC1155Received, + createMockNotificationERC1155Sent, + createMockNotificationERC20Received, + createMockNotificationERC20Sent, + createMockNotificationERC721Received, + createMockNotificationERC721Sent, + createMockNotificationEthReceived, + createMockNotificationEthSent, + createMockNotificationLidoReadyToBeWithdrawn, + createMockNotificationLidoStakeCompleted, + createMockNotificationLidoWithdrawalCompleted, + createMockNotificationLidoWithdrawalRequested, + createMockNotificationMetaMaskSwapsCompleted, + createMockNotificationRocketPoolStakeCompleted, + createMockNotificationRocketPoolUnStakeCompleted, +} from '../../metamask-notifications/mocks/mock-raw-notifications'; +import { processNotification } from '../../metamask-notifications/processors/process-notifications'; +import { createNotificationMessage } from './get-notification-message'; + +describe('notification-message tests', () => { + test('displays erc20 sent notification', () => { + const notification = processNotification(createMockNotificationERC20Sent()); + const result = createNotificationMessage(notification); + + expect(result?.title).toBe('Funds sent'); + expect(result?.description).toContain('You successfully sent 4.96K USDC'); + }); + + test('displays erc20 received notification', () => { + const notification = processNotification( + createMockNotificationERC20Received(), + ); + const result = createNotificationMessage(notification); + + expect(result?.title).toBe('Funds received'); + expect(result?.description).toContain('You received 8.38B SHIB'); + }); + + test('displays eth/native sent notification', () => { + const notification = processNotification(createMockNotificationEthSent()); + const result = createNotificationMessage(notification); + + expect(result?.title).toBe('Funds sent'); + expect(result?.description).toContain('You successfully sent 0.005 ETH'); + }); + + test('displays eth/native received notification', () => { + const notification = processNotification( + createMockNotificationEthReceived(), + ); + const result = createNotificationMessage(notification); + + expect(result?.title).toBe('Funds received'); + expect(result?.description).toContain('You received 808 ETH'); + }); + + test('displays metamask swap completed notification', () => { + const notification = processNotification( + createMockNotificationMetaMaskSwapsCompleted(), + ); + const result = createNotificationMessage(notification); + + expect(result?.title).toBe('Swap completed'); + expect(result?.description).toContain('Your MetaMask Swap was successful'); + }); + + test('displays erc721 sent notification', () => { + const notification = processNotification( + createMockNotificationERC721Sent(), + ); + const result = createNotificationMessage(notification); + + expect(result?.title).toBe('NFT sent'); + expect(result?.description).toContain('You have successfully sent an NFT'); + }); + + test('displays erc721 received notification', () => { + const notification = processNotification( + createMockNotificationERC721Received(), + ); + const result = createNotificationMessage(notification); + + expect(result?.title).toBe('NFT received'); + expect(result?.description).toContain('You received new NFTs'); + }); + + test('displays erc1155 sent notification', () => { + const notification = processNotification( + createMockNotificationERC1155Sent(), + ); + const result = createNotificationMessage(notification); + + expect(result?.title).toBe('NFT sent'); + expect(result?.description).toContain('You have successfully sent an NFT'); + }); + + test('displays erc1155 received notification', () => { + const notification = processNotification( + createMockNotificationERC1155Received(), + ); + const result = createNotificationMessage(notification); + + expect(result?.title).toBe('NFT received'); + expect(result?.description).toContain('You received new NFTs'); + }); + + test('displays rocketpool stake completed notification', () => { + const notification = processNotification( + createMockNotificationRocketPoolStakeCompleted(), + ); + const result = createNotificationMessage(notification); + + expect(result?.title).toBe('Stake complete'); + expect(result?.description).toContain( + 'Your RocketPool stake was successful', + ); + }); + + test('displays rocketpool unstake completed notification', () => { + const notification = processNotification( + createMockNotificationRocketPoolUnStakeCompleted(), + ); + const result = createNotificationMessage(notification); + + expect(result?.title).toBe('Unstake complete'); + expect(result?.description).toContain( + 'Your RocketPool unstake was successful', + ); + }); + + test('displays lido stake completed notification', () => { + const notification = processNotification( + createMockNotificationLidoStakeCompleted(), + ); + const result = createNotificationMessage(notification); + + expect(result?.title).toBe('Stake complete'); + expect(result?.description).toContain('Your Lido stake was successful'); + }); + + test('displays lido stake ready to be withdrawn notification', () => { + const notification = processNotification( + createMockNotificationLidoReadyToBeWithdrawn(), + ); + const result = createNotificationMessage(notification); + + expect(result?.title).toBe('Stake ready for withdrawal'); + expect(result?.description).toContain( + 'Your Lido stake is now ready to be withdrawn', + ); + }); + + test('displays lido withdrawal requested notification', () => { + const notification = processNotification( + createMockNotificationLidoWithdrawalRequested(), + ); + const result = createNotificationMessage(notification); + + expect(result?.title).toBe('Withdrawal requested'); + expect(result?.description).toContain( + 'Your Lido withdrawal request was submitted', + ); + }); + + test('displays lido withdrawal completed notification', () => { + const notification = processNotification( + createMockNotificationLidoWithdrawalCompleted(), + ); + const result = createNotificationMessage(notification); + + expect(result?.title).toBe('Withdrawal completed'); + expect(result?.description).toContain( + 'Your Lido withdrawal was successful', + ); + }); +}); diff --git a/app/scripts/controllers/push-platform-notifications/utils/get-notification-message.ts b/app/scripts/controllers/push-platform-notifications/utils/get-notification-message.ts new file mode 100644 index 000000000000..514c5b40fadc --- /dev/null +++ b/app/scripts/controllers/push-platform-notifications/utils/get-notification-message.ts @@ -0,0 +1,264 @@ +// We are defining that this file uses a webworker global scope. +// eslint-disable-next-line spaced-comment +/// + +import { CHAIN_SYMBOLS } from '../../metamask-notifications/constants/notification-schema'; +import type { TRIGGER_TYPES } from '../../metamask-notifications/constants/notification-schema'; +import type { OnChainRawNotification } from '../../metamask-notifications/types/on-chain-notification/on-chain-notification'; +import { t } from '../../../translate'; +import type { Notification } from '../../metamask-notifications/types/types'; +import ExtensionPlatform from '../../../platforms/extension'; +import { getAmount, formatAmount } from './get-notification-data'; +import { getNotificationImage } from './get-notification-image'; + +type PushNotificationMessage = { + title: string; + description: string; +}; + +type NotificationMessage = { + title: string | null; + defaultDescription: string | null; + getDescription?: (n: N) => string | null; +}; + +type NotificationMessageDict = { + [K in TRIGGER_TYPES]?: NotificationMessage< + Extract + >; +}; + +const sw = self as unknown as ServiceWorkerGlobalScope; +const extensionPlatform = new ExtensionPlatform(); + +function getChainSymbol(chainId: number) { + return CHAIN_SYMBOLS[chainId] ?? null; +} + +export async function onPushNotification( + notification: Notification, +): Promise { + const notificationMessage = createNotificationMessage(notification); + if (!notificationMessage) { + return; + } + + const registration = sw?.registration; + if (!registration) { + return; + } + + const iconUrl = await getNotificationImage(); + + await registration.showNotification(notificationMessage.title, { + body: notificationMessage.description, + icon: iconUrl, + tag: notification?.id, + data: notification, + }); +} + +export async function onNotificationClick( + event: NotificationEvent, + emitEvent?: (n: Notification) => void, +) { + // Close notification + event.notification.close(); + + // Get Data + const data: Notification = event?.notification?.data; + emitEvent?.(data); + + // Navigate + const destination = `${extensionPlatform.getExtensionURL( + null, + null, + )}#notifications/${data.id}`; + event.waitUntil(sw.clients.openWindow(destination)); +} + +export function isOnChainNotification(n: unknown): n is OnChainRawNotification { + const assumed = n as OnChainRawNotification; + + // We don't have a validation/parsing library to check all possible types of an on chain notification + // It is safe enough just to check "some" fields, and catch any errors down the line if the shape is bad. + const isValidEnoughToBeOnChainNotification = [ + assumed?.id, + assumed?.data, + assumed?.trigger_id, + ].every((field) => field !== undefined); + return isValidEnoughToBeOnChainNotification; +} + +const notificationMessageDict: NotificationMessageDict = { + erc20_sent: { + title: t('pushPlatformNotificationsFundsSentTitle'), + defaultDescription: t( + 'pushPlatformNotificationsFundsSentDescriptionDefault', + ), + getDescription: (n) => { + const symbol = n?.data?.token?.symbol; + const tokenAmount = n?.data?.token?.amount; + const tokenDecimals = n?.data?.token?.decimals; + if (!symbol || !tokenAmount || !tokenDecimals) { + return null; + } + + const amount = getAmount(tokenAmount, tokenDecimals, { + shouldEllipse: true, + }); + return t('pushPlatformNotificationsFundsSentDescription', amount, symbol); + }, + }, + eth_sent: { + title: t('pushPlatformNotificationsFundsSentTitle'), + defaultDescription: t( + 'pushPlatformNotificationsFundsSentDescriptionDefault', + ), + getDescription: (n) => { + const symbol = getChainSymbol(n?.chain_id); + const tokenAmount = n?.data?.amount?.eth; + if (!symbol || !tokenAmount) { + return null; + } + + const amount = formatAmount(parseFloat(tokenAmount), { + shouldEllipse: true, + }); + return t('pushPlatformNotificationsFundsSentDescription', amount, symbol); + }, + }, + erc20_received: { + title: t('pushPlatformNotificationsFundsReceivedTitle'), + defaultDescription: t( + 'pushPlatformNotificationsFundsReceivedDescriptionDefault', + ), + getDescription: (n) => { + const symbol = n?.data?.token?.symbol; + const tokenAmount = n?.data?.token?.amount; + const tokenDecimals = n?.data?.token?.decimals; + if (!symbol || !tokenAmount || !tokenDecimals) { + return null; + } + + const amount = getAmount(tokenAmount, tokenDecimals, { + shouldEllipse: true, + }); + return t( + 'pushPlatformNotificationsFundsReceivedDescription', + amount, + symbol, + ); + }, + }, + eth_received: { + title: t('pushPlatformNotificationsFundsReceivedTitle'), + defaultDescription: t( + 'pushPlatformNotificationsFundsReceivedDescriptionDefault', + ), + getDescription: (n) => { + const symbol = getChainSymbol(n?.chain_id); + const tokenAmount = n?.data?.amount?.eth; + if (!symbol || !tokenAmount) { + return null; + } + + const amount = formatAmount(parseFloat(tokenAmount), { + shouldEllipse: true, + }); + return t( + 'pushPlatformNotificationsFundsReceivedDescription', + amount, + symbol, + ); + }, + }, + metamask_swap_completed: { + title: t('pushPlatformNotificationsSwapCompletedTitle'), + defaultDescription: t('pushPlatformNotificationsSwapCompletedDescription'), + }, + erc721_sent: { + title: t('pushPlatformNotificationsNftSentTitle'), + defaultDescription: t('pushPlatformNotificationsNftSentDescription'), + }, + erc1155_sent: { + title: t('pushPlatformNotificationsNftSentTitle'), + defaultDescription: t('pushPlatformNotificationsNftSentDescription'), + }, + erc721_received: { + title: t('pushPlatformNotificationsNftReceivedTitle'), + defaultDescription: t('pushPlatformNotificationsNftReceivedDescription'), + }, + erc1155_received: { + title: t('pushPlatformNotificationsNftReceivedTitle'), + defaultDescription: t('pushPlatformNotificationsNftReceivedDescription'), + }, + rocketpool_stake_completed: { + title: t('pushPlatformNotificationsStakingRocketpoolStakeCompletedTitle'), + defaultDescription: t( + 'pushPlatformNotificationsStakingRocketpoolStakeCompletedDescription', + ), + }, + rocketpool_unstake_completed: { + title: t('pushPlatformNotificationsStakingRocketpoolUnstakeCompletedTitle'), + defaultDescription: t( + 'pushPlatformNotificationsStakingRocketpoolUnstakeCompletedDescription', + ), + }, + lido_stake_completed: { + title: t('pushPlatformNotificationsStakingLidoStakeCompletedTitle'), + defaultDescription: t( + 'pushPlatformNotificationsStakingLidoStakeCompletedDescription', + ), + }, + lido_stake_ready_to_be_withdrawn: { + title: t( + 'pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnTitle', + ), + defaultDescription: t( + 'pushPlatformNotificationsStakingLidoStakeReadyToBeWithdrawnDescription', + ), + }, + lido_withdrawal_requested: { + title: t('pushPlatformNotificationsStakingLidoWithdrawalRequestedTitle'), + defaultDescription: t( + 'pushPlatformNotificationsStakingLidoWithdrawalRequestedDescription', + ), + }, + lido_withdrawal_completed: { + title: t('pushPlatformNotificationsStakingLidoWithdrawalCompletedTitle'), + defaultDescription: t( + 'pushPlatformNotificationsStakingLidoWithdrawalCompletedDescription', + ), + }, +}; + +export function createNotificationMessage( + n: Notification, +): PushNotificationMessage | null { + if (!n?.type) { + return null; + } + const notificationMessage = notificationMessageDict[n.type] as + | NotificationMessage + | undefined; + + if (!notificationMessage) { + return null; + } + + let description: string | null = null; + try { + description = + notificationMessage?.getDescription?.(n) ?? + notificationMessage.defaultDescription ?? + null; + } catch (e) { + description = notificationMessage.defaultDescription ?? null; + } + + return { + title: notificationMessage.title ?? '', // Ensure title is always a string + description: description ?? '', // Fallback to empty string if null + }; +} diff --git a/app/scripts/controllers/swaps.constants.ts b/app/scripts/controllers/swaps.constants.ts new file mode 100644 index 000000000000..d959c02c439e --- /dev/null +++ b/app/scripts/controllers/swaps.constants.ts @@ -0,0 +1,50 @@ +import { + FALLBACK_SMART_TRANSACTIONS_MAX_FEE_MULTIPLIER, + FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME, +} from '../../../shared/constants/smartTransactions'; +import { MINUTE } from '../../../shared/constants/time'; + +import type { SwapsControllerState } from './swaps.types'; + +// The MAX_GAS_LIMIT is a number that is higher than the maximum gas costs we have observed on any aggregator +export const MAX_GAS_LIMIT = 2500000; + +// To ensure that our serves are not spammed if MetaMask is left idle, we limit the number of fetches for quotes that are made on timed intervals. +// 3 seems to be an appropriate balance of giving users the time they need when MetaMask is not left idle, and turning polling off when it is. +export const POLL_COUNT_LIMIT = 3; + +// If for any reason the MetaSwap API fails to provide a refresh time, +// provide a reasonable fallback to avoid further errors +export const FALLBACK_QUOTE_REFRESH_TIME = MINUTE; + +export const swapsControllerInitialState: { swapsState: SwapsControllerState } = + { + swapsState: { + quotes: {}, + quotesPollingLimitEnabled: false, + fetchParams: null, + tokens: null, + tradeTxId: null, + approveTxId: null, + quotesLastFetched: null, + customMaxGas: '', + customGasPrice: null, + customMaxFeePerGas: null, + customMaxPriorityFeePerGas: null, + swapsUserFeeLevel: '', + selectedAggId: null, + customApproveTxData: '', + errorKey: '', + topAggId: null, + routeState: '', + swapsFeatureIsLive: true, + saveFetchedQuotes: false, + swapsQuoteRefreshTime: FALLBACK_QUOTE_REFRESH_TIME, + swapsQuotePrefetchingRefreshTime: FALLBACK_QUOTE_REFRESH_TIME, + swapsStxBatchStatusRefreshTime: FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME, + swapsStxGetTransactionsRefreshTime: + FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME, + swapsStxMaxFeeMultiplier: FALLBACK_SMART_TRANSACTIONS_MAX_FEE_MULTIPLIER, + swapsFeatureFlags: {}, + }, + }; diff --git a/app/scripts/controllers/swaps.test.js b/app/scripts/controllers/swaps.test.js index a7ebd0aaed74..e5059467532d 100644 --- a/app/scripts/controllers/swaps.test.js +++ b/app/scripts/controllers/swaps.test.js @@ -1,6 +1,3 @@ -import { strict as assert } from 'assert'; -import sinon from 'sinon'; - import { BigNumber } from '@ethersproject/bignumber'; import { mapValues } from 'lodash'; import BigNumberjs from 'bignumber.js'; @@ -13,7 +10,8 @@ import { FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME, FALLBACK_SMART_TRANSACTIONS_MAX_FEE_MULTIPLIER, } from '../../../shared/constants/smartTransactions'; -import SwapsController, { utils } from './swaps'; +import SwapsController from './swaps'; +import { getMedianEthValueQuote } from './swaps.utils'; const MOCK_FETCH_PARAMS = { slippage: 3, @@ -81,9 +79,11 @@ const MOCK_FETCH_METADATA = { }; const MOCK_TOKEN_RATES_STORE = () => ({ - contractExchangeRates: { - '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48': 2, - '0x1111111111111111111111111111111111111111': 0.1, + marketData: { + '0x1': { + '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48': { price: 2 }, + '0x1111111111111111111111111111111111111111': { price: 0.1 }, + }, }, }); @@ -125,17 +125,15 @@ const EMPTY_INIT_STATE = { }, }; -const sandbox = sinon.createSandbox(); -let fetchTradesInfoStub = sandbox.stub(); -const getCurrentChainIdStub = sandbox.stub(); -getCurrentChainIdStub.returns(CHAIN_IDS.MAINNET); -const getEIP1559GasFeeEstimatesStub = sandbox.stub(() => { - return { - gasFeeEstimates: { - high: '150', - }, - gasEstimateType: GasEstimateTypes.legacy, - }; +const fetchTradesInfoStub = jest.fn(); +const getCurrentChainIdStub = jest.fn().mockReturnValue(CHAIN_IDS.MAINNET); +const getLayer1GasFeeStub = jest.fn().mockReturnValue('0x1'); +const getNetworkClientIdStub = jest.fn().mockReturnValue('1'); +const getEIP1559GasFeeEstimatesStub = jest.fn().mockReturnValue({ + gasFeeEstimates: { + high: '150', + }, + gasEstimateType: GasEstimateTypes.legacy, }); describe('SwapsController', function () { @@ -150,10 +148,12 @@ describe('SwapsController', function () { fetchTradesInfo: fetchTradesInfoStub, getCurrentChainId: getCurrentChainIdStub, getEIP1559GasFeeEstimates: getEIP1559GasFeeEstimatesStub, + getNetworkClientId: getNetworkClientIdStub, + getLayer1GasFee: getLayer1GasFeeStub, }); }; - before(function () { + beforeEach(function () { const providerResultStub = { // 1 gwei eth_gasPrice: '0x0de0b6b3a7640000', @@ -165,26 +165,23 @@ describe('SwapsController', function () { networkId: 1, chainId: 1, }).provider; + jest.useFakeTimers(); }); afterEach(function () { - sandbox.restore(); + jest.useRealTimers(); + jest.restoreAllMocks(); }); describe('constructor', function () { it('should setup correctly', function () { const swapsController = getSwapsController(); - assert.deepStrictEqual( - swapsController.store.getState(), - EMPTY_INIT_STATE, - ); - assert.deepStrictEqual( - swapsController.getBufferedGasLimit, + expect(swapsController.store.getState()).toStrictEqual(EMPTY_INIT_STATE); + expect(swapsController.getBufferedGasLimit).toStrictEqual( MOCK_GET_BUFFERED_GAS_LIMIT, ); - assert.strictEqual(swapsController.pollCount, 0); - assert.deepStrictEqual( - swapsController.getProviderConfig, + expect(swapsController._pollCount).toStrictEqual(0); + expect(swapsController.getProviderConfig).toStrictEqual( MOCK_GET_PROVIDER_CONFIG, ); }); @@ -200,64 +197,57 @@ describe('SwapsController', function () { it('should set selected quote agg id', function () { const selectedAggId = 'test'; swapsController.setSelectedQuoteAggId(selectedAggId); - assert.deepStrictEqual( + expect( swapsController.store.getState().swapsState.selectedAggId, - selectedAggId, - ); + ).toStrictEqual(selectedAggId); }); it('should set swaps tokens', function () { const tokens = []; swapsController.setSwapsTokens(tokens); - assert.deepStrictEqual( + expect( swapsController.store.getState().swapsState.tokens, - tokens, - ); + ).toStrictEqual(tokens); }); it('should set trade tx id', function () { const tradeTxId = 'test'; swapsController.setTradeTxId(tradeTxId); - assert.strictEqual( + expect( swapsController.store.getState().swapsState.tradeTxId, - tradeTxId, - ); + ).toStrictEqual(tradeTxId); }); it('should set swaps tx gas price', function () { const gasPrice = 1; swapsController.setSwapsTxGasPrice(gasPrice); - assert.deepStrictEqual( + expect( swapsController.store.getState().swapsState.customGasPrice, - gasPrice, - ); + ).toStrictEqual(gasPrice); }); it('should set swaps tx gas limit', function () { const gasLimit = '1'; swapsController.setSwapsTxGasLimit(gasLimit); - assert.deepStrictEqual( + expect( swapsController.store.getState().swapsState.customMaxGas, - gasLimit, - ); + ).toStrictEqual(gasLimit); }); it('should set background swap route state', function () { const routeState = 'test'; swapsController.setBackgroundSwapRouteState(routeState); - assert.deepStrictEqual( + expect( swapsController.store.getState().swapsState.routeState, - routeState, - ); + ).toStrictEqual(routeState); }); it('should set swaps error key', function () { const errorKey = 'test'; swapsController.setSwapsErrorKey(errorKey); - assert.deepStrictEqual( + expect( swapsController.store.getState().swapsState.errorKey, - errorKey, - ); + ).toStrictEqual(errorKey); }); it('should set initial gas estimate', async function () { @@ -280,9 +270,9 @@ describe('SwapsController', function () { await swapsController.getBufferedGasLimit(); const { gasEstimate, gasEstimateWithRefund } = swapsController.store.getState().swapsState.quotes[initialAggId]; - assert.strictEqual(gasEstimate, bufferedGasLimit); - assert.strictEqual( - gasEstimateWithRefund, + + expect(gasEstimate).toStrictEqual(bufferedGasLimit); + expect(gasEstimateWithRefund).toStrictEqual( `0x${new BigNumberjs(maxGas, 10) .minus(estimatedRefund, 10) .toString(16)}`, @@ -292,10 +282,9 @@ describe('SwapsController', function () { it('should set custom approve tx data', function () { const data = 'test'; swapsController.setCustomApproveTxData(data); - assert.deepStrictEqual( + expect( swapsController.store.getState().swapsState.customApproveTxData, - data, - ); + ).toStrictEqual(data); }); }); @@ -308,14 +297,13 @@ describe('SwapsController', function () { }); it('returns empty object if passed undefined or empty object', async function () { - assert.deepStrictEqual( + expect( await swapsController._findTopQuoteAndCalculateSavings(), - {}, - ); - assert.deepStrictEqual( + ).toStrictEqual({}); + + expect( await swapsController._findTopQuoteAndCalculateSavings({}), - {}, - ); + ).toStrictEqual({}); }); it('returns the top aggId and quotes with savings and fee values if passed necessary data and an even number of quotes', async function () { @@ -323,9 +311,8 @@ describe('SwapsController', function () { await swapsController._findTopQuoteAndCalculateSavings( getTopQuoteAndSavingsMockQuotes(), ); - assert.equal(topAggId, TEST_AGG_ID_1); - assert.deepStrictEqual( - resultQuotes, + expect(topAggId).toStrictEqual(TEST_AGG_ID_1); + expect(resultQuotes).toStrictEqual( getTopQuoteAndSavingsBaseExpectedResults(), ); }); @@ -345,8 +332,8 @@ describe('SwapsController', function () { const [topAggId, resultQuotes] = await swapsController._findTopQuoteAndCalculateSavings(testInput); - assert.equal(topAggId, TEST_AGG_ID_1); - assert.deepStrictEqual(resultQuotes, expectedResultQuotes); + expect(topAggId).toStrictEqual(TEST_AGG_ID_1); + expect(resultQuotes).toStrictEqual(expectedResultQuotes); }); it('returns the top aggId, without best quote flagged, and quotes with fee values if passed necessary data but no custom convert rate exists', async function () { @@ -386,8 +373,8 @@ describe('SwapsController', function () { const [topAggId, resultQuotes] = await swapsController._findTopQuoteAndCalculateSavings(testInput); - assert.equal(topAggId, TEST_AGG_ID_1); - assert.deepStrictEqual(resultQuotes, expectedResultQuotes); + expect(topAggId).toStrictEqual(TEST_AGG_ID_1); + expect(resultQuotes).toStrictEqual(expectedResultQuotes); }); it('returns the top aggId and quotes with savings and fee values if passed necessary data and the source token is ETH', async function () { @@ -449,8 +436,8 @@ describe('SwapsController', function () { const [topAggId, resultQuotes] = await swapsController._findTopQuoteAndCalculateSavings(testInput); - assert.equal(topAggId, TEST_AGG_ID_1); - assert.deepStrictEqual(resultQuotes, expectedResultQuotes); + expect(topAggId).toStrictEqual(TEST_AGG_ID_1); + expect(resultQuotes).toStrictEqual(expectedResultQuotes); }); it('returns the top aggId and quotes with savings and fee values if passed necessary data and the source token is ETH and an ETH fee is included in the trade value of what would be the best quote', async function () { @@ -525,8 +512,8 @@ describe('SwapsController', function () { const [topAggId, resultQuotes] = await swapsController._findTopQuoteAndCalculateSavings(testInput); - assert.equal(topAggId, TEST_AGG_ID_2); - assert.deepStrictEqual(resultQuotes, expectedResultQuotes); + expect(topAggId).toStrictEqual(TEST_AGG_ID_2); + expect(resultQuotes).toStrictEqual(expectedResultQuotes); }); it('returns the top aggId and quotes with savings and fee values if passed necessary data and the source token is not ETH and an ETH fee is included in the trade value of what would be the best quote', async function () { @@ -560,31 +547,36 @@ describe('SwapsController', function () { const [topAggId, resultQuotes] = await swapsController._findTopQuoteAndCalculateSavings(testInput); - assert.equal(topAggId, TEST_AGG_ID_2); - assert.deepStrictEqual(resultQuotes, expectedResultQuotes); + expect(topAggId).toStrictEqual(TEST_AGG_ID_2); + expect(resultQuotes).toStrictEqual(expectedResultQuotes); }); }); describe('fetchAndSetQuotes', function () { it('returns null if fetchParams is not provided', async function () { const quotes = await swapsController.fetchAndSetQuotes(undefined); - assert.strictEqual(quotes, null); + expect(quotes).toStrictEqual(null); }); it('calls fetchTradesInfo with the given fetchParams and returns the correct quotes', async function () { - fetchTradesInfoStub.resolves(getMockQuotes()); + const fetchTradesInfoSpy = jest + .spyOn(swapsController, '_fetchTradesInfo') + .mockReturnValue(getMockQuotes()); // Make it so approval is not required - sandbox - .stub(swapsController, '_getERC20Allowance') - .resolves(BigNumber.from(1)); + jest + .spyOn(swapsController, '_getERC20Allowance') + .mockReturnValue(BigNumber.from(1)); + + // Make the network fetch error message disappear + jest.spyOn(swapsController, '_setSwapsNetworkConfig').mockReturnValue(); const [newQuotes] = await swapsController.fetchAndSetQuotes( MOCK_FETCH_PARAMS, MOCK_FETCH_METADATA, ); - assert.deepStrictEqual(newQuotes[TEST_AGG_ID_BEST], { + expect(newQuotes[TEST_AGG_ID_BEST]).toStrictEqual({ ...getMockQuotes()[TEST_AGG_ID_BEST], sourceTokenInfo: undefined, destinationTokenInfo: { @@ -607,16 +599,15 @@ describe('SwapsController', function () { metaMaskFeeInEth: '0.50505050505050505050505050505050505', ethValueOfTokens: '50', }); - assert.strictEqual( - fetchTradesInfoStub.calledOnceWithExactly(MOCK_FETCH_PARAMS, { - ...MOCK_FETCH_METADATA, - }), - true, - ); + + expect(fetchTradesInfoSpy).toHaveBeenCalledTimes(1); + expect(fetchTradesInfoSpy).toHaveBeenCalledWith(MOCK_FETCH_PARAMS, { + ...MOCK_FETCH_METADATA, + }); }); it('calls returns the correct quotes on the optimism chain', async function () { - fetchTradesInfoStub.resetHistory(); + fetchTradesInfoStub.mockReset(); const OPTIMISM_MOCK_FETCH_METADATA = { ...MOCK_FETCH_METADATA, chainId: CHAIN_IDS.OPTIMISM, @@ -637,19 +628,24 @@ describe('SwapsController', function () { swapsController = getSwapsController(optimismProvider); - fetchTradesInfoStub.resolves(getMockQuotes()); + const fetchTradesInfoSpy = jest + .spyOn(swapsController, '_fetchTradesInfo') + .mockReturnValue(getMockQuotes()); // Make it so approval is not required - sandbox - .stub(swapsController, '_getERC20Allowance') - .resolves(BigNumber.from(1)); + jest + .spyOn(swapsController, '_getERC20Allowance') + .mockReturnValue(BigNumber.from(1)); + + // Make the network fetch error message disappear + jest.spyOn(swapsController, '_setSwapsNetworkConfig').mockReturnValue(); const [newQuotes] = await swapsController.fetchAndSetQuotes( MOCK_FETCH_PARAMS, OPTIMISM_MOCK_FETCH_METADATA, ); - assert.deepStrictEqual(newQuotes[TEST_AGG_ID_BEST], { + expect(newQuotes[TEST_AGG_ID_BEST]).toStrictEqual({ ...getMockQuotes()[TEST_AGG_ID_BEST], sourceTokenInfo: undefined, destinationTokenInfo: { @@ -667,55 +663,62 @@ describe('SwapsController', function () { total: '5.43388249494949494949494949494949495', medianMetaMaskFee: '0.444444444444444444444444444444444444', }, - ethFee: '0.113822', - multiLayerL1TradeFeeTotal: '0x0103c18816d4e8', - overallValueOfQuote: '49.886178', + ethFee: '0.113536', + multiLayerL1TradeFeeTotal: '0x1', + overallValueOfQuote: '49.886464', metaMaskFeeInEth: '0.50505050505050505050505050505050505', ethValueOfTokens: '50', }); - assert.strictEqual( - fetchTradesInfoStub.calledOnceWithExactly(MOCK_FETCH_PARAMS, { - ...OPTIMISM_MOCK_FETCH_METADATA, - }), - true, - ); + + expect(fetchTradesInfoSpy).toHaveBeenCalledTimes(1); + expect(fetchTradesInfoSpy).toHaveBeenCalledWith(MOCK_FETCH_PARAMS, { + ...OPTIMISM_MOCK_FETCH_METADATA, + }); }); it('performs the allowance check', async function () { - fetchTradesInfoStub.resolves(getMockQuotes()); + jest + .spyOn(swapsController, '_fetchTradesInfo') + .mockReturnValue(getMockQuotes()); // Make it so approval is not required - const allowanceStub = sandbox - .stub(swapsController, '_getERC20Allowance') - .resolves(BigNumber.from(1)); + const getERC20AllowanceSpy = jest + .spyOn(swapsController, '_getERC20Allowance') + .mockReturnValue(BigNumber.from(1)); + + // Make the network fetch error message disappear + jest.spyOn(swapsController, '_setSwapsNetworkConfig').mockReturnValue(); await swapsController.fetchAndSetQuotes( MOCK_FETCH_PARAMS, MOCK_FETCH_METADATA, ); - assert.strictEqual( - allowanceStub.calledOnceWithExactly( - MOCK_FETCH_PARAMS.sourceToken, - MOCK_FETCH_PARAMS.fromAddress, - CHAIN_IDS.MAINNET, - ), - true, + expect(getERC20AllowanceSpy).toHaveBeenCalledTimes(1); + expect(getERC20AllowanceSpy).toHaveBeenCalledWith( + MOCK_FETCH_PARAMS.sourceToken, + MOCK_FETCH_PARAMS.fromAddress, + CHAIN_IDS.MAINNET, ); }); it('gets the gas limit if approval is required', async function () { - fetchTradesInfoStub.resolves(MOCK_QUOTES_APPROVAL_REQUIRED); + jest + .spyOn(swapsController, '_fetchTradesInfo') + .mockReturnValue(MOCK_QUOTES_APPROVAL_REQUIRED); // Ensure approval is required - sandbox - .stub(swapsController, '_getERC20Allowance') - .resolves(BigNumber.from(0)); + jest + .spyOn(swapsController, '_getERC20Allowance') + .mockReturnValue(BigNumber.from(0)); + + // Make the network fetch error message disappear + jest.spyOn(swapsController, '_setSwapsNetworkConfig').mockReturnValue(); const timedoutGasReturnResult = { gasLimit: 1000000 }; - const timedoutGasReturnStub = sandbox - .stub(swapsController, 'timedoutGasReturn') - .resolves(timedoutGasReturnResult); + const timedoutGasReturnSpy = jest + .spyOn(swapsController, '_timedoutGasReturn') + .mockReturnValue(timedoutGasReturnResult); await swapsController.fetchAndSetQuotes( MOCK_FETCH_PARAMS, @@ -723,30 +726,33 @@ describe('SwapsController', function () { ); // Mocked quotes approvalNeeded is null, so it will only be called with the gas - assert.strictEqual( - timedoutGasReturnStub.calledOnceWithExactly( - MOCK_APPROVAL_NEEDED, - TEST_AGG_ID_APPROVAL, - ), - true, + expect(timedoutGasReturnSpy).toHaveBeenCalledTimes(1); + expect(timedoutGasReturnSpy).toHaveBeenCalledWith( + MOCK_APPROVAL_NEEDED, + TEST_AGG_ID_APPROVAL, ); }); it('marks the best quote', async function () { - fetchTradesInfoStub.resolves(getMockQuotes()); + jest + .spyOn(swapsController, '_fetchTradesInfo') + .mockReturnValue(getMockQuotes()); // Make it so approval is not required - sandbox - .stub(swapsController, '_getERC20Allowance') - .resolves(BigNumber.from(1)); + jest + .spyOn(swapsController, '_getERC20Allowance') + .mockReturnValue(BigNumber.from(1)); + + // Make the network fetch error message disappear + jest.spyOn(swapsController, '_setSwapsNetworkConfig').mockReturnValue(); const [newQuotes, topAggId] = await swapsController.fetchAndSetQuotes( MOCK_FETCH_PARAMS, MOCK_FETCH_METADATA, ); - assert.strictEqual(topAggId, TEST_AGG_ID_BEST); - assert.strictEqual(newQuotes[topAggId].isBestQuote, true); + expect(topAggId).toStrictEqual(TEST_AGG_ID_BEST); + expect(newQuotes[topAggId].isBestQuote).toStrictEqual(true); }); it('selects the best quote', async function () { @@ -763,32 +769,43 @@ describe('SwapsController', function () { .toString(), }; const quotes = { ...getMockQuotes(), [bestAggId]: bestQuote }; - fetchTradesInfoStub.resolves(quotes); + + jest.spyOn(swapsController, '_fetchTradesInfo').mockReturnValue(quotes); // Make it so approval is not required - sandbox - .stub(swapsController, '_getERC20Allowance') - .resolves(BigNumber.from(1)); + jest + .spyOn(swapsController, '_getERC20Allowance') + .mockReturnValue(BigNumber.from(1)); + + // Make the network fetch error message disappear + jest.spyOn(swapsController, '_setSwapsNetworkConfig').mockReturnValue(); const [newQuotes, topAggId] = await swapsController.fetchAndSetQuotes( MOCK_FETCH_PARAMS, MOCK_FETCH_METADATA, ); - assert.strictEqual(topAggId, bestAggId); - assert.strictEqual(newQuotes[topAggId].isBestQuote, true); + expect(topAggId).toStrictEqual(bestAggId); + expect(newQuotes[topAggId].isBestQuote).toStrictEqual(true); }); it('does not mark as best quote if no conversion rate exists for destination token', async function () { - fetchTradesInfoStub.resolves(getMockQuotes()); + jest + .spyOn(swapsController, '_fetchTradesInfo') + .mockReturnValue(getMockQuotes()); // Make it so approval is not required - sandbox - .stub(swapsController, '_getERC20Allowance') - .resolves(BigNumber.from(1)); + jest + .spyOn(swapsController, '_getERC20Allowance') + .mockReturnValue(BigNumber.from(1)); + + // Make the network fetch error message disappear + jest.spyOn(swapsController, '_setSwapsNetworkConfig').mockReturnValue(); swapsController.getTokenRatesState = () => ({ - contractExchangeRates: {}, + marketData: { + '0x1': {}, + }, }); const [newQuotes, topAggId] = await swapsController.fetchAndSetQuotes( @@ -796,27 +813,28 @@ describe('SwapsController', function () { MOCK_FETCH_METADATA, ); - assert.strictEqual(newQuotes[topAggId].isBestQuote, undefined); + expect(newQuotes[topAggId].isBestQuote).toStrictEqual(undefined); }); it('should replace ethers instance when called with a different chainId than was current when the controller was instantiated', async function () { - fetchTradesInfoStub = sandbox.stub(); + fetchTradesInfoStub.mockReset(); const _swapsController = getSwapsController(); - const currentEthersInstance = _swapsController.ethersProvider; + const currentEthersInstance = _swapsController._ethersProvider; + + // Make the network fetch error message disappear + jest + .spyOn(_swapsController, '_setSwapsNetworkConfig') + .mockReturnValue(); await _swapsController.fetchAndSetQuotes(MOCK_FETCH_PARAMS, { ...MOCK_FETCH_METADATA, chainId: CHAIN_IDS.GOERLI, }); - const newEthersInstance = _swapsController.ethersProvider; - assert.notStrictEqual( - currentEthersInstance, - newEthersInstance, - 'Ethers provider should be replaced', - ); + const newEthersInstance = _swapsController._ethersProvider; + expect(currentEthersInstance).not.toStrictEqual(newEthersInstance); }); it('should not replace ethers instance when called with the same chainId that was current when the controller was instantiated', async function () { @@ -828,19 +846,18 @@ describe('SwapsController', function () { fetchTradesInfo: fetchTradesInfoStub, getCurrentChainId: getCurrentChainIdStub, }); - const currentEthersInstance = _swapsController.ethersProvider; + const currentEthersInstance = _swapsController._ethersProvider; + + // Make the network fetch error message disappear + jest.spyOn(swapsController, '_setSwapsNetworkConfig').mockReturnValue(); await swapsController.fetchAndSetQuotes(MOCK_FETCH_PARAMS, { ...MOCK_FETCH_METADATA, chainId: CHAIN_IDS.MAINNET, }); - const newEthersInstance = _swapsController.ethersProvider; - assert.strictEqual( - currentEthersInstance, - newEthersInstance, - 'Ethers provider should not be replaced', - ); + const newEthersInstance = _swapsController._ethersProvider; + expect(currentEthersInstance).toStrictEqual(newEthersInstance); }); it('should replace ethers instance, and _ethersProviderChainId, twice when called twice with two different chainIds, and successfully set the _ethersProviderChainId when returning to the original chain', async function () { @@ -851,29 +868,30 @@ describe('SwapsController', function () { getTokenRatesState: MOCK_TOKEN_RATES_STORE, fetchTradesInfo: fetchTradesInfoStub, getCurrentChainId: getCurrentChainIdStub, + getLayer1GasFee: getLayer1GasFeeStub, + getNetworkClientId: getNetworkClientIdStub, }); - const firstEthersInstance = _swapsController.ethersProvider; + const firstEthersInstance = _swapsController._ethersProvider; const firstEthersProviderChainId = _swapsController._ethersProviderChainId; + // Make the network fetch error message disappear + jest + .spyOn(_swapsController, '_setSwapsNetworkConfig') + .mockReturnValue(); + await _swapsController.fetchAndSetQuotes(MOCK_FETCH_PARAMS, { ...MOCK_FETCH_METADATA, chainId: CHAIN_IDS.GOERLI, }); - const secondEthersInstance = _swapsController.ethersProvider; + const secondEthersInstance = _swapsController._ethersProvider; const secondEthersProviderChainId = _swapsController._ethersProviderChainId; - assert.notStrictEqual( - firstEthersInstance, - secondEthersInstance, - 'Ethers provider should be replaced', - ); - assert.notStrictEqual( - firstEthersInstance, + expect(firstEthersInstance).not.toStrictEqual(secondEthersInstance); + expect(firstEthersInstance).not.toStrictEqual( secondEthersProviderChainId, - 'Ethers provider chainId should be replaced', ); await _swapsController.fetchAndSetQuotes(MOCK_FETCH_PARAMS, { @@ -881,29 +899,19 @@ describe('SwapsController', function () { chainId: CHAIN_IDS.LOCALHOST, }); - const thirdEthersInstance = _swapsController.ethersProvider; + const thirdEthersInstance = _swapsController._ethersProvider; const thirdEthersProviderChainId = _swapsController._ethersProviderChainId; - assert.notStrictEqual( - firstEthersProviderChainId, + expect(firstEthersProviderChainId).not.toStrictEqual( thirdEthersInstance, - 'Ethers provider should be replaced', ); - assert.notStrictEqual( - secondEthersInstance, - thirdEthersInstance, - 'Ethers provider should be replaced', - ); - assert.notStrictEqual( - firstEthersInstance, + expect(secondEthersInstance).not.toStrictEqual(thirdEthersInstance); + expect(firstEthersInstance).not.toStrictEqual( thirdEthersProviderChainId, - 'Ethers provider chainId should be replaced', ); - assert.notStrictEqual( - secondEthersProviderChainId, + expect(secondEthersProviderChainId).not.toStrictEqual( thirdEthersProviderChainId, - 'Ethers provider chainId should be replaced', ); await _swapsController.fetchAndSetQuotes(MOCK_FETCH_PARAMS, { @@ -914,10 +922,8 @@ describe('SwapsController', function () { const lastEthersProviderChainId = _swapsController._ethersProviderChainId; - assert.strictEqual( - firstEthersProviderChainId, + expect(firstEthersProviderChainId).toStrictEqual( lastEthersProviderChainId, - 'Ethers provider chainId should match what it was originally', ); }); }); @@ -927,7 +933,8 @@ describe('SwapsController', function () { const { swapsState: old } = swapsController.store.getState(); swapsController.resetSwapsState(); const { swapsState } = swapsController.store.getState(); - assert.deepStrictEqual(swapsState, { + + expect(swapsState).toStrictEqual({ ...EMPTY_INIT_STATE.swapsState, tokens: old.tokens, swapsQuoteRefreshTime: old.swapsQuoteRefreshTime, @@ -940,41 +947,50 @@ describe('SwapsController', function () { }); it('clears polling timeout', function () { - swapsController.pollingTimeout = setTimeout( - () => assert.fail(), - POLLING_TIMEOUT, - ); + swapsController._pollingTimeout = setTimeout(() => { + throw new Error('Polling timeout not cleared'); + }, POLLING_TIMEOUT); + + // Reseting swaps state should clear the polling timeout swapsController.resetSwapsState(); - assert.strictEqual(swapsController.pollingTimeout._idleTimeout, -1); + + // Verify by ensuring the error is not thrown, indicating that the timer was cleared + expect(jest.runOnlyPendingTimers).not.toThrow(); }); }); describe('stopPollingForQuotes', function () { it('clears polling timeout', function () { - swapsController.pollingTimeout = setTimeout( - () => assert.fail(), - POLLING_TIMEOUT, - ); + swapsController._pollingTimeout = setTimeout(() => { + throw new Error('Polling timeout not cleared'); + }, POLLING_TIMEOUT); + + // Stop polling for quotes should clear the polling timeout swapsController.stopPollingForQuotes(); - assert.strictEqual(swapsController.pollingTimeout._idleTimeout, -1); + + // Verify by ensuring the error is not thrown, indicating that the timer was cleared + expect(jest.runOnlyPendingTimers).not.toThrow(); }); it('resets quotes state correctly', function () { swapsController.stopPollingForQuotes(); const { swapsState } = swapsController.store.getState(); - assert.deepStrictEqual(swapsState.quotes, {}); - assert.strictEqual(swapsState.quotesLastFetched, null); + expect(swapsState.quotes).toStrictEqual({}); + expect(swapsState.quotesLastFetched).toStrictEqual(null); }); }); describe('resetPostFetchState', function () { it('clears polling timeout', function () { - swapsController.pollingTimeout = setTimeout( - () => assert.fail(), - POLLING_TIMEOUT, - ); + swapsController._pollingTimeout = setTimeout(() => { + throw new Error('Polling timeout not cleared'); + }, POLLING_TIMEOUT); + + // Reset post fetch state should clear the polling timeout swapsController.resetPostFetchState(); - assert.strictEqual(swapsController.pollingTimeout._idleTimeout, -1); + + // Verify by ensuring the error is not thrown, indicating that the timer was cleared + expect(jest.runOnlyPendingTimers).not.toThrow(); }); it('updates state correctly', function () { @@ -1002,7 +1018,7 @@ describe('SwapsController', function () { swapsController.resetPostFetchState(); const { swapsState } = swapsController.store.getState(); - assert.deepStrictEqual(swapsState, { + expect(swapsState).toStrictEqual({ ...EMPTY_INIT_STATE.swapsState, tokens, fetchParams, @@ -1016,14 +1032,13 @@ describe('SwapsController', function () { describe('utils', function () { describe('getMedianEthValueQuote', function () { - const { getMedianEthValueQuote } = utils; - it('calculates median correctly with uneven sample', function () { const expectedResult = { ethFee: '10', metaMaskFeeInEth: '5', ethValueOfTokens: '0.3', }; + const values = [ { overallValueOfQuote: '3', @@ -1046,12 +1061,7 @@ describe('SwapsController', function () { ]; const median = getMedianEthValueQuote(values); - - assert.deepEqual( - median, - expectedResult, - 'should have returned correct median quote object', - ); + expect(median).toStrictEqual(expectedResult); }); it('calculates median correctly with even sample', function () { @@ -1060,6 +1070,7 @@ describe('SwapsController', function () { metaMaskFeeInEth: '6.5', ethValueOfTokens: '0.25', }; + const values = [ { overallValueOfQuote: '3', @@ -1086,13 +1097,9 @@ describe('SwapsController', function () { ethValueOfTokens: '0.6', }, ]; - const median = getMedianEthValueQuote(values); - assert.deepEqual( - median, - expectedResult, - 'should have returned correct median quote object', - ); + const median = getMedianEthValueQuote(values); + expect(median).toStrictEqual(expectedResult); }); it('calculates median correctly with an uneven sample where multiple quotes have the median overall value', function () { @@ -1146,13 +1153,9 @@ describe('SwapsController', function () { metaMaskFeeInEth: '0.8', }, ]; - const median = getMedianEthValueQuote(values); - assert.deepEqual( - median, - expectedResult, - 'should have returned correct median quote object', - ); + const median = getMedianEthValueQuote(values); + expect(median).toStrictEqual(expectedResult); }); it('calculates median correctly with an even sample where multiple quotes have the same overall value as either of the two middle values', function () { @@ -1200,29 +1203,22 @@ describe('SwapsController', function () { metaMaskFeeInEth: '0.8', }, ]; - const median = getMedianEthValueQuote(values); - assert.deepEqual( - median, - expectedResult, - 'should have returned correct median quote object', - ); + const median = getMedianEthValueQuote(values); + expect(median).toStrictEqual(expectedResult); }); it('throws on empty or non-array sample', function () { - assert.throws( - () => getMedianEthValueQuote([]), - 'should throw on empty array', + expect(() => getMedianEthValueQuote([])).toThrow( + 'Expected non-empty array param.', ); - assert.throws( - () => getMedianEthValueQuote(), - 'should throw on non-array param', + expect(() => getMedianEthValueQuote()).toThrow( + 'Expected non-empty array param.', ); - assert.throws( - () => getMedianEthValueQuote({}), - 'should throw on non-array param', + expect(() => getMedianEthValueQuote({})).toThrow( + 'Expected non-empty array param.', ); }); }); diff --git a/app/scripts/controllers/swaps.js b/app/scripts/controllers/swaps.ts similarity index 59% rename from app/scripts/controllers/swaps.js rename to app/scripts/controllers/swaps.ts index 9e19286c99c1..b0915b2ed21f 100644 --- a/app/scripts/controllers/swaps.js +++ b/app/scripts/controllers/swaps.ts @@ -1,264 +1,195 @@ -import { Web3Provider } from '@ethersproject/providers'; import { Contract } from '@ethersproject/contracts'; -import BigNumber from 'bignumber.js'; +import { + ExternalProvider, + JsonRpcFetchFunc, + Web3Provider, +} from '@ethersproject/providers'; +import type { ChainId } from '@metamask/controller-utils'; +import { GasFeeState } from '@metamask/gas-fee-controller'; +import { ProviderConfig } from '@metamask/network-controller'; import { ObservableStore } from '@metamask/obs-store'; -import { mapValues, cloneDeep } from 'lodash'; -import abi from 'human-standard-token-abi'; +import { TransactionParams } from '@metamask/transaction-controller'; import { captureException } from '@sentry/browser'; - -import { - decGWEIToHexWEI, - sumHexes, -} from '../../../shared/modules/conversion.utils'; -import { - DEFAULT_ERC20_APPROVE_GAS, - QUOTES_EXPIRED_ERROR, - QUOTES_NOT_AVAILABLE_ERROR, - SWAPS_FETCH_ORDER_CONFLICT, - SWAPS_CHAINID_CONTRACT_ADDRESS_MAP, -} from '../../../shared/constants/swaps'; +import { BigNumber } from 'bignumber.js'; +import abi from 'human-standard-token-abi'; +import { cloneDeep, mapValues } from 'lodash'; +import { EtherDenomination } from '../../../shared/constants/common'; import { GasEstimateTypes } from '../../../shared/constants/gas'; -import { CHAIN_IDS } from '../../../shared/constants/network'; import { MetaMetricsEventCategory, - MetaMetricsEventName, MetaMetricsEventErrorType, + MetaMetricsEventName, } from '../../../shared/constants/metametrics'; +import { CHAIN_IDS } from '../../../shared/constants/network'; import { - FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME, - FALLBACK_SMART_TRANSACTIONS_DEADLINE, FALLBACK_SMART_TRANSACTIONS_MAX_FEE_MULTIPLIER, + FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME, } from '../../../shared/constants/smartTransactions'; - -import { isSwapsDefaultTokenAddress } from '../../../shared/modules/swaps.utils'; - +import { + DEFAULT_ERC20_APPROVE_GAS, + QUOTES_EXPIRED_ERROR, + QUOTES_NOT_AVAILABLE_ERROR, + SWAPS_CHAINID_CONTRACT_ADDRESS_MAP, + SWAPS_FETCH_ORDER_CONFLICT, +} from '../../../shared/constants/swaps'; +import { SECOND } from '../../../shared/constants/time'; +import fetchWithCache from '../../../shared/lib/fetch-with-cache'; import { fetchTradesInfo as defaultFetchTradesInfo, getBaseApi, } from '../../../shared/lib/swaps-utils'; -import fetchWithCache from '../../../shared/lib/fetch-with-cache'; -import { MINUTE, SECOND } from '../../../shared/constants/time'; -import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils'; import { calcGasTotal, calcTokenAmount, } from '../../../shared/lib/transactions-controller-utils'; -import fetchEstimatedL1Fee from '../../../ui/helpers/utils/optimism/fetchEstimatedL1Fee'; - +import { + decGWEIToHexWEI, + sumHexes, +} from '../../../shared/modules/conversion.utils'; import { Numeric } from '../../../shared/modules/Numeric'; -import { EtherDenomination } from '../../../shared/constants/common'; +import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils'; +import { isSwapsDefaultTokenAddress } from '../../../shared/modules/swaps.utils'; +import { + FALLBACK_QUOTE_REFRESH_TIME, + MAX_GAS_LIMIT, + POLL_COUNT_LIMIT, + swapsControllerInitialState, +} from './swaps.constants'; +import type { + FetchTradesInfoParams, + FetchTradesInfoParamsMetadata, + Quote, + QuoteSavings, + SwapsControllerOptions, + SwapsControllerState, + SwapsControllerStore, + Trade, +} from './swaps.types'; +import { + calculateGasEstimateWithRefund, + getMedianEthValueQuote, +} from './swaps.utils'; -// The MAX_GAS_LIMIT is a number that is higher than the maximum gas costs we have observed on any aggregator -const MAX_GAS_LIMIT = 2500000; - -// To ensure that our serves are not spammed if MetaMask is left idle, we limit the number of fetches for quotes that are made on timed intervals. -// 3 seems to be an appropriate balance of giving users the time they need when MetaMask is not left idle, and turning polling off when it is. -const POLL_COUNT_LIMIT = 3; - -// If for any reason the MetaSwap API fails to provide a refresh time, -// provide a reasonable fallback to avoid further errors -const FALLBACK_QUOTE_REFRESH_TIME = MINUTE; - -function calculateGasEstimateWithRefund( - maxGas = MAX_GAS_LIMIT, - estimatedRefund = 0, - estimatedGas = 0, -) { - const maxGasMinusRefund = new BigNumber(maxGas, 10).minus( - estimatedRefund, - 10, - ); - const isMaxGasMinusRefundNegative = maxGasMinusRefund.lt(0); - - const gasEstimateWithRefund = - !isMaxGasMinusRefundNegative && maxGasMinusRefund.lt(estimatedGas, 16) - ? `0x${maxGasMinusRefund.toString(16)}` - : estimatedGas; - - return gasEstimateWithRefund; -} +export default class SwapsController { + public store: SwapsControllerStore; + + public getBufferedGasLimit: ( + params: { + txParams: { + value: string; + data: string; + to: string; + from: string; + }; + }, + factor: number, + ) => Promise<{ gasLimit: string; simulationFails: boolean }>; -const initialState = { - swapsState: { - quotes: {}, - quotesPollingLimitEnabled: false, - fetchParams: null, - tokens: null, - tradeTxId: null, - approveTxId: null, - quotesLastFetched: null, - customMaxGas: '', - customGasPrice: null, - customMaxFeePerGas: null, - customMaxPriorityFeePerGas: null, - swapsUserFeeLevel: '', - selectedAggId: null, - customApproveTxData: '', - errorKey: '', - topAggId: null, - routeState: '', - swapsFeatureIsLive: true, - saveFetchedQuotes: false, - swapsQuoteRefreshTime: FALLBACK_QUOTE_REFRESH_TIME, - swapsQuotePrefetchingRefreshTime: FALLBACK_QUOTE_REFRESH_TIME, - swapsStxBatchStatusRefreshTime: FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME, - swapsStxGetTransactionsRefreshTime: - FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME, - swapsStxMaxFeeMultiplier: FALLBACK_SMART_TRANSACTIONS_MAX_FEE_MULTIPLIER, - swapsFeatureFlags: {}, - }, -}; + public getProviderConfig: () => ProviderConfig; + + public getTokenRatesState: () => { + marketData: Record< + string, + { + [tokenAddress: string]: { + price: number; + }; + } + >; + }; + + public resetState: () => void; + + public trackMetaMetricsEvent: (event: { + event: MetaMetricsEventName; + category: MetaMetricsEventCategory; + properties: Record; + }) => void; + + private _ethersProvider: Web3Provider; + + private _ethersProviderChainId: ChainId; + + private _indexOfNewestCallInFlight: number; + + private _pollCount: number; + + private _pollingTimeout: ReturnType | null = null; + + private _provider: ExternalProvider | JsonRpcFetchFunc; + + private _fetchTradesInfo: ( + fetchParams: FetchTradesInfoParams, + fetchMetadata: { chainId: ChainId }, + ) => Promise<{ + [aggId: string]: Quote; + }> = defaultFetchTradesInfo; + + private _getCurrentChainId: () => ChainId; + + private _getEIP1559GasFeeEstimates: () => Promise; + + private _getLayer1GasFee: (params: { + transactionParams: TransactionParams; + chainId: ChainId; + }) => Promise; -export default class SwapsController { constructor( - { - getBufferedGasLimit, - provider, - getProviderConfig, - getTokenRatesState, - fetchTradesInfo = defaultFetchTradesInfo, - getCurrentChainId, - getEIP1559GasFeeEstimates, - trackMetaMetricsEvent, - }, - state, + opts: SwapsControllerOptions, + state: { swapsState: SwapsControllerState }, ) { + // The store is initialized with the initial state, and then updated with the state from storage this.store = new ObservableStore({ swapsState: { - ...initialState.swapsState, + ...swapsControllerInitialState.swapsState, swapsFeatureFlags: state?.swapsState?.swapsFeatureFlags || {}, }, }); + this.getBufferedGasLimit = opts.getBufferedGasLimit; + this.getTokenRatesState = opts.getTokenRatesState; + this.getProviderConfig = opts.getProviderConfig; + this.trackMetaMetricsEvent = opts.trackMetaMetricsEvent; + + // The resetState function is used to reset the state to the initial state, but keep the swapsFeatureFlags this.resetState = () => { this.store.updateState({ swapsState: { - ...initialState.swapsState, + ...swapsControllerInitialState.swapsState, swapsFeatureFlags: state?.swapsState?.swapsFeatureFlags, }, }); }; - this._fetchTradesInfo = fetchTradesInfo; - this._getCurrentChainId = getCurrentChainId; - this._getEIP1559GasFeeEstimates = getEIP1559GasFeeEstimates; - - this.getBufferedGasLimit = getBufferedGasLimit; - this.getTokenRatesState = getTokenRatesState; - this.trackMetaMetricsEvent = trackMetaMetricsEvent; - - this.pollCount = 0; - this.getProviderConfig = getProviderConfig; - - this.indexOfNewestCallInFlight = 0; - - this.provider = provider; - this.ethersProvider = new Web3Provider(provider); + this._fetchTradesInfo = opts.fetchTradesInfo || defaultFetchTradesInfo; + this._getCurrentChainId = opts.getCurrentChainId; + this._getEIP1559GasFeeEstimates = opts.getEIP1559GasFeeEstimates; + this._getLayer1GasFee = opts.getLayer1GasFee; + this._ethersProvider = new Web3Provider(opts.provider); this._ethersProviderChainId = this._getCurrentChainId(); + this._indexOfNewestCallInFlight = 0; + this._pollCount = 0; + this._provider = opts.provider; } - async fetchSwapsNetworkConfig(chainId) { - const response = await fetchWithCache({ - url: getBaseApi('network', chainId), - fetchOptions: { method: 'GET' }, - cacheOptions: { cacheRefreshTime: 600000 }, - functionName: 'fetchSwapsNetworkConfig', - }); - const { refreshRates, parameters = {} } = response || {}; - if ( - !refreshRates || - typeof refreshRates.quotes !== 'number' || - typeof refreshRates.quotesPrefetching !== 'number' - ) { - throw new Error( - `MetaMask - invalid response for refreshRates: ${response}`, - ); - } - // We presently use milliseconds in the UI. - return { - quotes: refreshRates.quotes * 1000, - quotesPrefetching: refreshRates.quotesPrefetching * 1000, - stxGetTransactions: refreshRates.stxGetTransactions * 1000, - stxBatchStatus: refreshRates.stxBatchStatus * 1000, - stxStatusDeadline: refreshRates.stxStatusDeadline, - stxMaxFeeMultiplier: parameters.stxMaxFeeMultiplier, - }; - } - - // Sets the network config from the MetaSwap API. - async _setSwapsNetworkConfig() { - const chainId = this._getCurrentChainId(); - let swapsNetworkConfig; - try { - swapsNetworkConfig = await this.fetchSwapsNetworkConfig(chainId); - } catch (e) { - console.error('Request for Swaps network config failed: ', e); - } - const { swapsState: latestSwapsState } = this.store.getState(); - this.store.updateState({ - swapsState: { - ...latestSwapsState, - swapsQuoteRefreshTime: - swapsNetworkConfig?.quotes || FALLBACK_QUOTE_REFRESH_TIME, - swapsQuotePrefetchingRefreshTime: - swapsNetworkConfig?.quotesPrefetching || FALLBACK_QUOTE_REFRESH_TIME, - swapsStxGetTransactionsRefreshTime: - swapsNetworkConfig?.stxGetTransactions || - FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME, - swapsStxBatchStatusRefreshTime: - swapsNetworkConfig?.stxBatchStatus || - FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME, - swapsStxStatusDeadline: - swapsNetworkConfig?.stxStatusDeadline || - FALLBACK_SMART_TRANSACTIONS_DEADLINE, - swapsStxMaxFeeMultiplier: - swapsNetworkConfig?.stxMaxFeeMultiplier || - FALLBACK_SMART_TRANSACTIONS_MAX_FEE_MULTIPLIER, - }, - }); - } - - // Once quotes are fetched, we poll for new ones to keep the quotes up to date. Market and aggregator contract conditions can change fast enough - // that quotes will no longer be available after 1 or 2 minutes. When fetchAndSetQuotes is first called, it receives fetch parameters that are stored in - // state. These stored parameters are used on subsequent calls made during polling. - // Note: we stop polling after 3 requests, until new quotes are explicitly asked for. The logic that enforces that maximum is in the body of fetchAndSetQuotes - pollForNewQuotes() { - const { - swapsState: { - swapsQuoteRefreshTime, - swapsQuotePrefetchingRefreshTime, - quotesPollingLimitEnabled, - }, - } = this.store.getState(); - // swapsQuoteRefreshTime is used on the View Quote page, swapsQuotePrefetchingRefreshTime is used on the Build Quote page. - const quotesRefreshRateInMs = quotesPollingLimitEnabled - ? swapsQuoteRefreshTime - : swapsQuotePrefetchingRefreshTime; - this.pollingTimeout = setTimeout(() => { - const { swapsState } = this.store.getState(); - this.fetchAndSetQuotes( - swapsState.fetchParams, - swapsState.fetchParams?.metaData, - true, - ); - }, quotesRefreshRateInMs); + public clearSwapsQuotes() { + const { swapsState } = this.store.getState(); + this.store.updateState({ swapsState: { ...swapsState, quotes: {} } }); } - stopPollingForQuotes() { - if (this.pollingTimeout) { - clearTimeout(this.pollingTimeout); + public async fetchAndSetQuotes( + fetchParams: FetchTradesInfoParams, + fetchParamsMetaData: FetchTradesInfoParamsMetadata, + isPolledRequest = false, + ) { + if (!fetchParams) { + return null; } - } - async fetchAndSetQuotes( - fetchParams, - fetchParamsMetaData = {}, - isPolledRequest, - ) { const { chainId } = fetchParamsMetaData; if (chainId !== this._ethersProviderChainId) { - this.ethersProvider = new Web3Provider(this.provider); + this._ethersProvider = new Web3Provider(this._provider); this._ethersProviderChainId = chainId; } @@ -266,32 +197,29 @@ export default class SwapsController { swapsState: { quotesPollingLimitEnabled, saveFetchedQuotes }, } = this.store.getState(); - if (!fetchParams) { - return null; - } // Every time we get a new request that is not from the polling, we reset the poll count so we can poll for up to three more sets of quotes with these new params. if (!isPolledRequest) { - this.pollCount = 0; + this._pollCount = 0; } // If there are any pending poll requests, clear them so that they don't get call while this new fetch is in process - clearTimeout(this.pollingTimeout); + if (this._pollingTimeout) { + clearTimeout(this._pollingTimeout); + } if (!isPolledRequest) { this.setSwapsErrorKey(''); } - const indexOfCurrentCall = this.indexOfNewestCallInFlight + 1; - this.indexOfNewestCallInFlight = indexOfCurrentCall; + const indexOfCurrentCall = this._indexOfNewestCallInFlight + 1; + this._indexOfNewestCallInFlight = indexOfCurrentCall; if (!saveFetchedQuotes) { - this.setSaveFetchedQuotes(true); + this._setSaveFetchedQuotes(true); } let [newQuotes] = await Promise.all([ - this._fetchTradesInfo(fetchParams, { - ...fetchParamsMetaData, - }), + this._fetchTradesInfo(fetchParams, { ...fetchParamsMetaData }), this._setSwapsNetworkConfig(), ]); @@ -308,24 +236,24 @@ export default class SwapsController { ]; } - newQuotes = mapValues(newQuotes, (quote) => ({ + newQuotes = mapValues(newQuotes, (quote: Quote) => ({ ...quote, - sourceTokenInfo: fetchParamsMetaData.sourceTokenInfo, - destinationTokenInfo: fetchParamsMetaData.destinationTokenInfo, + sourceTokenInfo: fetchParamsMetaData?.sourceTokenInfo, + destinationTokenInfo: fetchParamsMetaData?.destinationTokenInfo, })); - if (chainId === CHAIN_IDS.OPTIMISM && Object.values(newQuotes).length > 0) { + const isOptimism = chainId === CHAIN_IDS.OPTIMISM.toString(); + const isBase = chainId === CHAIN_IDS.BASE.toString(); + + if ((isOptimism || isBase) && Object.values(newQuotes).length > 0) { await Promise.all( Object.values(newQuotes).map(async (quote) => { if (quote.trade) { - const multiLayerL1TradeFeeTotal = await fetchEstimatedL1Fee( + const multiLayerL1TradeFeeTotal = await this._getLayer1GasFee({ + transactionParams: quote.trade, chainId, - { - txParams: quote.trade, - chainId, - }, - this.ethersProvider, - ); + }); + quote.multiLayerL1TradeFeeTotal = multiLayerL1TradeFeeTotal; } return quote; @@ -360,19 +288,25 @@ export default class SwapsController { ...quote, approvalNeeded: null, })); - } else if (!isPolledRequest) { - const { gasLimit: approvalGas } = await this.timedoutGasReturn( + } else if (!isPolledRequest && firstQuote.approvalNeeded) { + const { gasLimit: approvalGas } = await this._timedoutGasReturn( firstQuote.approvalNeeded, firstQuote.aggregator, ); - newQuotes = mapValues(newQuotes, (quote) => ({ - ...quote, - approvalNeeded: { - ...quote.approvalNeeded, - gas: approvalGas || DEFAULT_ERC20_APPROVE_GAS, - }, - })); + newQuotes = mapValues(newQuotes, (quote) => + quote.approvalNeeded + ? { + ...quote, + approvalNeeded: { + // approvalNeeded is guaranteed to be defined here because of the conditional above, since all quotes are from the same source token + // the approvalNeeded object will be present for all quotes + ...quote.approvalNeeded, + gas: approvalGas || DEFAULT_ERC20_APPROVE_GAS, + }, + } + : quote, + ); } } @@ -381,27 +315,30 @@ export default class SwapsController { // We can reduce time on the loading screen by only doing this after the // loading screen and best quote have rendered. if (!approvalRequired && !fetchParams?.balanceError) { - newQuotes = await this.getAllQuotesWithGasEstimates(newQuotes); + newQuotes = await this._getAllQuotesWithGasEstimates(newQuotes); } if (Object.values(newQuotes).length === 0) { this.setSwapsErrorKey(QUOTES_NOT_AVAILABLE_ERROR); } else { - const [_topAggId, quotesWithSavingsAndFeeData] = - await this._findTopQuoteAndCalculateSavings(newQuotes); - topAggId = _topAggId; - newQuotes = quotesWithSavingsAndFeeData; + const topQuoteAndSavings = await this._findTopQuoteAndCalculateSavings( + newQuotes, + ); + if (Array.isArray(topQuoteAndSavings)) { + topAggId = topQuoteAndSavings[0]; + newQuotes = topQuoteAndSavings[1]; + } } // If a newer call has been made, don't update state with old information // Prevents timing conflicts between fetches - if (this.indexOfNewestCallInFlight !== indexOfCurrentCall) { + if (this._indexOfNewestCallInFlight !== indexOfCurrentCall) { throw new Error(SWAPS_FETCH_ORDER_CONFLICT); } const { swapsState } = this.store.getState(); let { selectedAggId } = swapsState; - if (!newQuotes[selectedAggId]) { + if (!selectedAggId || !newQuotes[selectedAggId]) { selectedAggId = null; } @@ -418,12 +355,12 @@ export default class SwapsController { if (quotesPollingLimitEnabled) { // We only want to do up to a maximum of three requests from polling if polling limit is enabled. - // Otherwise we won't increase pollCount, so polling will run without a limit. - this.pollCount += 1; + // Otherwise we won't increase _pollCount, so polling will run without a limit. + this._pollCount += 1; } - if (!quotesPollingLimitEnabled || this.pollCount < POLL_COUNT_LIMIT + 1) { - this.pollForNewQuotes(); + if (!quotesPollingLimitEnabled || this._pollCount < POLL_COUNT_LIMIT + 1) { + this._pollForNewQuotes(); } else { this.resetPostFetchState(); this.setSwapsErrorKey(QUOTES_EXPIRED_ERROR); @@ -433,129 +370,78 @@ export default class SwapsController { return [newQuotes, topAggId]; } - safeRefetchQuotes() { + public resetPostFetchState() { const { swapsState } = this.store.getState(); - if (!this.pollingTimeout && swapsState.fetchParams) { - this.fetchAndSetQuotes(swapsState.fetchParams); + this.store.updateState({ + swapsState: { + ...swapsControllerInitialState.swapsState, + tokens: swapsState.tokens, + fetchParams: swapsState.fetchParams, + swapsFeatureIsLive: swapsState.swapsFeatureIsLive, + swapsQuoteRefreshTime: swapsState.swapsQuoteRefreshTime, + swapsQuotePrefetchingRefreshTime: + swapsState.swapsQuotePrefetchingRefreshTime, + swapsFeatureFlags: swapsState.swapsFeatureFlags, + }, + }); + if (this._pollingTimeout) { + clearTimeout(this._pollingTimeout); } } - setSelectedQuoteAggId(selectedAggId) { - const { swapsState } = this.store.getState(); - this.store.updateState({ swapsState: { ...swapsState, selectedAggId } }); - } - - setSwapsTokens(tokens) { + public resetSwapsState() { const { swapsState } = this.store.getState(); - this.store.updateState({ swapsState: { ...swapsState, tokens } }); + this.store.updateState({ + swapsState: { + ...swapsControllerInitialState.swapsState, + swapsQuoteRefreshTime: swapsState.swapsQuoteRefreshTime, + swapsQuotePrefetchingRefreshTime: + swapsState.swapsQuotePrefetchingRefreshTime, + swapsFeatureFlags: swapsState.swapsFeatureFlags, + }, + }); + if (this._pollingTimeout) { + clearTimeout(this._pollingTimeout); + } } - clearSwapsQuotes() { + public safeRefetchQuotes() { const { swapsState } = this.store.getState(); - this.store.updateState({ swapsState: { ...swapsState, quotes: {} } }); + if (!this._pollingTimeout && swapsState.fetchParams) { + this.fetchAndSetQuotes(swapsState.fetchParams, { + ...swapsState.fetchParams.metaData, + }); + } } - setSwapsErrorKey(errorKey) { + public setApproveTxId(approveTxId: string | null) { const { swapsState } = this.store.getState(); - this.store.updateState({ swapsState: { ...swapsState, errorKey } }); - } - - async getAllQuotesWithGasEstimates(quotes) { - const quoteGasData = await Promise.all( - Object.values(quotes).map(async (quote) => { - const { gasLimit, simulationFails } = await this.timedoutGasReturn( - quote.trade, - quote.aggregator, - ); - return [gasLimit, simulationFails, quote.aggregator]; - }), - ); - - const newQuotes = {}; - quoteGasData.forEach(([gasLimit, simulationFails, aggId]) => { - if (gasLimit && !simulationFails) { - const gasEstimateWithRefund = calculateGasEstimateWithRefund( - quotes[aggId].maxGas, - quotes[aggId].estimatedRefund, - gasLimit, - ); - - newQuotes[aggId] = { - ...quotes[aggId], - gasEstimate: gasLimit, - gasEstimateWithRefund, - }; - } else if (quotes[aggId].approvalNeeded) { - // If gas estimation fails, but an ERC-20 approve is needed, then we do not add any estimate property to the quote object - // Such quotes will rely on the maxGas and averageGas properties from the api - newQuotes[aggId] = quotes[aggId]; - } - // If gas estimation fails and no approval is needed, then we filter that quote out, so that it is not shown to the user - }); - return newQuotes; + this.store.updateState({ swapsState: { ...swapsState, approveTxId } }); } - timedoutGasReturn(tradeTxParams, aggregator = '') { - return new Promise((resolve) => { - let gasTimedOut = false; - - const gasTimeout = setTimeout(() => { - gasTimedOut = true; - this.trackMetaMetricsEvent({ - event: MetaMetricsEventName.QuoteError, - category: MetaMetricsEventCategory.Swaps, - properties: { - error_type: MetaMetricsEventErrorType.GasTimeout, - aggregator, - }, - }); - resolve({ - gasLimit: null, - simulationFails: true, - }); - }, SECOND * 5); - - // Remove gas from params that will be passed to the `estimateGas` call - // Including it can cause the estimate to fail if the actual gas needed - // exceeds the passed gas - const tradeTxParamsForGasEstimate = { - data: tradeTxParams.data, - from: tradeTxParams.from, - to: tradeTxParams.to, - value: tradeTxParams.value, - }; - - this.getBufferedGasLimit({ txParams: tradeTxParamsForGasEstimate }, 1) - .then(({ gasLimit, simulationFails }) => { - if (!gasTimedOut) { - clearTimeout(gasTimeout); - resolve({ gasLimit, simulationFails }); - } - }) - .catch((e) => { - captureException(e, { - extra: { - aggregator, - }, - }); - if (!gasTimedOut) { - clearTimeout(gasTimeout); - resolve({ gasLimit: null, simulationFails: true }); - } - }); + public setBackgroundSwapRouteState(routeState: string) { + const { swapsState } = this.store.getState(); + this.store.updateState({ swapsState: { ...swapsState, routeState } }); + } + + public setCustomApproveTxData(data: string) { + const { swapsState } = this.store.getState(); + this.store.updateState({ + swapsState: { ...swapsState, customApproveTxData: data }, }); } - async setInitialGasEstimate(initialAggId) { + public async setInitialGasEstimate(initialAggId: string) { const { swapsState } = this.store.getState(); const quoteToUpdate = { ...swapsState.quotes[initialAggId] }; - const { gasLimit: newGasEstimate, simulationFails } = - await this.timedoutGasReturn( - quoteToUpdate.trade, - quoteToUpdate.aggregator, - ); + const { gasLimit: newGasEstimate, simulationFails } = quoteToUpdate.trade + ? await this._timedoutGasReturn( + quoteToUpdate.trade, + quoteToUpdate.aggregator, + ) + : { gasLimit: null, simulationFails: true }; if (newGasEstimate && !simulationFails) { const gasEstimateWithRefund = calculateGasEstimateWithRefund( @@ -576,143 +462,145 @@ export default class SwapsController { }); } - setApproveTxId(approveTxId) { - const { swapsState } = this.store.getState(); - this.store.updateState({ swapsState: { ...swapsState, approveTxId } }); - } - - setTradeTxId(tradeTxId) { - const { swapsState } = this.store.getState(); - this.store.updateState({ swapsState: { ...swapsState, tradeTxId } }); - } - - setQuotesLastFetched(quotesLastFetched) { + public setSelectedQuoteAggId(selectedAggId: string) { const { swapsState } = this.store.getState(); - this.store.updateState({ - swapsState: { ...swapsState, quotesLastFetched }, - }); + this.store.updateState({ swapsState: { ...swapsState, selectedAggId } }); } - setSwapsTxGasPrice(gasPrice) { + public setSwapsFeatureFlags(swapsFeatureFlags: Record) { const { swapsState } = this.store.getState(); this.store.updateState({ - swapsState: { ...swapsState, customGasPrice: gasPrice }, + swapsState: { ...swapsState, swapsFeatureFlags }, }); } - setSwapsTxMaxFeePerGas(maxFeePerGas) { + public setSwapsErrorKey(errorKey: string) { const { swapsState } = this.store.getState(); - this.store.updateState({ - swapsState: { ...swapsState, customMaxFeePerGas: maxFeePerGas }, - }); + this.store.updateState({ swapsState: { ...swapsState, errorKey } }); } - setSwapsUserFeeLevel(swapsUserFeeLevel) { + public setSwapsLiveness(swapsLiveness: { swapsFeatureIsLive: boolean }) { const { swapsState } = this.store.getState(); + const { swapsFeatureIsLive } = swapsLiveness; this.store.updateState({ - swapsState: { ...swapsState, swapsUserFeeLevel }, + swapsState: { ...swapsState, swapsFeatureIsLive }, }); } - setSwapsQuotesPollingLimitEnabled(quotesPollingLimitEnabled) { + public setSwapsQuotesPollingLimitEnabled(quotesPollingLimitEnabled: boolean) { const { swapsState } = this.store.getState(); this.store.updateState({ swapsState: { ...swapsState, quotesPollingLimitEnabled }, }); } - setSwapsTxMaxFeePriorityPerGas(maxPriorityFeePerGas) { + public setSwapsTokens(tokens: string[]) { const { swapsState } = this.store.getState(); - this.store.updateState({ - swapsState: { - ...swapsState, - customMaxPriorityFeePerGas: maxPriorityFeePerGas, - }, - }); + this.store.updateState({ swapsState: { ...swapsState, tokens } }); } - setSwapsTxGasLimit(gasLimit) { + public setSwapsTxGasLimit(gasLimit: string) { const { swapsState } = this.store.getState(); this.store.updateState({ swapsState: { ...swapsState, customMaxGas: gasLimit }, }); } - setCustomApproveTxData(data) { + public setSwapsTxGasPrice(gasPrice: string | null) { const { swapsState } = this.store.getState(); this.store.updateState({ - swapsState: { ...swapsState, customApproveTxData: data }, + swapsState: { ...swapsState, customGasPrice: gasPrice }, }); } - setBackgroundSwapRouteState(routeState) { - const { swapsState } = this.store.getState(); - this.store.updateState({ swapsState: { ...swapsState, routeState } }); - } - - setSaveFetchedQuotes(status) { + public setSwapsTxMaxFeePerGas(maxFeePerGas: string | null) { const { swapsState } = this.store.getState(); this.store.updateState({ - swapsState: { ...swapsState, saveFetchedQuotes: status }, + swapsState: { ...swapsState, customMaxFeePerGas: maxFeePerGas }, }); } - setSwapsLiveness(swapsLiveness) { + public setSwapsTxMaxFeePriorityPerGas(maxPriorityFeePerGas: string | null) { const { swapsState } = this.store.getState(); - const { swapsFeatureIsLive } = swapsLiveness; this.store.updateState({ - swapsState: { ...swapsState, swapsFeatureIsLive }, + swapsState: { + ...swapsState, + customMaxPriorityFeePerGas: maxPriorityFeePerGas, + }, }); } - setSwapsFeatureFlags(swapsFeatureFlags) { + public setSwapsUserFeeLevel(swapsUserFeeLevel: string) { const { swapsState } = this.store.getState(); this.store.updateState({ - swapsState: { ...swapsState, swapsFeatureFlags }, + swapsState: { ...swapsState, swapsUserFeeLevel }, }); } - resetPostFetchState() { + public setTradeTxId(tradeTxId: string | null) { const { swapsState } = this.store.getState(); - this.store.updateState({ - swapsState: { - ...initialState.swapsState, - tokens: swapsState.tokens, - fetchParams: swapsState.fetchParams, - swapsFeatureIsLive: swapsState.swapsFeatureIsLive, - swapsQuoteRefreshTime: swapsState.swapsQuoteRefreshTime, - swapsQuotePrefetchingRefreshTime: - swapsState.swapsQuotePrefetchingRefreshTime, - swapsFeatureFlags: swapsState.swapsFeatureFlags, - }, - }); - clearTimeout(this.pollingTimeout); + this.store.updateState({ swapsState: { ...swapsState, tradeTxId } }); } - resetSwapsState() { - const { swapsState } = this.store.getState(); - this.store.updateState({ - swapsState: { - ...initialState.swapsState, - swapsQuoteRefreshTime: swapsState.swapsQuoteRefreshTime, - swapsQuotePrefetchingRefreshTime: - swapsState.swapsQuotePrefetchingRefreshTime, - swapsFeatureFlags: swapsState.swapsFeatureFlags, - }, + /** + * Once quotes are fetched, we poll for new ones to keep the quotes up to date. + * Market and aggregator contract conditions can change fast enough that quotes + * will no longer be available after 1 or 2 minutes. When `fetchAndSetQuotes` is + * first called, it receives fetch parameters that are stored in state. These stored + * parameters are used on subsequent calls made during polling. + * + * Note: We stop polling after 3 requests, until new quotes are explicitly asked for. + * The logic that enforces that maximum is in the body of `fetchAndSetQuotes`. + */ + public stopPollingForQuotes() { + if (this._pollingTimeout) { + clearTimeout(this._pollingTimeout); + } + } + + // Private Methods + + private async _fetchSwapsNetworkConfig(chainId: ChainId) { + const response = await fetchWithCache({ + url: getBaseApi('network', chainId), + fetchOptions: { method: 'GET' }, + cacheOptions: { cacheRefreshTime: 600000 }, + functionName: '_fetchSwapsNetworkConfig', }); - clearTimeout(this.pollingTimeout); + const { refreshRates, parameters = {} } = response || {}; + if ( + !refreshRates || + typeof refreshRates.quotes !== 'number' || + typeof refreshRates.quotesPrefetching !== 'number' + ) { + throw new Error( + `MetaMask - invalid response for refreshRates: ${response}`, + ); + } + // We presently use milliseconds in the UI. + return { + quotes: refreshRates.quotes * 1000, + quotesPrefetching: refreshRates.quotesPrefetching * 1000, + stxGetTransactions: refreshRates.stxGetTransactions * 1000, + stxBatchStatus: refreshRates.stxBatchStatus * 1000, + stxStatusDeadline: refreshRates.stxStatusDeadline, + stxMaxFeeMultiplier: parameters.stxMaxFeeMultiplier, + }; } - async _findTopQuoteAndCalculateSavings(quotes = {}) { - const { contractExchangeRates: tokenConversionRates } = - this.getTokenRatesState(); + private async _findTopQuoteAndCalculateSavings( + quotes: Record = {}, + ): Promise<[string | null, Record] | Record> { + const { marketData } = this.getTokenRatesState(); + const chainId = this._getCurrentChainId(); + const tokenConversionRates = marketData[chainId]; + const { swapsState: { customGasPrice, customMaxPriorityFeePerGas }, } = this.store.getState(); - const chainId = this._getCurrentChainId(); const numQuotes = Object.keys(quotes).length; - if (!numQuotes) { + if (numQuotes === 0) { return {}; } @@ -730,7 +618,7 @@ export default class SwapsController { } = gasFeeEstimates; const suggestedMaxPriorityFeePerGasInHexWEI = decGWEIToHexWEI( - suggestedMaxPriorityFeePerGas, + Number(suggestedMaxPriorityFeePerGas), ); const estimatedBaseFeeNumeric = new Numeric( estimatedBaseFee, @@ -746,14 +634,15 @@ export default class SwapsController { .round(6) .toString(); } else if (gasEstimateType === GasEstimateTypes.legacy) { - usedGasPrice = customGasPrice || decGWEIToHexWEI(gasFeeEstimates.high); + usedGasPrice = + customGasPrice || decGWEIToHexWEI(Number(gasFeeEstimates.high)); } else if (gasEstimateType === GasEstimateTypes.ethGasPrice) { usedGasPrice = - customGasPrice || decGWEIToHexWEI(gasFeeEstimates.gasPrice); + customGasPrice || decGWEIToHexWEI(Number(gasFeeEstimates.gasPrice)); } - let topAggId = null; - let overallValueOfBestQuoteForSorting = null; + let topAggId: string = ''; + let overallValueOfBestQuoteForSorting: BigNumber; Object.values(newQuotes).forEach((quote) => { const { @@ -771,6 +660,10 @@ export default class SwapsController { multiLayerL1TradeFeeTotal, } = quote; + if (!trade || !destinationToken) { + return; + } + const tradeGasLimitForCalculation = gasEstimateWithRefund ? new BigNumber(gasEstimateWithRefund, 16) : new BigNumber(averageGas || MAX_GAS_LIMIT, 10); @@ -829,13 +722,16 @@ export default class SwapsController { decimalAdjustedDestinationAmount, ); - const tokenConversionRate = - tokenConversionRates[ - Object.keys(tokenConversionRates).find((tokenAddress) => - isEqualCaseInsensitive(tokenAddress, destinationToken), - ) - ]; - const conversionRateForSorting = tokenConversionRate || 1; + const tokenConversionRateKey = Object.keys(tokenConversionRates).find( + (tokenAddress) => + isEqualCaseInsensitive(tokenAddress, destinationToken), + ); + + const tokenConversionRate = tokenConversionRateKey + ? tokenConversionRates[tokenConversionRateKey] + : null; + + const conversionRateForSorting = tokenConversionRate?.price || 1; const ethValueOfTokens = decimalAdjustedDestinationAmount.times( conversionRateForSorting.toString(10), @@ -847,16 +743,15 @@ export default class SwapsController { chainId, ) ? 1 - : tokenConversionRate; + : tokenConversionRate?.price; - const overallValueOfQuoteForSorting = - conversionRateForCalculations === undefined - ? ethValueOfTokens - : ethValueOfTokens.minus(ethFee, 10); + const overallValueOfQuoteForSorting = conversionRateForCalculations + ? ethValueOfTokens.minus(ethFee, 10) + : ethValueOfTokens; quote.ethFee = ethFee.toString(10); - if (conversionRateForCalculations !== undefined) { + if (conversionRateForCalculations) { quote.ethValueOfTokens = ethValueOfTokens.toString(10); quote.overallValueOfQuote = overallValueOfQuoteForSorting.toString(10); quote.metaMaskFeeInEth = metaMaskFeeInTokens @@ -865,37 +760,35 @@ export default class SwapsController { } if ( - overallValueOfBestQuoteForSorting === null || - overallValueOfQuoteForSorting.gt(overallValueOfBestQuoteForSorting) + !overallValueOfBestQuoteForSorting || + overallValueOfQuoteForSorting.gt(overallValueOfBestQuoteForSorting || 0) ) { topAggId = aggregator; overallValueOfBestQuoteForSorting = overallValueOfQuoteForSorting; } }); + const tokenConversionRateKey = Object.keys(tokenConversionRates).find( + (tokenAddress) => + isEqualCaseInsensitive( + tokenAddress, + newQuotes[topAggId]?.destinationToken, + ), + ); + + const tokenConversionRate = tokenConversionRateKey + ? tokenConversionRates[tokenConversionRateKey] + : null; + const isBest = isSwapsDefaultTokenAddress( - newQuotes[topAggId].destinationToken, + newQuotes[topAggId]?.destinationToken, chainId, - ) || - Boolean( - tokenConversionRates[ - Object.keys(tokenConversionRates).find((tokenAddress) => - isEqualCaseInsensitive( - tokenAddress, - newQuotes[topAggId]?.destinationToken, - ), - ) - ], - ); - - let savings = null; + ) || Boolean(tokenConversionRate?.price); if (isBest) { const bestQuote = newQuotes[topAggId]; - savings = {}; - const { ethFee: medianEthFee, metaMaskFeeInEth: medianMetaMaskFee, @@ -904,26 +797,32 @@ export default class SwapsController { // Performance savings are calculated as: // (ethValueOfTokens for the best trade) - (ethValueOfTokens for the media trade) - savings.performance = new BigNumber(bestQuote.ethValueOfTokens, 10).minus( - medianEthValueOfTokens, - 10, - ); + const savingsPerformance = new BigNumber(bestQuote.ethValueOfTokens, 10) + .minus(medianEthValueOfTokens, 10) + .toString(10); // Fee savings are calculated as: // (fee for the median trade) - (fee for the best trade) - savings.fee = new BigNumber(medianEthFee).minus(bestQuote.ethFee, 10); + const fee = new BigNumber(medianEthFee) + .minus(bestQuote.ethFee, 10) + .toString(10); - savings.metaMaskFee = bestQuote.metaMaskFeeInEth; + const metaMaskFee = bestQuote.metaMaskFeeInEth; // Total savings are calculated as: // performance savings + fee savings - metamask fee - savings.total = savings.performance - .plus(savings.fee) - .minus(savings.metaMaskFee) + const total = new BigNumber(savingsPerformance) + .plus(fee) + .minus(metaMaskFee) .toString(10); - savings.performance = savings.performance.toString(10); - savings.fee = savings.fee.toString(10); - savings.medianMetaMaskFee = medianMetaMaskFee; + + const savings: QuoteSavings = { + performance: savingsPerformance, + fee, + total, + metaMaskFee, + medianMetaMaskFee, + }; newQuotes[topAggId].isBestQuote = true; newQuotes[topAggId].savings = savings; @@ -932,133 +831,174 @@ export default class SwapsController { return [topAggId, newQuotes]; } - async _getERC20Allowance(contractAddress, walletAddress, chainId) { - const contract = new Contract(contractAddress, abi, this.ethersProvider); + private async _getAllQuotesWithGasEstimates(quotes: Record) { + const quoteGasData = await Promise.all( + Object.values(quotes).map(async (quote) => { + if (!quote.trade) { + return { + gasLimit: null, + simulationFails: true, + aggId: quote.aggregator, + }; + } + const { gasLimit, simulationFails } = await this._timedoutGasReturn( + quote.trade, + quote.aggregator, + ); + return { gasLimit, simulationFails, aggId: quote.aggregator }; + }), + ); + + const newQuotes: Record = {}; + quoteGasData.forEach(({ gasLimit, simulationFails, aggId }) => { + if (gasLimit && !simulationFails) { + const gasEstimateWithRefund = calculateGasEstimateWithRefund( + quotes[aggId].maxGas, + quotes[aggId].estimatedRefund, + gasLimit, + ); + + // add to newQuotes object + + newQuotes[aggId] = { + ...quotes[aggId], + gasEstimate: gasLimit, + gasEstimateWithRefund, + }; + } else if (quotes[aggId].approvalNeeded) { + // If gas estimation fails, but an ERC-20 approve is needed, then we do not add any estimate property to the quote object + // Such quotes will rely on the maxGas and averageGas properties from the api + newQuotes[aggId] = quotes[aggId]; + } + // If gas estimation fails and no approval is needed, then we filter that quote out, so that it is not shown to the user + }); + return newQuotes; + } + + private async _getERC20Allowance( + contractAddress: string, + walletAddress: string, + chainId: ChainId, + ) { + const contract = new Contract(contractAddress, abi, this._ethersProvider); return await contract.allowance( walletAddress, - SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[chainId], + SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[ + chainId as keyof typeof SWAPS_CHAINID_CONTRACT_ADDRESS_MAP + ], ); } -} -/** - * Calculates the median overallValueOfQuote of a sample of quotes. - * - * @param {Array} _quotes - A sample of quote objects with overallValueOfQuote, ethFee, metaMaskFeeInEth, and ethValueOfTokens properties - * @returns {object} An object with the ethValueOfTokens, ethFee, and metaMaskFeeInEth of the quote with the median overallValueOfQuote - */ -function getMedianEthValueQuote(_quotes) { - if (!Array.isArray(_quotes) || _quotes.length === 0) { - throw new Error('Expected non-empty array param.'); + private _pollForNewQuotes() { + const { + swapsState: { + swapsQuoteRefreshTime, + swapsQuotePrefetchingRefreshTime, + quotesPollingLimitEnabled, + }, + } = this.store.getState(); + // swapsQuoteRefreshTime is used on the View Quote page, swapsQuotePrefetchingRefreshTime is used on the Build Quote page. + const quotesRefreshRateInMs = quotesPollingLimitEnabled + ? swapsQuoteRefreshTime + : swapsQuotePrefetchingRefreshTime; + this._pollingTimeout = setTimeout(() => { + const { swapsState } = this.store.getState(); + this.fetchAndSetQuotes( + swapsState.fetchParams as FetchTradesInfoParams, + swapsState.fetchParams?.metaData as FetchTradesInfoParamsMetadata, + true, + ); + }, quotesRefreshRateInMs); } - const quotes = [..._quotes]; + private _setSaveFetchedQuotes(status: boolean) { + const { swapsState } = this.store.getState(); + this.store.updateState({ + swapsState: { ...swapsState, saveFetchedQuotes: status }, + }); + } - quotes.sort((quoteA, quoteB) => { - const overallValueOfQuoteA = new BigNumber(quoteA.overallValueOfQuote, 10); - const overallValueOfQuoteB = new BigNumber(quoteB.overallValueOfQuote, 10); - if (overallValueOfQuoteA.equals(overallValueOfQuoteB)) { - return 0; + // Sets the network config from the MetaSwap API. + private async _setSwapsNetworkConfig() { + const chainId = this._getCurrentChainId(); + let swapsNetworkConfig; + try { + swapsNetworkConfig = await this._fetchSwapsNetworkConfig(chainId); + } catch (e) { + console.error('Request for Swaps network config failed: ', e); } - return overallValueOfQuoteA.lessThan(overallValueOfQuoteB) ? -1 : 1; - }); - - if (quotes.length % 2 === 1) { - // return middle values - const medianOverallValue = - quotes[(quotes.length - 1) / 2].overallValueOfQuote; - const quotesMatchingMedianQuoteValue = quotes.filter( - (quote) => medianOverallValue === quote.overallValueOfQuote, - ); - return meansOfQuotesFeesAndValue(quotesMatchingMedianQuoteValue); + const { swapsState: latestSwapsState } = this.store.getState(); + this.store.updateState({ + swapsState: { + ...latestSwapsState, + swapsQuoteRefreshTime: + swapsNetworkConfig?.quotes || FALLBACK_QUOTE_REFRESH_TIME, + swapsQuotePrefetchingRefreshTime: + swapsNetworkConfig?.quotesPrefetching || FALLBACK_QUOTE_REFRESH_TIME, + swapsStxGetTransactionsRefreshTime: + swapsNetworkConfig?.stxGetTransactions || + FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME, + swapsStxBatchStatusRefreshTime: + swapsNetworkConfig?.stxBatchStatus || + FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME, + swapsStxMaxFeeMultiplier: + swapsNetworkConfig?.stxMaxFeeMultiplier || + FALLBACK_SMART_TRANSACTIONS_MAX_FEE_MULTIPLIER, + }, + }); } - // return mean of middle two values - const upperIndex = quotes.length / 2; - const lowerIndex = upperIndex - 1; - - const overallValueAtUpperIndex = quotes[upperIndex].overallValueOfQuote; - const overallValueAtLowerIndex = quotes[lowerIndex].overallValueOfQuote; - - const quotesMatchingUpperIndexValue = quotes.filter( - (quote) => overallValueAtUpperIndex === quote.overallValueOfQuote, - ); - const quotesMatchingLowerIndexValue = quotes.filter( - (quote) => overallValueAtLowerIndex === quote.overallValueOfQuote, - ); - - const feesAndValueAtUpperIndex = meansOfQuotesFeesAndValue( - quotesMatchingUpperIndexValue, - ); - const feesAndValueAtLowerIndex = meansOfQuotesFeesAndValue( - quotesMatchingLowerIndexValue, - ); - - return { - ethFee: new BigNumber(feesAndValueAtUpperIndex.ethFee, 10) - .plus(feesAndValueAtLowerIndex.ethFee, 10) - .dividedBy(2) - .toString(10), - metaMaskFeeInEth: new BigNumber( - feesAndValueAtUpperIndex.metaMaskFeeInEth, - 10, - ) - .plus(feesAndValueAtLowerIndex.metaMaskFeeInEth, 10) - .dividedBy(2) - .toString(10), - ethValueOfTokens: new BigNumber( - feesAndValueAtUpperIndex.ethValueOfTokens, - 10, - ) - .plus(feesAndValueAtLowerIndex.ethValueOfTokens, 10) - .dividedBy(2) - .toString(10), - }; -} + private _timedoutGasReturn( + tradeTxParams: Trade, + aggregator = '', + ): Promise<{ gasLimit: string | null; simulationFails: boolean }> { + return new Promise((resolve) => { + let gasTimedOut = false; -/** - * Calculates the arithmetic mean for each of three properties - ethFee, metaMaskFeeInEth and ethValueOfTokens - across - * an array of objects containing those properties. - * - * @param {Array} quotes - A sample of quote objects with overallValueOfQuote, ethFee, metaMaskFeeInEth and - * ethValueOfTokens properties - * @returns {object} An object with the arithmetic mean each of the ethFee, metaMaskFeeInEth and ethValueOfTokens of - * the passed quote objects - */ -function meansOfQuotesFeesAndValue(quotes) { - const feeAndValueSumsAsBigNumbers = quotes.reduce( - (feeAndValueSums, quote) => ({ - ethFee: feeAndValueSums.ethFee.plus(quote.ethFee, 10), - metaMaskFeeInEth: feeAndValueSums.metaMaskFeeInEth.plus( - quote.metaMaskFeeInEth, - 10, - ), - ethValueOfTokens: feeAndValueSums.ethValueOfTokens.plus( - quote.ethValueOfTokens, - 10, - ), - }), - { - ethFee: new BigNumber(0, 10), - metaMaskFeeInEth: new BigNumber(0, 10), - ethValueOfTokens: new BigNumber(0, 10), - }, - ); - - return { - ethFee: feeAndValueSumsAsBigNumbers.ethFee - .div(quotes.length, 10) - .toString(10), - metaMaskFeeInEth: feeAndValueSumsAsBigNumbers.metaMaskFeeInEth - .div(quotes.length, 10) - .toString(10), - ethValueOfTokens: feeAndValueSumsAsBigNumbers.ethValueOfTokens - .div(quotes.length, 10) - .toString(10), - }; -} + const gasTimeout = setTimeout(() => { + gasTimedOut = true; + this.trackMetaMetricsEvent({ + event: MetaMetricsEventName.QuoteError, + category: MetaMetricsEventCategory.Swaps, + properties: { + error_type: MetaMetricsEventErrorType.GasTimeout, + aggregator, + }, + }); + resolve({ + gasLimit: null, + simulationFails: true, + }); + }, SECOND * 5); -export const utils = { - getMedianEthValueQuote, - meansOfQuotesFeesAndValue, -}; + // Remove gas from params that will be passed to the `estimateGas` call + // Including it can cause the estimate to fail if the actual gas needed + // exceeds the passed gas + const tradeTxParamsForGasEstimate = { + data: tradeTxParams.data, + from: tradeTxParams.from, + to: tradeTxParams.to, + value: tradeTxParams.value, + }; + + this.getBufferedGasLimit({ txParams: tradeTxParamsForGasEstimate }, 1) + .then(({ gasLimit, simulationFails }) => { + if (!gasTimedOut) { + clearTimeout(gasTimeout); + resolve({ gasLimit, simulationFails }); + } + }) + .catch((e) => { + captureException(e, { + extra: { + aggregator, + }, + }); + if (!gasTimedOut) { + clearTimeout(gasTimeout); + resolve({ gasLimit: null, simulationFails: true }); + } + }); + }); + } +} diff --git a/app/scripts/controllers/swaps.types.ts b/app/scripts/controllers/swaps.types.ts new file mode 100644 index 000000000000..0164e253678e --- /dev/null +++ b/app/scripts/controllers/swaps.types.ts @@ -0,0 +1,189 @@ +import { ExternalProvider, JsonRpcFetchFunc } from '@ethersproject/providers'; +import type { ChainId } from '@metamask/controller-utils'; +import { GasFeeState } from '@metamask/gas-fee-controller'; +import { ProviderConfig } from '@metamask/network-controller'; +import type { ObservableStore } from '@metamask/obs-store'; +import { TransactionParams } from '@metamask/transaction-controller'; +import type { + MetaMetricsEventCategory, + MetaMetricsEventName, +} from '../../../shared/constants/metametrics'; +import { fetchTradesInfo as defaultFetchTradesInfo } from '../../../shared/lib/swaps-utils'; + +export type SwapsControllerStore = ObservableStore<{ + swapsState: SwapsControllerState; +}>; + +export type SwapsControllerState = { + quotes: Record; + quotesPollingLimitEnabled: boolean; + fetchParams: + | (FetchTradesInfoParams & { + metaData: FetchTradesInfoParamsMetadata; + }) + | null; + tokens: string[] | null; + tradeTxId: string | null; + approveTxId: string | null; + quotesLastFetched: number | null; + customMaxGas: string; + customGasPrice: string | null; + customMaxFeePerGas: string | null; + customMaxPriorityFeePerGas: string | null; + swapsUserFeeLevel: string; + selectedAggId: string | null; + customApproveTxData: string; + errorKey: string; + topAggId: string | null; + routeState: string; + swapsFeatureIsLive: boolean; + saveFetchedQuotes: boolean; + swapsQuoteRefreshTime: number; + swapsQuotePrefetchingRefreshTime: number; + swapsStxBatchStatusRefreshTime: number; + swapsStxStatusDeadline?: number; + swapsStxGetTransactionsRefreshTime: number; + swapsStxMaxFeeMultiplier: number; + swapsFeatureFlags: Record; +}; + +export type SwapsControllerOptions = { + getBufferedGasLimit: ( + params: { + txParams: { + value: string; + data: string; + to: string; + from: string; + }; + }, + factor: number, + ) => Promise<{ gasLimit: string; simulationFails: boolean }>; + provider: ExternalProvider | JsonRpcFetchFunc; + getProviderConfig: () => ProviderConfig; + getTokenRatesState: () => { + marketData: Record< + string, + { + [tokenAddress: string]: { + price: number; + }; + } + >; + }; + fetchTradesInfo: typeof defaultFetchTradesInfo; + getCurrentChainId: () => ChainId; + getLayer1GasFee: (params: { + transactionParams: TransactionParams; + chainId: ChainId; + }) => Promise; + getEIP1559GasFeeEstimates: () => Promise; + trackMetaMetricsEvent: (event: { + event: MetaMetricsEventName; + category: MetaMetricsEventCategory; + properties: Record; + }) => void; +}; + +export type FetchTradesInfoParams = { + slippage: number; + sourceToken: string; + sourceDecimals: number; + destinationToken: string; + value: string; + fromAddress: string; + exchangeList: string; + balanceError: boolean; +}; + +export type FetchTradesInfoParamsMetadata = { + chainId: ChainId; + sourceTokenInfo: { + address: string; + symbol: string; + decimals: number; + iconUrl?: string; + }; + destinationTokenInfo: { + address: string; + symbol: string; + decimals: number; + iconUrl?: string; + }; +}; + +export type QuoteRequest = { + chainId: number; + destinationToken: string; + slippage: number; + sourceAmount: string; + sourceToken: string; + walletAddress: string; +}; + +export type AggType = 'DEX' | 'RFQ' | 'CONTRACT' | 'CNT' | 'AGG'; + +export type PriceSlippage = { + bucket: 'low' | 'medium' | 'high'; + calculationError: string; + destinationAmountInETH: number | null; + destinationAmountInNativeCurrency: number | null; + ratio: number | null; + sourceAmountInETH: number | null; + sourceAmountInNativeCurrency: number | null; + sourceAmountInUSD: number | null; + destinationAmountInUSD: number | null; +}; + +export type Trade = { + data: string; + from: string; + to: string; + value: string; + gas?: string; +}; + +export type QuoteSavings = { + performance: string; + fee: string; + metaMaskFee: string; + medianMetaMaskFee: string; + total: string; +}; +export type Quote = { + aggregator: string; + aggType: AggType; + approvalNeeded?: Trade | null; + averageGas: number; + destinationAmount: string | null; + destinationToken: string; + destinationTokenInfo: { + address: string; + symbol: string; + decimals: number; + iconUrl?: string; + }; + destinationTokenRate: number | null; + error: null | string; + estimatedRefund: string; + ethFee: string; + ethValueOfTokens: string; + fee: number; + fetchTime: number; + gasEstimate: string; + gasEstimateWithRefund: string; + gasMultiplier: number; + hasRoute: boolean; + isBestQuote: boolean; + maxGas: number; + metaMaskFeeInEth: string; + multiLayerL1TradeFeeTotal?: string; + overallValueOfQuote: string; + priceSlippage: PriceSlippage; + quoteRefreshSeconds: number; + savings?: QuoteSavings; + sourceAmount: string; + sourceToken: string; + sourceTokenRate: number; + trade: null | Trade; +}; diff --git a/app/scripts/controllers/swaps.utils.ts b/app/scripts/controllers/swaps.utils.ts new file mode 100644 index 000000000000..eb8a082272ff --- /dev/null +++ b/app/scripts/controllers/swaps.utils.ts @@ -0,0 +1,148 @@ +import { BigNumber } from 'bignumber.js'; +import { MAX_GAS_LIMIT } from './swaps.constants'; +import type { Quote } from './swaps.types'; + +/** + * Calculates the median overallValueOfQuote of a sample of quotes. + * + * @param _quotes - A sample of quote objects with overallValueOfQuote, ethFee, metaMaskFeeInEth, and ethValueOfTokens properties + * @returns An object with the ethValueOfTokens, ethFee, and metaMaskFeeInEth of the quote with the median overallValueOfQuote + */ +export function getMedianEthValueQuote(_quotes: Quote[]) { + if (!Array.isArray(_quotes) || _quotes.length === 0) { + throw new Error('Expected non-empty array param.'); + } + + const quotes = [..._quotes]; + + quotes.sort((quoteA, quoteB) => { + const overallValueOfQuoteA = new BigNumber(quoteA.overallValueOfQuote, 10); + const overallValueOfQuoteB = new BigNumber(quoteB.overallValueOfQuote, 10); + if (overallValueOfQuoteA.equals(overallValueOfQuoteB)) { + return 0; + } + return overallValueOfQuoteA.lessThan(overallValueOfQuoteB) ? -1 : 1; + }); + + if (quotes.length % 2 === 1) { + // return middle values + const medianOverallValue = + quotes[(quotes.length - 1) / 2].overallValueOfQuote; + const quotesMatchingMedianQuoteValue = quotes.filter( + (quote) => medianOverallValue === quote.overallValueOfQuote, + ); + return meansOfQuotesFeesAndValue(quotesMatchingMedianQuoteValue); + } + + // return mean of middle two values + const upperIndex = quotes.length / 2; + const lowerIndex = upperIndex - 1; + + const overallValueAtUpperIndex = quotes[upperIndex].overallValueOfQuote; + const overallValueAtLowerIndex = quotes[lowerIndex].overallValueOfQuote; + + const quotesMatchingUpperIndexValue = quotes.filter( + (quote) => overallValueAtUpperIndex === quote.overallValueOfQuote, + ); + const quotesMatchingLowerIndexValue = quotes.filter( + (quote) => overallValueAtLowerIndex === quote.overallValueOfQuote, + ); + + const feesAndValueAtUpperIndex = meansOfQuotesFeesAndValue( + quotesMatchingUpperIndexValue, + ); + const feesAndValueAtLowerIndex = meansOfQuotesFeesAndValue( + quotesMatchingLowerIndexValue, + ); + + return { + ethFee: new BigNumber(feesAndValueAtUpperIndex.ethFee, 10) + .plus(feesAndValueAtLowerIndex.ethFee, 10) + .dividedBy(2) + .toString(10), + metaMaskFeeInEth: new BigNumber( + feesAndValueAtUpperIndex.metaMaskFeeInEth, + 10, + ) + .plus(feesAndValueAtLowerIndex.metaMaskFeeInEth, 10) + .dividedBy(2) + .toString(10), + ethValueOfTokens: new BigNumber( + feesAndValueAtUpperIndex.ethValueOfTokens, + 10, + ) + .plus(feesAndValueAtLowerIndex.ethValueOfTokens, 10) + .dividedBy(2) + .toString(10), + }; +} + +/** + * Calculates the arithmetic mean for each of three properties - ethFee, metaMaskFeeInEth and ethValueOfTokens - across + * an array of objects containing those properties. + * + * @param quotes - A sample of quote objects with overallValueOfQuote, ethFee, metaMaskFeeInEth and + * ethValueOfTokens properties + * @returns An object with the arithmetic mean each of the ethFee, metaMaskFeeInEth and ethValueOfTokens of + * the passed quote objects + */ +export function meansOfQuotesFeesAndValue(quotes: Quote[]) { + const feeAndValueSumsAsBigNumbers = quotes.reduce( + (feeAndValueSums, quote) => ({ + ethFee: feeAndValueSums.ethFee.plus(quote.ethFee, 10), + metaMaskFeeInEth: feeAndValueSums.metaMaskFeeInEth.plus( + quote.metaMaskFeeInEth, + 10, + ), + ethValueOfTokens: feeAndValueSums.ethValueOfTokens.plus( + quote.ethValueOfTokens, + 10, + ), + }), + { + ethFee: new BigNumber(0, 10), + metaMaskFeeInEth: new BigNumber(0, 10), + ethValueOfTokens: new BigNumber(0, 10), + }, + ); + + return { + ethFee: feeAndValueSumsAsBigNumbers.ethFee + .div(quotes.length, 10) + .toString(10), + metaMaskFeeInEth: feeAndValueSumsAsBigNumbers.metaMaskFeeInEth + .div(quotes.length, 10) + .toString(10), + ethValueOfTokens: feeAndValueSumsAsBigNumbers.ethValueOfTokens + .div(quotes.length, 10) + .toString(10), + }; +} + +/** + * Calculates the gas estimate after subtracting a refund from the maximum gas limit. + * + * @param maxGas - The maximum gas limit, defaulting to MAX_GAS_LIMIT. + * @param estimatedRefund - The estimated refund to subtract from the maximum gas limit, represented as a string. + * @param estimatedGas - The estimated gas required for the transaction, represented as a string. + * @returns The gas estimate with refund applied, represented as a hexadecimal string. If the subtraction + * results in a negative value or is less than the estimated gas, returns the estimated gas. + */ +export function calculateGasEstimateWithRefund( + maxGas = MAX_GAS_LIMIT, + estimatedRefund = '0', + estimatedGas = '0', +) { + const maxGasMinusRefund = new BigNumber(maxGas, 10).minus( + estimatedRefund, + 10, + ); + const isMaxGasMinusRefundNegative = maxGasMinusRefund.lt(0); + + const gasEstimateWithRefund = + !isMaxGasMinusRefundNegative && maxGasMinusRefund.lt(estimatedGas, 16) + ? `0x${maxGasMinusRefund.toString(16)}` + : estimatedGas; + + return gasEstimateWithRefund; +} diff --git a/app/scripts/controllers/user-storage/encryption/cache.ts b/app/scripts/controllers/user-storage/encryption/cache.ts new file mode 100644 index 000000000000..7e9d80c78442 --- /dev/null +++ b/app/scripts/controllers/user-storage/encryption/cache.ts @@ -0,0 +1,105 @@ +import { base64ToByteArray, byteArrayToBase64 } from './utils'; + +type CachedEntry = { + salt: Uint8Array; + base64Salt: string; + key: Uint8Array; +}; + +const MAX_PASSWORD_CACHES = 3; +const MAX_SALT_CACHES = 10; + +/** + * In-Memory Caching derived keys based from a given salt and password. + */ +type PasswordMemCachedKDF = { + [hashedPassword: string]: Map; +}; +let inMemCachedKDF: PasswordMemCachedKDF = {}; +const getPasswordCache = (hashedPassword: string) => { + inMemCachedKDF[hashedPassword] ??= new Map(); + return inMemCachedKDF[hashedPassword]; +}; + +/** + * Returns a given cached derived key from a hashed password and salt + * + * @param hashedPassword - hashed password for cache lookup + * @param salt - provide salt to receive cached key + * @returns cached key + */ +export function getCachedKeyBySalt( + hashedPassword: string, + salt: Uint8Array, +): CachedEntry | undefined { + const cache = getPasswordCache(hashedPassword); + const base64Salt = byteArrayToBase64(salt); + const cachedKey = cache.get(base64Salt); + if (!cachedKey) { + return undefined; + } + + return { + salt, + base64Salt, + key: cachedKey, + }; +} + +/** + * Gets any cached key for a given hashed password + * + * @param hashedPassword - hashed password for cache lookup + * @returns any (the first) cached key + */ +export function getAnyCachedKey( + hashedPassword: string, +): CachedEntry | undefined { + const cache = getPasswordCache(hashedPassword); + + // Takes 1 item from an Iterator via Map.entries() + const cachedEntry: [string, Uint8Array] | undefined = cache + .entries() + .next().value; + + if (!cachedEntry) { + return undefined; + } + + const base64Salt = cachedEntry[0]; + const bytesSalt = base64ToByteArray(base64Salt); + return { + salt: bytesSalt, + base64Salt, + key: cachedEntry[1], + }; +} + +/** + * Sets a key to the in memory cache. + * We have set an arbitrary size of 10 cached keys per hashed password. + * + * @param hashedPassword - hashed password for cache lookup + * @param salt - salt to set new derived key + * @param key - derived key we are setting + */ +export function setCachedKey( + hashedPassword: string, + salt: Uint8Array, + key: Uint8Array, +): void { + // Max password caches + if (Object.keys(inMemCachedKDF).length > MAX_PASSWORD_CACHES) { + inMemCachedKDF = {}; + } + + const cache = getPasswordCache(hashedPassword); + const base64Salt = byteArrayToBase64(salt); + + // Max salt caches + if (cache.size > MAX_SALT_CACHES) { + cache.clear(); + } + + cache.set(base64Salt, key); +} diff --git a/app/scripts/controllers/user-storage/encryption/encryption.test.ts b/app/scripts/controllers/user-storage/encryption/encryption.test.ts new file mode 100644 index 000000000000..dbe34a73a5e8 --- /dev/null +++ b/app/scripts/controllers/user-storage/encryption/encryption.test.ts @@ -0,0 +1,40 @@ +import { createMockFullUserStorage } from '../../metamask-notifications/mocks/mock-notification-user-storage'; +import encryption, { createSHA256Hash } from './encryption'; + +describe('encryption tests', () => { + const PASSWORD = '123'; + const DATA1 = 'Hello World'; + const DATA2 = JSON.stringify({ foo: 'bar' }); + const DATA3 = JSON.stringify(createMockFullUserStorage()); + + it('Should encrypt and decrypt data', () => { + function actEncryptDecrypt(data: string) { + const encryptedString = encryption.encryptString(data, PASSWORD); + const decryptString = encryption.decryptString(encryptedString, PASSWORD); + return decryptString; + } + + expect(actEncryptDecrypt(DATA1)).toBe(DATA1); + expect(actEncryptDecrypt(DATA2)).toBe(DATA2); + expect(actEncryptDecrypt(DATA3)).toBe(DATA3); + }); + + it('Should decrypt some existing data', () => { + const encryptedData = `{"v":"1","t":"scrypt","d":"WNEp1QXUZsxCfW9b27uzZ18CtsMvKP6+cqLq8NLAItXeYcFcUjtKprfvedHxf5JN9Q7pe50qnA==","o":{"N":131072,"r":8,"p":1,"dkLen":16},"saltLen":16}`; + const result = encryption.decryptString(encryptedData, PASSWORD); + expect(result).toBe(DATA1); + }); + + it('Should sha-256 hash a value and should be deterministic', () => { + const DATA = 'Hello World'; + const EXPECTED_HASH = + 'a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e'; + + const hash1 = createSHA256Hash(DATA); + expect(hash1).toBe(EXPECTED_HASH); + + // Hash should be deterministic (same output with same input) + const hash2 = createSHA256Hash(DATA); + expect(hash1).toBe(hash2); + }); +}); diff --git a/app/scripts/controllers/user-storage/encryption/encryption.ts b/app/scripts/controllers/user-storage/encryption/encryption.ts new file mode 100644 index 000000000000..cdd8feaf77b3 --- /dev/null +++ b/app/scripts/controllers/user-storage/encryption/encryption.ts @@ -0,0 +1,196 @@ +import { scrypt } from '@noble/hashes/scrypt'; +import { sha256 } from '@noble/hashes/sha256'; +import { utf8ToBytes, concatBytes, bytesToHex } from '@noble/hashes/utils'; +import { gcm } from '@noble/ciphers/aes'; +import { randomBytes } from '@noble/ciphers/webcrypto'; +import { getAnyCachedKey, getCachedKeyBySalt, setCachedKey } from './cache'; +import { base64ToByteArray, byteArrayToBase64, bytesToUtf8 } from './utils'; + +export type EncryptedPayload = { + // version + v: '1'; + + // key derivation function algorithm - scrypt + t: 'scrypt'; + + // data + d: string; + + // encryption options - scrypt + o: { + N: number; + r: number; + p: number; + dkLen: number; + }; + + // Salt options + saltLen: number; +}; + +class EncryptorDecryptor { + #ALGORITHM_NONCE_SIZE: number = 12; // 12 bytes + + #ALGORITHM_KEY_SIZE: number = 16; // 16 bytes + + #SCRYPT_SALT_SIZE: number = 16; // 16 bytes + + // see: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#scrypt + #SCRYPT_N: number = 2 ** 17; // CPU/memory cost parameter (must be a power of 2, > 1) + + #SCRYPT_r: number = 8; // Block size parameter + + #SCRYPT_p: number = 1; // Parallelization parameter + + encryptString(plaintext: string, password: string): string { + try { + return this.#encryptStringV1(plaintext, password); + } catch (e) { + const errorMessage = e instanceof Error ? e.message : e; + throw new Error(`Unable to encrypt string - ${errorMessage}`); + } + } + + decryptString(encryptedDataStr: string, password: string): string { + try { + const encryptedData: EncryptedPayload = JSON.parse(encryptedDataStr); + if (encryptedData.v === '1') { + if (encryptedData.t === 'scrypt') { + return this.#decryptStringV1(encryptedData, password); + } + } + throw new Error( + `Unsupported encrypted data payload - ${encryptedDataStr}`, + ); + } catch (e) { + const errorMessage = e instanceof Error ? e.message : e; + throw new Error(`Unable to decrypt string - ${errorMessage}`); + } + } + + #encryptStringV1(plaintext: string, password: string): string { + const { key, salt } = this.#getOrGenerateScryptKey(password, { + N: this.#SCRYPT_N, + r: this.#SCRYPT_r, + p: this.#SCRYPT_p, + dkLen: this.#ALGORITHM_KEY_SIZE, + }); + + // Encrypt and prepend salt. + const plaintextRaw = utf8ToBytes(plaintext); + const ciphertextAndNonceAndSalt = concatBytes( + salt, + this.#encrypt(plaintextRaw, key), + ); + + // Convert to Base64 + const encryptedData = byteArrayToBase64(ciphertextAndNonceAndSalt); + + const encryptedPayload: EncryptedPayload = { + v: '1', + t: 'scrypt', + d: encryptedData, + o: { + N: this.#SCRYPT_N, + r: this.#SCRYPT_r, + p: this.#SCRYPT_p, + dkLen: this.#ALGORITHM_KEY_SIZE, + }, + saltLen: this.#SCRYPT_SALT_SIZE, + }; + + return JSON.stringify(encryptedPayload); + } + + #decryptStringV1(data: EncryptedPayload, password: string): string { + const { o, d: base64CiphertextAndNonceAndSalt, saltLen } = data; + + // Decode the base64. + const ciphertextAndNonceAndSalt = base64ToByteArray( + base64CiphertextAndNonceAndSalt, + ); + + // Create buffers of salt and ciphertextAndNonce. + const salt = ciphertextAndNonceAndSalt.slice(0, saltLen); + const ciphertextAndNonce = ciphertextAndNonceAndSalt.slice( + saltLen, + ciphertextAndNonceAndSalt.length, + ); + + // Derive the key. + const { key } = this.#getOrGenerateScryptKey( + password, + { + N: o.N, + r: o.r, + p: o.p, + dkLen: o.dkLen, + }, + salt, + ); + + // Decrypt and return result. + return bytesToUtf8(this.#decrypt(ciphertextAndNonce, key)); + } + + #encrypt(plaintext: Uint8Array, key: Uint8Array): Uint8Array { + const nonce = randomBytes(this.#ALGORITHM_NONCE_SIZE); + + // Encrypt and prepend nonce. + const ciphertext = gcm(key, nonce).encrypt(plaintext); + + return concatBytes(nonce, ciphertext); + } + + #decrypt(ciphertextAndNonce: Uint8Array, key: Uint8Array): Uint8Array { + // Create buffers of nonce and ciphertext. + const nonce = ciphertextAndNonce.slice(0, this.#ALGORITHM_NONCE_SIZE); + const ciphertext = ciphertextAndNonce.slice( + this.#ALGORITHM_NONCE_SIZE, + ciphertextAndNonce.length, + ); + + // Decrypt and return result. + return gcm(key, nonce).decrypt(ciphertext); + } + + #getOrGenerateScryptKey( + password: string, + o: EncryptedPayload['o'], + salt?: Uint8Array, + ) { + const hashedPassword = createSHA256Hash(password); + const cachedKey = salt + ? getCachedKeyBySalt(hashedPassword, salt) + : getAnyCachedKey(hashedPassword); + + if (cachedKey) { + return { + key: cachedKey.key, + salt: cachedKey.salt, + }; + } + + const newSalt = salt ?? randomBytes(this.#SCRYPT_SALT_SIZE); + const newKey = scrypt(password, newSalt, { + N: o.N, + r: o.r, + p: o.p, + dkLen: o.dkLen, + }); + setCachedKey(hashedPassword, newSalt, newKey); + + return { + key: newKey, + salt: newSalt, + }; + } +} + +const encryption = new EncryptorDecryptor(); +export default encryption; + +export function createSHA256Hash(data: string): string { + const hashedData = sha256(data); + return bytesToHex(hashedData); +} diff --git a/app/scripts/controllers/user-storage/encryption/index.ts b/app/scripts/controllers/user-storage/encryption/index.ts new file mode 100644 index 000000000000..3582e3b9e2a1 --- /dev/null +++ b/app/scripts/controllers/user-storage/encryption/index.ts @@ -0,0 +1,4 @@ +import Encryption from './encryption'; + +export * from './encryption'; +export default Encryption; diff --git a/app/scripts/controllers/user-storage/encryption/utils.ts b/app/scripts/controllers/user-storage/encryption/utils.ts new file mode 100644 index 000000000000..76ceda77eb7b --- /dev/null +++ b/app/scripts/controllers/user-storage/encryption/utils.ts @@ -0,0 +1,12 @@ +export function byteArrayToBase64(byteArray: Uint8Array) { + return Buffer.from(byteArray).toString('base64'); +} + +export function base64ToByteArray(base64: string) { + return new Uint8Array(Buffer.from(base64, 'base64')); +} + +export function bytesToUtf8(byteArray: Uint8Array) { + const decoder = new TextDecoder('utf-8'); + return decoder.decode(byteArray); +} diff --git a/app/scripts/controllers/user-storage/mocks/mockResponses.ts b/app/scripts/controllers/user-storage/mocks/mockResponses.ts new file mode 100644 index 000000000000..c1b3896f446f --- /dev/null +++ b/app/scripts/controllers/user-storage/mocks/mockResponses.ts @@ -0,0 +1,35 @@ +import { createEntryPath } from '../schema'; +import { GetUserStorageResponse, USER_STORAGE_ENDPOINT } from '../services'; +import { MOCK_ENCRYPTED_STORAGE_DATA, MOCK_STORAGE_KEY } from './mockStorage'; + +type MockResponse = { + url: string; + requestMethod: 'GET' | 'POST' | 'PUT'; + response: unknown; +}; + +export const MOCK_USER_STORAGE_NOTIFICATIONS_ENDPOINT = `${USER_STORAGE_ENDPOINT}${createEntryPath( + 'notification_settings', + MOCK_STORAGE_KEY, +)}`; + +const MOCK_GET_USER_STORAGE_RESPONSE: GetUserStorageResponse = { + HashedKey: 'HASHED_KEY', + Data: MOCK_ENCRYPTED_STORAGE_DATA, +}; + +export function getMockUserStorageGetResponse() { + return { + url: MOCK_USER_STORAGE_NOTIFICATIONS_ENDPOINT, + requestMethod: 'GET', + response: MOCK_GET_USER_STORAGE_RESPONSE, + } satisfies MockResponse; +} + +export function getMockUserStoragePutResponse() { + return { + url: MOCK_USER_STORAGE_NOTIFICATIONS_ENDPOINT, + requestMethod: 'PUT', + response: null, + } satisfies MockResponse; +} diff --git a/app/scripts/controllers/user-storage/mocks/mockServices.ts b/app/scripts/controllers/user-storage/mocks/mockServices.ts new file mode 100644 index 000000000000..d612ebe6ed55 --- /dev/null +++ b/app/scripts/controllers/user-storage/mocks/mockServices.ts @@ -0,0 +1,34 @@ +import nock from 'nock'; +import { + getMockUserStorageGetResponse, + getMockUserStoragePutResponse, +} from './mockResponses'; + +type MockReply = { + status: nock.StatusCode; + body?: nock.Body; +}; + +export function mockEndpointGetUserStorage(mockReply?: MockReply) { + const mockResponse = getMockUserStorageGetResponse(); + const reply = mockReply ?? { + status: 200, + body: mockResponse.response, + }; + + const mockEndpoint = nock(mockResponse.url) + .get('') + .reply(reply.status, reply.body); + + return mockEndpoint; +} + +export function mockEndpointUpsertUserStorage( + mockReply?: Pick, +) { + const mockResponse = getMockUserStoragePutResponse(); + const mockEndpoint = nock(mockResponse.url) + .put('') + .reply(mockReply?.status ?? 204); + return mockEndpoint; +} diff --git a/app/scripts/controllers/user-storage/mocks/mockStorage.ts b/app/scripts/controllers/user-storage/mocks/mockStorage.ts new file mode 100644 index 000000000000..4a43a80556e1 --- /dev/null +++ b/app/scripts/controllers/user-storage/mocks/mockStorage.ts @@ -0,0 +1,9 @@ +import encryption, { createSHA256Hash } from '../encryption'; + +export const MOCK_STORAGE_KEY_SIGNATURE = 'mockStorageKey'; +export const MOCK_STORAGE_KEY = createSHA256Hash(MOCK_STORAGE_KEY_SIGNATURE); +export const MOCK_STORAGE_DATA = JSON.stringify({ hello: 'world' }); +export const MOCK_ENCRYPTED_STORAGE_DATA = encryption.encryptString( + MOCK_STORAGE_DATA, + MOCK_STORAGE_KEY, +); diff --git a/app/scripts/controllers/user-storage/schema.test.ts b/app/scripts/controllers/user-storage/schema.test.ts new file mode 100644 index 000000000000..d08b0802bf49 --- /dev/null +++ b/app/scripts/controllers/user-storage/schema.test.ts @@ -0,0 +1,21 @@ +import { USER_STORAGE_ENTRIES, createEntryPath } from './schema'; + +describe('schema.ts - createEntryPath()', () => { + const MOCK_STORAGE_KEY = 'MOCK_STORAGE_KEY'; + + test('creates a valid entry path', () => { + const result = createEntryPath('notification_settings', MOCK_STORAGE_KEY); + + // Ensures that the path and the entry name are correct. + // If this differs then indicates a potential change on how this path is computed + const expected = `/${USER_STORAGE_ENTRIES.notification_settings.path}/50f65447980018849b991e038d7ad87de5cf07fbad9736b0280e93972e17bac8`; + expect(result).toBe(expected); + }); + + test('Should throw if using an entry that does not exist', () => { + expect(() => { + // @ts-expect-error mocking a fake entry for testing. + createEntryPath('fake_entry'); + }).toThrow(); + }); +}); diff --git a/app/scripts/controllers/user-storage/schema.ts b/app/scripts/controllers/user-storage/schema.ts new file mode 100644 index 000000000000..19bc0ccfae52 --- /dev/null +++ b/app/scripts/controllers/user-storage/schema.ts @@ -0,0 +1,38 @@ +import { createSHA256Hash } from './encryption'; + +type UserStorageEntry = { path: string; entryName: string }; + +/** + * The User Storage Endpoint requires a path and an entry name. + * Developers can provide additional paths by extending this variable below + */ +export const USER_STORAGE_ENTRIES = { + notification_settings: { + path: 'notifications', + entryName: 'notification_settings', + }, +} satisfies Record; + +export type UserStorageEntryKeys = keyof typeof USER_STORAGE_ENTRIES; + +/** + * Constructs a unique entry path for a user. + * This can be done due to the uniqueness of the storage key (no users will share the same storage key). + * The users entry is a unique hash that cannot be reversed. + * + * @param entryKey + * @param storageKey + * @returns + */ +export function createEntryPath( + entryKey: UserStorageEntryKeys, + storageKey: string, +): string { + const entry = USER_STORAGE_ENTRIES[entryKey]; + if (!entry) { + throw new Error(`user-storage - invalid entry provided: ${entryKey}`); + } + + const hashedKey = createSHA256Hash(entry.entryName + storageKey); + return `/${entry.path}/${hashedKey}`; +} diff --git a/app/scripts/controllers/user-storage/services.test.ts b/app/scripts/controllers/user-storage/services.test.ts new file mode 100644 index 000000000000..a746dcee858f --- /dev/null +++ b/app/scripts/controllers/user-storage/services.test.ts @@ -0,0 +1,89 @@ +import { + mockEndpointGetUserStorage, + mockEndpointUpsertUserStorage, +} from './mocks/mockServices'; +import { + MOCK_ENCRYPTED_STORAGE_DATA, + MOCK_STORAGE_DATA, + MOCK_STORAGE_KEY, +} from './mocks/mockStorage'; +import { + GetUserStorageResponse, + getUserStorage, + upsertUserStorage, +} from './services'; + +describe('user-storage/services.ts - getUserStorage() tests', () => { + test('returns user storage data', async () => { + const mockGetUserStorage = mockEndpointGetUserStorage(); + const result = await actCallGetUserStorage(); + + mockGetUserStorage.done(); + expect(result).toBe(MOCK_STORAGE_DATA); + }); + + test('returns null if endpoint does not have entry', async () => { + const mockGetUserStorage = mockEndpointGetUserStorage({ status: 404 }); + const result = await actCallGetUserStorage(); + + mockGetUserStorage.done(); + expect(result).toBe(null); + }); + + test('returns null if endpoint fails', async () => { + const mockGetUserStorage = mockEndpointGetUserStorage({ status: 500 }); + const result = await actCallGetUserStorage(); + + mockGetUserStorage.done(); + expect(result).toBe(null); + }); + + test('returns null if unable to decrypt data', async () => { + const badResponseData: GetUserStorageResponse = { + HashedKey: 'MOCK_HASH', + Data: 'Bad Encrypted Data', + }; + const mockGetUserStorage = mockEndpointGetUserStorage({ + status: 200, + body: badResponseData, + }); + const result = await actCallGetUserStorage(); + + mockGetUserStorage.done(); + expect(result).toBe(null); + }); + + function actCallGetUserStorage() { + return getUserStorage({ + bearerToken: 'MOCK_BEARER_TOKEN', + entryKey: 'notification_settings', + storageKey: MOCK_STORAGE_KEY, + }); + } +}); + +describe('user-storage/services.ts - upsertUserStorage() tests', () => { + test('invokes upsert endpoint with no errors', async () => { + const mockUpsertUserStorage = mockEndpointUpsertUserStorage(); + await actCallUpsertUserStorage(); + + expect(mockUpsertUserStorage.isDone()).toBe(true); + }); + + test('throws error if unable to upsert user storage', async () => { + const mockUpsertUserStorage = mockEndpointUpsertUserStorage({ + status: 500, + }); + + await expect(actCallUpsertUserStorage()).rejects.toThrow(); + mockUpsertUserStorage.done(); + }); + + function actCallUpsertUserStorage() { + return upsertUserStorage(MOCK_ENCRYPTED_STORAGE_DATA, { + bearerToken: 'MOCK_BEARER_TOKEN', + entryKey: 'notification_settings', + storageKey: MOCK_STORAGE_KEY, + }); + } +}); diff --git a/app/scripts/controllers/user-storage/services.ts b/app/scripts/controllers/user-storage/services.ts new file mode 100644 index 000000000000..269009850079 --- /dev/null +++ b/app/scripts/controllers/user-storage/services.ts @@ -0,0 +1,83 @@ +import log from 'loglevel'; + +import encryption from './encryption'; +import { UserStorageEntryKeys, createEntryPath } from './schema'; + +export const USER_STORAGE_API = process.env.USER_STORAGE_API || ''; +export const USER_STORAGE_ENDPOINT = `${USER_STORAGE_API}/api/v1/userstorage`; + +export type GetUserStorageResponse = { + HashedKey: string; + Data: string; +}; + +export type UserStorageOptions = { + bearerToken: string; + entryKey: UserStorageEntryKeys; + storageKey: string; +}; + +export async function getUserStorage( + opts: UserStorageOptions, +): Promise { + try { + const path = createEntryPath(opts.entryKey, opts.storageKey); + const url = new URL(`${USER_STORAGE_ENDPOINT}${path}`); + + const userStorageResponse = await fetch(url.toString(), { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${opts.bearerToken}`, + }, + }); + + // Acceptable error - since indicates entry does not exist. + if (userStorageResponse.status === 404) { + return null; + } + + if (userStorageResponse.status !== 200) { + throw new Error('Unable to get User Storage'); + } + + const userStorage: GetUserStorageResponse | null = + await userStorageResponse.json(); + const encryptedData = userStorage?.Data ?? null; + + if (!encryptedData) { + return null; + } + + const decryptedData = encryption.decryptString( + encryptedData, + opts.storageKey, + ); + + return decryptedData; + } catch (e) { + log.error('Failed to get user storage', e); + return null; + } +} + +export async function upsertUserStorage( + data: string, + opts: UserStorageOptions, +): Promise { + const encryptedData = encryption.encryptString(data, opts.storageKey); + const path = createEntryPath(opts.entryKey, opts.storageKey); + const url = new URL(`${USER_STORAGE_ENDPOINT}${path}`); + + const res = await fetch(url.toString(), { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${opts.bearerToken}`, + }, + body: JSON.stringify({ data: encryptedData }), + }); + + if (!res.ok) { + throw new Error('user-storage - unable to upsert data'); + } +} diff --git a/app/scripts/controllers/user-storage/user-storage-controller.test.ts b/app/scripts/controllers/user-storage/user-storage-controller.test.ts new file mode 100644 index 000000000000..b70141f6eaab --- /dev/null +++ b/app/scripts/controllers/user-storage/user-storage-controller.test.ts @@ -0,0 +1,418 @@ +import nock from 'nock'; +import { ControllerMessenger } from '@metamask/base-controller'; +import { + AuthenticationControllerGetBearerToken, + AuthenticationControllerGetSessionProfile, + AuthenticationControllerIsSignedIn, + AuthenticationControllerPerformSignIn, +} from '../authentication/authentication-controller'; +import { + MetamaskNotificationsControllerDisableMetamaskNotifications, + MetamaskNotificationsControllerSelectIsMetamaskNotificationsEnabled, +} from '../metamask-notifications/metamask-notifications'; +import { + MOCK_STORAGE_DATA, + MOCK_STORAGE_KEY, + MOCK_STORAGE_KEY_SIGNATURE, +} from './mocks/mockStorage'; +import UserStorageController, { + AllowedActions, +} from './user-storage-controller'; +import { + mockEndpointGetUserStorage, + mockEndpointUpsertUserStorage, +} from './mocks/mockServices'; + +const typedMockFn = unknown>() => + jest.fn, Parameters>(); + +describe('user-storage/user-storage-controller - constructor() tests', () => { + test('Creates UserStorage with default state', () => { + const { messengerMocks } = arrangeMocks(); + const controller = new UserStorageController({ + messenger: messengerMocks.messenger, + getMetaMetricsState: () => true, + }); + + expect(controller.state.isProfileSyncingEnabled).toBe(true); + }); + + function arrangeMocks() { + return { + messengerMocks: mockUserStorageMessenger(), + }; + } +}); + +describe('user-storage/user-storage-controller - performGetStorage() tests', () => { + test('returns users notification storage', async () => { + const { messengerMocks, mockAPI } = arrangeMocks(); + const controller = new UserStorageController({ + messenger: messengerMocks.messenger, + getMetaMetricsState: () => true, + }); + + const result = await controller.performGetStorage('notification_settings'); + mockAPI.done(); + expect(result).toBe(MOCK_STORAGE_DATA); + }); + + test('rejects if UserStorage is not enabled', async () => { + const { messengerMocks } = arrangeMocks(); + const controller = new UserStorageController({ + messenger: messengerMocks.messenger, + getMetaMetricsState: () => true, + state: { + isProfileSyncingEnabled: false, + isProfileSyncingUpdateLoading: false, + }, + }); + + await expect( + controller.performGetStorage('notification_settings'), + ).rejects.toThrow(); + }); + + // @ts-expect-error This is missing from the Mocha type definitions + test.each([ + [ + 'fails when no bearer token is found (auth errors)', + (messengerMocks: ReturnType) => + messengerMocks.mockAuthGetBearerToken.mockRejectedValue( + new Error('MOCK FAILURE'), + ), + ], + [ + 'fails when no session identifier is found (auth errors)', + (messengerMocks: ReturnType) => + messengerMocks.mockAuthGetSessionProfile.mockRejectedValue( + new Error('MOCK FAILURE'), + ), + ], + ])( + 'rejects on auth failure - %s', + async ( + _: string, + arrangeFailureCase: ( + messengerMocks: ReturnType, + ) => void, + ) => { + const { messengerMocks } = arrangeMocks(); + arrangeFailureCase(messengerMocks); + const controller = new UserStorageController({ + messenger: messengerMocks.messenger, + getMetaMetricsState: () => true, + }); + + await expect( + controller.performGetStorage('notification_settings'), + ).rejects.toThrow(); + }, + ); + + function arrangeMocks() { + return { + messengerMocks: mockUserStorageMessenger(), + mockAPI: mockEndpointGetUserStorage(), + }; + } +}); + +describe('user-storage/user-storage-controller - performSetStorage() tests', () => { + test('saves users storage', async () => { + const { messengerMocks, mockAPI } = arrangeMocks(); + const controller = new UserStorageController({ + messenger: messengerMocks.messenger, + getMetaMetricsState: () => true, + }); + + await controller.performSetStorage('notification_settings', 'new data'); + mockAPI.done(); + }); + + test('rejects if UserStorage is not enabled', async () => { + const { messengerMocks } = arrangeMocks(); + const controller = new UserStorageController({ + messenger: messengerMocks.messenger, + getMetaMetricsState: () => true, + state: { + isProfileSyncingEnabled: false, + isProfileSyncingUpdateLoading: false, + }, + }); + + await expect( + controller.performSetStorage('notification_settings', 'new data'), + ).rejects.toThrow(); + }); + + // @ts-expect-error This is missing from the Mocha type definitions + test.each([ + [ + 'fails when no bearer token is found (auth errors)', + (messengerMocks: ReturnType) => + messengerMocks.mockAuthGetBearerToken.mockRejectedValue( + new Error('MOCK FAILURE'), + ), + ], + [ + 'fails when no session identifier is found (auth errors)', + (messengerMocks: ReturnType) => + messengerMocks.mockAuthGetSessionProfile.mockRejectedValue( + new Error('MOCK FAILURE'), + ), + ], + ])( + 'rejects on auth failure - %s', + async ( + _: string, + arrangeFailureCase: ( + messengerMocks: ReturnType, + ) => void, + ) => { + const { messengerMocks } = arrangeMocks(); + arrangeFailureCase(messengerMocks); + const controller = new UserStorageController({ + messenger: messengerMocks.messenger, + getMetaMetricsState: () => true, + }); + + await expect( + controller.performSetStorage('notification_settings', 'new data'), + ).rejects.toThrow(); + }, + ); + + test('rejects if api call fails', async () => { + const { messengerMocks } = arrangeMocks({ + mockAPI: mockEndpointUpsertUserStorage({ status: 500 }), + }); + const controller = new UserStorageController({ + messenger: messengerMocks.messenger, + getMetaMetricsState: () => true, + }); + await expect( + controller.performSetStorage('notification_settings', 'new data'), + ).rejects.toThrow(); + }); + + function arrangeMocks(overrides?: { mockAPI?: nock.Scope }) { + return { + messengerMocks: mockUserStorageMessenger(), + mockAPI: overrides?.mockAPI ?? mockEndpointUpsertUserStorage(), + }; + } +}); + +describe('user-storage/user-storage-controller - performSetStorage() tests', () => { + test('Should return a storage key', async () => { + const { messengerMocks } = arrangeMocks(); + const controller = new UserStorageController({ + messenger: messengerMocks.messenger, + getMetaMetricsState: () => true, + }); + + const result = await controller.getStorageKey(); + expect(result).toBe(MOCK_STORAGE_KEY); + }); + + test('rejects if UserStorage is not enabled', async () => { + const { messengerMocks } = arrangeMocks(); + const controller = new UserStorageController({ + messenger: messengerMocks.messenger, + getMetaMetricsState: () => true, + state: { + isProfileSyncingEnabled: false, + isProfileSyncingUpdateLoading: false, + }, + }); + + await expect(controller.getStorageKey()).rejects.toThrow(); + }); + + function arrangeMocks() { + return { + messengerMocks: mockUserStorageMessenger(), + }; + } +}); + +describe('user-storage/user-storage-controller - disableProfileSyncing() tests', () => { + test('should disable user storage / profile syncing when called', async () => { + const { messengerMocks } = arrangeMocks(); + const controller = new UserStorageController({ + messenger: messengerMocks.messenger, + getMetaMetricsState: () => true, + }); + + expect(controller.state.isProfileSyncingEnabled).toBe(true); + await controller.disableProfileSyncing(); + expect(controller.state.isProfileSyncingEnabled).toBe(false); + }); + + function arrangeMocks() { + return { + messengerMocks: mockUserStorageMessenger(), + }; + } +}); + +describe('user-storage/user-storage-controller - enableProfileSyncing() tests', () => { + test('should enable user storage / profile syncing', async () => { + const { messengerMocks } = arrangeMocks(); + messengerMocks.mockAuthIsSignedIn.mockReturnValue(false); // mock that auth is not enabled + + const controller = new UserStorageController({ + messenger: messengerMocks.messenger, + getMetaMetricsState: () => true, + state: { + isProfileSyncingEnabled: false, + isProfileSyncingUpdateLoading: false, + }, + }); + + expect(controller.state.isProfileSyncingEnabled).toBe(false); + await controller.enableProfileSyncing(); + expect(controller.state.isProfileSyncingEnabled).toBe(true); + expect(messengerMocks.mockAuthIsSignedIn).toBeCalled(); + expect(messengerMocks.mockAuthPerformSignIn).toBeCalled(); + }); + + function arrangeMocks() { + return { + messengerMocks: mockUserStorageMessenger(), + }; + } +}); + +function mockUserStorageMessenger() { + const messenger = new ControllerMessenger< + AllowedActions, + never + >().getRestricted({ + name: 'UserStorageController', + allowedActions: [ + 'SnapController:handleRequest', + 'AuthenticationController:getBearerToken', + 'AuthenticationController:getSessionProfile', + 'AuthenticationController:isSignedIn', + 'AuthenticationController:performSignIn', + 'AuthenticationController:performSignOut', + 'MetamaskNotificationsController:disableMetamaskNotifications', + 'MetamaskNotificationsController:selectIsMetamaskNotificationsEnabled', + ], + allowedEvents: [], + }); + + const mockSnapGetPublicKey = jest.fn().mockResolvedValue('MOCK_PUBLIC_KEY'); + const mockSnapSignMessage = jest + .fn() + .mockResolvedValue(MOCK_STORAGE_KEY_SIGNATURE); + + const mockAuthGetBearerToken = + typedMockFn< + AuthenticationControllerGetBearerToken['handler'] + >().mockResolvedValue('MOCK_BEARER_TOKEN'); + + const mockAuthGetSessionProfile = typedMockFn< + AuthenticationControllerGetSessionProfile['handler'] + >().mockResolvedValue({ + identifierId: '', + profileId: 'MOCK_PROFILE_ID', + }); + + const mockAuthPerformSignIn = + typedMockFn< + AuthenticationControllerPerformSignIn['handler'] + >().mockResolvedValue('New Access Token'); + + const mockAuthIsSignedIn = + typedMockFn< + AuthenticationControllerIsSignedIn['handler'] + >().mockReturnValue(true); + + const mockAuthPerformSignOut = + typedMockFn< + AuthenticationControllerIsSignedIn['handler'] + >().mockReturnValue(true); + + const mockMetamaskNotificationsIsMetamaskNotificationsEnabled = + typedMockFn< + MetamaskNotificationsControllerSelectIsMetamaskNotificationsEnabled['handler'] + >().mockReturnValue(true); + + const mockMetamaskNotificationsDisableNotifications = + typedMockFn< + MetamaskNotificationsControllerDisableMetamaskNotifications['handler'] + >().mockResolvedValue(); + + jest.spyOn(messenger, 'call').mockImplementation((...args) => { + const [actionType, params] = args; + if (actionType === 'SnapController:handleRequest') { + if (params?.request.method === 'getPublicKey') { + return mockSnapGetPublicKey(); + } + + if (params?.request.method === 'signMessage') { + return mockSnapSignMessage(); + } + + throw new Error( + `MOCK_FAIL - unsupported SnapController:handleRequest call: ${params?.request.method}`, + ); + } + + if (actionType === 'AuthenticationController:getBearerToken') { + return mockAuthGetBearerToken(); + } + + if (actionType === 'AuthenticationController:getSessionProfile') { + return mockAuthGetSessionProfile(); + } + + if (actionType === 'AuthenticationController:performSignIn') { + return mockAuthPerformSignIn(); + } + + if (actionType === 'AuthenticationController:isSignedIn') { + return mockAuthIsSignedIn(); + } + + if ( + actionType === + 'MetamaskNotificationsController:selectIsMetamaskNotificationsEnabled' + ) { + return mockMetamaskNotificationsIsMetamaskNotificationsEnabled(); + } + + if ( + actionType === + 'MetamaskNotificationsController:disableMetamaskNotifications' + ) { + return mockMetamaskNotificationsDisableNotifications(); + } + + if (actionType === 'AuthenticationController:performSignOut') { + return mockAuthPerformSignOut(); + } + + function exhaustedMessengerMocks(action: never) { + throw new Error(`MOCK_FAIL - unsupported messenger call: ${action}`); + } + + return exhaustedMessengerMocks(actionType); + }); + + return { + messenger, + mockSnapGetPublicKey, + mockSnapSignMessage, + mockAuthGetBearerToken, + mockAuthGetSessionProfile, + mockAuthPerformSignIn, + mockAuthIsSignedIn, + mockMetamaskNotificationsIsMetamaskNotificationsEnabled, + mockMetamaskNotificationsDisableNotifications, + mockAuthPerformSignOut, + }; +} diff --git a/app/scripts/controllers/user-storage/user-storage-controller.ts b/app/scripts/controllers/user-storage/user-storage-controller.ts new file mode 100644 index 000000000000..bcbc81618da8 --- /dev/null +++ b/app/scripts/controllers/user-storage/user-storage-controller.ts @@ -0,0 +1,388 @@ +import { + BaseController, + RestrictedControllerMessenger, + StateMetadata, +} from '@metamask/base-controller'; +import { HandleSnapRequest } from '@metamask/snaps-controllers'; +import { + AuthenticationControllerGetBearerToken, + AuthenticationControllerGetSessionProfile, + AuthenticationControllerIsSignedIn, + AuthenticationControllerPerformSignIn, + AuthenticationControllerPerformSignOut, +} from '../authentication/authentication-controller'; +import { + MetamaskNotificationsControllerDisableMetamaskNotifications, + MetamaskNotificationsControllerSelectIsMetamaskNotificationsEnabled, +} from '../metamask-notifications/metamask-notifications'; +import { createSnapSignMessageRequest } from '../authentication/auth-snap-requests'; +import { getUserStorage, upsertUserStorage } from './services'; +import { UserStorageEntryKeys } from './schema'; +import { createSHA256Hash } from './encryption'; + +const controllerName = 'UserStorageController'; + +// State +export type UserStorageControllerState = { + /** + * Condition used by UI and to determine if we can use some of the User Storage methods. + */ + isProfileSyncingEnabled: boolean; + /** + * Loading state for the profile syncing update + */ + isProfileSyncingUpdateLoading: boolean; +}; + +const defaultState: UserStorageControllerState = { + isProfileSyncingEnabled: true, + isProfileSyncingUpdateLoading: false, +}; + +const metadata: StateMetadata = { + isProfileSyncingEnabled: { + persist: true, + anonymous: true, + }, + isProfileSyncingUpdateLoading: { + persist: false, + anonymous: false, + }, +}; + +// Messenger Actions +type CreateActionsObj = { + [K in T]: { + type: `${typeof controllerName}:${K}`; + handler: UserStorageController[K]; + }; +}; +type ActionsObj = CreateActionsObj< + | 'performGetStorage' + | 'performSetStorage' + | 'getStorageKey' + | 'enableProfileSyncing' + | 'disableProfileSyncing' +>; +export type Actions = ActionsObj[keyof ActionsObj]; +export type UserStorageControllerPerformGetStorage = + ActionsObj['performGetStorage']; +export type UserStorageControllerPerformSetStorage = + ActionsObj['performSetStorage']; +export type UserStorageControllerGetStorageKey = ActionsObj['getStorageKey']; +export type UserStorageControllerEnableProfileSyncing = + ActionsObj['enableProfileSyncing']; +export type UserStorageControllerDisableProfileSyncing = + ActionsObj['disableProfileSyncing']; + +// Allowed Actions +export type AllowedActions = + // Snap Requests + | HandleSnapRequest + // Auth Requests + | AuthenticationControllerGetBearerToken + | AuthenticationControllerGetSessionProfile + | AuthenticationControllerPerformSignIn + | AuthenticationControllerIsSignedIn + | AuthenticationControllerPerformSignOut + // Metamask Notifications + | MetamaskNotificationsControllerDisableMetamaskNotifications + | MetamaskNotificationsControllerSelectIsMetamaskNotificationsEnabled; + +// Messenger +export type UserStorageControllerMessenger = RestrictedControllerMessenger< + typeof controllerName, + Actions | AllowedActions, + never, + AllowedActions['type'], + never +>; + +/** + * Reusable controller that allows any team to store synchronized data for a given user. + * These can be settings shared cross MetaMask clients, or data we want to persist when uninstalling/reinstalling. + * + * NOTE: + * - data stored on UserStorage is FULLY encrypted, with the only keys stored/managed on the client. + * - No one can access this data unless they are have the SRP and are able to run the signing snap. + */ +export default class UserStorageController extends BaseController< + typeof controllerName, + UserStorageControllerState, + UserStorageControllerMessenger +> { + #auth = { + getBearerToken: async () => { + return await this.messagingSystem.call( + 'AuthenticationController:getBearerToken', + ); + }, + getProfileId: async () => { + const sessionProfile = await this.messagingSystem.call( + 'AuthenticationController:getSessionProfile', + ); + return sessionProfile?.profileId; + }, + isAuthEnabled: () => { + return this.messagingSystem.call('AuthenticationController:isSignedIn'); + }, + signIn: async () => { + return await this.messagingSystem.call( + 'AuthenticationController:performSignIn', + ); + }, + signOut: async () => { + return await this.messagingSystem.call( + 'AuthenticationController:performSignOut', + ); + }, + }; + + #metamaskNotifications = { + disableMetamaskNotifications: async () => { + return await this.messagingSystem.call( + 'MetamaskNotificationsController:disableMetamaskNotifications', + ); + }, + selectIsMetamaskNotificationsEnabled: async () => { + return await this.messagingSystem.call( + 'MetamaskNotificationsController:selectIsMetamaskNotificationsEnabled', + ); + }, + }; + + getMetaMetricsState: () => boolean; + + constructor(params: { + messenger: UserStorageControllerMessenger; + state?: UserStorageControllerState; + getMetaMetricsState: () => boolean; + }) { + super({ + messenger: params.messenger, + metadata, + name: controllerName, + state: { ...defaultState, ...params.state }, + }); + + this.getMetaMetricsState = params.getMetaMetricsState; + this.#registerMessageHandlers(); + } + + /** + * Constructor helper for registering this controller's messaging system + * actions. + */ + #registerMessageHandlers(): void { + this.messagingSystem.registerActionHandler( + 'UserStorageController:performGetStorage', + this.performGetStorage.bind(this), + ); + + this.messagingSystem.registerActionHandler( + 'UserStorageController:performSetStorage', + this.performSetStorage.bind(this), + ); + + this.messagingSystem.registerActionHandler( + 'UserStorageController:getStorageKey', + this.getStorageKey.bind(this), + ); + + this.messagingSystem.registerActionHandler( + 'UserStorageController:enableProfileSyncing', + this.enableProfileSyncing.bind(this), + ); + + this.messagingSystem.registerActionHandler( + 'UserStorageController:disableProfileSyncing', + this.disableProfileSyncing.bind(this), + ); + } + + public async enableProfileSyncing(): Promise { + try { + this.#setIsProfileSyncingUpdateLoading(true); + + const authEnabled = this.#auth.isAuthEnabled(); + if (!authEnabled) { + await this.#auth.signIn(); + } + + this.update((state) => { + state.isProfileSyncingEnabled = true; + }); + + this.#setIsProfileSyncingUpdateLoading(false); + } catch (e) { + this.#setIsProfileSyncingUpdateLoading(false); + const errorMessage = e instanceof Error ? e.message : e; + throw new Error( + `${controllerName} - failed to enable profile syncing - ${errorMessage}`, + ); + } + } + + public async setIsProfileSyncingEnabled( + isProfileSyncingEnabled: boolean, + ): Promise { + this.update((state) => { + state.isProfileSyncingEnabled = isProfileSyncingEnabled; + }); + } + + public async disableProfileSyncing(): Promise { + const isAlreadyDisabled = !this.state.isProfileSyncingEnabled; + if (isAlreadyDisabled) { + return; + } + + try { + this.#setIsProfileSyncingUpdateLoading(true); + + const isMetamaskNotificationsEnabled = + await this.#metamaskNotifications.selectIsMetamaskNotificationsEnabled(); + + if (isMetamaskNotificationsEnabled) { + await this.#metamaskNotifications.disableMetamaskNotifications(); + } + + const isMetaMetricsParticipation = this.getMetaMetricsState(); + + if (!isMetaMetricsParticipation) { + await this.messagingSystem.call( + 'AuthenticationController:performSignOut', + ); + } + + this.#setIsProfileSyncingUpdateLoading(false); + + this.update((state) => { + state.isProfileSyncingEnabled = false; + }); + } catch (e) { + this.#setIsProfileSyncingUpdateLoading(false); + const errorMessage = e instanceof Error ? e.message : e; + throw new Error( + `${controllerName} - failed to disable profile syncing - ${errorMessage}`, + ); + } + } + + /** + * Allows retrieval of stored data. Data stored is string formatted. + * Developers can extend the entry path and entry name through the `schema.ts` file. + * + * @param entryKey + * @returns the decrypted string contents found from user storage (or null if not found) + */ + public async performGetStorage( + entryKey: UserStorageEntryKeys, + ): Promise { + this.#assertProfileSyncingEnabled(); + const { bearerToken, storageKey } = + await this.#getStorageKeyAndBearerToken(); + const result = await getUserStorage({ + entryKey, + bearerToken, + storageKey, + }); + + return result; + } + + /** + * Allows storage of user data. Data stored must be string formatted. + * Developers can extend the entry path and entry name through the `schema.ts` file. + * + * @param entryKey + * @param value - The string data you want to store. + * @returns nothing. NOTE that an error is thrown if fails to store data. + */ + public async performSetStorage( + entryKey: UserStorageEntryKeys, + value: string, + ): Promise { + this.#assertProfileSyncingEnabled(); + const { bearerToken, storageKey } = + await this.#getStorageKeyAndBearerToken(); + + await upsertUserStorage(value, { + entryKey, + bearerToken, + storageKey, + }); + } + + /** + * Retrieves the storage key, for internal use only! + * + * @returns the storage key + */ + public async getStorageKey(): Promise { + this.#assertProfileSyncingEnabled(); + const storageKey = await this.#createStorageKey(); + return storageKey; + } + + #assertProfileSyncingEnabled(): void { + if (!this.state.isProfileSyncingEnabled) { + throw new Error( + `${controllerName}: Unable to call method, user is not authenticated`, + ); + } + } + + /** + * Utility to get the bearer token and storage key + */ + async #getStorageKeyAndBearerToken(): Promise<{ + bearerToken: string; + storageKey: string; + }> { + const bearerToken = await this.#auth.getBearerToken(); + if (!bearerToken) { + throw new Error('UserStorageController - unable to get bearer token'); + } + const storageKey = await this.#createStorageKey(); + + return { bearerToken, storageKey }; + } + + /** + * Rather than storing the storage key, we can compute the storage key when needed. + * + * @returns the storage key + */ + async #createStorageKey(): Promise { + const id = await this.#auth.getProfileId(); + if (!id) { + throw new Error('UserStorageController - unable to create storage key'); + } + + const storageKeySignature = await this.#snapSignMessage(`metamask:${id}`); + const storageKey = createSHA256Hash(storageKeySignature); + return storageKey; + } + + /** + * Signs a specific message using an underlying auth snap. + * + * @param message - A specific tagged message to sign. + * @returns A Signature created by the snap. + */ + #snapSignMessage(message: `metamask:${string}`): Promise { + return this.messagingSystem.call( + 'SnapController:handleRequest', + createSnapSignMessageRequest(message), + ) as Promise; + } + + async #setIsProfileSyncingUpdateLoading( + isProfileSyncingUpdateLoading: boolean, + ): Promise { + this.update((state) => { + state.isProfileSyncingUpdateLoading = isProfileSyncingUpdateLoading; + }); + } +} diff --git a/app/scripts/detect-multiple-instances.test.js b/app/scripts/detect-multiple-instances.test.js index f873adcfded7..29c6af2d9fe9 100644 --- a/app/scripts/detect-multiple-instances.test.js +++ b/app/scripts/detect-multiple-instances.test.js @@ -1,6 +1,4 @@ -import { strict as assert } from 'assert'; import browser from 'webextension-polyfill'; -import sinon from 'sinon'; import { PLATFORM_CHROME, PLATFORM_EDGE, @@ -19,98 +17,78 @@ import * as util from './lib/util'; describe('multiple instances running detector', function () { const PING_MESSAGE = 'isRunning'; - let sendMessageStub = sinon.stub(); + const sendMessageStub = jest.fn(); - beforeEach(async function () { - sinon.replace(browser, 'runtime', { + beforeEach(function () { + jest.replaceProperty(browser, 'runtime', { sendMessage: sendMessageStub, id: METAMASK_BETA_CHROME_ID, }); - - sinon.stub(util, 'getPlatform').callsFake((_) => { - return PLATFORM_CHROME; - }); + jest.spyOn(util, 'getPlatform').mockReturnValue(PLATFORM_CHROME); }); afterEach(function () { - sinon.restore(); + jest.restoreAllMocks(); }); describe('checkForMultipleVersionsRunning', function () { it('should send ping message to multiple instances', async function () { await checkForMultipleVersionsRunning(); - assert(sendMessageStub.callCount === 4); - assert( - sendMessageStub - .getCall(0) - .calledWithExactly(METAMASK_PROD_CHROME_ID, PING_MESSAGE), - ); - assert( - sendMessageStub - .getCall(1) - .calledWithExactly(METAMASK_FLASK_CHROME_ID, PING_MESSAGE), - ); - assert( - sendMessageStub - .getCall(2) - .calledWithExactly(METAMASK_MMI_BETA_CHROME_ID, PING_MESSAGE), - ); - assert( - sendMessageStub - .getCall(3) - .calledWithExactly(METAMASK_MMI_PROD_CHROME_ID, PING_MESSAGE), - ); + expect(sendMessageStub.mock.calls).toHaveLength(4); + expect( + sendMessageStub.mock.instances[0].sendMessage, + ).toHaveBeenCalledWith(METAMASK_PROD_CHROME_ID, PING_MESSAGE); + expect( + sendMessageStub.mock.instances[1].sendMessage, + ).toHaveBeenCalledWith(METAMASK_FLASK_CHROME_ID, PING_MESSAGE); + expect( + sendMessageStub.mock.instances[2].sendMessage, + ).toHaveBeenCalledWith(METAMASK_MMI_BETA_CHROME_ID, PING_MESSAGE); + expect( + sendMessageStub.mock.instances[3].sendMessage, + ).toHaveBeenCalledWith(METAMASK_MMI_PROD_CHROME_ID, PING_MESSAGE); }); it('should not send ping message if platform is not Chrome or Firefox', async function () { - util.getPlatform.restore(); - sendMessageStub = sinon.stub(); + sendMessageStub.mockRestore(); - sinon.stub(util, 'getPlatform').callsFake((_) => { - return PLATFORM_EDGE; - }); + jest.spyOn(util, 'getPlatform').mockReturnValue(PLATFORM_EDGE); await checkForMultipleVersionsRunning(); - assert(sendMessageStub.notCalled); + expect(sendMessageStub).not.toHaveBeenCalled(); }); it('should not expose an error outside if sendMessage throws', async function () { - sinon.restore(); - - sinon.replace(browser, 'runtime', { - sendMessage: sinon.stub().throws(), + jest.replaceProperty(browser, 'runtime', { + sendMessage: sendMessageStub.mockImplementation(() => { + throw new Error(); + }), id: METAMASK_BETA_CHROME_ID, }); - const spy = sinon.spy(checkForMultipleVersionsRunning); - - await checkForMultipleVersionsRunning(); - - assert(!spy.threw()); + expect(async () => await checkForMultipleVersionsRunning()).not.toThrow(); }); }); describe('onMessageReceived', function () { beforeEach(function () { - sinon.spy(console, 'warn'); + jest.spyOn(console, 'warn'); }); it('should print warning message to on ping message received', async function () { onMessageReceived(PING_MESSAGE); - assert( - console.warn.calledWithExactly( - 'Warning! You have multiple instances of MetaMask running!', - ), + expect(console.warn).toHaveBeenCalledWith( + 'Warning! You have multiple instances of MetaMask running!', ); }); it('should not print warning message if wrong message received', async function () { onMessageReceived(PING_MESSAGE.concat('wrong')); - assert(console.warn.notCalled); + expect(console.warn).not.toHaveBeenCalled(); }); }); }); diff --git a/app/scripts/lib/AbstractPetnamesBridge.test.ts b/app/scripts/lib/AbstractPetnamesBridge.test.ts index 608454b38afe..3347c90f13f5 100644 --- a/app/scripts/lib/AbstractPetnamesBridge.test.ts +++ b/app/scripts/lib/AbstractPetnamesBridge.test.ts @@ -94,6 +94,8 @@ function createNameControllerMock(state: NameControllerState) { function createMessengerMock(): jest.Mocked { return { subscribe: jest.fn(), + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any; } diff --git a/app/scripts/lib/AccountIdentitiesPetnamesBridge.test.ts b/app/scripts/lib/AccountIdentitiesPetnamesBridge.test.ts index 6431381d7099..c17ce27d68aa 100644 --- a/app/scripts/lib/AccountIdentitiesPetnamesBridge.test.ts +++ b/app/scripts/lib/AccountIdentitiesPetnamesBridge.test.ts @@ -27,7 +27,6 @@ const MOCK_INTERNAL_ACCOUNT = createMockInternalAccount({ address: ADDRESS_MOCK, name: NAME_MOCK, keyringType: KeyringTypes.hd, - is4337: false, snapOptions: undefined, }); @@ -105,16 +104,22 @@ function createNameControllerMock( return { state, setName: jest.fn(), + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any; } function simulateSubscribe( messenger: jest.Mocked, stateChange: AccountsControllerState, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any patch: any[], ) { const listener = messenger.subscribe.mock.calls[0][1] as ( stateChange: AccountsControllerState, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any patch: any[], ) => void; listener(stateChange, patch); @@ -199,6 +204,7 @@ describe('AccountIdentitiesPetnamesBridge', () => { }); describe('shouldSyncPetname', () => { + // @ts-expect-error This is missing from the Mocha type definitions it.each([ { origin: NameOrigin.ACCOUNT_IDENTITY, @@ -210,7 +216,13 @@ describe('AccountIdentitiesPetnamesBridge', () => { }, ])( 'returns $expectedReturn if origin is $origin', - ({ origin, expectedReturn }) => { + ({ + origin, + expectedReturn, + }: { + origin: NameOrigin; + expectedReturn: boolean; + }) => { class TestBridge extends AccountIdentitiesPetnamesBridge { public shouldSyncPetname(entry: PetnameEntry): boolean { return super.shouldSyncPetname(entry); diff --git a/app/scripts/lib/AddressBookPetnamesBridge.test.ts b/app/scripts/lib/AddressBookPetnamesBridge.test.ts index c98e6a5e309e..f95726fba7b2 100644 --- a/app/scripts/lib/AddressBookPetnamesBridge.test.ts +++ b/app/scripts/lib/AddressBookPetnamesBridge.test.ts @@ -37,12 +37,16 @@ function createNameControllerMock( return { state, setName: jest.fn(), + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any; } function createMessengerMock(): jest.Mocked { return { subscribe: jest.fn(), + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any; } diff --git a/app/scripts/lib/AddressBookPetnamesBridge.ts b/app/scripts/lib/AddressBookPetnamesBridge.ts index e6f7e9813fa1..141814a9ef62 100644 --- a/app/scripts/lib/AddressBookPetnamesBridge.ts +++ b/app/scripts/lib/AddressBookPetnamesBridge.ts @@ -35,9 +35,13 @@ export class AddressBookPetnamesBridge extends AbstractPetnamesBridge { const entries: PetnameEntry[] = []; const { state } = this.#addressBookController; for (const chainId of Object.keys(state.addressBook)) { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const chainEntries = state.addressBook[chainId as any]; for (const address of Object.keys(chainEntries)) { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const entry = state.addressBook[chainId as any][address]; const normalizedChainId = chainId.toLowerCase(); const { name, isEns } = entry; @@ -64,11 +68,17 @@ export class AddressBookPetnamesBridge extends AbstractPetnamesBridge { */ protected updateSourceEntry(type: ChangeType, entry: PetnameEntry): void { if (type === ChangeType.DELETED) { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any this.#addressBookController.delete(entry.variation as any, entry.value); } else { this.#addressBookController.set( entry.value, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any entry.name as any, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any entry.variation as any, ); } diff --git a/app/scripts/lib/SnapsNameProvider.test.ts b/app/scripts/lib/SnapsNameProvider.test.ts index 6d6f0dd6a120..25a5f22a3f80 100644 --- a/app/scripts/lib/SnapsNameProvider.test.ts +++ b/app/scripts/lib/SnapsNameProvider.test.ts @@ -94,6 +94,8 @@ function createMockMessenger({ return { call: callMock, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any; } diff --git a/app/scripts/lib/WeakRefObjectMap.test.ts b/app/scripts/lib/WeakRefObjectMap.test.ts new file mode 100644 index 000000000000..289bc4a8548c --- /dev/null +++ b/app/scripts/lib/WeakRefObjectMap.test.ts @@ -0,0 +1,147 @@ +import { WeakRefObjectMap } from './WeakRefObjectMap'; + +describe('WeakDomainProxyMap', () => { + let map: WeakRefObjectMap>; + + beforeEach(() => { + map = new WeakRefObjectMap(); + }); + + it('sets and gets a value', () => { + const key: string = 'testKey'; + const value: { [key: string]: object } = { objKey: {} }; + map.set(key, value); + + const retrieved = map.get(key); + expect(retrieved).toHaveProperty('objKey'); + expect(retrieved?.objKey).toBe(value.objKey); + }); + + it('confirms presence of a key with has()', () => { + const key: string = 'testKey'; + const value: { [key: string]: object } = { objKey: {} }; + map.set(key, value); + + expect(map.has(key)).toBe(true); + }); + + it('deletes a key-value pair', () => { + const key: string = 'testKey'; + const value: { [key: string]: object } = { objKey: {} }; + map.set(key, value); + + expect(map.has(key)).toBe(true); + map.delete(key); + expect(map.has(key)).toBe(false); + }); + + it('clears the map', () => { + map.set('key1', { objKey: {} }); + map.set('key2', { objKey: {} }); + + map.clear(); + expect(map.has('key1')).toBe(false); + expect(map.has('key2')).toBe(false); + }); + + it('get returns undefined for non-existent key', () => { + expect(map.get('nonExistentKey')).toBeUndefined(); + }); + + it('delete returns false when key does not exist', () => { + expect(map.delete('nonExistentKey')).toBe(false); + }); + + describe('iterators', () => { + beforeEach(() => { + map = new WeakRefObjectMap(); + map.set('key1', { objKey1: { detail: 'value1' } }); + map.set('key2', { objKey2: { detail: 'value2' } }); + }); + + it('iterates over entries correctly', () => { + const entries = Array.from(map.entries()); + expect(entries.length).toBe(2); + expect(entries).toEqual( + expect.arrayContaining([ + ['key1', { objKey1: { detail: 'value1' } }], + ['key2', { objKey2: { detail: 'value2' } }], + ]), + ); + }); + + it('iterates over keys correctly', () => { + const keys = Array.from(map.keys()); + expect(keys.length).toBe(2); + expect(keys).toEqual(expect.arrayContaining(['key1', 'key2'])); + }); + + it('iterates over values correctly', () => { + const values = Array.from(map.values()); + expect(values.length).toBe(2); + expect(values).toEqual( + expect.arrayContaining([ + { objKey1: { detail: 'value1' } }, + { objKey2: { detail: 'value2' } }, + ]), + ); + }); + + it('executes forEach callback correctly', () => { + const mockCallback = jest.fn(); + map.forEach(mockCallback); + + expect(mockCallback.mock.calls.length).toBe(2); + expect(mockCallback).toHaveBeenCalledWith( + { objKey1: { detail: 'value1' } }, + 'key1', + map, + ); + expect(mockCallback).toHaveBeenCalledWith( + { objKey2: { detail: 'value2' } }, + 'key2', + map, + ); + }); + + it('handles empty map in iterations', () => { + const emptyMap = new WeakRefObjectMap>(); + expect(Array.from(emptyMap.entries()).length).toBe(0); + expect(Array.from(emptyMap.keys()).length).toBe(0); + expect(Array.from(emptyMap.values()).length).toBe(0); + + const mockCallback = jest.fn(); + emptyMap.forEach(mockCallback); + expect(mockCallback).not.toHaveBeenCalled(); + }); + + it('[Symbol.iterator] behaves like entries', () => { + const iterator = map[Symbol.iterator](); + expect(Array.from(iterator)).toEqual(Array.from(map.entries())); + }); + }); +}); + +// Commenting until we figure out how best to expose garbage collection in jest env +// describe('WeakDomainProxyMap with garbage collection', () => { +// it('cleans up weakly referenced objects after garbage collection', () => { +// if ((global as any).gc) { +// const map = new WeakDomainProxyMap(); +// let obj: object = { a: 1 }; +// map.set('key', { obj }); + +// expect(map.get('key')).toHaveProperty('obj', obj); + +// obj = null!; // Remove the strong reference to the object + +// (global as any).gc(); // Force garbage collection + +// // The weakly referenced object should be gone after garbage collection. +// expect(map.get('key')).toBeUndefined(); +// } else { +// console.warn( +// 'Garbage collection is not exposed. Run Node.js with the --expose-gc flag.', +// ); +// } +// }); +// }); diff --git a/app/scripts/lib/WeakRefObjectMap.ts b/app/scripts/lib/WeakRefObjectMap.ts new file mode 100644 index 000000000000..09d0a9c54499 --- /dev/null +++ b/app/scripts/lib/WeakRefObjectMap.ts @@ -0,0 +1,218 @@ +type WeakRefObject> = { + [P in keyof RecordType]: WeakRef; +}; + +/** + * `WeakRefObjectMap` is a custom map-like structure designed to hold key-value pairs where the values are objects. + * Unlike a standard `Map`, this implementation stores each property of the value objects as weak references. + * This means that the properties of the objects are not prevented from being garbage collected when there are no other + * references to them outside of this map. + * + * It is important to note that while the map itself behaves similarly to a standard `Map`, the weak references apply + * to each property of the objects stored as values. This means that individual properties of these objects may become + * unavailable (i.e., garbage collected) independently of one another. Users of this map should be prepared to handle + * cases where a property's value has been collected and is therefore `undefined`. + * + * This class was implemented to help with memory management of network client proxies used by the SelectedNetworkController + * to keep per domain selected networks in sync. The properties of the NetworkClient object (provider and blockTracker) are weakly + * referenced so that they can be garbage collected if/when a dapp connection ends without effective cleanup. + */ + +export class WeakRefObjectMap> + implements Map +{ + /** + * Internal map to store keys and their corresponding weakly referenced object values. + */ + private map: Map>; + + constructor() { + this.map = new Map(); + } + + /** + * Associates a key with a value in the map. If the key already exists, its associated value is updated. + * The values are stored as weak references. + * + * @param key - The key under which to store the value. + * @param value - The value to store under the specified key. Must be an object. + * @returns The `WeakRefObjectMap` instance. + */ + set(key: string, value: RecordType): this { + const weakRefValue: Partial> = {}; + for (const keyValue in value) { + if (!Object.prototype.hasOwnProperty.call(value, keyValue)) { + continue; + } + const item: RecordType[typeof keyValue] = value[keyValue]; + if (typeof item === 'object' && item !== null) { + weakRefValue[keyValue] = new WeakRef(item); + } else { + throw new Error( + `Property ${String( + keyValue, + )} is not an object and cannot be weakly referenced.`, + ); + } + } + this.map.set(key, weakRefValue as WeakRefObject); + return this; + } + + /** + * Retrieves the value associated with the specified key. The value is dereferenced before being returned. + * If the key does not exist or the value has been garbage collected, `undefined` is returned. + * + * @param key - The key whose associated value is to be returned. + * @returns The dereferenced value associated with the key, or `undefined`. + */ + get(key: string): RecordType | undefined { + const weakRefValue = this.map.get(key); + if (!weakRefValue) { + return undefined; + } + + const deRefValue: Partial = {}; + for (const keyValue in weakRefValue) { + if (!Object.prototype.hasOwnProperty.call(weakRefValue, keyValue)) { + continue; + } + const deref = weakRefValue[keyValue].deref(); + if (deref === undefined) { + this.map.delete(key); + return undefined; + } + deRefValue[keyValue] = deref; + } + + return deRefValue as RecordType; + } + + /** + * Checks whether the map contains the specified key. + * + * @param key - The key to check for presence in the map. + * @returns `true` if the map contains the key, otherwise `false`. + */ + has(key: string): boolean { + return this.get(key) !== undefined; + } + + /** + * Removes the specified key and its associated value from the map. + * + * @param key - The key to remove along with its associated value. + * @returns `true` if the element was successfully removed, otherwise `false`. + */ + delete(key: string): boolean { + const value = this.get(key); + if (value !== undefined) { + return this.map.delete(key); + } + return false; + } + + /** + * Removes all key-value pairs from the map. + */ + clear() { + this.map.clear(); + } + + /** + * Returns the number of key-value pairs present in the map. + */ + get size(): number { + return this.map.size; + } + + /** + * Returns a new iterator object that contains an array of `[key, value]` for each element in the map. + * The values are dereferenced before being returned. + */ + entries(): IterableIterator<[string, RecordType]> { + const entries: [string, RecordType][] = []; + this.map.forEach((_, key) => { + const derefValue = this.get(key); + if (derefValue !== undefined) { + entries.push([key, derefValue]); + } + }); + return entries.values(); + } + + /** + * Returns a new iterator object that contains the keys for each element in the map. + */ + keys(): IterableIterator { + return this.map.keys(); + } + + /** + * Returns a new iterator object that contains the values for each element in the map. + * The values are dereferenced before being returned. + */ + values(): IterableIterator { + const values: RecordType[] = []; + this.map.forEach((_, key) => { + const derefValue = this.get(key); + if (derefValue !== undefined) { + values.push(derefValue); + } + }); + return values.values(); + } + + /** + * Returns a new iterator object that contains an array of `[key, value]` for each element in the map, + * making the map itself iterable. + */ + [Symbol.iterator](): IterableIterator<[string, RecordType]> { + return this.entries(); + } + + /** + * Returns a string representing the map. This is used when converting the map to a string, + * e.g., by `Object.prototype.toString`. + */ + get [Symbol.toStringTag](): string { + return 'WeakRefObjectMap'; + } + + /** + * Executes a provided function once for each key-value pair in the map, in insertion order. + * Note that the values passed to the callback function are the `WeakRefObject`s, + * not the dereferenced objects. This allows consumers to manage dereferencing according to their needs, + * acknowledging that some references may have been garbage collected. + * + * @param callback - Function to execute for each element, taking three arguments: + * - `value`: The value part of the key-value pair. Note that this is the weakly referenced object, + * encapsulated within a `WeakRefObject`, allowing for manual dereferencing. + * -`key`: The key part of the key-value pair. + * - `map`: The `WeakRefObjectMap` instance that the `forEach` method was called on. + * @param thisArg - Optional. Value to use as `this` when executing `callback`. + */ + forEach( + callback: ( + value: RecordType, + key: string, + map: Map, + ) => void, + // this is an unbound method, so the this value is unknown. + // Also the Map type this is based on uses any for this parameter as well. + // eslint-disable-next-line @typescript-eslint/no-explicit-any + thisArg?: any, + ): void { + this.map.forEach((_, key) => { + const deRefValue = this.get(key); + if (deRefValue === undefined) { + return; + } + if (thisArg) { + callback.call(thisArg, deRefValue, key, this); + } else { + callback(deRefValue, key, this); + } + }); + } +} diff --git a/app/scripts/lib/account-tracker.js b/app/scripts/lib/account-tracker.js index ea772a9d90aa..3918f835f5d8 100644 --- a/app/scripts/lib/account-tracker.js +++ b/app/scripts/lib/account-tracker.js @@ -78,14 +78,6 @@ export default class AccountTracker { this.onboardingController = opts.onboardingController; this.controllerMessenger = opts.controllerMessenger; - // blockTracker.currentBlock may be null - this.#currentBlockNumberByChainId = { - [this.getCurrentChainId()]: this.#blockTracker.getCurrentBlock(), - }; - this.#blockTracker.once('latest', (blockNumber) => { - this.#currentBlockNumberByChainId[this.getCurrentChainId()] = blockNumber; - }); - // subscribe to account removal opts.onAccountRemoved((address) => this.removeAccounts([address])); @@ -104,7 +96,7 @@ export default class AccountTracker { ); this.controllerMessenger.subscribe( - 'AccountsController:selectedAccountChange', + 'AccountsController:selectedEvmAccountChange', (newAccount) => { const { useMultiAccountBalanceChecker } = this.preferencesController.store.getState(); @@ -124,6 +116,14 @@ export default class AccountTracker { * Starts polling with global selected network */ start() { + // blockTracker.currentBlock may be null + this.#currentBlockNumberByChainId = { + [this.getCurrentChainId()]: this.#blockTracker.getCurrentBlock(), + }; + this.#blockTracker.once('latest', (blockNumber) => { + this.#currentBlockNumberByChainId[this.getCurrentChainId()] = blockNumber; + }); + // remove first to avoid double add this.#blockTracker.removeListener('latest', this.#updateForBlock); // add listener diff --git a/app/scripts/lib/accounts/BalancesController.test.ts b/app/scripts/lib/accounts/BalancesController.test.ts new file mode 100644 index 000000000000..01ce1f88c608 --- /dev/null +++ b/app/scripts/lib/accounts/BalancesController.test.ts @@ -0,0 +1,122 @@ +import { ControllerMessenger } from '@metamask/base-controller'; +import { + Balance, + BtcAccountType, + CaipAssetType, + InternalAccount, +} from '@metamask/keyring-api'; +import { createMockInternalAccount } from '../../../../test/jest/mocks'; +import { + BalancesController, + AllowedActions, + BalancesControllerEvents, + BalancesControllerState, + defaultState, +} from './BalancesController'; +import { Poller } from './Poller'; + +const mockBtcAccount = createMockInternalAccount({ + address: '', + name: 'Btc Account', + // @ts-expect-error - account type may be btc or eth, mock file is not typed + type: BtcAccountType.P2wpkh, + snapOptions: { + id: 'mock-btc-snap', + name: 'mock-btc-snap', + enabled: true, + }, +}); + +const mockBalanceResult = { + 'bip122:000000000933ea01ad0ee984209779ba/slip44:0': { + amount: '0.00000000', + unit: 'BTC', + }, +}; + +const setupController = ({ + state = defaultState, + mocks, +}: { + state?: BalancesControllerState; + mocks?: { + listMultichainAccounts?: InternalAccount[]; + handleRequestReturnValue?: Record; + }; +} = {}) => { + const controllerMessenger = new ControllerMessenger< + AllowedActions, + BalancesControllerEvents + >(); + + const balancesControllerMessenger = controllerMessenger.getRestricted({ + name: 'BalancesController', + allowedActions: ['SnapController:handleRequest'], + allowedEvents: [], + }); + + const mockSnapHandleRequest = jest.fn(); + controllerMessenger.registerActionHandler( + 'SnapController:handleRequest', + mockSnapHandleRequest.mockReturnValue( + mocks?.handleRequestReturnValue ?? mockBalanceResult, + ), + ); + + // TODO: remove when listMultichainAccounts action is available + const mockListMultichainAccounts = jest + .fn() + .mockReturnValue(mocks?.listMultichainAccounts ?? [mockBtcAccount]); + + const controller = new BalancesController({ + messenger: balancesControllerMessenger, + state, + // TODO: remove when listMultichainAccounts action is available + listMultichainAccounts: mockListMultichainAccounts, + }); + + return { + controller, + mockSnapHandleRequest, + mockListMultichainAccounts, + }; +}; + +describe('BalancesController', () => { + it('initialize with default state', () => { + const { controller } = setupController({}); + expect(controller.state).toEqual({ balances: {} }); + }); + + it('starts polling when calling start', async () => { + const spyPoller = jest.spyOn(Poller.prototype, 'start'); + const { controller } = setupController(); + await controller.start(); + expect(spyPoller).toHaveBeenCalledTimes(1); + }); + + it('stops polling when calling stop', async () => { + const spyPoller = jest.spyOn(Poller.prototype, 'stop'); + const { controller } = setupController(); + await controller.start(); + await controller.stop(); + expect(spyPoller).toHaveBeenCalledTimes(1); + }); + + it('update balances when calling updateBalances', async () => { + const { controller } = setupController(); + + await controller.updateBalances(); + + expect(controller.state).toEqual({ + balances: { + [mockBtcAccount.id]: { + 'bip122:000000000933ea01ad0ee984209779ba/slip44:0': { + amount: '0.00000000', + unit: 'BTC', + }, + }, + }, + }); + }); +}); diff --git a/app/scripts/lib/accounts/BalancesController.ts b/app/scripts/lib/accounts/BalancesController.ts new file mode 100644 index 000000000000..eee4ac11889a --- /dev/null +++ b/app/scripts/lib/accounts/BalancesController.ts @@ -0,0 +1,255 @@ +import type { Json, JsonRpcRequest } from '@metamask/utils'; + +import { + BaseController, + type ControllerGetStateAction, + type ControllerStateChangeEvent, + type RestrictedControllerMessenger, +} from '@metamask/base-controller'; +import { + BtcAccountType, + KeyringClient, + type Balance, + type CaipAssetType, + type InternalAccount, +} from '@metamask/keyring-api'; +import type { HandleSnapRequest } from '@metamask/snaps-controllers'; +import type { SnapId } from '@metamask/snaps-sdk'; +import { HandlerType } from '@metamask/snaps-utils'; +import type { Draft } from 'immer'; +import { Poller } from './Poller'; + +const controllerName = 'BalancesController'; + +/** + * State used by the {@link BalancesController} to cache account balances. + */ +export type BalancesControllerState = { + balances: { + [account: string]: { + [asset: string]: { + amount: string; + unit: string; + }; + }; + }; +}; + +/** + * Default state of the {@link BalancesController}. + */ +export const defaultState: BalancesControllerState = { balances: {} }; + +/** + * Returns the state of the {@link BalancesController}. + */ +export type BalancesControllerGetStateAction = ControllerGetStateAction< + typeof controllerName, + BalancesControllerState +>; + +/** + * Updates the balances of all supported accounts. + */ +export type BalancesControllerUpdateBalancesAction = { + type: `${typeof controllerName}:updateBalances`; + handler: BalancesController['updateBalances']; +}; + +/** + * Event emitted when the state of the {@link BalancesController} changes. + */ +export type BalancesControllerStateChange = ControllerStateChangeEvent< + typeof controllerName, + BalancesControllerState +>; + +/** + * Actions exposed by the {@link BalancesController}. + */ +export type BalancesControllerActions = + | BalancesControllerGetStateAction + | BalancesControllerUpdateBalancesAction; + +/** + * Events emitted by {@link BalancesController}. + */ +export type BalancesControllerEvents = BalancesControllerStateChange; + +/** + * Actions that this controller is allowed to call. + */ +export type AllowedActions = HandleSnapRequest; + +/** + * Messenger type for the BalancesController. + */ +export type BalancesControllerMessenger = RestrictedControllerMessenger< + typeof controllerName, + BalancesControllerActions | AllowedActions, + BalancesControllerEvents, + AllowedActions['type'], + never +>; + +/** + * {@link BalancesController}'s metadata. + * + * This allows us to choose if fields of the state should be persisted or not + * using the `persist` flag; and if they can be sent to Sentry or not, using + * the `anonymous` flag. + */ +const balancesControllerMetadata = { + balances: { + persist: true, + anonymous: false, + }, +}; + +const BTC_TESTNET_ASSETS = ['bip122:000000000933ea01ad0ee984209779ba/slip44:0']; +const BTC_MAINNET_ASSETS = ['bip122:000000000019d6689c085ae165831e93/slip44:0']; +export const BTC_AVG_BLOCK_TIME = 600000; // 10 minutes in milliseconds + +/** + * Returns whether an address is on the Bitcoin mainnet. + * + * This function only checks the prefix of the address to determine if it's on + * the mainnet or not. It doesn't validate the address itself, and should only + * be used as a temporary solution until this information is included in the + * account object. + * + * @param address - The address to check. + * @returns `true` if the address is on the Bitcoin mainnet, `false` otherwise. + */ +function isBtcMainnet(address: string): boolean { + return address.startsWith('bc1') || address.startsWith('1'); +} + +/** + * The BalancesController is responsible for fetching and caching account + * balances. + */ +export class BalancesController extends BaseController< + typeof controllerName, + BalancesControllerState, + BalancesControllerMessenger +> { + #poller: Poller; + + // TODO: remove once action is implemented + #listMultichainAccounts: () => InternalAccount[]; + + constructor({ + messenger, + state, + listMultichainAccounts, + }: { + messenger: BalancesControllerMessenger; + state: BalancesControllerState; + listMultichainAccounts: () => InternalAccount[]; + }) { + super({ + messenger, + name: controllerName, + metadata: balancesControllerMetadata, + state: { + ...defaultState, + ...state, + }, + }); + + this.#listMultichainAccounts = listMultichainAccounts; + this.#poller = new Poller(() => this.updateBalances(), BTC_AVG_BLOCK_TIME); + } + + /** + * Starts the polling process. + */ + async start(): Promise { + this.#poller.start(); + } + + /** + * Stops the polling process. + */ + async stop(): Promise { + this.#poller.stop(); + } + + /** + * Lists the accounts that we should get balances for. + * + * Currently, we only get balances for P2WPKH accounts, but this will change + * in the future when we start support other non-EVM account types. + * + * @returns A list of accounts that we should get balances for. + */ + async #listAccounts(): Promise { + const accounts = this.#listMultichainAccounts(); + + return accounts.filter((account) => account.type === BtcAccountType.P2wpkh); + } + + /** + * Updates the balances of all supported accounts. This method doesn't return + * anything, but it updates the state of the controller. + */ + async updateBalances() { + const accounts = await this.#listAccounts(); + const partialState: BalancesControllerState = { balances: {} }; + + for (const account of accounts) { + if (account.metadata.snap) { + partialState.balances[account.id] = await this.#getBalances( + account.id, + account.metadata.snap.id, + isBtcMainnet(account.address) + ? BTC_MAINNET_ASSETS + : BTC_TESTNET_ASSETS, + ); + } + } + + this.update((state: Draft) => ({ + ...state, + ...partialState, + })); + } + + /** + * Get the balances for an account. + * + * @param accountId - ID of the account to get balances for. + * @param snapId - ID of the Snap which manages the account. + * @param assetTypes - Array of asset types to get balances for. + * @returns A map of asset types to balances. + */ + async #getBalances( + accountId: string, + snapId: string, + assetTypes: CaipAssetType[], + ): Promise> { + return await this.#getClient(snapId).getAccountBalances( + accountId, + assetTypes, + ); + } + + /** + * Gets a `KeyringClient` for a Snap. + * + * @param snapId - ID of the Snap to get the client for. + * @returns A `KeyringClient` for the Snap. + */ + #getClient(snapId: string): KeyringClient { + return new KeyringClient({ + send: async (request: JsonRpcRequest) => + (await this.messagingSystem.call('SnapController:handleRequest', { + snapId: snapId as SnapId, + origin: 'metamask', + handler: HandlerType.OnKeyringRequest, + request, + })) as Promise, + }); + } +} diff --git a/app/scripts/lib/accounts/Poller.test.ts b/app/scripts/lib/accounts/Poller.test.ts new file mode 100644 index 000000000000..e79d4961a0c8 --- /dev/null +++ b/app/scripts/lib/accounts/Poller.test.ts @@ -0,0 +1,59 @@ +import { Poller } from './Poller'; + +jest.useFakeTimers(); + +const interval = 1000; +const intervalPlus100ms = interval + 100; + +describe('Poller', () => { + let callback: jest.Mock; + + beforeEach(() => { + callback = jest.fn(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('calls the callback function after the specified interval', async () => { + const poller = new Poller(callback, interval); + poller.start(); + jest.advanceTimersByTime(intervalPlus100ms); + poller.stop(); + + expect(callback).toHaveBeenCalledTimes(1); + }); + + it('does not call the callback function if stopped before the interval', async () => { + const poller = new Poller(callback, interval); + poller.start(); + poller.stop(); + jest.advanceTimersByTime(intervalPlus100ms); + + expect(callback).not.toHaveBeenCalled(); + }); + + it('calls the callback function multiple times if started and stopped multiple times', async () => { + const poller = new Poller(callback, interval); + poller.start(); + jest.advanceTimersByTime(intervalPlus100ms); + poller.stop(); + jest.advanceTimersByTime(intervalPlus100ms); + poller.start(); + jest.advanceTimersByTime(intervalPlus100ms); + poller.stop(); + + expect(callback).toHaveBeenCalledTimes(2); + }); + + it('does not call the callback if the poller is stopped before the interval has passed', async () => { + const poller = new Poller(callback, interval); + poller.start(); + // Wait for some time, but resumes before reaching out + // the `interval` timeout + jest.advanceTimersByTime(interval / 2); + poller.stop(); + expect(callback).not.toHaveBeenCalled(); + }); +}); diff --git a/app/scripts/lib/accounts/Poller.ts b/app/scripts/lib/accounts/Poller.ts new file mode 100644 index 000000000000..600e2ea615d7 --- /dev/null +++ b/app/scripts/lib/accounts/Poller.ts @@ -0,0 +1,28 @@ +export class Poller { + #interval: number; + + #callback: () => void; + + #handle: NodeJS.Timeout | undefined = undefined; + + constructor(callback: () => void, interval: number) { + this.#interval = interval; + this.#callback = callback; + } + + start() { + if (this.#handle) { + return; + } + + this.#handle = setInterval(this.#callback, this.#interval); + } + + stop() { + if (!this.#handle) { + return; + } + clearInterval(this.#handle); + this.#handle = undefined; + } +} diff --git a/app/scripts/lib/backup.test.js b/app/scripts/lib/backup.test.js index ceab30f28188..9f994ec52d55 100644 --- a/app/scripts/lib/backup.test.js +++ b/app/scripts/lib/backup.test.js @@ -1,7 +1,8 @@ /** * @jest-environment node */ -import { EthAccountType, EthMethod } from '@metamask/keyring-api'; +import { EthAccountType } from '@metamask/keyring-api'; +import { ETH_EOA_METHODS } from '../../../shared/constants/eth-methods'; import Backup from './backup'; function getMockPreferencesController() { @@ -161,14 +162,16 @@ const jsonData = JSON.stringify({ showExtensionInFullSizeView: false, showFiatInTestnets: false, showTestNetworks: true, + smartTransactionsOptInStatus: false, useNativeCurrencyAsPrimaryCurrency: true, + showTokenAutodetectModal: false, }, ipfsGateway: 'dweb.link', ledgerTransportType: 'webhid', theme: 'light', customNetworkListEnabled: false, textDirection: 'auto', - useRequestQueue: false, + useRequestQueue: true, }, internalAccounts: { accounts: { @@ -183,14 +186,7 @@ const jsonData = JSON.stringify({ lastSelected: 1693289751176, }, options: {}, - methods: [ - EthMethod.PersonalSign, - EthMethod.Sign, - EthMethod.SignTransaction, - EthMethod.SignTypedDataV1, - EthMethod.SignTypedDataV3, - EthMethod.SignTypedDataV4, - ], + methods: ETH_EOA_METHODS, type: EthAccountType.Eoa, }, }, diff --git a/app/scripts/lib/createDupeReqFilterMiddleware.js b/app/scripts/lib/createDupeReqFilterMiddleware.js deleted file mode 100644 index 556e71c18517..000000000000 --- a/app/scripts/lib/createDupeReqFilterMiddleware.js +++ /dev/null @@ -1,23 +0,0 @@ -import log from 'loglevel'; - -/** - * Returns a middleware that filters out requests already seen - * - * @returns {Function} - */ -export default function createDupeReqFilterMiddleware() { - const processedRequestId = []; - return function filterDuplicateRequestMiddleware( - /** @type {any} */ req, - /** @type {any} */ _res, - /** @type {Function} */ next, - /** @type {Function} */ end, - ) { - if (processedRequestId.indexOf(req.id) >= 0) { - log.info(`RPC request with id ${req.id} already seen.`); - return end(); - } - processedRequestId.push(req.id); - return next(); - }; -} diff --git a/app/scripts/lib/createDupeReqFilterMiddleware.test.js b/app/scripts/lib/createDupeReqFilterMiddleware.test.js deleted file mode 100644 index 503f383d9ed1..000000000000 --- a/app/scripts/lib/createDupeReqFilterMiddleware.test.js +++ /dev/null @@ -1,30 +0,0 @@ -import createDupeReqFilterMiddleware from './createDupeReqFilterMiddleware'; - -describe('createDupeReqFilterMiddleware', () => { - it('call function next if request is seen first time', () => { - const filterFn = createDupeReqFilterMiddleware(); - const request = { id: 1 }; - const nextMock = jest.fn(); - const endMock = jest.fn(); - - filterFn(request, undefined, nextMock, endMock); - - expect(nextMock).toHaveBeenCalledTimes(1); - expect(endMock).not.toHaveBeenCalled(); - }); - - it('call function end if request is seen second time', () => { - const filterFn = createDupeReqFilterMiddleware(); - const request = { id: 1 }; - const nextMock = jest.fn(); - const endMock = jest.fn(); - - filterFn(request, undefined, nextMock, endMock); - expect(nextMock).toHaveBeenCalledTimes(1); - expect(endMock).not.toHaveBeenCalled(); - - filterFn(request, undefined, nextMock, endMock); - expect(nextMock).toHaveBeenCalledTimes(1); - expect(endMock).toHaveBeenCalledTimes(1); - }); -}); diff --git a/app/scripts/lib/createDupeReqFilterStream.test.ts b/app/scripts/lib/createDupeReqFilterStream.test.ts new file mode 100644 index 000000000000..4a3ff375b7e6 --- /dev/null +++ b/app/scripts/lib/createDupeReqFilterStream.test.ts @@ -0,0 +1,392 @@ +import NodeStream from 'node:stream'; +import OurReadableStream from 'readable-stream'; +import ReadableStream2 from 'readable-stream-2'; +import ReadableStream3 from 'readable-stream-3'; + +import type { JsonRpcRequest } from '@metamask/utils'; +import createDupeReqFilterStream, { + THREE_MINUTES, +} from './createDupeReqFilterStream'; + +const { Transform } = OurReadableStream; + +function createTestStream(output: JsonRpcRequest[] = [], S = Transform) { + const transformStream = createDupeReqFilterStream(); + const testOutStream = new S({ + transform: (chunk: JsonRpcRequest, _, cb) => { + output.push(chunk); + cb(); + }, + objectMode: true, + }); + + transformStream.pipe(testOutStream); + + return transformStream; +} + +function runStreamTest( + requests: JsonRpcRequest[] = [], + advanceTimersTime = 10, + S = Transform, +) { + return new Promise((resolve, reject) => { + const output: JsonRpcRequest[] = []; + const testStream = createTestStream(output, S); + + testStream + .on('finish', () => resolve(output)) + .on('error', (err) => reject(err)); + + requests.forEach((request) => testStream.write(request)); + testStream.end(); + + jest.advanceTimersByTime(advanceTimersTime); + }); +} + +describe('createDupeReqFilterStream', () => { + beforeEach(() => { + jest.useFakeTimers({ now: 10 }); + }); + + it('lets through requests with ids being seen for the first time', async () => { + const requests = [ + { id: 1, method: 'foo' }, + { id: 2, method: 'bar' }, + ]; + + const expectedOutput = [ + { id: 1, method: 'foo' }, + { id: 2, method: 'bar' }, + ]; + + const output = await runStreamTest(requests); + expect(output).toEqual(expectedOutput); + }); + + it('does not let through the request if the id has been seen before', async () => { + const requests = [ + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, // duplicate + ]; + + const expectedOutput = [{ id: 1, method: 'foo' }]; + + const output = await runStreamTest(requests); + expect(output).toEqual(expectedOutput); + }); + + it("lets through requests if they don't have an id", async () => { + const requests = [{ method: 'notify1' }, { method: 'notify2' }]; + + const expectedOutput = [{ method: 'notify1' }, { method: 'notify2' }]; + + const output = await runStreamTest(requests); + expect(output).toEqual(expectedOutput); + }); + + it('handles a mix of request types', async () => { + const requests = [ + { id: 1, method: 'foo' }, + { method: 'notify1' }, + { id: 1, method: 'foo' }, + { id: 2, method: 'bar' }, + { method: 'notify2' }, + { id: 2, method: 'bar' }, + { id: 3, method: 'baz' }, + ]; + + const expectedOutput = [ + { id: 1, method: 'foo' }, + { method: 'notify1' }, + { id: 2, method: 'bar' }, + { method: 'notify2' }, + { id: 3, method: 'baz' }, + ]; + + const output = await runStreamTest(requests); + expect(output).toEqual(expectedOutput); + }); + + it('expires single id after three minutes', () => { + const output: JsonRpcRequest[] = []; + const testStream = createTestStream(output); + + const requests1 = [ + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + ]; + const expectedOutputBeforeExpiryTime = [{ id: 1, method: 'foo' }]; + + requests1.forEach((request) => testStream.write(request)); + expect(output).toEqual(expectedOutputBeforeExpiryTime); + + const requests2 = [ + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + ]; + const expectedOutputAfterExpiryTime = [ + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + ]; + + jest.advanceTimersByTime(THREE_MINUTES); + + requests2.forEach((request) => testStream.write(request)); + expect(output).toEqual(expectedOutputAfterExpiryTime); + }); + + it('does not expire single id after less than three', () => { + const output: JsonRpcRequest[] = []; + const testStream = createTestStream(output); + + const requests1 = [ + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + ]; + const expectedOutputBeforeTimeElapses = [{ id: 1, method: 'foo' }]; + + requests1.forEach((request) => testStream.write(request)); + expect(output).toEqual(expectedOutputBeforeTimeElapses); + + const requests2 = [ + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + ]; + const expectedOutputAfterTimeElapses = expectedOutputBeforeTimeElapses; + + jest.advanceTimersByTime(THREE_MINUTES - 1); + + requests2.forEach((request) => testStream.write(request)); + expect(output).toEqual(expectedOutputAfterTimeElapses); + }); + + it('expires multiple ids after three minutes', () => { + const output: JsonRpcRequest[] = []; + const testStream = createTestStream(output); + + const requests1 = [ + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + { id: 2, method: 'bar' }, + { id: 2, method: 'bar' }, + { id: 3, method: 'baz' }, + { id: 3, method: 'baz' }, + ]; + const expectedOutputBeforeExpiryTime = [ + { id: 1, method: 'foo' }, + { id: 2, method: 'bar' }, + { id: 3, method: 'baz' }, + ]; + + requests1.forEach((request) => testStream.write(request)); + expect(output).toEqual(expectedOutputBeforeExpiryTime); + + const requests2 = [ + { id: 3, method: 'baz' }, + { id: 3, method: 'baz' }, + { id: 2, method: 'bar' }, + { id: 2, method: 'bar' }, + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + ]; + const expectedOutputAfterExpiryTime = [ + { id: 1, method: 'foo' }, + { id: 2, method: 'bar' }, + { id: 3, method: 'baz' }, + { id: 3, method: 'baz' }, + { id: 2, method: 'bar' }, + { id: 1, method: 'foo' }, + ]; + + jest.advanceTimersByTime(THREE_MINUTES); + + requests2.forEach((request) => testStream.write(request)); + expect(output).toEqual(expectedOutputAfterExpiryTime); + }); + + it('expires single id in three minute intervals', () => { + const output: JsonRpcRequest[] = []; + const testStream = createTestStream(output); + + const requests1 = [ + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + ]; + const expectedOutputBeforeExpiryTime = [{ id: 1, method: 'foo' }]; + + requests1.forEach((request) => testStream.write(request)); + expect(output).toEqual(expectedOutputBeforeExpiryTime); + + const requests2 = [ + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + ]; + const expectedOutputAfterFirstExpiryTime = [ + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + ]; + + jest.advanceTimersByTime(THREE_MINUTES); + + requests2.forEach((request) => testStream.write(request)); + expect(output).toEqual(expectedOutputAfterFirstExpiryTime); + + const requests3 = [ + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + ]; + const expectedOutputAfterSecondExpiryTime = [ + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + { id: 1, method: 'foo' }, + ]; + + jest.advanceTimersByTime(THREE_MINUTES); + + requests3.forEach((request) => testStream.write(request)); + expect(output).toEqual(expectedOutputAfterSecondExpiryTime); + }); + + it('expires somes ids at intervals while not expiring others', () => { + const output: JsonRpcRequest[] = []; + const testStream = createTestStream(output); + + const requests1 = [ + { id: 1, method: 'foo' }, + { id: 2, method: 'bar' }, + ]; + const expectedOutputBeforeExpiryTime = [ + { id: 1, method: 'foo' }, + { id: 2, method: 'bar' }, + ]; + + requests1.forEach((request) => testStream.write(request)); + expect(output).toEqual(expectedOutputBeforeExpiryTime); + + const requests2 = [{ id: 3, method: 'baz' }]; + const expectedOutputAfterFirstExpiryTime = [ + { id: 1, method: 'foo' }, + { id: 2, method: 'bar' }, + { id: 3, method: 'baz' }, + ]; + + jest.advanceTimersByTime(THREE_MINUTES - 1); + + requests2.forEach((request) => testStream.write(request)); + expect(output).toEqual(expectedOutputAfterFirstExpiryTime); + + const requests3 = [ + { id: 1, method: 'foo' }, + { id: 2, method: 'bar' }, + { id: 3, method: 'baz' }, + { id: 4, method: 'buzz' }, + ]; + const expectedOutputAfterSecondExpiryTime = [ + { id: 1, method: 'foo' }, + { id: 2, method: 'bar' }, + { id: 3, method: 'baz' }, + { id: 1, method: 'foo' }, + { id: 2, method: 'bar' }, + { id: 4, method: 'buzz' }, + ]; + + jest.advanceTimersByTime(THREE_MINUTES - 1); + + requests3.forEach((request) => testStream.write(request)); + expect(output).toEqual(expectedOutputAfterSecondExpiryTime); + }); + + it('handles running expiry job without seeing any ids', () => { + const output: JsonRpcRequest[] = []; + const testStream = createTestStream(output); + + const requests1 = [{ id: 1, method: 'foo' }]; + const expectedOutputBeforeExpiryTime = [{ id: 1, method: 'foo' }]; + + requests1.forEach((request) => testStream.write(request)); + expect(output).toEqual(expectedOutputBeforeExpiryTime); + + jest.advanceTimersByTime(THREE_MINUTES + 1); + + expect(output).toEqual(expectedOutputBeforeExpiryTime); + }); + + [ + ['node:stream', NodeStream] as [string, typeof NodeStream], + // Redundantly include used version twice for regression-detection purposes + ['readable-stream', OurReadableStream] as [ + string, + typeof OurReadableStream, + ], + ['readable-stream v2', ReadableStream2] as [string, typeof ReadableStream2], + ['readable-stream v3', ReadableStream3] as [string, typeof ReadableStream3], + ].forEach(([name, streamsImpl]) => { + describe(`Using Streams implementation: ${name}`, () => { + [ + ['Duplex', streamsImpl.Duplex] as [string, typeof streamsImpl.Duplex], + ['Transform', streamsImpl.Transform] as [ + string, + typeof streamsImpl.Transform, + ], + ['Writable', streamsImpl.Writable] as [ + string, + typeof streamsImpl.Writable, + ], + ].forEach(([className, S]) => { + it(`handles a mix of request types coming through a ${className} stream`, async () => { + const requests = [ + { id: 1, method: 'foo' }, + { method: 'notify1' }, + { id: 1, method: 'foo' }, + { id: 2, method: 'bar' }, + { method: 'notify2' }, + { id: 2, method: 'bar' }, + { id: 3, method: 'baz' }, + ]; + + const expectedOutput = [ + { id: 1, method: 'foo' }, + { method: 'notify1' }, + { id: 2, method: 'bar' }, + { method: 'notify2' }, + { id: 3, method: 'baz' }, + ]; + + const output: JsonRpcRequest[] = []; + const testStream = createDupeReqFilterStream(); + const testOutStream = new S({ + transform: (chunk: JsonRpcRequest, _, cb) => { + output.push(chunk); + cb(); + }, + objectMode: true, + }); + + testOutStream._write = ( + chunk: JsonRpcRequest, + _: BufferEncoding, + callback: (error?: Error | null) => void, + ) => { + output.push(chunk); + callback(); + }; + + testStream.pipe(testOutStream); + + requests.forEach((request) => testStream.write(request)); + + expect(output).toEqual(expectedOutput); + }); + }); + }); + }); +}); diff --git a/app/scripts/lib/createDupeReqFilterStream.ts b/app/scripts/lib/createDupeReqFilterStream.ts new file mode 100644 index 000000000000..63d801e7f1e4 --- /dev/null +++ b/app/scripts/lib/createDupeReqFilterStream.ts @@ -0,0 +1,68 @@ +import { Transform } from 'readable-stream'; +import log from 'loglevel'; +import type { JsonRpcRequest } from '@metamask/utils'; +import { MINUTE } from '../../../shared/constants/time'; + +export const THREE_MINUTES = MINUTE * 3; + +/** + * Creates a set abstraction whose values expire after three minutes. + * + * @returns The expiry set. + */ +const makeExpirySet = () => { + const map: Map = new Map(); + + setInterval(() => { + const cutoffTime = Date.now() - THREE_MINUTES; + + for (const [id, timestamp] of map.entries()) { + if (timestamp <= cutoffTime) { + map.delete(id); + } else { + break; + } + } + }, THREE_MINUTES); + + return { + /** + * Attempts to add a value to the set. + * + * @param value - The value to add. + * @returns `true` if the value was added, and `false` if it already existed. + */ + add(value: string | number) { + if (!map.has(value)) { + map.set(value, Date.now()); + return true; + } + return false; + }, + }; +}; + +/** + * Returns a transform stream that filters out requests whose ids we've already seen. + * Ignores JSON-RPC notifications, i.e. requests with an `undefined` id. + * + * @returns The stream object. + */ +export default function createDupeReqFilterStream() { + const seenRequestIds = makeExpirySet(); + return new Transform({ + transform(chunk: JsonRpcRequest, _, cb) { + // JSON-RPC notifications have no ids; our only recourse is to let them through. + const hasNoId = chunk.id === undefined; + const requestNotYetSeen = seenRequestIds.add(chunk.id); + + if (hasNoId || requestNotYetSeen) { + cb(null, chunk); + } else { + log.debug(`RPC request with id "${chunk.id}" already seen.`); + cb(); + } + }, + objectMode: true, + }); +} diff --git a/app/scripts/lib/createEvmMethodsToNonEvmAccountReqFilterMiddleware.test.ts b/app/scripts/lib/createEvmMethodsToNonEvmAccountReqFilterMiddleware.test.ts new file mode 100644 index 000000000000..3b677225a148 --- /dev/null +++ b/app/scripts/lib/createEvmMethodsToNonEvmAccountReqFilterMiddleware.test.ts @@ -0,0 +1,285 @@ +import { jsonrpc2 } from '@metamask/utils'; +import { BtcAccountType, EthAccountType } from '@metamask/keyring-api'; +import { Json } from 'json-rpc-engine'; +import createEvmMethodsToNonEvmAccountReqFilterMiddleware, { + EvmMethodsToNonEvmAccountFilterMessenger, +} from './createEvmMethodsToNonEvmAccountReqFilterMiddleware'; + +describe('createEvmMethodsToNonEvmAccountReqFilterMiddleware', () => { + const getMockRequest = (method: string, params?: Json) => ({ + jsonrpc: jsonrpc2, + id: 1, + method, + params, + }); + const getMockResponse = () => ({ jsonrpc: jsonrpc2, id: 'foo' }); + + // @ts-expect-error This function is missing from the Mocha type definitions + it.each([ + // EVM requests + { + accountType: BtcAccountType.P2wpkh, + method: 'eth_accounts', + calledNext: false, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'eth_sendRawTransaction', + calledNext: false, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'eth_sendTransaction', + calledNext: false, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'eth_sign', + calledNext: false, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'eth_signTypedData', + calledNext: false, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'eth_signTypedData_v1', + calledNext: false, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'eth_signTypedData_v3', + calledNext: false, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'eth_signTypedData_v4', + calledNext: false, + }, + { + accountType: EthAccountType.Eoa, + method: 'eth_accounts', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'eth_sendRawTransaction', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'eth_sendTransaction', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'eth_sign', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'eth_signTypedData', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'eth_signTypedData_v1', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'eth_signTypedData_v3', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'eth_signTypedData_v4', + calledNext: true, + }, + + // EVM requests not associated with an account + { + accountType: BtcAccountType.P2wpkh, + method: 'eth_blockNumber', + calledNext: true, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'eth_chainId', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'eth_blockNumber', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'eth_chainId', + calledNext: true, + }, + + // other requests + { + accountType: BtcAccountType.P2wpkh, + method: 'wallet_getSnaps', + calledNext: true, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'wallet_invokeSnap', + calledNext: true, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'wallet_requestSnaps', + calledNext: true, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'snap_getClientStatus', + calledNext: true, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'wallet_addEthereumChain', + calledNext: true, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'wallet_getPermissions', + calledNext: true, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'wallet_requestPermissions', + calledNext: true, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'wallet_revokePermissions', + calledNext: true, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'wallet_switchEthereumChain', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'wallet_getSnaps', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'wallet_invokeSnap', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'wallet_requestSnaps', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'snap_getClientStatus', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'wallet_addEthereumChain', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'wallet_getPermissions', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'wallet_requestPermissions', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'wallet_revokePermissions', + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'wallet_switchEthereumChain', + calledNext: true, + }, + + // wallet_requestPermissions request + { + accountType: BtcAccountType.P2wpkh, + method: 'wallet_requestPermissions', + params: [{ eth_accounts: {} }], + calledNext: false, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'wallet_requestPermissions', + params: [{ snap_getClientStatus: {} }], + calledNext: true, + }, + { + accountType: BtcAccountType.P2wpkh, + method: 'wallet_requestPermissions', + params: [{ eth_accounts: {}, snap_getClientStatus: {} }], + calledNext: false, + }, + { + accountType: EthAccountType.Eoa, + method: 'wallet_requestPermissions', + params: [{ eth_accounts: {} }], + calledNext: true, + }, + + { + accountType: EthAccountType.Eoa, + method: 'wallet_requestPermissions', + params: [{ snap_getClientStatus: {} }], + calledNext: true, + }, + { + accountType: EthAccountType.Eoa, + method: 'wallet_requestPermissions', + params: [{ eth_accounts: {}, snap_getClientStatus: {} }], + calledNext: true, + }, + ])( + `accountType $accountType method $method with non-EVM account is passed to next called $calledNext times`, + ({ + accountType, + method, + params, + calledNext, + }: { + accountType: EthAccountType | BtcAccountType; + method: string; + params?: Json; + calledNext: number; + }) => { + const filterFn = createEvmMethodsToNonEvmAccountReqFilterMiddleware({ + messenger: { + call: jest.fn().mockReturnValue({ type: accountType }), + } as unknown as EvmMethodsToNonEvmAccountFilterMessenger, + }); + const mockNext = jest.fn(); + const mockEnd = jest.fn(); + + filterFn( + getMockRequest(method, params), + getMockResponse(), + mockNext, + mockEnd, + ); + + expect(mockNext).toHaveBeenCalledTimes(calledNext ? 1 : 0); + expect(mockEnd).toHaveBeenCalledTimes(calledNext ? 0 : 1); + }, + ); +}); diff --git a/app/scripts/lib/createEvmMethodsToNonEvmAccountReqFilterMiddleware.ts b/app/scripts/lib/createEvmMethodsToNonEvmAccountReqFilterMiddleware.ts new file mode 100644 index 000000000000..3e1eca86997e --- /dev/null +++ b/app/scripts/lib/createEvmMethodsToNonEvmAccountReqFilterMiddleware.ts @@ -0,0 +1,94 @@ +import { isEvmAccountType } from '@metamask/keyring-api'; +import { RestrictedControllerMessenger } from '@metamask/base-controller'; +import { AccountsControllerGetSelectedAccountAction } from '@metamask/accounts-controller'; +import { JsonRpcMiddleware } from 'json-rpc-engine'; +import { RestrictedEthMethods } from '../../../shared/constants/permissions'; +import { unrestrictedEthSigningMethods } from '../controllers/permissions'; + +type AllowedActions = AccountsControllerGetSelectedAccountAction; + +export type EvmMethodsToNonEvmAccountFilterMessenger = + RestrictedControllerMessenger< + 'EvmMethodsToNonEvmAccountFilterMessenger', + AllowedActions, + never, + AllowedActions['type'], + never + >; + +const METHODS_TO_CHECK = [ + ...Object.values(RestrictedEthMethods), + ...unrestrictedEthSigningMethods, +]; + +/** + * Returns a middleware that filters out requests whose requests are restricted to EVM accounts. + * + * @param opt - The middleware options. + * @param opt.messenger - The messenger object. + * @returns The middleware function. + */ +export default function createEvmMethodsToNonEvmAccountReqFilterMiddleware({ + messenger, +}: { + messenger: EvmMethodsToNonEvmAccountFilterMessenger; +}): JsonRpcMiddleware { + return function filterEvmRequestToNonEvmAccountsMiddleware( + req, + _res, + next, + end, + ) { + const selectedAccount = messenger.call( + 'AccountsController:getSelectedAccount', + ); + + // If it's an EVM account, there nothing to filter, so jump to the next + // middleware directly. + if (isEvmAccountType(selectedAccount.type)) { + return next(); + } + + const ethMethodsRequiringEthAccount = METHODS_TO_CHECK.includes(req.method); + if (ethMethodsRequiringEthAccount) { + return end( + new Error(`Non-EVM account cannot request this method: ${req.method}`), + ); + } + + // https://docs.metamask.io/wallet/reference/wallet_requestpermissions/ + // wallet_requestPermissions param is an array with one object. The object may contain + // multiple keys that represent the permissions being requested. + + // Example: + // { + // "method": "wallet_requestPermissions", + // "params": [ + // { + // "eth_accounts": {}, + // "anotherPermission": {} + // } + // ] + // } + + // TODO: Convert this to superstruct schema + const isWalletRequestPermission = + req.method === 'wallet_requestPermissions'; + if (isWalletRequestPermission && req?.params && Array.isArray(req.params)) { + const permissionsMethodRequest = Object.keys(req.params[0]); + + const isEvmPermissionRequest = METHODS_TO_CHECK.some((method) => + permissionsMethodRequest.includes(method), + ); + if (isEvmPermissionRequest) { + return end( + new Error( + `Non-EVM account cannot request this method: ${permissionsMethodRequest.toString()}`, + ), + ); + } + } + + return next(); + }; +} diff --git a/app/scripts/lib/createMetaRPCHandler.js b/app/scripts/lib/createMetaRPCHandler.js index f55319783fea..77f86d23fe02 100644 --- a/app/scripts/lib/createMetaRPCHandler.js +++ b/app/scripts/lib/createMetaRPCHandler.js @@ -1,9 +1,9 @@ import { ethErrors, serializeError } from 'eth-rpc-errors'; -import { isManifestV3 } from '../../../shared/modules/mv3.utils'; +import { isStreamWritable } from './stream-utils'; -const createMetaRPCHandler = (api, outStream, store, localStoreApiWrapper) => { +const createMetaRPCHandler = (api, outStream) => { return async (data) => { - if (outStream._writableState.ended) { + if (!isStreamWritable(outStream)) { return; } if (!api[data.method]) { @@ -23,13 +23,9 @@ const createMetaRPCHandler = (api, outStream, store, localStoreApiWrapper) => { result = await api[data.method](...data.params); } catch (err) { error = err; - } finally { - if (isManifestV3 && store && data.method !== 'getState') { - localStoreApiWrapper.set(store.getState()); - } } - if (outStream._writableState.ended) { + if (!isStreamWritable(outStream)) { if (error) { console.error(error); } diff --git a/app/scripts/lib/createRPCMethodTrackingMiddleware.js b/app/scripts/lib/createRPCMethodTrackingMiddleware.js index d934a87eff41..195f9c05fed5 100644 --- a/app/scripts/lib/createRPCMethodTrackingMiddleware.js +++ b/app/scripts/lib/createRPCMethodTrackingMiddleware.js @@ -1,14 +1,13 @@ -import { detectSIWE } from '@metamask/controller-utils'; +import { ApprovalType, detectSIWE } from '@metamask/controller-utils'; import { errorCodes } from 'eth-rpc-errors'; import { isValidAddress } from 'ethereumjs-util'; -import { TransactionStatus } from '@metamask/transaction-controller'; import { MESSAGE_TYPE, ORIGIN_METAMASK } from '../../../shared/constants/app'; import { MetaMetricsEventCategory, MetaMetricsEventName, MetaMetricsEventUiCustomization, } from '../../../shared/constants/metametrics'; -import { SECOND } from '../../../shared/constants/time'; +import { parseTypedDataMessage } from '../../../shared/modules/transaction.utils'; import { BlockaidResultType, @@ -17,24 +16,30 @@ import { ///: END:ONLY_INCLUDE_IF } from '../../../shared/constants/security-provider'; -import { SIGNING_METHODS } from '../../../shared/constants/transaction'; +///: BEGIN:ONLY_INCLUDE_IF(blockaid) +import { + EIP712_PRIMARY_TYPE_PERMIT, + SIGNING_METHODS, +} from '../../../shared/constants/transaction'; import { getBlockaidMetricsProps } from '../../../ui/helpers/utils/metrics'; +///: END:ONLY_INCLUDE_IF +import { REDESIGN_APPROVAL_TYPES } from '../../../ui/pages/confirmations/utils/confirm'; import { getSnapAndHardwareInfoForMetrics } from './snap-keyring/metrics'; /** * These types determine how the method tracking middleware handles incoming - * requests based on the method name. There are three options right now but - * the types could be expanded to cover other options in the future. + * requests based on the method name. */ const RATE_LIMIT_TYPES = { - RATE_LIMITED: 'rate_limited', + TIMEOUT: 'timeout', BLOCKED: 'blocked', NON_RATE_LIMITED: 'non_rate_limited', + RANDOM_SAMPLE: 'random_sample', }; /** * This object maps a method name to a RATE_LIMIT_TYPE. If not in this map the - * default is 'RATE_LIMITED' + * default is RANDOM_SAMPLE */ const RATE_LIMIT_MAP = { [MESSAGE_TYPE.ETH_SIGN]: RATE_LIMIT_TYPES.NON_RATE_LIMITED, @@ -45,12 +50,25 @@ const RATE_LIMIT_MAP = { [MESSAGE_TYPE.ETH_DECRYPT]: RATE_LIMIT_TYPES.NON_RATE_LIMITED, [MESSAGE_TYPE.ETH_GET_ENCRYPTION_PUBLIC_KEY]: RATE_LIMIT_TYPES.NON_RATE_LIMITED, - [MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS]: RATE_LIMIT_TYPES.RATE_LIMITED, - [MESSAGE_TYPE.WALLET_REQUEST_PERMISSIONS]: RATE_LIMIT_TYPES.RATE_LIMITED, + [MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS]: RATE_LIMIT_TYPES.TIMEOUT, + [MESSAGE_TYPE.WALLET_REQUEST_PERMISSIONS]: RATE_LIMIT_TYPES.TIMEOUT, [MESSAGE_TYPE.SEND_METADATA]: RATE_LIMIT_TYPES.BLOCKED, + [MESSAGE_TYPE.ETH_CHAIN_ID]: RATE_LIMIT_TYPES.BLOCKED, + [MESSAGE_TYPE.ETH_ACCOUNTS]: RATE_LIMIT_TYPES.BLOCKED, + [MESSAGE_TYPE.LOG_WEB3_SHIM_USAGE]: RATE_LIMIT_TYPES.BLOCKED, [MESSAGE_TYPE.GET_PROVIDER_STATE]: RATE_LIMIT_TYPES.BLOCKED, }; +const MESSAGE_TYPE_TO_APPROVAL_TYPE = { + [MESSAGE_TYPE.PERSONAL_SIGN]: ApprovalType.PersonalSign, + [MESSAGE_TYPE.ETH_SIGN]: ApprovalType.Sign, + [MESSAGE_TYPE.SIGN]: ApprovalType.SignTransaction, + [MESSAGE_TYPE.ETH_SIGN_TYPED_DATA]: ApprovalType.EthSignTypedData, + [MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V1]: ApprovalType.EthSignTypedData, + [MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V3]: ApprovalType.EthSignTypedData, + [MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4]: ApprovalType.EthSignTypedData, +}; + /** * For events with user interaction (approve / reject | cancel) this map will * return an object with APPROVED, REJECTED, REQUESTED, and FAILED keys that map to the @@ -105,8 +123,19 @@ const EVENT_NAME_MAP = { }, }; -const rateLimitTimeouts = {}; +/** + * This object maps a method name to a function that accept the method params and + * returns a non-sensitive version that can be included in tracked events. + * The default is to return undefined. + */ +const TRANSFORM_PARAMS_MAP = { + [MESSAGE_TYPE.WATCH_ASSET]: ({ type }) => ({ type }), +}; + +const rateLimitTimeoutsByMethod = {}; +let globalRateLimitCount = 0; +///: BEGIN:ONLY_INCLUDE_IF(blockaid) /** * Returns a middleware that tracks inpage_provider usage using sampling for * each type of event except those that require user interaction, such as @@ -117,40 +146,69 @@ const rateLimitTimeouts = {}; * MetaMetricsController * @param {Function} opts.getMetricsState - get the state of * MetaMetricsController - * @param {number} [opts.rateLimitSeconds] - number of seconds to wait before - * allowing another set of events to be tracked. - * @param opts.securityProviderRequest + * @param {number} [opts.rateLimitTimeout] - time, in milliseconds, to wait before + * allowing another set of events to be tracked for methods rate limited by timeout. + * @param {number} [opts.rateLimitSamplePercent] - percentage, in decimal, of events + * that should be tracked for methods rate limited by random sample. * @param {Function} opts.getAccountType * @param {Function} opts.getDeviceModel + * @param {Function} opts.isConfirmationRedesignEnabled * @param {RestrictedControllerMessenger} opts.snapAndHardwareMessenger * @param {AppStateController} opts.appStateController + * @param {number} [opts.globalRateLimitTimeout] - time, in milliseconds, of the sliding + * time window that should limit the number of method calls tracked to globalRateLimitMaxAmount. + * @param {number} [opts.globalRateLimitMaxAmount] - max number of method calls that should + * tracked within the globalRateLimitTimeout time window. * @returns {Function} */ +///: END:ONLY_INCLUDE_IF + export default function createRPCMethodTrackingMiddleware({ trackEvent, getMetricsState, - rateLimitSeconds = 60 * 5, - securityProviderRequest, + rateLimitTimeout = 60 * 5 * 1000, // 5 minutes + rateLimitSamplePercent = 0.001, // 0.1% + globalRateLimitTimeout = 60 * 5 * 1000, // 5 minutes + globalRateLimitMaxAmount = 10, // max of events in the globalRateLimitTimeout window. pass 0 for no global rate limit getAccountType, getDeviceModel, + isConfirmationRedesignEnabled, snapAndHardwareMessenger, + ///: BEGIN:ONLY_INCLUDE_IF(blockaid) appStateController, + ///: END:ONLY_INCLUDE_IF }) { return async function rpcMethodTrackingMiddleware( /** @type {any} */ req, /** @type {any} */ res, /** @type {Function} */ next, ) { - const { origin, method } = req; + const { origin, method, params } = req; - // Determine what type of rate limit to apply based on method const rateLimitType = - RATE_LIMIT_MAP[method] ?? RATE_LIMIT_TYPES.RATE_LIMITED; + RATE_LIMIT_MAP[method] ?? RATE_LIMIT_TYPES.RANDOM_SAMPLE; + + let isRateLimited; + switch (rateLimitType) { + case RATE_LIMIT_TYPES.TIMEOUT: + isRateLimited = + typeof rateLimitTimeoutsByMethod[method] !== 'undefined'; + break; + case RATE_LIMIT_TYPES.NON_RATE_LIMITED: + isRateLimited = false; + break; + case RATE_LIMIT_TYPES.BLOCKED: + isRateLimited = true; + break; + default: + case RATE_LIMIT_TYPES.RANDOM_SAMPLE: + isRateLimited = Math.random() >= rateLimitSamplePercent; + break; + } - // If the rateLimitType is RATE_LIMITED check the rateLimitTimeouts - const rateLimited = - rateLimitType === RATE_LIMIT_TYPES.RATE_LIMITED && - typeof rateLimitTimeouts[method] !== 'undefined'; + const isGlobalRateLimited = + globalRateLimitMaxAmount > 0 && + globalRateLimitCount >= globalRateLimitMaxAmount; // Get the participateInMetaMetrics state to determine if we should track // anything. This is extra redundancy because this value is checked in @@ -168,10 +226,10 @@ export default function createRPCMethodTrackingMiddleware({ const shouldTrackEvent = // Don't track if the request came from our own UI or background origin !== ORIGIN_METAMASK && - // Don't track if this is a blocked method - rateLimitType !== RATE_LIMIT_TYPES.BLOCKED && // Don't track if the rate limit has been hit - rateLimited === false && + !isRateLimited && + // Don't track if the global rate limit has been hit + !isGlobalRateLimited && // Don't track if the user isn't participating in metametrics userParticipatingInMetaMetrics === true; @@ -190,15 +248,11 @@ export default function createRPCMethodTrackingMiddleware({ // In personal messages the first param is data while in typed messages second param is data // if condition below is added to ensure that the right params are captured as data and address. let data; - let from; if (isValidAddress(req?.params?.[1])) { data = req?.params?.[0]; - from = req?.params?.[1]; } else { data = req?.params?.[1]; - from = req?.params?.[0]; } - const paramsExamplePassword = req?.params?.[2]; ///: BEGIN:ONLY_INCLUDE_IF(blockaid) if (req.securityAlertResponse?.providerRequestsCount) { @@ -222,6 +276,18 @@ export default function createRPCMethodTrackingMiddleware({ req.securityAlertResponse.description; } ///: END:ONLY_INCLUDE_IF + const isConfirmationRedesign = + isConfirmationRedesignEnabled() && + REDESIGN_APPROVAL_TYPES.find( + (type) => type === MESSAGE_TYPE_TO_APPROVAL_TYPE[method], + ); + + if (isConfirmationRedesign) { + eventProperties.ui_customizations = [ + ...(eventProperties.ui_customizations || []), + MetaMetricsEventUiCustomization.RedesignedConfirmation, + ]; + } const snapAndHardwareInfo = await getSnapAndHardwareInfoForMetrics( getAccountType, @@ -232,50 +298,37 @@ export default function createRPCMethodTrackingMiddleware({ // merge the snapAndHardwareInfo into eventProperties Object.assign(eventProperties, snapAndHardwareInfo); - const msgData = { - msgParams: { - ...paramsExamplePassword, - from, - data, - origin, - }, - status: TransactionStatus.unapproved, - type: req.method, - }; - try { - const securityProviderResponse = await securityProviderRequest( - msgData, - req.method, - ); - - if (securityProviderResponse?.flagAsDangerous === 1) { - eventProperties.ui_customizations = [ - MetaMetricsEventUiCustomization.FlaggedAsMalicious, - ]; - } else if (securityProviderResponse?.flagAsDangerous === 2) { - eventProperties.ui_customizations = [ - MetaMetricsEventUiCustomization.FlaggedAsSafetyUnknown, - ]; - } - if (method === MESSAGE_TYPE.PERSONAL_SIGN) { const { isSIWEMessage } = detectSIWE({ data }); if (isSIWEMessage) { - eventProperties.ui_customizations = ( - eventProperties.ui_customizations || [] - ).concat(MetaMetricsEventUiCustomization.Siwe); + eventProperties.ui_customizations = [ + ...(eventProperties.ui_customizations || []), + MetaMetricsEventUiCustomization.Siwe, + ]; + } + } else if (method === MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4) { + const { primaryType } = parseTypedDataMessage(data); + eventProperties.eip712_primary_type = primaryType; + if (primaryType === EIP712_PRIMARY_TYPE_PERMIT) { + eventProperties.ui_customizations = [ + ...(eventProperties.ui_customizations || []), + MetaMetricsEventUiCustomization.Permit, + ]; } } } catch (e) { - console.warn( - `createRPCMethodTrackingMiddleware: Error calling securityProviderRequest - ${e}`, - ); + console.warn(`createRPCMethodTrackingMiddleware: Errored - ${e}`); } } else { eventProperties.method = method; } + const transformParams = TRANSFORM_PARAMS_MAP[method]; + if (transformParams) { + eventProperties.params = transformParams(params); + } + trackEvent({ event, category: MetaMetricsEventCategory.InpageProvider, @@ -285,9 +338,16 @@ export default function createRPCMethodTrackingMiddleware({ properties: eventProperties, }); - rateLimitTimeouts[method] = setTimeout(() => { - delete rateLimitTimeouts[method]; - }, SECOND * rateLimitSeconds); + if (rateLimitType === RATE_LIMIT_TYPES.TIMEOUT) { + rateLimitTimeoutsByMethod[method] = setTimeout(() => { + delete rateLimitTimeoutsByMethod[method]; + }, rateLimitTimeout); + } + + globalRateLimitCount += 1; + setTimeout(() => { + globalRateLimitCount -= 1; + }, globalRateLimitTimeout); } next(async (callback) => { @@ -321,6 +381,7 @@ export default function createRPCMethodTrackingMiddleware({ let blockaidMetricProps = {}; + ///: BEGIN:ONLY_INCLUDE_IF(blockaid) if (!isDisabledRPCMethod) { if (SIGNING_METHODS.includes(method)) { const securityAlertResponse = @@ -333,6 +394,7 @@ export default function createRPCMethodTrackingMiddleware({ }); } } + ///: END:ONLY_INCLUDE_IF const properties = { ...eventProperties, diff --git a/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js b/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js index 41b78c080e0c..a0c0da552db1 100644 --- a/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js +++ b/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js @@ -1,7 +1,9 @@ import { errorCodes } from 'eth-rpc-errors'; import { detectSIWE } from '@metamask/controller-utils'; + import { MESSAGE_TYPE } from '../../../shared/constants/app'; import { + MetaMetricsEventCategory, MetaMetricsEventName, MetaMetricsEventUiCustomization, } from '../../../shared/constants/metametrics'; @@ -10,20 +12,13 @@ import { BlockaidReason, BlockaidResultType, } from '../../../shared/constants/security-provider'; +import { permitSignatureMsg } from '../../../test/data/confirmations/typed_sign'; import createRPCMethodTrackingMiddleware from './createRPCMethodTrackingMiddleware'; const trackEvent = jest.fn(); const metricsState = { participateInMetaMetrics: null }; const getMetricsState = () => metricsState; -let flagAsDangerous = 0; - -const securityProviderRequest = () => { - return { - flagAsDangerous, - }; -}; - const appStateController = { store: { getState: () => ({ @@ -42,13 +37,18 @@ const appStateController = { }, }; -const handler = createRPCMethodTrackingMiddleware({ - trackEvent, - getMetricsState, - rateLimitSeconds: 1, - securityProviderRequest, - appStateController, -}); +const createHandler = (opts) => + createRPCMethodTrackingMiddleware({ + trackEvent, + getMetricsState, + rateLimitTimeout: 1000, + rateLimitSamplePercent: 0.1, + globalRateLimitTimeout: 0, + globalRateLimitMaxAmount: 0, + appStateController, + isConfirmationRedesignEnabled: () => false, + ...opts, + }); function getNext(timeout = 500) { let deferred; @@ -107,6 +107,7 @@ describe('createRPCMethodTrackingMiddleware', () => { error: null, }; const { executeMiddlewareStack, next } = getNext(); + const handler = createHandler(); handler(req, res, next); await executeMiddlewareStack(); expect(trackEvent).not.toHaveBeenCalled(); @@ -128,6 +129,7 @@ describe('createRPCMethodTrackingMiddleware', () => { error: null, }; const { executeMiddlewareStack, next } = getNext(); + const handler = createHandler(); handler(req, res, next); await executeMiddlewareStack(); expect(trackEvent).not.toHaveBeenCalled(); @@ -154,10 +156,11 @@ describe('createRPCMethodTrackingMiddleware', () => { error: null, }; const { next } = getNext(); + const handler = createHandler(); await handler(req, res, next); expect(trackEvent).toHaveBeenCalledTimes(1); expect(trackEvent.mock.calls[0][0]).toMatchObject({ - category: 'inpage_provider', + category: MetaMetricsEventCategory.InpageProvider, event: MetaMetricsEventName.SignatureRequested, properties: { signature_type: MESSAGE_TYPE.ETH_SIGN, @@ -187,6 +190,7 @@ describe('createRPCMethodTrackingMiddleware', () => { error: null, }; const { next } = getNext(); + const handler = createHandler(); await handler(req, res, next); expect(trackEvent).toHaveBeenCalledTimes(1); /** @@ -197,7 +201,7 @@ describe('createRPCMethodTrackingMiddleware', () => { * */ expect(trackEvent.mock.calls[0][0]).toStrictEqual({ - category: 'inpage_provider', + category: MetaMetricsEventCategory.InpageProvider, event: MetaMetricsEventName.SignatureRequested, properties: { signature_type: MESSAGE_TYPE.ETH_SIGN, @@ -220,11 +224,12 @@ describe('createRPCMethodTrackingMiddleware', () => { error: null, }; const { next, executeMiddlewareStack } = getNext(); + const handler = createHandler(); await handler(req, res, next); await executeMiddlewareStack(); expect(trackEvent).toHaveBeenCalledTimes(2); expect(trackEvent.mock.calls[1][0]).toMatchObject({ - category: 'inpage_provider', + category: MetaMetricsEventCategory.InpageProvider, event: MetaMetricsEventName.SignatureApproved, properties: { signature_type: MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4, @@ -243,11 +248,12 @@ describe('createRPCMethodTrackingMiddleware', () => { error: { code: errorCodes.provider.userRejectedRequest }, }; const { next, executeMiddlewareStack } = getNext(); + const handler = createHandler(); await handler(req, res, next); await executeMiddlewareStack(); expect(trackEvent).toHaveBeenCalledTimes(2); expect(trackEvent.mock.calls[1][0]).toMatchObject({ - category: 'inpage_provider', + category: MetaMetricsEventCategory.InpageProvider, event: MetaMetricsEventName.SignatureRejected, properties: { signature_type: MESSAGE_TYPE.PERSONAL_SIGN, @@ -264,11 +270,12 @@ describe('createRPCMethodTrackingMiddleware', () => { const res = {}; const { next, executeMiddlewareStack } = getNext(); + const handler = createHandler(); await handler(req, res, next); await executeMiddlewareStack(); expect(trackEvent).toHaveBeenCalledTimes(2); expect(trackEvent.mock.calls[1][0]).toMatchObject({ - category: 'inpage_provider', + category: MetaMetricsEventCategory.InpageProvider, event: MetaMetricsEventName.PermissionsApproved, properties: { method: MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS }, referrer: { url: 'some.dapp' }, @@ -285,36 +292,189 @@ describe('createRPCMethodTrackingMiddleware', () => { error: null, }; const { next, executeMiddlewareStack } = getNext(); + const handler = createHandler(); handler(req, res, next); expect(trackEvent).not.toHaveBeenCalled(); executeMiddlewareStack(); }); - it(`should only track events when not rate limited`, async () => { + describe('events rated limited by timeout', () => { + it.each([ + ['wallet_requestPermissions', 2], + ['eth_requestAccounts', 2], + ])( + `should only track '%s' events while the timeout rate limit is not active`, + async (method, eventsTrackedPerRequest) => { + const req = { + method, + origin: 'some.dapp', + }; + + const res = { + error: null, + }; + + const handler = createHandler(); + + let callCount = 0; + while (callCount < 3) { + callCount += 1; + const { next, executeMiddlewareStack } = getNext(); + handler(req, res, next); + await executeMiddlewareStack(); + if (callCount !== 3) { + await waitForSeconds(0.6); + } + } + + const expectedNumberOfCalls = 2 * eventsTrackedPerRequest; + expect(trackEvent).toHaveBeenCalledTimes(expectedNumberOfCalls); + trackEvent.mock.calls.forEach((call) => { + expect(call[0].properties.method).toBe(method); + }); + }, + ); + }); + + describe('events rated limited by random', () => { + beforeEach(() => { + jest + .spyOn(Math, 'random') + .mockReturnValueOnce(0) // not rate limited + .mockReturnValueOnce(0.09) // not rate limited + .mockReturnValueOnce(0.1) // rate limited + .mockReturnValueOnce(0.11) // rate limited + .mockReturnValueOnce(1); // rate limited + }); + afterEach(() => { + jest.spyOn(Math, 'random').mockRestore(); + }); + it.each([ + ['any_method_without_rate_limit_type_set', 1], + ['eth_getBalance', 1], + ])( + `should only track a random percentage of '%s' events`, + async (method, eventsTrackedPerRequest) => { + const req = { + method, + origin: 'some.dapp', + }; + + const res = { + error: null, + }; + + const handler = createHandler(); + + let callCount = 0; + while (callCount < 5) { + callCount += 1; + const { next, executeMiddlewareStack } = getNext(); + handler(req, res, next); + await executeMiddlewareStack(); + } + + const expectedNumberOfCalls = 2 * eventsTrackedPerRequest; + expect(trackEvent).toHaveBeenCalledTimes(expectedNumberOfCalls); + trackEvent.mock.calls.forEach((call) => { + expect(call[0].properties.method).toBe(method); + }); + }, + ); + }); + + describe('events rated globally rate limited', () => { + it('should only track events if the global rate limit has not been hit', async () => { + const req = { + method: 'some_method_rate_limited_by_sample', + origin: 'some.dapp', + }; + + const res = { + error: null, + }; + + const handler = createHandler({ + rateLimitSamplePercent: 1, // track every event for this spec + globalRateLimitTimeout: 1000, + globalRateLimitMaxAmount: 3, + }); + + let callCount = 0; + while (callCount < 4) { + callCount += 1; + const { next, executeMiddlewareStack } = getNext(); + handler(req, res, next); + await executeMiddlewareStack(); + if (callCount !== 4) { + await waitForSeconds(0.6); + } + } + + expect(trackEvent).toHaveBeenCalledTimes(3); + trackEvent.mock.calls.forEach((call) => { + expect(call[0].properties.method).toBe( + 'some_method_rate_limited_by_sample', + ); + }); + }); + }); + + it('should track Confirmation Redesign through ui_customizations prop if enabled', async () => { const req = { - method: 'eth_chainId', + method: MESSAGE_TYPE.PERSONAL_SIGN, origin: 'some.dapp', }; - const res = { error: null, }; + const { next, executeMiddlewareStack } = getNext(); + const handler = createHandler({ + isConfirmationRedesignEnabled: () => true, + }); - let callCount = 0; + await handler(req, res, next); + await executeMiddlewareStack(); - while (callCount < 3) { - callCount += 1; - const { next, executeMiddlewareStack } = getNext(); - handler(req, res, next); - await executeMiddlewareStack(); - if (callCount !== 3) { - await waitForSeconds(0.6); - } - } + expect(trackEvent).toHaveBeenCalledTimes(2); + + expect(trackEvent.mock.calls[1][0]).toMatchObject({ + category: MetaMetricsEventCategory.InpageProvider, + event: MetaMetricsEventName.SignatureApproved, + properties: { + signature_type: MESSAGE_TYPE.PERSONAL_SIGN, + ui_customizations: [ + MetaMetricsEventUiCustomization.RedesignedConfirmation, + ], + }, + referrer: { url: 'some.dapp' }, + }); + }); + + it('should not track Confirmation Redesign through ui_customizations prop if not enabled', async () => { + const req = { + method: MESSAGE_TYPE.PERSONAL_SIGN, + origin: 'some.dapp', + }; + const res = { + error: null, + }; + const { next, executeMiddlewareStack } = getNext(); + const handler = createHandler(); + + await handler(req, res, next); + await executeMiddlewareStack(); expect(trackEvent).toHaveBeenCalledTimes(2); - expect(trackEvent.mock.calls[0][0].properties.method).toBe('eth_chainId'); - expect(trackEvent.mock.calls[1][0].properties.method).toBe('eth_chainId'); + + expect(trackEvent.mock.calls[1][0]).toMatchObject({ + category: MetaMetricsEventCategory.InpageProvider, + event: MetaMetricsEventName.SignatureApproved, + properties: { + signature_type: MESSAGE_TYPE.PERSONAL_SIGN, + }, + referrer: { url: 'some.dapp' }, + }); }); it('should track Sign-in With Ethereum (SIWE) message if detected', async () => { @@ -326,6 +486,7 @@ describe('createRPCMethodTrackingMiddleware', () => { error: null, }; const { next, executeMiddlewareStack } = getNext(); + const handler = createHandler(); detectSIWE.mockImplementation(() => { return { isSIWEMessage: true }; @@ -337,7 +498,7 @@ describe('createRPCMethodTrackingMiddleware', () => { expect(trackEvent).toHaveBeenCalledTimes(2); expect(trackEvent.mock.calls[1][0]).toMatchObject({ - category: 'inpage_provider', + category: MetaMetricsEventCategory.InpageProvider, event: MetaMetricsEventName.SignatureApproved, properties: { signature_type: MESSAGE_TYPE.PERSONAL_SIGN, @@ -347,6 +508,35 @@ describe('createRPCMethodTrackingMiddleware', () => { }); }); + it('should track typed-sign permit message if detected', async () => { + const req = { + method: MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4, + origin: 'some.dapp', + params: [undefined, permitSignatureMsg.msgParams.data], + }; + const res = { + error: null, + }; + const { next, executeMiddlewareStack } = getNext(); + const handler = createHandler(); + + await handler(req, res, next); + await executeMiddlewareStack(); + + expect(trackEvent).toHaveBeenCalledTimes(2); + + expect(trackEvent.mock.calls[1][0]).toMatchObject({ + category: MetaMetricsEventCategory.InpageProvider, + event: MetaMetricsEventName.SignatureApproved, + properties: { + signature_type: MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4, + ui_customizations: [MetaMetricsEventUiCustomization.Permit], + eip712_primary_type: 'Permit', + }, + referrer: { url: 'some.dapp' }, + }); + }); + describe(`when '${MESSAGE_TYPE.ETH_SIGN}' is disabled in advanced settings`, () => { it(`should track ${MetaMetricsEventName.SignatureFailed} and include error property`, async () => { const mockError = { code: errorCodes.rpc.methodNotFound }; @@ -358,6 +548,7 @@ describe('createRPCMethodTrackingMiddleware', () => { error: mockError, }; const { next, executeMiddlewareStack } = getNext(); + const handler = createHandler(); await handler(req, res, next); await executeMiddlewareStack(); @@ -365,7 +556,7 @@ describe('createRPCMethodTrackingMiddleware', () => { expect(trackEvent).toHaveBeenCalledTimes(2); expect(trackEvent.mock.calls[1][0]).toMatchObject({ - category: 'inpage_provider', + category: MetaMetricsEventCategory.InpageProvider, event: MetaMetricsEventName.SignatureFailed, properties: { signature_type: MESSAGE_TYPE.ETH_SIGN, @@ -386,12 +577,13 @@ describe('createRPCMethodTrackingMiddleware', () => { error: null, }; const { next } = getNext(); + const handler = createHandler(); await handler(req, res, next); expect(trackEvent).toHaveBeenCalledTimes(1); expect(trackEvent.mock.calls[0][0]).toMatchObject({ - category: 'inpage_provider', + category: MetaMetricsEventCategory.InpageProvider, event: MetaMetricsEventName.SignatureRequested, properties: { signature_type: MESSAGE_TYPE.ETH_SIGN, @@ -401,125 +593,75 @@ describe('createRPCMethodTrackingMiddleware', () => { }); }); - describe('when request is flagged as malicious by security provider', () => { - beforeEach(() => { - flagAsDangerous = 1; - }); - - it(`should immediately track a ${MetaMetricsEventName.SignatureRequested} event which is flagged as malicious`, async () => { - const req = { - method: MESSAGE_TYPE.ETH_SIGN, - origin: 'some.dapp', - }; - const res = { - error: null, - }; - const { next } = getNext(); - - await handler(req, res, next); - - expect(trackEvent).toHaveBeenCalledTimes(1); - expect(trackEvent.mock.calls[0][0]).toMatchObject({ - category: 'inpage_provider', - event: MetaMetricsEventName.SignatureRequested, - properties: { - signature_type: MESSAGE_TYPE.ETH_SIGN, - ui_customizations: ['flagged_as_malicious'], + it.each([ + ['no params', 'method_without_transform', {}, undefined], + [ + 'no params', + 'eth_call', + [ + { + accessList: [], + blobVersionedHashes: [], + blobs: [], + to: null, }, - referrer: { url: 'some.dapp' }, - }); - }); - }); - - describe('when request flagged as safety unknown by security provider', () => { - beforeEach(() => { - flagAsDangerous = 2; - }); - - it(`should immediately track a ${MetaMetricsEventName.SignatureRequested} event which is flagged as safety unknown`, async () => { + null, + ], + undefined, + ], + ['no params', 'eth_sandRawTransaction', ['0xdeadbeef'], undefined], + [ + 'no params', + 'eth_sendTransaction', + { + to: '0x1', + from: '0x2', + gas: '0x3', + gasPrice: '0x4', + value: '0x5', + data: '0xdeadbeef', + maxPriorityFeePerGas: '0x6', + maxFeePerGas: '0x7', + }, + undefined, + ], + [ + 'only the type param', + 'wallet_watchAsset', + { + type: 'ERC20', + options: { + address: '0xb60e8dd61c5d32be8058bb8eb970870f07233155', + symbol: 'FOO', + decimals: 18, + image: 'https://foo.io/token-image.svg', + }, + }, + { type: 'ERC20' }, + ], + ])( + `should include %s in the '%s' tracked events params property`, + async (_, method, params, expected) => { const req = { - method: MESSAGE_TYPE.ETH_SIGN, + method, origin: 'some.dapp', + params, }; + const res = { error: null, }; + const { next } = getNext(); + const handler = createHandler({ rateLimitSamplePercent: 1 }); await handler(req, res, next); expect(trackEvent).toHaveBeenCalledTimes(1); - expect(trackEvent.mock.calls[0][0]).toMatchObject({ - category: 'inpage_provider', - event: MetaMetricsEventName.SignatureRequested, - properties: { - signature_type: MESSAGE_TYPE.ETH_SIGN, - ui_customizations: ['flagged_as_safety_unknown'], - }, - referrer: { url: 'some.dapp' }, - }); - }); - }); - - describe('when signature requests are received', () => { - let securityProviderReq, fnHandler; - beforeEach(() => { - securityProviderReq = jest.fn().mockReturnValue(() => - Promise.resolve({ - flagAsDangerous: 0, - }), + expect(trackEvent.mock.calls[0][0].properties.params).toStrictEqual( + expected, ); - - fnHandler = createRPCMethodTrackingMiddleware({ - trackEvent, - getMetricsState, - rateLimitSeconds: 1, - securityProviderRequest: securityProviderReq, - }); - }); - it(`should pass correct data for personal sign`, async () => { - const req = { - method: 'personal_sign', - params: [ - '0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765', - '0x8eeee1781fd885ff5ddef7789486676961873d12', - 'Example password', - ], - jsonrpc: '2.0', - id: 1142196570, - origin: 'https://metamask.github.io', - tabId: 1048582817, - }; - const res = { id: 1142196570, jsonrpc: '2.0' }; - const { next } = getNext(); - - await fnHandler(req, res, next); - - expect(securityProviderReq).toHaveBeenCalledTimes(1); - const call = securityProviderReq.mock.calls[0][0]; - expect(call.msgParams.data).toStrictEqual(req.params[0]); - }); - it(`should pass correct data for typed sign`, async () => { - const req = { - method: 'eth_signTypedData_v4', - params: [ - '0x8eeee1781fd885ff5ddef7789486676961873d12', - '{"domain":{"chainId":"5","name":"Ether Mail","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","version":"1"},"message":{"contents":"Hello, Bob!","from":{"name":"Cow","wallets":["0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826","0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"]},"to":[{"name":"Bob","wallets":["0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB","0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57","0xB0B0b0b0b0b0B000000000000000000000000000"]}]},"primaryType":"Mail","types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Group":[{"name":"name","type":"string"},{"name":"members","type":"Person[]"}],"Mail":[{"name":"from","type":"Person"},{"name":"to","type":"Person[]"},{"name":"contents","type":"string"}],"Person":[{"name":"name","type":"string"},{"name":"wallets","type":"address[]"}]}}', - ], - jsonrpc: '2.0', - id: 1142196571, - origin: 'https://metamask.github.io', - tabId: 1048582817, - }; - const res = { id: 1142196571, jsonrpc: '2.0' }; - const { next } = getNext(); - - await fnHandler(req, res, next); - - expect(securityProviderReq).toHaveBeenCalledTimes(1); - const call = securityProviderReq.mock.calls[0][0]; - expect(call.msgParams.data).toStrictEqual(req.params[1]); - }); - }); + }, + ); }); }); diff --git a/app/scripts/lib/encryptor-factory.test.ts b/app/scripts/lib/encryptor-factory.test.ts new file mode 100644 index 000000000000..5e8b10feb152 --- /dev/null +++ b/app/scripts/lib/encryptor-factory.test.ts @@ -0,0 +1,257 @@ +import * as browserPassworder from '@metamask/browser-passworder'; +import { encryptorFactory } from './encryptor-factory'; + +jest.mock('@metamask/browser-passworder'); + +const mockIterations = 100; +const mockPassword = 'password'; +const mockSalt = 'salt'; +const mockData = 'data'; + +describe('encryptorFactory', () => { + afterEach(async () => { + jest.resetAllMocks(); + }); + + const mockBrowserPassworder = browserPassworder as jest.Mocked< + typeof browserPassworder + >; + + it('should return an object with browser passworder methods', () => { + const encryptor = encryptorFactory(mockIterations); + + [ + 'encrypt', + 'encryptWithDetail', + 'encryptWithKey', + 'decrypt', + 'decryptWithDetail', + 'decryptWithKey', + 'keyFromPassword', + 'importKey', + 'exportKey', + 'generateSalt', + 'isVaultUpdated', + ].forEach((method) => { + expect(encryptor).toHaveProperty(method); + }); + }); + + describe('encrypt', () => { + it('should call browser-passworder.encrypt with the given password, data, and iterations', async () => { + const encryptor = encryptorFactory(mockIterations); + + await encryptor.encrypt(mockPassword, mockData); + + expect(mockBrowserPassworder.encrypt).toHaveBeenCalledWith( + mockPassword, + mockData, + undefined, + undefined, + { + algorithm: 'PBKDF2', + params: { + iterations: mockIterations, + }, + }, + ); + }); + + it('should return the result of browser-passworder.encrypt', async () => { + const encryptor = encryptorFactory(mockIterations); + const mockResult = 'result'; + mockBrowserPassworder.encrypt.mockResolvedValue(mockResult); + + expect(await encryptor.encrypt(mockPassword, mockData)).toBe(mockResult); + }); + }); + + describe('encryptWithDetail', () => { + it('should call browser-passworder.encryptWithDetail with the given password, object, and iterations', async () => { + const encryptor = encryptorFactory(mockIterations); + + await encryptor.encryptWithDetail(mockPassword, { foo: 'bar' }, 'salt'); + + expect(mockBrowserPassworder.encryptWithDetail).toHaveBeenCalledWith( + mockPassword, + { foo: 'bar' }, + 'salt', + { + algorithm: 'PBKDF2', + params: { + iterations: mockIterations, + }, + }, + ); + }); + + it('should return the result of browser-passworder.encryptWithDetail', async () => { + const encryptor = encryptorFactory(mockIterations); + const mockResult = { + vault: 'vault', + exportedKeyString: 'salt', + }; + mockBrowserPassworder.encryptWithDetail.mockResolvedValue(mockResult); + + expect( + await encryptor.encryptWithDetail(mockPassword, { foo: 'bar' }, 'salt'), + ).toBe(mockResult); + }); + }); + + describe('decrypt', () => { + it('should call browser-passworder.decrypt with the given password, data, and iterations', async () => { + const encryptor = encryptorFactory(mockIterations); + + await encryptor.decrypt(mockPassword, mockData); + + expect(mockBrowserPassworder.decrypt).toHaveBeenCalledWith( + mockPassword, + mockData, + ); + }); + + it('should return the result of browser-passworder.decrypt', async () => { + const encryptor = encryptorFactory(mockIterations); + const mockResult = 'result'; + mockBrowserPassworder.decrypt.mockResolvedValue(mockResult); + + expect(await encryptor.decrypt(mockPassword, mockData)).toBe(mockResult); + }); + }); + + describe('decryptWithDetail', () => { + it('should call browser-passworder.decryptWithDetail with the given password and object', async () => { + const encryptor = encryptorFactory(mockIterations); + + await encryptor.decryptWithDetail(mockPassword, mockData); + + expect(mockBrowserPassworder.decryptWithDetail).toHaveBeenCalledWith( + mockPassword, + mockData, + ); + }); + + it('should return the result of browser-passworder.decryptWithDetail', async () => { + const encryptor = encryptorFactory(mockIterations); + const mockResult = { + exportedKeyString: 'key', + vault: 'data', + salt: 'salt', + }; + mockBrowserPassworder.decryptWithDetail.mockResolvedValue(mockResult); + + expect(await encryptor.decryptWithDetail(mockPassword, mockData)).toBe( + mockResult, + ); + }); + }); + + describe('keyFromPassword', () => { + it('should call browser-passworder.keyFromPassword with the given parameters', async () => { + const encryptor = encryptorFactory(mockIterations); + + const keyDerivationOpts = { + algorithm: 'PBKDF2' as const, + params: { + iterations: 1, + }, + }; + + const mockResult = { + key: 'key', + derivationOptions: keyDerivationOpts, + }; + + // @ts-expect-error The key type is a mock type and not valid. + mockBrowserPassworder.keyFromPassword.mockResolvedValue(mockResult); + + expect( + await encryptor.keyFromPassword( + mockPassword, + mockSalt, + true, + keyDerivationOpts, + ), + ).toBe(mockResult); + + expect(mockBrowserPassworder.keyFromPassword).toHaveBeenCalledWith( + mockPassword, + mockSalt, + true, + { + algorithm: 'PBKDF2', + params: { + iterations: 1, + }, + }, + ); + }); + + it('should call browser-passworder.keyFromPassword with overriden opts', async () => { + const encryptor = encryptorFactory(mockIterations); + + const mockResult = { + key: 'key', + derivationOptions: { + algorithm: 'PBKDF2', + params: { + iterations: mockIterations, + }, + }, + }; + + // @ts-expect-error The key type is a mock type and not valid. + mockBrowserPassworder.keyFromPassword.mockResolvedValue(mockResult); + + expect( + await encryptor.keyFromPassword( + mockPassword, + mockSalt, + true, + undefined, + ), + ).toBe(mockResult); + + expect(mockBrowserPassworder.keyFromPassword).toHaveBeenCalledWith( + mockPassword, + mockSalt, + true, + { + algorithm: 'PBKDF2', + params: { + iterations: mockIterations, + }, + }, + ); + }); + }); + + describe('isVaultUpdated', () => { + it('should call browser-passworder.isVaultUpdated with the given vault and iterations', () => { + const encryptor = encryptorFactory(mockIterations); + const mockVault = 'vault'; + + encryptor.isVaultUpdated(mockVault); + + expect(mockBrowserPassworder.isVaultUpdated).toHaveBeenCalledWith( + mockVault, + { + algorithm: 'PBKDF2', + params: { + iterations: mockIterations, + }, + }, + ); + }); + + it('should return the result of browser-passworder.isVaultUpdated', () => { + const encryptor = encryptorFactory(mockIterations); + const mockResult = false; + const mockVault = 'vault'; + mockBrowserPassworder.isVaultUpdated.mockReturnValue(mockResult); + + expect(encryptor.isVaultUpdated(mockVault)).toBe(mockResult); + }); + }); +}); diff --git a/app/scripts/lib/encryptor-factory.ts b/app/scripts/lib/encryptor-factory.ts index 68f8ee42307e..9f8ba0a303fb 100644 --- a/app/scripts/lib/encryptor-factory.ts +++ b/app/scripts/lib/encryptor-factory.ts @@ -8,7 +8,10 @@ import { isVaultUpdated, keyFromPassword, importKey, + exportKey, + generateSalt, EncryptionKey, + KeyDerivationOptions, } from '@metamask/browser-passworder'; /** @@ -50,6 +53,36 @@ const encryptWithDetailFactory = }, }); +/** + * A factory function for the keyFromPassword method of the browser-passworder library, + * that generates a key from a password and a salt. + * + * This factory function overrides the default key derivation options with the specified + * number of iterations, unless existing key derivation options are passed in. + * + * @param iterations - The number of iterations to use for the PBKDF2 algorithm. + * @returns A function that generates a key with a potentially overriden number of iterations. + */ +const keyFromPasswordFactory = + (iterations: number) => + async ( + password: string, + salt: string, + exportable?: boolean, + opts?: KeyDerivationOptions, + ) => + keyFromPassword( + password, + salt, + exportable, + opts ?? { + algorithm: 'PBKDF2', + params: { + iterations, + }, + }, + ); + /** * A factory function for the isVaultUpdated method of the browser-passworder library, * that checks if the given vault was encrypted with the given number of iterations. @@ -57,7 +90,7 @@ const encryptWithDetailFactory = * @param iterations - The number of iterations to use for the PBKDF2 algorithm. * @returns A function that checks if the vault was encrypted with the given number of iterations. */ -const isVaultUpdatedFactory = (iterations: number) => async (vault: string) => +const isVaultUpdatedFactory = (iterations: number) => (vault: string) => isVaultUpdated(vault, { algorithm: 'PBKDF2', params: { @@ -81,7 +114,9 @@ export const encryptorFactory = (iterations: number) => ({ decrypt, decryptWithKey, decryptWithDetail, - keyFromPassword, + keyFromPassword: keyFromPasswordFactory(iterations), isVaultUpdated: isVaultUpdatedFactory(iterations), importKey, + exportKey, + generateSalt, }); diff --git a/app/scripts/lib/multichain/address.test.ts b/app/scripts/lib/multichain/address.test.ts new file mode 100644 index 000000000000..61dbed67629f --- /dev/null +++ b/app/scripts/lib/multichain/address.test.ts @@ -0,0 +1,96 @@ +import { + isEthAddress, + normalizeAddress, + normalizeSafeAddress, +} from './address'; + +type TestAddress = { + address: string; + normalizedAddress: string; + checksumAddress: string; +}; + +const ETH_ADDRESSES = [ + // Lower-case address + { + address: '0x6431726eee67570bf6f0cf892ae0a3988f03903f', + normalizedAddress: '0x6431726eee67570bf6f0cf892ae0a3988f03903f', + checksumAddress: '0x6431726EEE67570BF6f0Cf892aE0a3988F03903F', + }, + // Checksum address + { + address: '0x6431726EEE67570BF6f0Cf892aE0a3988F03903F', + normalizedAddress: '0x6431726eee67570bf6f0cf892ae0a3988f03903f', + checksumAddress: '0x6431726EEE67570BF6f0Cf892aE0a3988F03903F', + }, +]; + +const NON_EVM_ADDRESSES = [ + { + address: '0xdeadbeef', + }, + { + address: 'bc1ql49ydapnjafl5t2cp9zqpjwe6pdgmxy98859v2', + }, +]; + +describe('address', () => { + describe('isEthAddress', () => { + // @ts-expect-error This is missing from the Mocha type definitions + it.each(ETH_ADDRESSES)( + 'returns true if address is an ethereum address: $address', + ({ address }: TestAddress) => { + expect(isEthAddress(address)).toBe(true); + expect(isEthAddress(address.toLowerCase())).toBe(true); + }, + ); + + // @ts-expect-error This is missing from the Mocha type definitions + it.each(NON_EVM_ADDRESSES)( + 'returns false if address is not an ethereum address: $address', + ({ address }: TestAddress) => { + expect(isEthAddress(address)).toBe(false); + }, + ); + }); + + describe('normalizeAddress', () => { + // @ts-expect-error This is missing from the Mocha type definitions + it.each(ETH_ADDRESSES)( + 'normalizes address: $address', + ({ address, normalizedAddress }: TestAddress) => { + expect(normalizeAddress(address)).toBe(normalizedAddress); + expect(normalizeAddress(address.toLowerCase())).toBe(normalizedAddress); + }, + ); + + // @ts-expect-error This is missing from the Mocha type definitions + it.each(NON_EVM_ADDRESSES)( + 'returns the original address if its a non-EVM address', + ({ address }: TestAddress) => { + expect(normalizeAddress(address)).toBe(address); + }, + ); + }); + + describe('normalizeSafeAddress', () => { + // @ts-expect-error This is missing from the Mocha type definitions + it.each(ETH_ADDRESSES)( + 'normalizes address to its "safe" form: $address to: $checksumAddress', + ({ address, checksumAddress }: TestAddress) => { + expect(normalizeSafeAddress(address)).toBe(checksumAddress); + expect(normalizeSafeAddress(address.toLowerCase())).toBe( + checksumAddress, + ); + }, + ); + + // @ts-expect-error This is missing from the Mocha type definitions + it.each(NON_EVM_ADDRESSES)( + 'returns the original address if its a non-EVM address', + ({ address }: TestAddress) => { + expect(normalizeSafeAddress(address)).toBe(address); + }, + ); + }); +}); diff --git a/app/scripts/lib/multichain/address.ts b/app/scripts/lib/multichain/address.ts new file mode 100644 index 000000000000..13032dc340c0 --- /dev/null +++ b/app/scripts/lib/multichain/address.ts @@ -0,0 +1,40 @@ +import { Hex, isValidHexAddress } from '@metamask/utils'; +import { normalize as normalizeEthAddress } from '@metamask/eth-sig-util'; +import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils'; + +/** + * Checks if an address is an ethereum one. + * + * @param address - An address. + * @returns True if the address is an ethereum one, false otherwise. + */ +export function isEthAddress(address: string): boolean { + return isValidHexAddress(address as Hex); +} + +/** + * Normalize an address. The address might be returned as-is, if there's no normalizer available. + * + * @param address - An address to normalize. + * @returns The normalized address. + */ +export function normalizeAddress(address: string): string { + // NOTE: We assume that the overhead over checking the address format + // at runtime is small + return isEthAddress(address) + ? (normalizeEthAddress(address) as string) + : address; +} + +/** + * Normalize an address to a "safer" representation. The address might be returned as-is, if + * there's no normalizer available. + * + * @param address - An address to normalize. + * @returns The "safer" normalized address. + */ +export function normalizeSafeAddress(address: string): string { + // NOTE: We assume that the overhead over checking the address format + // at runtime is small + return isEthAddress(address) ? toChecksumHexAddress(address) : address; +} diff --git a/app/scripts/lib/notification-manager.js b/app/scripts/lib/notification-manager.js index 225d2f3c5ef5..4fe538188ba3 100644 --- a/app/scripts/lib/notification-manager.js +++ b/app/scripts/lib/notification-manager.js @@ -1,8 +1,9 @@ import EventEmitter from '@metamask/safe-event-emitter'; import ExtensionPlatform from '../platforms/extension'; - -const NOTIFICATION_HEIGHT = 620; -const NOTIFICATION_WIDTH = 360; +import { + NOTIFICATION_HEIGHT, + NOTIFICATION_WIDTH, +} from '../../../shared/constants/notifications'; export const NOTIFICATION_MANAGER_EVENTS = { POPUP_CLOSED: 'onPopupClosed', diff --git a/app/scripts/lib/offscreen-bridge/lattice-offscreen-keyring.ts b/app/scripts/lib/offscreen-bridge/lattice-offscreen-keyring.ts index c690c1004382..27993e04d03c 100644 --- a/app/scripts/lib/offscreen-bridge/lattice-offscreen-keyring.ts +++ b/app/scripts/lib/offscreen-bridge/lattice-offscreen-keyring.ts @@ -61,6 +61,8 @@ class LatticeKeyringOffscreen extends LatticeKeyring { }); return creds; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (err: any) { throw new Error(err); } diff --git a/app/scripts/lib/offscreen-bridge/ledger-offscreen-bridge.ts b/app/scripts/lib/offscreen-bridge/ledger-offscreen-bridge.ts index fd622fac3b8a..e17178a76b25 100644 --- a/app/scripts/lib/offscreen-bridge/ledger-offscreen-bridge.ts +++ b/app/scripts/lib/offscreen-bridge/ledger-offscreen-bridge.ts @@ -131,7 +131,7 @@ export class LedgerOffscreenBridge implements LedgerBridge { chrome.runtime.sendMessage( { target: OffscreenCommunicationTarget.ledgerOffscreen, - action: LedgerAction.signMessage, + action: LedgerAction.signPersonalMessage, params, }, (response) => { diff --git a/app/scripts/lib/ppom/indexed-db-backend.ts b/app/scripts/lib/ppom/indexed-db-backend.ts index 41c5af2629d1..8fbf63c1aced 100644 --- a/app/scripts/lib/ppom/indexed-db-backend.ts +++ b/app/scripts/lib/ppom/indexed-db-backend.ts @@ -38,6 +38,8 @@ export class IndexedDBPPOMStorage implements StorageBackend { reject( new Error( `Failed to open database ${this.storeName}: ${ + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any (event.target as any)?.error }`, ), @@ -65,8 +67,12 @@ export class IndexedDBPPOMStorage implements StorageBackend { private async objectStoreAction( method: 'get' | 'delete' | 'put' | 'getAllKeys', + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any args?: any, mode: IDBTransactionMode = 'readonly', + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any ): Promise { return new Promise((resolve, reject) => { this.#getObjectStore(mode) @@ -81,6 +87,8 @@ export class IndexedDBPPOMStorage implements StorageBackend { reject( new Error( `Error in indexDB operation ${method}: ${ + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any (event.target as any)?.error }`, ), @@ -95,6 +103,8 @@ export class IndexedDBPPOMStorage implements StorageBackend { async read(key: StorageKey, checksum: string): Promise { const event = await this.objectStoreAction('get', [key.name, key.chainId]); + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const data = (event.target as any)?.result?.data; await validateChecksum(key, data, checksum); return data; @@ -119,6 +129,8 @@ export class IndexedDBPPOMStorage implements StorageBackend { async dir(): Promise { const event = await this.objectStoreAction('getAllKeys'); + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any return (event.target as any)?.result.map(([name, chainId]: string[]) => ({ name, chainId, diff --git a/app/scripts/lib/ppom/ppom-middleware.test.ts b/app/scripts/lib/ppom/ppom-middleware.test.ts index ff21e4502806..354b2a8e4408 100644 --- a/app/scripts/lib/ppom/ppom-middleware.test.ts +++ b/app/scripts/lib/ppom/ppom-middleware.test.ts @@ -1,29 +1,50 @@ +import { + type Hex, + JsonRpcRequestStruct, + JsonRpcResponseStruct, +} from '@metamask/utils'; import { CHAIN_IDS } from '../../../../shared/constants/network'; + import { BlockaidReason, BlockaidResultType, } from '../../../../shared/constants/security-provider'; +import { flushPromises } from '../../../../test/lib/timer-helpers'; import { createPPOMMiddleware } from './ppom-middleware'; +import { + generateSecurityAlertId, + handlePPOMError, + validateRequestWithPPOM, +} from './ppom-util'; +import { SecurityAlertResponse } from './types'; -Object.defineProperty(globalThis, 'fetch', { - writable: true, - value: () => undefined, -}); +jest.mock('./ppom-util'); -Object.defineProperty(globalThis, 'performance', { - writable: true, - value: () => undefined, -}); +const SECURITY_ALERT_ID_MOCK = '123'; -const createMiddleWare = ( - usePPOM?: any, - securityAlertsEnabled?: boolean, - chainId?: string, +const SECURITY_ALERT_RESPONSE_MOCK: SecurityAlertResponse = { + securityAlertId: SECURITY_ALERT_ID_MOCK, + result_type: BlockaidResultType.Malicious, + reason: BlockaidReason.permitFarming, +}; + +const createMiddleware = ( + options: { + chainId?: Hex; + error?: Error; + securityAlertsEnabled?: boolean; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + updateSecurityAlertResponse?: any; + } = { + updateSecurityAlertResponse: () => undefined, + }, ) => { - const usePPOMMock = jest.fn(); - const ppomController = { - usePPOM: usePPOM || usePPOMMock, - }; + const { chainId, error, securityAlertsEnabled, updateSecurityAlertResponse } = + options; + + const ppomController = {}; + const preferenceController = { store: { getState: () => ({ @@ -32,147 +53,191 @@ const createMiddleWare = ( }), }, }; + + if (error) { + preferenceController.store.getState = () => { + throw error; + }; + } + const networkController = { state: { providerConfig: { chainId: chainId || CHAIN_IDS.MAINNET } }, }; + const appStateController = { addSignatureSecurityAlertResponse: () => undefined, }; return createPPOMMiddleware( + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any ppomController as any, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any preferenceController as any, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any networkController as any, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any appStateController as any, - () => undefined, + updateSecurityAlertResponse, ); }; describe('PPOMMiddleware', () => { - it('should call ppomController.usePPOM for requests of type confirmation', async () => { - const usePPOMMock = jest.fn(); - const middlewareFunction = createMiddleWare(usePPOMMock); - await middlewareFunction( - { method: 'eth_sendTransaction' }, - undefined, - () => undefined, - ); - expect(usePPOMMock).toHaveBeenCalledTimes(1); + const validateRequestWithPPOMMock = jest.mocked(validateRequestWithPPOM); + const generateSecurityAlertIdMock = jest.mocked(generateSecurityAlertId); + const handlePPOMErrorMock = jest.mocked(handlePPOMError); + + beforeEach(() => { + jest.resetAllMocks(); + + validateRequestWithPPOMMock.mockResolvedValue(SECURITY_ALERT_RESPONSE_MOCK); + generateSecurityAlertIdMock.mockReturnValue(SECURITY_ALERT_ID_MOCK); + handlePPOMErrorMock.mockReturnValue(SECURITY_ALERT_RESPONSE_MOCK); }); - it('should add validation response on confirmation requests', async () => { - const usePPOM = async () => Promise.resolve('VALIDATION_RESULT'); - const middlewareFunction = createMiddleWare(usePPOM); + it('updates alert response after validating request', async () => { + const updateSecurityAlertResponse = jest.fn(); + + const middlewareFunction = createMiddleware({ + updateSecurityAlertResponse, + }); + const req = { + ...JsonRpcRequestStruct, method: 'eth_sendTransaction', securityAlertResponse: undefined, }; - await middlewareFunction(req, undefined, () => undefined); - expect(req.securityAlertResponse).toBeDefined(); + + await middlewareFunction( + req, + { ...JsonRpcResponseStruct }, + () => undefined, + ); + + await flushPromises(); + + expect(updateSecurityAlertResponse).toHaveBeenCalledTimes(1); + expect(updateSecurityAlertResponse).toHaveBeenCalledWith( + req.method, + SECURITY_ALERT_ID_MOCK, + SECURITY_ALERT_RESPONSE_MOCK, + ); }); - it('should not do validation if user has not enabled preference', async () => { - const usePPOM = async () => Promise.resolve('VALIDATION_RESULT'); - const middlewareFunction = createMiddleWare(usePPOM, false); + it('adds loading response to confirmation requests while validation is in progress', async () => { + const middlewareFunction = createMiddleware(); + const req = { + ...JsonRpcRequestStruct, method: 'eth_sendTransaction', securityAlertResponse: undefined, }; - await middlewareFunction(req, undefined, () => undefined); - expect(req.securityAlertResponse).toBeUndefined(); + + await middlewareFunction( + req, + { ...JsonRpcResponseStruct }, + () => undefined, + ); + + expect(req.securityAlertResponse.reason).toBe(BlockaidReason.inProgress); + expect(req.securityAlertResponse.result_type).toBe( + BlockaidResultType.Loading, + ); }); - it('should not do validation if user is not on mainnet', async () => { - const usePPOM = async () => Promise.resolve('VALIDATION_RESULT'); - const middlewareFunction = createMiddleWare(usePPOM, false, '0x2'); + it('does not do validation if the user has not enabled the preference', async () => { + const middlewareFunction = createMiddleware({ + securityAlertsEnabled: false, + }); + const req = { + ...JsonRpcRequestStruct, method: 'eth_sendTransaction', securityAlertResponse: undefined, }; + await middlewareFunction(req, undefined, () => undefined); + expect(req.securityAlertResponse).toBeUndefined(); + expect(validateRequestWithPPOM).not.toHaveBeenCalled(); }); - it('should set error type in response if usePPOM throw error', async () => { - const usePPOM = async () => { - throw new Error('some error'); - }; - const middlewareFunction = createMiddleWare({ usePPOM }); + it('does not do validation if user is not on a supported network', async () => { + const middlewareFunction = createMiddleware({ + chainId: '0x2', + }); + const req = { + ...JsonRpcRequestStruct, method: 'eth_sendTransaction', securityAlertResponse: undefined, }; - await middlewareFunction(req, undefined, () => undefined); - expect((req.securityAlertResponse as any)?.result_type).toBe( - BlockaidResultType.Errored, - ); - expect((req.securityAlertResponse as any)?.reason).toBe( - BlockaidReason.errored, + + await middlewareFunction( + req, + { ...JsonRpcResponseStruct }, + () => undefined, ); + + expect(req.securityAlertResponse).toBeUndefined(); + expect(validateRequestWithPPOM).not.toHaveBeenCalled(); }); - it('should call next method when ppomController.usePPOM completes', async () => { - const ppom = { - validateJsonRpc: () => undefined, - }; - const usePPOM = async (callback: any) => { - callback(ppom); + it('does not do validation when request is not for confirmation method', async () => { + const middlewareFunction = createMiddleware(); + + const req = { + ...JsonRpcRequestStruct, + method: 'eth_someRequest', + securityAlertResponse: undefined, }; - const middlewareFunction = createMiddleWare(usePPOM); - const nextMock = jest.fn(); + await middlewareFunction( - { method: 'eth_sendTransaction' }, - undefined, - nextMock, + req, + { ...JsonRpcResponseStruct }, + () => undefined, ); - expect(nextMock).toHaveBeenCalledTimes(1); + + expect(req.securityAlertResponse).toBeUndefined(); + expect(validateRequestWithPPOM).not.toHaveBeenCalled(); }); - it('should call next method when ppomController.usePPOM throws error', async () => { - const usePPOM = async (_callback: any) => { - throw Error('Some error'); - }; - const middlewareFunction = createMiddleWare(usePPOM); + it('calls next method', async () => { + const middlewareFunction = createMiddleware(); const nextMock = jest.fn(); + await middlewareFunction( - { method: 'eth_sendTransaction' }, - undefined, + { ...JsonRpcRequestStruct, method: 'eth_sendTransaction' }, + { ...JsonRpcResponseStruct }, nextMock, ); + expect(nextMock).toHaveBeenCalledTimes(1); }); - it('should call ppom.validateJsonRpc when invoked', async () => { - const validateMock = jest.fn(); - const ppom = { - validateJsonRpc: validateMock, - }; - const usePPOM = async (callback: any) => { - callback(ppom); - }; - const middlewareFunction = createMiddleWare(usePPOM); - await middlewareFunction( - { method: 'eth_sendTransaction' }, - undefined, - () => undefined, - ); - expect(validateMock).toHaveBeenCalledTimes(1); - }); + it('handles error if middleware throws', async () => { + const error = new Error('Test Error Message'); + error.name = 'TestName'; - it('should not call ppom.validateJsonRpc when request is not for confirmation method', async () => { - const validateMock = jest.fn(); - const ppom = { - validateJsonRpc: validateMock, - }; - const usePPOM = async (callback: any) => { - callback(ppom); + const nextMock = jest.fn(); + + const middlewareFunction = createMiddleware({ error }); + + const req = { + ...JsonRpcRequestStruct, + method: 'eth_sendTransaction', + securityAlertResponse: undefined, }; - const middlewareFunction = createMiddleWare(usePPOM); - await middlewareFunction( - { method: 'eth_someRequest' }, - undefined, - () => undefined, + + await middlewareFunction(req, { ...JsonRpcResponseStruct }, nextMock); + + expect(req.securityAlertResponse).toStrictEqual( + SECURITY_ALERT_RESPONSE_MOCK, ); - expect(validateMock).toHaveBeenCalledTimes(0); + + expect(nextMock).toHaveBeenCalledTimes(1); }); }); diff --git a/app/scripts/lib/ppom/ppom-middleware.ts b/app/scripts/lib/ppom/ppom-middleware.ts index aa9682657436..0bdd46edba3f 100644 --- a/app/scripts/lib/ppom/ppom-middleware.ts +++ b/app/scripts/lib/ppom/ppom-middleware.ts @@ -1,18 +1,25 @@ -import { PPOM } from '@blockaid/ppom_release'; import { PPOMController } from '@metamask/ppom-validator'; import { NetworkController } from '@metamask/network-controller'; -import { v4 as uuid } from 'uuid'; - import { - BlockaidReason, - BlockaidResultType, -} from '../../../../shared/constants/security-provider'; -import { CHAIN_IDS } from '../../../../shared/constants/network'; + Json, + JsonRpcParams, + JsonRpcRequest, + JsonRpcResponse, +} from '@metamask/utils'; + import { SIGNING_METHODS } from '../../../../shared/constants/transaction'; import { PreferencesController } from '../../controllers/preferences'; -import { SecurityAlertResponse } from '../transaction/util'; - -const { sentry } = global as any; +import { AppStateController } from '../../controllers/app-state'; +import { + LOADING_SECURITY_ALERT_RESPONSE, + SECURITY_PROVIDER_SUPPORTED_CHAIN_IDS, +} from '../../../../shared/constants/security-provider'; +import { + generateSecurityAlertId, + handlePPOMError, + validateRequestWithPPOM, +} from './ppom-util'; +import { SecurityAlertResponse } from './types'; const CONFIRMATION_METHODS = Object.freeze([ 'eth_sendRawTransaction', @@ -20,18 +27,6 @@ const CONFIRMATION_METHODS = Object.freeze([ ...SIGNING_METHODS, ]); -export const SUPPORTED_CHAIN_IDS: string[] = [ - CHAIN_IDS.ARBITRUM, - CHAIN_IDS.AVALANCHE, - CHAIN_IDS.BASE, - CHAIN_IDS.BSC, - CHAIN_IDS.LINEA_MAINNET, - CHAIN_IDS.MAINNET, - CHAIN_IDS.OPTIMISM, - CHAIN_IDS.POLYGON, - CHAIN_IDS.SEPOLIA, -]; - /** * Middleware function that handles JSON RPC requests. * This function will be called for every JSON RPC request. @@ -45,86 +40,73 @@ export const SUPPORTED_CHAIN_IDS: string[] = [ * @param preferencesController - Instance of PreferenceController. * @param networkController - Instance of NetworkController. * @param appStateController - * @param updateSecurityAlertResponseByTxId + * @param updateSecurityAlertResponse * @returns PPOMMiddleware function. */ -export function createPPOMMiddleware( +export function createPPOMMiddleware< + Params extends JsonRpcParams, + Result extends Json, +>( ppomController: PPOMController, preferencesController: PreferencesController, networkController: NetworkController, - appStateController: any, - updateSecurityAlertResponseByTxId: ( - req: any, + appStateController: AppStateController, + updateSecurityAlertResponse: ( + method: string, + signatureAlertId: string, securityAlertResponse: SecurityAlertResponse, ) => void, ) { - return async (req: any, _res: any, next: () => void) => { + return async ( + req: JsonRpcRequest, + _res: JsonRpcResponse, + next: () => void, + ) => { try { const securityAlertsEnabled = preferencesController.store.getState()?.securityAlertsEnabled; + const { chainId } = networkController.state.providerConfig; + if ( - securityAlertsEnabled && - CONFIRMATION_METHODS.includes(req.method) && - SUPPORTED_CHAIN_IDS.includes(chainId) + !securityAlertsEnabled || + !CONFIRMATION_METHODS.includes(req.method) || + !SECURITY_PROVIDER_SUPPORTED_CHAIN_IDS.includes(chainId) ) { - // eslint-disable-next-line require-atomic-updates - const securityAlertId = uuid(); + return; + } - ppomController - .usePPOM(async (ppom: PPOM) => { - try { - const securityAlertResponse = await ppom.validateJsonRpc(req); - securityAlertResponse.securityAlertId = securityAlertId; - return securityAlertResponse; - } catch (error: any) { - sentry?.captureException(error); - const errorObject = error as unknown as Error; - console.error('Error validating JSON RPC using PPOM: ', error); - const securityAlertResponse = { - result_type: BlockaidResultType.Errored, - reason: BlockaidReason.errored, - description: `${errorObject.name}: ${errorObject.message}`, - }; + const securityAlertId = generateSecurityAlertId(); - return securityAlertResponse; - } - }) - .then((securityAlertResponse) => { - updateSecurityAlertResponseByTxId(req, { - ...securityAlertResponse, - securityAlertId, - }); - }); + validateRequestWithPPOM({ + ppomController, + request: req, + securityAlertId, + }).then((securityAlertResponse) => { + updateSecurityAlertResponse( + req.method, + securityAlertId, + securityAlertResponse, + ); + }); - if (SIGNING_METHODS.includes(req.method)) { - req.securityAlertResponse = { - reason: BlockaidResultType.Loading, - result_type: BlockaidReason.inProgress, - securityAlertId, - }; - appStateController.addSignatureSecurityAlertResponse({ - reason: BlockaidResultType.Loading, - result_type: BlockaidReason.inProgress, - securityAlertId, - }); - } else { - req.securityAlertResponse = { - reason: BlockaidResultType.Loading, - result_type: BlockaidReason.inProgress, - securityAlertId, - }; - } - } - } catch (error: any) { - const errorObject = error as unknown as Error; - sentry?.captureException(error); - console.error('Error validating JSON RPC using PPOM: ', error); - req.securityAlertResponse = { - result_type: BlockaidResultType.Errored, - reason: BlockaidReason.errored, - description: `${errorObject.name}: ${errorObject.message}`, + const loadingSecurityAlertResponse: SecurityAlertResponse = { + ...LOADING_SECURITY_ALERT_RESPONSE, + securityAlertId, }; + + if (SIGNING_METHODS.includes(req.method)) { + appStateController.addSignatureSecurityAlertResponse( + loadingSecurityAlertResponse, + ); + } + + req.securityAlertResponse = loadingSecurityAlertResponse; + } catch (error) { + req.securityAlertResponse = handlePPOMError( + error, + 'Error createPPOMMiddleware: ', + ); } finally { next(); } diff --git a/app/scripts/lib/ppom/ppom-util.test.ts b/app/scripts/lib/ppom/ppom-util.test.ts new file mode 100644 index 000000000000..ac16022cee8a --- /dev/null +++ b/app/scripts/lib/ppom/ppom-util.test.ts @@ -0,0 +1,284 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { PPOMController } from '@metamask/ppom-validator'; +import { PPOM } from '@blockaid/ppom_release'; +import { + TransactionController, + TransactionParams, + normalizeTransactionParams, +} from '@metamask/transaction-controller'; +import { SignatureController } from '@metamask/signature-controller'; +import { Message } from '@metamask/message-manager'; +import { + BlockaidReason, + BlockaidResultType, +} from '../../../../shared/constants/security-provider'; +import { AppStateController } from '../../controllers/app-state'; +import { + generateSecurityAlertId, + updateSecurityAlertResponse, + validateRequestWithPPOM, +} from './ppom-util'; +import { SecurityAlertResponse } from './types'; + +jest.mock('@metamask/transaction-controller', () => ({ + ...jest.requireActual('@metamask/transaction-controller'), + normalizeTransactionParams: jest.fn(), +})); + +const SECURITY_ALERT_ID_MOCK = '1234-5678'; +const TRANSACTION_ID_MOCK = '123'; + +const REQUEST_MOCK = { + method: 'eth_signTypedData_v4', + params: [], +}; + +const SECURITY_ALERT_RESPONSE_MOCK: SecurityAlertResponse = { + result_type: 'success', + reason: 'success', +}; + +const TRANSACTION_PARAMS_MOCK_1: TransactionParams = { + to: '0x123', + from: '0x123', + value: '0x123', +}; + +const TRANSACTION_PARAMS_MOCK_2: TransactionParams = { + ...TRANSACTION_PARAMS_MOCK_1, + to: '0x456', +}; + +function createPPOMMock() { + return { + validateJsonRpc: jest.fn(), + } as unknown as jest.Mocked; +} + +function createPPOMControllerMock() { + return { + usePPOM: jest.fn(), + } as unknown as jest.Mocked; +} + +function createErrorMock() { + const error = new Error('Test error message'); + error.name = 'Test Error'; + + return error; +} + +function createAppStateControllerMock() { + return { + addSignatureSecurityAlertResponse: jest.fn(), + } as unknown as jest.Mocked; +} + +function createSignatureControllerMock( + messages: SignatureController['messages'], +) { + return { + messages, + } as unknown as jest.Mocked; +} + +function createTransactionControllerMock( + state: TransactionController['state'], +) { + return { + state, + updateSecurityAlertResponse: jest.fn(), + } as unknown as jest.Mocked; +} + +describe('PPOM Utils', () => { + const normalizeTransactionParamsMock = jest.mocked( + normalizeTransactionParams, + ); + + beforeEach(() => { + jest.resetAllMocks(); + jest.spyOn(console, 'error').mockImplementation(() => undefined); + }); + + describe('validateRequestWithPPOM', () => { + it('returns response from validation with PPOM instance via controller', async () => { + const ppom = createPPOMMock(); + const ppomController = createPPOMControllerMock(); + + ppom.validateJsonRpc.mockResolvedValue(SECURITY_ALERT_RESPONSE_MOCK); + + ppomController.usePPOM.mockImplementation( + (callback) => + // eslint-disable-next-line @typescript-eslint/no-explicit-any + callback(ppom as any) as any, + ); + + const response = await validateRequestWithPPOM({ + ppomController, + request: REQUEST_MOCK, + securityAlertId: SECURITY_ALERT_ID_MOCK, + }); + + expect(response).toStrictEqual({ + ...SECURITY_ALERT_RESPONSE_MOCK, + securityAlertId: SECURITY_ALERT_ID_MOCK, + }); + + expect(ppom.validateJsonRpc).toHaveBeenCalledTimes(1); + expect(ppom.validateJsonRpc).toHaveBeenCalledWith(REQUEST_MOCK); + }); + + it('returns error response if validation with PPOM instance throws', async () => { + const ppom = createPPOMMock(); + const ppomController = createPPOMControllerMock(); + + ppom.validateJsonRpc.mockRejectedValue(createErrorMock()); + + ppomController.usePPOM.mockImplementation( + (callback) => + // eslint-disable-next-line @typescript-eslint/no-explicit-any + callback(ppom as any) as any, + ); + + const response = await validateRequestWithPPOM({ + ppomController, + request: REQUEST_MOCK, + securityAlertId: SECURITY_ALERT_ID_MOCK, + }); + + expect(response).toStrictEqual({ + result_type: BlockaidResultType.Errored, + reason: BlockaidReason.errored, + description: 'Test Error: Test error message', + }); + }); + + it('returns error response if controller throws', async () => { + const ppomController = createPPOMControllerMock(); + + ppomController.usePPOM.mockRejectedValue(createErrorMock()); + + const response = await validateRequestWithPPOM({ + ppomController, + request: REQUEST_MOCK, + securityAlertId: SECURITY_ALERT_ID_MOCK, + }); + + expect(response).toStrictEqual({ + result_type: BlockaidResultType.Errored, + reason: BlockaidReason.errored, + description: 'Test Error: Test error message', + }); + }); + + it('normalizes request if method is eth_sendTransaction', async () => { + const ppom = createPPOMMock(); + const ppomController = createPPOMControllerMock(); + + ppomController.usePPOM.mockImplementation( + (callback) => + // eslint-disable-next-line @typescript-eslint/no-explicit-any + callback(ppom as any) as any, + ); + + normalizeTransactionParamsMock.mockReturnValue(TRANSACTION_PARAMS_MOCK_2); + + const request = { + ...REQUEST_MOCK, + method: 'eth_sendTransaction', + params: [TRANSACTION_PARAMS_MOCK_1], + }; + + await validateRequestWithPPOM({ + ppomController, + request, + securityAlertId: SECURITY_ALERT_ID_MOCK, + }); + + expect(ppom.validateJsonRpc).toHaveBeenCalledTimes(1); + expect(ppom.validateJsonRpc).toHaveBeenCalledWith({ + ...request, + params: [TRANSACTION_PARAMS_MOCK_2], + }); + + expect(normalizeTransactionParamsMock).toHaveBeenCalledTimes(1); + expect(normalizeTransactionParamsMock).toHaveBeenCalledWith( + TRANSACTION_PARAMS_MOCK_1, + ); + }); + }); + + describe('generateSecurityAlertId', () => { + it('returns uuid', () => { + const securityAlertId = generateSecurityAlertId(); + + expect(securityAlertId).toMatch( + /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/u, + ); + }); + }); + + describe('updateSecurityAlertResponse', () => { + it('adds response to app state controller if matching message found', async () => { + const appStateController = createAppStateControllerMock(); + + const signatureController = createSignatureControllerMock({ + '123': { + securityAlertResponse: { + ...SECURITY_ALERT_RESPONSE_MOCK, + securityAlertId: SECURITY_ALERT_ID_MOCK, + }, + } as unknown as Message, + }); + + await updateSecurityAlertResponse({ + appStateController, + method: 'eth_signTypedData_v4', + securityAlertId: SECURITY_ALERT_ID_MOCK, + securityAlertResponse: SECURITY_ALERT_RESPONSE_MOCK, + signatureController, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + transactionController: {} as any, + }); + + expect( + appStateController.addSignatureSecurityAlertResponse, + ).toHaveBeenCalledTimes(1); + + expect( + appStateController.addSignatureSecurityAlertResponse, + ).toHaveBeenCalledWith(SECURITY_ALERT_RESPONSE_MOCK); + }); + + it('adds response to transaction controller if matching transaction found', async () => { + const transactionController = createTransactionControllerMock({ + transactions: [ + { + id: TRANSACTION_ID_MOCK, + securityAlertResponse: { + securityAlertId: SECURITY_ALERT_ID_MOCK, + }, + }, + ], + } as any); + + await updateSecurityAlertResponse({ + appStateController: {} as any, + method: 'eth_sendTransaction', + securityAlertId: SECURITY_ALERT_ID_MOCK, + securityAlertResponse: SECURITY_ALERT_RESPONSE_MOCK, + signatureController: {} as any, + transactionController, + }); + + expect( + transactionController.updateSecurityAlertResponse, + ).toHaveBeenCalledTimes(1); + + expect( + transactionController.updateSecurityAlertResponse, + ).toHaveBeenCalledWith(TRANSACTION_ID_MOCK, SECURITY_ALERT_RESPONSE_MOCK); + }); + }); +}); diff --git a/app/scripts/lib/ppom/ppom-util.ts b/app/scripts/lib/ppom/ppom-util.ts new file mode 100644 index 000000000000..8d64aacd3a91 --- /dev/null +++ b/app/scripts/lib/ppom/ppom-util.ts @@ -0,0 +1,180 @@ +import { PPOMController } from '@metamask/ppom-validator'; +import { + TransactionController, + TransactionParams, + normalizeTransactionParams, +} from '@metamask/transaction-controller'; +import { JsonRpcRequest } from '@metamask/utils'; +import { v4 as uuid } from 'uuid'; +import { PPOM } from '@blockaid/ppom_release'; +import { SignatureController } from '@metamask/signature-controller'; +import { + BlockaidReason, + BlockaidResultType, +} from '../../../../shared/constants/security-provider'; +import { SIGNING_METHODS } from '../../../../shared/constants/transaction'; +import { AppStateController } from '../../controllers/app-state'; +import { SecurityAlertResponse } from './types'; + +const { sentry } = global; + +const METHOD_SEND_TRANSACTION = 'eth_sendTransaction'; + +const SECURITY_ALERT_RESPONSE_ERROR = { + result_type: BlockaidResultType.Errored, + reason: BlockaidReason.errored, +}; + +export async function validateRequestWithPPOM({ + ppomController, + request, + securityAlertId, +}: { + ppomController: PPOMController; + request: JsonRpcRequest; + securityAlertId: string; +}): Promise { + try { + return await ppomController.usePPOM(async (ppom: PPOM) => { + return await usePPOM(request, securityAlertId, ppom); + }); + } catch (error) { + return handlePPOMError(error, 'Error validateRequestWithPPOM#usePPOM: '); + } +} + +export function generateSecurityAlertId(): string { + return uuid(); +} + +export async function updateSecurityAlertResponse({ + appStateController, + method, + securityAlertId, + securityAlertResponse, + signatureController, + transactionController, +}: { + appStateController: AppStateController; + method: string; + securityAlertId: string; + securityAlertResponse: SecurityAlertResponse; + signatureController: SignatureController; + transactionController: TransactionController; +}) { + const isSignatureRequest = SIGNING_METHODS.includes(method); + + const confirmation = await findConfirmationBySecurityAlertId( + securityAlertId, + method, + signatureController, + transactionController, + ); + + if (isSignatureRequest) { + appStateController.addSignatureSecurityAlertResponse(securityAlertResponse); + } else { + transactionController.updateSecurityAlertResponse( + confirmation.id, + securityAlertResponse, + ); + } +} + +export function handlePPOMError( + error: unknown, + logMessage: string, +): SecurityAlertResponse { + const errorData = getErrorData(error); + const description = getErrorMessage(error); + + sentry?.captureException(error); + console.error(logMessage, errorData); + + return { + ...SECURITY_ALERT_RESPONSE_ERROR, + description, + }; +} + +async function usePPOM( + request: JsonRpcRequest, + securityAlertId: string, + ppom: PPOM, +): Promise { + try { + const normalizedRequest = normalizePPOMRequest(request); + const ppomResponse = await ppom.validateJsonRpc(normalizedRequest); + + return { + ...ppomResponse, + securityAlertId, + }; + } catch (error: unknown) { + return handlePPOMError(error, 'Error validating JSON RPC using PPOM: '); + } +} + +function normalizePPOMRequest(request: JsonRpcRequest): JsonRpcRequest { + if (request.method !== METHOD_SEND_TRANSACTION) { + return request; + } + + const transactionParams = (request.params?.[0] || {}) as TransactionParams; + const normalizedParams = normalizeTransactionParams(transactionParams); + + return { + ...request, + params: [normalizedParams], + }; +} + +function getErrorMessage(error: unknown) { + if (error instanceof Error) { + return `${error.name}: ${error.message}`; + } + + return JSON.stringify(error); +} + +function getErrorData(error: unknown) { + if (typeof error === 'object' || typeof error === 'string') { + return error; + } + + return JSON.stringify(error); +} + +async function findConfirmationBySecurityAlertId( + securityAlertId: string, + method: string, + signatureController: SignatureController, + transactionController: TransactionController, +) { + const isSignatureRequest = SIGNING_METHODS.includes(method); + + // eslint-disable-next-line no-constant-condition + while (true) { + let confirmation; + + if (isSignatureRequest) { + confirmation = Object.values(signatureController.messages).find( + (message) => + message.securityAlertResponse?.securityAlertId === securityAlertId, + ); + } else { + confirmation = transactionController.state.transactions.find( + (meta) => + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (meta.securityAlertResponse as any)?.securityAlertId === + securityAlertId, + ); + } + + if (confirmation) { + return confirmation; + } + + await new Promise((resolve) => setTimeout(resolve, 100)); + } +} diff --git a/app/scripts/lib/ppom/types.ts b/app/scripts/lib/ppom/types.ts new file mode 100644 index 000000000000..8dc272edbf24 --- /dev/null +++ b/app/scripts/lib/ppom/types.ts @@ -0,0 +1,8 @@ +export type SecurityAlertResponse = { + description?: string; + features?: string[]; + providerRequestsCount?: Record; + reason: string; + result_type: string; + securityAlertId?: string; +}; diff --git a/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js b/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js index d0653fd6332a..e4b436163fc6 100644 --- a/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js +++ b/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js @@ -1,72 +1,111 @@ import { permissionRpcMethods } from '@metamask/permission-controller'; import { selectHooks } from '@metamask/snaps-rpc-methods'; +import { hasProperty } from '@metamask/utils'; import { ethErrors } from 'eth-rpc-errors'; -import { flatten } from 'lodash'; -import { UNSUPPORTED_RPC_METHODS } from '../../../../shared/constants/network'; -import localHandlers from './handlers'; +import { handlers as localHandlers, legacyHandlers } from './handlers'; const allHandlers = [...localHandlers, ...permissionRpcMethods.handlers]; -const handlerMap = allHandlers.reduce((map, handler) => { - for (const methodName of handler.methodNames) { - map.set(methodName, handler); - } - return map; -}, new Map()); +// The primary home of RPC method implementations in MetaMask. MUST be subsequent +// to our permissioning logic in the JSON-RPC middleware pipeline. +export const createMethodMiddleware = makeMethodMiddlewareMaker(allHandlers); -const expectedHookNames = Array.from( - new Set( - flatten(allHandlers.map(({ hookNames }) => Object.keys(hookNames))), - ).values(), -); +// A collection of RPC method implementations that, for legacy reasons, MAY precede +// our permissioning logic in the JSON-RPC middleware pipeline. +export const createLegacyMethodMiddleware = + makeMethodMiddlewareMaker(legacyHandlers); /** - * Creates a json-rpc-engine middleware of RPC method implementations. - * - * Handlers consume functions that hook into the background, and only depend - * on their signatures, not e.g. controller internals. + * Creates a method middleware factory function given a set of method handlers. * - * @param {Record} hooks - Required "hooks" into our - * controllers. - * @returns {(req: object, res: object, next: Function, end: Function) => void} + * @param {Record} handlers - The RPC method + * handler implementations. + * @returns The method middleware factory function. */ -export function createMethodMiddleware(hooks) { - // Fail immediately if we forgot to provide any expected hooks. - const missingHookNames = expectedHookNames.filter( - (hookName) => !Object.hasOwnProperty.call(hooks, hookName), +function makeMethodMiddlewareMaker(handlers) { + const handlerMap = handlers.reduce((map, handler) => { + for (const methodName of handler.methodNames) { + map[methodName] = handler; + } + return map; + }, {}); + + const expectedHookNames = new Set( + handlers.flatMap(({ hookNames }) => Object.getOwnPropertyNames(hookNames)), ); - if (missingHookNames.length > 0) { - throw new Error( - `Missing expected hooks:\n\n${missingHookNames.join('\n')}\n`, - ); - } - return async function methodMiddleware(req, res, next, end) { - // Reject unsupported methods. - if (UNSUPPORTED_RPC_METHODS.has(req.method)) { - return end(ethErrors.rpc.methodNotSupported()); - } + /** + * Creates a json-rpc-engine middleware of RPC method implementations. + * + * Handlers consume functions that hook into the background, and only depend + * on their signatures, not e.g. controller internals. + * + * @param {Record unknown | Promise>} hooks - Required "hooks" into our + * controllers. + * @returns {import('json-rpc-engine').JsonRpcMiddleware} The method middleware function. + */ + const makeMethodMiddleware = (hooks) => { + assertExpectedHook(hooks, expectedHookNames); - const handler = handlerMap.get(req.method); - if (handler) { - const { implementation, hookNames } = handler; - try { - // Implementations may or may not be async, so we must await them. - return await implementation( - req, - res, - next, - end, - selectHooks(hooks, hookNames), - ); - } catch (error) { - if (process.env.METAMASK_DEBUG) { - console.error(error); + const methodMiddleware = async (req, res, next, end) => { + const handler = handlerMap[req.method]; + if (handler) { + const { implementation, hookNames } = handler; + try { + // Implementations may or may not be async, so we must await them. + return await implementation( + req, + res, + next, + end, + selectHooks(hooks, hookNames), + ); + } catch (error) { + if (process.env.METAMASK_DEBUG) { + console.error(error); + } + return end( + error instanceof Error + ? error + : ethErrors.rpc.internal({ data: error }), + ); } - return end(error); } - } - return next(); + return next(); + }; + + return methodMiddleware; }; + + return makeMethodMiddleware; +} + +/** + * Asserts that the specified hooks object only has all expected hooks and no extraneous ones. + * + * @param {Record} hooks - Required "hooks" into our controllers. + * @param {string[]} expectedHookNames - The expected hook names. + */ +function assertExpectedHook(hooks, expectedHookNames) { + const missingHookNames = []; + expectedHookNames.forEach((hookName) => { + if (!hasProperty(hooks, hookName)) { + missingHookNames.push(hookName); + } + }); + if (missingHookNames.length > 0) { + throw new Error( + `Missing expected hooks:\n\n${missingHookNames.join('\n')}\n`, + ); + } + + const extraneousHookNames = Object.getOwnPropertyNames(hooks).filter( + (hookName) => !expectedHookNames.has(hookName), + ); + if (extraneousHookNames.length > 0) { + throw new Error( + `Received unexpected hooks:\n\n${extraneousHookNames.join('\n')}\n`, + ); + } } diff --git a/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.test.js b/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.test.js new file mode 100644 index 000000000000..46aba9abe746 --- /dev/null +++ b/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.test.js @@ -0,0 +1,179 @@ +import { JsonRpcEngine } from 'json-rpc-engine'; +import { + assertIsJsonRpcFailure, + assertIsJsonRpcSuccess, +} from '@metamask/utils'; +import { createMethodMiddleware, createLegacyMethodMiddleware } from '.'; + +jest.mock('@metamask/permission-controller', () => ({ + permissionRpcMethods: { handlers: [] }, +})); + +jest.mock('./handlers', () => { + const getHandler = () => ({ + implementation: (req, res, _next, end, hooks) => { + if (Array.isArray(req.params)) { + switch (req.params[0]) { + case 1: + res.result = hooks.hook1(); + break; + case 2: + res.result = hooks.hook2(); + break; + case 3: + return end(new Error('test error')); + case 4: + throw new Error('test error'); + case 5: + // eslint-disable-next-line no-throw-literal + throw 'foo'; + default: + throw new Error(`unexpected param "${req.params[0]}"`); + } + } + return end(); + }, + hookNames: { hook1: true, hook2: true }, + methodNames: ['method1', 'method2'], + }); + + return { + handlers: [getHandler()], + legacyHandlers: [getHandler()], + }; +}); + +describe.each([ + ['createMethodMiddleware', createMethodMiddleware], + ['createLegacyMethodMiddleware', createLegacyMethodMiddleware], +])('%s', (_name, createMiddleware) => { + const method1 = 'method1'; + + const getDefaultHooks = () => ({ + hook1: () => 42, + hook2: () => 99, + }); + + it('should return a function', () => { + const middleware = createMiddleware(getDefaultHooks()); + expect(typeof middleware).toBe('function'); + }); + + it('should throw an error if a required hook is missing', () => { + const hooks = { hook1: () => 42 }; + + // @ts-expect-error Intentional destructive testing + expect(() => createMiddleware(hooks)).toThrow('Missing expected hooks'); + }); + + it('should throw an error if an extraneous hook is provided', () => { + const hooks = { + ...getDefaultHooks(), + extraneousHook: () => 100, + }; + + expect(() => createMiddleware(hooks)).toThrow('Received unexpected hooks'); + }); + + it('should call the handler for the matching method (uses hook1)', async () => { + const middleware = createMiddleware(getDefaultHooks()); + const engine = new JsonRpcEngine(); + engine.push(middleware); + + const response = await engine.handle({ + jsonrpc: '2.0', + id: 1, + method: method1, + params: [1], + }); + assertIsJsonRpcSuccess(response); + + expect(response.result).toBe(42); + }); + + it('should call the handler for the matching method (uses hook2)', async () => { + const middleware = createMiddleware(getDefaultHooks()); + const engine = new JsonRpcEngine(); + engine.push(middleware); + + const response = await engine.handle({ + jsonrpc: '2.0', + id: 1, + method: method1, + params: [2], + }); + assertIsJsonRpcSuccess(response); + + expect(response.result).toBe(99); + }); + + it('should not call the handler for a non-matching method', async () => { + const middleware = createMiddleware(getDefaultHooks()); + const engine = new JsonRpcEngine(); + engine.push(middleware); + + const response = await engine.handle({ + jsonrpc: '2.0', + id: 1, + method: 'nonMatchingMethod', + }); + assertIsJsonRpcFailure(response); + + expect(response.error).toMatchObject({ + message: expect.stringMatching( + /Response has no error or result for request/u, + ), + }); + }); + + it('should handle errors returned by the implementation', async () => { + const middleware = createMiddleware(getDefaultHooks()); + const engine = new JsonRpcEngine(); + engine.push(middleware); + + const response = await engine.handle({ + jsonrpc: '2.0', + id: 1, + method: method1, + params: [3], + }); + assertIsJsonRpcFailure(response); + + expect(response.error.message).toBe('test error'); + }); + + it('should handle errors thrown by the implementation', async () => { + const middleware = createMiddleware(getDefaultHooks()); + const engine = new JsonRpcEngine(); + engine.push(middleware); + + const response = await engine.handle({ + jsonrpc: '2.0', + id: 1, + method: method1, + params: [4], + }); + assertIsJsonRpcFailure(response); + + expect(response.error.message).toBe('test error'); + }); + + it('should handle non-errors thrown by the implementation', async () => { + const middleware = createMiddleware(getDefaultHooks()); + const engine = new JsonRpcEngine(); + engine.push(middleware); + + const response = await engine.handle({ + jsonrpc: '2.0', + id: 1, + method: method1, + params: [5], + }); + assertIsJsonRpcFailure(response); + + expect(response.error).toMatchObject({ + message: 'Internal JSON-RPC error.', + data: 'foo', + }); + }); +}); diff --git a/app/scripts/lib/rpc-method-middleware/createUnsupportedMethodMiddleware.test.ts b/app/scripts/lib/rpc-method-middleware/createUnsupportedMethodMiddleware.test.ts new file mode 100644 index 000000000000..e50c86d13268 --- /dev/null +++ b/app/scripts/lib/rpc-method-middleware/createUnsupportedMethodMiddleware.test.ts @@ -0,0 +1,40 @@ +import { jsonrpc2 } from '@metamask/utils'; +import { UNSUPPORTED_RPC_METHODS } from '../../../../shared/constants/network'; +import { createUnsupportedMethodMiddleware } from '.'; + +describe('createUnsupportedMethodMiddleware', () => { + const getMockRequest = (method: string) => ({ + jsonrpc: jsonrpc2, + id: 1, + method, + }); + const getMockResponse = () => ({ jsonrpc: jsonrpc2, id: 'foo' }); + + it('forwards requests whose methods are not on the list of unsupported methods', () => { + const middleware = createUnsupportedMethodMiddleware(); + const nextMock = jest.fn(); + const endMock = jest.fn(); + + middleware(getMockRequest('foo'), getMockResponse(), nextMock, endMock); + + expect(nextMock).toHaveBeenCalledTimes(1); + expect(endMock).not.toHaveBeenCalled(); + }); + + // @ts-expect-error This function is missing from the Mocha type definitions + it.each([...UNSUPPORTED_RPC_METHODS.keys()])( + 'ends requests for methods that are on the list of unsupported methods: %s', + (method: string) => { + const middleware = createUnsupportedMethodMiddleware(); + const nextMock = jest.fn(); + const endMock = jest.fn(); + + const response = getMockResponse(); + middleware(getMockRequest(method), response, nextMock, endMock); + + expect('result' in response).toBe(false); + expect(nextMock).not.toHaveBeenCalled(); + expect(endMock).toHaveBeenCalledTimes(1); + }, + ); +}); diff --git a/app/scripts/lib/rpc-method-middleware/createUnsupportedMethodMiddleware.ts b/app/scripts/lib/rpc-method-middleware/createUnsupportedMethodMiddleware.ts new file mode 100644 index 000000000000..193cc54b5a38 --- /dev/null +++ b/app/scripts/lib/rpc-method-middleware/createUnsupportedMethodMiddleware.ts @@ -0,0 +1,19 @@ +import { ethErrors } from 'eth-rpc-errors'; +import type { JsonRpcMiddleware } from 'json-rpc-engine'; +import { UNSUPPORTED_RPC_METHODS } from '../../../../shared/constants/network'; + +/** + * Creates a middleware that rejects explicitly unsupported RPC methods with the + * appropriate error. + */ +export function createUnsupportedMethodMiddleware(): JsonRpcMiddleware< + unknown, + void +> { + return async function unsupportedMethodMiddleware(req, _res, next, end) { + if ((UNSUPPORTED_RPC_METHODS as Set).has(req.method)) { + return end(ethErrors.rpc.methodNotSupported()); + } + return next(); + }; +} diff --git a/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js b/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js index f4dc00e145d7..c9e39c1b8579 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js @@ -1,34 +1,31 @@ +import { ethErrors } from 'eth-rpc-errors'; import { ApprovalType } from '@metamask/controller-utils'; -import { errorCodes, ethErrors } from 'eth-rpc-errors'; -import { omit } from 'lodash'; -import { - MESSAGE_TYPE, - UNKNOWN_TICKER_SYMBOL, -} from '../../../../../shared/constants/app'; -import { MetaMetricsNetworkEventSource } from '../../../../../shared/constants/metametrics'; + +import { MESSAGE_TYPE } from '../../../../../shared/constants/app'; import { - isPrefixedFormattedHexString, - isSafeChainId, -} from '../../../../../shared/modules/network.utils'; -import { getValidUrl } from '../../util'; + findExistingNetwork, + validateAddEthereumChainParams, + switchChain, +} from './ethereum-chain-utils'; const addEthereumChain = { methodNames: [MESSAGE_TYPE.ADD_ETHEREUM_CHAIN], implementation: addEthereumChainHandler, hookNames: { upsertNetworkConfiguration: true, - getCurrentChainId: true, getCurrentRpcUrl: true, findNetworkConfigurationBy: true, - setNetworkClientIdForDomain: true, setActiveNetwork: true, requestUserApproval: true, startApprovalFlow: true, endApprovalFlow: true, - getProviderConfig: true, - hasPermissions: true, + getCurrentChainIdForDomain: true, + getCaveat: true, + requestPermittedChainsPermission: true, + getChainPermissionsFeatureFlag: true, }, }; + export default addEthereumChain; async function addEthereumChainHandler( @@ -38,287 +35,134 @@ async function addEthereumChainHandler( end, { upsertNetworkConfiguration, - getCurrentChainId, getCurrentRpcUrl, findNetworkConfigurationBy, - setNetworkClientIdForDomain, setActiveNetwork, requestUserApproval, startApprovalFlow, endApprovalFlow, - getProviderConfig, - hasPermissions, + getCurrentChainIdForDomain, + getCaveat, + requestPermittedChainsPermission, + getChainPermissionsFeatureFlag, }, ) { - if (!req.params?.[0] || typeof req.params[0] !== 'object') { - return end( - ethErrors.rpc.invalidParams({ - message: `Expected single, object parameter. Received:\n${JSON.stringify( - req.params, - )}`, - }), - ); + let validParams; + try { + validParams = validateAddEthereumChainParams(req.params[0], end); + } catch (error) { + return end(error); } - const { origin } = req; - const { chainId, - chainName = null, - blockExplorerUrls = null, - nativeCurrency = null, - rpcUrls, - } = req.params[0]; + chainName, + firstValidBlockExplorerUrl, + firstValidRPCUrl, + ticker, + } = validParams; + const { origin } = req; - const otherKeys = Object.keys( - omit(req.params[0], [ - 'chainId', - 'chainName', - 'blockExplorerUrls', - 'iconUrls', - 'rpcUrls', - 'nativeCurrency', - ]), + const currentChainIdForDomain = getCurrentChainIdForDomain(origin); + const currentNetworkConfiguration = findExistingNetwork( + currentChainIdForDomain, + findNetworkConfigurationBy, ); - if (otherKeys.length > 0) { - return end( - ethErrors.rpc.invalidParams({ - message: `Received unexpected keys on object parameter. Unsupported keys:\n${otherKeys}`, - }), - ); - } - - function isLocalhostOrHttps(urlString) { - const url = getValidUrl(urlString); - - return ( - url !== null && - (url.hostname === 'localhost' || - url.hostname === '127.0.0.1' || - url.protocol === 'https:') - ); - } - - const firstValidRPCUrl = Array.isArray(rpcUrls) - ? rpcUrls.find((rpcUrl) => isLocalhostOrHttps(rpcUrl)) - : null; - - const firstValidBlockExplorerUrl = - blockExplorerUrls !== null && Array.isArray(blockExplorerUrls) - ? blockExplorerUrls.find((blockExplorerUrl) => - isLocalhostOrHttps(blockExplorerUrl), - ) - : null; - - if (!firstValidRPCUrl) { - return end( - ethErrors.rpc.invalidParams({ - message: `Expected an array with at least one valid string HTTPS url 'rpcUrls', Received:\n${rpcUrls}`, - }), - ); - } - - if (blockExplorerUrls !== null && !firstValidBlockExplorerUrl) { - return end( - ethErrors.rpc.invalidParams({ - message: `Expected null or array with at least one valid string HTTPS URL 'blockExplorerUrl'. Received: ${blockExplorerUrls}`, - }), - ); - } - - const _chainId = typeof chainId === 'string' && chainId.toLowerCase(); - - if (!isPrefixedFormattedHexString(_chainId)) { - return end( - ethErrors.rpc.invalidParams({ - message: `Expected 0x-prefixed, unpadded, non-zero hexadecimal string 'chainId'. Received:\n${chainId}`, - }), - ); - } + const existingNetwork = findExistingNetwork( + chainId, + findNetworkConfigurationBy, + ); - if (!isSafeChainId(parseInt(_chainId, 16))) { + if ( + existingNetwork && + existingNetwork.chainId === chainId && + existingNetwork.ticker !== ticker + ) { return end( ethErrors.rpc.invalidParams({ - message: `Invalid chain ID "${_chainId}": numerical value greater than max safe value. Received:\n${chainId}`, + message: `nativeCurrency.symbol does not match currency symbol for a network the user already has added with the same chainId. Received:\n${ticker}`, }), ); } - const existingNetwork = findNetworkConfigurationBy({ chainId: _chainId }); + let networkClientId; + let requestData; + let approvalFlowId; - // if the request is to add a network that is already added and configured - // with the same RPC gateway we shouldn't try to add it again. - if (existingNetwork && existingNetwork.rpcUrl === firstValidRPCUrl) { - // If the network already exists, the request is considered successful - res.result = null; + if (!existingNetwork || existingNetwork.rpcUrl !== firstValidRPCUrl) { + ({ id: approvalFlowId } = await startApprovalFlow()); - const currentChainId = getCurrentChainId(); - const currentRpcUrl = getCurrentRpcUrl(); - - // If the current chainId and rpcUrl matches that of the incoming request - // We don't need to proceed further. - if (currentChainId === _chainId && currentRpcUrl === firstValidRPCUrl) { - return end(); - } - - // If this network is already added with but is not the currently selected network - // Ask the user to switch the network try { await requestUserApproval({ origin, - type: ApprovalType.SwitchEthereumChain, + type: ApprovalType.AddEthereumChain, requestData: { - toNetworkConfiguration: existingNetwork, - fromNetworkConfiguration: getProviderConfig(), + chainId, + rpcPrefs: { blockExplorerUrl: firstValidBlockExplorerUrl }, + chainName, + rpcUrl: firstValidRPCUrl, + ticker, }, }); - await setActiveNetwork(existingNetwork.id); - res.result = null; - } catch (error) { - // For the purposes of this method, it does not matter if the user - // declines to switch the selected network. However, other errors indicate - // that something is wrong. - if (error.code !== errorCodes.provider.userRejectedRequest) { - return end(error); - } - } - return end(); - } - - if (typeof chainName !== 'string' || !chainName) { - return end( - ethErrors.rpc.invalidParams({ - message: `Expected non-empty string 'chainName'. Received:\n${chainName}`, - }), - ); - } - const _chainName = - chainName.length > 100 ? chainName.substring(0, 100) : chainName; - - if (nativeCurrency !== null) { - if (typeof nativeCurrency !== 'object' || Array.isArray(nativeCurrency)) { - return end( - ethErrors.rpc.invalidParams({ - message: `Expected null or object 'nativeCurrency'. Received:\n${nativeCurrency}`, - }), - ); - } - if (nativeCurrency.decimals !== 18) { - return end( - ethErrors.rpc.invalidParams({ - message: `Expected the number 18 for 'nativeCurrency.decimals' when 'nativeCurrency' is provided. Received: ${nativeCurrency.decimals}`, - }), - ); - } - - if (!nativeCurrency.symbol || typeof nativeCurrency.symbol !== 'string') { - return end( - ethErrors.rpc.invalidParams({ - message: `Expected a string 'nativeCurrency.symbol'. Received: ${nativeCurrency.symbol}`, - }), + networkClientId = await upsertNetworkConfiguration( + { + chainId, + rpcPrefs: { blockExplorerUrl: firstValidBlockExplorerUrl }, + nickname: chainName, + rpcUrl: firstValidRPCUrl, + ticker, + }, + { source: 'dapp', referrer: origin }, ); + } catch (error) { + endApprovalFlow({ id: approvalFlowId }); + return end(error); } - } - - const ticker = nativeCurrency?.symbol || UNKNOWN_TICKER_SYMBOL; - - if ( - ticker !== UNKNOWN_TICKER_SYMBOL && - (typeof ticker !== 'string' || ticker.length < 2 || ticker.length > 6) - ) { - return end( - ethErrors.rpc.invalidParams({ - message: `Expected 2-6 character string 'nativeCurrency.symbol'. Received:\n${ticker}`, - }), - ); - } - // if the chainId is the same as an existing network but the ticker is different we want to block this action - // as it is potentially malicious and confusing - if ( - existingNetwork && - existingNetwork.chainId === _chainId && - existingNetwork.ticker !== ticker - ) { - return end( - ethErrors.rpc.invalidParams({ - message: `nativeCurrency.symbol does not match currency symbol for a network the user already has added with the same chainId. Received:\n${ticker}`, - }), - ); - } - let networkConfigurationId; - - const { id: approvalFlowId } = await startApprovalFlow(); - - try { - await requestUserApproval({ - origin, - type: ApprovalType.AddEthereumChain, - requestData: { - chainId: _chainId, - rpcPrefs: { blockExplorerUrl: firstValidBlockExplorerUrl }, - chainName: _chainName, - rpcUrl: firstValidRPCUrl, - ticker, - }, - }); - networkConfigurationId = await upsertNetworkConfiguration( - { - chainId: _chainId, - rpcPrefs: { blockExplorerUrl: firstValidBlockExplorerUrl }, - nickname: _chainName, + requestData = { + toNetworkConfiguration: { rpcUrl: firstValidRPCUrl, + chainId, + nickname: chainName, ticker, + networkClientId, }, - { source: MetaMetricsNetworkEventSource.Dapp, referrer: origin }, - ); - - // Once the network has been added, the requested is considered successful - res.result = null; - } catch (error) { - endApprovalFlow({ id: approvalFlowId }); - return end(error); - } + fromNetworkConfiguration: currentNetworkConfiguration, + }; + } else { + networkClientId = existingNetwork.id ?? existingNetwork.type; + const currentRpcUrl = getCurrentRpcUrl(); - // Ask the user to switch the network - try { - await requestUserApproval({ - origin, - type: ApprovalType.SwitchEthereumChain, - requestData: { - toNetworkConfiguration: { - rpcUrl: firstValidRPCUrl, - chainId: _chainId, - nickname: _chainName, - ticker, - networkConfigurationId, - }, - fromNetworkConfiguration: getProviderConfig(), - }, - }); - if (hasPermissions(req.origin)) { - setNetworkClientIdForDomain(req.origin, networkConfigurationId); + if ( + currentChainIdForDomain === chainId && + currentRpcUrl === firstValidRPCUrl + ) { + return end(); } - } catch (error) { - // For the purposes of this method, it does not matter if the user - // declines to switch the selected network. However, other errors indicate - // that something is wrong. - return end( - error.code === errorCodes.provider.userRejectedRequest - ? undefined - : error, - ); - } finally { - endApprovalFlow({ id: approvalFlowId }); - } - try { - await setActiveNetwork(networkConfigurationId); - } catch (error) { - return end(error); + requestData = { + toNetworkConfiguration: existingNetwork, + fromNetworkConfiguration: currentNetworkConfiguration, + }; } - return end(); + return switchChain( + res, + end, + origin, + chainId, + requestData, + networkClientId, + approvalFlowId, + { + getChainPermissionsFeatureFlag, + setActiveNetwork, + requestUserApproval, + getCaveat, + requestPermittedChainsPermission, + endApprovalFlow, + }, + ); } diff --git a/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.test.js b/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.test.js new file mode 100644 index 000000000000..ee8993ceb3fc --- /dev/null +++ b/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.test.js @@ -0,0 +1,544 @@ +import { ethErrors } from 'eth-rpc-errors'; +import { + CHAIN_IDS, + NETWORK_TYPES, +} from '../../../../../shared/constants/network'; +import addEthereumChain from './add-ethereum-chain'; + +const NON_INFURA_CHAIN_ID = '0x123456789'; + +const createMockMainnetConfiguration = () => ({ + chainId: CHAIN_IDS.MAINNET, + nickname: 'Ethereum Mainnet', + rpcUrl: 'https://mainnet.infura.io/v3/', + type: NETWORK_TYPES.MAINNET, + ticker: 'ETH', + rpcPrefs: { + blockExplorerUrl: 'https://etherscan.io', + }, +}); + +const createMockOptimismConfiguration = () => ({ + chainId: CHAIN_IDS.OPTIMISM, + nickname: 'Optimism', + rpcUrl: 'https://optimism.llamarpc.com', + rpcPrefs: { + blockExplorerUrl: 'https://optimistic.etherscan.io', + }, + ticker: 'ETH', +}); + +const createMockNonInfuraConfiguration = () => ({ + chainId: NON_INFURA_CHAIN_ID, + rpcUrl: 'https://custom.network', + ticker: 'CUST', + nickname: 'Custom Network', + rpcPrefs: { + blockExplorerUrl: 'https://custom.blockexplorer', + }, +}); + +describe('addEthereumChainHandler', () => { + const addEthereumChainHandler = addEthereumChain.implementation; + + const makeMocks = ({ + permissionedChainIds = [], + permissionsFeatureFlagIsActive, + overrides = {}, + } = {}) => { + return { + getChainPermissionsFeatureFlag: () => permissionsFeatureFlagIsActive, + getCurrentChainIdForDomain: jest + .fn() + .mockReturnValue(NON_INFURA_CHAIN_ID), + setNetworkClientIdForDomain: jest.fn(), + findNetworkConfigurationBy: jest + .fn() + .mockReturnValue(createMockMainnetConfiguration()), + setActiveNetwork: jest.fn(), + getCurrentRpcUrl: jest + .fn() + .mockReturnValue(createMockMainnetConfiguration().rpcUrl), + requestUserApproval: jest.fn().mockResolvedValue(123), + requestPermittedChainsPermission: jest.fn(), + getCaveat: jest.fn().mockReturnValue({ value: permissionedChainIds }), + upsertNetworkConfiguration: jest.fn().mockResolvedValue(123), + startApprovalFlow: () => ({ id: 'approvalFlowId' }), + endApprovalFlow: jest.fn(), + ...overrides, + }; + }; + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('with permittedChains permissioning inactive', () => { + it('creates a new network configuration for the given chainid and switches to it if none exists', async () => { + const mocks = makeMocks({ + permissionsFeatureFlagIsActive: false, + }); + await addEthereumChainHandler( + { + origin: 'example.com', + params: [ + { + chainId: CHAIN_IDS.OPTIMISM, + chainName: 'Optimism Mainnet', + rpcUrls: ['https://optimism.llamarpc.com'], + nativeCurrency: { + symbol: 'ETH', + decimals: 18, + }, + blockExplorerUrls: ['https://optimistic.etherscan.io'], + iconUrls: ['https://optimism.icon.com'], + }, + ], + }, + {}, + jest.fn(), + jest.fn(), + mocks, + ); + + // called twice, once for the add and once for the switch + expect(mocks.requestUserApproval).toHaveBeenCalledTimes(2); + expect(mocks.upsertNetworkConfiguration).toHaveBeenCalledTimes(1); + expect(mocks.upsertNetworkConfiguration).toHaveBeenCalledWith( + { + chainId: CHAIN_IDS.OPTIMISM, + nickname: 'Optimism Mainnet', + rpcUrl: 'https://optimism.llamarpc.com', + ticker: 'ETH', + rpcPrefs: { + blockExplorerUrl: 'https://optimistic.etherscan.io', + }, + }, + { referrer: 'example.com', source: 'dapp' }, + ); + expect(mocks.setActiveNetwork).toHaveBeenCalledTimes(1); + expect(mocks.setActiveNetwork).toHaveBeenCalledWith(123); + }); + + describe('if a networkConfiguration for the given chainId already exists', () => { + it('creates a new network configuration for the given chainid and switches to it if proposed networkConfiguration has a different rpcUrl from all existing networkConfigurations', async () => { + const mocks = makeMocks({ + permissionsFeatureFlagIsActive: false, + overrides: { + upsertNetworkConfiguration: jest.fn().mockResolvedValue(123456), + }, + }); + await addEthereumChainHandler( + { + origin: 'example.com', + params: [ + { + chainId: CHAIN_IDS.MAINNET, + chainName: 'Ethereum Mainnet', + rpcUrls: ['https://eth.llamarpc.com'], + nativeCurrency: { + symbol: 'ETH', + decimals: 18, + }, + blockExplorerUrls: ['https://etherscan.io'], + }, + ], + }, + {}, + jest.fn(), + jest.fn(), + mocks, + ); + + expect(mocks.upsertNetworkConfiguration).toHaveBeenCalledTimes(1); + expect(mocks.setActiveNetwork).toHaveBeenCalledWith(123456); + }); + + it('switches to the existing networkConfiguration if the proposed networkConfiguration has the same rpcUrl as an existing networkConfiguration and the currently selected network doesnt match the requested one', async () => { + const mocks = makeMocks({ + permissionsFeatureFlagIsActive: false, + overrides: { + getCurrentRpcUrl: jest + .fn() + .mockReturnValue(createMockNonInfuraConfiguration().rpcUrl), + getCurrentChainIdForDomain: jest + .fn() + .mockReturnValue(createMockNonInfuraConfiguration().chainId), + findNetworkConfigurationBy: jest + .fn() + .mockImplementation(({ chainId }) => { + switch (chainId) { + case createMockNonInfuraConfiguration().chainId: + return createMockNonInfuraConfiguration(); + case createMockOptimismConfiguration().chainId: + return createMockOptimismConfiguration(); + default: + return undefined; + } + }), + upsertNetworkConfiguration: jest.fn().mockResolvedValue(123), + }, + }); + + await addEthereumChainHandler( + { + origin: 'example.com', + params: [ + { + chainId: createMockOptimismConfiguration().chainId, + chainName: createMockOptimismConfiguration().nickname, + rpcUrls: [createMockOptimismConfiguration().rpcUrl], + nativeCurrency: { + symbol: createMockOptimismConfiguration().ticker, + decimals: 18, + }, + blockExplorerUrls: [ + createMockOptimismConfiguration().rpcPrefs.blockExplorerUrl, + ], + }, + ], + }, + {}, + jest.fn(), + jest.fn(), + mocks, + ); + + expect(mocks.requestUserApproval).toHaveBeenCalledTimes(1); + expect(mocks.requestUserApproval).toHaveBeenCalledWith({ + origin: 'example.com', + requestData: { + fromNetworkConfiguration: createMockNonInfuraConfiguration(), + toNetworkConfiguration: { + chainId: '0xa', + nickname: 'Optimism', + rpcPrefs: { + blockExplorerUrl: 'https://optimistic.etherscan.io', + }, + rpcUrl: 'https://optimism.llamarpc.com', + ticker: 'ETH', + }, + }, + type: 'wallet_switchEthereumChain', + }); + expect(mocks.setActiveNetwork).toHaveBeenCalledTimes(1); + expect(mocks.setActiveNetwork).toHaveBeenCalledWith( + createMockOptimismConfiguration().id, + ); + }); + + it('should return error for invalid chainId', async () => { + const mocks = makeMocks({ + permissionsFeatureFlagIsActive: false, + }); + const mockEnd = jest.fn(); + + await addEthereumChainHandler( + { + origin: 'example.com', + params: [{ chainId: 'invalid_chain_id' }], + }, + {}, + jest.fn(), + mockEnd, + mocks, + ); + + expect(mockEnd).toHaveBeenCalledWith( + ethErrors.rpc.invalidParams({ + message: `Expected 0x-prefixed, unpadded, non-zero hexadecimal string 'chainId'. Received:\ninvalid_chain_id`, + }), + ); + }); + }); + }); + + describe('with permittedChains permissioning active', () => { + it('creates a new network configuration for the given chainid, requests permittedChains permission and switches to it if no networkConfigurations with the same chainId exist', async () => { + const mocks = makeMocks({ + permissionedChainIds: [], + permissionsFeatureFlagIsActive: true, + }); + await addEthereumChainHandler( + { + origin: 'example.com', + params: [ + { + chainId: createMockNonInfuraConfiguration().chainId, + chainName: createMockNonInfuraConfiguration().nickname, + rpcUrls: [createMockNonInfuraConfiguration().rpcUrl], + nativeCurrency: { + symbol: createMockNonInfuraConfiguration().ticker, + decimals: 18, + }, + blockExplorerUrls: [ + createMockNonInfuraConfiguration().rpcPrefs.blockExplorerUrl, + ], + }, + ], + }, + {}, + jest.fn(), + jest.fn(), + mocks, + ); + + expect(mocks.upsertNetworkConfiguration).toHaveBeenCalledWith( + createMockNonInfuraConfiguration(), + { referrer: 'example.com', source: 'dapp' }, + ); + expect(mocks.requestPermittedChainsPermission).toHaveBeenCalledTimes(1); + expect(mocks.requestPermittedChainsPermission).toHaveBeenCalledWith([ + createMockNonInfuraConfiguration().chainId, + ]); + expect(mocks.setActiveNetwork).toHaveBeenCalledTimes(1); + expect(mocks.setActiveNetwork).toHaveBeenCalledWith(123); + }); + + describe('if a networkConfiguration for the given chainId already exists', () => { + describe('if the proposed networkConfiguration has a different rpcUrl from the one already in state', () => { + it('create a new networkConfiguration and switches to it without requesting permissions, if the requested chainId has permittedChains permission granted for requesting origin', async () => { + const mocks = makeMocks({ + permissionedChainIds: [CHAIN_IDS.MAINNET], + permissionsFeatureFlagIsActive: true, + }); + + await addEthereumChainHandler( + { + origin: 'example.com', + params: [ + { + chainId: CHAIN_IDS.MAINNET, + chainName: 'Ethereum Mainnet', + rpcUrls: ['https://eth.llamarpc.com'], + nativeCurrency: { + symbol: 'ETH', + decimals: 18, + }, + blockExplorerUrls: ['https://etherscan.io'], + }, + ], + }, + {}, + jest.fn(), + jest.fn(), + mocks, + ); + + expect(mocks.requestUserApproval).toHaveBeenCalledTimes(1); + expect(mocks.requestPermittedChainsPermission).not.toHaveBeenCalled(); + expect(mocks.setActiveNetwork).toHaveBeenCalledTimes(1); + expect(mocks.setActiveNetwork).toHaveBeenCalledWith(123); + }); + + it('create a new networkConfiguration, requests permissions and switches to it, if the requested chainId does not have permittedChains permission granted for requesting origin', async () => { + const mocks = makeMocks({ + permissionsFeatureFlagIsActive: true, + permissionedChainIds: [], + overrides: { + findNetworkConfigurationBy: jest + .fn() + .mockReturnValue(createMockNonInfuraConfiguration()), + getCurrentChainIdForDomain: jest + .fn() + .mockReturnValue(CHAIN_IDS.MAINNET), + }, + }); + + await addEthereumChainHandler( + { + origin: 'example.com', + params: [ + { + chainId: NON_INFURA_CHAIN_ID, + chainName: 'Custom Network', + rpcUrls: ['https://new-custom.network'], + nativeCurrency: { + symbol: 'CUST', + decimals: 18, + }, + blockExplorerUrls: ['https://custom.blockexplorer'], + }, + ], + }, + {}, + jest.fn(), + jest.fn(), + mocks, + ); + + expect(mocks.upsertNetworkConfiguration).toHaveBeenCalledTimes(1); + expect(mocks.requestPermittedChainsPermission).toHaveBeenCalledTimes( + 1, + ); + expect(mocks.requestPermittedChainsPermission).toHaveBeenCalledWith([ + NON_INFURA_CHAIN_ID, + ]); + expect(mocks.setActiveNetwork).toHaveBeenCalledTimes(1); + }); + }); + + it('should switch to the existing networkConfiguration if the proposed networkConfiguration has the same rpcUrl as the one already in state (and is not currently selected)', async () => { + const mocks = makeMocks({ + permissionedChainIds: [createMockOptimismConfiguration().chainId], + permissionsFeatureFlagIsActive: true, + overrides: { + getCurrentRpcUrl: jest + .fn() + .mockReturnValue('https://eth.llamarpc.com'), + findNetworkConfigurationBy: jest + .fn() + .mockReturnValue(createMockOptimismConfiguration()), + }, + }); + + await addEthereumChainHandler( + { + origin: 'example.com', + params: [ + { + chainId: createMockOptimismConfiguration().chainId, + chainName: createMockOptimismConfiguration().nickname, + rpcUrls: [createMockOptimismConfiguration().rpcUrl], + nativeCurrency: { + symbol: createMockOptimismConfiguration().ticker, + decimals: 18, + }, + blockExplorerUrls: [ + createMockOptimismConfiguration().rpcPrefs.blockExplorerUrl, + ], + }, + ], + }, + {}, + jest.fn(), + jest.fn(), + mocks, + ); + + expect(mocks.requestUserApproval).not.toHaveBeenCalled(); + expect(mocks.requestPermittedChainsPermission).not.toHaveBeenCalled(); + expect(mocks.setActiveNetwork).toHaveBeenCalledTimes(1); + expect(mocks.setActiveNetwork).toHaveBeenCalledWith( + createMockOptimismConfiguration().id, + ); + }); + }); + }); + + it('should return an error if an unexpected parameter is provided', async () => { + const mocks = makeMocks({ + permissionsFeatureFlagIsActive: false, + }); + const mockEnd = jest.fn(); + + const unexpectedParam = 'unexpected'; + + await addEthereumChainHandler( + { + origin: 'example.com', + params: [ + { + chainId: createMockNonInfuraConfiguration().chainId, + chainName: createMockNonInfuraConfiguration().nickname, + rpcUrls: [createMockNonInfuraConfiguration().rpcUrl], + nativeCurrency: { + symbol: createMockNonInfuraConfiguration().ticker, + decimals: 18, + }, + blockExplorerUrls: [ + createMockNonInfuraConfiguration().rpcPrefs.blockExplorerUrl, + ], + [unexpectedParam]: 'parameter', + }, + ], + }, + {}, + jest.fn(), + mockEnd, + mocks, + ); + + expect(mockEnd).toHaveBeenCalledWith( + ethErrors.rpc.invalidParams({ + message: `Received unexpected keys on object parameter. Unsupported keys:\n${unexpectedParam}`, + }), + ); + }); + + it('should handle errors during the switch network permission request', async () => { + const mockError = new Error('Permission request failed'); + const mocks = makeMocks({ + permissionsFeatureFlagIsActive: true, + permissionedChainIds: [], + overrides: { + requestPermittedChainsPermission: jest + .fn() + .mockRejectedValue(mockError), + }, + }); + const mockEnd = jest.fn(); + + await addEthereumChainHandler( + { + origin: 'example.com', + params: [ + { + chainId: CHAIN_IDS.MAINNET, + chainName: 'Ethereum Mainnet', + rpcUrls: ['https://mainnet.infura.io/v3/'], + nativeCurrency: { + symbol: 'ETH', + decimals: 18, + }, + blockExplorerUrls: ['https://etherscan.io'], + }, + ], + }, + {}, + jest.fn(), + mockEnd, + mocks, + ); + + expect(mocks.requestPermittedChainsPermission).toHaveBeenCalledTimes(1); + expect(mockEnd).toHaveBeenCalledWith(mockError); + expect(mocks.setActiveNetwork).not.toHaveBeenCalled(); + }); + + it('should return an error if nativeCurrency.symbol does not match an existing network with the same chainId', async () => { + const mocks = makeMocks({ + permissionedChainIds: [CHAIN_IDS.MAINNET], + permissionsFeatureFlagIsActive: true, + }); + const mockEnd = jest.fn(); + + await addEthereumChainHandler( + { + origin: 'example.com', + params: [ + { + chainId: CHAIN_IDS.MAINNET, + chainName: 'Ethereum Mainnet', + rpcUrls: ['https://mainnet.infura.io/v3/'], + nativeCurrency: { + symbol: 'WRONG', + decimals: 18, + }, + blockExplorerUrls: ['https://etherscan.io'], + }, + ], + }, + {}, + jest.fn(), + mockEnd, + mocks, + ); + + expect(mockEnd).toHaveBeenCalledWith( + ethErrors.rpc.invalidParams({ + message: `nativeCurrency.symbol does not match currency symbol for a network the user already has added with the same chainId. Received:\nWRONG`, + }), + ); + }); +}); diff --git a/app/scripts/lib/rpc-method-middleware/handlers/ethereum-chain-utils.js b/app/scripts/lib/rpc-method-middleware/handlers/ethereum-chain-utils.js new file mode 100644 index 000000000000..8b10cbb9cd6f --- /dev/null +++ b/app/scripts/lib/rpc-method-middleware/handlers/ethereum-chain-utils.js @@ -0,0 +1,252 @@ +import { errorCodes, ethErrors } from 'eth-rpc-errors'; +import { ApprovalType } from '@metamask/controller-utils'; + +import { + BUILT_IN_INFURA_NETWORKS, + CHAIN_ID_TO_RPC_URL_MAP, + CHAIN_ID_TO_TYPE_MAP, + CURRENCY_SYMBOLS, + NETWORK_TO_NAME_MAP, +} from '../../../../../shared/constants/network'; +import { + isPrefixedFormattedHexString, + isSafeChainId, +} from '../../../../../shared/modules/network.utils'; +import { CaveatTypes } from '../../../../../shared/constants/permissions'; +import { UNKNOWN_TICKER_SYMBOL } from '../../../../../shared/constants/app'; +import { PermissionNames } from '../../../controllers/permissions'; +import { getValidUrl } from '../../util'; + +export function findExistingNetwork(chainId, findNetworkConfigurationBy) { + if ( + Object.values(BUILT_IN_INFURA_NETWORKS) + .map(({ chainId: id }) => id) + .includes(chainId) + ) { + return { + chainId, + ticker: CURRENCY_SYMBOLS.ETH, + nickname: NETWORK_TO_NAME_MAP[chainId], + rpcUrl: CHAIN_ID_TO_RPC_URL_MAP[chainId], + type: CHAIN_ID_TO_TYPE_MAP[chainId], + }; + } + return findNetworkConfigurationBy({ chainId }); +} + +export function validateChainId(chainId) { + const _chainId = typeof chainId === 'string' && chainId.toLowerCase(); + if (!isPrefixedFormattedHexString(_chainId)) { + throw ethErrors.rpc.invalidParams({ + message: `Expected 0x-prefixed, unpadded, non-zero hexadecimal string 'chainId'. Received:\n${chainId}`, + }); + } + + if (!isSafeChainId(parseInt(_chainId, 16))) { + throw ethErrors.rpc.invalidParams({ + message: `Invalid chain ID "${_chainId}": numerical value greater than max safe value. Received:\n${chainId}`, + }); + } + + return _chainId; +} + +export function validateSwitchEthereumChainParams(req, end) { + if (!req.params?.[0] || typeof req.params[0] !== 'object') { + throw ethErrors.rpc.invalidParams({ + message: `Expected single, object parameter. Received:\n${JSON.stringify( + req.params, + )}`, + }); + } + const { chainId, ...otherParams } = req.params[0]; + + if (Object.keys(otherParams).length > 0) { + throw ethErrors.rpc.invalidParams({ + message: `Received unexpected keys on object parameter. Unsupported keys:\n${Object.keys( + otherParams, + )}`, + }); + } + + return validateChainId(chainId, end); +} + +export function validateAddEthereumChainParams(params, end) { + if (!params || typeof params !== 'object') { + throw ethErrors.rpc.invalidParams({ + message: `Expected single, object parameter. Received:\n${JSON.stringify( + params, + )}`, + }); + } + + const { + chainId, + chainName, + blockExplorerUrls, + nativeCurrency, + rpcUrls, + ...otherParams + } = params; + + const otherKeys = Object.keys(otherParams).filter( + // iconUrls is a valid optional but not currently used parameter + (v) => !['iconUrls'].includes(v), + ); + + if (otherKeys.length > 0) { + throw ethErrors.rpc.invalidParams({ + message: `Received unexpected keys on object parameter. Unsupported keys:\n${otherKeys}`, + }); + } + + const _chainId = validateChainId(chainId, end); + if (!rpcUrls || !Array.isArray(rpcUrls) || rpcUrls.length === 0) { + throw ethErrors.rpc.invalidParams({ + message: `Expected an array with at least one valid string HTTPS url 'rpcUrls', Received:\n${rpcUrls}`, + }); + } + + const isLocalhostOrHttps = (urlString) => { + const url = getValidUrl(urlString); + return ( + url !== null && + (url.hostname === 'localhost' || + url.hostname === '127.0.0.1' || + url.protocol === 'https:') + ); + }; + + const firstValidRPCUrl = rpcUrls.find((rpcUrl) => isLocalhostOrHttps(rpcUrl)); + const firstValidBlockExplorerUrl = + blockExplorerUrls !== null && Array.isArray(blockExplorerUrls) + ? blockExplorerUrls.find((blockExplorerUrl) => + isLocalhostOrHttps(blockExplorerUrl), + ) + : null; + + if (!firstValidRPCUrl) { + throw ethErrors.rpc.invalidParams({ + message: `Expected an array with at least one valid string HTTPS url 'rpcUrls', Received:\n${rpcUrls}`, + }); + } + + if (blockExplorerUrls !== null && !firstValidBlockExplorerUrl) { + throw ethErrors.rpc.invalidParams({ + message: `Expected null or array with at least one valid string HTTPS URL 'blockExplorerUrl'. Received: ${blockExplorerUrls}`, + }); + } + + if (typeof chainName !== 'string' || !chainName) { + throw ethErrors.rpc.invalidParams({ + message: `Expected non-empty string 'chainName'. Received:\n${chainName}`, + }); + } + + const _chainName = + chainName.length > 100 ? chainName.substring(0, 100) : chainName; + + if (nativeCurrency !== null) { + if (typeof nativeCurrency !== 'object' || Array.isArray(nativeCurrency)) { + throw ethErrors.rpc.invalidParams({ + message: `Expected null or object 'nativeCurrency'. Received:\n${nativeCurrency}`, + }); + } + if (nativeCurrency.decimals !== 18) { + throw ethErrors.rpc.invalidParams({ + message: `Expected the number 18 for 'nativeCurrency.decimals' when 'nativeCurrency' is provided. Received: ${nativeCurrency.decimals}`, + }); + } + + if (!nativeCurrency.symbol || typeof nativeCurrency.symbol !== 'string') { + throw ethErrors.rpc.invalidParams({ + message: `Expected a string 'nativeCurrency.symbol'. Received: ${nativeCurrency.symbol}`, + }); + } + } + + const ticker = nativeCurrency?.symbol || UNKNOWN_TICKER_SYMBOL; + if ( + ticker !== UNKNOWN_TICKER_SYMBOL && + (typeof ticker !== 'string' || ticker.length < 1 || ticker.length > 6) + ) { + throw ethErrors.rpc.invalidParams({ + message: `Expected 1-6 character string 'nativeCurrency.symbol'. Received:\n${ticker}`, + }); + } + + return { + chainId: _chainId, + chainName: _chainName, + firstValidBlockExplorerUrl, + firstValidRPCUrl, + ticker, + }; +} + +export async function switchChain( + res, + end, + origin, + chainId, + requestData, + networkClientId, + approvalFlowId, + { + getChainPermissionsFeatureFlag, + setActiveNetwork, + endApprovalFlow, + requestUserApproval, + getCaveat, + requestPermittedChainsPermission, + }, +) { + try { + if (getChainPermissionsFeatureFlag()) { + const { value: permissionedChainIds } = + getCaveat({ + target: PermissionNames.permittedChains, + caveatType: CaveatTypes.restrictNetworkSwitching, + }) ?? {}; + + if ( + permissionedChainIds === undefined || + !permissionedChainIds.includes(chainId) + ) { + await requestPermittedChainsPermission([ + ...(permissionedChainIds ?? []), + chainId, + ]); + } + } else { + await requestUserApproval({ + origin, + type: ApprovalType.SwitchEthereumChain, + requestData, + }); + } + + await setActiveNetwork(networkClientId); + res.result = null; + } catch (error) { + // We don't want to return an error if user rejects the request + // and this is a chained switch request after wallet_addEthereumChain. + // approvalFlowId is only defined when this call is of a + // wallet_addEthereumChain request so we can use it to determine + // if we should return an error + if ( + error.code === errorCodes.provider.userRejectedRequest && + approvalFlowId + ) { + res.result = null; + return end(); + } + return end(error); + } finally { + if (approvalFlowId) { + endApprovalFlow({ id: approvalFlowId }); + } + } + return end(); +} diff --git a/app/scripts/lib/rpc-method-middleware/handlers/index.js b/app/scripts/lib/rpc-method-middleware/handlers/index.ts similarity index 94% rename from app/scripts/lib/rpc-method-middleware/handlers/index.js rename to app/scripts/lib/rpc-method-middleware/handlers/index.ts index 4474b4f8da75..09bca12b5b67 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/index.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/index.ts @@ -16,9 +16,8 @@ import mmiSetAccountAndNetwork from './institutional/mmi-set-account-and-network import mmiOpenAddHardwareWallet from './institutional/mmi-open-add-hardware-wallet'; ///: END:ONLY_INCLUDE_IF -const handlers = [ +export const handlers = [ addEthereumChain, - ethAccounts, getProviderState, logWeb3ShimUsage, requestAccounts, @@ -34,4 +33,5 @@ const handlers = [ mmiOpenAddHardwareWallet, ///: END:ONLY_INCLUDE_IF ]; -export default handlers; + +export const legacyHandlers = [ethAccounts]; diff --git a/app/scripts/lib/rpc-method-middleware/handlers/institutional/mmi-open-add-hardware-wallet.js b/app/scripts/lib/rpc-method-middleware/handlers/institutional/mmi-open-add-hardware-wallet.js index 2518a326a9ef..61af6eb43fe8 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/institutional/mmi-open-add-hardware-wallet.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/institutional/mmi-open-add-hardware-wallet.js @@ -1,4 +1,4 @@ -import { RPC_ALLOWED_ORIGINS } from '@metamask-institutional/rpc-allowlist'; +import { isAllowedRPCOrigin } from '@metamask-institutional/rpc-allowlist'; import { MESSAGE_TYPE } from '../../../../../../shared/constants/app'; const mmiOpenAddHardwareWallet = { @@ -30,14 +30,8 @@ async function mmiOpenAddHardwareWalletHandler( { handleMmiOpenAddHardwareWallet }, ) { try { - let validUrl = false; - // if (!RPC_ALLOWED_ORIGINS[MESSAGE_TYPE.MMI_PORTFOLIO].includes(req.origin)) { - RPC_ALLOWED_ORIGINS[MESSAGE_TYPE.MMI_PORTFOLIO].forEach((regexp) => { - // eslint-disable-next-line require-unicode-regexp - if (regexp.test(req.origin)) { - validUrl = true; - } - }); + const validUrl = isAllowedRPCOrigin(MESSAGE_TYPE.MMI_PORTFOLIO, req.origin); + // eslint-disable-next-line no-negated-condition if (!validUrl) { throw new Error('Unauthorized'); diff --git a/app/scripts/lib/rpc-method-middleware/handlers/institutional/mmi-portfolio.js b/app/scripts/lib/rpc-method-middleware/handlers/institutional/mmi-portfolio.js index e52599ee9736..cbe96127682f 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/institutional/mmi-portfolio.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/institutional/mmi-portfolio.js @@ -1,4 +1,4 @@ -import { RPC_ALLOWED_ORIGINS } from '@metamask-institutional/rpc-allowlist'; +import { isAllowedRPCOrigin } from '@metamask-institutional/rpc-allowlist'; import { MESSAGE_TYPE } from '../../../../../../shared/constants/app'; const mmiPortfolio = { @@ -36,13 +36,8 @@ async function mmiPortfolioHandler( { handleMmiDashboardData }, ) { try { - let validUrl = false; - RPC_ALLOWED_ORIGINS[MESSAGE_TYPE.MMI_PORTFOLIO].forEach((regexp) => { - // eslint-disable-next-line require-unicode-regexp - if (regexp.test(req.origin)) { - validUrl = true; - } - }); + const validUrl = isAllowedRPCOrigin(MESSAGE_TYPE.MMI_PORTFOLIO, req.origin); + // eslint-disable-next-line no-negated-condition if (!validUrl) { throw new Error('Unauthorized'); diff --git a/app/scripts/lib/rpc-method-middleware/handlers/institutional/mmi-set-account-and-network.js b/app/scripts/lib/rpc-method-middleware/handlers/institutional/mmi-set-account-and-network.js index db880691536e..9dca692601a3 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/institutional/mmi-set-account-and-network.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/institutional/mmi-set-account-and-network.js @@ -1,5 +1,5 @@ import { ethErrors } from 'eth-rpc-errors'; -import { RPC_ALLOWED_ORIGINS } from '@metamask-institutional/rpc-allowlist'; +import { isAllowedRPCOrigin } from '@metamask-institutional/rpc-allowlist'; import { MESSAGE_TYPE } from '../../../../../../shared/constants/app'; const mmiSetAccountAndNetwork = { @@ -37,13 +37,8 @@ async function mmiSetAccountAndNetworkHandler( { handleMmiSetAccountAndNetwork }, ) { try { - let validUrl = false; - RPC_ALLOWED_ORIGINS[MESSAGE_TYPE.MMI_PORTFOLIO].forEach((regexp) => { - // eslint-disable-next-line require-unicode-regexp - if (regexp.test(req.origin)) { - validUrl = true; - } - }); + const validUrl = isAllowedRPCOrigin(MESSAGE_TYPE.MMI_PORTFOLIO, req.origin); + // eslint-disable-next-line no-negated-condition if (!validUrl) { throw new Error('Unauthorized'); diff --git a/app/scripts/lib/rpc-method-middleware/handlers/request-accounts.js b/app/scripts/lib/rpc-method-middleware/handlers/request-accounts.js index abd626aea642..f90fb5bd0d42 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/request-accounts.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/request-accounts.js @@ -4,6 +4,7 @@ import { MetaMetricsEventName, MetaMetricsEventCategory, } from '../../../../../shared/constants/metametrics'; +import { shouldEmitDappViewedEvent } from '../../util'; /** * This method attempts to retrieve the Ethereum accounts available to the @@ -108,18 +109,26 @@ async function requestEthereumAccountsHandler( res.result = accounts; const numberOfConnectedAccounts = getPermissionsForOrigin(origin).eth_accounts.caveats[0].value.length; - sendMetrics({ - event: MetaMetricsEventName.DappViewed, - category: MetaMetricsEventCategory.InpageProvider, - referrer: { - url: origin, - }, - properties: { - is_first_visit: true, - number_of_accounts: Object.keys(metamaskState.accounts).length, - number_of_accounts_connected: numberOfConnectedAccounts, - }, - }); + // first time connection to dapp will lead to no log in the permissionHistory + // and if user has connected to dapp before, the dapp origin will be included in the permissionHistory state + // we will leverage that to identify `is_first_visit` for metrics + const isFirstVisit = !Object.keys(metamaskState.permissionHistory).includes( + origin, + ); + if (shouldEmitDappViewedEvent(metamaskState.metaMetricsId)) { + sendMetrics({ + event: MetaMetricsEventName.DappViewed, + category: MetaMetricsEventCategory.InpageProvider, + referrer: { + url: origin, + }, + properties: { + is_first_visit: isFirstVisit, + number_of_accounts: Object.keys(metamaskState.accounts).length, + number_of_accounts_connected: numberOfConnectedAccounts, + }, + }); + } } else { // This should never happen, because it should be caught in the // above catch clause diff --git a/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js b/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js index 6e9d2297b8d0..f701ba06ea6f 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js @@ -1,168 +1,96 @@ import { ethErrors } from 'eth-rpc-errors'; -import { omit } from 'lodash'; -import { ApprovalType } from '@metamask/controller-utils'; import { MESSAGE_TYPE } from '../../../../../shared/constants/app'; import { - CHAIN_ID_TO_TYPE_MAP, - NETWORK_TO_NAME_MAP, - CHAIN_ID_TO_RPC_URL_MAP, - CURRENCY_SYMBOLS, - BUILT_IN_INFURA_NETWORKS, -} from '../../../../../shared/constants/network'; -import { - isPrefixedFormattedHexString, - isSafeChainId, -} from '../../../../../shared/modules/network.utils'; + findExistingNetwork, + validateSwitchEthereumChainParams, + switchChain, +} from './ethereum-chain-utils'; const switchEthereumChain = { methodNames: [MESSAGE_TYPE.SWITCH_ETHEREUM_CHAIN], implementation: switchEthereumChainHandler, hookNames: { - getCurrentChainId: true, findNetworkConfigurationBy: true, - findNetworkClientIdByChainId: true, - setNetworkClientIdForDomain: true, - setProviderType: true, setActiveNetwork: true, + getCaveat: true, + requestPermittedChainsPermission: true, + getCurrentChainIdForDomain: true, requestUserApproval: true, - getNetworkConfigurations: true, - getProviderConfig: true, - hasPermissions: true, + getChainPermissionsFeatureFlag: true, }, }; export default switchEthereumChain; -function findExistingNetwork(chainId, findNetworkConfigurationBy) { - if ( - Object.values(BUILT_IN_INFURA_NETWORKS) - .map(({ chainId: id }) => id) - .includes(chainId) - ) { - return { - chainId, - ticker: CURRENCY_SYMBOLS.ETH, - nickname: NETWORK_TO_NAME_MAP[chainId], - rpcUrl: CHAIN_ID_TO_RPC_URL_MAP[chainId], - type: CHAIN_ID_TO_TYPE_MAP[chainId], - }; - } - - return findNetworkConfigurationBy({ chainId }); -} - async function switchEthereumChainHandler( req, res, _next, end, { - getCurrentChainId, findNetworkConfigurationBy, - findNetworkClientIdByChainId, - setNetworkClientIdForDomain, - setProviderType, setActiveNetwork, + requestPermittedChainsPermission, + getCaveat, + getCurrentChainIdForDomain, requestUserApproval, - getProviderConfig, - hasPermissions, + getChainPermissionsFeatureFlag, }, ) { - if (!req.params?.[0] || typeof req.params[0] !== 'object') { - return end( - ethErrors.rpc.invalidParams({ - message: `Expected single, object parameter. Received:\n${JSON.stringify( - req.params, - )}`, - }), - ); + let chainId; + try { + chainId = validateSwitchEthereumChainParams(req, end); + } catch (error) { + return end(error); } const { origin } = req; - - const { chainId } = req.params[0]; - - const otherKeys = Object.keys(omit(req.params[0], ['chainId'])); - - if (otherKeys.length > 0) { - return end( - ethErrors.rpc.invalidParams({ - message: `Received unexpected keys on object parameter. Unsupported keys:\n${otherKeys}`, - }), - ); + const currentChainIdForOrigin = getCurrentChainIdForDomain(origin); + if (currentChainIdForOrigin === chainId) { + res.result = null; + return end(); } - const _chainId = typeof chainId === 'string' && chainId.toLowerCase(); + const networkConfigurationForRequestedChainId = findExistingNetwork( + chainId, + findNetworkConfigurationBy, + ); - if (!isPrefixedFormattedHexString(_chainId)) { - return end( - ethErrors.rpc.invalidParams({ - message: `Expected 0x-prefixed, unpadded, non-zero hexadecimal string 'chainId'. Received:\n${chainId}`, - }), - ); - } + const networkClientIdToSwitchTo = + networkConfigurationForRequestedChainId?.id ?? + networkConfigurationForRequestedChainId?.type; - if (!isSafeChainId(parseInt(_chainId, 16))) { + if (!networkClientIdToSwitchTo) { return end( - ethErrors.rpc.invalidParams({ - message: `Invalid chain ID "${_chainId}": numerical value greater than max safe value. Received:\n${chainId}`, + ethErrors.provider.custom({ + code: 4902, + message: `Unrecognized chain ID "${chainId}". Try adding the chain using ${MESSAGE_TYPE.ADD_ETHEREUM_CHAIN} first.`, }), ); } const requestData = { - toNetworkConfiguration: findExistingNetwork( - _chainId, + toNetworkConfiguration: networkConfigurationForRequestedChainId, + fromNetworkConfiguration: findExistingNetwork( + currentChainIdForOrigin, findNetworkConfigurationBy, ), }; - requestData.fromNetworkConfiguration = getProviderConfig(); - - if (requestData.toNetworkConfiguration) { - const currentChainId = getCurrentChainId(); - - // we might want to change all this so that it displays the network you are switching from -> to (in a way that is domain - specific) - - const networkClientId = findNetworkClientIdByChainId(_chainId); - - if (currentChainId === _chainId) { - if (hasPermissions(req.origin)) { - setNetworkClientIdForDomain(req.origin, networkClientId); - } - res.result = null; - return end(); - } - - try { - const approvedRequestData = await requestUserApproval({ - origin, - type: ApprovalType.SwitchEthereumChain, - requestData, - }); - if ( - Object.values(BUILT_IN_INFURA_NETWORKS) - .map(({ chainId: id }) => id) - .includes(_chainId) - ) { - await setProviderType(approvedRequestData.type); - } else { - await setActiveNetwork(approvedRequestData.id); - } - if (hasPermissions(req.origin)) { - setNetworkClientIdForDomain(req.origin, networkClientId); - } - res.result = null; - } catch (error) { - return end(error); - } - return end(); - } - - return end( - ethErrors.provider.custom({ - code: 4902, // To-be-standardized "unrecognized chain ID" error - message: `Unrecognized chain ID "${chainId}". Try adding the chain using ${MESSAGE_TYPE.ADD_ETHEREUM_CHAIN} first.`, - }), + return switchChain( + res, + end, + origin, + chainId, + requestData, + networkClientIdToSwitchTo, + null, + { + getChainPermissionsFeatureFlag, + setActiveNetwork, + requestUserApproval, + getCaveat, + requestPermittedChainsPermission, + }, ); } diff --git a/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.test.js b/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.test.js index 685065c0bcc7..2677425cce12 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.test.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.test.js @@ -10,131 +10,249 @@ const mockRequestUserApproval = ({ requestData }) => { return Promise.resolve(requestData.toNetworkConfiguration); }; -const MOCK_MAINNET_CONFIGURATION = { +const createMockMainnetConfiguration = () => ({ id: 123, chainId: CHAIN_IDS.MAINNET, type: NETWORK_TYPES.MAINNET, -}; -const MOCK_LINEA_MAINNET_CONFIGURATION = { - id: 123, +}); + +const createMockLineaMainnetConfiguration = () => ({ + id: 1234, chainId: CHAIN_IDS.LINEA_MAINNET, type: NETWORK_TYPES.LINEA_MAINNET, -}; +}); describe('switchEthereumChainHandler', () => { - it('should call setProviderType when switching to a built in infura network', async () => { - const mockSetProviderType = jest.fn(); - const mockSetActiveNetwork = jest.fn(); - const switchEthereumChainHandler = switchEthereumChain.implementation; - await switchEthereumChainHandler( - { - origin: 'example.com', - params: [{ chainId: CHAIN_IDS.MAINNET }], - }, - {}, - jest.fn(), - jest.fn(), - { - getCurrentChainId: () => NON_INFURA_CHAIN_ID, - findNetworkClientIdByChainId: () => 123, - setNetworkClientIdForDomain: jest.fn(), - getProviderConfig: () => ({ chainId: NON_INFURA_CHAIN_ID }), - findNetworkConfigurationBy: () => MOCK_MAINNET_CONFIGURATION, - setProviderType: mockSetProviderType, - setActiveNetwork: mockSetActiveNetwork, - requestUserApproval: mockRequestUserApproval, - }, - ); - expect(mockSetProviderType).toHaveBeenCalledTimes(1); - expect(mockSetProviderType).toHaveBeenCalledWith( - MOCK_MAINNET_CONFIGURATION.type, - ); - }); + const makeMocks = ({ + permissionedChainIds = [], + permissionsFeatureFlagIsActive = false, + overrides = {}, + mockedFindNetworkConfigurationByReturnValue = createMockMainnetConfiguration(), + mockedGetCurrentChainIdForDomainReturnValue = NON_INFURA_CHAIN_ID, + } = {}) => { + const mockGetCaveat = jest.fn(); + mockGetCaveat.mockReturnValue({ value: permissionedChainIds }); + + return { + getChainPermissionsFeatureFlag: () => permissionsFeatureFlagIsActive, + getCurrentChainIdForDomain: jest + .fn() + .mockReturnValue(mockedGetCurrentChainIdForDomainReturnValue), + setNetworkClientIdForDomain: jest.fn(), + findNetworkConfigurationBy: jest + .fn() + .mockReturnValue(mockedFindNetworkConfigurationByReturnValue), + setActiveNetwork: jest.fn(), + requestUserApproval: jest + .fn() + .mockImplementation(mockRequestUserApproval), + requestPermittedChainsPermission: jest.fn(), + getCaveat: mockGetCaveat, + ...overrides, + }; + }; - it('should call setProviderType when switching to a built in infura network, when chainId from request is lower case', async () => { - const mockSetProviderType = jest.fn(); - const mockSetActiveNetwork = jest.fn(); - const switchEthereumChainHandler = switchEthereumChain.implementation; - await switchEthereumChainHandler( - { - origin: 'example.com', - params: [{ chainId: CHAIN_IDS.LINEA_MAINNET.toLowerCase() }], - }, - {}, - jest.fn(), - jest.fn(), - { - getCurrentChainId: () => NON_INFURA_CHAIN_ID, - getProviderConfig: () => ({ chainId: NON_INFURA_CHAIN_ID }), - setNetworkClientIdForDomain: jest.fn(), - findNetworkClientIdByChainId: () => 123, - findNetworkConfigurationBy: () => MOCK_LINEA_MAINNET_CONFIGURATION, - setProviderType: mockSetProviderType, - setActiveNetwork: mockSetActiveNetwork, - requestUserApproval: mockRequestUserApproval, - }, - ); - expect(mockSetProviderType).toHaveBeenCalledTimes(1); - expect(mockSetProviderType).toHaveBeenCalledWith( - MOCK_LINEA_MAINNET_CONFIGURATION.type, - ); + afterEach(() => { + jest.clearAllMocks(); }); - it('should call setProviderType when switching to a built in infura network, when chainId from request is upper case', async () => { - const mockSetProviderType = jest.fn(); - const mockSetActiveNetwork = jest.fn(); - const switchEthereumChainHandler = switchEthereumChain.implementation; - await switchEthereumChainHandler( - { - origin: 'example.com', - params: [{ chainId: CHAIN_IDS.LINEA_MAINNET.toUpperCase() }], - }, - {}, - jest.fn(), - jest.fn(), - { - getCurrentChainId: () => NON_INFURA_CHAIN_ID, - findNetworkClientIdByChainId: () => 123, - setNetworkClientIdForDomain: jest.fn(), - getProviderConfig: () => ({ chainId: NON_INFURA_CHAIN_ID }), - findNetworkConfigurationBy: () => MOCK_LINEA_MAINNET_CONFIGURATION, - setProviderType: mockSetProviderType, - setActiveNetwork: mockSetActiveNetwork, - requestUserApproval: mockRequestUserApproval, - }, - ); - expect(mockSetProviderType).toHaveBeenCalledTimes(1); - expect(mockSetProviderType).toHaveBeenCalledWith( - MOCK_LINEA_MAINNET_CONFIGURATION.type, - ); + describe('with permittedChains permissioning inactive', () => { + const permissionsFeatureFlagIsActive = false; + + it('should call setActiveNetwork when switching to a built-in infura network', async () => { + const mocks = makeMocks({ + permissionsFeatureFlagIsActive, + overrides: { + findNetworkConfigurationBy: jest + .fn() + .mockReturnValue(createMockMainnetConfiguration()), + }, + }); + const switchEthereumChainHandler = switchEthereumChain.implementation; + await switchEthereumChainHandler( + { + origin: 'example.com', + params: [{ chainId: CHAIN_IDS.MAINNET }], + }, + {}, + jest.fn(), + jest.fn(), + mocks, + ); + expect(mocks.setActiveNetwork).toHaveBeenCalledTimes(1); + expect(mocks.setActiveNetwork).toHaveBeenCalledWith( + createMockMainnetConfiguration().type, + ); + }); + + it('should call setActiveNetwork when switching to a built-in infura network, when chainId from request is lower case', async () => { + const mocks = makeMocks({ + permissionsFeatureFlagIsActive, + overrides: { + findNetworkConfigurationBy: jest + .fn() + .mockReturnValue(createMockLineaMainnetConfiguration()), + }, + }); + const switchEthereumChainHandler = switchEthereumChain.implementation; + await switchEthereumChainHandler( + { + origin: 'example.com', + params: [{ chainId: CHAIN_IDS.LINEA_MAINNET.toLowerCase() }], + }, + {}, + jest.fn(), + jest.fn(), + mocks, + ); + expect(mocks.setActiveNetwork).toHaveBeenCalledTimes(1); + expect(mocks.setActiveNetwork).toHaveBeenCalledWith( + createMockLineaMainnetConfiguration().type, + ); + }); + + it('should call setActiveNetwork when switching to a built-in infura network, when chainId from request is upper case', async () => { + const mocks = makeMocks({ + permissionsFeatureFlagIsActive, + overrides: { + findNetworkConfigurationBy: jest + .fn() + .mockReturnValue(createMockLineaMainnetConfiguration()), + }, + }); + const switchEthereumChainHandler = switchEthereumChain.implementation; + await switchEthereumChainHandler( + { + origin: 'example.com', + params: [{ chainId: CHAIN_IDS.LINEA_MAINNET.toUpperCase() }], + }, + {}, + jest.fn(), + jest.fn(), + mocks, + ); + expect(mocks.setActiveNetwork).toHaveBeenCalledTimes(1); + expect(mocks.setActiveNetwork).toHaveBeenCalledWith( + createMockLineaMainnetConfiguration().type, + ); + }); + + it('should call setActiveNetwork when switching to a custom network', async () => { + const mocks = makeMocks({ + permissionsFeatureFlagIsActive, + overrides: { + getCurrentChainIdForDomain: jest + .fn() + .mockReturnValue(CHAIN_IDS.MAINNET), + }, + }); + const switchEthereumChainHandler = switchEthereumChain.implementation; + await switchEthereumChainHandler( + { + origin: 'example.com', + params: [{ chainId: NON_INFURA_CHAIN_ID }], + }, + {}, + jest.fn(), + jest.fn(), + mocks, + ); + expect(mocks.setActiveNetwork).toHaveBeenCalledTimes(1); + expect(mocks.setActiveNetwork).toHaveBeenCalledWith( + createMockMainnetConfiguration().id, + ); + }); }); - it('should call setActiveNetwork when switching to a custom network', async () => { - const mockSetProviderType = jest.fn(); - const mockSetActiveNetwork = jest.fn(); - const switchEthereumChainHandler = switchEthereumChain.implementation; - await switchEthereumChainHandler( - { - origin: 'example.com', - params: [{ chainId: NON_INFURA_CHAIN_ID }], - }, - {}, - jest.fn(), - jest.fn(), - { - getCurrentChainId: () => CHAIN_IDS.MAINNET, - findNetworkClientIdByChainId: () => 123, - setNetworkClientIdForDomain: jest.fn(), - getProviderConfig: () => ({ chainId: CHAIN_IDS.MAINNET }), - findNetworkConfigurationBy: () => MOCK_MAINNET_CONFIGURATION, - setProviderType: mockSetProviderType, - setActiveNetwork: mockSetActiveNetwork, - requestUserApproval: mockRequestUserApproval, - }, - ); - expect(mockSetActiveNetwork).toHaveBeenCalledTimes(1); - expect(mockSetActiveNetwork).toHaveBeenCalledWith( - MOCK_MAINNET_CONFIGURATION.id, - ); + describe('with permittedChains permissioning active', () => { + const permissionsFeatureFlagIsActive = true; + + it('should call requestPermittedChainsPermission and setActiveNetwork when chainId is not in permittedChains', async () => { + const mockrequestPermittedChainsPermission = jest + .fn() + .mockResolvedValue(); + const mocks = makeMocks({ + permissionsFeatureFlagIsActive, + overrides: { + requestPermittedChainsPermission: + mockrequestPermittedChainsPermission, + }, + }); + const switchEthereumChainHandler = switchEthereumChain.implementation; + await switchEthereumChainHandler( + { + origin: 'example.com', + params: [{ chainId: CHAIN_IDS.MAINNET }], + }, + {}, + jest.fn(), + jest.fn(), + mocks, + ); + + expect(mocks.requestPermittedChainsPermission).toHaveBeenCalledTimes(1); + expect(mocks.requestPermittedChainsPermission).toHaveBeenCalledWith([ + CHAIN_IDS.MAINNET, + ]); + expect(mocks.setActiveNetwork).toHaveBeenCalledTimes(1); + expect(mocks.setActiveNetwork).toHaveBeenCalledWith( + createMockMainnetConfiguration().type, + ); + }); + + it('should call setActiveNetwork without calling requestPermittedChainsPermission when requested chainId is in permittedChains', async () => { + const mocks = makeMocks({ + permissionsFeatureFlagIsActive, + permissionedChainIds: [CHAIN_IDS.MAINNET], + }); + const switchEthereumChainHandler = switchEthereumChain.implementation; + await switchEthereumChainHandler( + { + origin: 'example.com', + params: [{ chainId: CHAIN_IDS.MAINNET }], + }, + {}, + jest.fn(), + jest.fn(), + mocks, + ); + + expect(mocks.requestPermittedChainsPermission).not.toHaveBeenCalled(); + expect(mocks.setActiveNetwork).toHaveBeenCalledTimes(1); + expect(mocks.setActiveNetwork).toHaveBeenCalledWith( + createMockMainnetConfiguration().type, + ); + }); + + it('should handle errors during the switch network permission request', async () => { + const mockError = new Error('Permission request failed'); + const mockrequestPermittedChainsPermission = jest + .fn() + .mockRejectedValue(mockError); + const mocks = makeMocks({ + permissionsFeatureFlagIsActive, + overrides: { + requestPermittedChainsPermission: + mockrequestPermittedChainsPermission, + }, + }); + const mockEnd = jest.fn(); + const switchEthereumChainHandler = switchEthereumChain.implementation; + + await switchEthereumChainHandler( + { + origin: 'example.com', + params: [{ chainId: CHAIN_IDS.MAINNET }], + }, + {}, + jest.fn(), + mockEnd, + mocks, + ); + + expect(mocks.requestPermittedChainsPermission).toHaveBeenCalledTimes(1); + expect(mockEnd).toHaveBeenCalledWith(mockError); + expect(mocks.setActiveNetwork).not.toHaveBeenCalled(); + }); }); }); diff --git a/app/scripts/lib/rpc-method-middleware/index.js b/app/scripts/lib/rpc-method-middleware/index.js index adf68c359374..591545e1b94b 100644 --- a/app/scripts/lib/rpc-method-middleware/index.js +++ b/app/scripts/lib/rpc-method-middleware/index.js @@ -1 +1,2 @@ export * from './createMethodMiddleware'; +export * from './createUnsupportedMethodMiddleware'; diff --git a/app/scripts/lib/security-provider-helpers.test.ts b/app/scripts/lib/security-provider-helpers.test.ts deleted file mode 100644 index 6f3d13ef29a7..000000000000 --- a/app/scripts/lib/security-provider-helpers.test.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { MESSAGE_TYPE } from '../../../shared/constants/app'; -import { - RequestData, - securityProviderCheck, -} from './security-provider-helpers'; - -describe('securityProviderCheck', () => { - let fetchSpy: jest.SpyInstance; - - beforeEach(() => { - // Spy on the global fetch function - fetchSpy = jest.spyOn(global, 'fetch'); - fetchSpy.mockImplementation(async () => { - return new Response(JSON.stringify('result_mocked'), { status: 200 }); - }); - }); - - const paramsMock = { - origin: 'https://example.com', - data: 'some_data', - from: '0x', - }; - - // Utility function to handle different data properties based on methodName - const getExpectedData = (methodName: string, requestData: RequestData) => { - switch (methodName) { - case MESSAGE_TYPE.ETH_SIGN: - case MESSAGE_TYPE.PERSONAL_SIGN: - return { - signer_address: requestData.msgParams?.from, - msg_to_sign: requestData.msgParams?.data, - }; - case MESSAGE_TYPE.ETH_SIGN_TYPED_DATA: - return requestData.messageParams?.data; - default: - return { - from_address: requestData.txParams?.from, - to_address: requestData.txParams?.to, - gas: requestData.txParams?.gas, - gasPrice: requestData.txParams?.gasPrice, - value: requestData.txParams?.value, - data: requestData.txParams?.data, - }; - } - }; - - test.each([ - [MESSAGE_TYPE.ETH_SIGN_TYPED_DATA], - [MESSAGE_TYPE.ETH_SIGN], - [MESSAGE_TYPE.PERSONAL_SIGN], - ['some_other_method'], - ])( - 'should call fetch with the correct parameters for %s', - async (methodName: string) => { - let requestData: RequestData; - - switch (methodName) { - case MESSAGE_TYPE.ETH_SIGN_TYPED_DATA: - requestData = { - origin: 'https://example.com', - messageParams: paramsMock, - }; - break; - case MESSAGE_TYPE.ETH_SIGN: - case MESSAGE_TYPE.PERSONAL_SIGN: - requestData = { - origin: 'https://example.com', - msgParams: paramsMock, - }; - break; - default: - requestData = { - origin: 'https://example.com', - txParams: { - from: '0x', - to: '0x', - gas: 'some_gas', - gasPrice: 'some_gasPrice', - value: 'some_value', - data: 'some_data', - }, - }; - } - - const result = await securityProviderCheck( - requestData, - methodName, - '1', - 'en', - ); - - expect(fetchSpy).toHaveBeenCalledTimes(1); - expect(fetchSpy).toHaveBeenCalledWith( - 'https://proxy.metafi.codefi.network/opensea/security/v1/validate', - expect.objectContaining({ - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - host_name: - methodName === 'some_other_method' - ? requestData.origin - : requestData.msgParams?.origin || - requestData.messageParams?.origin, - rpc_method_name: methodName, - chain_id: '1', - data: getExpectedData(methodName, requestData), - currentLocale: 'en', - }), - }), - ); - expect(result).toEqual('result_mocked'); - }, - ); -}); diff --git a/app/scripts/lib/security-provider-helpers.ts b/app/scripts/lib/security-provider-helpers.ts deleted file mode 100644 index 4b4bca0d6914..000000000000 --- a/app/scripts/lib/security-provider-helpers.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { Json } from '@metamask/utils'; -import { MessageParams } from '@metamask/message-manager'; -import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout'; -import { MESSAGE_TYPE } from '../../../shared/constants/app'; - -const fetchWithTimeout = getFetchWithTimeout(); - -export type TransactionRequestData = { - txParams: Record; - messageParams?: never; - msgParams?: never; -}; - -export type MessageRequestData = - | { - msgParams: MessageParams; - txParams?: never; - messageParams?: never; - } - | { - messageParams: MessageParams; - msgParams?: never; - txParams?: never; - } - | TransactionRequestData; - -export type RequestData = { - origin: string; -} & MessageRequestData; - -export async function securityProviderCheck( - requestData: RequestData, - methodName: string, - chainId: string, - currentLocale: string, -): Promise> { - let dataToValidate; - // Core message managers use messageParams but frontend uses msgParams with lots of references - const params = requestData.msgParams || requestData.messageParams; - - if (methodName === MESSAGE_TYPE.ETH_SIGN_TYPED_DATA) { - dataToValidate = { - host_name: params?.origin, - rpc_method_name: methodName, - chain_id: chainId, - data: params?.data, - currentLocale, - }; - } else if ( - methodName === MESSAGE_TYPE.ETH_SIGN || - methodName === MESSAGE_TYPE.PERSONAL_SIGN - ) { - dataToValidate = { - host_name: params?.origin, - rpc_method_name: methodName, - chain_id: chainId, - data: { - signer_address: params?.from, - msg_to_sign: params?.data, - }, - currentLocale, - }; - } else { - dataToValidate = { - host_name: requestData.origin, - rpc_method_name: methodName, - chain_id: chainId, - data: { - from_address: requestData.txParams?.from, - to_address: requestData.txParams?.to, - gas: requestData.txParams?.gas, - gasPrice: requestData.txParams?.gasPrice, - value: requestData.txParams?.value, - data: requestData.txParams?.data, - }, - currentLocale, - }; - } - - const response: Response = await fetchWithTimeout( - 'https://proxy.metafi.codefi.network/opensea/security/v1/validate', - { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - body: JSON.stringify(dataToValidate), - }, - ); - return await response.json(); -} diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js index 784d4471f2d3..92173fc5f72c 100644 --- a/app/scripts/lib/setupSentry.js +++ b/app/scripts/lib/setupSentry.js @@ -64,6 +64,9 @@ export const SENTRY_BACKGROUND_STATE = { AnnouncementController: { announcements: false, }, + AuthenticationController: { + isSignedIn: false, + }, NetworkOrderController: { orderedNetworkList: [], }, @@ -76,6 +79,7 @@ export const SENTRY_BACKGROUND_STATE = { currentMigrationVersion: true, previousAppVersion: true, previousMigrationVersion: true, + showTokenAutodetectModalOnUpgrade: false, }, ApprovalController: { approvalFlows: false, @@ -86,6 +90,8 @@ export const SENTRY_BACKGROUND_STATE = { browserEnvironment: true, connectedStatusPopoverHasBeenShown: true, currentPopupId: false, + onboardingDate: false, + currentExtensionPopupId: false, defaultHomeActiveTabName: true, fullScreenGasPollTokens: true, hadAdvancedGasFeesSetPriorToMigration92_3: true, @@ -99,9 +105,10 @@ export const SENTRY_BACKGROUND_STATE = { recoveryPhraseReminderLastShown: true, showBetaHeader: true, showPermissionsTour: true, - showProductTour: true, showNetworkBanner: true, showAccountBanner: true, + switchedNetworkDetails: false, + switchedNetworkNeverShowMessage: false, showTestnetMessageInDropdown: true, surveyLinkLastClickedOrClosed: true, snapsInstallPrivacyWarningShown: true, @@ -110,6 +117,9 @@ export const SENTRY_BACKGROUND_STATE = { trezorModel: true, usedNetworks: true, }, + MultichainBalancesController: { + balances: false, + }, CronjobController: { jobs: false, }, @@ -134,6 +144,7 @@ export const SENTRY_BACKGROUND_STATE = { gasEstimateType: true, gasFeeEstimates: true, gasFeeEstimatesByChainId: true, + nonRPCGasFeeApisDisabled: false, }, KeyringController: { isUnlocked: true, @@ -142,6 +153,18 @@ export const SENTRY_BACKGROUND_STATE = { LoggingController: { logs: false, }, + MetamaskNotificationsController: { + subscriptionAccountsSeen: false, + isMetamaskNotificationsFeatureSeen: false, + isMetamaskNotificationsEnabled: false, + isFeatureAnnouncementsEnabled: false, + metamaskNotificationsList: false, + metamaskNotificationsReadList: false, + isCheckingAccountsPresence: false, + isFetchingMetamaskNotifications: false, + isUpdatingMetamaskNotifications: false, + isUpdatingMetamaskNotificationsAccount: false, + }, MetaMetricsController: { eventsBeforeMetricsOptIn: false, fragments: false, @@ -150,6 +173,7 @@ export const SENTRY_BACKGROUND_STATE = { previousUserTraits: false, segmentApiCalls: false, traits: false, + dataCollectionForMarketing: false, }, NameController: { names: false, @@ -187,7 +211,6 @@ export const SENTRY_BACKGROUND_STATE = { PPOMController: { securityAlertsEnabled: false, storageMetadata: [], - versionFileETag: false, versionInfo: [], }, PermissionController: { @@ -209,7 +232,6 @@ export const SENTRY_BACKGROUND_STATE = { incomingTransactionsPreferences: true, isIpfsGatewayEnabled: false, ipfsGateway: false, - isLineaMainnetReleased: true, knownMethodData: false, ledgerTransportType: true, lostIdentities: false, @@ -220,14 +242,16 @@ export const SENTRY_BACKGROUND_STATE = { showExtensionInFullSizeView: true, showFiatInTestnets: true, showTestNetworks: true, + smartTransactionsOptInStatus: true, useNativeCurrencyAsPrimaryCurrency: true, petnamesEnabled: true, + showTokenAutodetectModal: false, }, + useExternalServices: false, selectedAddress: false, snapRegistryList: false, theme: true, signatureSecurityAlertResponses: false, - transactionSecurityCheckEnabled: true, use4ByteResolution: true, useAddressBarEnsResolution: true, useBlockie: true, @@ -238,6 +262,20 @@ export const SENTRY_BACKGROUND_STATE = { usePhishDetect: true, useTokenDetection: true, useRequestQueue: true, + useTransactionSimulations: true, + enableMV3TimestampSave: true, + hasDismissedOpenSeaToBlockaidBanner: true, + }, + PushPlatformNotificationsController: { + fcmToken: false, + }, + MultichainRatesController: { + fiatCurrency: true, + rates: true, + cryptocurrencies: true, + }, + QueuedRequestController: { + queuedRequestCount: true, }, SelectedNetworkController: { domains: false }, SignatureController: { @@ -316,8 +354,7 @@ export const SENTRY_BACKGROUND_STATE = { }, }, TokenRatesController: { - contractExchangeRates: false, - contractExchangeRatesByChainId: false, + marketData: false, }, TokensController: { allDetectedTokens: { @@ -344,6 +381,10 @@ export const SENTRY_BACKGROUND_STATE = { UserOperationController: { userOperations: false, }, + UserStorageController: { + isProfileSyncingEnabled: true, + isProfileSyncingUpdateLoading: false, + }, ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) ...MMI_SENTRY_BACKGROUND_STATE, ///: END:ONLY_INCLUDE_IF @@ -381,6 +422,10 @@ export const SENTRY_UI_STATE = { addSnapAccountEnabled: false, snapsAddSnapAccountModalDismissed: false, ///: END:ONLY_INCLUDE_IF + switchedNetworkDetails: false, + switchedNetworkNeverShowMessage: false, + newPrivacyPolicyToastClickedOrClosed: false, + newPrivacyPolicyToastShownDate: false, }, unconnectedAccount: true, }; @@ -475,10 +520,18 @@ export default function setupSentry({ release, getState }) { `Missing SENTRY_DSN environment variable in production environment`, ); } + + ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) + sentryTarget = process.env.SENTRY_MMI_DSN; + ///: END:ONLY_INCLUDE_IF + + ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) + sentryTarget = process.env.SENTRY_DSN; + ///: END:ONLY_INCLUDE_IF + console.log( `Setting up Sentry Remote Error Reporting for '${environment}': SENTRY_DSN`, ); - sentryTarget = process.env.SENTRY_DSN; } else { console.log( `Setting up Sentry Remote Error Reporting for '${environment}': SENTRY_DSN_DEV`, @@ -493,6 +546,10 @@ export default function setupSentry({ release, getState }) { * @returns `true` if MetaMetrics is enabled, `false` otherwise. */ async function getMetaMetricsEnabled() { + if (METAMASK_BUILD_TYPE === 'mmi') { + return true; + } + const appState = getState(); if (appState.state || appState.persistedState) { return getMetaMetricsEnabledFromAppState(appState); @@ -508,6 +565,22 @@ export default function setupSentry({ release, getState }) { } } + /** + * Returns whether Sentry should be enabled or not. If the build type is mmi + * it will always be enabled, if it's main it will first check for MetaMetrics + * value before returning true or false + * + * @returns `true` if Sentry should be enabled, depends on the build type and + * whether MetaMetrics is on or off for all build types except mmi + */ + async function getSentryEnabled() { + // For MMI we want Sentry always logging, doesn't depend on MetaMetrics being on or off + if (METAMASK_BUILD_TYPE === 'mmi') { + return true; + } + return getMetaMetricsEnabled(); + } + Sentry.init({ dsn: sentryTarget, debug: METAMASK_DEBUG, @@ -553,10 +626,27 @@ export default function setupSentry({ release, getState }) { new FilterEvents({ getMetaMetricsEnabled }), new Dedupe(), new ExtraErrorData(), + new Sentry.BrowserProfilingIntegration(), ], release, + /** + * Setting a value for `tracesSampleRate` enables performance monitoring in Sentry. + * Once performance monitoring is enabled, transactions are sent to Sentry every time + * a user loads a page or navigates within the app. + * Since the amount of traffic the app gets is important, this means a lot of + * transactions are sent. By setting `tracesSampleRate` to a value lower than 1.0, we + * reduce the volume of transactions to a more reasonable amount. + */ + tracesSampleRate: 0.01, beforeSend: (report) => rewriteReport(report, getState), beforeBreadcrumb: beforeBreadcrumb(getState), + // Client reports are automatically sent when a page's visibility changes to + // "hidden", but cancelled (with an Error) that gets logged to the console. + // Our test infra sometimes reports these errors as unexpected failures, + // which results in test flakiness. We don't use these client reports, so + // we can safely turn them off by setting the `sendClientReports` option to + // `false`. + sendClientReports: false, }); /** @@ -567,7 +657,7 @@ export default function setupSentry({ release, getState }) { const startSession = async () => { const hub = Sentry.getCurrentHub?.(); const options = hub.getClient?.().getOptions?.() ?? {}; - if (hub && (await getMetaMetricsEnabled()) === true) { + if (hub && (await getSentryEnabled()) === true) { options.autoSessionTracking = true; hub.startSession(); } @@ -581,7 +671,7 @@ export default function setupSentry({ release, getState }) { const endSession = async () => { const hub = Sentry.getCurrentHub?.(); const options = hub.getClient?.().getOptions?.() ?? {}; - if (hub && (await getMetaMetricsEnabled()) === false) { + if (hub && (await getSentryEnabled()) === false) { options.autoSessionTracking = false; hub.endSession(); } @@ -597,14 +687,11 @@ export default function setupSentry({ release, getState }) { const options = hub.getClient?.().getOptions?.() ?? { autoSessionTracking: false, }; - const isMetaMetricsEnabled = await getMetaMetricsEnabled(); - if ( - isMetaMetricsEnabled === true && - options.autoSessionTracking === false - ) { + const isSentryEnabled = await getSentryEnabled(); + if (isSentryEnabled === true && options.autoSessionTracking === false) { await startSession(); } else if ( - isMetaMetricsEnabled === false && + isSentryEnabled === false && options.autoSessionTracking === true ) { await endSession(); diff --git a/app/scripts/lib/keyring-snaps-permissions.test.ts b/app/scripts/lib/snap-keyring/keyring-snaps-permissions.test.ts similarity index 84% rename from app/scripts/lib/keyring-snaps-permissions.test.ts rename to app/scripts/lib/snap-keyring/keyring-snaps-permissions.test.ts index afe4b40fefa6..bd48d78cd6bb 100644 --- a/app/scripts/lib/keyring-snaps-permissions.test.ts +++ b/app/scripts/lib/snap-keyring/keyring-snaps-permissions.test.ts @@ -15,6 +15,8 @@ describe('keyringSnapPermissionsBuilder', () => { registerActionHandler: jest.fn(), registerInitialEventPayload: jest.fn(), publish: jest.fn(), + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any, state: {}, }); @@ -69,6 +71,7 @@ describe('keyringSnapPermissionsBuilder', () => { expect(permissions()).toStrictEqual([]); }); + // @ts-expect-error This is missing from the Mocha type definitions it.each([ '', 'null', @@ -82,9 +85,11 @@ describe('keyringSnapPermissionsBuilder', () => { 1, 0, -1, - ])('"%s" cannot call any methods', (origin) => { + ])('"%s" cannot call any methods', (origin: unknown) => { const permissions = keyringSnapPermissionsBuilder( mockController, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any origin as any, ); expect(permissions()).toStrictEqual([]); @@ -92,6 +97,7 @@ describe('keyringSnapPermissionsBuilder', () => { }); describe('isProtocolAllowed', () => { + // @ts-expect-error This is missing from the Mocha type definitions it.each([ ['http://some-dapp.com', true], ['https://some-dapp.com', true], @@ -106,6 +112,8 @@ describe('isProtocolAllowed', () => { [1, false], [0, false], [-1, false], + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any ])('"%s" cannot call any methods', (origin: any, expected: boolean) => { expect(isProtocolAllowed(origin)).toBe(expected); }); diff --git a/app/scripts/lib/keyring-snaps-permissions.ts b/app/scripts/lib/snap-keyring/keyring-snaps-permissions.ts similarity index 100% rename from app/scripts/lib/keyring-snaps-permissions.ts rename to app/scripts/lib/snap-keyring/keyring-snaps-permissions.ts diff --git a/app/scripts/lib/snap-keyring/metrics.test.ts b/app/scripts/lib/snap-keyring/metrics.test.ts index e0ef57fc2b59..fe49b2be73e4 100644 --- a/app/scripts/lib/snap-keyring/metrics.test.ts +++ b/app/scripts/lib/snap-keyring/metrics.test.ts @@ -3,6 +3,8 @@ import { getSnapAndHardwareInfoForMetrics } from './metrics'; describe('getSnapAndHardwareInfoForMetrics', () => { let getAccountType: jest.Mock; let getDeviceModel: jest.Mock; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any let messenger: any; beforeEach(() => { diff --git a/app/scripts/lib/snap-keyring/snap-keyring.ts b/app/scripts/lib/snap-keyring/snap-keyring.ts index 25fa4456d6a0..667353eae2f8 100644 --- a/app/scripts/lib/snap-keyring/snap-keyring.ts +++ b/app/scripts/lib/snap-keyring/snap-keyring.ts @@ -3,17 +3,16 @@ import type { SnapController } from '@metamask/snaps-controllers'; import browser from 'webextension-polyfill'; import { SnapId } from '@metamask/snaps-sdk'; import { + MetaMetricsEventAccountType, MetaMetricsEventCategory, MetaMetricsEventName, - MetaMetricsEventAccountType, } from '../../../../shared/constants/metametrics'; import { SNAP_MANAGE_ACCOUNTS_CONFIRMATION_TYPES } from '../../../../shared/constants/app'; import { t } from '../../translate'; import MetamaskController from '../../metamask-controller'; import { IconName } from '../../../../ui/components/component-library/icon'; -import { getSnapName } from './utils/getSnapName'; import { isBlockedUrl } from './utils/isBlockedUrl'; -import { showSuccess, showError } from './utils/showResult'; +import { showError, showSuccess } from './utils/showResult'; import { SnapKeyringBuilderMessenger } from './types'; /** @@ -40,6 +39,9 @@ export const getAccountsBySnapId = async ( * @param setSelectedAccountHelper - A function to update current selected account. * @param removeAccountHelper - A function to help remove an account based on its address. * @param trackEvent - A function to track MetaMetrics events. + * @param getSnapName - A function to get a snap's localized + * (or non-localized if there are no localization files) name from its manifest. + * @param isSnapPreinstalled - A function to check if a Snap is pre-installed. * @returns The constructed SnapKeyring builder instance with the following methods: * - `saveState`: Persists all keyrings in the keyring controller. * - `addAccount`: Initiates the process of adding an account with user confirmation and handling the user input. @@ -50,13 +52,23 @@ export const snapKeyringBuilder = ( getSnapController: () => SnapController, persistKeyringHelper: () => Promise, setSelectedAccountHelper: (address: string) => void, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any removeAccountHelper: (address: string) => Promise, trackEvent: ( + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any payload: Record, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any options?: Record, ) => void, + getSnapName: (snapId: string) => string, + isSnapPreinstalled: (snapId: string) => boolean, ) => { const builder = (() => { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any return new SnapKeyring(getSnapController() as any, { addressExists: async (address) => { const addresses = await controllerMessenger.call( @@ -110,11 +122,10 @@ export const snapKeyringBuilder = ( address: string, snapId: string, handleUserInput: (accepted: boolean) => Promise, + _accountNameSuggestion?: string, + displayConfirmation: boolean = false, ) => { - const snapName = getSnapName(controllerMessenger, snapId); - const { id: addAccountApprovalId } = controllerMessenger.call( - 'ApprovalController:startFlow', - ); + const snapName = getSnapName(snapId); const trackSnapAccountEvent = (event: MetaMetricsEventName) => { trackEvent({ @@ -131,19 +142,29 @@ export const snapKeyringBuilder = ( const learnMoreLink = 'https://support.metamask.io/hc/en-us/articles/360015289452-How-to-add-accounts-in-your-wallet'; - // Since we use this in the finally, better to give it a default value if the controller call fails - let confirmationResult = false; + // If snap is preinstalled and does not request confirmation, skip the confirmation dialog + const skipConfirmation = + isSnapPreinstalled(snapId) && !displayConfirmation; + // If confirmation dialog is skipped, we consider the account creation to be confirmed + let confirmationResult = skipConfirmation; + let confirmationApprovalId = ''; try { - confirmationResult = Boolean( - await controllerMessenger.call( - 'ApprovalController:addRequest', - { - origin: snapId, - type: SNAP_MANAGE_ACCOUNTS_CONFIRMATION_TYPES.confirmAccountCreation, - }, - true, - ), - ); + if (!skipConfirmation) { + const { id } = controllerMessenger.call( + 'ApprovalController:startFlow', + ); + confirmationApprovalId = id; + confirmationResult = Boolean( + await controllerMessenger.call( + 'ApprovalController:addRequest', + { + origin: snapId, + type: SNAP_MANAGE_ACCOUNTS_CONFIRMATION_TYPES.confirmAccountCreation, + }, + true, + ), + ); + } if (confirmationResult) { try { @@ -170,19 +191,22 @@ export const snapKeyringBuilder = ( trackSnapAccountEvent( MetaMetricsEventName.AddSnapAccountSuccessViewed, ); - await showSuccess( - controllerMessenger, - snapId, - { - icon: IconName.UserCircleAdd, - title: t('snapAccountCreated'), - }, - { - message: t('snapAccountCreatedDescription') as string, - address, - learnMoreLink, - }, - ); + + if (!skipConfirmation) { + await showSuccess( + controllerMessenger, + snapId, + { + icon: IconName.UserCircleAdd, + title: t('snapAccountCreated'), + }, + { + message: t('snapAccountCreatedDescription') as string, + address, + learnMoreLink, + }, + ); + } // User has clicked on "OK" trackSnapAccountEvent( @@ -226,10 +250,12 @@ export const snapKeyringBuilder = ( if (confirmationResult) { trackSnapAccountEvent(MetaMetricsEventName.AccountAdded); } - - controllerMessenger.call('ApprovalController:endFlow', { - id: addAccountApprovalId, - }); + // End the approval flow if it was started + if (!skipConfirmation) { + controllerMessenger.call('ApprovalController:endFlow', { + id: confirmationApprovalId, + }); + } } }, removeAccount: async ( @@ -237,7 +263,7 @@ export const snapKeyringBuilder = ( snapId: string, handleUserInput: (accepted: boolean) => Promise, ) => { - const snapName = getSnapName(controllerMessenger, snapId); + const snapName = getSnapName(snapId); const { id: removeAccountApprovalId } = controllerMessenger.call( 'ApprovalController:startFlow', ); @@ -346,6 +372,8 @@ export const snapKeyringBuilder = ( } }, }); + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any }) as any; builder.type = SnapKeyring.type; return builder; diff --git a/app/scripts/lib/snap-keyring/utils/getSnapName.test.ts b/app/scripts/lib/snap-keyring/utils/getSnapName.test.ts deleted file mode 100644 index c010f61c5756..000000000000 --- a/app/scripts/lib/snap-keyring/utils/getSnapName.test.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { SubjectMetadataController } from '@metamask/permission-controller'; -import { ControllerMessenger } from '@metamask/base-controller'; -import { getSnapName } from './getSnapName'; - -const MOCK_SNAP_NAME = 'snap.test'; -const MOCK_SNAP_PREFIX = 'local'; -const MOCK_SNAP_ORIGIN = `${MOCK_SNAP_PREFIX}:${MOCK_SNAP_NAME}`; - -function setupControllerMessenger() { - const controllerMessenger = new ControllerMessenger(); - - // The SubjectMetadataController also requires some methods from PermissionController - controllerMessenger.registerActionHandler( - 'PermissionController:hasPermissions', - // Not important for our tests - (_) => true as never, - ); - - const subjectMetadata = [ - { - origin: MOCK_SNAP_ORIGIN, - name: MOCK_SNAP_NAME, - }, - ]; - const subjectMetadataController = new SubjectMetadataController({ - messenger: controllerMessenger.getRestricted({ - name: 'SubjectMetadataController', - allowedActions: [ - 'PermissionController:hasPermissions' as unknown as never, - ], - }), - subjectCacheLimit: subjectMetadata.length, - }); - subjectMetadata.forEach((x) => - subjectMetadataController.addSubjectMetadata(x), - ); - - return controllerMessenger; -} - -function getSnapKeyringBuilderMessenger( - controllerMessenger: any, - allowedActions: string[], -) { - return controllerMessenger.getRestricted({ - name: 'SnapKeyringBuilder', - allowedActions, - }); -} - -describe('getSnapName', () => { - const controllerMessenger = setupControllerMessenger(); - const messenger = getSnapKeyringBuilderMessenger(controllerMessenger, [ - 'SubjectMetadataController:getSubjectMetadata', - ]); - - it('should return the snap name', () => { - expect(getSnapName(messenger, MOCK_SNAP_ORIGIN)).toBe(MOCK_SNAP_NAME); - }); - - it('should return the snap name even if the SubjectMetadata is not known', () => { - const snapName = 'unknown-snap.test'; - const snapId = `${MOCK_SNAP_PREFIX}:${snapName}`; - - expect(getSnapName(messenger, snapId)).toBe(snapName); - }); - - it('should return null if snapId is null', () => { - // In our case we should probably never get a `null` origin (== snapId), but for the sake - // of completeness we make sure this is a well defined behavior - expect(getSnapName(messenger, null as unknown as string)).toBe(null); - }); - - it('should return null if snapId is undefined', () => { - // Same here - expect(getSnapName(messenger, undefined as unknown as string)).toBe(null); - }); - - it('should raise if the SubjectMetadata cannot be retrieved', () => { - // Disallow calls to `:getSubjectMetadata` - const unallowedMessenger = getSnapKeyringBuilderMessenger( - controllerMessenger, - [], - ); - - expect(() => { - return getSnapName(unallowedMessenger, MOCK_SNAP_ORIGIN); - }).toThrowError(); - }); -}); diff --git a/app/scripts/lib/snap-keyring/utils/getSnapName.ts b/app/scripts/lib/snap-keyring/utils/getSnapName.ts deleted file mode 100644 index 6ca98b205c6c..000000000000 --- a/app/scripts/lib/snap-keyring/utils/getSnapName.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { getSnapName as getSnapNameFromSubjectMetadata } from '../../../../../ui/helpers/utils/util'; -import { SnapKeyringBuilderMessenger } from '../types'; - -export const getSnapName = ( - controllerMessenger: SnapKeyringBuilderMessenger, - snapId: string, -): string => { - const subjectMetadata = controllerMessenger.call( - 'SubjectMetadataController:getSubjectMetadata', - snapId, - ); - - return getSnapNameFromSubjectMetadata(snapId, subjectMetadata); -}; diff --git a/app/scripts/lib/snap-keyring/utils/isBlockedUrl.test.ts b/app/scripts/lib/snap-keyring/utils/isBlockedUrl.test.ts index 839176dca5a1..b40e52afe170 100644 --- a/app/scripts/lib/snap-keyring/utils/isBlockedUrl.test.ts +++ b/app/scripts/lib/snap-keyring/utils/isBlockedUrl.test.ts @@ -6,6 +6,8 @@ describe('isBlockedUrl', () => { const messenger = new ControllerMessenger(); const phishingControllerMessenger = messenger.getRestricted({ name: 'PhishingController', + allowedActions: [], + allowedEvents: [], }); const phishingController = new PhishingController({ messenger: phishingControllerMessenger, @@ -24,6 +26,7 @@ describe('isBlockedUrl', () => { }, }); + // @ts-expect-error This is missing from the Mocha type definitions it.each([ ['http://metamask.io', false], ['https://metamask.io', false], @@ -36,6 +39,8 @@ describe('isBlockedUrl', () => { [1, true], [0, true], [-1, true], + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any ])('"%s" is blocked: %s', async (url: any, expected: boolean) => { const result = await isBlockedUrl( url, diff --git a/app/scripts/lib/snap-keyring/utils/isBlockedUrl.ts b/app/scripts/lib/snap-keyring/utils/isBlockedUrl.ts index f196faff0b96..50bc4bfa08eb 100644 --- a/app/scripts/lib/snap-keyring/utils/isBlockedUrl.ts +++ b/app/scripts/lib/snap-keyring/utils/isBlockedUrl.ts @@ -1,5 +1,5 @@ import { PhishingController } from '@metamask/phishing-controller'; -import { isProtocolAllowed } from '../../keyring-snaps-permissions'; +import { isProtocolAllowed } from '../keyring-snaps-permissions'; /** * Checks whether a given URL is blocked due to not using HTTPS or being diff --git a/app/scripts/lib/snap-keyring/utils/showResult.ts b/app/scripts/lib/snap-keyring/utils/showResult.ts index c0b4c530ed09..086f9fe07174 100644 --- a/app/scripts/lib/snap-keyring/utils/showResult.ts +++ b/app/scripts/lib/snap-keyring/utils/showResult.ts @@ -42,6 +42,8 @@ export const showError = ( controllerMessenger: SnapKeyringBuilderMessenger, snapId: string, opts: ResultComponentOptions, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any properties: Record, ): Promise => { return controllerMessenger.call('ApprovalController:showError', { @@ -70,6 +72,8 @@ export const showSuccess = ( controllerMessenger: SnapKeyringBuilderMessenger, snapId: string, opts: ResultComponentOptions, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any properties: Record, ): Promise => { return controllerMessenger.call('ApprovalController:showSuccess', { diff --git a/app/scripts/lib/stream-utils.js b/app/scripts/lib/stream-utils.js index 9a1b37f6a4ca..db50728669fd 100644 --- a/app/scripts/lib/stream-utils.js +++ b/app/scripts/lib/stream-utils.js @@ -1,5 +1,5 @@ -import ObjectMultiplex from 'obj-multiplex'; -import pump from 'pump'; +import ObjectMultiplex from '@metamask/object-multiplex'; +import { pipeline } from 'readable-stream'; import { EXTENSION_MESSAGES } from '../../../shared/constants/app'; @@ -17,10 +17,35 @@ export function setupMultiplex(connectionStream) { * https://github.com/MetaMask/object-multiplex/blob/280385401de84f57ef57054d92cfeb8361ef2680/src/ObjectMultiplex.ts#L63 */ mux.ignoreStream(EXTENSION_MESSAGES.CONNECTION_READY); - pump(connectionStream, mux, connectionStream, (err) => { + pipeline(connectionStream, mux, connectionStream, (err) => { if (err) { console.error(err); } }); return mux; } + +/** + * Checks if a stream is writable and usable + * + * @param {stream.Stream} stream - the stream to check + * @returns {boolean} if the stream can be written to + */ +export function isStreamWritable(stream) { + /** + * Roughly: + * stream.writable: + * readable-stream-3 (confusingly: not mentioned in docs for streamsv2 and not consistently implemented there, despite v3 docs mentioning it as older) + * readable-stream-4/NodeStream (here it's mentioned as introduced much later) + * stream.destroyed: + * readable-stream-4/NodeStream (docs mention it as introduced in v2 despite being absent from both implementation and docs of v2 and v3) + * stream._writableState.ended: + * Present in all implementations, seems like the most reasonable fallback for legacy. + * + * The only accurate references seem to be sources for Node.js and readable-stream. Intended compatibility must be ensured by tests. + */ + + return Boolean( + stream.writable && !stream.destroyed && !stream._writableState?.ended, + ); +} diff --git a/app/scripts/lib/stream-utils.test.ts b/app/scripts/lib/stream-utils.test.ts new file mode 100644 index 000000000000..6dfa4629fd31 --- /dev/null +++ b/app/scripts/lib/stream-utils.test.ts @@ -0,0 +1,96 @@ +import NodeStream from 'node:stream'; +import OurReadableStream from 'readable-stream'; +import ReadableStream2 from 'readable-stream-2'; +import ReadableStream3 from 'readable-stream-3'; +import ObjectMultiplex from '@metamask/object-multiplex'; +import { isStreamWritable } from './stream-utils'; + +describe('Stream Utils', () => { + describe('isStreamWritable', () => { + describe('Using @metamask/object-multiplex', () => { + let stream: ObjectMultiplex; + beforeEach(() => { + stream = new ObjectMultiplex(); + }); + it(`should return true for fresh instance`, () => { + const result = isStreamWritable(stream); + expect(result).toBe(true); + }); + it(`should return false for destroyed instance`, () => { + stream.destroy(); + const result = isStreamWritable(stream); + expect(result).toBe(false); + }); + it(`should return false for ended instance`, (done) => { + stream.end(() => { + const result = isStreamWritable(stream); + expect(result).toBe(false); + done(); + }); + }); + }); + + [ + ['node:stream', NodeStream] as [string, typeof NodeStream], + // Redundantly include used version twice for regression-detection purposes + ['readable-stream', OurReadableStream] as [ + string, + typeof OurReadableStream, + ], + ['readable-stream v2', ReadableStream2] as [ + string, + typeof ReadableStream2, + ], + ['readable-stream v3', ReadableStream3] as [ + string, + typeof ReadableStream3, + ], + ].forEach(([name, streamsImpl]) => { + describe(`Using Streams implementation: ${name}`, () => { + [ + ['Duplex', streamsImpl.Duplex] as [string, typeof streamsImpl.Duplex], + ['Transform', streamsImpl.Transform] as [ + string, + typeof streamsImpl.Transform, + ], + ['Writable', streamsImpl.Writable] as [ + string, + typeof streamsImpl.Writable, + ], + ].forEach(([className, S]) => { + it(`should return true for fresh ${className}`, () => { + const stream = new S(); + const result = isStreamWritable(stream); + expect(result).toBe(true); + }); + it(`should return false for destroyed ${className}`, () => { + const stream = new S(); + stream.destroy(); + const result = isStreamWritable(stream); + expect(result).toBe(false); + }); + it(`should return false for ended ${className}`, (done) => { + const stream = new S(); + stream.end(() => { + const result = isStreamWritable(stream); + expect(result).toBe(false); + done(); + }); + }); + }); + [ + ['Readable', streamsImpl.Readable] as [ + string, + typeof streamsImpl.Readable, + ], + ].forEach(([className, S]) => { + it(`should return false for fresh ${className}`, () => { + const stream = new S(); + const result = isStreamWritable(stream); + expect(result).toBe(false); + }); + }); + }); + }); + }); +}); diff --git a/app/scripts/lib/transaction/metrics.test.ts b/app/scripts/lib/transaction/metrics.test.ts index a4eb13918d7d..74d5aaa13ca0 100644 --- a/app/scripts/lib/transaction/metrics.test.ts +++ b/app/scripts/lib/transaction/metrics.test.ts @@ -68,8 +68,12 @@ const mockTransactionMetricsRequest = { getTokenStandardAndDetails: jest.fn(), getTransaction: jest.fn(), provider: provider as Provider, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any snapAndHardwareMessenger: jest.fn() as any, trackEvent: jest.fn(), + getIsSmartTransaction: jest.fn(), + getSmartTransactionByMinedTxHash: jest.fn(), } as TransactionMetricsRequest; describe('Transaction metrics', () => { @@ -77,9 +81,17 @@ describe('Transaction metrics', () => { mockChainId, mockNetworkId, mockTransactionMeta: TransactionMeta, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any mockTransactionMetaWithBlockaid: any, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any expectedProperties: any, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any expectedSensitiveProperties: any, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any mockActionId: any; beforeEach(() => { @@ -160,6 +172,8 @@ describe('Transaction metrics', () => { describe('handleTransactionAdded', () => { it('should return if transaction meta is not defined', async () => { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any await handleTransactionAdded(mockTransactionMetricsRequest, {} as any); expect( mockTransactionMetricsRequest.createEventFragment, @@ -168,6 +182,8 @@ describe('Transaction metrics', () => { it('should create event fragment', async () => { await handleTransactionAdded(mockTransactionMetricsRequest, { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any transactionMeta: mockTransactionMeta as any, actionId: mockActionId, }); @@ -195,6 +211,8 @@ describe('Transaction metrics', () => { }; await handleTransactionAdded(mockTransactionMetricsRequest, { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any transactionMeta: mockTransactionMeta as any, actionId: mockActionId, }); @@ -221,6 +239,8 @@ describe('Transaction metrics', () => { it('should create event fragment with blockaid', async () => { await handleTransactionAdded(mockTransactionMetricsRequest, { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any transactionMeta: mockTransactionMetaWithBlockaid as any, actionId: mockActionId, }); @@ -251,6 +271,8 @@ describe('Transaction metrics', () => { describe('handleTransactionApproved', () => { it('should return if transaction meta is not defined', async () => { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any await handleTransactionApproved(mockTransactionMetricsRequest, {} as any); expect( mockTransactionMetricsRequest.createEventFragment, @@ -265,6 +287,8 @@ describe('Transaction metrics', () => { it('should create, update, finalize event fragment', async () => { await handleTransactionApproved(mockTransactionMetricsRequest, { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any transactionMeta: mockTransactionMeta as any, actionId: mockActionId, }); @@ -306,6 +330,8 @@ describe('Transaction metrics', () => { it('should create, update, finalize event fragment with blockaid', async () => { await handleTransactionApproved(mockTransactionMetricsRequest, { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any transactionMeta: mockTransactionMetaWithBlockaid as any, actionId: mockActionId, }); @@ -362,6 +388,8 @@ describe('Transaction metrics', () => { describe('handleTransactionFailed', () => { it('should return if transaction meta is not defined', async () => { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any await handleTransactionFailed(mockTransactionMetricsRequest, {} as any); expect( mockTransactionMetricsRequest.createEventFragment, @@ -386,6 +414,8 @@ describe('Transaction metrics', () => { transactionMeta: mockTransactionMeta, actionId: mockActionId, error: mockErrorMessage, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any); const expectedUniqueId = 'transaction-submitted-1'; @@ -440,6 +470,8 @@ describe('Transaction metrics', () => { transactionMeta: mockTransactionMetaWithBlockaid, actionId: mockActionId, error: mockErrorMessage, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any); const expectedUniqueId = 'transaction-submitted-1'; @@ -503,6 +535,8 @@ describe('Transaction metrics', () => { transactionMeta: mockTransactionMeta, actionId: mockActionId, error: mockErrorMessage, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any); const expectedUniqueId = 'transaction-submitted-1'; @@ -550,6 +584,8 @@ describe('Transaction metrics', () => { it('should return if transaction meta is not defined', async () => { await handleTransactionConfirmed( mockTransactionMetricsRequest, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any {} as any, ); expect( @@ -571,8 +607,10 @@ describe('Transaction metrics', () => { mockTransactionMeta.submittedTime = 123; await handleTransactionConfirmed(mockTransactionMetricsRequest, { - transactionMeta: mockTransactionMeta, + ...mockTransactionMeta, actionId: mockActionId, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any); const expectedUniqueId = 'transaction-submitted-1'; @@ -627,8 +665,10 @@ describe('Transaction metrics', () => { mockTransactionMetaWithBlockaid.submittedTime = 123; await handleTransactionConfirmed(mockTransactionMetricsRequest, { - transactionMeta: mockTransactionMetaWithBlockaid, + ...mockTransactionMetaWithBlockaid, actionId: mockActionId, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any); const expectedUniqueId = 'transaction-submitted-1'; @@ -692,6 +732,8 @@ describe('Transaction metrics', () => { describe('handleTransactionDropped', () => { it('should return if transaction meta is not defined', async () => { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any await handleTransactionDropped(mockTransactionMetricsRequest, {} as any); expect( mockTransactionMetricsRequest.createEventFragment, @@ -708,6 +750,8 @@ describe('Transaction metrics', () => { await handleTransactionDropped(mockTransactionMetricsRequest, { transactionMeta: mockTransactionMeta, actionId: mockActionId, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any); const expectedUniqueId = 'transaction-submitted-1'; @@ -756,6 +800,8 @@ describe('Transaction metrics', () => { await handleTransactionDropped(mockTransactionMetricsRequest, { transactionMeta: mockTransactionMetaWithBlockaid, actionId: mockActionId, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any); const expectedUniqueId = 'transaction-submitted-1'; @@ -817,6 +863,8 @@ describe('Transaction metrics', () => { describe('handleTransactionRejected', () => { it('should return if transaction meta is not defined', async () => { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any await handleTransactionRejected(mockTransactionMetricsRequest, {} as any); expect( mockTransactionMetricsRequest.createEventFragment, @@ -833,6 +881,8 @@ describe('Transaction metrics', () => { await handleTransactionRejected(mockTransactionMetricsRequest, { transactionMeta: mockTransactionMeta, actionId: mockActionId, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any); const expectedUniqueId = 'transaction-added-1'; @@ -876,6 +926,8 @@ describe('Transaction metrics', () => { await handleTransactionRejected(mockTransactionMetricsRequest, { transactionMeta: mockTransactionMetaWithBlockaid, actionId: mockActionId, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any); const expectedUniqueId = 'transaction-added-1'; @@ -934,6 +986,8 @@ describe('Transaction metrics', () => { it('should return if transaction meta is not defined', async () => { await handleTransactionSubmitted( mockTransactionMetricsRequest, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any {} as any, ); expect( @@ -943,6 +997,8 @@ describe('Transaction metrics', () => { it('should only create event fragment', async () => { await handleTransactionSubmitted(mockTransactionMetricsRequest, { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any transactionMeta: mockTransactionMeta as any, actionId: mockActionId, }); diff --git a/app/scripts/lib/transaction/metrics.ts b/app/scripts/lib/transaction/metrics.ts index ba806f245cb0..ff8b937c3b4c 100644 --- a/app/scripts/lib/transaction/metrics.ts +++ b/app/scripts/lib/transaction/metrics.ts @@ -7,6 +7,7 @@ import { TransactionMeta, TransactionType, } from '@metamask/transaction-controller'; +import { SmartTransaction } from '@metamask/smart-transactions-controller/dist/types'; import { ORIGIN_METAMASK } from '../../../../shared/constants/app'; import { determineTransactionAssetType, @@ -38,6 +39,7 @@ import { ///: BEGIN:ONLY_INCLUDE_IF(blockaid) import { getBlockaidMetricsProps } from '../../../../ui/helpers/utils/metrics'; ///: END:ONLY_INCLUDE_IF +import { getSmartTransactionMetricsProperties } from '../../../../shared/modules/metametrics'; import { getSnapAndHardwareInfoForMetrics, type SnapAndHardwareMessenger, @@ -69,19 +71,27 @@ export type TransactionMetricsRequest = { // According to the type GasFeeState returned from getEIP1559GasFeeEstimates // doesn't include some properties used in buildEventFragmentProperties, // hence returning any here to avoid type errors. + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any getEIP1559GasFeeEstimates(options?: FetchGasFeeEstimateOptions): Promise; getParticipateInMetrics: () => boolean; getSelectedAddress: () => string; - getTokenStandardAndDetails: () => { + getTokenStandardAndDetails: () => Promise<{ decimals?: string; balance?: string; symbol?: string; standard?: TokenStandard; - }; + }>; getTransaction: (transactionId: string) => TransactionMeta; provider: Provider; snapAndHardwareMessenger: SnapAndHardwareMessenger; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any trackEvent: (payload: any) => void; + getIsSmartTransaction: () => boolean; + getSmartTransactionByMinedTxHash: ( + txhash: string | undefined, + ) => SmartTransaction; }; export const METRICS_STATUS_FAILED = 'failed on-chain'; @@ -92,6 +102,11 @@ export type TransactionEventPayload = { error?: string; }; +export type TransactionMetaEventPayload = TransactionMeta & { + actionId?: string; + error?: string; +}; + /** * This function is called when a transaction is added to the controller. * @@ -161,6 +176,8 @@ export const handleTransactionFailed = async ( return; } + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const extraParams = {} as Record; if (transactionEventPayload.error) { // This is a failed transaction @@ -185,14 +202,16 @@ export const handleTransactionFailed = async ( */ export const handleTransactionConfirmed = async ( transactionMetricsRequest: TransactionMetricsRequest, - transactionEventPayload: TransactionEventPayload, + transactionEventPayload: TransactionMetaEventPayload, ) => { - if (!transactionEventPayload.transactionMeta) { + if (Object.keys(transactionEventPayload).length === 0) { return; } + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const extraParams = {} as Record; - const { transactionMeta } = transactionEventPayload; + const transactionMeta = { ...transactionEventPayload }; const { txReceipt } = transactionMeta; extraParams.gas_used = txReceipt?.gasUsed; @@ -209,7 +228,10 @@ export const handleTransactionConfirmed = async ( await createUpdateFinalizeTransactionEventFragment({ eventName: TransactionMetaMetricsEvent.finalized, extraParams, - transactionEventPayload, + transactionEventPayload: { + actionId: transactionMeta.actionId, + transactionMeta, + }, transactionMetricsRequest, }); }; @@ -312,10 +334,10 @@ export const createTransactionEventFragmentWithTxId = async ( actionId: string; }, ) => { - const transactionMeta = - transactionMetricsRequest.getTransaction(transactionId); - - transactionMeta.actionId = actionId; + const transactionMeta = { + ...transactionMetricsRequest.getTransaction(transactionId), + actionId, + }; const { properties, sensitiveProperties } = await buildEventFragmentProperties({ @@ -484,6 +506,8 @@ function createTransactionEventFragment({ eventName: TransactionMetaMetricsEvent; transactionEventPayload: TransactionEventPayload; transactionMetricsRequest: TransactionMetricsRequest; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any payload: any; }) { if ( @@ -597,6 +621,8 @@ function updateTransactionEventFragment({ eventName: TransactionMetaMetricsEvent; transactionEventPayload: TransactionEventPayload; transactionMetricsRequest: TransactionMetricsRequest; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any payload: any; }) { const uniqueId = getUniqueId(eventName, transactionMeta.id); @@ -666,6 +692,8 @@ async function createUpdateFinalizeTransactionEventFragment({ eventName: TransactionMetaMetricsEvent; transactionEventPayload: TransactionEventPayload; transactionMetricsRequest: TransactionMetricsRequest; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any extraParams?: Record; }) { const { properties, sensitiveProperties } = @@ -703,6 +731,8 @@ async function createUpdateFinalizeTransactionEventFragment({ } function hasFragment( + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any getEventFragmentById: (arg0: string) => any, eventName: TransactionMetaMetricsEvent, transactionMeta: TransactionMeta, @@ -731,6 +761,8 @@ async function buildEventFragmentProperties({ transactionMetricsRequest, extraParams = {}, }: { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any extraParams?: Record; transactionEventPayload: TransactionEventPayload; transactionMetricsRequest: TransactionMetricsRequest; @@ -770,6 +802,8 @@ async function buildEventFragmentProperties({ transactionMetricsRequest.getTokenStandardAndDetails, ); + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const gasParams = {} as Record; if (isEIP1559Transaction(transactionMeta)) { @@ -844,12 +878,13 @@ async function buildEventFragmentProperties({ [ TransactionType.contractInteraction, TransactionType.tokenMethodApprove, + TransactionType.tokenMethodIncreaseAllowance, TransactionType.tokenMethodSafeTransferFrom, TransactionType.tokenMethodSetApprovalForAll, TransactionType.tokenMethodTransfer, TransactionType.tokenMethodTransferFrom, - TransactionType.smart, TransactionType.swap, + TransactionType.swapAndSend, TransactionType.swapApproval, ].includes(type); @@ -934,6 +969,8 @@ async function buildEventFragmentProperties({ } ///: BEGIN:ONLY_INCLUDE_IF(blockaid) + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const blockaidProperties: any = getBlockaidMetricsProps(transactionMeta); if (blockaidProperties?.ui_customizations?.length > 0) { @@ -945,6 +982,12 @@ async function buildEventFragmentProperties({ uiCustomizations.push(MetaMetricsEventUiCustomization.GasEstimationFailed); } + const smartTransactionMetricsProperties = + getSmartTransactionMetricsProperties( + transactionMetricsRequest, + transactionMeta, + ); + /** The transaction status property is not considered sensitive and is now included in the non-anonymous event */ let properties = { chain_id: chainId, @@ -971,6 +1014,9 @@ async function buildEventFragmentProperties({ ///: END:ONLY_INCLUDE_IF // ui_customizations must come after ...blockaidProperties ui_customizations: uiCustomizations.length > 0 ? uiCustomizations : null, + ...smartTransactionMetricsProperties, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as Record; const snapAndHardwareInfo = await getSnapAndHardwareInfoForMetrics( @@ -997,6 +1043,8 @@ async function buildEventFragmentProperties({ transaction_replaced: transactionReplaced, ...extraParams, ...gasParamsInGwei, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as Record; if (transactionContractMethod === contractMethodNames.APPROVE) { @@ -1012,7 +1060,11 @@ async function buildEventFragmentProperties({ return { properties, sensitiveProperties }; } +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any function getGasValuesInGWEI(gasParams: Record) { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const gasValuesInGwei = {} as Record; for (const param in gasParams) { if (isHexString(gasParams[param])) { diff --git a/app/scripts/lib/transaction/mmi-hooks.test.ts b/app/scripts/lib/transaction/mmi-hooks.test.ts index 210c3093ada8..fee5dff83de5 100644 --- a/app/scripts/lib/transaction/mmi-hooks.test.ts +++ b/app/scripts/lib/transaction/mmi-hooks.test.ts @@ -13,6 +13,8 @@ describe('MMI hooks', () => { const custodyIdMocked = '123'; describe('afterTransactionSign', () => { it('returns false if txMeta has no custodyStatus', () => { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const txMeta = { to: toMocked } as any; const signedEthTx = {}; const result = afterTransactionSign(txMeta, signedEthTx, jest.fn()); @@ -24,6 +26,8 @@ describe('MMI hooks', () => { custodyStatus: TransactionStatus.approved, custodyId: custodyIdMocked, txParams: { from: fromMocked }, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any; const signedEthTx = { custodian_transactionId: custodyIdMocked, @@ -47,12 +51,16 @@ describe('MMI hooks', () => { describe('beforeTransactionPublish', () => { it('returns true if txMeta has custodyStatus', () => { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const txMeta = { custodyStatus: TransactionStatus.approved } as any; const result = beforeTransactionPublish(txMeta); expect(result).toBe(false); }); it('returns false if txMeta has no custodyStatus', () => { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const txMeta = { to: toMocked } as any; const result = beforeTransactionPublish(txMeta); expect(result).toBe(true); @@ -61,12 +69,16 @@ describe('MMI hooks', () => { describe('getAdditionalSignArguments', () => { it('returns an array with txMeta when custodyStatus is truthy', () => { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const txMeta = { custodyStatus: TransactionStatus.approved } as any; const result = getAdditionalSignArguments(txMeta); expect(result).toEqual([txMeta]); }); it('returns an empty array when custodyStatus is falsy', () => { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const txMeta = { to: toMocked } as any; const result = getAdditionalSignArguments(txMeta); expect(result).toEqual([]); @@ -75,12 +87,16 @@ describe('MMI hooks', () => { describe('beforeTransactionApproveOnInit', () => { it('returns true if txMeta has custodyStatus', () => { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const txMeta = { custodyStatus: TransactionStatus.approved } as any; const result = beforeTransactionApproveOnInit(txMeta); expect(result).toBe(false); }); it('returns false if txMeta has no custodyStatus', () => { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const txMeta = { to: toMocked } as any; const result = beforeTransactionApproveOnInit(txMeta); expect(result).toBe(true); @@ -92,12 +108,16 @@ describe('MMI hooks', () => { const txMeta = { custodyStatus: TransactionStatus.approved, custodyId: 1, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any; const result = beforeCheckPendingTransaction(txMeta); expect(result).toBe(false); }); it('returns false if txMeta has no custodyStatus', () => { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const txMeta = { to: toMocked } as any; const result = beforeCheckPendingTransaction(txMeta); expect(result).toBe(true); diff --git a/app/scripts/lib/transaction/mmi-hooks.ts b/app/scripts/lib/transaction/mmi-hooks.ts index 92ea0cf792b9..d4dc3cc4dcda 100644 --- a/app/scripts/lib/transaction/mmi-hooks.ts +++ b/app/scripts/lib/transaction/mmi-hooks.ts @@ -9,6 +9,8 @@ import { TransactionMeta } from '@metamask/transaction-controller'; */ export function afterTransactionSign( txMeta: TransactionMeta, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any signedEthTx: any, addTransactionToWatchList: ( custodianTransactionId: string | undefined, diff --git a/app/scripts/lib/transaction/smart-transactions.test.ts b/app/scripts/lib/transaction/smart-transactions.test.ts new file mode 100644 index 000000000000..04c029c3ef8b --- /dev/null +++ b/app/scripts/lib/transaction/smart-transactions.test.ts @@ -0,0 +1,372 @@ +import EventEmitter from 'events'; +import { + TransactionType, + TransactionStatus, + TransactionController, +} from '@metamask/transaction-controller'; +import SmartTransactionsController from '@metamask/smart-transactions-controller'; +import { CHAIN_IDS } from '../../../../shared/constants/network'; +import { submitSmartTransactionHook } from './smart-transactions'; +import type { + SubmitSmartTransactionRequest, + SmartTransactionsControllerMessenger, +} from './smart-transactions'; + +const addressFrom = '0xabce7847fd3661a9b7c86aaf1daea08d9da5750e'; +const txHash = + '0x0302b75dfb9fd9eb34056af031efcaee2a8cbd799ea054a85966165cd82a7356'; +const uuid = 'uuid'; +const txId = '1'; + +let addRequestCallback: () => void; + +type SubmitSmartTransactionRequestMocked = SubmitSmartTransactionRequest & { + smartTransactionsController: jest.Mocked; + transactionController: jest.Mocked; +}; + +const createSignedTransaction = () => { + return '0xf86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a02b79f322a625d623a2bb2911e0c6b3e7eaf741a7c7c5d2e8c67ef3ff4acf146ca01ae168fea63dc3391b75b586c8a7c0cb55cdf3b8e2e4d8e097957a3a56c6f2c5'; +}; + +const createTransactionControllerMock = () => { + return { + approveTransactionsWithSameNonce: jest.fn((transactions = []) => { + return transactions.length === 0 ? [] : [createSignedTransaction()]; + }), + state: { transactions: [] }, + } as unknown as jest.Mocked; +}; + +const createSmartTransactionsControllerMessengerMock = () => { + return { + call: jest.fn((type) => { + if (type === 'ApprovalController:addRequest') { + return { + then: (callback: () => void) => { + addRequestCallback = callback; + }, + }; + } + return Promise.resolve({ id: 'approvalId' }); + }), + } as unknown as jest.Mocked; +}; + +const createSmartTransactionsControllerMock = () => { + return { + getFees: jest.fn(async () => { + return { + tradeTxFees: { + cancelFees: [], + feeEstimate: 42000000000000, + fees: [ + { maxFeePerGas: 12843636951, maxPriorityFeePerGas: 2853145236 }, + ], + gasLimit: 21000, + gasUsed: 21000, + }, + }; + }), + submitSignedTransactions: jest.fn(async () => { + return { + uuid, + txHash, + }; + }), + eventEmitter: new EventEmitter(), + } as unknown as jest.Mocked; +}; + +describe('submitSmartTransactionHook', () => { + const createRequest = () => { + return { + transactionMeta: { + hash: txHash, + status: TransactionStatus.signed, + id: '1', + txParams: { + from: addressFrom, + to: '0x1678a085c290ebd122dc42cba69373b5953b831d', + gasPrice: '0x77359400', + gas: '0x7b0d', + nonce: '0x4b', + }, + type: TransactionType.simpleSend, + chainId: CHAIN_IDS.MAINNET, + time: 1624408066355, + defaultGasEstimates: { + gas: '0x7b0d', + gasPrice: '0x77359400', + }, + error: { + name: 'Error', + message: 'Details of the error', + }, + securityProviderResponse: { + flagAsDangerous: 0, + }, + }, + smartTransactionsController: createSmartTransactionsControllerMock(), + transactionController: createTransactionControllerMock(), + isSmartTransaction: true, + controllerMessenger: createSmartTransactionsControllerMessengerMock(), + featureFlags: { + extensionActive: true, + mobileActive: false, + smartTransactions: { + expectedDeadline: 45, + maxDeadline: 150, + returnTxHashAsap: false, + }, + }, + }; + }; + + beforeEach(() => { + addRequestCallback = () => undefined; + }); + + it('does not submit a transaction that is not a smart transaction', async () => { + const request: SubmitSmartTransactionRequestMocked = createRequest(); + request.isSmartTransaction = false; + const result = await submitSmartTransactionHook(request); + expect(result).toEqual({ transactionHash: undefined }); + }); + + it('falls back to regular transaction submit if the transaction type is "swapAndSend"', async () => { + const request: SubmitSmartTransactionRequestMocked = createRequest(); + request.transactionMeta.type = TransactionType.swapAndSend; + const result = await submitSmartTransactionHook(request); + expect(result).toEqual({ transactionHash: undefined }); + }); + + it('falls back to regular transaction submit if /getFees throws an error', async () => { + const request: SubmitSmartTransactionRequestMocked = createRequest(); + jest + .spyOn(request.smartTransactionsController, 'getFees') + .mockImplementation(() => { + throw new Error('Backend call to /getFees failed'); + }); + const result = await submitSmartTransactionHook(request); + expect(request.controllerMessenger.call).toHaveBeenCalledWith( + 'ApprovalController:endFlow', + { + id: 'approvalId', + }, + ); + expect(result).toEqual({ transactionHash: undefined }); + }); + + it('returns a txHash asap if the feature flag requires it', async () => { + const request: SubmitSmartTransactionRequestMocked = createRequest(); + request.featureFlags.smartTransactions.returnTxHashAsap = true; + const result = await submitSmartTransactionHook(request); + expect(result).toEqual({ transactionHash: txHash }); + }); + + it('throws an error if there is no uuid', async () => { + const request: SubmitSmartTransactionRequestMocked = createRequest(); + request.smartTransactionsController.submitSignedTransactions = jest.fn( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async ({ signedTransactions, signedCanceledTransactions }) => { + return { uuid: undefined }; + }, + ); + await expect(submitSmartTransactionHook(request)).rejects.toThrow( + 'No smart transaction UUID', + ); + }); + + it('throws an error if there is no transaction hash', async () => { + const request: SubmitSmartTransactionRequestMocked = createRequest(); + setImmediate(() => { + request.smartTransactionsController.eventEmitter.emit( + `uuid:smartTransaction`, + { + status: 'cancelled', + statusMetadata: { + minedHash: '', + }, + }, + ); + }); + await expect(submitSmartTransactionHook(request)).rejects.toThrow( + 'Transaction does not have a transaction hash, there was a problem', + ); + }); + + it('submits a smart transaction', async () => { + const request: SubmitSmartTransactionRequestMocked = createRequest(); + setImmediate(() => { + request.smartTransactionsController.eventEmitter.emit( + `uuid:smartTransaction`, + { + status: 'pending', + statusMetadata: { + minedHash: '', + }, + }, + ); + request.smartTransactionsController.eventEmitter.emit( + `uuid:smartTransaction`, + { + status: 'success', + statusMetadata: { + minedHash: txHash, + }, + }, + ); + }); + const result = await submitSmartTransactionHook(request); + expect(result).toEqual({ transactionHash: txHash }); + const { txParams, chainId } = request.transactionMeta; + expect( + request.transactionController.approveTransactionsWithSameNonce, + ).toHaveBeenCalledWith( + [ + { + ...txParams, + maxFeePerGas: '0x2fd8a58d7', + maxPriorityFeePerGas: '0xaa0f8a94', + chainId, + }, + ], + { hasNonce: true }, + ); + expect( + request.smartTransactionsController.submitSignedTransactions, + ).toHaveBeenCalledWith({ + signedTransactions: [createSignedTransaction()], + signedCanceledTransactions: [], + txParams, + transactionMeta: request.transactionMeta, + }); + addRequestCallback(); + expect(request.controllerMessenger.call).toHaveBeenCalledTimes(4); + expect(request.controllerMessenger.call).toHaveBeenCalledWith( + 'ApprovalController:startFlow', + ); + expect(request.controllerMessenger.call).toHaveBeenCalledWith( + 'ApprovalController:addRequest', + { + id: 'approvalId', + origin: 'http://localhost', + type: 'smartTransaction:showSmartTransactionStatusPage', + requestState: { + smartTransaction: { + status: 'pending', + uuid, + creationTime: expect.any(Number), + }, + isDapp: true, + txId, + }, + }, + true, + ); + expect(request.controllerMessenger.call).toHaveBeenCalledWith( + 'ApprovalController:updateRequestState', + { + id: 'approvalId', + requestState: { + smartTransaction: { + status: 'success', + statusMetadata: { + minedHash: + '0x0302b75dfb9fd9eb34056af031efcaee2a8cbd799ea054a85966165cd82a7356', + }, + }, + isDapp: true, + txId, + }, + }, + ); + + expect(request.controllerMessenger.call).toHaveBeenCalledWith( + 'ApprovalController:endFlow', + { + id: 'approvalId', + }, + ); + }); + + it('submits a smart transaction and does not update approval request if approval was already approved or rejected', async () => { + const request: SubmitSmartTransactionRequestMocked = createRequest(); + setImmediate(() => { + request.smartTransactionsController.eventEmitter.emit( + `uuid:smartTransaction`, + { + status: 'pending', + uuid, + statusMetadata: { + minedHash: '', + }, + }, + ); + addRequestCallback(); + request.smartTransactionsController.eventEmitter.emit( + `uuid:smartTransaction`, + { + status: 'success', + uuid, + statusMetadata: { + minedHash: txHash, + }, + }, + ); + }); + const result = await submitSmartTransactionHook(request); + expect(result).toEqual({ transactionHash: txHash }); + const { txParams, chainId } = request.transactionMeta; + expect( + request.transactionController.approveTransactionsWithSameNonce, + ).toHaveBeenCalledWith( + [ + { + ...txParams, + maxFeePerGas: '0x2fd8a58d7', + maxPriorityFeePerGas: '0xaa0f8a94', + chainId, + }, + ], + { hasNonce: true }, + ); + expect( + request.smartTransactionsController.submitSignedTransactions, + ).toHaveBeenCalledWith({ + signedTransactions: [createSignedTransaction()], + signedCanceledTransactions: [], + txParams, + transactionMeta: request.transactionMeta, + }); + expect(request.controllerMessenger.call).toHaveBeenCalledTimes(3); + expect(request.controllerMessenger.call).toHaveBeenCalledWith( + 'ApprovalController:startFlow', + ); + expect(request.controllerMessenger.call).toHaveBeenCalledWith( + 'ApprovalController:addRequest', + { + id: 'approvalId', + origin: 'http://localhost', + type: 'smartTransaction:showSmartTransactionStatusPage', + requestState: { + smartTransaction: { + status: 'pending', + uuid, + creationTime: expect.any(Number), + }, + isDapp: true, + txId, + }, + }, + true, + ); + expect(request.controllerMessenger.call).toHaveBeenCalledWith( + 'ApprovalController:endFlow', + { + id: 'approvalId', + }, + ); + }); +}); diff --git a/app/scripts/lib/transaction/smart-transactions.ts b/app/scripts/lib/transaction/smart-transactions.ts new file mode 100644 index 000000000000..97e37965d6ea --- /dev/null +++ b/app/scripts/lib/transaction/smart-transactions.ts @@ -0,0 +1,345 @@ +import SmartTransactionsController from '@metamask/smart-transactions-controller'; +import { + Fee, + Fees, + SmartTransactionStatuses, + SmartTransaction, +} from '@metamask/smart-transactions-controller/dist/types'; +import type { Hex } from '@metamask/utils'; +import { + TransactionController, + TransactionMeta, + TransactionParams, + TransactionType, +} from '@metamask/transaction-controller'; +import log from 'loglevel'; +import { + RestrictedControllerMessenger, + EventConstraint, +} from '@metamask/base-controller'; +import { + AddApprovalRequest, + UpdateRequestState, + StartFlow, + EndFlow, +} from '@metamask/approval-controller'; + +import { decimalToHex } from '../../../../shared/modules/conversion.utils'; +import { CANCEL_GAS_LIMIT_DEC } from '../../../../shared/constants/smartTransactions'; +import { + SMART_TRANSACTION_CONFIRMATION_TYPES, + ORIGIN_METAMASK, +} from '../../../../shared/constants/app'; + +const namespace = 'SmartTransactions'; + +type AllowedActions = + | AddApprovalRequest + | UpdateRequestState + | StartFlow + | EndFlow; + +export type SmartTransactionsControllerMessenger = + RestrictedControllerMessenger< + typeof namespace, + AllowedActions, + EventConstraint, + AllowedActions['type'], + never + >; + +export type FeatureFlags = { + extensionActive: boolean; + mobileActive: boolean; + smartTransactions: { + expectedDeadline?: number; + maxDeadline?: number; + returnTxHashAsap?: boolean; + }; +}; + +export type SubmitSmartTransactionRequest = { + transactionMeta: TransactionMeta; + smartTransactionsController: SmartTransactionsController; + transactionController: TransactionController; + isSmartTransaction: boolean; + controllerMessenger: SmartTransactionsControllerMessenger; + featureFlags: FeatureFlags; +}; + +class SmartTransactionHook { + #approvalFlowEnded: boolean; + + #approvalFlowId: string; + + #chainId: Hex; + + #controllerMessenger: SmartTransactionsControllerMessenger; + + #featureFlags: { + extensionActive: boolean; + mobileActive: boolean; + smartTransactions: { + expectedDeadline?: number; + maxDeadline?: number; + returnTxHashAsap?: boolean; + }; + }; + + #isDapp: boolean; + + #isSmartTransaction: boolean; + + #smartTransactionsController: SmartTransactionsController; + + #transactionController: TransactionController; + + #transactionMeta: TransactionMeta; + + #txParams: TransactionParams; + + constructor(request: SubmitSmartTransactionRequest) { + const { + transactionMeta, + smartTransactionsController, + transactionController, + isSmartTransaction, + controllerMessenger, + featureFlags, + } = request; + this.#approvalFlowId = ''; + this.#approvalFlowEnded = false; + this.#transactionMeta = transactionMeta; + this.#smartTransactionsController = smartTransactionsController; + this.#transactionController = transactionController; + this.#isSmartTransaction = isSmartTransaction; + this.#controllerMessenger = controllerMessenger; + this.#featureFlags = featureFlags; + this.#isDapp = transactionMeta.origin !== ORIGIN_METAMASK; + this.#chainId = transactionMeta.chainId; + this.#txParams = transactionMeta.txParams; + } + + async submit() { + const isUnsupportedTransactionTypeForSmartTransaction = + this.#transactionMeta?.type === TransactionType.swapAndSend; + + // Will cause TransactionController to publish to the RPC provider as normal. + const useRegularTransactionSubmit = { transactionHash: undefined }; + if ( + !this.#isSmartTransaction || + isUnsupportedTransactionTypeForSmartTransaction + ) { + return useRegularTransactionSubmit; + } + const { id: approvalFlowId } = await this.#controllerMessenger.call( + 'ApprovalController:startFlow', + ); + this.#approvalFlowId = approvalFlowId; + let getFeesResponse; + try { + getFeesResponse = await this.#smartTransactionsController.getFees( + { ...this.#txParams, chainId: this.#chainId }, + undefined, + ); + } catch (error) { + log.error( + 'Error in smart transaction publish hook, falling back to regular transaction submission', + error, + ); + this.#onApproveOrReject(); + return useRegularTransactionSubmit; // Fallback to regular transaction submission. + } + try { + const submitTransactionResponse = await this.#signAndSubmitTransactions({ + getFeesResponse, + }); + const uuid = submitTransactionResponse?.uuid; + if (!uuid) { + throw new Error('No smart transaction UUID'); + } + const returnTxHashAsap = + this.#featureFlags?.smartTransactions?.returnTxHashAsap; + this.#addApprovalRequest({ + uuid, + }); + this.#addListenerToUpdateStatusPage({ + uuid, + }); + let transactionHash: string | undefined | null; + if (returnTxHashAsap && submitTransactionResponse?.txHash) { + transactionHash = submitTransactionResponse.txHash; + } else { + transactionHash = await this.#waitForTransactionHash({ + uuid, + }); + } + if (transactionHash === null) { + throw new Error( + 'Transaction does not have a transaction hash, there was a problem', + ); + } + return { transactionHash }; + } catch (error) { + log.error('Error in smart transaction publish hook', error); + this.#onApproveOrReject(); + throw error; + } + } + + #onApproveOrReject() { + if (this.#approvalFlowEnded) { + return; + } + this.#approvalFlowEnded = true; + this.#controllerMessenger.call('ApprovalController:endFlow', { + id: this.#approvalFlowId, + }); + } + + #addApprovalRequest({ uuid }: { uuid: string }) { + const onApproveOrRejectWrapper = () => { + this.#onApproveOrReject(); + }; + this.#controllerMessenger + .call( + 'ApprovalController:addRequest', + { + id: this.#approvalFlowId, + origin, + type: SMART_TRANSACTION_CONFIRMATION_TYPES.showSmartTransactionStatusPage, + requestState: { + smartTransaction: { + status: SmartTransactionStatuses.PENDING, + creationTime: Date.now(), + uuid, + }, + isDapp: this.#isDapp, + txId: this.#transactionMeta.id, + }, + }, + true, + ) + .then(onApproveOrRejectWrapper, onApproveOrRejectWrapper); + } + + async #updateApprovalRequest({ + smartTransaction, + }: { + smartTransaction: SmartTransaction; + }) { + return await this.#controllerMessenger.call( + 'ApprovalController:updateRequestState', + { + id: this.#approvalFlowId, + requestState: { + smartTransaction, + isDapp: this.#isDapp, + txId: this.#transactionMeta.id, + }, + }, + ); + } + + async #addListenerToUpdateStatusPage({ uuid }: { uuid: string }) { + this.#smartTransactionsController.eventEmitter.on( + `${uuid}:smartTransaction`, + async (smartTransaction: SmartTransaction) => { + const { status } = smartTransaction; + if (!status || status === SmartTransactionStatuses.PENDING) { + return; + } + if (!this.#approvalFlowEnded) { + await this.#updateApprovalRequest({ + smartTransaction, + }); + } + }, + ); + } + + #waitForTransactionHash({ uuid }: { uuid: string }): Promise { + return new Promise((resolve) => { + this.#smartTransactionsController.eventEmitter.on( + `${uuid}:smartTransaction`, + async (smartTransaction: SmartTransaction) => { + const { status, statusMetadata } = smartTransaction; + if (!status || status === SmartTransactionStatuses.PENDING) { + return; + } + log.debug('Smart Transaction: ', smartTransaction); + if (statusMetadata?.minedHash) { + log.debug( + 'Smart Transaction - Received tx hash: ', + statusMetadata?.minedHash, + ); + resolve(statusMetadata.minedHash); + } else { + resolve(null); + } + }, + ); + }); + } + + async #signAndSubmitTransactions({ + getFeesResponse, + }: { + getFeesResponse: Fees; + }) { + const signedTransactions = await this.#createSignedTransactions( + getFeesResponse.tradeTxFees?.fees ?? [], + false, + ); + const signedCanceledTransactions = await this.#createSignedTransactions( + getFeesResponse.tradeTxFees?.cancelFees || [], + true, + ); + return await this.#smartTransactionsController.submitSignedTransactions({ + signedTransactions, + signedCanceledTransactions, + txParams: this.#txParams, + transactionMeta: this.#transactionMeta, + }); + } + + #applyFeeToTransaction(fee: Fee, isCancel: boolean): TransactionParams { + const unsignedTransaction = { + ...this.#txParams, + maxFeePerGas: `0x${decimalToHex(fee.maxFeePerGas)}`, + maxPriorityFeePerGas: `0x${decimalToHex(fee.maxPriorityFeePerGas)}`, + gas: isCancel + ? `0x${decimalToHex(CANCEL_GAS_LIMIT_DEC)}` // It has to be 21000 for cancel transactions, otherwise the API would reject it. + : this.#txParams.gas, + }; + if (isCancel) { + unsignedTransaction.to = unsignedTransaction.from; + unsignedTransaction.data = '0x'; + } + return unsignedTransaction; + } + + async #createSignedTransactions( + fees: Fee[], + isCancel: boolean, + ): Promise { + const unsignedTransactions = fees.map((fee) => { + return this.#applyFeeToTransaction(fee, isCancel); + }); + const transactionsWithChainId = unsignedTransactions.map((tx) => ({ + ...tx, + chainId: tx.chainId || this.#chainId, + })); + return (await this.#transactionController.approveTransactionsWithSameNonce( + transactionsWithChainId, + { hasNonce: true }, + )) as string[]; + } +} + +export const submitSmartTransactionHook = ( + request: SubmitSmartTransactionRequest, +) => { + const smartTransactionHook = new SmartTransactionHook(request); + return smartTransactionHook.submit(); +}; diff --git a/app/scripts/lib/transaction/util.test.ts b/app/scripts/lib/transaction/util.test.ts index 481f6a76c2a8..782a27e87cb1 100644 --- a/app/scripts/lib/transaction/util.test.ts +++ b/app/scripts/lib/transaction/util.test.ts @@ -7,7 +7,16 @@ import { } from '@metamask/transaction-controller'; import { UserOperationController } from '@metamask/user-operation-controller'; import { cloneDeep } from 'lodash'; -import { PPOMController } from '@metamask/ppom-validator'; +import { + generateSecurityAlertId, + validateRequestWithPPOM, +} from '../ppom/ppom-util'; +import { + BlockaidReason, + BlockaidResultType, +} from '../../../../shared/constants/security-provider'; +import { SecurityAlertResponse } from '../ppom/types'; +import { flushPromises } from '../../../../test/lib/timer-helpers'; import { AddDappTransactionRequest, AddTransactionOptions, @@ -16,6 +25,8 @@ import { addTransaction, } from './util'; +jest.mock('../ppom/ppom-util'); + jest.mock('uuid', () => { const actual = jest.requireActual('uuid'); @@ -25,6 +36,8 @@ jest.mock('uuid', () => { }; }); +const SECURITY_ALERT_ID_MOCK = '123'; + const TRANSACTION_PARAMS_MOCK: TransactionParams = { from: '0x1', }; @@ -58,6 +71,11 @@ const TRANSACTION_REQUEST_MOCK: AddTransactionRequest = { waitForSubmit: false, } as AddTransactionRequest; +const SECURITY_ALERT_RESPONSE_MOCK: SecurityAlertResponse = { + result_type: BlockaidResultType.Malicious, + reason: BlockaidReason.maliciousDomain, +}; + function createTransactionControllerMock() { return { addTransaction: jest.fn(), @@ -72,28 +90,14 @@ function createUserOperationControllerMock() { } as unknown as jest.Mocked; } -///: BEGIN:ONLY_INCLUDE_IF(blockaid) -function createPPOMControllerMock() { - return { - usePPOM: jest.fn().mockResolvedValue({ - reason: 'testReason', - result_type: 'testResultType', - }), - } as unknown as jest.Mocked; -} -///: END:ONLY_INCLUDE_IF - -async function flushPromises() { - return new Promise((resolve) => setImmediate(resolve)); -} - describe('Transaction Utils', () => { let request: AddTransactionRequest; let dappRequest: AddDappTransactionRequest; let transactionController: jest.Mocked; let userOperationController: jest.Mocked; ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - let ppomController: jest.Mocked; + const validateRequestWithPPOMMock = jest.mocked(validateRequestWithPPOM); + const generateSecurityAlertIdMock = jest.mocked(generateSecurityAlertId); ///: END:ONLY_INCLUDE_IF beforeEach(() => { @@ -103,8 +107,8 @@ describe('Transaction Utils', () => { transactionController = createTransactionControllerMock(); userOperationController = createUserOperationControllerMock(); ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - ppomController = createPPOMControllerMock(); - request.ppomController = ppomController; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + request.ppomController = {} as any; ///: END:ONLY_INCLUDE_IF transactionController.addTransaction.mockResolvedValue({ @@ -120,8 +124,11 @@ describe('Transaction Utils', () => { transactionHash: jest.fn().mockResolvedValue(TRANSACTION_META_MOCK.hash), }); + generateSecurityAlertIdMock.mockReturnValue(SECURITY_ALERT_ID_MOCK); + request.transactionController = transactionController; request.userOperationController = userOperationController; + request.updateSecurityAlertResponse = jest.fn(); dappRequest = { ...request, @@ -391,8 +398,12 @@ describe('Transaction Utils', () => { }); }); - describe('when blockaid is enabled', () => { - it('validates if blockaid is enabled and chain id is supported', async () => { + describe('validates using security provider', () => { + it('adds loading response to request options', async () => { + validateRequestWithPPOMMock.mockResolvedValue( + SECURITY_ALERT_RESPONSE_MOCK, + ); + await addTransaction({ ...request, securityAlertsEnabled: true, @@ -402,129 +413,130 @@ describe('Transaction Utils', () => { expect( request.transactionController.addTransaction, ).toHaveBeenCalledTimes(1); + expect( request.transactionController.addTransaction, ).toHaveBeenCalledWith(TRANSACTION_PARAMS_MOCK, { ...TRANSACTION_OPTIONS_MOCK, securityAlertResponse: { - reason: 'loading', - result_type: 'validation_in_progress', + reason: BlockaidReason.inProgress, + result_type: BlockaidResultType.Loading, + securityAlertId: SECURITY_ALERT_ID_MOCK, }, }); + }); - expect(request.ppomController.usePPOM).toHaveBeenCalledTimes(1); - expect(request.ppomController.usePPOM).toHaveBeenCalledWith( - expect.any(Function), + it('updates response after validation', async () => { + validateRequestWithPPOMMock.mockResolvedValue( + SECURITY_ALERT_RESPONSE_MOCK, ); - expect(request.ppomController.usePPOM).toHaveReturnedWith( - Promise.resolve({ - reason: 'testReason', - result_type: 'testResultType', - }), - ); - }); - it('does not validate if blockaid is enabled and chain id is not supported', async () => { await addTransaction({ ...request, securityAlertsEnabled: true, - chainId: '0xF', + chainId: '0x1', }); - expect( - request.transactionController.addTransaction, - ).toHaveBeenCalledTimes(1); - expect( - request.transactionController.addTransaction, - ).toHaveBeenCalledWith(TRANSACTION_PARAMS_MOCK, { - ...TRANSACTION_OPTIONS_MOCK, - }); + await flushPromises(); + + expect(request.updateSecurityAlertResponse).toHaveBeenCalledTimes(1); + expect(request.updateSecurityAlertResponse).toHaveBeenCalledWith( + 'eth_sendTransaction', + SECURITY_ALERT_ID_MOCK, + SECURITY_ALERT_RESPONSE_MOCK, + ); - expect(request.ppomController.usePPOM).toHaveBeenCalledTimes(0); + expect(validateRequestWithPPOMMock).toHaveBeenCalledTimes(1); }); - it('does not validate if blockaid is enabled and chain id is supported, but transaction type is swap', async () => { - const swapRequest = { ...request }; - swapRequest.transactionOptions.type = TransactionType.swap; + it('unless blockaid is disabled', async () => { await addTransaction({ - ...swapRequest, - securityAlertsEnabled: true, + ...request, + securityAlertsEnabled: false, chainId: '0x1', }); expect( request.transactionController.addTransaction, ).toHaveBeenCalledTimes(1); + expect( request.transactionController.addTransaction, - ).toHaveBeenCalledWith(TRANSACTION_PARAMS_MOCK, { - ...TRANSACTION_OPTIONS_MOCK, - type: TransactionType.swap, - }); + ).toHaveBeenCalledWith( + TRANSACTION_PARAMS_MOCK, + TRANSACTION_OPTIONS_MOCK, + ); - expect(request.ppomController.usePPOM).toHaveBeenCalledTimes(0); + expect(validateRequestWithPPOMMock).toHaveBeenCalledTimes(0); }); - it('does not validate if blockaid is enabled and chain id is supported, but transaction type is swapApproval', async () => { - const swapRequest = { ...request }; - swapRequest.transactionOptions.type = TransactionType.swapApproval; + it('unless chain is not supported', async () => { await addTransaction({ - ...swapRequest, + ...request, securityAlertsEnabled: true, - chainId: '0x1', + chainId: '0xF', }); expect( request.transactionController.addTransaction, ).toHaveBeenCalledTimes(1); + expect( request.transactionController.addTransaction, - ).toHaveBeenCalledWith(TRANSACTION_PARAMS_MOCK, { - ...TRANSACTION_OPTIONS_MOCK, - type: TransactionType.swapApproval, - }); + ).toHaveBeenCalledWith( + TRANSACTION_PARAMS_MOCK, + TRANSACTION_OPTIONS_MOCK, + ); - expect(request.ppomController.usePPOM).toHaveBeenCalledTimes(0); + expect(validateRequestWithPPOMMock).toHaveBeenCalledTimes(0); }); - }); - describe('when blockaid is disabled', () => { - it('does not validate if blockaid is disabled and chain id is supported', async () => { + it('unless transaction type is swap', async () => { + const swapRequest = { ...request }; + swapRequest.transactionOptions.type = TransactionType.swap; + await addTransaction({ - ...request, - securityAlertsEnabled: false, + ...swapRequest, + securityAlertsEnabled: true, chainId: '0x1', }); expect( request.transactionController.addTransaction, ).toHaveBeenCalledTimes(1); + expect( request.transactionController.addTransaction, ).toHaveBeenCalledWith(TRANSACTION_PARAMS_MOCK, { ...TRANSACTION_OPTIONS_MOCK, + type: TransactionType.swap, }); - expect(request.ppomController.usePPOM).toHaveBeenCalledTimes(0); + expect(validateRequestWithPPOMMock).toHaveBeenCalledTimes(0); }); - it('does not validate if blockaid is disabled and chain id is not supported', async () => { + it('unless transaction type is swapApproval', async () => { + const swapRequest = { ...request }; + swapRequest.transactionOptions.type = TransactionType.swapApproval; + await addTransaction({ - ...request, - securityAlertsEnabled: false, - chainId: '0xF', + ...swapRequest, + securityAlertsEnabled: true, + chainId: '0x1', }); expect( request.transactionController.addTransaction, ).toHaveBeenCalledTimes(1); + expect( request.transactionController.addTransaction, ).toHaveBeenCalledWith(TRANSACTION_PARAMS_MOCK, { ...TRANSACTION_OPTIONS_MOCK, + type: TransactionType.swapApproval, }); - expect(request.ppomController.usePPOM).toHaveBeenCalledTimes(0); + expect(validateRequestWithPPOMMock).toHaveBeenCalledTimes(0); }); }); }); diff --git a/app/scripts/lib/transaction/util.ts b/app/scripts/lib/transaction/util.ts index bd2396907bd5..adf24fea3ed3 100644 --- a/app/scripts/lib/transaction/util.ts +++ b/app/scripts/lib/transaction/util.ts @@ -3,68 +3,47 @@ import { TransactionController, TransactionMeta, TransactionParams, - WalletDevice, TransactionType, - SendFlowHistoryEntry, - Result, } from '@metamask/transaction-controller'; import { AddUserOperationOptions, UserOperationController, } from '@metamask/user-operation-controller'; +import type { Hex } from '@metamask/utils'; +import { addHexPrefix } from 'ethereumjs-util'; ///: BEGIN:ONLY_INCLUDE_IF(blockaid) import { PPOMController } from '@metamask/ppom-validator'; -import { captureException } from '@sentry/browser'; -import { addHexPrefix } from 'ethereumjs-util'; -import { v4 as uuid } from 'uuid'; -import { SUPPORTED_CHAIN_IDS } from '../ppom/ppom-middleware'; + +import { + generateSecurityAlertId, + handlePPOMError, + validateRequestWithPPOM, +} from '../ppom/ppom-util'; +import { SecurityAlertResponse } from '../ppom/types'; import { - BlockaidReason, - BlockaidResultType, + LOADING_SECURITY_ALERT_RESPONSE, + SECURITY_PROVIDER_EXCLUDED_TRANSACTION_TYPES, + SECURITY_PROVIDER_SUPPORTED_CHAIN_IDS, } from '../../../../shared/constants/security-provider'; ///: END:ONLY_INCLUDE_IF -/** - * Type for security alert response from transaction validator. - */ -export type SecurityAlertResponse = { - reason: string; - features?: string[]; - result_type: string; - providerRequestsCount?: Record; - securityAlertId?: string; -}; - export type AddTransactionOptions = NonNullable< - Parameters< - ( - txParams: TransactionParams, - options?: { - actionId?: string; - deviceConfirmedOn?: WalletDevice; - method?: string; - origin?: string; - requireApproval?: boolean | undefined; - securityAlertResponse?: SecurityAlertResponse; - sendFlowHistory?: SendFlowHistoryEntry[]; - swaps?: { - hasApproveTx?: boolean; - meta?: Partial; - }; - type?: TransactionType; - }, - ) => Promise - >[1] + Parameters[1] >; type BaseAddTransactionRequest = { - chainId: string; + chainId: Hex; networkClientId: string; ppomController: PPOMController; securityAlertsEnabled: boolean; selectedAccount: InternalAccount; transactionParams: TransactionParams; transactionController: TransactionController; + updateSecurityAlertResponse: ( + method: string, + securityAlertId: string, + securityAlertResponse: SecurityAlertResponse, + ) => void; userOperationController: UserOperationController; }; @@ -77,6 +56,8 @@ export type AddTransactionRequest = FinalAddTransactionRequest & { }; export type AddDappTransactionRequest = BaseAddTransactionRequest & { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any dappRequest: Record; }; @@ -109,95 +90,10 @@ export async function addDappTransaction( return (await waitForHash()) as string; } -///: BEGIN:ONLY_INCLUDE_IF(blockaid) -const PPOM_EXCLUDED_TRANSACTION_TYPES = [ - TransactionType.swap, - TransactionType.swapApproval, -]; -///: END:ONLY_INCLUDE_IF - export async function addTransaction( request: AddTransactionRequest, - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - updateSecurityAlertResponseByTxId?: ( - req: AddTransactionOptions | undefined, - securityAlertResponse: SecurityAlertResponse, - ) => void, - ///: END:ONLY_INCLUDE_IF ): Promise { - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - const { - transactionParams, - transactionOptions, - ppomController, - securityAlertsEnabled, - chainId, - } = request; - - const typeIsExcludedFromPPOM = - transactionOptions.type && - PPOM_EXCLUDED_TRANSACTION_TYPES.includes(transactionOptions.type); - - if ( - securityAlertsEnabled && - SUPPORTED_CHAIN_IDS.includes(chainId) && - !typeIsExcludedFromPPOM - ) { - try { - const ppomRequest = { - method: 'eth_sendTransaction', - id: 'actionId' in transactionOptions ? transactionOptions.actionId : '', - origin: 'origin' in transactionOptions ? transactionOptions.origin : '', - params: [ - { - from: transactionParams.from, - to: transactionParams.to, - value: transactionParams.value, - data: transactionParams.data, - }, - ], - }; - - const securityAlertId = uuid(); - - ppomController - .usePPOM(async (ppom) => { - try { - const securityAlertResponse = await ppom.validateJsonRpc( - ppomRequest, - ); - return securityAlertResponse; - } catch (e) { - captureException(e); - const errorObject = e as unknown as Error; - console.error('Error validating JSON RPC using PPOM: ', e); - const securityAlertResponse = { - securityAlertId, - result_type: BlockaidResultType.Errored, - reason: BlockaidReason.errored, - description: `${errorObject.name}: ${errorObject.message}`, - }; - return securityAlertResponse; - } - }) - .then((securityAlertResponse) => { - updateSecurityAlertResponseByTxId?.(request.transactionOptions, { - ...securityAlertResponse, - securityAlertId, - }); - }); - - request.transactionOptions.securityAlertResponse = { - reason: BlockaidResultType.Loading, - result_type: BlockaidReason.inProgress, - securityAlertId, - }; - } catch (e) { - console.error('Error validating JSON RPC using PPOM: ', e); - captureException(e); - } - } - ///: END:ONLY_INCLUDE_IF + validateSecurity(request); const { transactionMeta, waitForHash } = await addTransactionOrUserOperation( request, @@ -269,6 +165,8 @@ async function addUserOperationWithController( } = request; const { maxFeePerGas, maxPriorityFeePerGas } = transactionParams; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const { origin, requireApproval, type } = transactionOptions as any; const normalisedTransaction: TransactionParams = { @@ -323,3 +221,74 @@ function getTransactionByHash( (tx) => tx.hash === transactionHash, ); } + +function validateSecurity(request: AddTransactionRequest) { + ///: BEGIN:ONLY_INCLUDE_IF(blockaid) + const { + chainId, + ppomController, + securityAlertsEnabled, + transactionOptions, + transactionParams, + updateSecurityAlertResponse, + } = request; + + const { type } = transactionOptions; + + const typeIsExcludedFromPPOM = + SECURITY_PROVIDER_EXCLUDED_TRANSACTION_TYPES.includes( + type as TransactionType, + ); + + if ( + !securityAlertsEnabled || + !SECURITY_PROVIDER_SUPPORTED_CHAIN_IDS.includes(chainId) || + typeIsExcludedFromPPOM + ) { + return; + } + + try { + const { from, to, value, data } = transactionParams; + const { actionId, origin } = transactionOptions; + + const ppomRequest = { + method: 'eth_sendTransaction', + id: actionId ?? '', + origin: origin ?? '', + params: [ + { + from, + to, + value, + data, + }, + ], + }; + + const securityAlertId = generateSecurityAlertId(); + + validateRequestWithPPOM({ + ppomController, + request: ppomRequest, + securityAlertId, + }).then((securityAlertResponse) => { + updateSecurityAlertResponse( + ppomRequest.method, + securityAlertId, + securityAlertResponse, + ); + }); + + const loadingSecurityAlertResponse: SecurityAlertResponse = { + ...LOADING_SECURITY_ALERT_RESPONSE, + securityAlertId, + }; + + request.transactionOptions.securityAlertResponse = + loadingSecurityAlertResponse; + } catch (error) { + handlePPOMError(error, 'Error validating JSON RPC using PPOM: '); + } + ///: END:ONLY_INCLUDE_IF +} diff --git a/app/scripts/lib/tx-verification/tx-verification-middleware.test.ts b/app/scripts/lib/tx-verification/tx-verification-middleware.test.ts new file mode 100644 index 000000000000..110a2dc3040e --- /dev/null +++ b/app/scripts/lib/tx-verification/tx-verification-middleware.test.ts @@ -0,0 +1,255 @@ +import { NetworkController } from '@metamask/network-controller'; +import { JsonRpcParams, jsonrpc2, Hex } from '@metamask/utils'; +import { + EXPERIENCES_TYPE, + FIRST_PARTY_CONTRACT_NAMES, +} from '../../../../shared/constants/first-party-contracts'; +import { + createTxVerificationMiddleware, + TxParams, +} from './tx-verification-middleware'; + +const getMockNetworkController = (chainId: `0x${string}` = '0x1') => + ({ state: { providerConfig: { chainId } } } as unknown as NetworkController); + +const mockTrustedSigners: Partial> = { + [EXPERIENCES_TYPE.METAMASK_BRIDGE]: + '0xe672B534ccf9876a7554a1dD1685a2a5C2Cc8e8C', +}; + +const jsonRpcTemplate = { jsonrpc: jsonrpc2, id: 1 }; + +const getMiddlewareParams = (method: string, params: JsonRpcParams = []) => { + const req = { ...jsonRpcTemplate, method, params }; + const res = { ...jsonRpcTemplate, result: null }; + const next = jest.fn(); + const end = jest.fn(); + return { req, res, next, end }; +}; + +const getBridgeTxParams = (txParams: Partial = {}): [TxParams] => { + return [ + { + data: '0x1', + from: '0x1', + to: '0x1', + value: '0x1', + ...txParams, + }, + ]; +}; + +describe('tx verification middleware', () => { + it('ignores methods other than eth_sendTransaction', () => { + const middleware = createTxVerificationMiddleware( + getMockNetworkController(), + mockTrustedSigners, + ); + const { req, res, next, end } = getMiddlewareParams('foo'); + middleware(req, res, next, end); + + expect(next).toHaveBeenCalledTimes(1); + expect(end).not.toHaveBeenCalled(); + }); + + // @ts-expect-error Our test types are broken + it.each([ + ['null', null], + ['string', 'foo'], + ['plain object', {}], + ['empty array', []], + ['array with non-object', ['foo']], + ['non-string "data"', [{ data: 1 }]], + ['non-string "from"', [{ data: 'data', from: 1 }]], + ['non-string "to"', [{ data: 'data', from: 'from', to: 1 }]], + [ + 'non-string "value"', + [{ data: 'data', from: 'from', to: 'to', value: 1 }], + ], + [ + 'non-string "chainId"', + [{ data: 'data', from: 'from', to: 'to', value: 'value', chainId: 1 }], + ], + [ + 'non-"0x"-prefixed "chainId"', + [{ data: 'data', from: 'from', to: 'to', value: 'value', chainId: '1' }], + ], + ])( + 'ignores invalid params: %s', + (_: string, invalidParams: JsonRpcParams) => { + const middleware = createTxVerificationMiddleware( + getMockNetworkController(), + mockTrustedSigners, + ); + + const { req, res, next, end } = getMiddlewareParams( + 'eth_sendTransaction', + invalidParams, + ); + middleware(req, res, next, end); + + expect(next).toHaveBeenCalledTimes(1); + expect(end).not.toHaveBeenCalled(); + }, + ); + + // @ts-expect-error Our test types are broken + it.each(Object.keys(FIRST_PARTY_CONTRACT_NAMES['MetaMask Bridge']))( + 'ignores transactions that are not addressed to the bridge contract for chain %s', + (chainId: `0x${string}`) => { + const middleware = createTxVerificationMiddleware( + getMockNetworkController(), + mockTrustedSigners, + ); + + const { req, res, next, end } = getMiddlewareParams( + 'eth_sendTransaction', + getBridgeTxParams({ chainId, to: '0x1' }), + ); + middleware(req, res, next, end); + + expect(next).toHaveBeenCalledTimes(1); + expect(end).not.toHaveBeenCalled(); + }, + ); + + // @ts-expect-error Our test types are broken + it.each(['0x11111', '0x111', '0x222222'])( + 'ignores transactions that do not have a bridge contract deployed for chain %s', + (chainId: `0x${string}`) => { + const middleware = createTxVerificationMiddleware( + getMockNetworkController(), + mockTrustedSigners, + ); + + const { req, res, next, end } = getMiddlewareParams( + 'eth_sendTransaction', + getBridgeTxParams({ chainId, to: '0x1' }), + ); + middleware(req, res, next, end); + + expect(next).toHaveBeenCalledTimes(1); + expect(end).not.toHaveBeenCalled(); + }, + ); + + it('calls next() if reverse address mapping look up is undefined', () => { + const middleware = createTxVerificationMiddleware( + getMockNetworkController(), + mockTrustedSigners, + ); + + const { req, res, next, end } = getMiddlewareParams( + 'eth_sendTransaction', + getBridgeTxParams({ ...getFixtures().mapUndefined }), + ); + middleware(req, res, next, end); + + expect(next).toHaveBeenCalledTimes(1); + expect(end).not.toHaveBeenCalled(); + }); + + it('calls next() if chainId for `to` address does not match', () => { + const middleware = createTxVerificationMiddleware( + getMockNetworkController(), + mockTrustedSigners, + ); + + const { req, res, next, end } = getMiddlewareParams( + 'eth_sendTransaction', + getBridgeTxParams({ ...getFixtures().mapIncorrectChain }), + ); + middleware(req, res, next, end); + + expect(next).toHaveBeenCalledTimes(1); + expect(end).not.toHaveBeenCalled(); + }); + + it('calls next() if experience type for `to` address is not an experience to verify', () => { + const middleware = createTxVerificationMiddleware( + getMockNetworkController(), + mockTrustedSigners, + ); + + const { req, res, next, end } = getMiddlewareParams( + 'eth_sendTransaction', + getBridgeTxParams({ ...getFixtures().mapIncorrectExp }), + ); + middleware(req, res, next, end); + + expect(next).toHaveBeenCalledTimes(1); + expect(end).not.toHaveBeenCalled(); + }); + + it('passes through a valid bridge transaction', () => { + const middleware = createTxVerificationMiddleware( + getMockNetworkController(), + mockTrustedSigners, + ); + + const { req, res, next, end } = getMiddlewareParams( + 'eth_sendTransaction', + getBridgeTxParams({ ...getFixtures().valid }), + ); + middleware(req, res, next, end); + + expect(next).toHaveBeenCalledTimes(1); + expect(end).not.toHaveBeenCalled(); + }); + + it('rejects modified bridge transactions', () => { + const middleware = createTxVerificationMiddleware( + getMockNetworkController(), + mockTrustedSigners, + ); + + const { req, res, next, end } = getMiddlewareParams( + 'eth_sendTransaction', + getBridgeTxParams({ ...getFixtures().invalid }), + ); + middleware(req, res, next, end); + + expect(next).not.toHaveBeenCalled(); + expect(end).toHaveBeenCalledTimes(1); + }); +}); + +/** + * Returns bridge transaction validation fixtures. + * + * @returns The fixtures. + */ +function getFixtures() { + return { + mapIncorrectExp: { + data: '0x3ce33bff0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000470de4df82000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000f736f636b6574416461707465725632000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002800000000000000000000000003a23f943181408eac424116af7b7790c94cb97a50000000000000000000000003a23f943181408eac424116af7b7790c94cb97a5000000000000000000000000000000000000000000000000000000000000a4b10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000466ebb82ac1000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000009f295cd5f000000000000000000000000000e6b738da243e8fa2a0ed5915645789add5de515200000000000000000000000000000000000000000000000000000000000001280000019fd025dec0000000000000000000000000e672b534ccf9876a7554a1dd1685a2a5c2cc8e8c000000000000000000000000b8901acb165ed027e32754e0ffe830802919727f000000000000000000000000710bda329b2a6224e4b44833de30f38e7f81d564000000000000000000000000000000000000000000000000000000000000a4b100000000000000000000000000000000000000000000000000466ebb82ac1000000000000000000000000000000000000000000000000000004614942c423e000000000000000000000000000000000000000000000000000000886c98b760000000000000000000000000000000000000000000000000000000019012a41ba800000000000000000000000000000000000000000000000000000000000000c40000000000000000000000000000000000000000000000005dedaf7e04c3f5c842c30ed9a4a19baceb915cdd3e865f0dad99ffca277743a20bac00e0f366e7265f1fcad502791ff49e9c5c98e1841a090df23ce5555051da1c', + from: '0xe672b534ccf9876a7554a1dd1685a2a5c2cc8e8c', + to: '0xc7bE520a13dC023A1b34C03F4Abdab8A43653F7B', + value: '0x470de4df820000', + }, + mapIncorrectChain: { + data: '0x3ce33bff0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000470de4df82000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000f736f636b6574416461707465725632000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002800000000000000000000000003a23f943181408eac424116af7b7790c94cb97a50000000000000000000000003a23f943181408eac424116af7b7790c94cb97a5000000000000000000000000000000000000000000000000000000000000a4b10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000466ebb82ac1000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000009f295cd5f000000000000000000000000000e6b738da243e8fa2a0ed5915645789add5de515200000000000000000000000000000000000000000000000000000000000001280000019fd025dec0000000000000000000000000e672b534ccf9876a7554a1dd1685a2a5c2cc8e8c000000000000000000000000b8901acb165ed027e32754e0ffe830802919727f000000000000000000000000710bda329b2a6224e4b44833de30f38e7f81d564000000000000000000000000000000000000000000000000000000000000a4b100000000000000000000000000000000000000000000000000466ebb82ac1000000000000000000000000000000000000000000000000000004614942c423e000000000000000000000000000000000000000000000000000000886c98b760000000000000000000000000000000000000000000000000000000019012a41ba800000000000000000000000000000000000000000000000000000000000000c40000000000000000000000000000000000000000000000005dedaf7e04c3f5c842c30ed9a4a19baceb915cdd3e865f0dad99ffca277743a20bac00e0f366e7265f1fcad502791ff49e9c5c98e1841a090df23ce5555051da1c', + from: '0xe672b534ccf9876a7554a1dd1685a2a5c2cc8e8c', + to: `0xaEc23140408534b378bf5832defc426dF8604B59`, + value: '0x470de4df820000', + }, + mapUndefined: { + data: '0x3ce33bff0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000470de4df82000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000f736f636b6574416461707465725632000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002800000000000000000000000003a23f943181408eac424116af7b7790c94cb97a50000000000000000000000003a23f943181408eac424116af7b7790c94cb97a5000000000000000000000000000000000000000000000000000000000000a4b10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000466ebb82ac1000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000009f295cd5f000000000000000000000000000e6b738da243e8fa2a0ed5915645789add5de515200000000000000000000000000000000000000000000000000000000000001280000019fd025dec0000000000000000000000000e672b534ccf9876a7554a1dd1685a2a5c2cc8e8c000000000000000000000000b8901acb165ed027e32754e0ffe830802919727f000000000000000000000000710bda329b2a6224e4b44833de30f38e7f81d564000000000000000000000000000000000000000000000000000000000000a4b100000000000000000000000000000000000000000000000000466ebb82ac1000000000000000000000000000000000000000000000000000004614942c423e000000000000000000000000000000000000000000000000000000886c98b760000000000000000000000000000000000000000000000000000000019012a41ba800000000000000000000000000000000000000000000000000000000000000c40000000000000000000000000000000000000000000000005dedaf7e04c3f5c842c30ed9a4a19baceb915cdd3e865f0dad99ffca277743a20bac00e0f366e7265f1fcad502791ff49e9c5c98e1841a090df23ce5555051da1c', + from: '0xe672b534ccf9876a7554a1dd1685a2a5c2cc8e8c', + to: '0x0439e60F02a8900a951603950d8D4527f400C3f9', + value: '0x470de4df820000', + }, + valid: { + data: '0x3ce33bff0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000470de4df82000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000f736f636b6574416461707465725632000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002800000000000000000000000003a23f943181408eac424116af7b7790c94cb97a50000000000000000000000003a23f943181408eac424116af7b7790c94cb97a5000000000000000000000000000000000000000000000000000000000000a4b10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000466ebb82ac1000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000009f295cd5f000000000000000000000000000e6b738da243e8fa2a0ed5915645789add5de515200000000000000000000000000000000000000000000000000000000000001280000019fd025dec0000000000000000000000000e672b534ccf9876a7554a1dd1685a2a5c2cc8e8c000000000000000000000000b8901acb165ed027e32754e0ffe830802919727f000000000000000000000000710bda329b2a6224e4b44833de30f38e7f81d564000000000000000000000000000000000000000000000000000000000000a4b100000000000000000000000000000000000000000000000000466ebb82ac1000000000000000000000000000000000000000000000000000004614942c423e000000000000000000000000000000000000000000000000000000886c98b760000000000000000000000000000000000000000000000000000000019012a41ba800000000000000000000000000000000000000000000000000000000000000c40000000000000000000000000000000000000000000000005dedaf7e04c3f5c842c30ed9a4a19baceb915cdd3e865f0dad99ffca277743a20bac00e0f366e7265f1fcad502791ff49e9c5c98e1841a090df23ce5555051da1c', + from: '0xe672b534ccf9876a7554a1dd1685a2a5c2cc8e8c', + to: FIRST_PARTY_CONTRACT_NAMES['MetaMask Bridge']['0x1'], + value: '0x470de4df820000', + }, + invalid: { + data: '0x3ce33bff0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000470de4df82000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000d6c6966694164617074657256320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000e397c4883ec89ed4fc9d258f00c689708b2799c9000000000000000000000000e397c4883ec89ed4fc9d258f00c689708b2799c9000000000000000000000000000000000000000000000000000000000000a4b10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000466ebb82ac1000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000009f295cd5f000000000000000000000000000c8c0e780960f954c3426a32b6ab453248d632b59000000000000000000000000000000000000000000000000000000000000006c5a39b10a5d458d62482fa1e7e672b534ccf9876a7554a1dd1685a2a5c2cc8e8c0000a4b10002a9de92aa00576661f103ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd00dfeeddeadbeef8932eb23bad9bddb5cf81426f78279a53c6c3b710000000000000000000000000000000000000000', + from: '0xe672b534ccf9876a7554a1dd1685a2a5c2cc8e8c', + to: FIRST_PARTY_CONTRACT_NAMES['MetaMask Bridge']['0x1'], + value: '0x470de4df820000', + }, + } as const; +} diff --git a/app/scripts/lib/tx-verification/tx-verification-middleware.ts b/app/scripts/lib/tx-verification/tx-verification-middleware.ts new file mode 100644 index 000000000000..30782a98721b --- /dev/null +++ b/app/scripts/lib/tx-verification/tx-verification-middleware.ts @@ -0,0 +1,115 @@ +import { hashMessage } from '@ethersproject/hash'; +import { verifyMessage } from '@ethersproject/wallet'; +import type { NetworkController } from '@metamask/network-controller'; +import { rpcErrors } from '@metamask/rpc-errors'; +import { + Json, + JsonRpcParams, + hasProperty, + isObject, + Hex, +} from '@metamask/utils'; +import { + JsonRpcRequest, + JsonRpcResponse, + JsonRpcEngineEndCallback, + JsonRpcEngineNextCallback, +} from 'json-rpc-engine'; +import { + EXPERIENCES_TO_VERIFY, + getExperience, + TX_SIG_LEN, + TRUSTED_SIGNERS, +} from '../../../../shared/constants/verification'; +import { MESSAGE_TYPE } from '../../../../shared/constants/app'; + +export type TxParams = { + chainId?: `0x${string}`; + data: string; + from: string; + to: string; + value: string; +}; + +/** + * Creates a middleware function that verifies bridge transactions from the + * Portfolio. + * + * @param networkController - The network controller instance. + * @param trustedSigners + * @returns The middleware function. + */ +export function createTxVerificationMiddleware( + networkController: NetworkController, + trustedSigners = TRUSTED_SIGNERS, +) { + return function txVerificationMiddleware( + req: JsonRpcRequest, + _res: JsonRpcResponse, + next: JsonRpcEngineNextCallback, + end: JsonRpcEngineEndCallback, + ) { + if ( + req.method !== MESSAGE_TYPE.ETH_SEND_TRANSACTION || + !Array.isArray(req.params) || + !isValidParams(req.params) + ) { + return next(); + } + + // the tx object is the first element + const params = req.params[0]; + const chainId = + typeof params.chainId === 'string' + ? (params.chainId.toLowerCase() as Hex) + : networkController.state.providerConfig.chainId; + + const experienceType = getExperience( + params.to.toLowerCase() as Hex, + chainId, + ); + // if undefined then no address matched - skip OR if experience is not one we want to verify against - skip + if (!experienceType || !EXPERIENCES_TO_VERIFY.includes(experienceType)) { + return next(); + } + + const signature = `0x${params.data.slice(-TX_SIG_LEN)}`; + const addressToVerify = verifyMessage(hashParams(params), signature); + if (addressToVerify !== trustedSigners[experienceType]) { + return end(rpcErrors.invalidParams('Invalid transaction signature.')); + } + return next(); + }; +} + +function hashParams(params: TxParams): string { + const paramsToVerify = { + to: hashMessage(params.to.toLowerCase()), + from: hashMessage(params.from.toLowerCase()), + data: hashMessage( + params.data.toLowerCase().slice(0, params.data.length - TX_SIG_LEN), + ), + value: hashMessage(params.value.toLowerCase()), + }; + return hashMessage(JSON.stringify(paramsToVerify)); +} + +/** + * Checks if the params of a JSON-RPC request are valid `eth_sendTransaction` + * params. + * + * @param params - The params to validate. + * @returns Whether the params are valid. + */ +function isValidParams(params: Json[]): params is [TxParams] { + return ( + isObject(params[0]) && + typeof params[0].data === 'string' && + typeof params[0].from === 'string' && + typeof params[0].to === 'string' && + typeof params[0].value === 'string' && + (!hasProperty(params[0], 'chainId') || + (typeof params[0].chainId === 'string' && + params[0].chainId.startsWith('0x'))) + ); +} diff --git a/app/scripts/lib/util.test.js b/app/scripts/lib/util.test.js index 2ac5970493ce..1868007f7684 100644 --- a/app/scripts/lib/util.test.js +++ b/app/scripts/lib/util.test.js @@ -15,6 +15,7 @@ import { } from '../../../shared/constants/app'; import { isPrefixedFormattedHexString } from '../../../shared/modules/network.utils'; import { + shouldEmitDappViewedEvent, addUrlProtocolPrefix, deferredPromise, formatTxMetaForRpcResult, @@ -255,6 +256,19 @@ describe('app utils', () => { }); }); + describe('shouldEmitDappViewedEvent', () => { + it('should return true for valid metrics IDs', () => { + expect(shouldEmitDappViewedEvent('fake-metrics-id-fd20')).toStrictEqual( + true, + ); + }); + it('should return false for invalid metrics IDs', () => { + expect( + shouldEmitDappViewedEvent('fake-metrics-id-invalid'), + ).toStrictEqual(false); + }); + }); + describe('formatTxMetaForRpcResult', () => { it('should correctly format the tx meta object (EIP-1559)', () => { const txMeta = { diff --git a/app/scripts/lib/util.ts b/app/scripts/lib/util.ts index 77c2e8543b64..f44dc48628fa 100644 --- a/app/scripts/lib/util.ts +++ b/app/scripts/lib/util.ts @@ -181,6 +181,8 @@ export const isValidDate = (d: Date | number) => { */ type DeferredPromise = { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any promise: Promise; resolve?: () => void; reject?: () => void; @@ -274,6 +276,25 @@ export function isWebUrl(urlString: string): boolean { ); } +/** + * Determines whether to emit a MetaMetrics event for a given metaMetricsId. + * Relies on the last 4 characters of the metametricsId. Assumes the IDs are evenly distributed. + * If metaMetricsIds are distributed evenly, this should be a 1% sample rate + * + * @param metaMetricsId - The metametricsId to use for the event. + * @returns Whether to emit the event or not. + */ +export function shouldEmitDappViewedEvent(metaMetricsId: string): boolean { + if (metaMetricsId === null) { + return false; + } + + const lastFourCharacters = metaMetricsId.slice(-4); + const lastFourCharactersAsNumber = parseInt(lastFourCharacters, 16); + + return lastFourCharactersAsNumber % 100 === 0; +} + type FormattedTransactionMeta = { blockHash: string | null; blockNumber: string | null; @@ -343,3 +364,21 @@ export function formatTxMetaForRpcResult( return formattedTxMeta; } + +export const isValidAmount = (amount: number | null | undefined): boolean => + amount !== null && amount !== undefined && !Number.isNaN(amount); + +export function formatValue( + value: number | null | undefined, + includeParentheses: boolean, +): string { + if (!isValidAmount(value)) { + return ''; + } + + const numericValue = value as number; + const sign = numericValue >= 0 ? '+' : ''; + const formattedNumber = `${sign}${numericValue.toFixed(2)}%`; + + return includeParentheses ? `(${formattedNumber})` : formattedNumber; +} diff --git a/app/scripts/metamask-controller.actions.test.js b/app/scripts/metamask-controller.actions.test.js index 31dcd6d5bf36..29ba6f11515a 100644 --- a/app/scripts/metamask-controller.actions.test.js +++ b/app/scripts/metamask-controller.actions.test.js @@ -1,6 +1,6 @@ -import { strict as assert } from 'assert'; -import sinon from 'sinon'; -import proxyquire from 'proxyquire'; +/** + * @jest-environment node + */ import { ListNames, METAMASK_STALELIST_URL, @@ -13,8 +13,9 @@ import { ApprovalRequestNotFoundError } from '@metamask/approval-controller'; import { PermissionsRequestNotFoundError } from '@metamask/permission-controller'; import nock from 'nock'; import mockEncryptor from '../../test/lib/mock-encryptor'; +import MetaMaskController from './metamask-controller'; -const { Ganache } = require('../../test/e2e/ganache'); +const { Ganache } = require('../../test/e2e/seeder/ganache'); const ganacheServer = new Ganache(); @@ -31,13 +32,23 @@ const browserPolyfillMock = { }, storage: { local: { - get: sinon.stub().resolves({}), - set: sinon.stub().resolves(), + get: jest.fn().mockReturnValue({}), + set: jest.fn(), }, }, }; let loggerMiddlewareMock; +const initializeMockMiddlewareLog = () => { + loggerMiddlewareMock = { + requests: [], + responses: [], + }; +}; +const tearDownMockMiddlewareLog = () => { + loggerMiddlewareMock = undefined; +}; + const createLoggerMiddlewareMock = () => (req, res, next) => { if (loggerMiddlewareMock) { loggerMiddlewareMock.requests.push(req); @@ -49,20 +60,16 @@ const createLoggerMiddlewareMock = () => (req, res, next) => { } next(); }; +jest.mock('./lib/createLoggerMiddleware', () => createLoggerMiddlewareMock); const TEST_SEED = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium'; -const MetaMaskController = proxyquire('./metamask-controller', { - './lib/createLoggerMiddleware': { default: createLoggerMiddlewareMock }, -}).default; - describe('MetaMaskController', function () { let metamaskController; - const sandbox = sinon.createSandbox(); const noop = () => undefined; - before(async function () { + beforeAll(async function () { await ganacheServer.start(); }); @@ -106,27 +113,27 @@ describe('MetaMaskController', function () { browser: browserPolyfillMock, infuraProjectId: 'foo', }); + initializeMockMiddlewareLog(); }); afterEach(function () { - sandbox.restore(); + jest.restoreAllMocks(); nock.cleanAll(); + tearDownMockMiddlewareLog(); }); - after(async function () { + afterAll(async function () { await ganacheServer.quit(); }); describe('Phishing Detection Mock', function () { it('should be updated to use v1 of the API', function () { // Update the fixture above if this test fails - assert.equal( - METAMASK_STALELIST_URL, - 'https://phishing-detection.metafi.codefi.network/v1/stalelist', + expect(METAMASK_STALELIST_URL).toStrictEqual( + 'https://phishing-detection.api.cx.metamask.io/v1/stalelist', ); - assert.equal( - METAMASK_HOTLIST_DIFF_URL, - 'https://phishing-detection.metafi.codefi.network/v1/diffsSince', + expect(METAMASK_HOTLIST_DIFF_URL).toStrictEqual( + 'https://phishing-detection.api.cx.metamask.io/v1/diffsSince', ); }); }); @@ -138,86 +145,74 @@ describe('MetaMaskController', function () { metamaskController.addNewAccount(1), metamaskController.addNewAccount(1), ]); - assert.equal(addNewAccountResult1, addNewAccountResult2); + expect(addNewAccountResult1).toStrictEqual(addNewAccountResult2); }); it('two successive calls with same accountCount give same result', async function () { await metamaskController.createNewVaultAndKeychain('test@123'); const addNewAccountResult1 = await metamaskController.addNewAccount(1); const addNewAccountResult2 = await metamaskController.addNewAccount(1); - assert.equal(addNewAccountResult1, addNewAccountResult2); + expect(addNewAccountResult1).toStrictEqual(addNewAccountResult2); }); it('two successive calls with different accountCount give different results', async function () { await metamaskController.createNewVaultAndKeychain('test@123'); const addNewAccountResult1 = await metamaskController.addNewAccount(1); const addNewAccountResult2 = await metamaskController.addNewAccount(2); - assert.notEqual(addNewAccountResult1, addNewAccountResult2); + expect(addNewAccountResult1).not.toStrictEqual(addNewAccountResult2); }); }); describe('#importAccountWithStrategy', function () { - it('two sequential calls with same strategy give same result', async function () { - let keyringControllerState1; - let keyringControllerState2; + it('throws an error when importing the same account twice', async function () { const importPrivkey = '4cfd3e90fc78b0f86bf7524722150bb8da9c60cd532564d7ff43f5716514f553'; - await metamaskController.createNewVaultAndKeychain('test@123'); - await Promise.all([ + + await metamaskController.importAccountWithStrategy('privateKey', [ + importPrivkey, + ]); + + await expect( metamaskController.importAccountWithStrategy('privateKey', [ importPrivkey, ]), - Promise.resolve(1).then(() => { - keyringControllerState1 = JSON.stringify( - metamaskController.keyringController.state, - ); - metamaskController.importAccountWithStrategy('privateKey', [ - importPrivkey, - ]); - }), - Promise.resolve(2).then(() => { - keyringControllerState2 = JSON.stringify( - metamaskController.keyringController.state, - ); - }), - ]); - assert.deepEqual(keyringControllerState1, keyringControllerState2); + ).rejects.toThrow( + 'KeyringController - The account you are trying to import is a duplicate', + ); }); }); describe('#createNewVaultAndRestore', function () { it('two successive calls with same inputs give same result', async function () { - const result1 = await metamaskController.createNewVaultAndRestore( - 'test@123', - TEST_SEED, - ); - const result2 = await metamaskController.createNewVaultAndRestore( - 'test@123', - TEST_SEED, - ); - assert.deepEqual(result1, result2); + await metamaskController.createNewVaultAndRestore('test@123', TEST_SEED); + const result1 = metamaskController.keyringController.state; + await metamaskController.createNewVaultAndRestore('test@123', TEST_SEED); + const result2 = metamaskController.keyringController.state; + expect(result1).toStrictEqual(result2); }); }); describe('#createNewVaultAndKeychain', function () { it('two successive calls with same inputs give same result', async function () { - const result1 = await metamaskController.createNewVaultAndKeychain( - 'test@123', - ); - const result2 = await metamaskController.createNewVaultAndKeychain( - 'test@123', - ); - assert.notEqual(result1, undefined); - assert.deepEqual(result1, result2); + await metamaskController.createNewVaultAndKeychain('test@123'); + const result1 = metamaskController.keyringController.state; + await metamaskController.createNewVaultAndKeychain('test@123'); + const result2 = metamaskController.keyringController.state; + expect(result1).not.toStrictEqual(undefined); + expect(result1).toStrictEqual(result2); }); }); describe('#setLocked', function () { it('should lock the wallet', async function () { - const { isUnlocked, keyrings } = await metamaskController.setLocked(); - assert(!isUnlocked); - assert.deepEqual(keyrings, []); + await metamaskController.setLocked(); + expect( + metamaskController.keyringController.state.isUnlocked, + ).toStrictEqual(false); + expect(metamaskController.keyringController.state.keyrings).toStrictEqual( + [], + ); }); }); @@ -227,38 +222,26 @@ describe('MetaMaskController', function () { const decimals = 18; it('two parallel calls with same token details give same result', async function () { - const supportsInterfaceStub = sinon - .stub() - .returns(Promise.resolve(false)); - sinon - .stub(metamaskController.tokensController, '_createEthersContract') - .callsFake(() => - Promise.resolve({ supportsInterface: supportsInterfaceStub }), - ); + const supportsInterfaceStub = jest.fn().mockResolvedValue(false); + jest + .spyOn(metamaskController.tokensController, '_createEthersContract') + .mockResolvedValue({ supportsInterface: supportsInterfaceStub }); const [token1, token2] = await Promise.all([ metamaskController.getApi().addToken({ address, symbol, decimals }), metamaskController.getApi().addToken({ address, symbol, decimals }), ]); - assert.deepEqual(token1, token2); + expect(token1).toStrictEqual(token2); }); it('networkClientId is used when provided', async function () { - const supportsInterfaceStub = sinon - .stub() - .returns(Promise.resolve(false)); - sinon - .stub(metamaskController.tokensController, '_createEthersContract') - .callsFake(() => - Promise.resolve({ supportsInterface: supportsInterfaceStub }), - ); - sinon - .stub(metamaskController.controllerMessenger, 'call') - .callsFake(() => ({ - configuration: { - chainId: '0xa', - }, - })); + const supportsInterfaceStub = jest.fn().mockResolvedValue(false); + jest + .spyOn(metamaskController.tokensController, '_createEthersContract') + .mockResolvedValue({ supportsInterface: supportsInterfaceStub }); + const callSpy = jest + .spyOn(metamaskController.controllerMessenger, 'call') + .mockReturnValue({ configuration: { chainId: '0xa' } }); await metamaskController.getApi().addToken({ address, @@ -266,10 +249,10 @@ describe('MetaMaskController', function () { decimals, networkClientId: 'networkClientId1', }); - assert.deepStrictEqual( - metamaskController.controllerMessenger.call.getCall(0).args, - ['NetworkController:getNetworkClientById', 'networkClientId1'], - ); + expect(callSpy.mock.calls[0]).toStrictEqual([ + 'NetworkController:getNetworkClientById', + 'networkClientId1', + ]); }); }); @@ -281,8 +264,9 @@ describe('MetaMaskController', function () { throw error; }, }; - // Line below will not throw error, in case it throws this test case will fail. - metamaskController.removePermissionsFor({ subject: 'test_subject' }); + expect(() => + metamaskController.removePermissionsFor({ subject: 'test_subject' }), + ).not.toThrow(error); }); it('should propagate Error other than PermissionsRequestNotFoundError', function () { @@ -292,9 +276,9 @@ describe('MetaMaskController', function () { throw error; }, }; - assert.throws(() => { - metamaskController.removePermissionsFor({ subject: 'test_subject' }); - }, error); + expect(() => + metamaskController.removePermissionsFor({ subject: 'test_subject' }), + ).toThrow(error); }); }); @@ -306,8 +290,9 @@ describe('MetaMaskController', function () { throw error; }, }; - // Line below will not throw error, in case it throws this test case will fail. - metamaskController.rejectPermissionsRequest('DUMMY_ID'); + expect(() => + metamaskController.rejectPermissionsRequest('DUMMY_ID'), + ).not.toThrow(error); }); it('should propagate Error other than PermissionsRequestNotFoundError', function () { @@ -317,9 +302,9 @@ describe('MetaMaskController', function () { throw error; }, }; - assert.throws(() => { - metamaskController.rejectPermissionsRequest('DUMMY_ID'); - }, error); + expect(() => + metamaskController.rejectPermissionsRequest('DUMMY_ID'), + ).toThrow(error); }); }); @@ -331,8 +316,9 @@ describe('MetaMaskController', function () { throw error; }, }; - // Line below will not throw error, in case it throws this test case will fail. - metamaskController.acceptPermissionsRequest('DUMMY_ID'); + expect(() => + metamaskController.acceptPermissionsRequest('DUMMY_ID'), + ).not.toThrow(error); }); it('should propagate Error other than PermissionsRequestNotFoundError', function () { @@ -342,9 +328,9 @@ describe('MetaMaskController', function () { throw error; }, }; - assert.throws(() => { - metamaskController.acceptPermissionsRequest('DUMMY_ID'); - }, error); + expect(() => + metamaskController.acceptPermissionsRequest('DUMMY_ID'), + ).toThrow(error); }); }); @@ -356,25 +342,21 @@ describe('MetaMaskController', function () { throw error; }, }; - // Line below will not throw error, in case it throws this test case will fail. - await metamaskController.resolvePendingApproval( - 'DUMMY_ID', - 'DUMMY_VALUE', - ); + await expect( + metamaskController.resolvePendingApproval('DUMMY_ID', 'DUMMY_VALUE'), + ).resolves.not.toThrow(error); }); - it('should propagate Error other than ApprovalRequestNotFoundError', function () { + it('should propagate Error other than ApprovalRequestNotFoundError', async function () { const error = new Error(); metamaskController.approvalController = { accept: () => { throw error; }, }; - assert.rejects( - () => - metamaskController.resolvePendingApproval('DUMMY_ID', 'DUMMY_VALUE'), - error, - ); + await expect( + metamaskController.resolvePendingApproval('DUMMY_ID', 'DUMMY_VALUE'), + ).rejects.toThrow(error); }); }); @@ -386,12 +368,13 @@ describe('MetaMaskController', function () { throw error; }, }; - // Line below will not throw error, in case it throws this test case will fail. - metamaskController.rejectPendingApproval('DUMMY_ID', { - code: 1, - message: 'DUMMY_MESSAGE', - data: 'DUMMY_DATA', - }); + expect(() => + metamaskController.rejectPendingApproval('DUMMY_ID', { + code: 1, + message: 'DUMMY_MESSAGE', + data: 'DUMMY_DATA', + }), + ).not.toThrow(error); }); it('should propagate Error other than ApprovalRequestNotFoundError', function () { @@ -401,13 +384,13 @@ describe('MetaMaskController', function () { throw error; }, }; - assert.throws(() => { + expect(() => metamaskController.rejectPendingApproval('DUMMY_ID', { code: 1, message: 'DUMMY_MESSAGE', data: 'DUMMY_DATA', - }); - }, error); + }), + ).toThrow(error); }); }); }); diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 89905caaeffa..298691e95695 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1,5 +1,5 @@ import EventEmitter from 'events'; -import pump from 'pump'; +import { pipeline } from 'readable-stream'; import { AssetsContractController, CurrencyRateController, @@ -10,6 +10,8 @@ import { TokenRatesController, TokensController, CodefiTokenPricesServiceV2, + RatesController, + fetchMultiExchangeRate, } from '@metamask/assets-controllers'; import { ObservableStore } from '@metamask/obs-store'; import { storeAsStream } from '@metamask/obs-store/dist/asStream'; @@ -24,8 +26,10 @@ import { wrap, ///: END:ONLY_INCLUDE_IF } from 'lodash'; -import { keyringBuilderFactory } from '@metamask/eth-keyring-controller'; -import { KeyringController } from '@metamask/keyring-controller'; +import { + KeyringController, + keyringBuilderFactory, +} from '@metamask/keyring-controller'; import createFilterMiddleware from '@metamask/eth-json-rpc-filters'; import createSubscriptionManager from '@metamask/eth-json-rpc-filters/subscriptionManager'; import { @@ -63,6 +67,7 @@ import { NetworkController } from '@metamask/network-controller'; import { GasFeeController } from '@metamask/gas-fee-controller'; import { PermissionController, + PermissionDoesNotExistError, PermissionsRequestNotFoundError, SubjectMetadataController, SubjectType, @@ -110,11 +115,6 @@ import { SignatureController } from '@metamask/signature-controller'; import { PPOMController } from '@metamask/ppom-validator'; ///: END:ONLY_INCLUDE_IF -///: BEGIN:ONLY_INCLUDE_IF(desktop) -// eslint-disable-next-line import/order -import { DesktopController } from '@metamask/desktop/dist/controllers/desktop'; -///: END:ONLY_INCLUDE_IF - import { ApprovalType, ERC1155, @@ -144,15 +144,24 @@ import { TransactionType, } from '@metamask/transaction-controller'; +///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) +import { + getLocalizedSnapManifest, + stripSnapPrefix, +} from '@metamask/snaps-utils'; +///: END:ONLY_INCLUDE_IF + +import { isEvmAccountType } from '@metamask/keyring-api'; +import { + methodsRequiringNetworkSwitch, + methodsWithConfirmation, +} from '../../shared/constants/methods-tags'; + ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) import { toChecksumHexAddress } from '../../shared/modules/hexstring-utils'; ///: END:ONLY_INCLUDE_IF -import { - AssetType, - TokenStandard, - SIGNING_METHODS, -} from '../../shared/constants/transaction'; +import { AssetType, TokenStandard } from '../../shared/constants/transaction'; import { GAS_API_BASE_URL, GAS_DEV_API_BASE_URL, @@ -164,6 +173,8 @@ import { TEST_NETWORK_TICKER_MAP, NetworkStatus, } from '../../shared/constants/network'; +import { getAllowedSmartTransactionsChainIds } from '../../shared/constants/smartTransactions'; + import { HardwareDeviceNames, LedgerTransportTypes, @@ -203,8 +214,15 @@ import { parseStandardTokenTransactionData } from '../../shared/modules/transact import { STATIC_MAINNET_TOKEN_LIST } from '../../shared/constants/tokens'; import { getTokenValueParam } from '../../shared/lib/metamask-controller-utils'; import { isManifestV3 } from '../../shared/modules/mv3.utils'; -import { hexToDecimal } from '../../shared/modules/conversion.utils'; import { convertNetworkId } from '../../shared/modules/network.utils'; +import { + getIsSmartTransaction, + getFeatureFlagsByChainId, + getSmartTransactionsOptInStatus, + getCurrentChainSupportsSmartTransactions, +} from '../../shared/modules/selectors'; +import { BaseUrl } from '../../shared/constants/urls'; +import { BalancesController as MultichainBalancesController } from './lib/accounts/BalancesController'; import { ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) handleMMITransactionUpdate, @@ -228,8 +246,9 @@ import { getAdditionalSignArguments as getAdditionalSignArgumentsMMI, } from './lib/transaction/mmi-hooks'; ///: END:ONLY_INCLUDE_IF +import { submitSmartTransactionHook } from './lib/transaction/smart-transactions'; ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) -import { keyringSnapPermissionsBuilder } from './lib/keyring-snaps-permissions'; +import { keyringSnapPermissionsBuilder } from './lib/snap-keyring/keyring-snaps-permissions'; ///: END:ONLY_INCLUDE_IF import { SnapsNameProvider } from './lib/SnapsNameProvider'; @@ -250,15 +269,19 @@ import { mmiKeyringBuilderFactory } from './mmi-keyring-builder-factory'; ///: END:ONLY_INCLUDE_IF import ComposableObservableStore from './lib/ComposableObservableStore'; import AccountTracker from './lib/account-tracker'; -import createDupeReqFilterMiddleware from './lib/createDupeReqFilterMiddleware'; +import createDupeReqFilterStream from './lib/createDupeReqFilterStream'; import createLoggerMiddleware from './lib/createLoggerMiddleware'; -import { createMethodMiddleware } from './lib/rpc-method-middleware'; +import { + createLegacyMethodMiddleware, + createMethodMiddleware, + createUnsupportedMethodMiddleware, +} from './lib/rpc-method-middleware'; import createOriginMiddleware from './lib/createOriginMiddleware'; import createTabIdMiddleware from './lib/createTabIdMiddleware'; import { NetworkOrderController } from './controllers/network-order'; import { AccountOrderController } from './controllers/account-order'; import createOnboardingMiddleware from './lib/createOnboardingMiddleware'; -import { setupMultiplex } from './lib/stream-utils'; +import { isStreamWritable, setupMultiplex } from './lib/stream-utils'; import PreferencesController from './controllers/preferences'; import AppStateController from './controllers/app-state'; import AlertController from './controllers/alert'; @@ -276,6 +299,7 @@ import EncryptionPublicKeyController from './controllers/encryption-public-key'; import AppMetadataController from './controllers/app-metadata'; import { + CaveatFactories, CaveatMutatorFactories, getCaveatSpecifications, getChangedAccounts, @@ -283,10 +307,10 @@ import { getPermissionSpecifications, getPermittedAccountsByOrigin, NOTIFICATION_NAMES, + PermissionNames, unrestrictedMethods, } from './controllers/permissions'; import createRPCMethodTrackingMiddleware from './lib/createRPCMethodTrackingMiddleware'; -import { securityProviderCheck } from './lib/security-provider-helpers'; ///: BEGIN:ONLY_INCLUDE_IF(blockaid) import { IndexedDBPPOMStorage } from './lib/ppom/indexed-db-backend'; ///: END:ONLY_INCLUDE_IF @@ -299,6 +323,20 @@ import { snapKeyringBuilder, getAccountsBySnapId } from './lib/snap-keyring'; import { encryptorFactory } from './lib/encryptor-factory'; import { addDappTransaction, addTransaction } from './lib/transaction/util'; import { LatticeKeyringOffscreen } from './lib/offscreen-bridge/lattice-offscreen-keyring'; +///: BEGIN:ONLY_INCLUDE_IF(snaps) +import PREINSTALLED_SNAPS from './snaps/preinstalled-snaps'; +///: END:ONLY_INCLUDE_IF +import { WeakRefObjectMap } from './lib/WeakRefObjectMap'; + +// Notification controllers +import AuthenticationController from './controllers/authentication/authentication-controller'; +import UserStorageController from './controllers/user-storage/user-storage-controller'; +import { PushPlatformNotificationsController } from './controllers/push-platform-notifications/push-platform-notifications'; +import { MetamaskNotificationsController } from './controllers/metamask-notifications/metamask-notifications'; +import { createTxVerificationMiddleware } from './lib/tx-verification/tx-verification-middleware'; +import { updateSecurityAlertResponse } from './lib/ppom/ppom-util'; +import createEvmMethodsToNonEvmAccountReqFilterMiddleware from './lib/createEvmMethodsToNonEvmAccountReqFilterMiddleware'; +import { isEthAddress } from './lib/multichain/address'; export const METAMASK_CONTROLLER_EVENTS = { // Fired after state changes that impact the extension badge (unapproved msg count) @@ -306,6 +344,12 @@ export const METAMASK_CONTROLLER_EVENTS = { UPDATE_BADGE: 'updateBadge', // TODO: Add this and similar enums to the `controllers` repo and export them APPROVAL_STATE_CHANGE: 'ApprovalController:stateChange', + QUEUED_REQUEST_STATE_CHANGE: 'QueuedRequestController:stateChange', + METAMASK_NOTIFICATIONS_LIST_UPDATED: + 'MetamaskNotificationsController:notificationsListUpdated', + METAMASK_NOTIFICATIONS_MARK_AS_READ: + 'MetamaskNotificationsController:markNotificationsAsRead', + NOTIFICATIONS_STATE_CHANGE: 'NotificationController:stateChange', }; // stream channels @@ -339,6 +383,8 @@ export default class MetamaskController extends EventEmitter { // the only thing that uses controller connections are open metamask UI instances this.activeControllerConnections = 0; + this.offscreenPromise = opts.offscreenPromise ?? Promise.resolve(); + this.getRequestAccountTabIds = opts.getRequestAccountTabIds; this.getOpenMetamaskTabsIds = opts.getOpenMetamaskTabsIds; @@ -394,11 +440,26 @@ export default class MetamaskController extends EventEmitter { // next, we will initialize the controllers // controller initialization order matters + const clearPendingConfirmations = () => { + this.encryptionPublicKeyController.clearUnapproved(); + this.decryptMessageController.clearUnapproved(); + this.signatureController.clearUnapproved(); + this.approvalController.clear(ethErrors.provider.userRejectedRequest()); + }; this.queuedRequestController = new QueuedRequestController({ messenger: this.controllerMessenger.getRestricted({ name: 'QueuedRequestController', + allowedActions: [ + 'NetworkController:getState', + 'NetworkController:setActiveNetwork', + 'SelectedNetworkController:getNetworkClientIdForDomain', + ], + allowedEvents: ['SelectedNetworkController:stateChange'], }), + shouldRequestSwitchNetwork: ({ method }) => + methodsRequiringNetworkSwitch.includes(method), + clearPendingConfirmations, }); this.approvalController = new ApprovalController({ @@ -475,47 +536,57 @@ export default class MetamaskController extends EventEmitter { this.networkController.getProviderAndBlockTracker().provider; this.blockTracker = this.networkController.getProviderAndBlockTracker().blockTracker; - - // TODO: Delete when ready to remove `networkVersion` from provider object - this.deprecatedNetworkId = null; - this.updateDeprecatedNetworkId(); - networkControllerMessenger.subscribe( - 'NetworkController:networkDidChange', - () => this.updateDeprecatedNetworkId(), - ); + this.deprecatedNetworkVersions = {}; const tokenListMessenger = this.controllerMessenger.getRestricted({ name: 'TokenListController', allowedEvents: ['NetworkController:stateChange'], }); - this.tokenListController = new TokenListController({ - chainId: this.networkController.state.providerConfig.chainId, - preventPollingOnNetworkRestart: initState.TokenListController - ? initState.TokenListController.preventPollingOnNetworkRestart - : true, - messenger: tokenListMessenger, - state: initState.TokenListController, + const accountsControllerMessenger = this.controllerMessenger.getRestricted({ + name: 'AccountsController', + allowedEvents: [ + 'SnapController:stateChange', + 'KeyringController:accountRemoved', + 'KeyringController:stateChange', + ], + allowedActions: [ + 'KeyringController:getAccounts', + 'KeyringController:getKeyringsByType', + 'KeyringController:getKeyringForAccount', + ], + }); + + this.accountsController = new AccountsController({ + messenger: accountsControllerMessenger, + state: initState.AccountsController, }); const preferencesMessenger = this.controllerMessenger.getRestricted({ name: 'PreferencesController', - allowedActions: ['PreferencesController:getState'], - allowedEvents: ['PreferencesController:stateChange'], + allowedActions: [ + 'AccountsController:setSelectedAccount', + 'AccountsController:getAccountByAddress', + 'AccountsController:setAccountName', + ], + allowedEvents: ['AccountsController:stateChange'], }); this.preferencesController = new PreferencesController({ initState: initState.PreferencesController, initLangCode: opts.initLangCode, messenger: preferencesMessenger, - tokenListController: this.tokenListController, provider: this.provider, networkConfigurations: this.networkController.state.networkConfigurations, - onKeyringStateChange: (listener) => - this.controllerMessenger.subscribe( - 'KeyringController:stateChange', - listener, - ), + }); + + this.tokenListController = new TokenListController({ + chainId: this.networkController.state.providerConfig.chainId, + preventPollingOnNetworkRestart: !this.#isTokenListPollingRequired( + this.preferencesController.store.getState(), + ), + messenger: tokenListMessenger, + state: initState.TokenListController, }); this.assetsContractController = new AssetsContractController( @@ -598,7 +669,10 @@ export default class MetamaskController extends EventEmitter { const nftControllerMessenger = this.controllerMessenger.getRestricted({ name: 'NftController', - allowedActions: [`${this.approvalController.name}:addRequest`], + allowedActions: [ + `${this.approvalController.name}:addRequest`, + `${this.networkController.name}:getNetworkClientById`, + ], }); this.nftController = new NftController( { @@ -675,6 +749,17 @@ export default class MetamaskController extends EventEmitter { addNft: this.nftController.addNft.bind(this.nftController), getNftApi: this.nftController.getNftApi.bind(this.nftController), getNftState: () => this.nftController.state, + // added this to track previous value of useNftDetection, should be true on very first initializing of controller[] + disabled: + this.preferencesController.store.getState().useNftDetection === + undefined + ? false // the detection is enabled by default + : !this.preferencesController.store.getState().useNftDetection, + selectedAddress: + this.preferencesController.store.getState().selectedAddress, + getNetworkClientById: this.networkController.getNetworkClientById.bind( + this.networkController, + ), }); this.metaMetricsController = new MetaMetricsController({ @@ -769,6 +854,19 @@ export default class MetamaskController extends EventEmitter { messenger: currencyRateMessenger, state: initState.CurrencyController, }); + const initialFetchExchangeRate = + this.currencyRateController.fetchExchangeRate.bind( + this.currencyRateController, + ); + this.currencyRateController.fetchExchangeRate = (...args) => { + if (this.preferencesController.store.getState().useCurrencyRateCheck) { + return initialFetchExchangeRate(...args); + } + return { + conversionRate: null, + usdConversionRate: null, + }; + }; const phishingControllerMessenger = this.controllerMessenger.getRestricted({ name: 'PhishingController', @@ -781,8 +879,6 @@ export default class MetamaskController extends EventEmitter { stalelistRefreshInterval: process.env.IN_TEST ? 30 * SECOND : undefined, }); - this.phishingController.maybeUpdateState(); - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) this.ppomController = new PPOMController({ messenger: this.controllerMessenger.getRestricted({ @@ -831,30 +927,32 @@ export default class MetamaskController extends EventEmitter { state: initState.AccountOrderController, }); - const accountsControllerMessenger = this.controllerMessenger.getRestricted({ - name: 'AccountsController', - allowedEvents: [ - 'SnapController:stateChange', - 'KeyringController:accountRemoved', - 'KeyringController:stateChange', - 'AccountsController:selectedAccountChange', - ], - allowedActions: [ - 'AccountsController:setCurrentAccount', - 'AccountsController:setAccountName', - 'AccountsController:listAccounts', - 'AccountsController:getSelectedAccount', - 'AccountsController:getAccountByAddress', - 'AccountsController:updateAccounts', - 'KeyringController:getAccounts', - 'KeyringController:getKeyringsByType', - 'KeyringController:getKeyringForAccount', - ], + const multichainBalancesControllerMessenger = + this.controllerMessenger.getRestricted({ + name: 'BalancesController', + allowedEvents: [], + allowedActions: ['SnapController:handleRequest'], + }); + + this.multichainBalancesController = new MultichainBalancesController({ + messenger: multichainBalancesControllerMessenger, + state: {}, + // TODO: remove when listMultichainAccounts action is available + listMultichainAccounts: + this.accountsController.listMultichainAccounts.bind( + this.accountsController, + ), }); - this.accountsController = new AccountsController({ - messenger: accountsControllerMessenger, - state: initState.AccountsController, + const multichainRatesControllerMessenger = + this.controllerMessenger.getRestricted({ + name: 'RatesController', + }); + this.multichainRatesController = new RatesController({ + state: initState.MultichainRatesController, + messenger: multichainRatesControllerMessenger, + includeUsdRate: true, + fetchMultiExchangeRate, }); // token exchange rate tracker @@ -889,21 +987,14 @@ export default class MetamaskController extends EventEmitter { }, initState.TokenRatesController, ); - if (this.preferencesController.store.getState().useCurrencyRateCheck) { - this.tokenRatesController.start(); - } this.preferencesController.store.subscribe( previousValueComparator((prevState, currState) => { const { useCurrencyRateCheck: prevUseCurrencyRateCheck } = prevState; const { useCurrencyRateCheck: currUseCurrencyRateCheck } = currState; if (currUseCurrencyRateCheck && !prevUseCurrencyRateCheck) { - this.currencyRateController.startPollingByNetworkClientId( - this.networkController.state.selectedNetworkClientId, - ); this.tokenRatesController.start(); } else if (!currUseCurrencyRateCheck && prevUseCurrencyRateCheck) { - this.currencyRateController.stopAllPolling(); this.tokenRatesController.stop(); } }, this.preferencesController.store.getState()), @@ -970,6 +1061,7 @@ export default class MetamaskController extends EventEmitter { additionalKeyrings.push( mmiKeyringBuilderFactory(CUSTODIAN_TYPES[custodianType].keyringClass, { mmiConfigurationController: this.mmiConfigurationController, + captureException, }), ); } @@ -989,7 +1081,6 @@ export default class MetamaskController extends EventEmitter { 'PhishingController:test', 'PhishingController:maybeUpdateState', 'KeyringController:getAccounts', - 'SubjectMetadataController:getSubjectMetadata', 'AccountsController:setSelectedAccount', 'AccountsController:getAccountByAddress', ], @@ -1003,6 +1094,35 @@ export default class MetamaskController extends EventEmitter { await this.accountsController.updateAccounts(); }; + const getSnapName = (id) => { + if (!id) { + return null; + } + + const currentLocale = this.getLocale(); + const { snaps } = this.snapController.state; + const snap = snaps[id]; + + if (!snap) { + return stripSnapPrefix(id); + } + + if (snap.localizationFiles) { + const localizedManifest = getLocalizedSnapManifest( + snap.manifest, + currentLocale, + snap.localizationFiles, + ); + return localizedManifest.proposedName; + } + + return snap.manifest.proposedName; + }; + + const isSnapPreinstalled = (id) => { + return PREINSTALLED_SNAPS.some((snap) => snap.snapId === id); + }; + additionalKeyrings.push( snapKeyringBuilder( snapKeyringBuildMessenger, @@ -1011,6 +1131,8 @@ export default class MetamaskController extends EventEmitter { (address) => this.preferencesController.setSelectedAddress(address), (address) => this.removeAccount(address), this.metaMetricsController.trackEvent.bind(this.metaMetricsController), + getSnapName, + isSnapPreinstalled, ), ); @@ -1026,35 +1148,6 @@ export default class MetamaskController extends EventEmitter { state: initState.KeyringController, encryptor: opts.encryptor || encryptorFactory(600_000), messenger: keyringControllerMessenger, - removeIdentity: this.preferencesController.removeAddress.bind( - this.preferencesController, - ), - setAccountLabel: (address, label) => { - const accountToBeNamed = - this.accountsController.getAccountByAddress(address); - if (accountToBeNamed === undefined) { - throw new Error(`No account found for address: ${address}`); - } - this.accountsController.setAccountName(accountToBeNamed.id, label); - - this.preferencesController.setAccountLabel(address, label); - }, - setSelectedAddress: (address) => { - const accountToBeSet = - this.accountsController.getAccountByAddress(address); - if (accountToBeSet === undefined) { - throw new Error(`No account found for address: ${address}`); - } - - this.accountsController.setSelectedAccount(accountToBeSet.id); - this.preferencesController.setSelectedAddress(address); - }, - syncIdentities: (identities) => { - this.preferencesController.syncAddresses(identities); - }, - updateIdentities: this.preferencesController.setAddresses.bind( - this.preferencesController, - ), }); this.controllerMessenger.subscribe('KeyringController:unlock', () => @@ -1063,6 +1156,7 @@ export default class MetamaskController extends EventEmitter { this.controllerMessenger.subscribe('KeyringController:lock', () => this._onLock(), ); + this.controllerMessenger.subscribe( 'KeyringController:stateChange', (state) => { @@ -1088,6 +1182,10 @@ export default class MetamaskController extends EventEmitter { getInternalAccounts: this.accountsController.listAccounts.bind( this.accountsController, ), + findNetworkClientIdByChainId: + this.networkController.findNetworkClientIdByChainId.bind( + this.networkController, + ), }), permissionSpecifications: { ...getPermissionSpecifications({ @@ -1139,6 +1237,7 @@ export default class MetamaskController extends EventEmitter { allowedActions: [ 'NetworkController:getNetworkClientById', 'NetworkController:getState', + 'NetworkController:getSelectedNetworkClient', 'PermissionController:hasPermissions', 'PermissionController:getSubjectNames', ], @@ -1148,9 +1247,11 @@ export default class MetamaskController extends EventEmitter { ], }), state: initState.SelectedNetworkController, - getUseRequestQueue: this.preferencesController.getUseRequestQueue.bind( - this.preferencesController, - ), + useRequestQueuePreference: + this.preferencesController.store.getState().useRequestQueue, + onPreferencesStateChange: (listener) => + this.preferencesController.store.subscribe(listener), + domainProxyMap: new WeakRefObjectMap(), }); this.permissionLogController = new PermissionLogController({ @@ -1191,9 +1292,8 @@ export default class MetamaskController extends EventEmitter { iframeUrl: new URL(process.env.IFRAME_EXECUTION_ENVIRONMENT_URL), }) : new OffscreenExecutionService({ - // eslint-disable-next-line no-undef - documentUrl: chrome.runtime.getURL('./offscreen.html'), ...snapExecutionServiceArgs, + offscreenPromise: this.offscreenPromise, }); const snapControllerMessenger = this.controllerMessenger.getRestricted({ @@ -1250,6 +1350,16 @@ export default class MetamaskController extends EventEmitter { allowLocalSnaps, requireAllowlist, }, + encryptor: encryptorFactory(600_000), + getMnemonic: this.getPrimaryKeyringMnemonic.bind(this), + preinstalledSnaps: PREINSTALLED_SNAPS, + getFeatureFlags: () => { + return { + disableSnaps: + this.preferencesController.store.getState().useExternalServices === + false, + }; + }, }); this.notificationController = new NotificationController({ @@ -1331,7 +1441,6 @@ export default class MetamaskController extends EventEmitter { state: initState.SnapsRegistry, messenger: snapsRegistryMessenger, refetchOnAllowlistMiss: requireAllowlist, - failOnUnavailableRegistry: requireAllowlist, url: { registry: 'https://acl.execution.metamask.io/latest/registry.json', signature: 'https://acl.execution.metamask.io/latest/signature.json', @@ -1356,6 +1465,100 @@ export default class MetamaskController extends EventEmitter { ///: END:ONLY_INCLUDE_IF + // Notification Controllers + this.authenticationController = new AuthenticationController({ + state: initState.AuthenticationController, + messenger: this.controllerMessenger.getRestricted({ + name: 'AuthenticationController', + allowedActions: [ + 'SnapController:handleRequest', + 'UserStorageController:disableProfileSyncing', + ], + }), + metametrics: { + getMetaMetricsId: () => this.metaMetricsController.getMetaMetricsId(), + }, + }); + + this.userStorageController = new UserStorageController({ + getMetaMetricsState: () => + this.metaMetricsController.state.participateInMetaMetrics, + state: initState.UserStorageController, + messenger: this.controllerMessenger.getRestricted({ + name: 'UserStorageController', + allowedActions: [ + 'SnapController:handleRequest', + 'AuthenticationController:getBearerToken', + 'AuthenticationController:getSessionProfile', + 'AuthenticationController:isSignedIn', + 'AuthenticationController:performSignOut', + 'AuthenticationController:performSignIn', + 'MetamaskNotificationsController:disableMetamaskNotifications', + 'MetamaskNotificationsController:selectIsMetamaskNotificationsEnabled', + ], + }), + }); + + const pushPlatformNotificationsControllerMessenger = + this.controllerMessenger.getRestricted({ + name: 'PushPlatformNotificationsController', + allowedActions: ['AuthenticationController:getBearerToken'], + }); + this.pushPlatformNotificationsController = + new PushPlatformNotificationsController({ + state: initState.PushPlatformNotificationsController, + messenger: pushPlatformNotificationsControllerMessenger, + }); + pushPlatformNotificationsControllerMessenger.subscribe( + 'PushPlatformNotificationsController:onNewNotifications', + (notification) => { + this.metaMetricsController.trackEvent({ + event: MetaMetricsEventName.PushNotificationReceived, + category: MetaMetricsEventCategory.PushNotifications, + properties: { + notification_type: notification.type, + chain_id: notification?.chain_id, + }, + }); + }, + ); + pushPlatformNotificationsControllerMessenger.subscribe( + 'PushPlatformNotificationsController:pushNotificationClicked', + (notification) => { + this.metaMetricsController.trackEvent({ + event: MetaMetricsEventName.PushNotificationClicked, + category: MetaMetricsEventCategory.PushNotifications, + properties: { + notification_type: notification.type, + chain_id: notification?.chain_id, + }, + }); + }, + ); + + this.metamaskNotificationsController = new MetamaskNotificationsController({ + messenger: this.controllerMessenger.getRestricted({ + name: 'MetamaskNotificationsController', + allowedActions: [ + 'KeyringController:getAccounts', + 'AuthenticationController:getBearerToken', + 'AuthenticationController:isSignedIn', + 'UserStorageController:enableProfileSyncing', + 'UserStorageController:getStorageKey', + 'UserStorageController:performGetStorage', + 'UserStorageController:performSetStorage', + 'PushPlatformNotificationsController:enablePushNotifications', + 'PushPlatformNotificationsController:disablePushNotifications', + 'PushPlatformNotificationsController:updateTriggerPushNotifications', + ], + allowedEvents: [ + 'KeyringController:stateChange', + 'PushPlatformNotificationsController:onNewNotifications', + ], + }), + state: initState.MetamaskNotificationsController, + }); + // account tracker watches balances, nonces, and any code at their address this.accountTracker = new AccountTracker({ provider: this.provider, @@ -1371,7 +1574,7 @@ export default class MetamaskController extends EventEmitter { onboardingController: this.onboardingController, controllerMessenger: this.controllerMessenger.getRestricted({ name: 'AccountTracker', - allowedEvents: ['AccountsController:selectedAccountChange'], + allowedEvents: ['AccountsController:selectedEvmAccountChange'], allowedActions: ['AccountsController:getSelectedAccount'], }), initState: { accounts: {} }, @@ -1397,17 +1600,20 @@ export default class MetamaskController extends EventEmitter { const { completedOnboarding: prevCompletedOnboarding } = prevState; const { completedOnboarding: currCompletedOnboarding } = currState; if (!prevCompletedOnboarding && currCompletedOnboarding) { + const { address } = this.accountsController.getSelectedAccount(); + + this._addAccountsWithBalance(); + + this.postOnboardingInitialization(); this.triggerNetworkrequests(); + // execute once the token detection on the post-onboarding + await this.tokenDetectionController.detectTokens({ + selectedAddress: address, + }); } }, this.onboardingController.store.getState()), ); - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - this.desktopController = new DesktopController({ - initState: initState.DesktopController, - }); - ///: END:ONLY_INCLUDE_IF - const tokenDetectionControllerMessenger = this.controllerMessenger.getRestricted({ name: 'TokenDetectionController', @@ -1502,109 +1708,98 @@ export default class MetamaskController extends EventEmitter { }), }; - this.txController = new TransactionController( - { - blockTracker: this.blockTracker, - cancelMultiplier: 1.1, - getCurrentNetworkEIP1559Compatibility: - this.networkController.getEIP1559Compatibility.bind( - this.networkController, - ), - getCurrentAccountEIP1559Compatibility: - this.getCurrentAccountEIP1559Compatibility.bind(this), - getExternalPendingTransactions: - this.getExternalPendingTransactions.bind(this), - getGasFeeEstimates: this.gasFeeController.fetchGasFeeEstimates.bind( - this.gasFeeController, - ), - getNetworkClientRegistry: - this.networkController.getNetworkClientRegistry.bind( - this.networkController, + const transactionControllerMessenger = + this.controllerMessenger.getRestricted({ + name: 'TransactionController', + allowedActions: [ + `${this.approvalController.name}:addRequest`, + 'NetworkController:findNetworkClientIdByChainId', + 'NetworkController:getNetworkClientById', + ], + allowedEvents: [`NetworkController:stateChange`], + }); + this.txController = new TransactionController({ + blockTracker: this.blockTracker, + getCurrentNetworkEIP1559Compatibility: + this.networkController.getEIP1559Compatibility.bind( + this.networkController, + ), + getCurrentAccountEIP1559Compatibility: + this.getCurrentAccountEIP1559Compatibility.bind(this), + getExternalPendingTransactions: + this.getExternalPendingTransactions.bind(this), + getGasFeeEstimates: this.gasFeeController.fetchGasFeeEstimates.bind( + this.gasFeeController, + ), + getNetworkClientRegistry: + this.networkController.getNetworkClientRegistry.bind( + this.networkController, + ), + getNetworkState: () => this.networkController.state, + getPermittedAccounts: this.getPermittedAccounts.bind(this), + getSavedGasFees: () => + this.preferencesController.store.getState().advancedGasFee[ + this.networkController.state.providerConfig.chainId + ], + getSelectedAddress: () => + this.accountsController.getSelectedAccount().address, + incomingTransactions: { + includeTokenTransfers: false, + isEnabled: () => + Boolean( + this.preferencesController.store.getState() + .incomingTransactionsPreferences?.[ + this.networkController.state.providerConfig.chainId + ] && this.onboardingController.store.getState().completedOnboarding, ), - getNetworkState: () => this.networkController.state, - getPermittedAccounts: this.getPermittedAccounts.bind(this), - getSavedGasFees: () => - this.preferencesController.store.getState().advancedGasFee[ - this.networkController.state.providerConfig.chainId - ], - getSelectedAddress: () => - this.accountsController.getSelectedAccount().address, - isMultichainEnabled: process.env.TRANSACTION_MULTICHAIN, - incomingTransactions: { - includeTokenTransfers: false, - isEnabled: () => - Boolean( - this.preferencesController.store.getState() - .incomingTransactionsPreferences?.[ - this.networkController.state.providerConfig.chainId - ] && - this.onboardingController.store.getState().completedOnboarding, - ), - queryEntireHistory: false, - updateTransactions: false, - }, - messenger: this.controllerMessenger.getRestricted({ - name: 'TransactionController', - allowedActions: [ - `${this.approvalController.name}:addRequest`, - 'NetworkController:findNetworkClientIdByChainId', - 'NetworkController:getNetworkClientById', - ], - allowedEvents: [`NetworkController:stateChange`], - }), - onNetworkStateChange: (listener) => { - networkControllerMessenger.subscribe( - 'NetworkController:networkDidChange', - () => listener(), + queryEntireHistory: false, + updateTransactions: false, + }, + isMultichainEnabled: process.env.TRANSACTION_MULTICHAIN, + isSimulationEnabled: () => + this.preferencesController.store.getState().useTransactionSimulations, + messenger: transactionControllerMessenger, + onNetworkStateChange: (listener) => { + networkControllerMessenger.subscribe( + 'NetworkController:networkDidChange', + () => listener(), + ); + }, + pendingTransactions: { + isResubmitEnabled: () => { + const state = this._getMetaMaskState(); + return !( + getSmartTransactionsOptInStatus(state) && + getCurrentChainSupportsSmartTransactions(state) ); }, - provider: this.provider, - hooks: { - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - afterSign: (txMeta, signedEthTx) => - afterTransactionSignMMI( - txMeta, - signedEthTx, - this.transactionUpdateController.addTransactionToWatchList.bind( - this.transactionUpdateController, - ), - ), - beforeCheckPendingTransaction: - beforeCheckPendingTransactionMMI.bind(this), - beforeApproveOnInit: beforeApproveOnInitMMI.bind(this), - beforePublish: beforeTransactionPublishMMI.bind(this), - getAdditionalSignArguments: getAdditionalSignArgumentsMMI.bind(this), - ///: END:ONLY_INCLUDE_IF - }, }, - { - sign: (...args) => this.keyringController.signTransaction(...args), + provider: this.provider, + testGasFeeFlows: process.env.TEST_GAS_FEE_FLOWS, + hooks: { + ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) + afterSign: (txMeta, signedEthTx) => + afterTransactionSignMMI( + txMeta, + signedEthTx, + this.transactionUpdateController.addTransactionToWatchList.bind( + this.transactionUpdateController, + ), + ), + beforeCheckPendingTransaction: + beforeCheckPendingTransactionMMI.bind(this), + beforeApproveOnInit: beforeApproveOnInitMMI.bind(this), + beforePublish: beforeTransactionPublishMMI.bind(this), + getAdditionalSignArguments: getAdditionalSignArgumentsMMI.bind(this), + ///: END:ONLY_INCLUDE_IF + publish: this._publishSmartTransactionHook.bind(this), }, - initState.TransactionController, - ); + sign: (...args) => this.keyringController.signTransaction(...args), + state: initState.TransactionController, + }); this._addTransactionControllerListeners(); - networkControllerMessenger.subscribe( - 'NetworkController:networkDidChange', - async () => { - try { - if ( - this.preferencesController.store.getState().useCurrencyRateCheck - ) { - await this.currencyRateController.stopAllPolling(); - this.currencyRateController.startPollingByNetworkClientId( - this.networkController.state.selectedNetworkClientId, - ); - } - } catch (error) { - // TODO: Handle failure to get conversion rate more gracefully - console.error(error); - } - }, - ); - - this.networkController.lookupNetwork(); this.decryptMessageController = new DecryptMessageController({ getState: this.getState.bind(this), messenger: this.controllerMessenger.getRestricted({ @@ -1658,7 +1853,6 @@ export default class MetamaskController extends EventEmitter { this.preferencesController.store.getState() ?.disabledRpcMethodPreferences?.eth_sign, getAllState: this.getState.bind(this), - securityProviderRequest: this.securityProviderRequest.bind(this), getCurrentChainId: () => this.networkController.state.providerConfig.chainId, }); @@ -1686,6 +1880,8 @@ export default class MetamaskController extends EventEmitter { 'AccountsController:getAccountByAddress', 'AccountsController:setAccountName', 'AccountsController:listAccounts', + 'AccountsController:getSelectedAccount', + 'AccountsController:setSelectedAccount', ], }); @@ -1730,6 +1926,10 @@ export default class MetamaskController extends EventEmitter { this.txController.updateTransaction(txMeta, note), updateTransactionHash: (id, hash) => this.txController.updateCustodialTransaction(id, { hash }), + setChannelId: (channelId) => + this.institutionalFeaturesController.setChannelId(channelId), + setConnectionRequest: (payload) => + this.institutionalFeaturesController.setConnectionRequest(payload), }); ///: END:ONLY_INCLUDE_IF @@ -1753,6 +1953,11 @@ export default class MetamaskController extends EventEmitter { this.gasFeeController.fetchGasFeeEstimates.bind( this.gasFeeController, ), + getLayer1GasFee: this.txController.getLayer1GasFee.bind( + this.txController, + ), + getNetworkClientId: () => + this.networkController.state.selectedNetworkClientId, trackMetaMetricsEvent: this.metaMetricsController.trackEvent.bind( this.metaMetricsController, ), @@ -1768,18 +1973,19 @@ export default class MetamaskController extends EventEmitter { networkControllerMessenger, 'NetworkController:stateChange', ), - getNonceLock: this.txController.nonceTracker.getNonceLock.bind( - this.txController.nonceTracker, - ), + getNonceLock: this.txController.getNonceLock.bind(this.txController), confirmExternalTransaction: this.txController.confirmExternalTransaction.bind(this.txController), + getTransactions: this.txController.getTransactions.bind( + this.txController, + ), provider: this.provider, trackMetaMetricsEvent: this.metaMetricsController.trackEvent.bind( this.metaMetricsController, ), }, { - supportedChainIds: [CHAIN_IDS.MAINNET, CHAIN_IDS.GOERLI], + supportedChainIds: getAllowedSmartTransactionsChainIds(), }, initState.SmartTransactionsController, ); @@ -1875,12 +2081,7 @@ export default class MetamaskController extends EventEmitter { // clear unapproved transactions and messages when the network will change networkControllerMessenger.subscribe( 'NetworkController:networkWillChange', - () => { - this.encryptionPublicKeyController.clearUnapproved(); - this.decryptMessageController.clearUnapproved(); - this.signatureController.clearUnapproved(); - this.approvalController.clear(ethErrors.provider.userRejectedRequest()); - }, + clearPendingConfirmations.bind(this), ); this.metamaskMiddleware = createMetamaskMiddleware({ @@ -1965,6 +2166,7 @@ export default class MetamaskController extends EventEmitter { this.encryptionPublicKeyController.newRequestEncryptionPublicKey.bind( this.encryptionPublicKeyController, ), + processDecryptMessage: this.decryptMessageController.newRequestDecryptMessage.bind( this.decryptMessageController, @@ -2002,6 +2204,7 @@ export default class MetamaskController extends EventEmitter { AccountsController: this.accountsController, AppStateController: this.appStateController.store, AppMetadataController: this.appMetadataController.store, + MultichainBalancesController: this.multichainBalancesController, TransactionController: this.txController, KeyringController: this.keyringController, PreferencesController: this.preferencesController.store, @@ -2025,6 +2228,7 @@ export default class MetamaskController extends EventEmitter { PhishingController: this.phishingController, SelectedNetworkController: this.selectedNetworkController, LoggingController: this.loggingController, + MultichainRatesController: this.multichainRatesController, ///: BEGIN:ONLY_INCLUDE_IF(snaps) SnapController: this.snapController, CronjobController: this.cronjobController, @@ -2032,9 +2236,6 @@ export default class MetamaskController extends EventEmitter { NotificationController: this.notificationController, SnapInterfaceController: this.snapInterfaceController, ///: END:ONLY_INCLUDE_IF - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - DesktopController: this.desktopController.store, - ///: END:ONLY_INCLUDE_IF ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) CustodyController: this.custodyController.store, @@ -2047,6 +2248,12 @@ export default class MetamaskController extends EventEmitter { ///: END:ONLY_INCLUDE_IF NameController: this.nameController, UserOperationController: this.userOperationController, + // Notification Controllers + AuthenticationController: this.authenticationController, + UserStorageController: this.userStorageController, + MetamaskNotificationsController: this.metamaskNotificationsController, + PushPlatformNotificationsController: + this.pushPlatformNotificationsController, ...resetOnRestartStore, }); @@ -2055,6 +2262,7 @@ export default class MetamaskController extends EventEmitter { AccountsController: this.accountsController, AppStateController: this.appStateController.store, AppMetadataController: this.appMetadataController.store, + MultichainBalancesController: this.multichainBalancesController, NetworkController: this.networkController, KeyringController: this.keyringController, PreferencesController: this.preferencesController.store, @@ -2077,6 +2285,7 @@ export default class MetamaskController extends EventEmitter { SelectedNetworkController: this.selectedNetworkController, LoggingController: this.loggingController, TxController: this.txController, + MultichainRatesController: this.multichainRatesController, ///: BEGIN:ONLY_INCLUDE_IF(snaps) SnapController: this.snapController, CronjobController: this.cronjobController, @@ -2084,9 +2293,6 @@ export default class MetamaskController extends EventEmitter { NotificationController: this.notificationController, SnapInterfaceController: this.snapInterfaceController, ///: END:ONLY_INCLUDE_IF - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - DesktopController: this.desktopController.store, - ///: END:ONLY_INCLUDE_IF ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) CustodyController: this.custodyController.store, InstitutionalFeaturesController: @@ -2095,6 +2301,13 @@ export default class MetamaskController extends EventEmitter { ///: END:ONLY_INCLUDE_IF NameController: this.nameController, UserOperationController: this.userOperationController, + // Notification Controllers + AuthenticationController: this.authenticationController, + UserStorageController: this.userStorageController, + MetamaskNotificationsController: this.metamaskNotificationsController, + QueuedRequestController: this.queuedRequestController, + PushPlatformNotificationsController: + this.pushPlatformNotificationsController, ...resetOnRestartStore, }, controllerMessenger: this.controllerMessenger, @@ -2153,6 +2366,7 @@ export default class MetamaskController extends EventEmitter { }); this.setupControllerEventSubscriptions(); + this.setupMultichainDataAndSubscriptions(); // For more information about these legacy streams, see here: // https://github.com/MetaMask/metamask-extension/issues/15491 @@ -2163,17 +2377,37 @@ export default class MetamaskController extends EventEmitter { this.extension.runtime.onMessageExternal.addListener(onMessageReceived); // Fire a ping message to check if other extensions are running checkForMultipleVersionsRunning(); + + if (this.onboardingController.store.getState().completedOnboarding) { + this.postOnboardingInitialization(); + } + } + + postOnboardingInitialization() { + const { usePhishDetect } = this.preferencesController.store.getState(); + + this.networkController.lookupNetwork(); + + if (usePhishDetect) { + this.phishingController.maybeUpdateState(); + } } triggerNetworkrequests() { this.accountTracker.start(); this.txController.startIncomingTransactionPolling(); - if (this.preferencesController.store.getState().useCurrencyRateCheck) { - this.currencyRateController.startPollingByNetworkClientId( - this.networkController.state.selectedNetworkClientId, - ); + this.tokenDetectionController.enable(); + + const preferencesControllerState = + this.preferencesController.store.getState(); + + const { useCurrencyRateCheck } = preferencesControllerState; + + if (useCurrencyRateCheck) { + this.tokenRatesController.start(); } - if (this.preferencesController.store.getState().useTokenDetection) { + + if (this.#isTokenListPollingRequired(preferencesControllerState)) { this.tokenListController.start(); } } @@ -2181,12 +2415,19 @@ export default class MetamaskController extends EventEmitter { stopNetworkRequests() { this.accountTracker.stop(); this.txController.stopIncomingTransactionPolling(); - if (this.preferencesController.store.getState().useCurrencyRateCheck) { - this.currencyRateController.stopAllPolling(); + this.tokenDetectionController.disable(); + + const preferencesControllerState = + this.preferencesController.store.getState(); + + const { useCurrencyRateCheck } = preferencesControllerState; + + if (useCurrencyRateCheck) { + this.tokenRatesController.stop(); } - if (this.preferencesController.store.getState().useTokenDetection) { + + if (this.#isTokenListPollingRequired(preferencesControllerState)) { this.tokenListController.stop(); - this.tokenRatesController.stop(); } } @@ -2219,7 +2460,7 @@ export default class MetamaskController extends EventEmitter { } ///: END:ONLY_INCLUDE_IF - ///: BEGIN:ONLY_INCLUDE_IF(build-flask) + ///: BEGIN:ONLY_INCLUDE_IF(snaps) trackInsightSnapView(snapId) { this.metaMetricsController.trackEvent({ event: MetaMetricsEventName.InsightSnapViewed, @@ -2314,15 +2555,11 @@ export default class MetamaskController extends EventEmitter { * Constructor helper for getting Snap permission specifications. */ getSnapPermissionSpecifications() { - const snapEncryptor = encryptorFactory(600_000); - return { ...buildSnapEndowmentSpecifications(Object.keys(ExcludedSnapEndowments)), ...buildSnapRestrictedMethodSpecifications( Object.keys(ExcludedSnapPermissions), { - encrypt: snapEncryptor.encrypt, - decrypt: snapEncryptor.decrypt, getLocale: this.getLocale.bind(this), clearSnapState: this.controllerMessenger.call.bind( this.controllerMessenger, @@ -2445,24 +2682,11 @@ export default class MetamaskController extends EventEmitter { setupControllerEventSubscriptions() { let lastSelectedAddress; - this.preferencesController.store.subscribe(async (state) => { - const { currentLocale } = state; - - const { chainId } = this.networkController.state.providerConfig; - await updateCurrentLocale(currentLocale); - - if (state.incomingTransactionsPreferences?.[chainId]) { - this.txController.startIncomingTransactionPolling(); - } else { - this.txController.stopIncomingTransactionPolling(); - } - - // TODO: Remove once the preferences controller has been replaced with the core monorepo implementation - this.controllerMessenger.publish( - `${this.preferencesController.name}:stateChange`, - [state, []], - ); - }); + this.preferencesController.store.subscribe( + previousValueComparator((prevState, currState) => { + this.#onPreferencesControllerStateChange(currState, prevState); + }, this.preferencesController.store.getState()), + ); this.controllerMessenger.subscribe( `${this.accountsController.name}:selectedAccountChange`, @@ -2626,6 +2850,35 @@ export default class MetamaskController extends EventEmitter { ///: END:ONLY_INCLUDE_IF } + /** + * Sets up multichain data and subscriptions. + * This method is called during the MetaMaskController constructor. + * It starts the MultichainRatesController if selected account is non-EVM + * and subscribes to account changes. + */ + setupMultichainDataAndSubscriptions() { + if ( + !isEvmAccountType( + this.accountsController.getSelectedMultichainAccount().type, + ) + ) { + this.multichainRatesController.start(); + } + + this.controllerMessenger.subscribe( + 'AccountsController:selectedAccountChange', + (selectedAccount) => { + if (isEvmAccountType(selectedAccount.type)) { + this.multichainRatesController.stop(); + return; + } + this.multichainRatesController.start(); + }, + ); + this.multichainBalancesController.start(); + this.multichainBalancesController.updateBalances(); + } + /** * TODO:LegacyProvider: Delete * Constructor helper: initialize a public config store. @@ -2635,20 +2888,21 @@ export default class MetamaskController extends EventEmitter { // subset of state for metamask inpage provider const publicConfigStore = new ObservableStore(); - const selectPublicState = (chainId, { isUnlocked }) => { + const selectPublicState = async ({ isUnlocked }) => { + const { chainId, networkVersion } = await this.getProviderNetworkState(); + return { isUnlocked, chainId, - networkVersion: this.deprecatedNetworkId ?? 'loading', + networkVersion: networkVersion ?? 'loading', }; }; - const updatePublicConfigStore = (memState) => { + const updatePublicConfigStore = async (memState) => { const networkStatus = memState.networksMetadata[memState.selectedNetworkClientId]?.status; - const { chainId } = this.networkController.state.providerConfig; if (networkStatus === NetworkStatus.Available) { - publicConfigStore.putState(selectPublicState(chainId, memState)); + publicConfigStore.putState(await selectPublicState(memState)); } }; @@ -2666,12 +2920,14 @@ export default class MetamaskController extends EventEmitter { * @returns {Promise<{ isUnlocked: boolean, networkVersion: string, chainId: string, accounts: string[] }>} An object with relevant state properties. */ async getProviderState(origin) { + const providerNetworkState = await this.getProviderNetworkState( + this.preferencesController.getUseRequestQueue() ? origin : undefined, + ); + return { isUnlocked: this.isUnlocked(), accounts: await this.getPermittedAccounts(origin), - ...this.getProviderNetworkState( - this.preferencesController.getUseRequestQueue() ? origin : undefined, - ), + ...providerNetworkState, }; } @@ -2681,71 +2937,41 @@ export default class MetamaskController extends EventEmitter { * @param {string} origin - The origin identifier for which network state is requested (default: 'metamask'). * @returns {object} An object containing important network state properties, including chainId and networkVersion. */ - getProviderNetworkState(origin = METAMASK_DOMAIN) { - let chainId; - if ( - this.preferencesController.getUseRequestQueue() && - origin !== METAMASK_DOMAIN - ) { - const networkClientId = this.controllerMessenger.call( - 'SelectedNetworkController:getNetworkClientIdForDomain', - origin, - ); - - const networkClient = this.controllerMessenger.call( - 'NetworkController:getNetworkClientById', - networkClientId, - ); - chainId = networkClient.configuration.chainId; - } else { - chainId = this.networkController.state.providerConfig.chainId; - } + async getProviderNetworkState(origin = METAMASK_DOMAIN) { + const networkClientId = this.controllerMessenger.call( + 'SelectedNetworkController:getNetworkClientIdForDomain', + origin, + ); - return { - chainId, - networkVersion: this.deprecatedNetworkId ?? 'loading', - }; - } + const networkClient = this.controllerMessenger.call( + 'NetworkController:getNetworkClientById', + networkClientId, + ); - /** - * TODO: Delete when ready to remove `networkVersion` from provider object - * Updates the `deprecatedNetworkId` value - */ - async updateDeprecatedNetworkId() { - try { - this.deprecatedNetworkId = await this.deprecatedGetNetworkId(); - } catch (error) { - console.error(error); - this.deprecatedNetworkId = null; - } - this._notifyChainChange(); - } + const { chainId } = networkClient.configuration; - /** - * TODO: Delete when ready to remove `networkVersion` from provider object - * Gets current networkId as returned by `net_version` - * - * @returns {string} The networkId for the current network or null on failure - * @throws Will throw if there is a problem getting the network version - */ - async deprecatedGetNetworkId() { - const ethQuery = this.controllerMessenger.call( - 'NetworkController:getEthQuery', - ); + const { completedOnboarding } = this.onboardingController.store.getState(); - if (!ethQuery) { - throw new Error('Provider has not been initialized'); + let networkVersion = this.deprecatedNetworkVersions[networkClientId]; + if (!networkVersion && completedOnboarding) { + const ethQuery = new EthQuery(networkClient.provider); + networkVersion = await new Promise((resolve) => { + ethQuery.sendAsync({ method: 'net_version' }, (error, result) => { + if (error) { + console.error(error); + resolve(null); + } else { + resolve(convertNetworkId(result)); + } + }); + }); + this.deprecatedNetworkVersions[networkClientId] = networkVersion; } - return new Promise((resolve, reject) => { - ethQuery.sendAsync({ method: 'net_version' }, (error, result) => { - if (error) { - reject(error); - } else { - resolve(convertNetworkId(result)); - } - }); - }); + return { + chainId, + networkVersion: networkVersion ?? 'loading', + }; } //============================================================================= @@ -2807,6 +3033,7 @@ export default class MetamaskController extends EventEmitter { networkController, announcementController, onboardingController, + appMetadataController, permissionController, preferencesController, swapsController, @@ -2817,6 +3044,11 @@ export default class MetamaskController extends EventEmitter { backup, approvalController, phishingController, + // Notification Controllers + authenticationController, + userStorageController, + metamaskNotificationsController, + pushPlatformNotificationsController, } = this; return { @@ -2838,6 +3070,10 @@ export default class MetamaskController extends EventEmitter { preferencesController.setUseMultiAccountBalanceChecker.bind( preferencesController, ), + dismissOpenSeaToBlockaidBanner: + preferencesController.dismissOpenSeaToBlockaidBanner.bind( + preferencesController, + ), setUseSafeChainsListValidation: preferencesController.setUseSafeChainsListValidation.bind( preferencesController, @@ -2879,6 +3115,10 @@ export default class MetamaskController extends EventEmitter { preferencesController.setUseExternalNameSources.bind( preferencesController, ), + setUseTransactionSimulations: + preferencesController.setUseTransactionSimulations.bind( + preferencesController, + ), setUseRequestQueue: this.setUseRequestQueue.bind(this), setIpfsGateway: preferencesController.setIpfsGateway.bind( preferencesController, @@ -2895,6 +3135,10 @@ export default class MetamaskController extends EventEmitter { metaMetricsController.setParticipateInMetaMetrics.bind( metaMetricsController, ), + setDataCollectionForMarketing: + metaMetricsController.setDataCollectionForMarketing.bind( + metaMetricsController, + ), setCurrentLocale: preferencesController.setCurrentLocale.bind( preferencesController, ), @@ -2902,6 +3146,10 @@ export default class MetamaskController extends EventEmitter { preferencesController.setIncomingTransactionsPreferences.bind( preferencesController, ), + setServiceWorkerKeepAlivePreference: + preferencesController.setServiceWorkerKeepAlivePreference.bind( + preferencesController, + ), markPasswordForgotten: this.markPasswordForgotten.bind(this), unMarkPasswordForgotten: this.unMarkPasswordForgotten.bind(this), getRequestAccountTabIds: this.getRequestAccountTabIds, @@ -2919,6 +3167,8 @@ export default class MetamaskController extends EventEmitter { resetAccount: this.resetAccount.bind(this), removeAccount: this.removeAccount.bind(this), importAccountWithStrategy: this.importAccountWithStrategy.bind(this), + getNextAvailableAccountName: + accountsController.getNextAvailableAccountName.bind(accountsController), ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) getAccountsBySnapId: (snapId) => getAccountsBySnapId(this, snapId), ///: END:ONLY_INCLUDE_IF @@ -2954,10 +3204,15 @@ export default class MetamaskController extends EventEmitter { setActiveNetwork: (networkConfigurationId) => { return this.networkController.setActiveNetwork(networkConfigurationId); }, + setNetworkClientIdForDomain: (origin, networkClientId) => { + return this.selectedNetworkController.setNetworkClientIdForDomain( + origin, + networkClientId, + ); + }, rollbackToPreviousProvider: networkController.rollbackToPreviousProvider.bind(networkController), - removeNetworkConfiguration: - networkController.removeNetworkConfiguration.bind(networkController), + removeNetworkConfiguration: this.removeNetworkConfiguration.bind(this), upsertNetworkConfiguration: this.networkController.upsertNetworkConfiguration.bind( this.networkController, @@ -2975,11 +3230,11 @@ export default class MetamaskController extends EventEmitter { const account = this.accountsController.getAccountByAddress(address); if (account) { this.accountsController.setSelectedAccount(account.id); - this.preferencesController.setSelectedAddress(address); } else { throw new Error(`No account found for address: ${address}`); } }, + toggleExternalServices: this.toggleExternalServices.bind(this), addToken: tokensController.addToken.bind(tokensController), updateTokenType: tokensController.updateTokenType.bind(tokensController), setFeatureFlag: preferencesController.setFeatureFlag.bind( @@ -3008,10 +3263,6 @@ export default class MetamaskController extends EventEmitter { preferencesController, ), setTheme: preferencesController.setTheme.bind(preferencesController), - setTransactionSecurityCheckEnabled: - preferencesController.setTransactionSecurityCheckEnabled.bind( - preferencesController, - ), ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) setSnapsAddSnapAccountModalDismissed: preferencesController.setSnapsAddSnapAccountModalDismissed.bind( @@ -3023,7 +3274,6 @@ export default class MetamaskController extends EventEmitter { setSelectedInternalAccount: (id) => { const account = this.accountsController.getAccount(id); if (account) { - this.preferencesController.setSelectedAddress(account.address); this.accountsController.setSelectedAccount(id); } }, @@ -3073,6 +3323,8 @@ export default class MetamaskController extends EventEmitter { // AppStateController setLastActiveTime: appStateController.setLastActiveTime.bind(appStateController), + setCurrentExtensionPopupId: + appStateController.setCurrentExtensionPopupId.bind(appStateController), setDefaultHomeActiveTabName: appStateController.setDefaultHomeActiveTabName.bind(appStateController), setConnectedStatusPopoverHasBeenShown: @@ -3093,6 +3345,16 @@ export default class MetamaskController extends EventEmitter { appStateController.setSurveyLinkLastClickedOrClosed.bind( appStateController, ), + setOnboardingDate: + appStateController.setOnboardingDate.bind(appStateController), + setNewPrivacyPolicyToastClickedOrClosed: + appStateController.setNewPrivacyPolicyToastClickedOrClosed.bind( + appStateController, + ), + setNewPrivacyPolicyToastShownDate: + appStateController.setNewPrivacyPolicyToastShownDate.bind( + appStateController, + ), ///: BEGIN:ONLY_INCLUDE_IF(snaps) setSnapsInstallPrivacyWarningShownStatus: appStateController.setSnapsInstallPrivacyWarningShownStatus.bind( @@ -3111,8 +3373,6 @@ export default class MetamaskController extends EventEmitter { appStateController.setShowBetaHeader.bind(appStateController), setShowPermissionsTour: appStateController.setShowPermissionsTour.bind(appStateController), - setShowProductTour: - appStateController.setShowProductTour.bind(appStateController), setShowAccountBanner: appStateController.setShowAccountBanner.bind(appStateController), setShowNetworkBanner: @@ -3121,6 +3381,14 @@ export default class MetamaskController extends EventEmitter { appStateController.updateNftDropDownState.bind(appStateController), setFirstTimeUsedNetwork: appStateController.setFirstTimeUsedNetwork.bind(appStateController), + setSwitchedNetworkDetails: + appStateController.setSwitchedNetworkDetails.bind(appStateController), + clearSwitchedNetworkDetails: + appStateController.clearSwitchedNetworkDetails.bind(appStateController), + setSwitchedNetworkNeverShowMessage: + appStateController.setSwitchedNetworkNeverShowMessage.bind( + appStateController, + ), // EnsController tryReverseResolveAddress: @@ -3147,7 +3415,6 @@ export default class MetamaskController extends EventEmitter { transactionOptions, waitForSubmit: false, }), - this.updateSecurityAlertResponseByTxId.bind(this), ), addTransactionAndWaitForPublish: ( transactionParams, @@ -3159,7 +3426,6 @@ export default class MetamaskController extends EventEmitter { transactionOptions, waitForSubmit: true, }), - this.updateSecurityAlertResponseByTxId.bind(this), ), createTransactionEventFragment: createTransactionEventFragmentWithTxId.bind( @@ -3180,6 +3446,7 @@ export default class MetamaskController extends EventEmitter { txController.updatePreviousGasParams.bind(txController), abortTransactionSigning: txController.abortTransactionSigning.bind(txController), + getLayer1GasFee: txController.getLayer1GasFee.bind(txController), // decryptMessageController decryptMessage: this.decryptMessageController.decryptMessage.bind( @@ -3204,6 +3471,12 @@ export default class MetamaskController extends EventEmitter { this.encryptionPublicKeyController, ), + // AppMetadataController + setShowTokenAutodetectModalOnUpgrade: + appMetadataController.setShowTokenAutodetectModalOnUpgrade.bind( + appMetadataController, + ), + // onboarding controller setSeedPhraseBackedUp: onboardingController.setSeedPhraseBackedUp.bind(onboardingController), @@ -3271,6 +3544,10 @@ export default class MetamaskController extends EventEmitter { this.institutionalFeaturesController.removeAddTokenConnectRequest.bind( this.institutionalFeaturesController, ), + setConnectionRequest: + this.institutionalFeaturesController.setConnectionRequest.bind( + this.institutionalFeaturesController, + ), showInteractiveReplacementTokenBanner: appStateController.showInteractiveReplacementTokenBanner.bind( appStateController, @@ -3331,24 +3608,6 @@ export default class MetamaskController extends EventEmitter { 'SnapInterfaceController:updateInterfaceState', ), ///: END:ONLY_INCLUDE_IF - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - // Desktop - getDesktopEnabled: this.desktopController.getDesktopEnabled.bind( - this.desktopController, - ), - setDesktopEnabled: this.desktopController.setDesktopEnabled.bind( - this.desktopController, - ), - generateDesktopOtp: this.desktopController.generateOtp.bind( - this.desktopController, - ), - testDesktopConnection: this.desktopController.testDesktopConnection.bind( - this.desktopController, - ), - disableDesktop: this.desktopController.disableDesktop.bind( - this.desktopController, - ), - ///: END:ONLY_INCLUDE_IF // swaps fetchAndSetQuotes: @@ -3390,10 +3649,6 @@ export default class MetamaskController extends EventEmitter { swapsController.setSwapsQuotesPollingLimitEnabled.bind(swapsController), // Smart Transactions - setSmartTransactionsOptInStatus: - smartTransactionsController.setOptInState.bind( - smartTransactionsController, - ), fetchSmartTransactionFees: smartTransactionsController.getFees.bind( smartTransactionsController, ), @@ -3437,7 +3692,7 @@ export default class MetamaskController extends EventEmitter { finalizeEventFragment: metaMetricsController.finalizeEventFragment.bind( metaMetricsController, ), - ///: BEGIN:ONLY_INCLUDE_IF(build-flask) + ///: BEGIN:ONLY_INCLUDE_IF(snaps) trackInsightSnapView: this.trackInsightSnapView.bind(this), ///: END:ONLY_INCLUDE_IF // approval controller @@ -3445,25 +3700,29 @@ export default class MetamaskController extends EventEmitter { rejectPendingApproval: this.rejectPendingApproval, // Notifications + resetViewedNotifications: announcementController.resetViewed.bind( + announcementController, + ), updateViewedNotifications: announcementController.updateViewed.bind( announcementController, ), + // CurrencyRateController + currencyRateStartPollingByNetworkClientId: + currencyRateController.startPollingByNetworkClientId.bind( + currencyRateController, + ), + currencyRateStopPollingByPollingToken: + currencyRateController.stopPollingByPollingToken.bind( + currencyRateController, + ), + // GasFeeController gasFeeStartPollingByNetworkClientId: gasFeeController.startPollingByNetworkClientId.bind(gasFeeController), - gasFeeStopPollingByPollingToken: gasFeeController.stopPollingByPollingToken.bind(gasFeeController), - getGasFeeEstimatesAndStartPolling: - gasFeeController.getGasFeeEstimatesAndStartPolling.bind( - gasFeeController, - ), - - disconnectGasFeeEstimatePoller: - gasFeeController.disconnectPoller.bind(gasFeeController), - getGasFeeTimeEstimate: gasFeeController.getTimeEstimate.bind(gasFeeController), @@ -3497,6 +3756,76 @@ export default class MetamaskController extends EventEmitter { assetsContractController, ), + // Authentication Controller + performSignIn: authenticationController.performSignIn.bind( + authenticationController, + ), + performSignOut: authenticationController.performSignOut.bind( + authenticationController, + ), + + // UserStorageController + enableProfileSyncing: userStorageController.enableProfileSyncing.bind( + userStorageController, + ), + disableProfileSyncing: userStorageController.disableProfileSyncing.bind( + userStorageController, + ), + setIsProfileSyncingEnabled: + userStorageController.setIsProfileSyncingEnabled.bind( + userStorageController, + ), + + // MetamaskNotificationsController + checkAccountsPresence: + metamaskNotificationsController.checkAccountsPresence.bind( + metamaskNotificationsController, + ), + createOnChainTriggers: + metamaskNotificationsController.createOnChainTriggers.bind( + metamaskNotificationsController, + ), + deleteOnChainTriggersByAccount: + metamaskNotificationsController.deleteOnChainTriggersByAccount.bind( + metamaskNotificationsController, + ), + updateOnChainTriggersByAccount: + metamaskNotificationsController.updateOnChainTriggersByAccount.bind( + metamaskNotificationsController, + ), + fetchAndUpdateMetamaskNotifications: + metamaskNotificationsController.fetchAndUpdateMetamaskNotifications.bind( + metamaskNotificationsController, + ), + markMetamaskNotificationsAsRead: + metamaskNotificationsController.markMetamaskNotificationsAsRead.bind( + metamaskNotificationsController, + ), + setFeatureAnnouncementsEnabled: + metamaskNotificationsController.setFeatureAnnouncementsEnabled.bind( + metamaskNotificationsController, + ), + enablePushNotifications: + pushPlatformNotificationsController.enablePushNotifications.bind( + pushPlatformNotificationsController, + ), + disablePushNotifications: + pushPlatformNotificationsController.disablePushNotifications.bind( + pushPlatformNotificationsController, + ), + updateTriggerPushNotifications: + pushPlatformNotificationsController.updateTriggerPushNotifications.bind( + pushPlatformNotificationsController, + ), + enableMetamaskNotifications: + metamaskNotificationsController.enableMetamaskNotifications.bind( + metamaskNotificationsController, + ), + disableMetamaskNotifications: + metamaskNotificationsController.disableMetamaskNotifications.bind( + metamaskNotificationsController, + ), + // E2E testing throwTestError: this.throwTestError.bind(this), @@ -3550,11 +3879,9 @@ export default class MetamaskController extends EventEmitter { let details; if (tokenCanBeTreatedAsAnERC20) { try { - const balance = await fetchTokenBalance( - address, - userAddress, - this.provider, - ); + const balance = userAddress + ? await fetchTokenBalance(address, userAddress, this.provider) + : undefined; details = { address, @@ -3647,15 +3974,7 @@ export default class MetamaskController extends EventEmitter { async createNewVaultAndKeychain(password) { const releaseLock = await this.createVaultMutex.acquire(); try { - const vault = await this.keyringController.createNewVaultAndKeychain( - password, - ); - - const accounts = await this.keyringController.getAccounts(); - this.preferencesController.setAddresses(accounts); - this.selectFirstAccount(); - - return vault; + return await this.keyringController.createNewVaultAndKeychain(password); } finally { releaseLock(); } @@ -3671,10 +3990,10 @@ export default class MetamaskController extends EventEmitter { async createNewVaultAndRestore(password, encodedSeedPhrase) { const releaseLock = await this.createVaultMutex.acquire(); try { - const seedPhraseAsBuffer = Buffer.from(encodedSeedPhrase); + const { completedOnboarding } = + this.onboardingController.store.getState(); - // clear known identities - this.preferencesController.setAddresses([]); + const seedPhraseAsBuffer = Buffer.from(encodedSeedPhrase); // clear permissions this.permissionController.clearState(); @@ -3691,60 +4010,65 @@ export default class MetamaskController extends EventEmitter { this.txController.clearUnapprovedTransactions(); + if (completedOnboarding) { + this.tokenDetectionController.enable(); + } + // create new vault - const vault = await this.keyringController.createNewVaultAndRestore( + await this.keyringController.createNewVaultAndRestore( password, this._convertMnemonicToWordlistIndices(seedPhraseAsBuffer), ); - // Scan accounts until we find an empty one - const { chainId } = this.networkController.state.providerConfig; - const ethQuery = new EthQuery(this.provider); - const accounts = await this.keyringController.getAccounts(); - let address = accounts[accounts.length - 1]; + if (completedOnboarding) { + await this._addAccountsWithBalance(); - for (let count = accounts.length; ; count++) { - const balance = await this.getBalance(address, ethQuery); + // This must be set as soon as possible to communicate to the + // keyring's iframe and have the setting initialized properly + // Optimistically called to not block MetaMask login due to + // Ledger Keyring GitHub downtime + this.setLedgerTransportPreference(); + } + } finally { + releaseLock(); + } + } - if (balance === '0x0') { - // This account has no balance, so check for tokens - await this.tokenDetectionController.detectTokens({ - selectedAddress: address, - }); + async _addAccountsWithBalance() { + // Scan accounts until we find an empty one + const { chainId } = this.networkController.state.providerConfig; + const ethQuery = new EthQuery(this.provider); + const accounts = await this.keyringController.getAccounts(); + let address = accounts[accounts.length - 1]; - const tokens = - this.tokensController.state.allTokens?.[chainId]?.[address]; - const detectedTokens = - this.tokensController.state.allDetectedTokens?.[chainId]?.[address]; + for (let count = accounts.length; ; count++) { + const balance = await this.getBalance(address, ethQuery); - if ( - (tokens?.length ?? 0) === 0 && - (detectedTokens?.length ?? 0) === 0 - ) { - // This account has no balance or tokens - if (count !== 1) { - await this.removeAccount(address); - } - break; + if (balance === '0x0') { + // This account has no balance, so check for tokens + await this.tokenDetectionController.detectTokens({ + selectedAddress: address, + }); + + const tokens = + this.tokensController.state.allTokens?.[chainId]?.[address]; + const detectedTokens = + this.tokensController.state.allDetectedTokens?.[chainId]?.[address]; + + if ( + (tokens?.length ?? 0) === 0 && + (detectedTokens?.length ?? 0) === 0 + ) { + // This account has no balance or tokens + if (count !== 1) { + await this.removeAccount(address); } + break; } - - // This account has assets, so check the next one - ({ addedAccountAddress: address } = - await this.keyringController.addNewAccount(count)); } - // This must be set as soon as possible to communicate to the - // keyring's iframe and have the setting initialized properly - // Optimistically called to not block MetaMask login due to - // Ledger Keyring GitHub downtime - this.setLedgerTransportPreference(); - - this.selectFirstAccount(); - - return vault; - } finally { - releaseLock(); + // This account has assets, so check the next one + address = await this.keyringController.addNewAccount(count); } } @@ -3809,6 +4133,11 @@ export default class MetamaskController extends EventEmitter { * @param {string} password - The user's password */ async submitPassword(password) { + const { completedOnboarding } = this.onboardingController.store.getState(); + + // Before attempting to unlock the keyrings, we need the offscreen to have loaded. + await this.offscreenPromise; + await this.keyringController.submitPassword(password); ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) @@ -3827,7 +4156,9 @@ export default class MetamaskController extends EventEmitter { // keyring's iframe and have the setting initialized properly // Optimistically called to not block MetaMask login due to // Ledger Keyring GitHub downtime - this.setLedgerTransportPreference(); + if (completedOnboarding) { + this.setLedgerTransportPreference(); + } } async _loginUser(password) { @@ -3902,18 +4233,6 @@ export default class MetamaskController extends EventEmitter { * receiving funds from our automatic Ropsten faucet. */ - /** - * Sets the first account in the state to the selected address - */ - selectFirstAccount() { - const { identities } = this.preferencesController.store.getState(); - const [address] = Object.keys(identities); - this.preferencesController.setSelectedAddress(address); - - const [account] = this.accountsController.listAccounts(); - this.accountsController.setSelectedAccount(account.id); - } - /** * Gets the mnemonic of the user's primary keyring. */ @@ -3999,6 +4318,10 @@ export default class MetamaskController extends EventEmitter { async connectHardware(deviceName, page, hdPath) { const keyring = await this.getKeyringForDevice(deviceName, hdPath); + if (deviceName === HardwareDeviceNames.ledger) { + await this.setLedgerTransportPreference(keyring); + } + let accounts = []; switch (page) { case -1: @@ -4014,6 +4337,7 @@ export default class MetamaskController extends EventEmitter { // Merge with existing accounts // and make sure addresses are not repeated const oldAccounts = await this.keyringController.getAccounts(); + const accountsToTrack = [ ...new Set( oldAccounts.concat(accounts.map((a) => a.address.toLowerCase())), @@ -4134,37 +4458,28 @@ export default class MetamaskController extends EventEmitter { const keyring = await this.getKeyringForDevice(deviceName, hdPath); keyring.setAccountToUnlock(index); - const oldAccounts = await this.keyringController.getAccounts(); - const keyState = await this.keyringController.addNewAccountForKeyring( - keyring, + const unlockedAccount = + await this.keyringController.addNewAccountForKeyring(keyring); + const label = this.getAccountLabel( + deviceName === HardwareDeviceNames.qr ? keyring.getName() : deviceName, + index, + hdPathDescription, ); - const newAccounts = await this.keyringController.getAccounts(); - this.preferencesController.setAddresses(newAccounts); - newAccounts.forEach((address) => { - if (!oldAccounts.includes(address)) { - const label = this.getAccountLabel( - deviceName === HardwareDeviceNames.qr - ? keyring.getName() - : deviceName, - index, - hdPathDescription, - ); - // Set the account label to Trezor 1 / Ledger 1 / QR Hardware 1, etc - this.preferencesController.setAccountLabel(address, label); - // Select the account - this.preferencesController.setSelectedAddress(address); + // Set the account label to Trezor 1 / Ledger 1 / QR Hardware 1, etc + this.preferencesController.setAccountLabel(unlockedAccount, label); + // Select the account + this.preferencesController.setSelectedAddress(unlockedAccount); - // It is expected that the account also exist in the accounts-controller - // in other case, an error shall be thrown - const account = this.accountsController.getAccountByAddress(address); - this.accountsController.setAccountName(account.id, label); - } - }); + // It is expected that the account also exist in the accounts-controller + // in other case, an error shall be thrown + const account = + this.accountsController.getAccountByAddress(unlockedAccount); + this.accountsController.setAccountName(account.id, label); const accounts = this.accountsController.listAccounts(); const { identities } = this.preferencesController.store.getState(); - return { ...keyState, identities, accounts }; + return { unlockedAccount, identities, accounts }; } // @@ -4180,7 +4495,7 @@ export default class MetamaskController extends EventEmitter { async addNewAccount(accountCount) { const oldAccounts = await this.keyringController.getAccounts(); - const { addedAccountAddress } = await this.keyringController.addNewAccount( + const addedAccountAddress = await this.keyringController.addNewAccount( accountCount, ); @@ -4218,7 +4533,11 @@ export default class MetamaskController extends EventEmitter { async resetAccount() { const selectedAddress = this.accountsController.getSelectedAccount().address; - this.txController.wipeTransactions(true, selectedAddress); + this.txController.wipeTransactions(false, selectedAddress); + this.smartTransactionsController.wipeSmartTransactions({ + address: selectedAddress, + ignoreNetwork: false, + }); this.networkController.resetConnection(); return selectedAddress; @@ -4253,6 +4572,48 @@ export default class MetamaskController extends EventEmitter { } } + /** + * Stops exposing the specified chain ID to all third parties. + * Exposed chain IDs are stored in caveats of the permittedChains permission. This + * method uses `PermissionController.updatePermissionsByCaveat` to + * remove the specified chain ID from every permittedChains permission. If a + * permission only included this chain ID, the permission is revoked entirely. + * + * @param {string} targetChainId - The chain ID to stop exposing + * to third parties. + */ + removeAllChainIdPermissions(targetChainId) { + this.permissionController.updatePermissionsByCaveat( + CaveatTypes.restrictNetworkSwitching, + (existingChainIds) => + CaveatMutatorFactories[ + CaveatTypes.restrictNetworkSwitching + ].removeChainId(targetChainId, existingChainIds), + ); + } + + removeNetworkConfiguration(networkConfigurationId) { + const { networkConfigurations } = this.networkController.state; + const { chainId } = networkConfigurations[networkConfigurationId] ?? {}; + if (!chainId) { + throw new Error('Network configuration not found'); + } + const hasOtherConfigsForChainId = Object.values(networkConfigurations).some( + (config) => + config.chainId === chainId && + config.id !== networkConfigurationId && + config.type !== networkConfigurationId, + ); + + // if this network configuration is only one for a given chainId + // remove all permissions for that chainId + if (!hasOtherConfigsForChainId) { + this.removeAllChainIdPermissions(chainId); + } + + this.networkController.removeNetworkConfiguration(networkConfigurationId); + } + /** * Stops exposing the account with the specified address to all third parties. * Exposed accounts are stored in caveats of the eth_accounts permission. This @@ -4299,14 +4660,14 @@ export default class MetamaskController extends EventEmitter { /** * Imports an account with the specified import strategy. - * These are defined in app/scripts/account-import-strategies + * These are defined in @metamask/keyring-controller * Each strategy represents a different way of serializing an Ethereum key pair. * * @param {'privateKey' | 'json'} strategy - A unique identifier for an account import strategy. * @param {any} args - The data required by that strategy to import an account. */ async importAccountWithStrategy(strategy, args) { - const { importedAccountAddress } = + const importedAccountAddress = await this.keyringController.importAccountWithStrategy(strategy, args); // set new account as selected this.preferencesController.setSelectedAddress(importedAccountAddress); @@ -4333,10 +4694,11 @@ export default class MetamaskController extends EventEmitter { transactionParams, userOperationController: this.userOperationController, ///: BEGIN:ONLY_INCLUDE_IF(blockaid) + chainId: this.networkController.state.providerConfig.chainId, ppomController: this.ppomController, securityAlertsEnabled: this.preferencesController.store.getState()?.securityAlertsEnabled, - chainId: this.networkController.state.providerConfig.chainId, + updateSecurityAlertResponse: this.updateSecurityAlertResponse.bind(this), ///: END:ONLY_INCLUDE_IF }; } @@ -4429,40 +4791,19 @@ export default class MetamaskController extends EventEmitter { } }; - async updateSecurityAlertResponseByTxId(req, securityAlertResponse) { - let foundConfirmation = false; - - while (!foundConfirmation) { - if (SIGNING_METHODS.includes(req.method)) { - foundConfirmation = Object.values( - this.signatureController.messages, - ).find( - (message) => - message.securityAlertResponse?.securityAlertId === - req.securityAlertResponse.securityAlertId, - ); - } else { - foundConfirmation = this.txController.state.transactions.find( - (meta) => - meta.securityAlertResponse?.securityAlertId === - req.securityAlertResponse.securityAlertId, - ); - } - if (!foundConfirmation) { - await new Promise((resolve) => setTimeout(resolve, 100)); - } - } - - if (SIGNING_METHODS.includes(req.method)) { - this.appStateController.addSignatureSecurityAlertResponse( - securityAlertResponse, - ); - } else { - this.txController.updateSecurityAlertResponse( - foundConfirmation.id, - securityAlertResponse, - ); - } + async updateSecurityAlertResponse( + method, + securityAlertId, + securityAlertResponse, + ) { + updateSecurityAlertResponse({ + appStateController: this.appStateController, + method, + securityAlertId, + securityAlertResponse, + signatureController: this.signatureController, + transactionController: this.txController, + }); } //============================================================================= @@ -4522,6 +4863,7 @@ export default class MetamaskController extends EventEmitter { * @param {string} [options.subjectType] - The type of the sender, i.e. subject. */ setupUntrustedCommunication({ connectionStream, sender, subjectType }) { + const { completedOnboarding } = this.onboardingController.store.getState(); const { usePhishDetect } = this.preferencesController.store.getState(); let _subjectType; @@ -4533,12 +4875,12 @@ export default class MetamaskController extends EventEmitter { _subjectType = SubjectType.Website; } - if (sender.url) { + if (usePhishDetect && completedOnboarding && sender.url) { const { hostname } = new URL(sender.url); this.phishingController.maybeUpdateState(); // Check if new connection is blocked if phishing detection is on const phishingTestResponse = this.phishingController.test(hostname); - if (usePhishDetect && phishingTestResponse?.result) { + if (phishingTestResponse?.result) { this.sendPhishingWarning(connectionStream, hostname); this.metaMetricsController.trackEvent({ event: MetaMetricsEventName.PhishingPageDisplayed, @@ -4648,17 +4990,9 @@ export default class MetamaskController extends EventEmitter { this.emit('controllerConnectionChanged', this.activeControllerConnections); // set up postStream transport - outStream.on( - 'data', - createMetaRPCHandler( - api, - outStream, - this.store, - this.localStoreApiWrapper, - ), - ); + outStream.on('data', createMetaRPCHandler(api, outStream)); const handleUpdate = (update) => { - if (outStream._writableState.ended) { + if (!isStreamWritable(outStream)) { return; } // send notification to client-side @@ -4670,7 +5004,7 @@ export default class MetamaskController extends EventEmitter { }; this.on('update', handleUpdate); const startUISync = () => { - if (outStream._writableState.ended) { + if (!isStreamWritable(outStream)) { return; } // send notification to client-side @@ -4737,23 +5071,36 @@ export default class MetamaskController extends EventEmitter { tabId, }); + const dupeReqFilterStream = createDupeReqFilterStream(); + // setup connection const providerStream = createEngineStream({ engine }); const connectionId = this.addConnection(origin, { engine }); - pump(outStream, providerStream, outStream, (err) => { - // handle any middleware cleanup - engine._middleware.forEach((mid) => { - if (mid.destroy && typeof mid.destroy === 'function') { - mid.destroy(); + pipeline( + outStream, + dupeReqFilterStream, + providerStream, + outStream, + (err) => { + // handle any middleware cleanup + engine._middleware.forEach((mid) => { + if (mid.destroy && typeof mid.destroy === 'function') { + mid.destroy(); + } + }); + connectionId && this.removeConnection(origin, connectionId); + if (err) { + log.error(err); } - }); - connectionId && this.removeConnection(origin, connectionId); - if (err) { - log.error(err); - } - }); + }, + ); + + // Used to show wallet liveliness to the provider + if (subjectType !== SubjectType.Internal) { + this._notifyChainChangeForConnection({ engine }, origin); + } } ///: BEGIN:ONLY_INCLUDE_IF(snaps) @@ -4782,64 +5129,65 @@ export default class MetamaskController extends EventEmitter { * @param {tabId} [options.tabId] - The tab ID of the sender - if the sender is within a tab */ setupProviderEngine({ origin, subjectType, sender, tabId }) { - // setup json rpc engine stack const engine = new JsonRpcEngine(); - // append origin to each request + // Append origin to each request engine.push(createOriginMiddleware({ origin })); - // append selectedNetworkClientId to each request + // Append selectedNetworkClientId to each request engine.push(createSelectedNetworkMiddleware(this.controllerMessenger)); - let proxyClient; - if ( - this.preferencesController.getUseRequestQueue() && - this.selectedNetworkController.state.domains[origin] - ) { - proxyClient = - this.selectedNetworkController.getProviderAndBlockTracker(origin); - } else { - // if useRequestQueue is false we want to use the globally selected network provider/blockTracker - // since this means the per domain network feature is disabled - - // if the origin is not in the selectedNetworkController's `domains` state, - // this means that origin does not have permissions (is not connected to the wallet) - // and will therefore not have its own selected network even if useRequestQueue is true - // and so in this case too we want to use the globally selected network provider/blockTracker - proxyClient = this.networkController.getProviderAndBlockTracker(); - } - + // Add a middleware that will switch chain on each request (as needed) const requestQueueMiddleware = createQueuedRequestMiddleware({ - messenger: this.controllerMessenger, + enqueueRequest: this.queuedRequestController.enqueueRequest.bind( + this.queuedRequestController, + ), useRequestQueue: this.preferencesController.getUseRequestQueue.bind( this.preferencesController, ), + shouldEnqueueRequest: (request) => { + if ( + request.method === 'eth_requestAccounts' && + this.permissionController.hasPermission( + request.origin, + PermissionNames.eth_accounts, + ) + ) { + return false; + } + return methodsWithConfirmation.includes(request.method); + }, }); - // add some middleware that will switch chain on each request (as needed) engine.push(requestQueueMiddleware); - // create filter polyfill middleware - const filterMiddleware = createFilterMiddleware(proxyClient); + // If the origin is not in the selectedNetworkController's `domains` state + // when the provider engine is created, the selectedNetworkController will + // fetch the globally selected networkClient from the networkController and wrap + // it in a proxy which can be switched to use its own state if/when the origin + // is added to the `domains` state + const proxyClient = + this.selectedNetworkController.getProviderAndBlockTracker(origin); - // create subscription polyfill middleware + // We create the filter and subscription manager middleware now, but they will + // be inserted into the engine later. + const filterMiddleware = createFilterMiddleware(proxyClient); const subscriptionManager = createSubscriptionManager(proxyClient); subscriptionManager.events.on('notification', (message) => engine.emit('notification', message), ); - if (isManifestV3) { - engine.push(createDupeReqFilterMiddleware()); - } - - // append tabId to each request if it exists + // Append tabId to each request if it exists if (tabId) { engine.push(createTabIdMiddleware({ tabId })); } - // logging engine.push(createLoggerMiddleware({ origin })); engine.push(this.permissionLogController.createMiddleware()); + if (origin === BaseUrl.Portfolio) { + engine.push(createTxVerificationMiddleware(this.networkController)); + } + ///: BEGIN:ONLY_INCLUDE_IF(blockaid) engine.push( createPPOMMiddleware( @@ -4847,11 +5195,16 @@ export default class MetamaskController extends EventEmitter { this.preferencesController, this.networkController, this.appStateController, - this.updateSecurityAlertResponseByTxId.bind(this), + this.updateSecurityAlertResponse.bind(this), ), ); ///: END:ONLY_INCLUDE_IF + const isConfirmationRedesignEnabled = () => { + return this.preferencesController.store.getState().preferences + .redesignedConfirmationsEnabled; + }; + engine.push( createRPCMethodTrackingMiddleware({ trackEvent: this.metaMetricsController.trackEvent.bind( @@ -4860,9 +5213,9 @@ export default class MetamaskController extends EventEmitter { getMetricsState: this.metaMetricsController.store.getState.bind( this.metaMetricsController.store, ), - securityProviderRequest: this.securityProviderRequest.bind(this), getAccountType: this.getAccountType.bind(this), getDeviceModel: this.getDeviceModel.bind(this), + isConfirmationRedesignEnabled, snapAndHardwareMessenger: this.controllerMessenger.getRestricted({ name: 'SnapAndHardwareMessenger', allowedActions: [ @@ -4877,7 +5230,24 @@ export default class MetamaskController extends EventEmitter { }), ); - // onboarding + engine.push(createUnsupportedMethodMiddleware()); + + // Legacy RPC methods that need to be implemented _ahead of_ the permission + // middleware. + engine.push( + createLegacyMethodMiddleware({ + getAccounts: this.getPermittedAccounts.bind(this, origin), + }), + ); + + if (subjectType !== SubjectType.Internal) { + engine.push( + this.permissionController.createPermissionMiddleware({ + origin, + }), + ); + } + if (subjectType === SubjectType.Website) { engine.push( createOnboardingMiddleware({ @@ -4887,7 +5257,19 @@ export default class MetamaskController extends EventEmitter { ); } - // Unrestricted/permissionless RPC method implementations + // EVM requests and eth permissions should not be passed to non-EVM accounts + // this middleware intercepts these requests and returns an error. + engine.push( + createEvmMethodsToNonEvmAccountReqFilterMiddleware({ + messenger: this.controllerMessenger.getRestricted({ + name: 'EvmMethodsToNonEvmAccountFilterMessenger', + allowedActions: ['AccountsController:getSelectedAccount'], + }), + }), + ); + + // Unrestricted/permissionless RPC method implementations. + // They must nevertheless be placed _behind_ the permission middleware. engine.push( createMethodMiddleware({ origin, @@ -4915,16 +5297,6 @@ export default class MetamaskController extends EventEmitter { endApprovalFlow: this.approvalController.endFlow.bind( this.approvalController, ), - setApprovalFlowLoadingText: - this.approvalController.setFlowLoadingText.bind( - this.approvalController, - ), - showApprovalSuccess: this.approvalController.success.bind( - this.approvalController, - ), - showApprovalError: this.approvalController.error.bind( - this.approvalController, - ), sendMetrics: this.metaMetricsController.trackEvent.bind( this.metaMetricsController, ), @@ -4938,16 +5310,25 @@ export default class MetamaskController extends EventEmitter { this.permissionController, origin, ), - hasPermissions: this.permissionController.hasPermissions.bind( - this.permissionController, - origin, - ), requestAccountsPermission: this.permissionController.requestPermissions.bind( this.permissionController, { origin }, { eth_accounts: {} }, ), + requestPermittedChainsPermission: (chainIds) => + this.permissionController.requestPermissions( + { origin }, + { + [PermissionNames.permittedChains]: { + caveats: [ + CaveatFactories[CaveatTypes.restrictNetworkSwitching]( + chainIds, + ), + ], + }, + }, + ), requestPermissionsForOrigin: this.permissionController.requestPermissions.bind( this.permissionController, @@ -4967,40 +5348,58 @@ export default class MetamaskController extends EventEmitter { console.log(e); } }, - getCurrentChainId: () => - this.networkController.state.providerConfig.chainId, + getCaveat: ({ target, caveatType }) => { + try { + return this.permissionController.getCaveat( + origin, + target, + caveatType, + ); + } catch (e) { + if (e instanceof PermissionDoesNotExistError) { + // suppress expected error in case that the origin + // does not have the target permission yet + } else { + throw e; + } + } + + return undefined; + }, + getChainPermissionsFeatureFlag: () => + Boolean(process.env.CHAIN_PERMISSIONS), getCurrentRpcUrl: () => this.networkController.state.providerConfig.rpcUrl, // network configuration-related - getNetworkConfigurations: () => - this.networkController.state.networkConfigurations, upsertNetworkConfiguration: this.networkController.upsertNetworkConfiguration.bind( this.networkController, ), - setActiveNetwork: (networkClientId) => { - this.networkController.setActiveNetwork(networkClientId); + setActiveNetwork: async (networkClientId) => { + await this.networkController.setActiveNetwork(networkClientId); + // if the origin has the eth_accounts permission + // we set per dapp network selection state + if ( + this.permissionController.hasPermission( + origin, + PermissionNames.eth_accounts, + ) + ) { + this.selectedNetworkController.setNetworkClientIdForDomain( + origin, + networkClientId, + ); + } }, - findNetworkClientIdByChainId: - this.networkController.findNetworkClientIdByChainId.bind( - this.networkController, - ), findNetworkConfigurationBy: this.findNetworkConfigurationBy.bind(this), - getNetworkClientIdForDomain: - this.selectedNetworkController.getNetworkClientIdForDomain.bind( - this.selectedNetworkController, - ), - setNetworkClientIdForDomain: - this.selectedNetworkController.setNetworkClientIdForDomain.bind( - this.selectedNetworkController, - ), - - getUseRequestQueue: this.preferencesController.getUseRequestQueue.bind( - this.preferencesController, - ), - getProviderConfig: () => this.networkController.state.providerConfig, - setProviderType: (type) => { - return this.networkController.setProviderType(type); + getCurrentChainIdForDomain: (domain) => { + const networkClientId = + this.selectedNetworkController.getNetworkClientIdForDomain(domain); + const { chainId } = + this.networkController.getNetworkConfigurationByNetworkClientId( + networkClientId, + ); + return chainId; }, // Web3 shim-related @@ -5064,6 +5463,11 @@ export default class MetamaskController extends EventEmitter { 'SnapController:install', origin, ), + invokeSnap: this.permissionController.executeRestrictedMethod.bind( + this.permissionController, + origin, + RestrictedMethods.wallet_snap, + ), getIsLocked: () => { return !this.appStateController.isUnlocked(); }, @@ -5109,17 +5513,8 @@ export default class MetamaskController extends EventEmitter { ); ///: END:ONLY_INCLUDE_IF - // filter and subscription polyfills engine.push(filterMiddleware); engine.push(subscriptionManager.middleware); - if (subjectType !== SubjectType.Internal) { - // permissions - engine.push( - this.permissionController.createPermissionMiddleware({ - origin, - }), - ); - } engine.push(this.metamaskMiddleware); @@ -5142,7 +5537,7 @@ export default class MetamaskController extends EventEmitter { setupPublicConfig(outStream) { const configStream = storeAsStream(this.publicConfigStore); - pump(configStream, outStream, (err) => { + pipeline(configStream, outStream, (err) => { configStream.destroy(); if (err) { log.error(err); @@ -5260,13 +5655,36 @@ export default class MetamaskController extends EventEmitter { Object.keys(this.connections).forEach((origin) => { Object.values(this.connections[origin]).forEach(async (conn) => { - if (conn.engine) { - conn.engine.emit('notification', await getPayload(origin)); + try { + this.notifyConnection(conn, await getPayload(origin)); + } catch (err) { + console.error(err); } }); }); } + /** + * Causes the RPC engine for passed connection to emit a + * notification event with the given payload. + * + * The caller is responsible for ensuring that only permitted notifications + * are sent. + * + * @param {object} connection - Data associated with the connection + * @param {object} connection.engine - The connection's JSON Rpc Engine + * @param {unknown} payload - The event payload + */ + notifyConnection(connection, payload) { + try { + if (connection.engine) { + connection.engine.emit('notification', payload); + } + } catch (err) { + console.error(err); + } + } + // handlers /** @@ -5278,17 +5696,17 @@ export default class MetamaskController extends EventEmitter { */ async _onKeyringControllerUpdate(state) { const { keyrings } = state; - const addresses = keyrings.reduce( - (acc, { accounts }) => acc.concat(accounts), - [], - ); + + // The accounts tracker only supports EVM addresses and the keyring + // controller may pass non-EVM addresses, so we filter them out + const addresses = keyrings + .reduce((acc, { accounts }) => acc.concat(accounts), []) + .filter(isEthAddress); if (!addresses.length) { return; } - // Ensure preferences + identities controller know about all addresses - this.preferencesController.syncAddresses(addresses); this.accountTracker.syncWithAddresses(addresses); } @@ -5432,58 +5850,61 @@ export default class MetamaskController extends EventEmitter { _addTransactionControllerListeners() { const transactionMetricsRequest = this.getTransactionMetricsRequest(); - this.txController.hub.on( - 'post-transaction-balance-updated', + this.controllerMessenger.subscribe( + 'TransactionController:postTransactionBalanceUpdated', handlePostTransactionBalanceUpdate.bind(null, transactionMetricsRequest), ); - this.txController.hub.on('unapprovedTransaction', (transactionMeta) => - handleTransactionAdded(transactionMetricsRequest, { transactionMeta }), + this.controllerMessenger.subscribe( + 'TransactionController:unapprovedTransactionAdded', + (transactionMeta) => + handleTransactionAdded(transactionMetricsRequest, { transactionMeta }), ); - this.txController.hub.on( - 'transaction-approved', + this.controllerMessenger.subscribe( + 'TransactionController:transactionApproved', handleTransactionApproved.bind(null, transactionMetricsRequest), ); - this.txController.hub.on( - 'transaction-dropped', + this.controllerMessenger.subscribe( + 'TransactionController:transactionDropped', handleTransactionDropped.bind(null, transactionMetricsRequest), ); - this.txController.hub.on( - 'transaction-confirmed', + this.controllerMessenger.subscribe( + 'TransactionController:transactionConfirmed', handleTransactionConfirmed.bind(null, transactionMetricsRequest), ); - this.txController.hub.on( - 'transaction-failed', + this.controllerMessenger.subscribe( + 'TransactionController:transactionFailed', handleTransactionFailed.bind(null, transactionMetricsRequest), ); - this.txController.hub.on('transaction-new-swap', ({ transactionMeta }) => { - this.swapsController.setTradeTxId(transactionMeta.id); - }); + this.controllerMessenger.subscribe( + 'TransactionController:transactionNewSwap', + ({ transactionMeta }) => + this.swapsController.setTradeTxId(transactionMeta.id), + ); - this.txController.hub.on( - 'transaction-new-swap-approval', - ({ transactionMeta }) => { - this.swapsController.setApproveTxId(transactionMeta.id); - }, + this.controllerMessenger.subscribe( + 'TransactionController:transactionNewSwapApproval', + ({ transactionMeta }) => + this.swapsController.setApproveTxId(transactionMeta.id), ); - this.txController.hub.on( - 'transaction-rejected', + this.controllerMessenger.subscribe( + 'TransactionController:transactionRejected', handleTransactionRejected.bind(null, transactionMetricsRequest), ); - this.txController.hub.on( - 'transaction-submitted', + this.controllerMessenger.subscribe( + 'TransactionController:transactionSubmitted', handleTransactionSubmitted.bind(null, transactionMetricsRequest), ); - this.txController.hub.on( - 'transaction-status-update', + this.controllerMessenger.subscribe( + 'TransactionController:transactionStatusUpdated', ({ transactionMeta }) => { this._onFinishedTransaction(transactionMeta); }, @@ -5518,10 +5939,18 @@ export default class MetamaskController extends EventEmitter { getEIP1559GasFeeEstimates: this.gasFeeController.fetchGasFeeEstimates.bind(this.gasFeeController), getSelectedAddress: () => - this.preferencesController.store.getState().selectedAddress, + this.accountsController.getSelectedAccount().address, getTokenStandardAndDetails: this.getTokenStandardAndDetails.bind(this), getTransaction: (id) => this.txController.state.transactions.find((tx) => tx.id === id), + getIsSmartTransaction: () => { + return getIsSmartTransaction(this._getMetaMaskState()); + }, + getSmartTransactionByMinedTxHash: (txHash) => { + return this.smartTransactionsController.getSmartTransactionByMinedTxHash( + txHash, + ); + }, }; return { ...controllerActions, @@ -5537,6 +5966,18 @@ export default class MetamaskController extends EventEmitter { }; } + toggleExternalServices(useExternal) { + this.preferencesController.toggleExternalServices(useExternal); + this.tokenListController.updatePreventPollingOnNetworkRestart(!useExternal); + if (useExternal) { + this.tokenDetectionController.enable(); + this.gasFeeController.enableNonRPCGasFeeApis(); + } else { + this.tokenDetectionController.disable(); + this.gasFeeController.disableNonRPCGasFeeApis(); + } + } + //============================================================================= // CONFIG //============================================================================= @@ -5564,14 +6005,16 @@ export default class MetamaskController extends EventEmitter { /** * Sets the Ledger Live preference to use for Ledger hardware wallet support * + * @param _keyring * @deprecated This method is deprecated and will be removed in the future. * Only webhid connections are supported in chrome and u2f in firefox. */ - async setLedgerTransportPreference() { + async setLedgerTransportPreference(_keyring) { const transportType = window.navigator.hid ? LedgerTransportTypes.webhid : LedgerTransportTypes.u2f; - const keyring = await this.getKeyringForDevice(HardwareDeviceNames.ledger); + const keyring = + _keyring || (await this.getKeyringForDevice(HardwareDeviceNames.ledger)); if (keyring?.updateTransportMethod) { return keyring.updateTransportMethod(transportType).catch((e) => { throw e; @@ -5606,11 +6049,6 @@ export default class MetamaskController extends EventEmitter { */ set isClientOpen(open) { this._isClientOpen = open; - if (open) { - this.tokenDetectionController.enable(); - } else { - this.tokenDetectionController.disable(); - } } /* eslint-enable accessor-pairs */ @@ -5620,7 +6058,8 @@ export default class MetamaskController extends EventEmitter { */ onClientClosed() { try { - this.gasFeeController.stopPolling(); + this.gasFeeController.stopAllPolling(); + this.currencyRateController.stopAllPolling(); this.appStateController.clearPollingTokens(); } catch (error) { console.error(error); @@ -5639,7 +6078,8 @@ export default class MetamaskController extends EventEmitter { const pollingTokensToDisconnect = this.appStateController.store.getState()[appStatePollingTokenType]; pollingTokensToDisconnect.forEach((pollingToken) => { - this.gasFeeController.disconnectPoller(pollingToken); + this.gasFeeController.stopPollingByPollingToken(pollingToken); + this.currencyRateController.stopPollingByPollingToken(pollingToken); this.appStateController.removePollingToken( pollingToken, appStatePollingTokenType, @@ -5766,33 +6206,6 @@ export default class MetamaskController extends EventEmitter { } }; - async securityProviderRequest(requestData, methodName) { - const { currentLocale, transactionSecurityCheckEnabled } = - this.preferencesController.store.getState(); - - if (transactionSecurityCheckEnabled) { - const chainId = Number( - hexToDecimal(this.networkController.state.providerConfig.chainId), - ); - - try { - const securityProviderResponse = await securityProviderCheck( - requestData, - methodName, - chainId, - currentLocale, - ); - - return securityProviderResponse; - } catch (err) { - log.error(err.message); - throw err; - } - } - - return null; - } - async _onAccountChange(newAddress) { const permittedAccountsMap = getPermittedAccountsByOrigin( this.permissionController.state, @@ -5827,16 +6240,30 @@ export default class MetamaskController extends EventEmitter { this.permissionLogController.updateAccountsHistory(origin, newAccounts); } - _notifyChainChange() { + async _notifyChainChange() { if (this.preferencesController.getUseRequestQueue()) { - this.notifyAllConnections((origin) => ({ + this.notifyAllConnections(async (origin) => ({ method: NOTIFICATION_NAMES.chainChanged, - params: this.getProviderNetworkState(origin), + params: await this.getProviderNetworkState(origin), })); } else { this.notifyAllConnections({ method: NOTIFICATION_NAMES.chainChanged, - params: this.getProviderNetworkState(), + params: await this.getProviderNetworkState(), + }); + } + } + + async _notifyChainChangeForConnection(connection, origin) { + if (this.preferencesController.getUseRequestQueue()) { + this.notifyConnection(connection, { + method: NOTIFICATION_NAMES.chainChanged, + params: await this.getProviderNetworkState(origin), + }); + } else { + this.notifyConnection(connection, { + method: NOTIFICATION_NAMES.chainChanged, + params: await this.getProviderNetworkState(), }); } } @@ -5894,7 +6321,6 @@ export default class MetamaskController extends EventEmitter { const { data, to: contractAddress, from: userAddress } = txParams; const transactionData = parseStandardTokenTransactionData(data); - // Sometimes the tokenId value is parsed as "_value" param. Not seeing this often any more, but still occasionally: // i.e. call approve() on BAYC contract - https://etherscan.io/token/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d#writeContract, and tokenId shows up as _value, // not sure why since it doesn't match the ERC721 ABI spec we use to parse these transactions - https://github.com/MetaMask/metamask-eth-abis/blob/d0474308a288f9252597b7c93a3a8deaad19e1b2/src/abis/abiERC721.ts#L62. @@ -5958,35 +6384,120 @@ export default class MetamaskController extends EventEmitter { } if (transactionMeta.type === TransactionType.swap) { - this.txController.hub.emit('transaction-new-swap', { - transactionMeta, - }); + this.controllerMessenger.publish( + 'TransactionController:transactionNewSwap', + { transactionMeta }, + ); } else if (transactionMeta.type === TransactionType.swapApproval) { - this.txController.hub.emit('transaction-new-swap-approval', { - transactionMeta, - }); + this.controllerMessenger.publish( + 'TransactionController:transactionNewSwapApproval', + { transactionMeta }, + ); } } _onUserOperationTransactionUpdated(transactionMeta) { - transactionMeta.txParams.from = - this.preferencesController.getSelectedAddress(); + const updatedTransactionMeta = { + ...transactionMeta, + txParams: { + ...transactionMeta.txParams, + from: this.accountsController.getSelectedAccount().address, + }, + }; const transactionExists = this.txController.state.transactions.some( - (tx) => tx.id === transactionMeta.id, + (tx) => tx.id === updatedTransactionMeta.id, ); if (!transactionExists) { - this.txController.state.transactions.push(transactionMeta); + this.txController.update((state) => { + state.transactions.push(updatedTransactionMeta); + }); } this.txController.updateTransaction( - transactionMeta, + updatedTransactionMeta, 'Generated from user operation', ); - this.txController.hub.emit('transaction-status-update', { + this.controllerMessenger.publish( + 'TransactionController:transactionStatusUpdated', + { transactionMeta: updatedTransactionMeta }, + ); + } + + _publishSmartTransactionHook(transactionMeta) { + const state = this._getMetaMaskState(); + const isSmartTransaction = getIsSmartTransaction(state); + if (!isSmartTransaction) { + // Will cause TransactionController to publish to the RPC provider as normal. + return { transactionHash: undefined }; + } + const featureFlags = getFeatureFlagsByChainId(state); + return submitSmartTransactionHook({ transactionMeta, + transactionController: this.txController, + smartTransactionsController: this.smartTransactionsController, + controllerMessenger: this.controllerMessenger, + isSmartTransaction, + featureFlags, }); } + + _getMetaMaskState() { + return { + metamask: this.getState(), + }; + } + + async #onPreferencesControllerStateChange(currentState, previousState) { + const { currentLocale } = currentState; + const { chainId } = this.networkController.state.providerConfig; + + await updateCurrentLocale(currentLocale); + + if (currentState.incomingTransactionsPreferences?.[chainId]) { + this.txController.startIncomingTransactionPolling(); + } else { + this.txController.stopIncomingTransactionPolling(); + } + + this.#checkTokenListPolling(currentState, previousState); + + // TODO: Remove once the preferences controller has been replaced with the core monorepo implementation + this.controllerMessenger.publish( + 'PreferencesController:stateChange', + currentState, + [], + ); + } + + #checkTokenListPolling(currentState, previousState) { + const previousEnabled = this.#isTokenListPollingRequired(previousState); + const newEnabled = this.#isTokenListPollingRequired(currentState); + + if (previousEnabled === newEnabled) { + return; + } + + this.tokenListController.updatePreventPollingOnNetworkRestart(!newEnabled); + + if (newEnabled) { + log.debug('Started token list controller polling'); + this.tokenListController.start(); + } else { + log.debug('Stopped token list controller polling'); + this.tokenListController.clearingTokenListData(); + this.tokenListController.stop(); + } + } + + #isTokenListPollingRequired(preferencesControllerState) { + const { useTokenDetection, useTransactionSimulations, preferences } = + preferencesControllerState ?? {}; + + const { petnamesEnabled } = preferences ?? {}; + + return useTokenDetection || petnamesEnabled || useTransactionSimulations; + } } diff --git a/app/scripts/metamask-controller.test.js b/app/scripts/metamask-controller.test.js index 766ea73417e0..06434643f93f 100644 --- a/app/scripts/metamask-controller.test.js +++ b/app/scripts/metamask-controller.test.js @@ -14,11 +14,21 @@ import { METAMASK_STALELIST_FILE, METAMASK_HOTLIST_DIFF_FILE, } from '@metamask/phishing-controller'; -import { EthMethod, EthAccountType } from '@metamask/keyring-api'; +import { + BtcAccountType, + BtcMethod, + EthAccountType, +} from '@metamask/keyring-api'; import { NetworkType } from '@metamask/controller-utils'; import { ControllerMessenger } from '@metamask/base-controller'; import { LoggingController, LogType } from '@metamask/logging-controller'; import { TransactionController } from '@metamask/transaction-controller'; +import { + RatesController, + TokenListController, +} from '@metamask/assets-controllers'; +import { TrezorKeyring } from '@metamask/eth-trezor-keyring'; +import { LedgerKeyring } from '@metamask/eth-ledger-bridge-keyring'; import { NETWORK_TYPES } from '../../shared/constants/network'; import { createTestProviderTools } from '../../test/stub/provider'; import { HardwareDeviceNames } from '../../shared/constants/hardware-wallets'; @@ -26,10 +36,17 @@ import { KeyringType } from '../../shared/constants/keyring'; import { LOG_EVENT } from '../../shared/constants/logs'; import mockEncryptor from '../../test/lib/mock-encryptor'; import * as tokenUtils from '../../shared/lib/token-util'; +import { flushPromises } from '../../test/lib/timer-helpers'; +import { ETH_EOA_METHODS } from '../../shared/constants/eth-methods'; +import { createMockInternalAccount } from '../../test/jest/mocks'; +import { + BalancesController as MultichainBalancesController, + BTC_AVG_BLOCK_TIME, +} from './lib/accounts/BalancesController'; import { deferredPromise } from './lib/util'; import MetaMaskController from './metamask-controller'; -const { Ganache } = require('../../test/e2e/ganache'); +const { Ganache } = require('../../test/e2e/seeder/ganache'); const ganacheServer = new Ganache(); @@ -81,8 +98,21 @@ const createLoggerMiddlewareMock = () => (req, res, next) => { } next(); }; - jest.mock('./lib/createLoggerMiddleware', () => createLoggerMiddlewareMock); + +const rpcMethodMiddlewareMock = { + createMethodMiddleware: () => (_req, _res, next, _end) => { + next(); + }, + createLegacyMethodMiddleware: () => (_req, _res, next, _end) => { + next(); + }, + createUnsupportedMethodMiddleware: () => (_req, _res, next, _end) => { + next(); + }, +}; +jest.mock('./lib/rpc-method-middleware', () => rpcMethodMiddlewareMock); + jest.mock( './controllers/preferences', () => @@ -99,6 +129,64 @@ jest.mock( }, ); +const KNOWN_PUBLIC_KEY = + '02065bc80d3d12b3688e4ad5ab1e9eda6adf24aec2518bfc21b87c99d4c5077ab0'; + +const KNOWN_PUBLIC_KEY_ADDRESSES = [ + { + address: '0x0e122670701207DB7c6d7ba9aE07868a4572dB3f', + balance: null, + index: 0, + }, + { + address: '0x2ae19DAd8b2569F7Bb4606D951Cc9495631e818E', + balance: null, + index: 1, + }, + { + address: '0x0051140bAaDC3E9AC92A4a90D18Bb6760c87e7ac', + balance: null, + index: 2, + }, + { + address: '0x9DBCF67CC721dBd8Df28D7A0CbA0fa9b0aFc6472', + balance: null, + index: 3, + }, + { + address: '0x828B2c51c5C1bB0c57fCD2C108857212c95903DE', + balance: null, + index: 4, + }, +]; + +const buildMockKeyringBridge = (publicKeyPayload) => + jest.fn(() => ({ + init: jest.fn(), + dispose: jest.fn(), + updateTransportMethod: jest.fn(), + getPublicKey: jest.fn(async () => publicKeyPayload), + })); + +jest.mock('@metamask/eth-trezor-keyring', () => ({ + ...jest.requireActual('@metamask/eth-trezor-keyring'), + TrezorConnectBridge: buildMockKeyringBridge({ + success: true, + payload: { + publicKey: KNOWN_PUBLIC_KEY, + chainCode: '0x1', + }, + }), +})); + +jest.mock('@metamask/eth-ledger-bridge-keyring', () => ({ + ...jest.requireActual('@metamask/eth-ledger-bridge-keyring'), + LedgerIframeBridge: buildMockKeyringBridge({ + publicKey: KNOWN_PUBLIC_KEY, + chainCode: '0x1', + }), +})); + const mockIsManifestV3 = jest.fn().mockReturnValue(false); jest.mock('../../shared/modules/mv3.utils', () => ({ get isManifestV3() { @@ -126,7 +214,7 @@ const TEST_INTERNAL_ACCOUNT = { lastSelected: 0, }, options: {}, - methods: [...Object.values(EthMethod)], + methods: ETH_EOA_METHODS, type: EthAccountType.Eoa, }; @@ -283,10 +371,10 @@ describe('MetaMaskController', () => { it('should be updated to use v1 of the API', () => { // Update the fixture above if this test fails expect(METAMASK_STALELIST_URL).toStrictEqual( - 'https://phishing-detection.metafi.codefi.network/v1/stalelist', + 'https://phishing-detection.api.cx.metamask.io/v1/stalelist', ); expect(METAMASK_HOTLIST_DIFF_URL).toStrictEqual( - 'https://phishing-detection.metafi.codefi.network/v1/diffsSince', + 'https://phishing-detection.api.cx.metamask.io/v1/diffsSince', ); }); }); @@ -294,6 +382,14 @@ describe('MetaMaskController', () => { describe('MetaMaskController Behaviour', () => { let metamaskController; + async function simulatePreferencesChange(preferences) { + metamaskController.preferencesController.store.subscribe.mock.lastCall[0]( + preferences, + ); + + await flushPromises(); + } + beforeEach(() => { jest.spyOn(MetaMaskController.prototype, 'resetStates'); @@ -316,6 +412,9 @@ describe('MetaMaskController', () => { .mockReturnValue(); jest.spyOn(ControllerMessenger.prototype, 'subscribe'); + jest.spyOn(TokenListController.prototype, 'start'); + jest.spyOn(TokenListController.prototype, 'stop'); + jest.spyOn(TokenListController.prototype, 'clearingTokenListData'); metamaskController = new MetaMaskController({ showUserConfirmation: noop, @@ -339,9 +438,6 @@ describe('MetaMaskController', () => { metamaskController.keyringController, 'createNewVaultAndRestore', ); - jest - .spyOn(metamaskController.preferencesController, 'removeAddress') - .mockImplementation((address) => address); }); describe('should reset states on first time profile load', () => { @@ -447,22 +543,51 @@ describe('MetaMaskController', () => { describe('submitPassword', () => { it('removes any identities that do not correspond to known accounts.', async () => { + const fakeAddress = '0xbad0'; + + const localMetaMaskController = new MetaMaskController({ + showUserConfirmation: noop, + encryptor: mockEncryptor, + initState: { + ...cloneDeep(firstTimeState), + KeyringController: { + keyrings: [{ type: KeyringType.trezor, accounts: ['0x123'] }], + isUnlocked: true, + }, + PreferencesController: { + identities: { + '0x123': { name: 'Trezor 1', address: '0x123' }, + [fakeAddress]: { name: 'fake', address: fakeAddress }, + }, + selectedAddress: '0x123', + }, + }, + initLangCode: 'en_US', + platform: { + showTransactionNotification: () => undefined, + getVersion: () => 'foo', + }, + browser: browserPolyfillMock, + infuraProjectId: 'foo', + isFirstMetaMaskControllerSetup: true, + }); + const accountsControllerSpy = jest.spyOn( - metamaskController.accountsController, + localMetaMaskController.accountsController, 'updateAccounts', ); + const password = 'password'; - await metamaskController.createNewVaultAndKeychain(password); + await localMetaMaskController.createNewVaultAndKeychain(password); - const fakeAddress = '0xbad0'; - metamaskController.preferencesController.addAddresses([fakeAddress]); - await metamaskController.submitPassword(password); + await localMetaMaskController.submitPassword(password); const identities = Object.keys( - metamaskController.preferencesController.store.getState().identities, + localMetaMaskController.preferencesController.store.getState() + .identities, ); const addresses = - await metamaskController.keyringController.getAccounts(); + await localMetaMaskController.keyringController.getAccounts(); identities.forEach((identity) => { expect(addresses).toContain(identity); @@ -473,7 +598,7 @@ describe('MetaMaskController', () => { }); const internalAccounts = - metamaskController.accountsController.listAccounts(); + localMetaMaskController.accountsController.listAccounts(); internalAccounts.forEach((account) => { expect(addresses).toContain(account.address); @@ -506,7 +631,6 @@ describe('MetaMaskController', () => { describe('#createNewVaultAndKeychain', () => { it('can only create new vault on keyringController once', async () => { - jest.spyOn(metamaskController, 'selectFirstAccount').mockReturnValue(); const password = 'a-fake-password'; const vault1 = await metamaskController.createNewVaultAndKeychain( @@ -611,6 +735,10 @@ describe('MetaMaskController', () => { } }); + jest + .spyOn(metamaskController.onboardingController.store, 'getState') + .mockReturnValue({ completedOnboarding: true }); + // Give account 2 a token jest .spyOn(metamaskController.tokensController, 'state', 'get') @@ -637,7 +765,11 @@ describe('MetaMaskController', () => { delete identities[TEST_ADDRESS].lastSelected; expect(identities).toStrictEqual({ [TEST_ADDRESS]: { address: TEST_ADDRESS, name: DEFAULT_LABEL }, - [TEST_ADDRESS_2]: { address: TEST_ADDRESS_2, name: 'Account 2' }, + [TEST_ADDRESS_2]: { + address: TEST_ADDRESS_2, + name: 'Account 2', + lastSelected: expect.any(Number), + }, }); }); }); @@ -682,307 +814,290 @@ describe('MetaMaskController', () => { }); }); - describe('#selectFirstAccount', () => { - let identities; - + describe('hardware keyrings', () => { beforeEach(async () => { - await metamaskController.keyringController.createNewVaultAndRestore( - 'password', - TEST_SEED, - ); - await metamaskController.addNewAccount(1); - await metamaskController.addNewAccount(2); + await metamaskController.createNewVaultAndKeychain('test@123'); + }); - identities = { - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { - TEST_ADDRESS, - name: 'Account 1', - }, - '0xc42edfcc21ed14dda456aa0756c153f7985d8813': { - TEST_ADDRESS_2, - name: 'Account 2', - }, - }; - metamaskController.preferencesController.store.updateState({ - identities, + describe('connectHardware', () => { + it('should throw if it receives an unknown device name', async () => { + const result = metamaskController.connectHardware( + 'Some random device name', + 0, + `m/44/0'/0'`, + ); + + await expect(result).rejects.toThrow( + 'MetamaskController:getKeyringForDevice - Unknown device', + ); }); - metamaskController.selectFirstAccount(); - }); - it('changes preferences controller select address', () => { - const preferenceControllerState = - metamaskController.preferencesController.store.getState(); - expect(preferenceControllerState.selectedAddress).toStrictEqual( - TEST_ADDRESS, - ); - }); + it('should add the Trezor Hardware keyring and return the first page of accounts', async () => { + jest.spyOn(metamaskController.keyringController, 'addNewKeyring'); - it('changes metamask controller selected address', () => { - const metamaskState = metamaskController.getState(); - expect(metamaskState.selectedAddress).toStrictEqual(TEST_ADDRESS); + const firstPage = await metamaskController.connectHardware( + HardwareDeviceNames.trezor, + 0, + ); + + expect( + metamaskController.keyringController.addNewKeyring, + ).toHaveBeenCalledWith(KeyringType.trezor); + expect( + metamaskController.keyringController.state.keyrings[1].type, + ).toBe(TrezorKeyring.type); + expect(firstPage).toStrictEqual(KNOWN_PUBLIC_KEY_ADDRESSES); + }); + + it('should add the Ledger Hardware keyring and return the first page of accounts', async () => { + jest.spyOn(metamaskController.keyringController, 'addNewKeyring'); + + const firstPage = await metamaskController.connectHardware( + HardwareDeviceNames.ledger, + 0, + ); + + expect( + metamaskController.keyringController.addNewKeyring, + ).toHaveBeenCalledWith(KeyringType.ledger); + expect( + metamaskController.keyringController.state.keyrings[1].type, + ).toBe(LedgerKeyring.type); + expect(firstPage).toStrictEqual(KNOWN_PUBLIC_KEY_ADDRESSES); + }); }); - }); - describe('connectHardware', () => { - it('should throw if it receives an unknown device name', async () => { - const result = metamaskController.connectHardware( - 'Some random device name', - 0, - `m/44/0'/0'`, - ); + describe('checkHardwareStatus', () => { + it('should throw if it receives an unknown device name', async () => { + const result = metamaskController.checkHardwareStatus( + 'Some random device name', + `m/44/0'/0'`, + ); + await expect(result).rejects.toThrow( + 'MetamaskController:getKeyringForDevice - Unknown device', + ); + }); + + [HardwareDeviceNames.trezor, HardwareDeviceNames.ledger].forEach( + (device) => { + describe(`using ${device}`, () => { + it('should be unlocked by default', async () => { + await metamaskController.connectHardware(device, 0); + + const status = await metamaskController.checkHardwareStatus( + device, + ); - await expect(result).rejects.toThrow( - 'MetamaskController:getKeyringForDevice - Unknown device', + expect(status).toStrictEqual(true); + }); + }); + }, ); }); - it('should add the Trezor Hardware keyring', async () => { - jest.spyOn(metamaskController.keyringController, 'addNewKeyring'); - await metamaskController - .connectHardware(HardwareDeviceNames.trezor, 0) - .catch(() => null); - const keyrings = - await metamaskController.keyringController.getKeyringsByType( - KeyringType.trezor, + describe('forgetDevice', () => { + it('should throw if it receives an unknown device name', async () => { + const result = metamaskController.forgetDevice( + 'Some random device name', ); - expect( - metamaskController.keyringController.addNewKeyring, - ).toHaveBeenCalledWith(KeyringType.trezor); - expect(keyrings).toHaveLength(1); - }); + await expect(result).rejects.toThrow( + 'MetamaskController:getKeyringForDevice - Unknown device', + ); + }); - it('should add the Ledger Hardware keyring', async () => { - jest.spyOn(metamaskController.keyringController, 'addNewKeyring'); - await metamaskController - .connectHardware(HardwareDeviceNames.ledger, 0) - .catch(() => null); - const keyrings = - await metamaskController.keyringController.getKeyringsByType( - KeyringType.ledger, + it('should remove the identities when the device is forgotten', async () => { + await metamaskController.connectHardware( + HardwareDeviceNames.trezor, + 0, ); - expect( - metamaskController.keyringController.addNewKeyring, - ).toHaveBeenCalledWith(KeyringType.ledger); - expect(keyrings).toHaveLength(1); - }); - }); + await metamaskController.unlockHardwareWalletAccount( + 0, + HardwareDeviceNames.trezor, + ); + const hardwareKeyringAccount = + metamaskController.keyringController.state.keyrings[1].accounts[0]; - describe('getPrimaryKeyringMnemonic', () => { - it('should return a mnemonic as a Uint8Array', () => { - const mockMnemonic = - 'above mercy benefit hospital call oval domain student sphere interest argue shock'; - const mnemonicIndices = mockMnemonic - .split(' ') - .map((word) => englishWordlist.indexOf(word)); - const uint8ArrayMnemonic = new Uint8Array( - new Uint16Array(mnemonicIndices).buffer, - ); + await metamaskController.forgetDevice(HardwareDeviceNames.trezor); - const mockHDKeyring = { - type: 'HD Key Tree', - mnemonic: uint8ArrayMnemonic, - }; - jest - .spyOn(metamaskController.keyringController, 'getKeyringsByType') - .mockReturnValue([mockHDKeyring]); + expect( + Object.keys( + metamaskController.preferencesController.store.getState() + .identities, + ), + ).not.toContain(hardwareKeyringAccount); + expect( + metamaskController.accountsController + .listAccounts() + .some((account) => account.address === hardwareKeyringAccount), + ).toStrictEqual(false); + }); - const recoveredMnemonic = - metamaskController.getPrimaryKeyringMnemonic(); + it('should wipe all the keyring info', async () => { + await metamaskController.connectHardware( + HardwareDeviceNames.trezor, + 0, + ); - expect(recoveredMnemonic).toStrictEqual(uint8ArrayMnemonic); - }); - }); + await metamaskController.forgetDevice(HardwareDeviceNames.trezor); + const keyrings = + await metamaskController.keyringController.getKeyringsByType( + KeyringType.trezor, + ); - describe('checkHardwareStatus', () => { - it('should throw if it receives an unknown device name', async () => { - const result = metamaskController.checkHardwareStatus( - 'Some random device name', - `m/44/0'/0'`, - ); - await expect(result).rejects.toThrow( - 'MetamaskController:getKeyringForDevice - Unknown device', - ); + expect(keyrings[0].accounts).toStrictEqual([]); + expect(keyrings[0].page).toStrictEqual(0); + expect(keyrings[0].isUnlocked()).toStrictEqual(false); + }); }); - it('should be locked by default', async () => { - await metamaskController - .connectHardware(HardwareDeviceNames.trezor, 0) - .catch(() => null); - const status = await metamaskController.checkHardwareStatus( - HardwareDeviceNames.trezor, - ); - expect(status).toStrictEqual(false); - }); - }); + describe('unlockHardwareWalletAccount', () => { + const accountToUnlock = 0; - describe('forgetDevice', () => { - it('should throw if it receives an unknown device name', async () => { - const result = metamaskController.forgetDevice( - 'Some random device name', - ); - await expect(result).rejects.toThrow( - 'MetamaskController:getKeyringForDevice - Unknown device', - ); - }); + [HardwareDeviceNames.trezor, HardwareDeviceNames.ledger].forEach( + (device) => { + describe(`using ${device}`, () => { + beforeEach(async () => { + await metamaskController.connectHardware(device, 0); + }); - it('should remove the identities when the device is forgotten', async () => { - jest.spyOn(window, 'open').mockReturnValue(); + it('should return the unlocked account', async () => { + const { unlockedAccount } = + await metamaskController.unlockHardwareWalletAccount( + accountToUnlock, + device, + ); + + expect(unlockedAccount).toBe( + KNOWN_PUBLIC_KEY_ADDRESSES[ + accountToUnlock + ].address.toLowerCase(), + ); + }); - const localMetaMaskController = new MetaMaskController({ - showUserConfirmation: noop, - encryptor: mockEncryptor, - initState: { - ...cloneDeep(firstTimeState), - KeyringController: { - keyrings: [{ type: KeyringType.trezor, accounts: ['0x123'] }], - isUnlocked: true, - }, - PreferencesController: { - identities: { - '0x123': { name: 'Trezor 1', address: '0x123' }, - }, - selectedAddress: '0x123', - }, - }, - initLangCode: 'en_US', - platform: { - showTransactionNotification: () => undefined, - getVersion: () => 'foo', - }, - browser: browserPolyfillMock, - infuraProjectId: 'foo', - isFirstMetaMaskControllerSetup: true, - }); + it('should add the unlocked account to KeyringController', async () => { + await metamaskController.unlockHardwareWalletAccount( + accountToUnlock, + device, + ); - await localMetaMaskController.keyringController.createNewVaultAndKeychain( - 'password', - ); + expect( + metamaskController.keyringController.state.keyrings[1] + .accounts, + ).toStrictEqual([ + KNOWN_PUBLIC_KEY_ADDRESSES[ + accountToUnlock + ].address.toLowerCase(), + ]); + }); - await localMetaMaskController.keyringController.addNewKeyring( - 'Trezor Hardware', - { - accounts: ['0x123'], - }, - ); + it('should call keyringController.addNewAccountForKeyring', async () => { + jest.spyOn( + metamaskController.keyringController, + 'addNewAccountForKeyring', + ); - await localMetaMaskController.forgetDevice(HardwareDeviceNames.trezor); - const { identities: updatedIdentities } = - localMetaMaskController.preferencesController.store.getState(); - expect(updatedIdentities['0x123']).toBeUndefined(); - }); + await metamaskController.unlockHardwareWalletAccount( + accountToUnlock, + device, + ); - it('should wipe all the keyring info', async () => { - await metamaskController - .connectHardware(HardwareDeviceNames.trezor, 0) - .catch(() => null); - await metamaskController.forgetDevice(HardwareDeviceNames.trezor); - const keyrings = - await metamaskController.keyringController.getKeyringsByType( - KeyringType.trezor, - ); + expect( + metamaskController.keyringController.addNewAccountForKeyring, + ).toHaveBeenCalledTimes(1); + }); - expect(keyrings[0].accounts).toStrictEqual([]); - expect(keyrings[0].page).toStrictEqual(0); - expect(keyrings[0].isUnlocked()).toStrictEqual(false); - }); - }); + it('should call preferencesController.setSelectedAddress', async () => { + jest.spyOn( + metamaskController.preferencesController, + 'setSelectedAddress', + ); - describe('unlockHardwareWalletAccount', () => { - const accountToUnlock = 10; - beforeEach(async () => { - await metamaskController.keyringController.createNewVaultAndRestore( - 'password', - TEST_SEED, - ); - jest.spyOn(window, 'open').mockReturnValue(); - jest - .spyOn( - metamaskController.keyringController, - 'addNewAccountForKeyring', - ) - .mockReturnValue('0x123'); + await metamaskController.unlockHardwareWalletAccount( + accountToUnlock, + device, + ); - jest - .spyOn(metamaskController.keyringController, 'getAccounts') - .mockResolvedValueOnce(['0x1']) - .mockResolvedValueOnce(['0x2']) - .mockResolvedValueOnce(['0x3']); - jest - .spyOn(metamaskController.preferencesController, 'setAddresses') - .mockReturnValue(); - jest - .spyOn(metamaskController.preferencesController, 'setSelectedAddress') - .mockReturnValue(); - jest - .spyOn(metamaskController.preferencesController, 'setAccountLabel') - .mockReturnValue(); + expect( + metamaskController.preferencesController.setSelectedAddress, + ).toHaveBeenCalledTimes(1); + }); - jest - .spyOn(metamaskController.accountsController, 'getAccountByAddress') - .mockReturnValue({ - account: { - id: '2d47e693-26c2-47cb-b374-6151199bbe3f', - }, - }); - jest - .spyOn(metamaskController.accountsController, 'setAccountName') - .mockReturnValue(); + it('should call preferencesController.setAccountLabel', async () => { + jest.spyOn( + metamaskController.preferencesController, + 'setAccountLabel', + ); - await metamaskController.unlockHardwareWalletAccount( - accountToUnlock, - HardwareDeviceNames.trezor, - `m/44'/1'/0'/0`, - ); - }); + await metamaskController.unlockHardwareWalletAccount( + accountToUnlock, + device, + ); - it('should set unlockedAccount in the keyring', async () => { - const keyrings = - await metamaskController.keyringController.getKeyringsByType( - KeyringType.trezor, - ); - expect(keyrings[0].unlockedAccount).toStrictEqual(accountToUnlock); - }); + expect( + metamaskController.preferencesController.setAccountLabel, + ).toHaveBeenCalledTimes(1); + }); - it('should call keyringController.addNewAccount', async () => { - expect( - metamaskController.keyringController.addNewAccountForKeyring, - ).toHaveBeenCalledTimes(1); - }); + it('should call accountsController.getAccountByAddress', async () => { + jest.spyOn( + metamaskController.accountsController, + 'getAccountByAddress', + ); - it('should call keyringController.getAccounts', async () => { - expect( - metamaskController.keyringController.getAccounts, - ).toHaveBeenCalledTimes(3); - }); + await metamaskController.unlockHardwareWalletAccount( + accountToUnlock, + device, + ); - it('should call preferencesController.setAddresses', async () => { - expect( - metamaskController.preferencesController.setAddresses, - ).toHaveBeenCalledTimes(1); - }); + expect( + metamaskController.accountsController.getAccountByAddress, + ).toHaveBeenCalledTimes(1); + }); - it('should call preferencesController.setSelectedAddress', async () => { - expect( - metamaskController.preferencesController.setSelectedAddress, - ).toHaveBeenCalledTimes(1); - }); + it('should call accountsController.setAccountName', async () => { + jest.spyOn( + metamaskController.accountsController, + 'setAccountName', + ); - it('should call preferencesController.setAccountLabel', async () => { - expect( - metamaskController.preferencesController.setAccountLabel, - ).toHaveBeenCalledTimes(1); - }); + await metamaskController.unlockHardwareWalletAccount( + accountToUnlock, + device, + ); - it('should call accountsController.getAccountByAddress', async () => { - expect( - metamaskController.accountsController.getAccountByAddress, - ).toHaveBeenCalledTimes(1); + expect( + metamaskController.accountsController.setAccountName, + ).toHaveBeenCalledTimes(1); + }); + }); + }, + ); }); + }); - it('should call accountsController.setAccountName', async () => { - expect( - metamaskController.accountsController.setAccountName, - ).toHaveBeenCalledTimes(1); + describe('getPrimaryKeyringMnemonic', () => { + it('should return a mnemonic as a Uint8Array', () => { + const mockMnemonic = + 'above mercy benefit hospital call oval domain student sphere interest argue shock'; + const mnemonicIndices = mockMnemonic + .split(' ') + .map((word) => englishWordlist.indexOf(word)); + const uint8ArrayMnemonic = new Uint8Array( + new Uint16Array(mnemonicIndices).buffer, + ); + + const mockHDKeyring = { + type: 'HD Key Tree', + mnemonic: uint8ArrayMnemonic, + }; + jest + .spyOn(metamaskController.keyringController, 'getKeyringsByType') + .mockReturnValue([mockHDKeyring]); + + const recoveredMnemonic = + metamaskController.getPrimaryKeyringMnemonic(); + + expect(recoveredMnemonic).toStrictEqual(uint8ArrayMnemonic); }); }); @@ -1020,15 +1135,28 @@ describe('MetaMaskController', () => { .mockReturnValue({ address: selectedAddressMock }); jest.spyOn(metamaskController.txController, 'wipeTransactions'); + jest.spyOn( + metamaskController.smartTransactionsController, + 'wipeSmartTransactions', + ); await metamaskController.resetAccount(); expect( metamaskController.txController.wipeTransactions, ).toHaveBeenCalledTimes(1); + expect( + metamaskController.smartTransactionsController.wipeSmartTransactions, + ).toHaveBeenCalledTimes(1); expect( metamaskController.txController.wipeTransactions, - ).toHaveBeenCalledWith(true, selectedAddressMock); + ).toHaveBeenCalledWith(false, selectedAddressMock); + expect( + metamaskController.smartTransactionsController.wipeSmartTransactions, + ).toHaveBeenCalledWith({ + address: selectedAddressMock, + ignoreNetwork: false, + }); }); }); @@ -1087,6 +1215,10 @@ describe('MetaMaskController', () => { metamaskController.preferencesController.setSecurityAlertsEnabled( false, ); + jest + .spyOn(metamaskController.onboardingController.store, 'getState') + .mockReturnValue({ completedOnboarding: true }); + metamaskController.preferencesController.setUsePhishDetect(true); }); afterAll(() => { @@ -1120,6 +1252,49 @@ describe('MetaMaskController', () => { streamTest.end(); }); + it('checks the sender hostname with the phishing controller', async () => { + jest + .spyOn(metamaskController.phishingController, 'maybeUpdateState') + .mockReturnValue(); + + jest + .spyOn(metamaskController.phishingController, 'test') + .mockReturnValue({ result: 'mock' }); + + jest.spyOn(metamaskController, 'sendPhishingWarning').mockReturnValue(); + const phishingMessageSender = { + url: 'http://test.metamask-phishing.io', + tab: {}, + }; + + const { resolve } = deferredPromise(); + const streamTest = createThoughStream((chunk, _, cb) => { + if (chunk.name !== 'phishing') { + cb(); + return; + } + expect(chunk.data.hostname).toStrictEqual( + new URL(phishingMessageSender.url).hostname, + ); + resolve(); + cb(); + }); + + metamaskController.setupUntrustedCommunication({ + connectionStream: streamTest, + sender: phishingMessageSender, + }); + + expect( + metamaskController.phishingController.maybeUpdateState, + ).toHaveBeenCalled(); + expect(metamaskController.phishingController.test).toHaveBeenCalled(); + expect(metamaskController.sendPhishingWarning).toHaveBeenCalledWith( + expect.anything(), + 'test.metamask-phishing.io', + ); + }); + it('adds a tabId, origin and networkClient to requests', async () => { const messageSender = { url: 'http://mycrypto.com', @@ -1255,10 +1430,12 @@ describe('MetaMaskController', () => { }); describe('#_onKeyringControllerUpdate', () => { + const accounts = [ + '0x603E83442BA54A2d0E080c34D6908ec228bef59f', + '0xDe95cE6E727692286E02A931d074efD1E5E2f03c', + ]; + it('should do nothing if there are no keyrings in state', async () => { - jest - .spyOn(metamaskController.preferencesController, 'syncAddresses') - .mockReturnValue(); jest .spyOn(metamaskController.accountTracker, 'syncWithAddresses') .mockReturnValue(); @@ -1266,9 +1443,6 @@ describe('MetaMaskController', () => { const oldState = metamaskController.getState(); await metamaskController._onKeyringControllerUpdate({ keyrings: [] }); - expect( - metamaskController.preferencesController.syncAddresses, - ).not.toHaveBeenCalled(); expect( metamaskController.accountTracker.syncWithAddresses, ).not.toHaveBeenCalled(); @@ -1276,9 +1450,6 @@ describe('MetaMaskController', () => { }); it('should sync addresses if there are keyrings in state', async () => { - jest - .spyOn(metamaskController.preferencesController, 'syncAddresses') - .mockReturnValue(); jest .spyOn(metamaskController.accountTracker, 'syncWithAddresses') .mockReturnValue(); @@ -1287,24 +1458,18 @@ describe('MetaMaskController', () => { await metamaskController._onKeyringControllerUpdate({ keyrings: [ { - accounts: ['0x1', '0x2'], + accounts, }, ], }); - expect( - metamaskController.preferencesController.syncAddresses, - ).toHaveBeenCalledWith(['0x1', '0x2']); expect( metamaskController.accountTracker.syncWithAddresses, - ).toHaveBeenCalledWith(['0x1', '0x2']); + ).toHaveBeenCalledWith(accounts); expect(metamaskController.getState()).toStrictEqual(oldState); }); it('should NOT update selected address if already unlocked', async () => { - jest - .spyOn(metamaskController.preferencesController, 'syncAddresses') - .mockReturnValue(); jest .spyOn(metamaskController.accountTracker, 'syncWithAddresses') .mockReturnValue(); @@ -1314,17 +1479,38 @@ describe('MetaMaskController', () => { isUnlocked: true, keyrings: [ { - accounts: ['0x1', '0x2'], + accounts, }, ], }); expect( - metamaskController.preferencesController.syncAddresses, - ).toHaveBeenCalledWith(['0x1', '0x2']); + metamaskController.accountTracker.syncWithAddresses, + ).toHaveBeenCalledWith(accounts); + expect(metamaskController.getState()).toStrictEqual(oldState); + }); + + it('filter out non-EVM addresses prior to calling syncWithAddresses', async () => { + jest + .spyOn(metamaskController.accountTracker, 'syncWithAddresses') + .mockReturnValue(); + + const oldState = metamaskController.getState(); + await metamaskController._onKeyringControllerUpdate({ + keyrings: [ + { + accounts: [ + ...accounts, + // Non-EVM address which should not be used by syncWithAddresses + 'bc1ql49ydapnjafl5t2cp9zqpjwe6pdgmxy98859v2', + ], + }, + ], + }); + expect( metamaskController.accountTracker.syncWithAddresses, - ).toHaveBeenCalledWith(['0x1', '0x2']); + ).toHaveBeenCalledWith(accounts); expect(metamaskController.getState()).toStrictEqual(oldState); }); }); @@ -1779,13 +1965,11 @@ describe('MetaMaskController', () => { TransactionController.prototype.startIncomingTransactionPolling, ).not.toHaveBeenCalled(); - await metamaskController.preferencesController.store.subscribe.mock.lastCall[0]( - { - incomingTransactionsPreferences: { - [MAINNET_CHAIN_ID]: true, - }, + await simulatePreferencesChange({ + incomingTransactionsPreferences: { + [MAINNET_CHAIN_ID]: true, }, - ); + }); expect( TransactionController.prototype.startIncomingTransactionPolling, @@ -1797,13 +1981,11 @@ describe('MetaMaskController', () => { TransactionController.prototype.stopIncomingTransactionPolling, ).not.toHaveBeenCalled(); - await metamaskController.preferencesController.store.subscribe.mock.lastCall[0]( - { - incomingTransactionsPreferences: { - [MAINNET_CHAIN_ID]: false, - }, + await simulatePreferencesChange({ + incomingTransactionsPreferences: { + [MAINNET_CHAIN_ID]: false, }, - ); + }); expect( TransactionController.prototype.stopIncomingTransactionPolling, @@ -1839,6 +2021,283 @@ describe('MetaMaskController', () => { ).toHaveBeenCalledTimes(1); }); }); + + describe('token list controller', () => { + it('stops polling if petnames, simulations, and token detection disabled', async () => { + expect(TokenListController.prototype.stop).not.toHaveBeenCalled(); + + expect( + TokenListController.prototype.clearingTokenListData, + ).not.toHaveBeenCalled(); + + await simulatePreferencesChange({ + useTransactionSimulations: false, + useTokenDetection: false, + preferences: { + petnamesEnabled: false, + }, + }); + + expect(TokenListController.prototype.stop).toHaveBeenCalledTimes(1); + + expect( + TokenListController.prototype.clearingTokenListData, + ).toHaveBeenCalledTimes(1); + }); + + it.each([ + [ + 'petnames', + { + preferences: { petnamesEnabled: false }, + useTokenDetection: true, + useTransactionSimulations: true, + }, + ], + [ + 'simulations', + { + preferences: { petnamesEnabled: true }, + useTokenDetection: true, + useTransactionSimulations: false, + }, + ], + [ + 'token detection', + { + preferences: { petnamesEnabled: true }, + useTokenDetection: false, + useTransactionSimulations: true, + }, + ], + ])( + 'does not stop polling if only %s disabled', + async (_, preferences) => { + expect(TokenListController.prototype.stop).not.toHaveBeenCalled(); + + expect( + TokenListController.prototype.clearingTokenListData, + ).not.toHaveBeenCalled(); + + await simulatePreferencesChange(preferences); + + expect(TokenListController.prototype.stop).not.toHaveBeenCalled(); + + expect( + TokenListController.prototype.clearingTokenListData, + ).not.toHaveBeenCalled(); + }, + ); + + it.each([ + [ + 'petnames', + { + preferences: { petnamesEnabled: true }, + useTokenDetection: false, + useTransactionSimulations: false, + }, + ], + [ + 'simulations', + { + preferences: { petnamesEnabled: false }, + useTokenDetection: false, + useTransactionSimulations: true, + }, + ], + [ + 'token detection', + { + preferences: { petnamesEnabled: false }, + useTokenDetection: true, + useTransactionSimulations: false, + }, + ], + ])('starts polling if only %s enabled', async (_, preferences) => { + expect(TokenListController.prototype.start).not.toHaveBeenCalled(); + + await simulatePreferencesChange({ + useTransactionSimulations: false, + useTokenDetection: false, + preferences: { + petnamesEnabled: false, + }, + }); + + await simulatePreferencesChange(preferences); + + expect(TokenListController.prototype.start).toHaveBeenCalledTimes(1); + }); + }); + + describe('MultichainRatesController start/stop', () => { + const mockEvmAccount = createMockInternalAccount(); + const mockNonEvmAccount = { + ...mockEvmAccount, + id: '21690786-6abd-45d8-a9f0-9ff1d8ca76a1', + type: BtcAccountType.P2wpkh, + methods: [BtcMethod.SendMany], + address: 'bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq', + }; + + beforeEach(() => { + jest.spyOn(metamaskController.multichainRatesController, 'start'); + jest.spyOn(metamaskController.multichainRatesController, 'stop'); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('starts MultichainRatesController if selected account is changed to non-EVM', async () => { + expect( + metamaskController.multichainRatesController.start, + ).not.toHaveBeenCalled(); + + metamaskController.controllerMessenger.publish( + 'AccountsController:selectedAccountChange', + mockNonEvmAccount, + ); + + expect( + metamaskController.multichainRatesController.start, + ).toHaveBeenCalledTimes(1); + }); + + it('stops MultichainRatesController if selected account is changed to EVM', async () => { + expect( + metamaskController.multichainRatesController.start, + ).not.toHaveBeenCalled(); + + metamaskController.controllerMessenger.publish( + 'AccountsController:selectedAccountChange', + mockNonEvmAccount, + ); + + expect( + metamaskController.multichainRatesController.start, + ).toHaveBeenCalledTimes(1); + + metamaskController.controllerMessenger.publish( + 'AccountsController:selectedAccountChange', + mockEvmAccount, + ); + expect( + metamaskController.multichainRatesController.start, + ).toHaveBeenCalledTimes(1); + expect( + metamaskController.multichainRatesController.stop, + ).toHaveBeenCalledTimes(1); + }); + + it('does not start MultichainRatesController if selected account is changed to EVM', async () => { + expect( + metamaskController.multichainRatesController.start, + ).not.toHaveBeenCalled(); + + metamaskController.controllerMessenger.publish( + 'AccountsController:selectedAccountChange', + mockEvmAccount, + ); + + expect( + metamaskController.multichainRatesController.start, + ).not.toHaveBeenCalled(); + }); + + it('starts MultichainRatesController if selected account is non-EVM account during initialization', async () => { + jest.spyOn(RatesController.prototype, 'start'); + const localMetamaskController = new MetaMaskController({ + showUserConfirmation: noop, + encryptor: mockEncryptor, + initState: { + ...cloneDeep(firstTimeState), + AccountsController: { + internalAccounts: { + accounts: { + [mockNonEvmAccount.id]: mockNonEvmAccount, + [mockEvmAccount.id]: mockEvmAccount, + }, + selectedAccount: mockNonEvmAccount.id, + }, + }, + }, + initLangCode: 'en_US', + platform: { + showTransactionNotification: () => undefined, + getVersion: () => 'foo', + }, + browser: browserPolyfillMock, + infuraProjectId: 'foo', + isFirstMetaMaskControllerSetup: true, + }); + + expect( + localMetamaskController.multichainRatesController.start, + ).toHaveBeenCalled(); + }); + }); + + describe('MultichainBalancesController', () => { + const mockEvmAccount = createMockInternalAccount(); + const mockNonEvmAccount = { + ...mockEvmAccount, + id: '21690786-6abd-45d8-a9f0-9ff1d8ca76a1', + type: BtcAccountType.P2wpkh, + methods: [BtcMethod.SendMany], + address: 'bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq', + }; + let localMetamaskController; + + beforeEach(() => { + jest.useFakeTimers(); + jest.spyOn(MultichainBalancesController.prototype, 'updateBalances'); + localMetamaskController = new MetaMaskController({ + showUserConfirmation: noop, + encryptor: mockEncryptor, + initState: { + ...cloneDeep(firstTimeState), + AccountsController: { + internalAccounts: { + accounts: { + [mockNonEvmAccount.id]: mockNonEvmAccount, + [mockEvmAccount.id]: mockEvmAccount, + }, + selectedAccount: mockNonEvmAccount.id, + }, + }, + }, + initLangCode: 'en_US', + platform: { + showTransactionNotification: () => undefined, + getVersion: () => 'foo', + }, + browser: browserPolyfillMock, + infuraProjectId: 'foo', + isFirstMetaMaskControllerSetup: true, + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + jest.useRealTimers(); + }); + + it('calls updateBalances during startup', async () => { + expect( + localMetamaskController.multichainBalancesController.updateBalances, + ).toHaveBeenCalled(); + }); + + it('calls updateBalances after the interval has passed', async () => { + jest.advanceTimersByTime(BTC_AVG_BLOCK_TIME); + // 2 calls because 1 is during startup + expect( + localMetamaskController.multichainBalancesController.updateBalances, + ).toHaveBeenCalledTimes(2); + }); + }); }); describe('MV3 Specific behaviour', () => { diff --git a/app/scripts/migrations/081.ts b/app/scripts/migrations/081.ts index 0162a43b6e49..aa7e48a8c9fa 100644 --- a/app/scripts/migrations/081.ts +++ b/app/scripts/migrations/081.ts @@ -91,7 +91,7 @@ function transformState(state: Record) { // Adding the snap name to the wallet_snap permission's caveat value const snapId = permissionName.slice(snapPrefix.length); const caveat = ( - (updatedPermissions.wallet_snap as Record) + (updatedPermissions.wallet_snap as Record) .caveats as unknown[] )[0]; diff --git a/app/scripts/migrations/095.test.ts b/app/scripts/migrations/095.test.ts index d4858de9066f..988f59b8f5f8 100644 --- a/app/scripts/migrations/095.test.ts +++ b/app/scripts/migrations/095.test.ts @@ -156,12 +156,13 @@ describe('migration #95', () => { }); }); + // @ts-expect-error This is missing from the Mocha type definitions it.each([ ['undefined', undefined], ['empty', {}], ])( 'does nothing if incoming transactions %s', - async (_title, incomingTransactions) => { + async (_title: string, incomingTransactions: unknown) => { const oldData = { some: 'data', IncomingTransactionsController: { diff --git a/app/scripts/migrations/095.ts b/app/scripts/migrations/095.ts index 39128284e03f..6361bba388fc 100644 --- a/app/scripts/migrations/095.ts +++ b/app/scripts/migrations/095.ts @@ -35,7 +35,11 @@ function migrateData(state: Record): void { removeIncomingTransactionsControllerState(state); } +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any function moveIncomingTransactions(state: Record) { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const incomingTransactions: Record = state.IncomingTransactionsController?.incomingTransactions || {}; @@ -46,6 +50,8 @@ function moveIncomingTransactions(state: Record) { const transactions = state.TransactionController?.transactions || {}; const updatedTransactions = Object.values(incomingTransactions).reduce( + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any (result: Record, tx: any) => { result[tx.id] = tx; return result; @@ -59,7 +65,11 @@ function moveIncomingTransactions(state: Record) { }; } +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any function generateLastFetchedBlockNumbers(state: Record) { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const incomingTransactions: Record = state.IncomingTransactionsController?.incomingTransactions || {}; diff --git a/app/scripts/migrations/096.ts b/app/scripts/migrations/096.ts index 749956a726b2..b04b7613e008 100644 --- a/app/scripts/migrations/096.ts +++ b/app/scripts/migrations/096.ts @@ -4,6 +4,8 @@ import { CHAIN_IDS } from '../../../shared/constants/network'; type VersionedData = { meta: { version: number }; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any data: Record; }; @@ -34,6 +36,8 @@ export async function migrate( } type NetworkConfiguration = { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any chainId: Record; }; @@ -48,10 +52,18 @@ function transformState(state: Record) { return state; } const { PreferencesController, NetworkController } = state; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const { featureFlags }: Record = PreferencesController; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const { showIncomingTransactions }: any = featureFlags; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const { networkConfigurations }: Record = NetworkController; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const addedNetwork: Record[] = Object.values(networkConfigurations).map( (network) => network.chainId, @@ -63,6 +75,8 @@ function transformState(state: Record) { CHAIN_IDS.SEPOLIA, CHAIN_IDS.LINEA_GOERLI, ]; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const allSavedNetworks: Record = [ ...mainNetworks, ...addedNetwork, diff --git a/app/scripts/migrations/097.ts b/app/scripts/migrations/097.ts index 9e99cf61b40a..56a11679449d 100644 --- a/app/scripts/migrations/097.ts +++ b/app/scripts/migrations/097.ts @@ -21,6 +21,8 @@ export async function migrate( return versionedData; } +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any function transformState(state: Record) { const transactionControllerState = state?.TransactionController || {}; const transactions = transactionControllerState?.transactions || {}; diff --git a/app/scripts/migrations/098.ts b/app/scripts/migrations/098.ts index 3085827b4c6a..2fe77148e052 100644 --- a/app/scripts/migrations/098.ts +++ b/app/scripts/migrations/098.ts @@ -25,6 +25,8 @@ export async function migrate( return versionedData; } +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any function transformState(state: Record) { const transactionControllerState = state?.TransactionController || {}; const transactions = transactionControllerState?.transactions || {}; diff --git a/app/scripts/migrations/099.test.ts b/app/scripts/migrations/099.test.ts index 1feba98e6fa3..3b98f4f72a26 100644 --- a/app/scripts/migrations/099.test.ts +++ b/app/scripts/migrations/099.test.ts @@ -72,6 +72,8 @@ describe('migration #99', () => { const newStorage = await migrate(oldStorage); + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const migratedTransactions = (newStorage.data.TransactionController as any) .transactions; diff --git a/app/scripts/migrations/099.ts b/app/scripts/migrations/099.ts index 9464d19a64df..38018c97919d 100644 --- a/app/scripts/migrations/099.ts +++ b/app/scripts/migrations/099.ts @@ -24,6 +24,8 @@ export async function migrate( return versionedData; } +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any function transformState(state: Record) { const transactionControllerState = state?.TransactionController || {}; const transactions = transactionControllerState?.transactions || {}; @@ -33,6 +35,8 @@ function transformState(state: Record) { } const newTxs = Object.keys(transactions).reduce( + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any (txs: { [key: string]: any }, oldTransactionId) => { // Clone the transaction const transaction = cloneDeep(transactions[oldTransactionId]); diff --git a/app/scripts/migrations/100.ts b/app/scripts/migrations/100.ts index c9b4a99afceb..89dbe0d5670d 100644 --- a/app/scripts/migrations/100.ts +++ b/app/scripts/migrations/100.ts @@ -25,6 +25,8 @@ export async function migrate( return versionedData; } +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any function transformState(state: Record) { const addressBook = state?.AddressBookController?.addressBook ?? {}; const names = state?.NameController?.names?.ethereumAddress ?? {}; diff --git a/app/scripts/migrations/102.ts b/app/scripts/migrations/102.ts index 820e67605251..a1fde4f27f7f 100644 --- a/app/scripts/migrations/102.ts +++ b/app/scripts/migrations/102.ts @@ -23,6 +23,8 @@ export async function migrate( return versionedData; } +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any function transformState(state: Record) { const transactionControllerState = state?.TransactionController || {}; const transactions = transactionControllerState?.transactions || {}; @@ -32,6 +34,8 @@ function transformState(state: Record) { } const newTxs = Object.keys(transactions).reduce( + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any (txs: { [key: string]: any }, txId) => { // Clone the transaction const transaction = cloneDeep(transactions[txId]); diff --git a/app/scripts/migrations/104.ts b/app/scripts/migrations/104.ts index 340d167ccd5f..38ab3c0f57c8 100644 --- a/app/scripts/migrations/104.ts +++ b/app/scripts/migrations/104.ts @@ -22,6 +22,8 @@ export async function migrate( return versionedData; } +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any function transformState(state: Record) { const transactionControllerState = state?.TransactionController; @@ -32,6 +34,8 @@ function transformState(state: Record) { const transactionsObject = transactionControllerState?.transactions || {}; const transactionsArray = Object.values(transactionsObject).sort( + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any (a: any, b: any) => (a.time > b.time ? -1 : 1), // Descending ); diff --git a/app/scripts/migrations/105.test.ts b/app/scripts/migrations/105.test.ts index c25659b641c9..944606043075 100644 --- a/app/scripts/migrations/105.test.ts +++ b/app/scripts/migrations/105.test.ts @@ -1,6 +1,7 @@ import { v4 as uuid } from 'uuid'; import { sha256FromString } from 'ethereumjs-util'; -import { EthMethod, InternalAccount } from '@metamask/keyring-api'; +import { InternalAccount } from '@metamask/keyring-api'; +import { ETH_EOA_METHODS } from '../../../shared/constants/eth-methods'; import { migrate } from './105'; const MOCK_ADDRESS = '0x0'; @@ -73,7 +74,7 @@ function expectedInternalAccount( lastSelected: lastSelected ? expect.any(Number) : undefined, }, options: {}, - methods: [...Object.values(EthMethod)], + methods: ETH_EOA_METHODS, type: 'eip155:eoa', }; } @@ -94,7 +95,7 @@ function createMockState( describe('migration #105', () => { it('updates the version metadata', async () => { const oldStorage = { - meta: { version: 103 }, + meta: { version: 104 }, data: createMockState(), }; @@ -108,7 +109,7 @@ describe('migration #105', () => { const oldData = createMockState(); const oldStorage = { - meta: { version: 103 }, + meta: { version: 104 }, data: oldData, }; @@ -139,7 +140,7 @@ describe('migration #105', () => { const oldData = createMockState(); const oldStorage = { - meta: { version: 103 }, + meta: { version: 104 }, data: oldData, }; @@ -151,7 +152,7 @@ describe('migration #105', () => { accounts: { [expectedUUID]: expectedInternalAccount( MOCK_ADDRESS, - `Account 1`, + 'Account 1', ), }, selectedAccount: expectedUUID, @@ -168,7 +169,7 @@ describe('migration #105', () => { ]), ); const oldStorage = { - meta: { version: 103 }, + meta: { version: 104 }, data: oldData, }; const newStorage = await migrate(oldStorage); @@ -179,7 +180,7 @@ describe('migration #105', () => { accounts: { [expectedUUID]: expectedInternalAccount( MOCK_ADDRESS, - `a random name`, + 'a random name', ), }, selectedAccount: expectedUUID, @@ -198,7 +199,7 @@ describe('migration #105', () => { }); const oldStorage = { - meta: { version: 103 }, + meta: { version: 104 }, data: oldData, }; @@ -210,11 +211,11 @@ describe('migration #105', () => { accounts: { [expectedUUID]: expectedInternalAccount( MOCK_ADDRESS, - `Account 1`, + 'Account 1', ), [expectedUUID2]: expectedInternalAccount( MOCK_ADDRESS_2, - `Account 2`, + 'Account 2', ), }, selectedAccount: expectedUUID, @@ -226,10 +227,14 @@ describe('migration #105', () => { }); describe('createSelectedAccountForAccountsController', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + it('should select the same account as the selected address', async () => { const oldData = createMockState(); const oldStorage = { - meta: { version: 103 }, + meta: { version: 104 }, data: oldData, }; const newStorage = await migrate(oldStorage); @@ -252,7 +257,7 @@ describe('migration #105', () => { }, }; const oldStorage = { - meta: { version: 103 }, + meta: { version: 104 }, data: oldData, }; const newStorage = await migrate(oldStorage); @@ -275,7 +280,7 @@ describe('migration #105', () => { }, }; const oldStorage = { - meta: { version: 103 }, + meta: { version: 104 }, data: oldData, }; await migrate(oldStorage); @@ -285,5 +290,41 @@ describe('migration #105', () => { new Error(`state.PreferencesController?.selectedAddress is undefined`), ); }); + + it('recovers from invalid selectedAddress state', async () => { + const expectedUUID = addressToUUID(MOCK_ADDRESS); + + const oldData = { + PreferencesController: { + identities: { + [MOCK_ADDRESS]: { name: 'Account 1', address: MOCK_ADDRESS }, + }, + selectedAddress: undefined, + }, + }; + const oldStorage = { + meta: { version: 104 }, + data: oldData, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.data).toStrictEqual({ + PreferencesController: expect.objectContaining({ + selectedAddress: MOCK_ADDRESS, + }), + AccountsController: { + internalAccounts: { + accounts: { + [expectedUUID]: expectedInternalAccount( + MOCK_ADDRESS, + 'Account 1', + ), + }, + selectedAccount: expectedUUID, + }, + }, + }); + }); }); }); diff --git a/app/scripts/migrations/105.ts b/app/scripts/migrations/105.ts index 10be55e69e0a..d4f5f2985215 100644 --- a/app/scripts/migrations/105.ts +++ b/app/scripts/migrations/105.ts @@ -1,11 +1,8 @@ -import { - EthAccountType, - InternalAccount, - EthMethod, -} from '@metamask/keyring-api'; +import { EthAccountType, InternalAccount } from '@metamask/keyring-api'; import { sha256FromString } from 'ethereumjs-util'; import { v4 as uuid } from 'uuid'; import { cloneDeep } from 'lodash'; +import { ETH_EOA_METHODS } from '../../../shared/constants/eth-methods'; type VersionedData = { meta: { version: number }; @@ -48,6 +45,22 @@ function migrateData(state: Record): void { createSelectedAccountForAccountsController(state); } +function findInternalAccountByAddress( + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + state: Record, + address: string, +): InternalAccount | undefined { + return Object.values( + state.AccountsController.internalAccounts.accounts, + ).find( + (account: InternalAccount) => + account.address.toLowerCase() === address.toLowerCase(), + ); +} + +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any function createDefaultAccountsController(state: Record) { state.AccountsController = { internalAccounts: { @@ -58,6 +71,8 @@ function createDefaultAccountsController(state: Record) { } function createInternalAccountsForAccountsController( + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any state: Record, ) { const identities: { @@ -89,7 +104,7 @@ function createInternalAccountsForAccountsController( type: 'HD Key Tree', }, }, - methods: [...Object.values(EthMethod)], + methods: ETH_EOA_METHODS, type: EthAccountType.Eoa, }; }); @@ -97,10 +112,23 @@ function createInternalAccountsForAccountsController( state.AccountsController.internalAccounts.accounts = accounts; } +function getFirstAddress( + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + state: Record, +) { + const [firstAddress] = Object.keys( + state.PreferencesController?.identities || {}, + ); + return firstAddress; +} + function createSelectedAccountForAccountsController( + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any state: Record, ) { - const selectedAddress = state.PreferencesController?.selectedAddress; + let selectedAddress = state.PreferencesController?.selectedAddress; if (typeof selectedAddress !== 'string') { global.sentry?.captureException?.( @@ -108,18 +136,18 @@ function createSelectedAccountForAccountsController( `state.PreferencesController?.selectedAddress is ${selectedAddress}`, ), ); - } - const selectedAccount = Object.values( - state.AccountsController.internalAccounts.accounts, - ).find((account: InternalAccount) => { - return account.address.toLowerCase() === selectedAddress.toLowerCase(); - }) as InternalAccount; + // Get the first account if selectedAddress is not a string + selectedAddress = getFirstAddress(state); + } + const selectedAccount = findInternalAccountByAddress(state, selectedAddress); if (selectedAccount) { + // Required in case there was no address selected + state.PreferencesController.selectedAddress = selectedAccount.address; state.AccountsController.internalAccounts = { ...state.AccountsController.internalAccounts, - selectedAccount: selectedAccount.id ?? '', + selectedAccount: selectedAccount.id, }; } } diff --git a/app/scripts/migrations/108.ts b/app/scripts/migrations/108.ts index 1ea75957b73a..4b12de5f9004 100644 --- a/app/scripts/migrations/108.ts +++ b/app/scripts/migrations/108.ts @@ -27,6 +27,8 @@ export async function migrate( return versionedData; } +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any function transformState(state: Record) { const addressBook = state?.AddressBookController?.addressBook ?? {}; const names = state?.NameController?.names?.ethereumAddress ?? {}; diff --git a/app/scripts/migrations/109.ts b/app/scripts/migrations/109.ts index 5c40b07d4b09..13e268b8e061 100644 --- a/app/scripts/migrations/109.ts +++ b/app/scripts/migrations/109.ts @@ -27,6 +27,8 @@ export async function migrate( return versionedData; } +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any function transformState(state: Record) { const identities: PreferencesControllerState['identities'] = state?.PreferencesController?.identities ?? {}; diff --git a/app/scripts/migrations/110.ts b/app/scripts/migrations/110.ts index bc941ac87695..7a677ed8b9cd 100644 --- a/app/scripts/migrations/110.ts +++ b/app/scripts/migrations/110.ts @@ -35,6 +35,8 @@ export async function migrate( return versionedData; } +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any function transformState(state: Record) { const NetworkController = state?.NetworkController || {}; const provider = NetworkController?.providerConfig || {}; diff --git a/app/scripts/migrations/111.ts b/app/scripts/migrations/111.ts index a45c24fa168f..1a06e655cabb 100644 --- a/app/scripts/migrations/111.ts +++ b/app/scripts/migrations/111.ts @@ -28,6 +28,8 @@ export async function migrate( return versionedData; } +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any function transformState(state: Record) { if (!hasProperty(state, 'SelectedNetworkController')) { return state; diff --git a/app/scripts/migrations/112.ts b/app/scripts/migrations/112.ts index 6313462be199..519be68c9ca3 100644 --- a/app/scripts/migrations/112.ts +++ b/app/scripts/migrations/112.ts @@ -26,6 +26,8 @@ export async function migrate( return versionedData; } +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any function transformState(state: Record) { if (!hasProperty(state, 'SelectedNetworkController')) { return state; diff --git a/app/scripts/migrations/113.test.ts b/app/scripts/migrations/113.test.ts new file mode 100644 index 000000000000..be687ec0215e --- /dev/null +++ b/app/scripts/migrations/113.test.ts @@ -0,0 +1,52 @@ +import { migrate, version } from './113'; + +const oldVersion = 112; + +describe('migration #113', () => { + it('updates the version metadata', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.meta).toStrictEqual({ version }); + }); + + it('should do nothing if isLineaMainnetReleased state does not exist', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: { + PreferencesController: { + bar: 'baz', + }, + foo: 'bar', + }, + }; + + const newStorage = await migrate(oldStorage); + expect(oldStorage.data).toStrictEqual(newStorage.data); + }); + + it('should delete isLineaMainnetReleased state', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: { + PreferencesController: { + isLineaMainnetReleased: true, + bar: 'baz', + }, + foo: 'bar', + }, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual({ + PreferencesController: { + bar: 'baz', + }, + foo: 'bar', + }); + }); +}); diff --git a/app/scripts/migrations/113.ts b/app/scripts/migrations/113.ts new file mode 100644 index 000000000000..bd24828af971 --- /dev/null +++ b/app/scripts/migrations/113.ts @@ -0,0 +1,48 @@ +import { hasProperty, isObject } from '@metamask/utils'; +import { captureException } from '@sentry/browser'; +import { cloneDeep } from 'lodash'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 113; + +/** + * Remove preferences controller `isLineaMainnetReleased` state. + * + * @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist. + * @param originalVersionedData.meta - State metadata. + * @param originalVersionedData.meta.version - The current state version. + * @param originalVersionedData.data - The persisted MetaMask state, keyed by controller. + * @returns Updated versioned MetaMask extension state. + */ +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} + +function transformState( + state: Record, +): Record { + if ( + !hasProperty(state, 'PreferencesController') || + !isObject(state.PreferencesController) + ) { + captureException( + `Migration ${version}: Invalid PreferencesController state: ${typeof state.PreferencesController}`, + ); + + return state; + } + + if (hasProperty(state.PreferencesController, 'isLineaMainnetReleased')) { + delete state.PreferencesController.isLineaMainnetReleased; + } + return state; +} diff --git a/app/scripts/migrations/114.test.ts b/app/scripts/migrations/114.test.ts new file mode 100644 index 000000000000..10474bc2c262 --- /dev/null +++ b/app/scripts/migrations/114.test.ts @@ -0,0 +1,86 @@ +import { migrate, version } from './114'; + +const oldVersion = 113; + +describe('migration #114', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + + it('updates the version metadata', async () => { + const oldStorage = { + meta: { + version: oldVersion, + }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.meta).toStrictEqual({ version }); + }); + + describe('deprecates transactionSecurityCheckEnabled in PreferencesController', () => { + it('sets securityAlertsEnabled and hasMigratedFromOpenSeaToBlockaid to true if transactionSecurityCheckEnabled is true', async () => { + const oldStorage = { + PreferencesController: { + transactionSecurityCheckEnabled: true, + securityAlertsEnabled: false, + }, + }; + + const expectedState = { + PreferencesController: { + securityAlertsEnabled: true, + hasMigratedFromOpenSeaToBlockaid: true, + }, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldStorage, + }); + + expect(transformedState.data).toEqual(expectedState); + }); + + it('should not change securityAlertsEnabled if transactionSecurityCheckEnabled is false', async () => { + const oldStorage = { + PreferencesController: { + transactionSecurityCheckEnabled: false, + securityAlertsEnabled: false, + }, + }; + + const expectedState = { + PreferencesController: { + securityAlertsEnabled: false, + }, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldStorage, + }); + + expect(transformedState.data).toEqual(expectedState); + }); + }); + + it('should not change state in controllers other than PreferencesController', async () => { + const oldStorage = { + meta: { + version: oldVersion, + }, + data: { + PreferencesController: { + bar: 'baz', + }, + foo: 'bar', + }, + }; + + const newStorage = await migrate(oldStorage); + expect(oldStorage.data).toStrictEqual(newStorage.data); + }); +}); diff --git a/app/scripts/migrations/114.ts b/app/scripts/migrations/114.ts new file mode 100644 index 000000000000..bed9c70a8850 --- /dev/null +++ b/app/scripts/migrations/114.ts @@ -0,0 +1,55 @@ +import { cloneDeep } from 'lodash'; +import { hasProperty, isObject } from '@metamask/utils'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 114; + +/** + * This migration sets preference securityAlertsEnabled to true if transactionSecurityCheckEnabled is true and removes transactionSecurityCheckEnabled + * + * @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist. + * @param originalVersionedData.meta - State metadata. + * @param originalVersionedData.meta.version - The current state version. + * @param originalVersionedData.data - The persisted MetaMask state, keyed by controller. + * @returns Updated versioned MetaMask extension state. + */ +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} + +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function transformState(state: Record) { + if (!hasProperty(state, 'PreferencesController')) { + return state; + } + + if (!isObject(state.PreferencesController)) { + global.sentry?.captureException?.( + new Error( + `state.PreferencesController is type: ${typeof state.PreferencesController}`, + ), + ); + state.PreferencesController = {}; + } else if ( + hasProperty(state.PreferencesController, 'transactionSecurityCheckEnabled') + ) { + if (state.PreferencesController.transactionSecurityCheckEnabled) { + state.PreferencesController.securityAlertsEnabled = true; + state.PreferencesController.hasMigratedFromOpenSeaToBlockaid = true; + } + + delete state.PreferencesController.transactionSecurityCheckEnabled; + } + + return state; +} diff --git a/app/scripts/migrations/115.test.ts b/app/scripts/migrations/115.test.ts new file mode 100644 index 000000000000..efc472c13b2f --- /dev/null +++ b/app/scripts/migrations/115.test.ts @@ -0,0 +1,66 @@ +import { migrate, version } from './115'; + +const oldVersion = 114; + +describe('migration #79', () => { + it('should update the version metadata', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.meta).toStrictEqual({ version }); + }); + + it('should remove the "showProductTour"', async () => { + const oldStorage = { + meta: { + version: oldVersion, + }, + data: { + AppStateController: { + showProductTour: false, + bar: 'baz', + }, + }, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage).toStrictEqual({ + meta: { + version: 115, + }, + data: { + AppStateController: { + bar: 'baz', + }, + }, + }); + }); + + it('should make no changes if "showProductTour" never existed', async () => { + const oldStorage = { + meta: { + version: oldVersion, + }, + data: { + AppStateController: { + bar: 'baz', + }, + }, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage).toStrictEqual({ + meta: { + version: 115, + }, + data: { + AppStateController: { + bar: 'baz', + }, + }, + }); + }); +}); diff --git a/app/scripts/migrations/115.ts b/app/scripts/migrations/115.ts new file mode 100644 index 000000000000..a2a06d2ff8e4 --- /dev/null +++ b/app/scripts/migrations/115.ts @@ -0,0 +1,41 @@ +import { cloneDeep, isObject } from 'lodash'; +import { hasProperty } from '@metamask/utils'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 115; + +/** + * As we have removed Product tour from Home Page so this migration is to remove showProductTour from AppState + * + * @param originalVersionedData + */ +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function transformState(state: Record) { + const AppStateController = state?.AppStateController || {}; + + if ( + hasProperty(state, 'AppStateController') && + isObject(state.AppStateController) && + hasProperty(state.AppStateController, 'showProductTour') && + state.AppStateController.showProductTour !== undefined + ) { + delete AppStateController.showProductTour; + } + + return { + ...state, + AppStateController, + }; +} diff --git a/app/scripts/migrations/116.test.ts b/app/scripts/migrations/116.test.ts new file mode 100644 index 000000000000..6d107c07db79 --- /dev/null +++ b/app/scripts/migrations/116.test.ts @@ -0,0 +1,104 @@ +import { TransactionStatus } from '@metamask/transaction-controller'; +import { migrate, version, StuckTransactionError, TARGET_DATE } from './116'; + +const oldVersion = 115; + +const TRANSACTIONS_MOCK = [ + { id: 'tx1', time: TARGET_DATE - 1000, status: 'approved' }, // Before target date, should be marked as failed + { id: 'tx2', time: TARGET_DATE + 1000, status: 'approved' }, // After target date, should remain unchanged + { id: 'tx3', time: TARGET_DATE - 1000, status: 'signed' }, // Before target date, should be marked as failed + { id: 'tx4', time: TARGET_DATE - 1000, status: 'confirmed' }, // Before target date but not approved/signed, should remain unchanged +]; + +describe('migration #116', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + + it('updates the version metadata', async () => { + const oldStorage = { + meta: { + version: oldVersion, + }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.meta).toStrictEqual({ version }); + }); + + it('handles missing TransactionController', async () => { + const oldState = { + OtherController: {}, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldState, + }); + + expect(transformedState.data).toEqual(oldState); + }); + + it('handles empty transactions', async () => { + const oldState = { + TransactionController: { + transactions: [], + }, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldState, + }); + + expect(transformedState.data).toEqual(oldState); + }); + + it('handles missing state', async () => { + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: {}, + }); + + expect(transformedState.data).toEqual({}); + }); + + it('marks the transactions as failed before December 8, 2023, if they are approved or signed', async () => { + const oldState = { + TransactionController: { + transactions: TRANSACTIONS_MOCK, + }, + }; + const oldStorage = { + meta: { version: oldVersion }, + data: oldState, + }; + + const newStorage = await migrate(oldStorage); + + // Expected modifications to the transactions based on the migration logic + const expectedTransactions = [ + { + ...TRANSACTIONS_MOCK[0], // Assuming tx1 is the first element + status: TransactionStatus.failed, + error: StuckTransactionError, + }, + TRANSACTIONS_MOCK[1], // Assuming tx2 remains unchanged + { + ...TRANSACTIONS_MOCK[2], // Assuming tx3 is the third element + status: TransactionStatus.failed, + error: StuckTransactionError, + }, + TRANSACTIONS_MOCK[3], // Assuming tx4 and any others remain unchanged + // Add more transactions if there are more than four in TRANSACTIONS_MOCK + ]; + + expect(newStorage.data).toEqual({ + TransactionController: { + transactions: expectedTransactions, + }, + }); + }); +}); diff --git a/app/scripts/migrations/116.ts b/app/scripts/migrations/116.ts new file mode 100644 index 000000000000..8835122fe675 --- /dev/null +++ b/app/scripts/migrations/116.ts @@ -0,0 +1,62 @@ +import { cloneDeep } from 'lodash'; +import { + TransactionMeta, + TransactionStatus, + TransactionError, +} from '@metamask/transaction-controller'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 116; + +// Target date is December 8, 2023 - 00:00:00 UTC +export const TARGET_DATE = new Date('2023-12-08T00:00:00Z').getTime(); + +const STUCK_STATES = [TransactionStatus.approved, TransactionStatus.signed]; + +type FailedTransactionMeta = TransactionMeta & { + status: TransactionStatus.failed; + error: TransactionError; +}; + +export const StuckTransactionError = { + name: 'StuckTransactionDueToStatus', + message: 'Transaction is stuck due to status - migration 115', +}; + +/** + * This migration sets the `status` to `failed` for all transactions created before December 8, 2023 that are still `approved` or `signed`. + * + * @param originalVersionedData + */ +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} + +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function transformState(state: Record) { + const transactions: TransactionMeta[] = + state?.TransactionController?.transactions ?? []; + + for (const transaction of transactions) { + if ( + transaction.time < TARGET_DATE && + STUCK_STATES.includes(transaction.status) + ) { + transaction.status = TransactionStatus.failed; + + const failedTransaction = transaction as FailedTransactionMeta; + + failedTransaction.error = StuckTransactionError; + } + } +} diff --git a/app/scripts/migrations/117.test.ts b/app/scripts/migrations/117.test.ts new file mode 100644 index 000000000000..abe93e849f5c --- /dev/null +++ b/app/scripts/migrations/117.test.ts @@ -0,0 +1,131 @@ +import { migrate, version } from './117'; + +const sentryCaptureExceptionMock = jest.fn(); + +global.sentry = { + captureException: sentryCaptureExceptionMock, +}; + +describe('migration #117', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + + it('updates the version metadata', async () => { + const oldStorage = { + meta: { version: 116 }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.meta).toStrictEqual({ version }); + }); + + it('does nothing if SelectedNetworkController is not present', async () => { + const oldState = { + OtherController: {}, + }; + + const transformedState = await migrate({ + meta: { version: 116 }, + data: oldState, + }); + + expect(transformedState.data).toEqual(oldState); + }); + + it('removes domains with npm: or local: prefixes and preserves other domains', async () => { + const oldState = { + SelectedNetworkController: { + domains: { + 'npm:package': 'network1', + 'local:development': 'network2', + otherDomain: 'network3', + }, + }, + }; + + const expectedState = { + SelectedNetworkController: { + domains: { + otherDomain: 'network3', + }, + }, + }; + + const transformedState = await migrate({ + meta: { version: 116 }, + data: oldState, + }); + + expect(transformedState.data).toEqual(expectedState); + }); + + it('keeps the domains unchanged if there are no npm: or local: prefixes', async () => { + const oldState = { + SelectedNetworkController: { + domains: { + someDomain: 'network1', + anotherDomain: 'network2', + }, + }, + }; + + const expectedState = { + SelectedNetworkController: { + domains: { + someDomain: 'network1', + anotherDomain: 'network2', + }, + }, + }; + + const transformedState = await migrate({ + meta: { version: 116 }, + data: oldState, + }); + + expect(transformedState.data).toEqual(expectedState); + }); + + it('should capture an exception if SelectedNetworkController is in state but is not an object', async () => { + const oldData = { + SelectedNetworkController: 'not an object', + }; + const oldStorage = { + meta: { + version: 116, + }, + data: oldData, + }; + + await migrate(oldStorage); + + expect(sentryCaptureExceptionMock).toHaveBeenCalledTimes(1); + expect(sentryCaptureExceptionMock).toHaveBeenCalledWith( + new Error('SelectedNetworkController is not an object.'), + ); + }); + + it('should capture an exception if SelectedNetworkController has domains but it is not an object', async () => { + const oldData = { + SelectedNetworkController: { + domains: 'not an object', + }, + }; + const oldStorage = { + meta: { + version: 116, + }, + data: oldData, + }; + + await migrate(oldStorage); + + expect(sentryCaptureExceptionMock).toHaveBeenCalledTimes(1); + expect(sentryCaptureExceptionMock).toHaveBeenCalledWith( + new Error('Domains state is not an object.'), + ); + }); +}); diff --git a/app/scripts/migrations/117.ts b/app/scripts/migrations/117.ts new file mode 100644 index 000000000000..1a8a847c5cbf --- /dev/null +++ b/app/scripts/migrations/117.ts @@ -0,0 +1,75 @@ +import { cloneDeep } from 'lodash'; +import log from 'loglevel'; +import { hasProperty, isObject } from '@metamask/utils'; + +export const version = 117; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +/** + * Removes all Snaps domains (identified as starting with 'npm:' or 'local:') from the SelectedNetworkController's domains state. + * + * @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist. + * @param originalVersionedData.meta - State metadata. + * @param originalVersionedData.meta.version - The current state version. + * @param originalVersionedData.data - The persisted MetaMask state, keyed by controller. + * @returns Updated versioned MetaMask extension state. + */ +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} + +/** + * Removes all domains starting with 'npm:' or 'local:' from the SelectedNetworkController's domains state. + * + * @param state - The entire state object of the MetaMask extension. + */ +function transformState(state: Record) { + const selectedNetworkControllerState = state.SelectedNetworkController; + if (!selectedNetworkControllerState) { + log.warn('Skipping migration. SelectedNetworkController state not found.'); + return; + } + + if (!isObject(selectedNetworkControllerState)) { + global.sentry?.captureException?.( + new Error('SelectedNetworkController is not an object.'), + ); + return; + } + + if (!hasProperty(selectedNetworkControllerState, 'domains')) { + global.sentry?.captureException?.( + new Error('Domains key is missing in SelectedNetworkController state.'), + ); + return; + } + + if (!isObject(selectedNetworkControllerState.domains)) { + global.sentry?.captureException?.( + new Error('Domains state is not an object.'), + ); + return; + } + + const { domains } = selectedNetworkControllerState; + const filteredDomains = Object.keys(domains).reduce>( + (acc, domain) => { + if (!domain.startsWith('npm:') && !domain.startsWith('local:')) { + acc[domain] = domains[domain]; + } + return acc; + }, + {}, + ); + + selectedNetworkControllerState.domains = filteredDomains; +} diff --git a/app/scripts/migrations/118.test.ts b/app/scripts/migrations/118.test.ts new file mode 100644 index 000000000000..eda2e658867c --- /dev/null +++ b/app/scripts/migrations/118.test.ts @@ -0,0 +1,66 @@ +import { migrate, version } from './118'; + +const oldVersion = 117; + +describe('migration #118', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + + it('updates the version metadata', async () => { + const oldStorage = { + meta: { + version: oldVersion, + }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.meta).toStrictEqual({ version }); + }); + + describe('set useRequestQueue to true in PreferencesController', () => { + it('sets useRequestQueue to true', async () => { + const oldStorage = { + PreferencesController: { + useRequestQueue: false, + }, + }; + + const expectedState = { + PreferencesController: { + useRequestQueue: true, + }, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldStorage, + }); + + expect(transformedState.data).toEqual(expectedState); + }); + + it('should not update useRequestQueue value if it was set true in initial state', async () => { + const oldStorage = { + PreferencesController: { + useRequestQueue: true, + }, + }; + + const expectedState = { + PreferencesController: { + useRequestQueue: true, + }, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldStorage, + }); + + expect(transformedState.data).toEqual(expectedState); + }); + }); +}); diff --git a/app/scripts/migrations/118.ts b/app/scripts/migrations/118.ts new file mode 100644 index 000000000000..f12bf0ed40a4 --- /dev/null +++ b/app/scripts/migrations/118.ts @@ -0,0 +1,52 @@ +import { cloneDeep } from 'lodash'; +import { hasProperty, isObject } from '@metamask/utils'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 118; + +/** + * This migration sets preference useRequestQueue to true + * + * @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist. + * @param originalVersionedData.meta - State metadata. + * @param originalVersionedData.meta.version - The current state version. + * @param originalVersionedData.data - The persisted MetaMask state, keyed by controller. + * @returns Updated versioned MetaMask extension state. + */ +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} + +// TODO: Replace `any` with specific type +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function transformState(state: Record) { + if (!hasProperty(state, 'PreferencesController')) { + return state; + } + + if (!isObject(state.PreferencesController)) { + const controllerType = typeof state.PreferencesController; + global.sentry?.captureException?.( + new Error(`state.PreferencesController is type: ${controllerType}`), + ); + state.PreferencesController = {}; + } + + if ( + state.PreferencesController.useRequestQueue === false || + state.PreferencesController.useRequestQueue === undefined + ) { + state.PreferencesController.useRequestQueue = true; + } + + return state; +} diff --git a/app/scripts/migrations/119.test.ts b/app/scripts/migrations/119.test.ts new file mode 100644 index 000000000000..c37a1e5919ae --- /dev/null +++ b/app/scripts/migrations/119.test.ts @@ -0,0 +1,125 @@ +import { createMockInternalAccount } from '../../../test/jest/mocks'; +import { migrate, version } from './119'; + +const mockTimeStamp = 1716972230; +jest.useFakeTimers().setSystemTime(new Date(mockTimeStamp)); + +const oldVersion = 118; +const newVersion = version; + +describe('migration #119', () => { + it('updates the version metadata', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.meta).toStrictEqual({ version }); + }); + + it('returns the default state if the AccountsController state is undefined', async () => { + const defaultState = { + internalAccounts: { + accounts: {}, + selectedAccount: '', + }, + }; + + const oldStorage = { + meta: { + version: oldVersion, + }, + data: { + AccountsController: defaultState, + }, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage).toStrictEqual({ + meta: { + version: newVersion, + }, + data: { + AccountsController: defaultState, + }, + }); + expect(newStorage); + }); + + it('adds importTime attribute to InternalAccount if it is not defined"', async () => { + const mockInternalAccount = createMockInternalAccount(); + // @ts-expect-error forcing the importTime to be undefined for migration test. + mockInternalAccount.metadata.importTime = undefined; + + const oldStorage = { + meta: { + version: oldVersion, + }, + data: { + AccountsController: { + internalAccounts: { + accounts: { + [mockInternalAccount.id]: mockInternalAccount, + }, + selectedAccount: mockInternalAccount.id, + }, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage).toStrictEqual({ + meta: { + version: newVersion, + }, + data: { + AccountsController: { + internalAccounts: { + accounts: { + [mockInternalAccount.id]: { + ...mockInternalAccount, + metadata: { + ...mockInternalAccount.metadata, + importTime: mockTimeStamp, + }, + }, + }, + selectedAccount: mockInternalAccount.id, + }, + }, + }, + }); + expect(newStorage); + }); + + it('does not change the importTime attribute if it already exists', async () => { + const mockInternalAccount = createMockInternalAccount(); + const mockAccountsControllerState = { + internalAccounts: { + accounts: { + [mockInternalAccount.id]: mockInternalAccount, + }, + selectedAccount: mockInternalAccount.id, + }, + }; + const oldStorage = { + meta: { + version: oldVersion, + }, + data: { + AccountsController: mockAccountsControllerState, + }, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage).toStrictEqual({ + meta: { + version: newVersion, + }, + data: { + AccountsController: mockAccountsControllerState, + }, + }); + }); +}); diff --git a/app/scripts/migrations/119.ts b/app/scripts/migrations/119.ts new file mode 100644 index 000000000000..6e0f66687350 --- /dev/null +++ b/app/scripts/migrations/119.ts @@ -0,0 +1,62 @@ +import { cloneDeep, isObject } from 'lodash'; +import { hasProperty } from '@metamask/utils'; +import { AccountsControllerState } from '@metamask/accounts-controller'; +import { InternalAccount } from '@metamask/keyring-api'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 119; + +/** + * Add a default value for importTime in the InternalAccount + * + * @param originalVersionedData + */ +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function transformState(state: Record) { + const accountsController = state?.AccountsController || {}; + + if ( + isObject(state.AccountsController) && + hasProperty(state.AccountsController, 'internalAccounts') && + hasProperty( + state.AccountsController + .internalAccounts as AccountsControllerState['internalAccounts'], + 'accounts', + ) && + Array.isArray( + Object.values( + (state.AccountsController as AccountsControllerState).internalAccounts + .accounts, + ), + ) && + Object.values( + (state.AccountsController as AccountsControllerState).internalAccounts + .accounts, + ).length > 0 + ) { + Object.values(accountsController.internalAccounts.accounts).forEach( + (internalAccount: InternalAccount) => { + if (!internalAccount.metadata?.importTime) { + internalAccount.metadata.importTime = Date.now(); + } + }, + ); + } + + return { + ...state, + AccountsController: accountsController, + }; +} diff --git a/app/scripts/migrations/120.test.ts b/app/scripts/migrations/120.test.ts new file mode 100644 index 000000000000..3c7fd5b6b74a --- /dev/null +++ b/app/scripts/migrations/120.test.ts @@ -0,0 +1,42 @@ +import { migrate, version } from './120'; + +const oldVersion = 119; + +describe('migration #120', () => { + afterEach(() => jest.resetAllMocks()); + + it('updates the version metadata', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.meta).toStrictEqual({ version }); + }); + + it('deletes the deprecated token rates controller fields', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: { + TokenRatesController: { + contractExchangeRates: { + '0x8290333ceF9e6D528dD5618Fb97a76f268f3EDD4': 0.00001142055192565137, + '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2': 1.000125, + }, + contractExchangeRatesByChainId: { + '0x1': { + ETH: { + '0x8290333ceF9e6D528dD5618Fb97a76f268f3EDD4': 0.00001142055192565137, + '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2': 1.000125, + }, + }, + }, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data.TokenRatesController).toStrictEqual({}); + }); +}); diff --git a/app/scripts/migrations/120.ts b/app/scripts/migrations/120.ts new file mode 100644 index 000000000000..ae6d99948a9d --- /dev/null +++ b/app/scripts/migrations/120.ts @@ -0,0 +1,37 @@ +import { cloneDeep } from 'lodash'; +import { hasProperty } from '@metamask/utils'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 120; + +/** + * This migration removes the deprecated fields `contractExchangeRates` + * and `contractExchangeRatesByChainId` from the TokenRatesController. + * + * @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist. + * @param originalVersionedData.meta - State metadata. + * @param originalVersionedData.meta.version - The current state version. + * @param originalVersionedData.data - The persisted MetaMask state, keyed by controller. + * @returns Updated versioned MetaMask extension state. + */ +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function transformState(state: Record) { + if (hasProperty(state, 'TokenRatesController')) { + delete state.TokenRatesController.contractExchangeRates; + delete state.TokenRatesController.contractExchangeRatesByChainId; + } + return state; +} diff --git a/app/scripts/migrations/121.test.ts b/app/scripts/migrations/121.test.ts new file mode 100644 index 000000000000..06cba77de93e --- /dev/null +++ b/app/scripts/migrations/121.test.ts @@ -0,0 +1,194 @@ +import { NetworkType } from '@metamask/controller-utils'; +import { + CHAIN_IDS, + CHAIN_ID_TO_RPC_URL_MAP, + LINEA_SEPOLIA_DISPLAY_NAME, + NETWORK_TYPES, + TEST_NETWORK_TICKER_MAP, +} from '../../../shared/constants/network'; +import { migrate, version } from './121'; + +const oldVersion = 120; + +const ethereumProviderConfig = { + chainId: '0x1', + rpcPrefs: { + blockExplorerUrl: 'https://etherscan.io', + }, + ticker: 'ETH', + type: 'mainnet', +}; + +const ethereumNetworksMetadata = { + mainnet: { + EIPS: { + '1559': true, + }, + status: 'available', + }, +}; +const ethereumOldState = { + CurrencyController: { + currencyRates: { + ETH: { + conversionDate: 1708532473.416, + conversionRate: 2918.02, + usdConversionRate: 2918.02, + }, + GoerliETH: { + conversionDate: 1708532466.732, + conversionRate: 2918.02, + usdConversionRate: 2918.02, + }, + }, + currentCurrency: 'usd', + }, + NetworkController: { + networkConfigurations: {}, + networksMetadata: ethereumNetworksMetadata, + providerConfig: ethereumProviderConfig, + selectedNetworkClientId: 'mainnet', + }, +}; + +const lineaGoerliState = { + NetworkController: { + networkConfigurations: {}, + networksMetadata: { + 'linea-goerli': { + EIPS: { + '1559': true, + }, + status: 'available', + }, + }, + providerConfig: { + chainId: CHAIN_IDS.LINEA_GOERLI, + rpcPrefs: {}, + ticker: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.LINEA_GOERLI], + type: NETWORK_TYPES.LINEA_GOERLI, + }, + selectedNetworkClientId: NETWORK_TYPES.LINEA_GOERLI, + }, +}; + +describe('migration #121', () => { + it('updates the version metadata', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.meta).toStrictEqual({ version }); + }); + + it('does nothing if no preferences state', async () => { + const oldState = { + OtherController: {}, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldState, + }); + + expect(transformedState.data).toEqual(oldState); + }); + + it('Should return state if chainId is not linea-goerli', async () => { + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: ethereumOldState, + }); + + expect(transformedState.data).toEqual(ethereumOldState); + }); + + it('Should return state if there is no NetworkController in state', async () => { + const { NetworkController, ...state } = ethereumOldState; + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: state, + }); + + expect(transformedState.data).toEqual(state); + }); + + it('Should return state if there is no provider in NetworkController', async () => { + const state = { + ...ethereumOldState, + NetworkController: {}, + }; + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: state, + }); + + expect(transformedState.data).toEqual(state); + }); + + it('Should return state if there is no chainId in provider in NetworkController', async () => { + const state = { + ...ethereumOldState, + NetworkController: { + providerConfig: {}, + }, + }; + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: state, + }); + + expect(transformedState.data).toEqual(state); + }); + + it('Should return state if chainId is not linea-goerli', async () => { + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: ethereumOldState, + }); + + expect(transformedState.data).toEqual(ethereumOldState); + }); + + it('Should update NetworkController to Linea Sepolia if chainId is on Linea Goerli', async () => { + const expectedNetworkControllerState = { + networkConfigurations: {}, + networksMetadata: { + 'linea-sepolia': { + EIPS: { + '1559': true, + }, + status: 'available', + }, + 'linea-goerli': { + EIPS: { + '1559': true, + }, + status: 'available', + }, + }, + providerConfig: { + type: NetworkType['linea-sepolia'], + rpcPrefs: {}, + chainId: CHAIN_IDS.LINEA_SEPOLIA, + nickname: LINEA_SEPOLIA_DISPLAY_NAME, + rpcUrl: CHAIN_ID_TO_RPC_URL_MAP[CHAIN_IDS.LINEA_SEPOLIA], + providerType: NETWORK_TYPES.LINEA_SEPOLIA, + ticker: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.LINEA_SEPOLIA], + id: NETWORK_TYPES.LINEA_SEPOLIA, + }, + selectedNetworkClientId: 'linea-sepolia', + }; + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: lineaGoerliState, + }); + + expect(transformedState.data).toEqual({ + NetworkController: expectedNetworkControllerState, + }); + }); +}); diff --git a/app/scripts/migrations/121.ts b/app/scripts/migrations/121.ts new file mode 100644 index 000000000000..a034eeaa7c81 --- /dev/null +++ b/app/scripts/migrations/121.ts @@ -0,0 +1,81 @@ +import { cloneDeep, isObject } from 'lodash'; +import { NetworkType } from '@metamask/controller-utils'; +import { hasProperty } from '@metamask/utils'; +import { NetworkStatus } from '@metamask/network-controller'; +import { + CHAIN_IDS, + CHAIN_ID_TO_RPC_URL_MAP, + NETWORK_TYPES, + TEST_NETWORK_TICKER_MAP, + LINEA_SEPOLIA_DISPLAY_NAME, +} from '../../../shared/constants/network'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 121; + +/** + * Migrates the user network to Linea Sepolia if the user is on Linea Goerli network. + * + * @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist. + * @param originalVersionedData.meta - State metadata. + * @param originalVersionedData.meta.version - The current state version. + * @param originalVersionedData.data - The persisted MetaMask state, keyed by controller. + * @returns Updated versioned MetaMask extension state. + */ +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function transformState(state: Record) { + const NetworkController = state?.NetworkController || {}; + const provider = NetworkController?.providerConfig || {}; + + if (provider?.chainId !== CHAIN_IDS.LINEA_GOERLI) { + return state; + } + const networkControllerState = state.NetworkController; + + if ( + hasProperty(state, 'NetworkController') && + isObject(state.NetworkController) && + hasProperty(state.NetworkController, 'providerConfig') && + isObject(state.NetworkController.providerConfig) && + hasProperty(state.NetworkController.providerConfig, 'chainId') && + state.NetworkController.providerConfig.chainId === CHAIN_IDS.LINEA_GOERLI + ) { + networkControllerState.providerConfig = { + type: NetworkType['linea-sepolia'], + rpcPrefs: {}, + chainId: CHAIN_IDS.LINEA_SEPOLIA, + nickname: LINEA_SEPOLIA_DISPLAY_NAME, + rpcUrl: CHAIN_ID_TO_RPC_URL_MAP[CHAIN_IDS.LINEA_SEPOLIA], + providerType: NETWORK_TYPES.LINEA_SEPOLIA, + ticker: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.LINEA_SEPOLIA], + id: NETWORK_TYPES.LINEA_SEPOLIA, + }; + networkControllerState.selectedNetworkClientId = + NETWORK_TYPES.LINEA_SEPOLIA; + networkControllerState.networksMetadata = { + ...networkControllerState.networksMetadata, + 'linea-sepolia': { + EIPS: { + '1559': true, + }, + status: NetworkStatus.Available, + }, + }; + } + return { + ...state, + NetworkController: networkControllerState, + }; +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index 8f961a99fcc3..f3ca59feb158 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -123,6 +123,15 @@ const migrations = [ require('./110'), require('./111'), require('./112'), + require('./113'), + require('./114'), + require('./115'), + require('./116'), + require('./117'), + require('./118'), + require('./119'), + require('./120'), + require('./121'), ]; export default migrations; diff --git a/app/scripts/offscreen.js b/app/scripts/offscreen.js new file mode 100644 index 000000000000..ba796874f2fc --- /dev/null +++ b/app/scripts/offscreen.js @@ -0,0 +1,44 @@ +import { OffscreenCommunicationTarget } from '../../shared/constants/offscreen-communication'; + +/** + * Creates an offscreen document that can be used to load additional scripts + * and iframes that can communicate with the extension through the chrome + * runtime API. Only one offscreen document may exist, so any iframes required + * by extension can be embedded in the offscreen.html file. See the offscreen + * folder for more details. + */ +export async function createOffscreen() { + const { chrome } = globalThis; + if (!chrome.offscreen || (await chrome.offscreen.hasDocument())) { + return; + } + + const loadPromise = new Promise((resolve) => { + const messageListener = (msg) => { + if ( + msg.target === OffscreenCommunicationTarget.extensionMain && + msg.isBooted + ) { + chrome.runtime.onMessage.removeListener(messageListener); + resolve(); + } + }; + chrome.runtime.onMessage.addListener(messageListener); + }); + + await chrome.offscreen.createDocument({ + url: './offscreen.html', + reasons: ['IFRAME_SCRIPTING'], + justification: + 'Used for Hardware Wallet and Snaps scripts to communicate with the extension.', + }); + + // In case we are in a bad state where the offscreen document is not loading, timeout and let execution continue. + const timeoutPromise = new Promise((resolve) => { + setTimeout(resolve, 5000); + }); + + await Promise.race([loadPromise, timeoutPromise]); + + console.debug('Offscreen iframe loaded'); +} diff --git a/app/scripts/skip-onboarding.js b/app/scripts/skip-onboarding.js new file mode 100644 index 000000000000..39c3b0b61865 --- /dev/null +++ b/app/scripts/skip-onboarding.js @@ -0,0 +1,151 @@ +import { ControllerMessenger } from '@metamask/base-controller'; +import { KeyringController } from '@metamask/keyring-controller'; +import { wordlist } from '@metamask/scure-bip39/dist/wordlists/english'; +import { UI_NOTIFICATIONS } from '../../shared/notifications'; +import { E2E_SRP, defaultFixture } from '../../test/e2e/default-fixture'; +import { encryptorFactory } from './lib/encryptor-factory'; + +export async function generateSkipOnboardingState() { + const state = defaultFixture('0xaa36a7').data; + + state.AppStateController = generateAppStateControllerState(); + state.AnnouncementController = generateAnnouncementControllerState(); + state.NetworkController = generateNetworkControllerState(); + + if (process.env.PASSWORD) { + const { vault, account } = await generateVaultAndAccount( + process.env.TEST_SRP || E2E_SRP, + process.env.PASSWORD, + ); + + state.KeyringController = generateKeyringControllerState(vault); + state.AccountsController = generateAccountsControllerState(account); + } + + return state; +} + +// dismiss product tour +function generateAppStateControllerState() { + return { + ...defaultFixture().data.AppStateController, + showProductTour: false, + }; +} + +// dismiss 'what's new' modals +function generateAnnouncementControllerState() { + const allAnnouncementsAlreadyShown = Object.keys(UI_NOTIFICATIONS).reduce( + (acc, val) => { + acc[val] = { + ...UI_NOTIFICATIONS[val], + isShown: true, + }; + return acc; + }, + {}, + ); + + return { + ...defaultFixture().data.AnnouncementController, + announcements: { + ...defaultFixture().data.AnnouncementController.announcements, + ...allAnnouncementsAlreadyShown, + }, + }; +} + +// configure 'Sepolia' network +// TODO: Support for local node +function generateNetworkControllerState() { + return { + ...defaultFixture().data.NetworkController, + providerConfig: { + chainId: '0xaa36a7', + rpcPrefs: { + blockExplorerUrl: 'https://sepolia.etherscan.io', + }, + ticker: 'SepoliaETH', + type: 'sepolia', + }, + networkConfigurations: { + networkConfigurationId: { + chainId: '0xaa36a7', + nickname: 'Sepolia', + rpcPrefs: {}, + rpcUrl: 'https://sepolia.infura.io/v3/6c21df2a8dcb4a77b9bbcc1b65ee9ded', + ticker: 'SepoliaETH', + networkConfigurationId: 'networkConfigurationId', + }, + }, + }; +} + +async function generateVaultAndAccount(encodedSeedPhrase, password) { + const controllerMessenger = new ControllerMessenger(); + const keyringControllerMessenger = controllerMessenger.getRestricted({ + name: 'KeyringController', + }); + const krCtrl = new KeyringController({ + encryptor: encryptorFactory(600_000), + messenger: keyringControllerMessenger, + }); + + const seedPhraseAsBuffer = Buffer.from(encodedSeedPhrase); + const _convertMnemonicToWordlistIndices = (mnemonic) => { + const indices = mnemonic + .toString() + .split(' ') + .map((word) => wordlist.indexOf(word)); + return new Uint8Array(new Uint16Array(indices).buffer); + }; + + await krCtrl.createNewVaultAndRestore( + password, + _convertMnemonicToWordlistIndices(seedPhraseAsBuffer), + ); + + const { vault } = krCtrl.state; + const account = krCtrl.state.keyrings[0].accounts[0]; + + return { vault, account }; +} + +function generateKeyringControllerState(vault) { + return { + ...defaultFixture().data.KeyringController, + vault, + }; +} + +function generateAccountsControllerState(account) { + return { + ...defaultFixture().data.AccountsController, + internalAccounts: { + selectedAccount: 'account-id', + accounts: { + 'account-id': { + id: 'account-id', + address: account, + metadata: { + name: 'Account 1', + lastSelected: 1665507600000, + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [ + 'personal_sign', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + }, + }; +} diff --git a/app/scripts/snaps/preinstalled-snaps.ts b/app/scripts/snaps/preinstalled-snaps.ts new file mode 100644 index 000000000000..0a014c350c21 --- /dev/null +++ b/app/scripts/snaps/preinstalled-snaps.ts @@ -0,0 +1,8 @@ +import type { PreinstalledSnap } from '@metamask/snaps-controllers'; +import MessageSigningSnap from '@metamask/message-signing-snap/dist/preinstalled-snap.json'; + +const PREINSTALLED_SNAPS: readonly PreinstalledSnap[] = Object.freeze([ + MessageSigningSnap as PreinstalledSnap, +]); + +export default PREINSTALLED_SNAPS; diff --git a/app/scripts/ui.js b/app/scripts/ui.js index 50917836a4b8..d7cf205ab486 100644 --- a/app/scripts/ui.js +++ b/app/scripts/ui.js @@ -23,12 +23,7 @@ import { import { isManifestV3 } from '../../shared/modules/mv3.utils'; import { checkForLastErrorAndLog } from '../../shared/modules/browser-runtime.utils'; import { SUPPORT_LINK } from '../../shared/lib/ui-utils'; -import { - getErrorHtml, - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - registerDesktopErrorActions, - ///: END:ONLY_INCLUDE_IF -} from '../../shared/lib/error-utils'; +import { getErrorHtml } from '../../shared/lib/error-utils'; import ExtensionPlatform from './platforms/extension'; import { setupMultiplex } from './lib/stream-utils'; import { getEnvironmentType, getPlatform } from './lib/util'; @@ -205,55 +200,28 @@ async function start() { } function initializeUiWithTab(tab) { - initializeUi( - tab, - connectionStream, - ( - err, - store, - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - backgroundConnection, - ///: END:ONLY_INCLUDE_IF - ) => { - if (err) { - // if there's an error, store will be = metamaskState - displayCriticalError( - 'troubleStarting', - err, - store, - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - backgroundConnection, - ///: END:ONLY_INCLUDE_IF - ); - return; - } - isUIInitialised = true; + initializeUi(tab, connectionStream, (err, store) => { + if (err) { + // if there's an error, store will be = metamaskState + displayCriticalError('troubleStarting', err, store); + return; + } + isUIInitialised = true; - const state = store.getState(); - const { metamask: { completedOnboarding } = {} } = state; + const state = store.getState(); + const { metamask: { completedOnboarding } = {} } = state; - if ( - !completedOnboarding && - windowType !== ENVIRONMENT_TYPE_FULLSCREEN - ) { - global.platform.openExtensionInBrowser(); - } - }, - ); + if (!completedOnboarding && windowType !== ENVIRONMENT_TYPE_FULLSCREEN) { + global.platform.openExtensionInBrowser(); + } + }); } // Function to update new backgroundConnection in the UI function updateUiStreams() { connectToAccountManager(connectionStream, (err, backgroundConnection) => { if (err) { - displayCriticalError( - 'troubleStarting', - err, - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - undefined, - backgroundConnection, - ///: END:ONLY_INCLUDE_IF - ); + displayCriticalError('troubleStarting', err); return; } @@ -289,13 +257,7 @@ async function queryCurrentActiveTab(windowType) { function initializeUi(activeTab, connectionStream, cb) { connectToAccountManager(connectionStream, (err, backgroundConnection) => { if (err) { - cb( - err, - null, - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - backgroundConnection, - ///: END:ONLY_INCLUDE_IF - ); + cb(err, null); return; } @@ -310,29 +272,11 @@ function initializeUi(activeTab, connectionStream, cb) { }); } -async function displayCriticalError( - errorKey, - err, - metamaskState, - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - backgroundConnection, - ///: END:ONLY_INCLUDE_IF -) { - const html = await getErrorHtml( - errorKey, - SUPPORT_LINK, - metamaskState, - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - err, - ///: END:ONLY_INCLUDE_IF - ); +async function displayCriticalError(errorKey, err, metamaskState) { + const html = await getErrorHtml(errorKey, SUPPORT_LINK, metamaskState); container.innerHTML = html; - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - registerDesktopErrorActions(backgroundConnection, browser); - ///: END:ONLY_INCLUDE_IF - const button = document.getElementById('critical-error-button'); button?.addEventListener('click', (_) => { diff --git a/app/trezor-usb-permissions.html b/app/trezor-usb-permissions.html index b3c6ce72b11c..8c92552cfa02 100644 --- a/app/trezor-usb-permissions.html +++ b/app/trezor-usb-permissions.html @@ -1,9 +1,11 @@ - - + <% if (it.shouldIncludeSnow) { %> + + + <% } %> TrezorConnect | Trezor @@ -31,5 +33,5 @@ - + diff --git a/attribution.txt b/attribution.txt new file mode 100644 index 000000000000..364128f620f3 --- /dev/null +++ b/attribution.txt @@ -0,0 +1,32778 @@ +abort-controller +3.0.0 +MIT License + +Copyright (c) 2017 Toru Nagashima + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +accounting +0.4.1 +Copyright (c) 2014 Open Exchange Rates + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +****************************** + +aes-js +3.1.2 +The MIT License (MIT) + +Copyright (c) 2015 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + + +****************************** + +agent-base +6.0.2 +license: MIT +authors: Nathan Rajlich (http://n8.io/) + +****************************** + +agentkeepalive +4.5.0 +The MIT License + +Copyright(c) node-modules and other contributors. +Copyright(c) 2012 - 2015 fengmk2 + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@ampproject/remapping +2.2.1 + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +ansi-regex +5.0.1 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +ansi-regex +6.0.1 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +ansi-styles +3.2.1 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +ansi-styles +4.2.1 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +ansi-styles +6.2.1 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +any-promise +1.3.0 +Copyright (C) 2014-2016 Kevin Beaty + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +apg-js +4.1.1 +## [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause) + +

+Copyright (c) 2021 Lowell D. Thomas
+All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +

+ + +****************************** + +array-buffer-byte-length +1.0.0 +MIT License + +Copyright (c) 2023 Inspect JS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +assert +2.1.0 +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + + +****************************** + +asynckit +0.4.0 +The MIT License (MIT) + +Copyright (c) 2016 Alex Indigo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +async-mutex +0.2.6 +The MIT License (MIT) + +Copyright (c) 2016 Christian Speckner + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +async-mutex +0.3.2 +The MIT License (MIT) + +Copyright (c) 2016 Christian Speckner + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +async-mutex +0.5.0 +The MIT License (MIT) + +Copyright (c) 2016 Christian Speckner + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +available-typed-arrays +1.0.5 +MIT License + +Copyright (c) 2020 Inspect JS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +await-semaphore +0.1.3 +The MIT License (MIT) + +Copyright (c) 2016 Emma Kuo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +axios +1.6.8 +# Copyright (c) 2014-present Matt Zabriskie & Collaborators + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +b4a +1.6.4 +ISC License + +Copyright (c) 2021 Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@babel/code-frame +7.10.4 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/code-frame +7.24.2 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/compat-data +7.23.2 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/core +7.23.2 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/generator +7.24.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-annotate-as-pure +7.22.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-compilation-targets +7.22.15 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-create-class-features-plugin +7.24.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-environment-visitor +7.22.20 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-function-name +7.23.0 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-hoist-variables +7.22.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-member-expression-to-functions +7.24.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-module-imports +7.24.3 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-module-transforms +7.24.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-optimise-call-expression +7.22.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-plugin-utils +7.24.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-replace-supers +7.24.1 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helpers +7.23.2 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-simple-access +7.24.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-skip-transparent-expression-wrappers +7.22.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-split-export-declaration +7.24.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-string-parser +7.24.1 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-validator-identifier +7.24.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/helper-validator-option +7.23.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/highlight +7.24.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/parser +7.24.5 +Copyright (C) 2012-2014 by various contributors (see AUTHORS) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@babel/plugin-syntax-jsx +7.24.1 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/plugin-syntax-typescript +7.24.1 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/plugin-transform-modules-commonjs +7.24.1 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/plugin-transform-typescript +7.24.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/preset-typescript +7.24.1 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/runtime +7.24.0 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/runtime +7.24.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/template +7.22.15 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/traverse +7.24.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@babel/types +7.24.5 +MIT License + +Copyright (c) 2014-present Sebastian McKenzie and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +bail +1.0.2 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +balanced-match +1.0.2 +(MIT) + +Copyright (c) 2013 Julian Gruber <julian@juliangruber.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +base32-encode +1.2.0 +MIT License + +Copyright (c) 2016-2017 Linus Unnebäck + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +base64-js +1.5.1 +The MIT License (MIT) + +Copyright (c) 2014 Jameson Little + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +base-x +3.0.9 +The MIT License (MIT) + +Copyright (c) 2018 base-x contributors +Copyright (c) 2014-2018 The Bitcoin Core developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +base-x +4.0.0 +The MIT License (MIT) + +Copyright (c) 2018 base-x contributors +Copyright (c) 2014-2018 The Bitcoin Core developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +bchaddrjs +0.5.2 +MIT License + +Copyright (c) 2018-2020 Emilio Almansi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +bech32 +1.1.4 +MIT License + +Copyright (c) 2017 Pieter Wuille +Copyright (c) 2018 bitcoinjs contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +bech32 +2.0.0 +MIT License + +Copyright (c) 2017 Pieter Wuille +Copyright (c) 2018 bitcoinjs contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +bigint-buffer +1.1.5 + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +big-integer +1.6.36 +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + + +****************************** + +big-integer +1.6.52 +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + + +****************************** + +bignumber.js +4.1.0 +license: MIT +authors: Michael Mclaughlin + +****************************** + +bignumber.js +9.1.2 +license: MIT +authors: Michael Mclaughlin + +****************************** + +bindings +1.5.0 +(The MIT License) + +Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +bip66 +1.1.5 +The MIT License (MIT) + +Copyright (c) 2015 Daniel Cousens + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +bitcoin-ops +1.4.1 +The MIT License (MIT) + +Copyright (c) 2016 Daniel Cousens + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +bitwise +2.1.0 +# The MIT License (MIT) + +Copyright (c) `2019` Florian Wendelborn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +blake-hash +2.0.0 +license: MIT +authors: Kirill Fomichev (https://github.com/fanatid) + +****************************** + +blakejs +1.2.1 +Copyright (c) 2022 Blakejs contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + +****************************** + +blo +1.2.0 +MIT License + +Copyright (c) 2023 Pierre Bertet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +@blockaid/ppom_release +1.4.6 <> +Blockaid BSL License, Version 1.0 (EPL-1.0) + +Licensor: Blockaid, Inc. + +Licensed Work: PPOM. The Licensed Work is Copyright © 2023 Blockaid, Inc. + +Additional Use Grant: No additional use right is granted. + +Change Date: Four years from release date. + +Change License: Version 2 or later of the GNU General Public License as published by the Free Software Foundation. + +License text copyright © 2023 MariaDB plc, All Rights Reserved. “Business Source License” is a trademark of MariaDB plc. + +________________________________________________________________________________________________________________________________________________________________________________ + +Terms + +The Licensor hereby grants you the right to copy, modify, create derivative works, redistribute, and make non-production use of the Licensed Work. The Licensor may make an Additional Use Grant, above, permitting limited production use. + +Effective on the Change Date, or the fourth anniversary of the first publicly available distribution of a specific version of the Licensed Work under this License, whichever comes first, the Licensor hereby grants you rights under the terms of the Change License, and the rights granted in the paragraph above terminate. + +If your use of the Licensed Work does not comply with the requirements currently in effect as described in this License, you must purchase a commercial license from the Licensor, its affiliated entities, or authorized resellers, or you must refrain from using the Licensed Work. + +All copies of the original and modified Licensed Work, and derivative works of the Licensed Work, are subject to this License. This License applies separately for each version of the Licensed Work and the Change Date may vary for each version of the Licensed Work released by Licensor. + +You must conspicuously display this License on each original or modified copy of the Licensed Work. If you receive the Licensed Work in original or modified form from a third party, the terms and conditions set forth in this License apply to your use of that work. + +Any use of the Licensed Work in violation of this License will automatically terminate your rights under this License for the current and all other versions of the Licensed Work. + +This License does not grant you any right in any trademark or logo of Licensor or its affiliates (provided that you may use a trademark or logo of Licensor as expressly required by this License). TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE. MariaDB hereby grants you permission to use this License’s text to license your works, and to refer to it using the trademark “Business Source License”, as long as you comply with the Covenants of Licensor below. + +________________________________________________________________________________________________________________________________________________________________________________ + +Covenants of Licensor + +In consideration of the right to use this License’s text and the “Business Source License” name and trademark, Licensor covenants to MariaDB, and to all other recipients of the licensed work to be provided by Licensor: + +To specify as the Change License the GPL Version 2.0 or any later version, or a license that is compatible with GPL Version 2.0 or a later version, where “compatible” means that software provided under the Change License can be included in a program with software provided under GPL Version 2.0 or a later version. Licensor may specify additional Change Licenses without limitation. +To either: (a) specify an additional grant of rights to use that does not impose any additional restriction on the right granted in this License, as the Additional Use Grant; or (b) insert the text “None” to specify a Change Date. Not to modify this License in any other way. + + ________________________________________________________________________________________________________________________________________________________________________________ + +Notice + +The Business Source License (this document, or the “License”) is not an Open Source license. However, the Licensed Work will eventually be made available under an Open Source License, as stated in this License. + +For more information on the use of the Business Source License for MariaDB products, please visit the MariaDB Business Source License FAQ. For more information on the use of the Business Source License generally, please visit the Adopting and Developing Business Source License FAQ. + +****************************** + +bn.js +5.2.1 +Copyright Fedor Indutny, 2015. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +borc +2.1.2 +The MIT License (MIT) + +Copyright (c) 2016 Friedel Ziegelmayer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +borsh +0.7.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Near + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +bowser +2.11.0 +Copyright 2015, Dustin Diaz (the "Original Author") +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +Distributions of all or part of the Software intended to be used +by the recipients as they would use the unmodified Software, +containing modifications that substantially alter, remove, or +disable functionality of the Software, outside of the documented +configuration mechanisms provided by the Software, shall be +modified such that the Original Author's bug reporting email +addresses and urls are either replaced with the contact information +of the parties responsible for the changes, or removed entirely. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + + +Except where noted, this license applies to any and all software +programs and associated documentation files created by the +Original Author, when distributed with the Software. + + +****************************** + +bplist-creator +0.1.1 +(The MIT License) + +Copyright (c) 2012 Near Infinity Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software +and associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +bplist-parser +0.3.2 +license: MIT +authors: Joe Ferner + +****************************** + +brace-expansion +1.1.11 +MIT License + +Copyright (c) 2013 Julian Gruber + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +brace-expansion +2.0.1 +MIT License + +Copyright (c) 2013 Julian Gruber + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +brorand +1.1.0 +license: MIT +authors: Fedor Indutny + +****************************** + +browserify-aes +1.2.0 +The MIT License (MIT) + +Copyright (c) 2014-2017 browserify-aes contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +browserify-zlib +0.2.0 +The MIT License (MIT) + +Copyright (c) 2014-2015 Devon Govett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +This project contains parts of Node.js. +Node.js is licensed for use as follows: + +""" +Copyright Node.js contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: + +""" +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + + +****************************** + +browserslist +4.23.0 +The MIT License (MIT) + +Copyright 2014 Andrey Sitnik and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +bs58 +4.0.1 +license: MIT +authors: undefined + +****************************** + +bs58 +5.0.0 +MIT License + +Copyright (c) 2018 cryptocoinjs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +bs58check +2.1.2 +The MIT License (MIT) + +Copyright (c) 2017 Daniel Cousens + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +bs58check +3.0.1 +The MIT License (MIT) + +Copyright (c) 2017 Daniel Cousens + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +buffer +5.6.0 +The MIT License (MIT) + +Copyright (c) Feross Aboukhadijeh, and other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +buffer +5.7.1 +The MIT License (MIT) + +Copyright (c) Feross Aboukhadijeh, and other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +buffer +6.0.3 +The MIT License (MIT) + +Copyright (c) Feross Aboukhadijeh, and other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +buffer-equal-constant-time +1.0.1 +Copyright (c) 2013, GoInstant Inc., a salesforce.com company +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +* Neither the name of salesforce.com, nor GoInstant, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +buffer-from +1.1.2 +MIT License + +Copyright (c) 2016, 2018 Linus Unnebäck + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +bufferutil +4.0.8 +Copyright (c) 2011 Einar Otto Stangvik +Copyright (c) 2013 Arnout Kazemier and contributors +Copyright (c) 2016 Luigi Pinca and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +buffer-xor +1.0.3 +The MIT License (MIT) + +Copyright (c) 2015 Daniel Cousens + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +builtin-modules +3.3.0 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +builtins +5.0.1 +Copyright (c) 2015 Julian Gruber + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +call-bind +1.0.6 +MIT License + +Copyright (c) 2020 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +caniuse-lite +1.0.30001600 +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. + + +****************************** + +case +1.6.3 +Copyright (c) 2013 Nathan Bubna + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +cashaddrjs +0.4.4 +MIT License + +Copyright (c) 2017-2020 Emilio Almansi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +cbor-sync +1.0.4 +Copyright (c) 2014 ARM Ltd. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +chain-function +1.0.1 +The MIT License (MIT) + +Copyright (c) 2015 Jason Quense + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@chainsafe/as-sha256 +0.3.1 + Copyright 2019 ChainSafe Systems + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + +****************************** + +@chainsafe/persistent-merkle-tree +0.4.2 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@chainsafe/ssz +0.9.4 <> +Copyright 2019- ChainSafe Systems + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + +****************************** + +chalk +2.4.2 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +chalk +4.1.2 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +character-entities +1.2.1 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +character-entities-legacy +1.1.1 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +character-reference-invalid +1.1.1 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +cids +1.1.7 +The MIT License (MIT) + +Copyright (c) 2016 Friedel Ziegelmayer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +cipher-base +1.0.4 +The MIT License (MIT) + +Copyright (c) 2017 crypto-browserify contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +classnames +2.2.6 +The MIT License (MIT) + +Copyright (c) 2017 Jed Watson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +cliui +8.0.1 +Copyright (c) 2015, Contributors + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice +appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE +LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +clone +1.0.3 +Copyright © 2011-2015 Paul Vorbach + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the “Software”), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +clsx +1.1.1 +MIT License + +Copyright (c) Luke Edwards (lukeed.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +cockatiel +3.1.2 +MIT License + +Copyright (c) 2019 Connor Peet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +color +0.11.4 +Copyright (c) 2012 Heather Arthur + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +****************************** + +color-convert +1.9.3 +Copyright (c) 2011-2016 Heather Arthur + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +****************************** + +color-convert +2.0.1 +Copyright (c) 2011-2016 Heather Arthur + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +****************************** + +color-name +1.1.3 +The MIT License (MIT) +Copyright (c) 2015 Dmitry Ivanov + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +****************************** + +color-name +1.1.4 +The MIT License (MIT) +Copyright (c) 2015 Dmitry Ivanov + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +****************************** + +color-string +0.3.0 +Copyright (c) 2011 Heather Arthur + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +****************************** + +combined-stream +1.0.8 +Copyright (c) 2011 Debuggable Limited + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +commander +2.20.3 +(The MIT License) + +Copyright (c) 2011 TJ Holowaychuk + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +commander +4.1.1 +(The MIT License) + +Copyright (c) 2011 TJ Holowaychuk + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +comma-separated-tokens +1.0.7 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +component-type +1.2.1 +license: MIT +authors: undefined + +****************************** + +concat-map +0.0.1 +This software is released under the MIT license: + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +concat-stream +2.0.0 +The MIT License + +Copyright (c) 2013 Max Ogden + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +****************************** + +contentful +10.8.7 +The MIT License (MIT) + +Copyright (c) 2016 Contentful + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +contentful-resolve-response +1.8.1 +MIT License + +Copyright (c) 2018 Contentful + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@contentful/rich-text-html-renderer +16.3.5 +MIT License + +Copyright (c) 2018 Contentful + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@contentful/rich-text-types +16.3.5 +MIT License + +Copyright (c) 2018 Contentful + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +contentful-sdk-core +8.1.2 +The MIT License (MIT) + +Copyright (c) 2016 Contentful + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +convert-source-map +2.0.0 +Copyright 2013 Thorsten Lorenz. +All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +copy-to-clipboard +3.3.3 +MIT License + +Copyright (c) 2017 sudodoki + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +core-util-is +1.0.2 +Copyright Node.js contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + + +****************************** + +crc +3.8.0 +The MIT License (MIT) + +Copyright 2014 Alex Gorbatchev + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +crc-32 +1.2.0 +Copyright (C) 2014-present SheetJS + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + +****************************** + +create-hash +1.2.0 +The MIT License (MIT) + +Copyright (c) 2017 crypto-browserify contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +create-hmac +1.1.7 +The MIT License (MIT) + +Copyright (c) 2017 crypto-browserify contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +cron-parser +4.6.0 +The MIT License (MIT) + +Copyright (c) 2014-2016 Harri Siirak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +cross-fetch +3.1.8 +The MIT License (MIT) + +Copyright (c) 2017 Leonardo Quixadá + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +cross-fetch +4.0.0 +The MIT License (MIT) + +Copyright (c) 2017 Leonardo Quixadá + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +cross-spawn +7.0.3 +The MIT License (MIT) + +Copyright (c) 2018 Made With MOXY Lda + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +crypto +1.0.1 +license: ISC +authors: undefined + +****************************** + +crypto-js +4.2.0 +# License + +[The MIT License (MIT)](http://opensource.org/licenses/MIT) + +Copyright (c) 2009-2013 Jeff Mott +Copyright (c) 2013-2016 Evan Vosberg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +css-box-model +1.2.1 +MIT License + +Copyright (c) 2018 Alex Reardon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +csstype +2.6.11 +Copyright (c) 2017-2018 Fredrik Nicol + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +csstype +3.0.11 +Copyright (c) 2017-2018 Fredrik Nicol + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +css-vendor +2.0.8 +The MIT License (MIT) +Copyright (c) 2014-present Oleg Slobodskoi + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +currency-formatter +1.4.2 +The MIT License (MIT) + +Copyright (c) 2015 Soroush Mirzaei + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +debounce +1.1.0 +license: MIT +authors: undefined + +****************************** + +debounce-stream +2.0.0 +The MIT License (MIT) + +Copyright (c) 2015 Nathan Wittstock + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + + +****************************** + +debug +4.3.4 +(The MIT License) + +Copyright (c) 2014-2017 TJ Holowaychuk +Copyright (c) 2018-2021 Josh Junon + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software +and associated documentation files (the 'Software'), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +****************************** + +decimal.js +10.4.3 +license: MIT +authors: Michael Mclaughlin + +****************************** + +deep-equal +2.2.2 +MIT License + +Copyright (c) 2012, 2013, 2014 James Halliday , 2009 Thomas Robinson <280north.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +deep-freeze-strict +1.1.1 +This software is released to the public domain. + +It is based in part on the deepFreeze function from: +https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/freeze + +https://developer.mozilla.org/en-US/docs/Project:Copyrights + + +****************************** + +deepmerge +4.3.1 +The MIT License (MIT) + +Copyright (c) 2012 James Halliday, Josh Duff, and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +define-data-property +1.1.2 +MIT License + +Copyright (c) 2023 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +define-properties +1.2.1 +The MIT License (MIT) + +Copyright (C) 2015 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +delay +5.0.0 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +delayed-stream +1.0.0 +Copyright (c) 2011 Debuggable Limited + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +delimit-stream +0.1.0 +Copyright (c) 2013, Jason Kuhrt +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +****************************** + +detect-browser +5.2.0 +The MIT License (MIT) + +Copyright (c) 2019 Damon Oehlman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +detect-node-es +1.1.0 +MIT License + +Copyright (c) 2017 Ilya Kantor + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +dom-helpers +3.4.0 +The MIT License (MIT) + +Copyright (c) 2015 Jason Quense + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +****************************** + +dom-helpers +5.1.4 +The MIT License (MIT) + +Copyright (c) 2015 Jason Quense + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +****************************** + +duplexer +0.1.2 +license: MIT +authors: Raynos + +****************************** + +eastasianwidth +0.2.0 +license: MIT +authors: Masaki Komagata + +****************************** + +ecdsa-sig-formatter +1.0.11 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2015 D2L Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +eciesjs +0.3.16 +MIT License + +Copyright (c) 2019-2022 Weiliang Li + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +electron-to-chromium +1.4.715 +Copyright 2018 Kilian Valkhof + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +elliptic +6.5.4 +license: MIT +authors: Fedor Indutny + +****************************** + +emoji-regex +8.0.0 +Copyright Mathias Bynens + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +emoji-regex +9.2.2 +Copyright Mathias Bynens + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@emotion/hash +0.8.0 +MIT License + +Copyright (c) Emotion team and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@emurgo/cardano-serialization-lib-browser +11.5.0 +MIT License + +Copyright (c) 2020 EMURGO + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Includes other software related under the MIT license: +- chain-libs, Copyright 2018-2019 IOHK. For licensing see /LICENSE-IOHK + + +****************************** + +@emurgo/cardano-serialization-lib-nodejs +11.5.0 +MIT License + +Copyright (c) 2020 EMURGO + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Includes other software related under the MIT license: +- chain-libs, Copyright 2018-2019 IOHK. For licensing see /LICENSE-IOHK + + +****************************** + +encoding +0.1.13 +Copyright (c) 2012-2014 Andris Reinman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@endo/env-options +1.1.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +end-of-stream +1.4.4 +The MIT License (MIT) + +Copyright (c) 2014 Mathias Buus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +@ensdomains/content-hash +2.5.7 +ISC License + +Copyright (c) 2018, Pierre-Louis Despaigne + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +****************************** + +es6-promise +4.2.8 +Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +es6-promisify +5.0.0 +license: MIT +authors: Mike Hall + +****************************** + +escalade +3.1.1 +MIT License + +Copyright (c) Luke Edwards (lukeed.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +escape-html +1.0.3 +(The MIT License) + +Copyright (c) 2012-2013 TJ Holowaychuk +Copyright (c) 2015 Andreas Lubbe +Copyright (c) 2015 Tiancheng "Timothy" Gu + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +escape-string-regexp +1.0.5 +The MIT License (MIT) + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +es-errors +1.3.0 +MIT License + +Copyright (c) 2024 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +es-get-iterator +1.1.3 +MIT License + +Copyright (c) 2019 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@eslint-community/eslint-utils +4.4.0 +MIT License + +Copyright (c) 2018 Toru Nagashima + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@eslint-community/regexpp +4.10.0 +MIT License + +Copyright (c) 2018 Toru Nagashima + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +eslint-compat-utils +0.1.2 +MIT License + +Copyright (c) 2023 Yosuke Ota + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +eslint-plugin-es-x +7.5.0 +MIT License + +Copyright (c) 2018 Toru Nagashima + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +eslint-plugin-n +16.6.2 +The MIT License (MIT) + +Copyright (c) 2015 Toru Nagashima + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +eslint-visitor-keys +3.4.3 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright contributors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +eth-eip712-util-browser +0.0.3 +license: ISC +authors: Dan Finlay + +****************************** + +eth-ens-namehash +2.0.8 +license: ISC +authors: Dan Finlay + +****************************** + +ethereum-cryptography +0.1.3 +bip39-without-wordlist.js is based on bip39, which is released under the +ISC license by the Wei Lu and Daniel Cousens. Its license complete license can be found here: https://github.com/bitcoinjs/bip39/blob/0a0e74eac9f4b753939dd6368984900fdba1975b/LICENSE + +hdkey-without-crypto.js is based on hdkey, which is released under the +MIT license by the cryptocoinjs. Its license complete license can be found here: https://github.com/cryptocoinjs/hdkey/blob/87d5495ac8e4dfe9917ddcebf6788ce69c0695ff/LICENSE + +The rest of the project is released under this license: + +Copyright 2019 The ethereum-cryptography contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +ethereum-cryptography +1.1.2 +The MIT License (MIT) + +Copyright (c) 2021 Patricio Palladino, Paul Miller, ethereum-cryptography contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +ethereum-cryptography +2.1.3 +The MIT License (MIT) + +Copyright (c) 2021 Patricio Palladino, Paul Miller, ethereum-cryptography contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +ethereum-ens-network-map +1.0.2 +license: ISC +authors: Dan Finlay + +****************************** + +@ethereumjs/common +3.1.1 +The MIT License (MIT) + +Copyright (c) 2015 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +@ethereumjs/common +3.2.0 +The MIT License (MIT) + +Copyright (c) 2015 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +@ethereumjs/common +4.3.0 +The MIT License (MIT) + +Copyright (c) 2015 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +@ethereumjs/rlp +4.0.1 +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + +****************************** + +@ethereumjs/rlp +5.0.2 +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + +****************************** + +@ethereumjs/tx +4.1.1 +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + +****************************** + +@ethereumjs/tx +4.2.0 +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + +****************************** + +@ethereumjs/tx +5.3.0 +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + +****************************** + +@ethereumjs/util +8.1.0 +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + +****************************** + +@ethereumjs/util +9.0.3 +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + +****************************** + +ethereumjs-util +7.1.5 +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + +****************************** + +ethereumjs-wallet +1.0.2 +The MIT License (MIT) + +Copyright (c) 2015 Alex Beregszaszi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/abi +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/abstract-provider +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/abstract-signer +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/address +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/base64 +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/basex +5.7.0 +Forked from https://github.com/cryptocoinjs/bs58 +Originally written by Mike Hearn for BitcoinJ +Copyright (c) 2011 Google Inc + +Ported to JavaScript by Stefan Thomas +Merged Buffer refactorings from base58-native by Stephen Pair +Copyright (c) 2013 BitPay Inc + +Removed Buffer Dependency +Copyright (c) 2019 Richard Moore + + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/bignumber +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/bytes +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/constants +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/contracts +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/hash +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/hdnode +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/keccak256 +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/logger +5.7.0 +license: MIT +authors: Richard Moore + +****************************** + +@ethersproject/networks +5.7.1 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/pbkdf2 +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/properties +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/providers +5.7.2 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/random +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/rlp +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/sha2 +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/signing-key +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/strings +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/transactions +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/web +5.7.1 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@ethersproject/wordlists +5.7.0 +MIT License + +Copyright (c) 2019 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +ethjs-abi +0.2.1 +The MIT License (MIT) + +Copyright (c) 2016 Nick Dodson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +ethjs-schema +0.2.1 +The MIT License + +Copyright (c) 2016 Nick Dodson. nickdodson.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +eth-lattice-keyring +0.12.4 +MIT License + +Copyright (c) 2021 GridPlus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +eth-method-registry +4.0.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +eth-phishing-detect +1.2.0 +# DON'T BE A DICK PUBLIC LICENSE + +> Version 1.1, December 2016 + +> Copyright (C) 2018 kumavis + +Everyone is permitted to copy and distribute verbatim or modified +copies of this license document. + +> DON'T BE A DICK PUBLIC LICENSE +> TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +1. Do whatever you like with the original work, just don't be a dick. + + Being a dick includes - but is not limited to - the following instances: + + 1a. Outright copyright infringement - Don't just copy this and change the name. + 1b. Selling the unmodified original with no work done what-so-ever, that's REALLY being a dick. + 1c. Modifying the original work to contain hidden harmful content. That would make you a PROPER dick. + +2. If you become rich through modifications, related works/services, or supporting the original work, +share the love. Only a dick would make loads off this work and not buy the original work's +creator(s) a pint. + +3. Code is provided with no warranty. Using somebody else's code and bitching when it goes wrong makes +you a DONKEY dick. Fix the problem yourself. A non-dick would submit the fix back. + + +****************************** + +eth-rpc-errors +4.0.3 +MIT License + +Copyright (c) 2019 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +eventemitter3 +4.0.7 +The MIT License (MIT) + +Copyright (c) 2014 Arnout Kazemier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +events +3.3.0 +MIT + +Copyright Joyent, Inc. and other Node contributors. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +event-target-shim +5.0.1 +The MIT License (MIT) + +Copyright (c) 2015 Toru Nagashima + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +evp_bytestokey +1.0.3 +The MIT License (MIT) + +Copyright (c) 2017 crypto-browserify contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +exit-on-epipe +1.0.1 +Copyright (C) 2015-present SheetJS + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@expo/config +8.5.6 +The MIT License (MIT) + +Copyright (c) 2015-present 650 Industries, Inc. (aka Expo) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +@expo/config-plugins +7.9.2 +The MIT License (MIT) + +Copyright (c) 2015-present 650 Industries, Inc. (aka Expo) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +@expo/config-types +50.0.1 +The MIT License (MIT) + +Copyright (c) 2020-present 650 Industries, Inc. (aka Expo) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +expo-constants +15.4.5 +license: MIT +authors: 650 Industries, Inc. + +****************************** + +@expo/fingerprint +0.6.1 +The MIT License (MIT) + +Copyright (c) 2015-present 650 Industries, Inc. (aka Expo) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +@expo/json-file +8.3.3 +The MIT License (MIT) + +Copyright (c) 2015-present 650 Industries, Inc. (aka Expo) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +@expo/plist +0.1.3 +license: MIT +authors: undefined + +****************************** + +@expo/sdk-runtime-versions +1.0.0 <> +license: MIT +authors: Expo + +****************************** + +@expo/spawn-async +1.7.2 +The MIT License (MIT) + +Copyright (c) 2015 650 Industries + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +extend +3.0.2 +The MIT License (MIT) + +Copyright (c) 2014 Stefan Thomas + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +****************************** + +extension-port-stream +2.1.1 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +extension-port-stream +3.0.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +eyes +0.1.8 <> +Copyright (c) 2009 cloudhead + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +fast-copy +2.1.7 +MIT License + +Copyright (c) 2018 Tony Quetano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +fast-deep-equal +3.1.3 +MIT License + +Copyright (c) 2017 Evgeny Poberezkin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +fast-fifo +1.3.2 +The MIT License (MIT) + +Copyright (c) 2019 Mathias Buus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@fastify/busboy +2.1.1 +Copyright Brian White. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + +****************************** + +fast-json-patch +3.1.1 +(The MIT License) + +Copyright (c) 2013, 2014, 2020 Joachim Wester + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +fast-json-stable-stringify +2.1.0 +This software is released under the MIT license: + +Copyright (c) 2017 Evgeny Poberezkin +Copyright (c) 2013 James Halliday + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +fast-levenshtein +2.0.6 +(MIT License) + +Copyright (c) 2013 [Ramesh Nair](http://www.hiddentao.com/) + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + + + +****************************** + +fast-safe-stringify +2.1.1 +The MIT License (MIT) + +Copyright (c) 2016 David Mark Clements +Copyright (c) 2017 David Mark Clements & Matteo Collina +Copyright (c) 2018 David Mark Clements, Matteo Collina & Ruben Bridgewater + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +fast-stable-stringify +1.0.0 +MIT License + +Copyright (c) 2017 Nicolaas Johannes Out + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +fast-xml-parser +4.3.4 +MIT License + +Copyright (c) 2017 Amit Kumar Gupta + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +faye-websocket +0.11.4 +Copyright 2010-2021 James Coglan + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. + + +****************************** + +file-uri-to-path +1.0.0 +Copyright (c) 2014 Nathan Rajlich + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +find-up +5.0.0 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +firebase +10.11.0 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/analytics +0.10.2 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/analytics-compat +0.2.8 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/analytics-types +0.8.1 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/app +0.10.1 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/app-check +0.8.3 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/app-check-compat +0.3.10 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/app-check-interop-types +0.3.1 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/app-check-types +0.5.1 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/app-compat +0.2.31 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/app-types +0.9.1 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/auth +1.7.1 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/auth-compat +0.5.6 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/auth-interop-types +0.2.2 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/auth-types +0.12.1 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/component +0.6.6 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/database +1.0.4 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/database-compat +1.0.4 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/database-types +1.0.2 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/firestore +4.6.0 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/firestore-compat +0.3.29 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/firestore-types +3.0.1 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/functions +0.11.4 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/functions-compat +0.3.10 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/functions-types +0.6.1 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/installations +0.6.6 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/installations-compat +0.2.6 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/installations-types +0.5.1 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/logger +0.4.1 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/messaging +0.12.8 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/messaging-compat +0.2.8 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/messaging-interop-types +0.2.1 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/performance +0.6.6 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/performance-compat +0.2.6 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/performance-types +0.2.1 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/remote-config +0.4.6 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/remote-config-compat +0.2.6 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/remote-config-types +0.3.1 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/storage +0.12.4 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/storage-compat +0.3.7 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/storage-types +0.8.1 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/util +1.9.5 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@firebase/webchannel-wrapper +0.10.6 +license: Apache-2.0 +authors: Firebase (https://firebase.google.com/) + +****************************** + +@fivebinaries/coin-selection +2.2.1 <> +license: Apache-2.0 +authors: fivebinaries.com + +****************************** + +focus-lock +0.11.6 +MIT License + +Copyright (c) 2017 Anton Korzunov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +follow-redirects +1.15.6 +Copyright 2014–present Olivier Lalonde , James Talmage , Ruben Verborgh + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +for-each +0.3.3 +The MIT License (MIT) + +Copyright (c) 2012 Raynos. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +foreground-child +3.1.1 +The ISC License + +Copyright (c) 2015-2023 Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +form-data +4.0.0 +Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + +****************************** + +@fortawesome/fontawesome-free +5.13.0 +Font Awesome Free License +------------------------- + +Font Awesome Free is free, open source, and GPL friendly. You can use it for +commercial projects, open source projects, or really almost whatever you want. +Full Font Awesome Free license: https://fontawesome.com/license/free. + +# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/) +In the Font Awesome Free download, the CC BY 4.0 license applies to all icons +packaged as SVG and JS file types. + +# Fonts: SIL OFL 1.1 License (https://scripts.sil.org/OFL) +In the Font Awesome Free download, the SIL OFL license applies to all icons +packaged as web and desktop font files. + +# Code: MIT License (https://opensource.org/licenses/MIT) +In the Font Awesome Free download, the MIT license applies to all non-font and +non-icon files. + +# Attribution +Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font +Awesome Free files already contain embedded comments with sufficient +attribution, so you shouldn't need to do anything additional when using these +files normally. + +We've kept attribution comments terse, so we ask that you do not actively work +to remove them from files, especially code. They're a great way for folks to +learn about Font Awesome. + +# Brand Icons +All brand icons are trademarks of their respective owners. The use of these +trademarks does not indicate endorsement of the trademark holder by Font +Awesome, nor vice versa. **Please do not use brand logos for any purpose except +to represent the company, product, or service to which they refer.** + + +****************************** + +function-bind +1.1.2 +Copyright (c) 2013 Raynos. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + + +****************************** + +functions-have-names +1.2.3 +MIT License + +Copyright (c) 2019 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +fuse.js +3.6.1 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 Kirollos Risk + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +futoin-hkdf +1.5.1 + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +gensync +1.0.0-beta.2 +Copyright 2018 Logan Smyth + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +get-caller-file +2.0.5 +ISC License (ISC) +Copyright 2018 Stefan Penner + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +getenv +1.0.0 +The MIT License (MIT) +Copyright (c) 2012-2019 Christoph Tavan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +get-intrinsic +1.2.4 +MIT License + +Copyright (c) 2020 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +get-npm-tarball-url +2.0.3 +MIT License + +Copyright (c) 2017-2021 Zoltan Kochan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +get-tsconfig +4.7.5 +MIT License + +Copyright (c) Hiroki Osame + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +gl-mat4 +1.1.4 +Copyright (c) 2013 Brandon Jones, Colin MacKenzie IV + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. + +****************************** + +glob +10.4.1 +The ISC License + +Copyright (c) 2009-2023 Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +globals +11.12.0 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +globals +13.24.0 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +gl-vec3 +1.0.3 +Copyright (c) 2013 Brandon Jones, Colin MacKenzie IV + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. + +****************************** + +gopd +1.0.1 +MIT License + +Copyright (c) 2022 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +graceful-fs +4.2.11 +The ISC License + +Copyright (c) 2011-2022 Isaac Z. Schlueter, Ben Noordhuis, and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +gridplus-sdk +2.5.1 +MIT License + +Copyright (c) 2019 GridPlus, Inc + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@grpc/grpc-js +1.9.14 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@grpc/proto-loader +0.7.12 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +gud +1.0.0 +license: MIT +authors: Jamie Kyle + +****************************** + +has-bigints +1.0.2 +MIT License + +Copyright (c) 2019 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +has-flag +3.0.0 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +has-flag +4.0.0 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +hash-base +3.1.0 +The MIT License (MIT) + +Copyright (c) 2016 Kirill Fomichev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +hash.js +1.1.7 +license: MIT +authors: Fedor Indutny + +****************************** + +hasown +2.0.0 +MIT License + +Copyright (c) Jordan Harband and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +has-property-descriptors +1.0.1 +MIT License + +Copyright (c) 2022 Inspect JS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +has-proto +1.0.1 +MIT License + +Copyright (c) 2022 Inspect JS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +has-symbols +1.0.3 +MIT License + +Copyright (c) 2016 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +has-tostringtag +1.0.0 +MIT License + +Copyright (c) 2021 Inspect JS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +hdkey +2.1.0 +MIT License + +Copyright (c) 2018 cryptocoinjs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +he +1.2.0 +Copyright Mathias Bynens + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +history +4.10.1 +MIT License + +Copyright (c) React Training 2016-2018 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +hmac-drbg +1.0.1 +license: MIT +authors: Fedor Indutny + +****************************** + +hoist-non-react-statics +3.3.2 +Software License Agreement (BSD License) +======================================== + +Copyright (c) 2015, Yahoo! Inc. All rights reserved. +---------------------------------------------------- + +Redistribution and use of this software in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Yahoo! Inc. nor the names of YUI's contributors may be + used to endorse or promote products derived from this software without + specific prior written permission of Yahoo! Inc. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +http-parser-js +0.4.9 +Copyright (c) 2015 Tim Caswell (https://github.com/creationix) and other +contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +Some files from the tests folder are from joyent/node and mscedex/io.js, a fork +of nodejs/io.js: + +- tests/iojs/test-http-parser-durability.js + + This file is from https://github.com/mscdex/io.js/blob/js-http-parser/test/pummel/test-http-parser-durability.js + with modifications by Jan Schär (jscissr). + + """ + Copyright io.js contributors. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + """ + +- tests/fixtures/* + tests/parallel/* + tests/testpy/* + tests/common.js + tests/test.py + tests/utils.py + + These files are from https://github.com/nodejs/node with changes by + Jan Schär (jscissr). + + Node.js is licensed for use as follows: + + """ + Copyright Node.js contributors. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + """ + + This license applies to parts of Node.js originating from the + https://github.com/joyent/node repository: + + """ + Copyright Joyent, Inc. and other Node contributors. All rights reserved. + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + """ + + +****************************** + +https-proxy-agent +5.0.1 +license: MIT +authors: Nathan Rajlich (http://n8.io/) + +****************************** + +humanize-ms +1.2.1 +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +human-standard-token-abi +2.0.0 +license: ISC +authors: Dan Finlay + +****************************** + +hyphenate-style-name +1.0.3 +Copyright (c) 2015, Espen Hovlandsdal +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of hyphenate-style-name nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +****************************** + +iconv-lite +0.6.3 +Copyright (c) 2011 Alexander Shtuchkin + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +****************************** + +idb +7.1.1 +ISC License (ISC) +Copyright (c) 2016, Jake Archibald + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +idna-uts46-hx +2.3.1 +Original work Copyright (c) 2015 Joshua Cranmer as part of jcranmer/idna-uts46. +Modified work Copyright (c) 2017 Kai Schwarz as part of this fork hexonet/idna-uts46. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +ieee754 +1.2.1 +Copyright 2008 Fair Oaks Labs, Inc. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +ignore +5.3.1 +Copyright (c) 2013 Kael Zhang , contributors +http://kael.me/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +****************************** + +immediate +3.0.6 +Copyright (c) 2012 Barnesandnoble.com, llc, Donavon West, Domenic Denicola, Brian Cavalier + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +immer +9.0.21 +MIT License + +Copyright (c) 2017 Michel Weststrate + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +imurmurhash +0.1.4 +license: MIT +authors: Jens Taylor + +****************************** + +inherits +2.0.4 +The ISC License + +Copyright (c) Isaac Z. Schlueter + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + + + +****************************** + +inline-style-parser +0.1.1 +license: MIT +authors: undefined + +****************************** + +int64-buffer +1.0.1 +The MIT License (MIT) + +Copyright (c) 2015-2020 Yusuke Kawasaki + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +internal-slot +1.0.6 +MIT License + +Copyright (c) 2019 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +ip-address +9.0.5 +Copyright (C) 2011 by Beau Gunderson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@isaacs/cliui +8.0.2 +Copyright (c) 2015, Contributors + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice +appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE +LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +is-alphabetical +1.0.4 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +is-alphanumerical +1.0.1 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +is-arguments +1.1.1 +The MIT License (MIT) + +Copyright (c) 2014 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +isarray +0.0.1 +license: MIT +authors: Julian Gruber + +****************************** + +isarray +1.0.0 +license: MIT +authors: Julian Gruber + +****************************** + +isarray +2.0.5 +MIT License + +Copyright (c) 2013 Julian Gruber + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +is-array-buffer +3.0.2 +MIT License + +Copyright (c) 2015 Chen Gengyuan, Inspect JS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +is-bigint +1.0.4 +MIT License + +Copyright (c) 2018 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +is-boolean-object +1.1.2 +The MIT License (MIT) + +Copyright (c) 2015 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +is-buffer +2.0.5 +The MIT License (MIT) + +Copyright (c) Feross Aboukhadijeh + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +is-builtin-module +3.2.1 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +is-callable +1.2.7 +The MIT License (MIT) + +Copyright (c) 2015 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +is-core-module +2.13.1 +The MIT License (MIT) + +Copyright (c) 2014 Dave Justice + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +****************************** + +is-date-object +1.0.5 +The MIT License (MIT) + +Copyright (c) 2015 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +is-decimal +1.0.4 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +isexe +2.0.0 +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +is-fn +1.0.0 +The MIT License (MIT) + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +is-fullwidth-code-point +3.0.0 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +is-generator-function +1.0.10 +The MIT License (MIT) + +Copyright (c) 2014 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +is-hexadecimal +1.0.1 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +is-hex-prefixed +1.0.0 +The MIT License + +Copyright (c) 2016 Nick Dodson. nickdodson.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +is-in-browser +1.1.3 +license: MIT +authors: Jared Anderson + +****************************** + +is-map +2.0.2 +MIT License + +Copyright (c) 2019 Inspect JS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +is-nan +1.3.2 +The MIT License (MIT) + +Copyright (c) 2014 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +is-number-object +1.0.7 +The MIT License (MIT) + +Copyright (c) 2015 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +isomorphic-ws +4.0.1 +The MIT License (MIT) + +Copyright (c) 2018 Zejin Zhuang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +****************************** + +iso-url +0.4.7 +MIT License + +Copyright (c) Hugo Dias (hugodias.me) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +is-plain-obj +2.1.0 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +is-regex +1.1.4 +The MIT License (MIT) + +Copyright (c) 2014 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +is-retry-allowed +2.2.0 +MIT License + +Copyright (c) Vsevolod Strukchinsky (github.com/floatdrop) +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +is-set +2.0.2 +MIT License + +Copyright (c) 2019 Inspect JS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +is-shared-array-buffer +1.0.2 +MIT License + +Copyright (c) 2021 Inspect JS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +is-stream +2.0.0 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +is-string +1.0.7 +The MIT License (MIT) + +Copyright (c) 2015 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +is-symbol +1.0.4 +The MIT License (MIT) + +Copyright (c) 2015 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +is-typed-array +1.1.10 +The MIT License (MIT) + +Copyright (c) 2015 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +is-weakmap +2.0.1 +MIT License + +Copyright (c) 2019 Inspect JS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +is-weakset +2.0.2 +MIT License + +Copyright (c) 2019 Inspect JS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +jackspeak +3.1.2 +# Blue Oak Model License + +Version 1.0.0 + +## Purpose + +This license gives everyone as much permission to work with +this software as possible, while protecting contributors +from liability. + +## Acceptance + +In order to receive this license, you must agree to its +rules. The rules of this license are both obligations +under that agreement and conditions to your license. +You must not do anything with this software that triggers +a rule that you cannot or will not follow. + +## Copyright + +Each contributor licenses you to do everything with this +software that would otherwise infringe that contributor's +copyright in it. + +## Notices + +You must ensure that everyone who gets a copy of +any part of this software from you, with or without +changes, also gets the text of this license or a link to +. + +## Excuse + +If anyone notifies you in writing that you have not +complied with [Notices](#notices), you can keep your +license by taking all practical steps to comply within 30 +days after the notice. If you do not do so, your license +ends immediately. + +## Patent + +Each contributor licenses you to do everything with this +software that would otherwise infringe any patent claims +they can license or become able to license. + +## Reliability + +No contributor can revoke this license. + +## No Liability + +***As far as the law allows, this software comes as is, +without any warranty or condition, and no contributor +will be liable to anyone for any damages related to this +software or this license, under any kind of legal claim.*** + + +****************************** + +jayson +4.1.0 +(The MIT License) + +Copyright (c) 2011-2012 Tedde Lundgren + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +jest-create-mock-instance +2.0.0 +MIT License + +Copyright (c) 2017 Alexey Svetliakov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +jest-fetch-mock +3.0.3 +MIT License + +Copyright (c) 2017 Jeff Lau + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +jest-junit +14.0.1 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Jason Palmer + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +join-component +1.1.0 <> +license: MIT +authors: undefined + +****************************** + +@jridgewell/gen-mapping +0.3.5 +Copyright 2022 Justin Ridgewell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@jridgewell/resolve-uri +3.1.1 +Copyright 2019 Justin Ridgewell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +****************************** + +@jridgewell/set-array +1.2.1 +Copyright 2022 Justin Ridgewell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@jridgewell/sourcemap-codec +1.4.15 +The MIT License + +Copyright (c) 2015 Rich Harris + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@jridgewell/trace-mapping +0.3.25 +Copyright 2022 Justin Ridgewell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +js-base64 +3.6.1 +Copyright (c) 2014, Dan Kogai +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of {{{project}}} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +jsbi +3.2.5 + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +****************************** + +jsbn +1.1.0 +Licensing +--------- + +This software is covered under the following copyright: + +/* + * Copyright (c) 2003-2005 Tom Wu + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF + * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * In addition, the following condition applies: + * + * All redistributions must retain an intact copy of this copyright notice + * and disclaimer. + */ + +Address all questions regarding this license to: + + Tom Wu + tjw@cs.Stanford.EDU + + +****************************** + +jsesc +2.5.2 +Copyright Mathias Bynens + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +json5 +2.2.3 +MIT License + +Copyright (c) 2012-2018 Aseem Kishore, and [others]. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +[others]: https://github.com/json5/json5/contributors + + +****************************** + +jsonify +0.0.1 +license: Public Domain +authors: Douglas Crockford + +****************************** + +jsonparse +1.3.1 +The MIT License + +Copyright (c) 2012 Tim Caswell + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +json-rpc-engine +6.1.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +json-rpc-middleware-stream +5.0.1 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +json-rpc-random-id +1.0.1 +license: ISC +authors: undefined + +****************************** + +jsonschema +1.2.2 +jsonschema is licensed under MIT license. + +Copyright (C) 2012-2015 Tom de Grunt + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +jsonschema +1.2.4 +jsonschema is licensed under MIT license. + +Copyright (C) 2012-2015 Tom de Grunt + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +json-stable-stringify +1.1.1 +MIT License + +Copyright (c) 2013 contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +JSONStream +1.3.5 +Apache License, Version 2.0 + +Copyright (c) 2011 Dominic Tarr + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +****************************** + +json-stringify-safe +5.0.1 +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +json-text-sequence +0.1.1 +The MIT License (MIT) + +Copyright (c) 2014 Joe Hildebrand + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +jsonwebtoken +9.0.0 +The MIT License (MIT) + +Copyright (c) 2015 Auth0, Inc. (http://auth0.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +jss +10.3.0 +The MIT License (MIT) +Copyright (c) 2014-present Oleg Isonen (Slobodskoi) & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +jssha +3.2.0 +Copyright (c) 2008-2020 Brian Turek, 1998-2009 Paul Johnston & Contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +****************************** + +js-sha3 +0.9.3 +Copyright 2015-2023 Chen, Yi-Cyuan + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +jss-plugin-camel-case +10.3.0 +The MIT License (MIT) +Copyright (c) 2014-present Oleg Isonen (Slobodskoi) & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +jss-plugin-default-unit +10.3.0 +The MIT License (MIT) +Copyright (c) 2014-present Oleg Isonen (Slobodskoi) & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +jss-plugin-global +10.3.0 +The MIT License (MIT) +Copyright (c) 2014-present Oleg Isonen (Slobodskoi) & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +jss-plugin-nested +10.3.0 +The MIT License (MIT) +Copyright (c) 2014-present Oleg Isonen (Slobodskoi) & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +jss-plugin-props-sort +10.3.0 +The MIT License (MIT) +Copyright (c) 2014-present Oleg Isonen (Slobodskoi) & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +jss-plugin-rule-value-function +10.3.0 +The MIT License (MIT) +Copyright (c) 2014-present Oleg Isonen (Slobodskoi) & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +jss-plugin-vendor-prefixer +10.3.0 +The MIT License (MIT) +Copyright (c) 2014-present Oleg Isonen (Slobodskoi) & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +js-tokens +4.0.0 +The MIT License (MIT) + +Copyright (c) 2014, 2015, 2016, 2017, 2018 Simon Lydell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +jwa +1.4.1 +Copyright (c) 2013 Brian J. Brennan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +jws +3.2.2 +Copyright (c) 2013 Brian J. Brennan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +keccak +3.0.2 +The MIT License (MIT) + +Copyright (c) 2016-2019 https://github.com/cryptocoinjs/keccak contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@keystonehq/alias-sampling +0.1.2 <> +MIT License + +Copyright (c) 2024 KeystoneHQ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@keystonehq/base-eth-keyring +0.14.1 +license: MIT +authors: aaronisme + +****************************** + +@keystonehq/bc-ur-registry +0.6.4 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@keystonehq/bc-ur-registry-eth +0.19.1 <> +license: ISC +authors: soralit + +****************************** + +@keystonehq/metamask-airgapped-keyring +0.13.1 +license: MIT +authors: aaronisme + +****************************** + +klona +2.0.6 +MIT License + +Copyright (c) Luke Edwards (lukeed.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@kwsites/file-exists +1.1.1 +The MIT License (MIT) + +Copyright (c) 2015 Steve King + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@kwsites/promise-deferred +1.1.1 +MIT License + +Copyright (c) 2018 kwsites + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +labeled-stream-splicer +2.0.2 +The MIT License (MIT) + +Copyright (c) James Halliday and browserify contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@lavamoat/lavadome-core +0.0.17 <> +license: MIT +authors: undefined + +****************************** + +@lavamoat/lavadome-react +0.0.17 <> +license: MIT +authors: undefined + +****************************** + +@lavamoat/preinstall-always-fail +2.0.0 +The MIT License (MIT) + +Copyright (c) 2020 Consensys Software + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@lavamoat/snow +2.0.1 +The MIT License (MIT) + +Copyright (c) 2020 Consensys Software + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +lie +3.1.1 +#Copyright (c) 2014 Calvin Metcalf + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +**THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.** + +****************************** + +lines-and-columns +1.1.6 +The MIT License (MIT) + +Copyright (c) 2015 Brian Donovan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +locale-currency +0.0.1 +license: BSD-2-Clause +authors: Thomas Deegan + +****************************** + +localforage +1.10.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2014 Mozilla + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +locate-path +6.0.0 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +lodash +4.17.21 +Copyright OpenJS Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + + +****************************** + +lodash.camelcase +4.3.0 +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + + +****************************** + +lodash.clonedeep +4.5.0 +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + + +****************************** + +lodash.isplainobject +4.0.6 +Copyright jQuery Foundation and other contributors + +Based on Underscore.js, copyright Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/lodash/lodash + +The following license applies to all parts of this software except as +documented below: + +==== + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +==== + +Copyright and related rights for sample code are waived via CC0. Sample +code is defined as all source code displayed within the prose of the +documentation. + +CC0: http://creativecommons.org/publicdomain/zero/1.0/ + +==== + +Files located in the node_modules and vendor directories are externally +maintained libraries used by this software which have their own +licenses; we recommend you read them, as their terms may differ from the +terms above. + + +****************************** + +lodash.isstring +4.0.1 +Copyright 2012-2016 The Dojo Foundation +Based on Underscore.js, copyright 2009-2016 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +loglevel +1.9.1 +Copyright (c) 2013 Tim Perry + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +long +4.0.0 + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +long +5.2.3 + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +loose-envify +1.4.0 +The MIT License (MIT) + +Copyright (c) 2015 Andres Suarez + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +lru-cache +10.2.2 +The ISC License + +Copyright (c) 2010-2023 Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +lru-cache +5.1.1 +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +lru-cache +6.0.0 +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +luxon +3.2.1 +Copyright 2019 JS Foundation and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +marked +12.0.1 +# License information + +## Contribution License Agreement + +If you contribute code to this project, you are implicitly allowing your code +to be distributed under the MIT license. You are also implicitly verifying that +all code is your original work. `` + +## Marked + +Copyright (c) 2018+, MarkedJS (https://github.com/markedjs/) +Copyright (c) 2011-2018, Christopher Jeffrey (https://github.com/chjj/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +## Markdown + +Copyright © 2004, John Gruber +http://daringfireball.net/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +* Neither the name “Markdown” nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +This software is provided by the copyright holders and contributors “as is” and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright owner or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. + + +****************************** + +@material-ui/core +4.11.0 +The MIT License (MIT) + +Copyright (c) 2014 Call-Em-All + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@material-ui/styles +4.10.0 +The MIT License (MIT) + +Copyright (c) 2014 Call-Em-All + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@material-ui/system +4.9.14 +The MIT License (MIT) + +Copyright (c) 2014 Call-Em-All + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@material-ui/types +5.1.0 +license: MIT +authors: Material-UI Team + +****************************** + +@material-ui/utils +4.10.2 +The MIT License (MIT) + +Copyright (c) 2014 Call-Em-All + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +md5.js +1.3.5 +The MIT License (MIT) + +Copyright (c) 2016 Kirill Fomichev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +mdast-util-definitions +4.0.0 +(The MIT License) + +Copyright (c) 2015-2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +mdast-util-from-markdown +0.8.5 +(The MIT License) + +Copyright (c) 2020 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +mdast-util-to-hast +10.2.0 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +mdast-util-to-string +2.0.0 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +mdurl +1.0.1 +Copyright (c) 2015 Vitaly Puzrin, Alex Kocharin. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +-------------------------------------------------------------------------------- + +.parse() is based on Joyent's node.js `url` code: + +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + + +****************************** + +memoize-one +5.2.1 +MIT License + +Copyright (c) 2019 Alexander Reardon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +****************************** + +mersenne-twister +1.1.0 +license: MIT +authors: Egor Gumenyuk + +****************************** + +@metamask/abi-utils +2.0.2 +license: (Apache-2.0 AND MIT) +authors: Maarten Zuidhoorn + +****************************** + +@metamask/accounts-controller +14.0.0 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/address-book-controller +4.0.1 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/announcement-controller +6.1.0 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/approval-controller +6.0.2 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/approval-controller +7.0.0 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/assets-controllers +29.0.0 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/base-controller +3.2.3 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/base-controller +4.1.1 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/base-controller +5.0.2 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/base-controller +6.0.0 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/browser-passworder +4.3.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/contract-metadata +2.5.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/controller-utils +11.0.0 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/controller-utils +8.0.4 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/controller-utils +9.1.0 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/design-tokens +3.0.0 +license: MIT +authors: undefined + +****************************** + +@metamask/desktop +0.3.0 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask/ens-controller +10.0.1 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/eth-block-tracker +9.0.3 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/etherscan-link +3.0.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/eth-hd-keyring +7.0.1 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/ethjs +0.6.0 +The MIT License + +Copyright (c) 2016 Nick Dodson. nickdodson.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@metamask/ethjs-contract +0.4.1 +The MIT License + +Copyright (c) 2016 Nick Dodson. nickdodson.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@metamask/ethjs-filter +0.3.0 +The MIT License + +Copyright (c) 2016 Nick Dodson. nickdodson.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@metamask/ethjs-format +0.3.0 +The MIT License + +Copyright (c) 2016 Nick Dodson. nickdodson.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@metamask/eth-json-rpc-filters +7.0.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/eth-json-rpc-infura +9.1.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/eth-json-rpc-middleware +12.1.1 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/eth-json-rpc-provider +2.3.2 +ISC License + +Copyright (c) 2022 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/eth-json-rpc-provider +3.0.2 +ISC License + +Copyright (c) 2022 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/ethjs-provider-http +0.3.0 +The MIT License + +Copyright (c) 2016 Nick Dodson. nickdodson.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@metamask/ethjs-query +0.7.1 +The MIT License + +Copyright (c) 2016 Nick Dodson. nickdodson.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@metamask/ethjs-rpc +0.4.0 +The MIT License + +Copyright (c) 2016 Nick Dodson. nickdodson.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@metamask/ethjs-unit +0.3.0 +The MIT License (MIT) + +Copyright (c) 2016 Nick Dodson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@metamask/ethjs-util +0.3.0 +The MIT License + +Copyright (c) 2016 Nick Dodson. nickdodson.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@metamask/eth-ledger-bridge-keyring +2.0.1 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/eth-query +3.0.1 +license: ISC +authors: undefined + +****************************** + +@metamask/eth-query +4.0.0 +license: ISC +authors: undefined + +****************************** + +@metamask/eth-sig-util +7.0.1 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/eth-simple-keyring +6.0.1 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/eth-snap-keyring +4.2.1 +license: Custom: https://metamask.github.io/eth-snap-keyring/latest/ +authors: undefined + +****************************** + +@metamask/eth-token-tracker +8.0.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/eth-trezor-keyring +3.1.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/gas-fee-controller +15.1.2 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/gas-fee-controller +17.0.0 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask-institutional/configuration-client +2.0.1 +MIT License + +Copyright (c) 2023 ConsenSys Vertical Apps + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask-institutional/custody-controller +0.2.27 +MIT License + +Copyright (c) 2023 ConsenSys Vertical Apps + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask-institutional/custody-keyring +2.0.0 +MIT License + +Copyright (c) 2023 ConsenSys Vertical Apps + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask-institutional/extension +0.3.24 +MIT License + +Copyright (c) 2023 ConsenSys Vertical Apps + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask-institutional/institutional-features +1.3.2 +MIT License + +Copyright (c) 2023 ConsenSys Vertical Apps + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask-institutional/portfolio-dashboard +1.4.1 +MIT License + +Copyright (c) 2023 ConsenSys Vertical Apps + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask-institutional/rpc-allowlist +1.0.3 +MIT License + +Copyright (c) 2023 ConsenSys Vertical Apps + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask-institutional/sdk +0.1.27 +MIT License + +Copyright (c) 2023 ConsenSys Vertical Apps + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask-institutional/simplecache +1.1.0 +MIT License + +Copyright (c) 2023 ConsenSys Vertical Apps + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask-institutional/transaction-update +0.2.2 +MIT License + +Copyright (c) 2023 ConsenSys Vertical Apps + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask-institutional/types +1.1.0 +MIT License + +Copyright (c) 2023 ConsenSys Vertical Apps + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask-institutional/websocket-client +0.2.2 +MIT License + +Copyright (c) 2023 ConsenSys Vertical Apps + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask/jazzicon +2.0.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/json-rpc-engine +7.3.3 +ISC License + +Copyright (c) 2022 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/json-rpc-engine +8.0.2 +ISC License + +Copyright (c) 2022 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/json-rpc-middleware-stream +7.0.1 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/keyring-api +5.1.0 +license: Custom: https://docs.metamask.io/snaps/ +authors: undefined + +****************************** + +@metamask/keyring-api +6.3.1 +license: Custom: https://docs.metamask.io/snaps/ +authors: undefined + +****************************** + +@metamask/keyring-controller +15.0.0 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/key-tree +9.1.1 +MIT License + +Copyright (c) 2021 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask/logging-controller +3.0.1 +license: MIT +authors: undefined + +****************************** + +@metamask/logo +3.1.2 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/message-manager +7.3.9 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/message-manager +8.0.2 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/message-signing-snap +0.3.3 +license: Custom: http://localhost +authors: undefined + +****************************** + +@metamask/metamask-eth-abis +3.1.1 +ISC License + +Copyright (c) 2021 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +****************************** + +@metamask/name-controller +6.0.1 +MIT License + +Copyright (c) 2023 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/network-controller +18.1.2 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/nonce-tracker +5.0.0 +MIT License + +Copyright (c) 2019 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask/notification-controller +3.0.0 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/number-to-bn +1.7.1 +The MIT License + +Copyright (c) 2016 Nick Dodson. nickdodson.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@metamask/object-multiplex +2.0.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/obs-store +5.0.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/obs-store +7.0.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/obs-store +8.1.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/obs-store +9.0.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/permission-controller +9.0.2 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/permission-log-controller +2.0.1 +Copyright ConsenSys Software Inc. 2022. All rights reserved. + +You acknowledge and agree that ConsenSys Software Inc. (“ConsenSys”) (or ConsenSys’s licensors) own all legal right, title and interest in and to the work, software, application, source code, documentation and any other documents in this repository (collectively, the “Program”), including any intellectual property rights which subsist in the Program (whether those rights happen to be registered or not, and wherever in the world those rights may exist), whether in source code or any other form. + +Subject to the limited license below, you may not (and you may not permit anyone else to) distribute, publish, copy, modify, merge, combine with another program, create derivative works of, reverse engineer, decompile or otherwise attempt to extract the source code of, the Program or any part thereof, except that you may contribute to this repository. + +You are granted a non-exclusive, non-transferable, non-sublicensable license to distribute, publish, copy, modify, merge, combine with another program or create derivative works of the Program (such resulting program, collectively, the “Resulting Program”) solely for Non-Commercial Use as long as you: + 1. give prominent notice (“Notice”) with each copy of the Resulting Program that the Program is used in the Resulting Program and that the Program is the copyright of ConsenSys; and + 2. subject the Resulting Program and any distribution, publication, copy, modification, merger therewith, combination with another program or derivative works thereof to the same Notice requirement and Non-Commercial Use restriction set forth herein. + +“Non-Commercial Use” means each use as described in clauses (1)-(3) below, as reasonably determined by ConsenSys in its sole discretion: + 1. personal use for research, personal study, private entertainment, hobby projects or amateur pursuits, in each case without any anticipated commercial application; + 2. use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization or government institution; or + 3. the number of monthly active users of the Resulting Program across all versions thereof and platforms globally do not exceed 10,000 at any time. + +You will not use any trade mark, service mark, trade name, logo of ConsenSys or any other company or organization in a way that is likely or intended to cause confusion about the owner or authorized user of such marks, names or logos. + +If you have any questions, comments or interest in pursuing any other use cases, please reach out to us at communications@metamask.io. + + +****************************** + +@metamask/phishing-controller +9.0.2 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/polling-controller +6.0.2 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/polling-controller +8.0.0 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/post-message-stream +8.1.0 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/ppom-validator +0.30.0 +license: Custom: https://nodejs.org +authors: undefined + +****************************** + +@metamask/preferences-controller +11.0.0 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/providers +14.0.2 +MIT License + +Copyright (c) 2020 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask/providers +16.1.0 +MIT License + +Copyright (c) 2020 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask/queued-request-controller +0.10.0 +MIT License + +Copyright (c) 2023 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/rate-limit-controller +5.0.1 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/rpc-errors +6.2.1 +MIT License + +Copyright (c) 2019 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@metamask/safe-event-emitter +2.0.0 <> +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/safe-event-emitter +3.1.1 +ISC License + +Copyright (c) 2020 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/scure-bip39 +2.1.1 +The MIT License (MIT) + +Copyright (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@metamask/selected-network-controller +13.0.0 +MIT License + +Copyright (c) 2023 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/signature-controller +14.0.1 +MIT License + +Copyright (c) 2023 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/slip44 +3.1.0 +license: ISC +authors: Dan Finlay + +****************************** + +@metamask/smart-transactions-controller +10.0.1 +Copyright ConsenSys Software Inc. 2020. All rights reserved. + +You acknowledge and agree that ConsenSys Software Inc. (“ConsenSys”) (or ConsenSys’s licensors) own all legal right, title and interest in and to the work, software, application, source code, documentation and any other documents in this repository (collectively, the “Program”), including any intellectual property rights which subsist in the Program (whether those rights happen to be registered or not, and wherever in the world those rights may exist), whether in source code or any other form. + +Subject to the limited license below, you may not (and you may not permit anyone else to) distribute, publish, copy, modify, merge, combine with another program, create derivative works of, reverse engineer, decompile or otherwise attempt to extract the source code of, the Program or any part thereof, except that you may contribute to this repository. + +You are granted a non-exclusive, non-transferable, non-sublicensable license to distribute, publish, copy, modify, merge, combine with another program or create derivative works of the Program (such resulting program, collectively, the “Resulting Program”) solely for Non-Commercial Use as long as you: + 1. give prominent notice (“Notice”) with each copy of the Resulting Program that the Program is used in the Resulting Program and that the Program is the copyright of ConsenSys; and + 2. subject the Resulting Program and any distribution, publication, copy, modification, merger therewith, combination with another program or derivative works thereof to the same Notice requirement and Non-Commercial Use restriction set forth herein. + +“Non-Commercial Use” means each use as described in clauses (1)-(3) below, as reasonably determined by ConsenSys in its sole discretion: + 1. personal use for research, personal study, private entertainment, hobby projects or amateur pursuits, in each case without any anticipated commercial application; + 2. use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization or government institution; or + 3. the number of monthly active users of the Resulting Program across all versions thereof and platforms globally do not exceed 10,000 at any time. + +You will not use any trade mark, service mark, trade name, logo of ConsenSys or any other company or organization in a way that is likely or intended to cause confusion about the owner or authorized user of such marks, names or logos. + +If you have any questions, comments or interest in pursuing any other use cases, please reach out to us at metamask.license@consensys.net. + + +****************************** + +@metamask/snaps-controllers +8.2.0 +Copyright ConsenSys Software Inc. 2021. All rights reserved. + +You acknowledge and agree that ConsenSys Software Inc. (“ConsenSys”) (or ConsenSys’s licensors) own all legal right, title and interest in and to the work, software, application, source code, documentation and any other documents in this repository (collectively, the “Program”), including any intellectual property rights which subsist in the Program (whether those rights happen to be registered or not, and wherever in the world those rights may exist), whether in source code or any other form. + +Subject to the limited license below, you may not (and you may not permit anyone else to) distribute, publish, copy, modify, merge, combine with another program, create derivative works of, reverse engineer, decompile or otherwise attempt to extract the source code of, the Program or any part thereof, except that you may contribute to this repository. + +You are granted a non-exclusive, non-transferable, non-sublicensable license to distribute, publish, copy, modify, merge, combine with another program or create derivative works of the Program (such resulting program, collectively, the “Resulting Program”) solely for Non-Commercial Use as long as you: + 1. give prominent notice (“Notice”) with each copy of the Resulting Program that the Program is used in the Resulting Program and that the Program is the copyright of ConsenSys; and + 2. subject the Resulting Program and any distribution, publication, copy, modification, merger therewith, combination with another program or derivative works thereof to the same Notice requirement and Non-Commercial Use restriction set forth herein. + +“Non-Commercial Use” means each use as described in clauses (1)-(3) below, as reasonably determined by ConsenSys in its sole discretion: + 1. personal use for research, personal study, private entertainment, hobby projects or amateur pursuits, in each case without any anticipated commercial application; + 2. use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization or government institution; or + 3. the number of monthly active users of the Resulting Program across all versions thereof and platforms globally do not exceed 10,000 at any time. + +You will not use any trade mark, service mark, trade name, logo of ConsenSys or any other company or organization in a way that is likely or intended to cause confusion about the owner or authorized user of such marks, names or logos. + +If you have any questions, comments or interest in pursuing any other use cases, please reach out to us at metamask.license@consensys.net. + + +****************************** + +@metamask/snaps-execution-environments +6.2.0 +Copyright ConsenSys Software Inc. 2022. All rights reserved. + +You acknowledge and agree that ConsenSys Software Inc. (“ConsenSys”) (or ConsenSys’s licensors) own all legal right, title and interest in and to the work, software, application, source code, documentation and any other documents in this repository (collectively, the “Program”), including any intellectual property rights which subsist in the Program (whether those rights happen to be registered or not, and wherever in the world those rights may exist), whether in source code or any other form. + +Subject to the limited license below, you may not (and you may not permit anyone else to) distribute, publish, copy, modify, merge, combine with another program, create derivative works of, reverse engineer, decompile or otherwise attempt to extract the source code of, the Program or any part thereof, except that you may contribute to this repository. + +You are granted a non-exclusive, non-transferable, non-sublicensable license to distribute, publish, copy, modify, merge, combine with another program or create derivative works of the Program (such resulting program, collectively, the “Resulting Program”) solely for Non-Commercial Use as long as you: + +1. give prominent notice (“Notice”) with each copy of the Resulting Program that the Program is used in the Resulting Program and that the Program is the copyright of ConsenSys; and +2. subject the Resulting Program and any distribution, publication, copy, modification, merger therewith, combination with another program or derivative works thereof to the same Notice requirement and Non-Commercial Use restriction set forth herein. + +“Non-Commercial Use” means each use as described in clauses (1)-(3) below, as reasonably determined by ConsenSys in its sole discretion: + +1. personal use for research, personal study, private entertainment, hobby projects or amateur pursuits, in each case without any anticipated commercial application; +2. use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization or government institution; or +3. the number of monthly active users of the Resulting Program across all versions thereof and platforms globally do not exceed 10,000 at any time. + +You will not use any trade mark, service mark, trade name, logo of ConsenSys or any other company or organization in a way that is likely or intended to cause confusion about the owner or authorized user of such marks, names or logos. + +If you have any questions, comments or interest in pursuing any other use cases, please reach out to us at metamask.license@consensys.net. + + +****************************** + +@metamask/snaps-registry +3.1.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 Consensys Software Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@metamask/snaps-rpc-methods +9.1.0 +Copyright ConsenSys Software Inc. 2021. All rights reserved. + +You acknowledge and agree that ConsenSys Software Inc. (“ConsenSys”) (or ConsenSys’s licensors) own all legal right, title and interest in and to the work, software, application, source code, documentation and any other documents in this repository (collectively, the “Program”), including any intellectual property rights which subsist in the Program (whether those rights happen to be registered or not, and wherever in the world those rights may exist), whether in source code or any other form. + +Subject to the limited license below, you may not (and you may not permit anyone else to) distribute, publish, copy, modify, merge, combine with another program, create derivative works of, reverse engineer, decompile or otherwise attempt to extract the source code of, the Program or any part thereof, except that you may contribute to this repository. + +You are granted a non-exclusive, non-transferable, non-sublicensable license to distribute, publish, copy, modify, merge, combine with another program or create derivative works of the Program (such resulting program, collectively, the “Resulting Program”) solely for Non-Commercial Use as long as you: + 1. give prominent notice (“Notice”) with each copy of the Resulting Program that the Program is used in the Resulting Program and that the Program is the copyright of ConsenSys; and + 2. subject the Resulting Program and any distribution, publication, copy, modification, merger therewith, combination with another program or derivative works thereof to the same Notice requirement and Non-Commercial Use restriction set forth herein. + +“Non-Commercial Use” means each use as described in clauses (1)-(3) below, as reasonably determined by ConsenSys in its sole discretion: + 1. personal use for research, personal study, private entertainment, hobby projects or amateur pursuits, in each case without any anticipated commercial application; + 2. use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization or government institution; or + 3. the number of monthly active users of the Resulting Program across all versions thereof and platforms globally do not exceed 10,000 at any time. + +You will not use any trade mark, service mark, trade name, logo of ConsenSys or any other company or organization in a way that is likely or intended to cause confusion about the owner or authorized user of such marks, names or logos. + +If you have any questions, comments or interest in pursuing any other use cases, please reach out to us at metamask.license@consensys.net. + + +****************************** + +@metamask/snaps-sdk +4.3.0 +ISC License + +Copyright (c) 2023 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/snaps-utils +7.4.0 +ISC License + +Copyright (c) 2022 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/swappable-obj-proxy +2.2.0 +license: ISC +authors: undefined + +****************************** + +@metamask/transaction-controller +32.0.0 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/user-operation-controller +10.0.0 +MIT License + +Copyright (c) 2023 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/utils +5.0.2 +ISC License + +Copyright (c) 2022 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/utils +8.4.0 +ISC License + +Copyright (c) 2022 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +micro-ftch +0.3.1 <> +The MIT License (MIT) + +Copyright (c) 2020 Paul Miller (https://paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +micromark +2.11.4 +(The MIT License) + +Copyright (c) 2020 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +mime-db +1.52.0 +(The MIT License) + +Copyright (c) 2014 Jonathan Ong +Copyright (c) 2015-2022 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +mime-types +2.1.35 +(The MIT License) + +Copyright (c) 2014 Jonathan Ong +Copyright (c) 2015 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +mini-create-react-context +0.3.2 +Copyright (c) 2019-present StringEpsilon + +Copyright (c) 2017-2019 James Kyle + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +minimalistic-assert +1.0.1 +Copyright 2015 Calvin Metcalf + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +****************************** + +minimalistic-crypto-utils +1.0.1 +license: MIT +authors: Fedor Indutny + +****************************** + +minimatch +3.1.2 +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +minimatch +9.0.4 +The ISC License + +Copyright (c) 2011-2023 Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +minipass +7.1.2 +The ISC License + +Copyright (c) 2017-2023 npm, Inc., Isaac Z. Schlueter, and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +mkdirp +1.0.4 +Copyright James Halliday (mail@substack.net) and Isaac Z. Schlueter (i@izs.me) + +This project is free software released under the MIT license: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@mobily/ts-belt +3.13.1 +The MIT License (MIT) + +Copyright (c) Marcin Dziewulski + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +mock-socket +9.2.1 +The MIT License (MIT) + +Copyright (c) 2017 Travis Hoover + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +ms +2.1.2 +The MIT License (MIT) + +Copyright (c) 2016 Zeit, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +ms +2.1.3 +The MIT License (MIT) + +Copyright (c) 2020 Vercel, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +multibase +2.0.0 +MIT License + +Copyright (c) 2020 Protocol Labs Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +multibase +4.0.4 +MIT License + +Copyright (c) 2020 Protocol Labs Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +multicodec +3.2.1 +MIT License + +Copyright © 2016 Multiformats + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +multiformats +9.9.0 +Copyright 2020 Protocol Labs + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +****************************** + +@multiformats/base-x +4.0.1 +The MIT License (MIT) + +Copyright (c) 2018 base-x contributors +Copyright (c) 2014-2018 The Bitcoin Core developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +multihashes +2.0.0 +The MIT License (MIT) + +Copyright (c) 2020 Protocol Labs Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +multihashes +4.0.2 +The MIT License (MIT) + +Copyright (c) 2020 Protocol Labs Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +mz +2.7.0 + +The MIT License (MIT) + +Copyright (c) 2014-2016 Jonathan Ong me@jongleberry.com and Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +nan +2.15.0 +The MIT License (MIT) +===================== + +Copyright (c) 2018 NAN contributors +----------------------------------- + +*NAN contributors listed at * + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +nanoid +2.1.11 +The MIT License (MIT) + +Copyright 2017 Andrey Sitnik + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +nanoid +3.3.7 +The MIT License (MIT) + +Copyright 2017 Andrey Sitnik + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@ngraveio/bc-ur +1.1.12 +MIT License + +Copyright (c) 2021 NGRAVE + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@noble/ciphers +0.5.2 +The MIT License (MIT) + +Copyright (c) 2022 Paul Miller (https://paulmillr.com) +Copyright (c) 2016 Thomas Pornin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +@noble/curves +1.3.0 +The MIT License (MIT) + +Copyright (c) 2022 Paul Miller (https://paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +@noble/curves +1.4.0 +The MIT License (MIT) + +Copyright (c) 2022 Paul Miller (https://paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +@noble/hashes +1.1.2 +The MIT License (MIT) + +Copyright (c) 2022 Paul Miller (https://paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +@noble/hashes +1.1.3 +The MIT License (MIT) + +Copyright (c) 2022 Paul Miller (https://paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +@noble/hashes +1.3.3 +The MIT License (MIT) + +Copyright (c) 2022 Paul Miller (https://paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +@noble/hashes +1.4.0 +The MIT License (MIT) + +Copyright (c) 2022 Paul Miller (https://paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +@noble/secp256k1 +1.6.3 +The MIT License (MIT) + +Copyright (c) 2019 Paul Miller (https://paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +@noble/secp256k1 +1.7.1 +The MIT License (MIT) + +Copyright (c) 2019 Paul Miller (https://paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +node-addon-api +2.0.2 +The MIT License (MIT) +===================== + +Copyright (c) 2017 Node.js API collaborators +----------------------------------- + +*Node.js API collaborators listed at * + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +****************************** + +node-addon-api +3.2.1 +The MIT License (MIT) +===================== + +Copyright (c) 2017 Node.js API collaborators +----------------------------------- + +*Node.js API collaborators listed at * + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +****************************** + +node-addon-api +7.1.0 +The MIT License (MIT) + +Copyright (c) 2017 [Node.js API collaborators](https://github.com/nodejs/node-addon-api#collaborators) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +node-fetch +2.7.0 +The MIT License (MIT) + +Copyright (c) 2016 David Frank + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +node-gyp-build +4.8.0 +The MIT License (MIT) + +Copyright (c) 2017 Mathias Buus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +node-releases +2.0.14 +The MIT License + +Copyright (c) 2017 Sergey Rubanov (https://github.com/chicoxyzzy) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +number-to-bn +1.7.0 +The MIT License + +Copyright (c) 2016 Nick Dodson. nickdodson.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +object-assign +4.1.1 +The MIT License (MIT) + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +object.assign +4.1.4 +The MIT License (MIT) + +Copyright (c) 2014 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +****************************** + +object-inspect +1.12.3 +MIT License + +Copyright (c) 2013 James Halliday + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +object-is +1.1.5 +The MIT License (MIT) + +Copyright (c) 2014 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +object-keys +1.1.1 +The MIT License (MIT) + +Copyright (C) 2013 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +obj-multiplex +1.0.0 <> +license: ISC +authors: undefined + +****************************** + +once +1.4.0 +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +otpauth +8.0.3 +The MIT License (MIT) +===================== + +Copyright © 2022 Héctor Molinero Fernández + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +pako +1.0.6 +(The MIT License) + +Copyright (C) 2014-2017 by Vitaly Puzrin and Andrei Tuputcyn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +parse-entities +2.0.0 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +path-exists +4.0.0 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +path-key +3.1.1 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +path-parse +1.0.7 +The MIT License (MIT) + +Copyright (c) 2015 Javier Blanco + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +path-scurry +1.11.1 +# Blue Oak Model License + +Version 1.0.0 + +## Purpose + +This license gives everyone as much permission to work with +this software as possible, while protecting contributors +from liability. + +## Acceptance + +In order to receive this license, you must agree to its +rules. The rules of this license are both obligations +under that agreement and conditions to your license. +You must not do anything with this software that triggers +a rule that you cannot or will not follow. + +## Copyright + +Each contributor licenses you to do everything with this +software that would otherwise infringe that contributor's +copyright in it. + +## Notices + +You must ensure that everyone who gets a copy of +any part of this software from you, with or without +changes, also gets the text of this license or a link to +. + +## Excuse + +If anyone notifies you in writing that you have not +complied with [Notices](#notices), you can keep your +license by taking all practical steps to comply within 30 +days after the notice. If you do not do so, your license +ends immediately. + +## Patent + +Each contributor licenses you to do everything with this +software that would otherwise infringe any patent claims +they can license or become able to license. + +## Reliability + +No contributor can revoke this license. + +## No Liability + +***As far as the law allows, this software comes as is, +without any warranty or condition, and no contributor +will be liable to anyone for any damages related to this +software or this license, under any kind of legal claim.*** + + +****************************** + +path-to-regexp +1.7.0 +The MIT License (MIT) + +Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +pbkdf2 +3.1.2 +The MIT License (MIT) + +Copyright (c) 2014 Daniel Cousens + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +performance-now +0.2.0 +Copyright (c) 2013 Meryn Stol + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +****************************** + +performance-now +2.1.0 +Copyright (c) 2013 Braveg1rl + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +****************************** + +picocolors +1.0.0 +ISC License + +Copyright (c) 2021 Alexey Raspopov, Kostiantyn Denysov, Anton Verinov + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +pify +5.0.0 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +pirates +4.0.6 +MIT License + +Copyright (c) 2016-2018 Ari Porad + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@pkgjs/parseargs +0.11.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +p-limit +3.1.0 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +plist +3.1.0 +(The MIT License) + +Copyright (c) 2010-2017 Nathan Rajlich + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +p-locate +5.0.0 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +pony-cause +2.1.10 +BSD Zero Clause License (0BSD) + +Copyright (c) 2020 Pelle Wessman + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +popper.js +1.15.0 +license: MIT +authors: Federico Zivolo + +****************************** + +popper.js +1.16.1-lts +license: MIT +authors: Federico Zivolo + +****************************** + +@popperjs/core +2.9.2 +The MIT License (MIT) + +Copyright (c) 2019 Federico Zivolo + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +printj +1.1.2 +Copyright (C) 2016-present SheetJS + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + +****************************** + +process +0.11.10 +(The MIT License) + +Copyright (c) 2013 Roman Shtylman + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +process-nextick-args +2.0.1 +# Copyright (c) 2015 Calvin Metcalf + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +**THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.** + + +****************************** + +promise-polyfill +8.3.0 +Copyright (c) 2014 Taylor Hakes +Copyright (c) 2014 Forbes Lindesay + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +promise-to-callback +1.0.0 +The MIT License (MIT) + +Copyright (c) Steve Mao (github.com/stevemao) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +property-information +5.6.0 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +prop-types +15.8.1 +MIT License + +Copyright (c) 2013-present, Facebook, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +protobufjs +7.2.6 +This license applies to all parts of protobuf.js except those files +either explicitly including or referencing a different license or +located in a directory containing a different LICENSE file. + +--- + +Copyright (c) 2016, Daniel Wirtz All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of its author, nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +--- + +Code generated by the command line utilities is owned by the owner +of the input file used when generating it. This code is not +standalone and requires a support library to be linked with it. This +support library is itself covered by the above license. + + +****************************** + +@protobufjs/aspromise +1.1.2 +Copyright (c) 2016, Daniel Wirtz All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of its author, nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +@protobufjs/base64 +1.1.2 +Copyright (c) 2016, Daniel Wirtz All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of its author, nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +@protobufjs/codegen +2.0.4 +Copyright (c) 2016, Daniel Wirtz All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of its author, nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +@protobufjs/eventemitter +1.1.0 +Copyright (c) 2016, Daniel Wirtz All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of its author, nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +@protobufjs/fetch +1.1.0 +Copyright (c) 2016, Daniel Wirtz All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of its author, nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +@protobufjs/float +1.0.2 +Copyright (c) 2016, Daniel Wirtz All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of its author, nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +@protobufjs/inquire +1.1.0 +Copyright (c) 2016, Daniel Wirtz All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of its author, nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +@protobufjs/path +1.1.2 +Copyright (c) 2016, Daniel Wirtz All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of its author, nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +@protobufjs/pool +1.1.0 +Copyright (c) 2016, Daniel Wirtz All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of its author, nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +@protobufjs/utf8 +1.1.0 +Copyright (c) 2016, Daniel Wirtz All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of its author, nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +proxy-from-env +1.1.0 +The MIT License + +Copyright (C) 2016-2018 Rob Wu + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +p-throttle +4.1.1 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +punycode +2.1.0 +Copyright Mathias Bynens + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +punycode +2.3.1 +Copyright Mathias Bynens + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +pushdata-bitcoin +1.0.1 +The MIT License (MIT) + +Copyright (c) 2016 Daniel Cousens + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +qrcode-generator +1.4.1 +license: MIT +authors: Kazuhiko Arase + +****************************** + +qrcode.react +1.0.1 +ISC License + +Copyright (c) 2015, Paul O’Shannessy + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +qr.js +0.0.0 +Copyright (c) 2013 Roman Shtylman + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +qs +6.11.2 +BSD 3-Clause License + +Copyright (c) 2014, Nathan LaFreniere and other [contributors](https://github.com/ljharb/qs/graphs/contributors) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +queue-tick +1.0.1 +The MIT License (MIT) + +Copyright (c) 2021 Mathias Buus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +raf +3.4.0 +license: MIT +authors: Chris Dickinson + +****************************** + +raf-schd +4.0.3 +MIT License + +Copyright (c) 2021 Alex Reardon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +randombytes +2.1.0 +MIT License + +Copyright (c) 2017 crypto-browserify + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +react +16.14.0 +MIT License + +Copyright (c) Facebook, Inc. and its affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +react-beautiful-dnd +13.1.1 +Copyright 2019 Atlassian Pty Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +****************************** + +react-clientside-effect +1.2.6 +The MIT License (MIT) + +Copyright (c) 2015 Dan Abramov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +react-dom +16.12.0 +MIT License + +Copyright (c) Facebook, Inc. and its affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +react-easy-swipe +0.0.21 +license: MIT +authors: Leandro Augusto Lemos + +****************************** + +react-fast-compare +3.2.0 +MIT License + +Copyright (c) 2018 Formidable Labs +Copyright (c) 2017 Evgeny Poberezkin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +react-focus-lock +2.9.4 +MIT License + +Copyright (c) 2017 Anton + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +react-idle-timer +4.2.5 +MIT License + +Copyright (c) 2017 Randy Lebeau + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +react-inspector +6.0.2 +The MIT License (MIT) + +Copyright (c) 2017 Xiaoyi Chen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +react-is +16.13.1 +MIT License + +Copyright (c) Facebook, Inc. and its affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +react-is +17.0.2 +MIT License + +Copyright (c) Facebook, Inc. and its affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +react-markdown +6.0.3 +The MIT License (MIT) + +Copyright (c) 2015 Espen Hovlandsdal + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +react-motion +0.5.2 +The MIT License (MIT) + +Copyright (c) 2015 React Motion authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +@react-native/normalize-color +2.1.0 +license: MIT +authors: undefined + +****************************** + +react-popper +2.2.4 +The MIT License (MIT) + +Copyright (c) 2018 React Popper authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +react-redux +7.2.0 +The MIT License (MIT) + +Copyright (c) 2015-present Dan Abramov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +react-responsive-carousel +3.2.21 +MIT License + +Copyright (c) [year] [fullname] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +react-router +5.1.2 +MIT License + +Copyright (c) React Training 2016-2018 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +react-router-dom +5.1.2 +MIT License + +Copyright (c) React Training 2016-2018 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +react-simple-file-input +2.0.1 +license: MIT +authors: Aleck Greenham + +****************************** + +react-tippy +1.2.2 +license: MIT +authors: Khoa Thai + +****************************** + +react-toggle-button +2.2.0 +The MIT License (MIT) + +Copyright (c) 2016 Gavin Owens + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +react-transition-group +1.2.1 +license: BSD-3-Clause +authors: undefined + +****************************** + +react-transition-group +4.4.2 +BSD 3-Clause License + +Copyright (c) 2018, React Community +Forked from React (https://github.com/facebook/react) Copyright 2013-present, Facebook, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +readable-stream +2.3.7 +Node.js is licensed for use as follows: + +""" +Copyright Node.js contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: + +""" +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + + +****************************** + +readable-stream +3.6.2 +Node.js is licensed for use as follows: + +""" +Copyright Node.js contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: + +""" +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + + +****************************** + +readable-stream +4.4.2 +Node.js is licensed for use as follows: + +""" +Copyright Node.js contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: + +""" +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + + +****************************** + +readable-web-to-node-stream +3.0.2 +license: MIT +authors: Borewit + +****************************** + +redux +4.2.1 +The MIT License (MIT) + +Copyright (c) 2015-present Dan Abramov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@reduxjs/toolkit +1.9.7 +MIT License + +Copyright (c) 2018 Mark Erikson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +redux-thunk +2.4.2 +The MIT License (MIT) + +Copyright (c) 2015-present Dan Abramov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +regenerator-runtime +0.14.0 +MIT License + +Copyright (c) 2014-present, Facebook, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +regexp.prototype.flags +1.5.1 +The MIT License (MIT) + +Copyright (C) 2014 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + + +****************************** + +remark-parse +9.0.0 +license: MIT +authors: Titus Wormer (https://wooorm.com) + +****************************** + +remark-rehype +8.1.0 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +remove-trailing-slash +0.1.1 +license: MIT +authors: Stephen Mathieson + +****************************** + +replace-ext +1.0.0 +The MIT License (MIT) + +Copyright (c) 2014 Blaine Bublitz , Eric Schoffstall and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +require-directory +2.1.1 +The MIT License (MIT) + +Copyright (c) 2011 Troy Goode + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +require-from-string +2.0.2 +The MIT License (MIT) + +Copyright (c) Vsevolod Strukchinsky (github.com/floatdrop) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +reselect +3.0.1 +The MIT License (MIT) + +Copyright (c) 2015-2016 Reselect Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +reselect +4.1.8 +The MIT License (MIT) + +Copyright (c) 2015-2018 Reselect Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +resolve +1.22.8 +MIT License + +Copyright (c) 2012 James Halliday + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +resolve-from +5.0.0 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +resolve-pathname +3.0.0 +MIT License + +Copyright (c) Michael Jackson 2016-2018 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +resolve-pkg-maps +1.0.0 +MIT License + +Copyright (c) Hiroki Osame + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +rfdc +1.3.0 +Copyright 2019 "David Mark Clements " + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + + +****************************** + +ripemd160 +2.0.2 +The MIT License (MIT) + +Copyright (c) 2016 crypto-browserify + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +ripple-address-codec +4.2.3 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 Ripple Labs Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +ripple-binary-codec +1.3.0 +Copyright (c) 2015 Ripple Labs Inc. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +ripple-keypairs +1.1.3 +ISC License + +Copyright (c) 2012-2015 Ripple Labs Inc. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +ripple-lib +1.10.1 +ISC License + +Copyright (c) 2012-2021 Contributers to xrpl.js + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +ripple-lib-transactionparser +0.8.2 +license: ISC +authors: undefined + +****************************** + +rlp +2.2.7 +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + +****************************** + +rlp +3.0.0 +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + +****************************** + +rpc-websockets +7.11.1 +Copyright (c) Elpheria j.d.o.o. + +rpc-websockets is an Open Source project licensed under the terms of +the LGPLv3 license. Please see +for license text. + +rpc-websockets Pro has a commercial-friendly license allowing private forks +and modifications of rpc-websockets. +Please see https://www.elpheria.com/products/rpc-websockets-pro.html +or email us at info@elpheria.com for more detail. + + +****************************** + +safe-buffer +5.1.2 +The MIT License (MIT) + +Copyright (c) Feross Aboukhadijeh + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +safe-buffer +5.2.1 +The MIT License (MIT) + +Copyright (c) Feross Aboukhadijeh + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +safer-buffer +2.1.2 +MIT License + +Copyright (c) 2018 Nikita Skovoroda + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +safe-stable-stringify +2.4.3 +The MIT License (MIT) + +Copyright (c) Ruben Bridgewater + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +sax +1.3.0 +The ISC License + +Copyright (c) 2010-2022 Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +==== + +`String.fromCodePoint` by Mathias Bynens used according to terms of MIT +License, as follows: + +Copyright (c) 2010-2022 Mathias Bynens + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +scheduler +0.18.0 +MIT License + +Copyright (c) Facebook, Inc. and its affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +scrypt-js +3.0.1 +The MIT License (MIT) + +Copyright (c) 2016 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + + +****************************** + +@scure/base +1.1.6 +The MIT License (MIT) + +Copyright (c) 2022 Paul Miller (https://paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@scure/bip32 +1.1.0 +The MIT License (MIT) + +Copyright (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@scure/bip32 +1.3.3 +The MIT License (MIT) + +Copyright (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@scure/bip39 +1.1.0 +The MIT License (MIT) + +Copyright (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@scure/bip39 +1.2.2 +The MIT License (MIT) + +Copyright (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +secp256k1 +4.0.2 +The MIT License (MIT) + +Copyright (c) 2014-2016 secp256k1-node contributors + +Parts of this software are based on bn.js, elliptic, hash.js +Copyright (c) 2014-2016 Fedor Indutny + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +secp256k1 +4.0.3 +The MIT License (MIT) + +Copyright (c) 2014-2016 secp256k1-node contributors + +Parts of this software are based on bn.js, elliptic, hash.js +Copyright (c) 2014-2016 Fedor Indutny + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@segment/loosely-validate-event +2.0.0 <> +The MIT License + +Copyright (c) 2017 Segment.io friends@segment.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +semver +6.3.1 +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +semver +7.5.3 +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +semver +7.6.2 +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@sentry/browser +7.53.0 +Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@sentry/core +7.53.0 +Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@sentry/integrations +7.53.0 +Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@sentry-internal/tracing +7.53.0 +Copyright (c) 2020 Sentry (https://sentry.io) and individual contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@sentry/replay +7.53.0 +Copyright (c) 2022 Sentry (https://sentry.io) and individual contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@sentry/types +7.53.0 +Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@sentry/utils +7.53.0 +Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +ses +1.1.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +set-function-length +1.2.1 +MIT License + +Copyright (c) Jordan Harband and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +set-function-name +2.0.1 +MIT License + +Copyright (c) Jordan Harband and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +setimmediate +1.0.5 +Copyright (c) 2012 Barnesandnoble.com, llc, Donavon West, and Domenic Denicola + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +set-immediate-shim +1.0.1 +license: MIT +authors: Sindre Sorhus + +****************************** + +sha.js +2.4.11 +Copyright (c) 2013-2018 sha.js contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +Copyright (c) 1998 - 2009, Paul Johnston & Contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of the author nor the names of its contributors may be used to +endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +****************************** + +shebang-command +2.0.0 +MIT License + +Copyright (c) Kevin Mårtensson (github.com/kevva) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +shebang-regex +3.0.0 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +side-channel +1.0.4 +MIT License + +Copyright (c) 2019 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +signal-exit +3.0.7 +The ISC License + +Copyright (c) 2015, Contributors + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice +appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE +LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +signal-exit +4.0.2 +The ISC License + +Copyright (c) 2015-2023 Benjamin Coe, Isaac Z. Schlueter, and Contributors + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice +appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE +LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +simple-git +3.20.0 +license: MIT +authors: Steve King + +****************************** + +simple-plist +1.4.0 +The MIT License (MIT) + +Copyright (c) 2013 Joe Wollard + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@sinclair/typebox +0.31.28 +TypeBox: JSON Schema Type Builder with Static Type Resolution for TypeScript + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +single-call-balance-checker-abi +1.0.0 <> +license: MIT +authors: Will O'Beirne + +****************************** + +slash +3.0.0 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +slugify +1.6.6 +The MIT License (MIT) + +Copyright (c) Simeon Velichkov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +smart-buffer +4.2.0 +The MIT License (MIT) + +Copyright (c) 2013-2017 Josh Glazebrook + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +socks +2.8.1 +The MIT License (MIT) + +Copyright (c) 2013 Josh Glazebrook + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +socks-proxy-agent +6.1.1 +license: MIT +authors: Nathan Rajlich (http://n8.io/) + +****************************** + +@solana/buffer-layout +4.0.1 +The MIT License (MIT) + +Copyright (c) 2015-2018 Peter A. Bigot + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@solana/web3.js +1.91.8 +Copyright (c) 2023 Solana Labs, Inc + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +space-separated-tokens +1.1.5 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +sprintf-js +1.1.3 +Copyright (c) 2007-present, Alexandru Mărășteanu +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of this software nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +@spruceid/siwe-parser +2.1.0 +license: Apache-2.0 +authors: Spruce Systems Inc. + +****************************** + +stop-iteration-iterator +1.0.0 +MIT License + +Copyright (c) 2023 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +stream-browserify +3.0.0 +MIT License + +Copyright (c) James Halliday + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +stream-buffers +2.2.0 +license: Unlicense +authors: Sam Day + +****************************** + +stream-splicer +2.0.0 +This software is released under the MIT license: + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +streamx +2.15.1 +The MIT License (MIT) + +Copyright (c) 2019 Mathias Buus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +string_decoder +1.1.1 +Node.js is licensed for use as follows: + +""" +Copyright Node.js contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: + +""" +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + + + +****************************** + +string_decoder +1.3.0 +Node.js is licensed for use as follows: + +""" +Copyright Node.js contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: + +""" +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + + + +****************************** + +string-width +4.2.3 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +string-width +5.1.2 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +strip-ansi +6.0.1 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +strip-ansi +7.1.0 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +strip-hex-prefix +1.0.0 +The MIT License + +Copyright (c) 2016 Nick Dodson. nickdodson.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +strnum +1.0.5 +MIT License + +Copyright (c) 2021 Natural Intelligence + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +style-to-object +0.3.0 +The MIT License (MIT) + +Copyright (c) 2017 Menglin "Mark" Xu + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +sucrase +3.35.0 +The MIT License (MIT) + +Copyright (c) 2012-2018 various contributors (see AUTHORS) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +superstruct +0.14.2 +The MIT License + +Copyright © 2017, [Ian Storm Taylor](https://ianstormtaylor.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +superstruct +1.0.3 +The MIT License + +Copyright © 2017, [Ian Storm Taylor](https://ianstormtaylor.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +supports-color +5.5.0 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +supports-color +7.1.0 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +supports-preserve-symlinks-flag +1.0.0 +MIT License + +Copyright (c) 2022 Inspect JS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +tar-stream +3.1.7 +The MIT License (MIT) + +Copyright (c) 2014 Mathias Buus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +text-encoding-utf-8 +1.0.2 +The encoding indexes, algorithms, and many comments in the code +derive from the Encoding Standard https://encoding.spec.whatwg.org/ + +Otherwise... + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + + +****************************** + +thenify +3.3.1 + +The MIT License (MIT) + +Copyright (c) 2014-2016 Jonathan Ong me@jongleberry.com and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +thenify-all +1.6.0 + +The MIT License (MIT) + +Copyright (c) 2014 Jonathan Ong me@jongleberry.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +through +2.3.8 +Apache License, Version 2.0 + +Copyright (c) 2011 Dominic Tarr + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +****************************** + +through2 +2.0.5 +# The MIT License (MIT) + +**Copyright (c) Rod Vagg (the "Original Author") and additional contributors** + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +tiny-invariant +1.3.3 +MIT License + +Copyright (c) 2019 Alexander Reardon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +****************************** + +tiny-secp256k1 +1.1.6 +MIT License + +Copyright (c) 2018 bitcoinjs contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +tiny-warning +1.0.3 +MIT License + +Copyright (c) 2019 Alexander Reardon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +****************************** + +to-data-view +1.1.0 +license: MIT +authors: undefined + +****************************** + +to-fast-properties +2.0.0 +MIT License + +Copyright (c) 2014 Petka Antonov + 2015 Sindre Sorhus + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +toggle-selection +1.0.6 +license: MIT +authors: sudodoki (sudodoki.name) + +****************************** + +tr46 +0.0.3 +license: MIT +authors: Sebastian Mayr + +****************************** + +@trezor/analytics +1.0.16 <> +license: Custom: https://data.trezor.io +authors: undefined + +****************************** + +@trezor/blockchain-link +2.1.28 +# TREZOR REFERENCE SOURCE LICENSE (T-RSL) + +This license governs use of the accompanying software. If you use the software, +you accept this license. If you do not accept the license, do not use the +software. + +## 1. Definitions + +The terms "reproduce," "reproduction" and "distribution" have the same meaning +here as under U.S. copyright law. + +"You" means the licensee of the software. + +"Your company" means the company you worked for when you downloaded the +software. + +"Reference use" means use of the software within your company as a reference, +in read only form, for the sole purposes of debugging your products, +maintaining your products, or enhancing the interoperability of your products +with the software, and specifically excludes the right to distribute the +software outside of your company. + +"Licensed patents" means any Licensor patent claims which read directly on the +software as distributed by the Licensor under this license. + +## 2. Grant of Rights + +(A) Copyright Grant - Subject to the terms of this license, the Licensor grants +you a non-transferable, non-exclusive, worldwide, royalty-free copyright +license to reproduce the software for reference use. + +(B) Patent Grant - Subject to the terms of this license, the Licensor grants +you a non-transferable, non-exclusive, worldwide, royalty-free patent license +under licensed patents for reference use. + +## 3. Limitations + +(A) No Trademark License - This license does not grant you any rights to use +the Licensor's name, logo, or trademarks. + +(B) If you begin patent litigation against the Licensor over patents that you +think may apply to the software (including a cross-claim or counterclaim in +a lawsuit), your license to the software ends automatically. + +(C) The software is licensed "as-is." You bear the risk of using it. The +Licensor gives no express warranties, guarantees or conditions. You may have +additional consumer rights under your local laws which this license cannot +change. To the extent permitted under your local laws, the Licensor excludes +the implied warranties of merchantability, fitness for a particular purpose and +non-infringement. + + +****************************** + +@trezor/blockchain-link-types +1.0.15 <> +license: UNKNOWN +authors: undefined + +****************************** + +@trezor/blockchain-link-utils +1.0.16 <> +license: UNKNOWN +authors: undefined + +****************************** + +@trezor/connect +9.2.2 +# TREZOR REFERENCE SOURCE LICENSE (T-RSL) + +This license governs use of the accompanying software. If you use the software, +you accept this license. If you do not accept the license, do not use the +software. + +## 1. Definitions + +The terms "reproduce," "reproduction" and "distribution" have the same meaning +here as under U.S. copyright law. + +"You" means the licensee of the software. + +"Your company" means the company you worked for when you downloaded the +software. + +"Reference use" means use of the software within your company as a reference, +in read only form, for the sole purposes of debugging your products, +maintaining your products, or enhancing the interoperability of your products +with the software, and specifically excludes the right to distribute the +software outside of your company. + +"Licensed patents" means any Licensor patent claims which read directly on the +software as distributed by the Licensor under this license. + +## 2. Grant of Rights + +(A) Copyright Grant - Subject to the terms of this license, the Licensor grants +you a non-transferable, non-exclusive, worldwide, royalty-free copyright +license to reproduce the software for reference use. + +(B) Patent Grant - Subject to the terms of this license, the Licensor grants +you a non-transferable, non-exclusive, worldwide, royalty-free patent license +under licensed patents for reference use. + +## 3. Limitations + +(A) No Trademark License - This license does not grant you any rights to use +the Licensor's name, logo, or trademarks. + +(B) If you begin patent litigation against the Licensor over patents that you +think may apply to the software (including a cross-claim or counterclaim in +a lawsuit), your license to the software ends automatically. + +(C) The software is licensed "as-is." You bear the risk of using it. The +Licensor gives no express warranties, guarantees or conditions. You may have +additional consumer rights under your local laws which this license cannot +change. To the extent permitted under your local laws, the Licensor excludes +the implied warranties of merchantability, fitness for a particular purpose and +non-infringement. + + +****************************** + +@trezor/connect-analytics +1.0.14 <> +license: UNKNOWN +authors: undefined + +****************************** + +@trezor/connect-common +0.0.31 +# TREZOR REFERENCE SOURCE LICENSE (T-RSL) + +This license governs use of the accompanying software. If you use the software, +you accept this license. If you do not accept the license, do not use the +software. + +## 1. Definitions + +The terms "reproduce," "reproduction" and "distribution" have the same meaning +here as under U.S. copyright law. + +"You" means the licensee of the software. + +"Your company" means the company you worked for when you downloaded the +software. + +"Reference use" means use of the software within your company as a reference, +in read only form, for the sole purposes of debugging your products, +maintaining your products, or enhancing the interoperability of your products +with the software, and specifically excludes the right to distribute the +software outside of your company. + +"Licensed patents" means any Licensor patent claims which read directly on the +software as distributed by the Licensor under this license. + +## 2. Grant of Rights + +(A) Copyright Grant - Subject to the terms of this license, the Licensor grants +you a non-transferable, non-exclusive, worldwide, royalty-free copyright +license to reproduce the software for reference use. + +(B) Patent Grant - Subject to the terms of this license, the Licensor grants +you a non-transferable, non-exclusive, worldwide, royalty-free patent license +under licensed patents for reference use. + +## 3. Limitations + +(A) No Trademark License - This license does not grant you any rights to use +the Licensor's name, logo, or trademarks. + +(B) If you begin patent litigation against the Licensor over patents that you +think may apply to the software (including a cross-claim or counterclaim in +a lawsuit), your license to the software ends automatically. + +(C) The software is licensed "as-is." You bear the risk of using it. The +Licensor gives no express warranties, guarantees or conditions. You may have +additional consumer rights under your local laws which this license cannot +change. To the extent permitted under your local laws, the Licensor excludes +the implied warranties of merchantability, fitness for a particular purpose and +non-infringement. + + +****************************** + +@trezor/connect-plugin-ethereum +9.0.3 +# TREZOR REFERENCE SOURCE LICENSE (T-RSL) + +This license governs use of the accompanying software. If you use the software, +you accept this license. If you do not accept the license, do not use the +software. + +## 1. Definitions + +The terms "reproduce," "reproduction" and "distribution" have the same meaning +here as under U.S. copyright law. + +"You" means the licensee of the software. + +"Your company" means the company you worked for when you downloaded the +software. + +"Reference use" means use of the software within your company as a reference, +in read only form, for the sole purposes of debugging your products, +maintaining your products, or enhancing the interoperability of your products +with the software, and specifically excludes the right to distribute the +software outside of your company. + +"Licensed patents" means any Licensor patent claims which read directly on the +software as distributed by the Licensor under this license. + +## 2. Grant of Rights + +(A) Copyright Grant - Subject to the terms of this license, the Licensor grants +you a non-transferable, non-exclusive, worldwide, royalty-free copyright +license to reproduce the software for reference use. + +(B) Patent Grant - Subject to the terms of this license, the Licensor grants +you a non-transferable, non-exclusive, worldwide, royalty-free patent license +under licensed patents for reference use. + +## 3. Limitations + +(A) No Trademark License - This license does not grant you any rights to use +the Licensor's name, logo, or trademarks. + +(B) If you begin patent litigation against the Licensor over patents that you +think may apply to the software (including a cross-claim or counterclaim in +a lawsuit), your license to the software ends automatically. + +(C) The software is licensed "as-is." You bear the risk of using it. The +Licensor gives no express warranties, guarantees or conditions. You may have +additional consumer rights under your local laws which this license cannot +change. To the extent permitted under your local laws, the Licensor excludes +the implied warranties of merchantability, fitness for a particular purpose and +non-infringement. + + +****************************** + +@trezor/connect-web +9.2.2 +# TREZOR REFERENCE SOURCE LICENSE (T-RSL) + +This license governs use of the accompanying software. If you use the software, +you accept this license. If you do not accept the license, do not use the +software. + +## 1. Definitions + +The terms "reproduce," "reproduction" and "distribution" have the same meaning +here as under U.S. copyright law. + +"You" means the licensee of the software. + +"Your company" means the company you worked for when you downloaded the +software. + +"Reference use" means use of the software within your company as a reference, +in read only form, for the sole purposes of debugging your products, +maintaining your products, or enhancing the interoperability of your products +with the software, and specifically excludes the right to distribute the +software outside of your company. + +"Licensed patents" means any Licensor patent claims which read directly on the +software as distributed by the Licensor under this license. + +## 2. Grant of Rights + +(A) Copyright Grant - Subject to the terms of this license, the Licensor grants +you a non-transferable, non-exclusive, worldwide, royalty-free copyright +license to reproduce the software for reference use. + +(B) Patent Grant - Subject to the terms of this license, the Licensor grants +you a non-transferable, non-exclusive, worldwide, royalty-free patent license +under licensed patents for reference use. + +## 3. Limitations + +(A) No Trademark License - This license does not grant you any rights to use +the Licensor's name, logo, or trademarks. + +(B) If you begin patent litigation against the Licensor over patents that you +think may apply to the software (including a cross-claim or counterclaim in +a lawsuit), your license to the software ends automatically. + +(C) The software is licensed "as-is." You bear the risk of using it. The +Licensor gives no express warranties, guarantees or conditions. You may have +additional consumer rights under your local laws which this license cannot +change. To the extent permitted under your local laws, the Licensor excludes +the implied warranties of merchantability, fitness for a particular purpose and +non-infringement. + + +****************************** + +@trezor/env-utils +1.0.15 +license: UNKNOWN +authors: undefined + +****************************** + +@trezor/protobuf +1.0.11 +license: UNKNOWN +authors: undefined + +****************************** + +@trezor/protocol +1.0.7 +license: UNKNOWN +authors: undefined + +****************************** + +@trezor/schema-utils +1.0.3 <> +license: Custom: https://github.com/sinclairzx81/typebox +authors: undefined + +****************************** + +@trezor/transport +1.1.27 +# TREZOR REFERENCE SOURCE LICENSE (T-RSL) + +This license governs use of the accompanying software. If you use the software, +you accept this license. If you do not accept the license, do not use the +software. + +## 1. Definitions + +The terms "reproduce," "reproduction" and "distribution" have the same meaning +here as under U.S. copyright law. + +"You" means the licensee of the software. + +"Your company" means the company you worked for when you downloaded the +software. + +"Reference use" means use of the software within your company as a reference, +in read only form, for the sole purposes of debugging your products, +maintaining your products, or enhancing the interoperability of your products +with the software, and specifically excludes the right to distribute the +software outside of your company. + +"Licensed patents" means any Licensor patent claims which read directly on the +software as distributed by the Licensor under this license. + +## 2. Grant of Rights + +(A) Copyright Grant - Subject to the terms of this license, the Licensor grants +you a non-transferable, non-exclusive, worldwide, royalty-free copyright +license to reproduce the software for reference use. + +(B) Patent Grant - Subject to the terms of this license, the Licensor grants +you a non-transferable, non-exclusive, worldwide, royalty-free patent license +under licensed patents for reference use. + +## 3. Limitations + +(A) No Trademark License - This license does not grant you any rights to use +the Licensor's name, logo, or trademarks. + +(B) If you begin patent litigation against the Licensor over patents that you +think may apply to the software (including a cross-claim or counterclaim in +a lawsuit), your license to the software ends automatically. + +(C) The software is licensed "as-is." You bear the risk of using it. The +Licensor gives no express warranties, guarantees or conditions. You may have +additional consumer rights under your local laws which this license cannot +change. To the extent permitted under your local laws, the Licensor excludes +the implied warranties of merchantability, fitness for a particular purpose and +non-infringement. + + +****************************** + +@trezor/type-utils +1.0.5 <> +license: UNKNOWN +authors: undefined + +****************************** + +@trezor/utils +9.0.23 +# TREZOR REFERENCE SOURCE LICENSE (T-RSL) + +This license governs use of the accompanying software. If you use the software, +you accept this license. If you do not accept the license, do not use the +software. + +## 1. Definitions + +The terms "reproduce," "reproduction" and "distribution" have the same meaning +here as under U.S. copyright law. + +"You" means the licensee of the software. + +"Your company" means the company you worked for when you downloaded the +software. + +"Reference use" means use of the software within your company as a reference, +in read only form, for the sole purposes of debugging your products, +maintaining your products, or enhancing the interoperability of your products +with the software, and specifically excludes the right to distribute the +software outside of your company. + +"Licensed patents" means any Licensor patent claims which read directly on the +software as distributed by the Licensor under this license. + +## 2. Grant of Rights + +(A) Copyright Grant - Subject to the terms of this license, the Licensor grants +you a non-transferable, non-exclusive, worldwide, royalty-free copyright +license to reproduce the software for reference use. + +(B) Patent Grant - Subject to the terms of this license, the Licensor grants +you a non-transferable, non-exclusive, worldwide, royalty-free patent license +under licensed patents for reference use. + +## 3. Limitations + +(A) No Trademark License - This license does not grant you any rights to use +the Licensor's name, logo, or trademarks. + +(B) If you begin patent litigation against the Licensor over patents that you +think may apply to the software (including a cross-claim or counterclaim in +a lawsuit), your license to the software ends automatically. + +(C) The software is licensed "as-is." You bear the risk of using it. The +Licensor gives no express warranties, guarantees or conditions. You may have +additional consumer rights under your local laws which this license cannot +change. To the extent permitted under your local laws, the Licensor excludes +the implied warranties of merchantability, fitness for a particular purpose and +non-infringement. + + +****************************** + +@trezor/utxo-lib +2.0.8 +# TREZOR REFERENCE SOURCE LICENSE (T-RSL) + +This license governs use of the accompanying software. If you use the software, +you accept this license. If you do not accept the license, do not use the +software. + +## 1. Definitions + +The terms "reproduce," "reproduction" and "distribution" have the same meaning +here as under U.S. copyright law. + +"You" means the licensee of the software. + +"Your company" means the company you worked for when you downloaded the +software. + +"Reference use" means use of the software within your company as a reference, +in read only form, for the sole purposes of debugging your products, +maintaining your products, or enhancing the interoperability of your products +with the software, and specifically excludes the right to distribute the +software outside of your company. + +"Licensed patents" means any Licensor patent claims which read directly on the +software as distributed by the Licensor under this license. + +## 2. Grant of Rights + +(A) Copyright Grant - Subject to the terms of this license, the Licensor grants +you a non-transferable, non-exclusive, worldwide, royalty-free copyright +license to reproduce the software for reference use. + +(B) Patent Grant - Subject to the terms of this license, the Licensor grants +you a non-transferable, non-exclusive, worldwide, royalty-free patent license +under licensed patents for reference use. + +## 3. Limitations + +(A) No Trademark License - This license does not grant you any rights to use +the Licensor's name, logo, or trademarks. + +(B) If you begin patent litigation against the Licensor over patents that you +think may apply to the software (including a cross-claim or counterclaim in +a lawsuit), your license to the software ends automatically. + +(C) The software is licensed "as-is." You bear the risk of using it. The +Licensor gives no express warranties, guarantees or conditions. You may have +additional consumer rights under your local laws which this license cannot +change. To the extent permitted under your local laws, the Licensor excludes +the implied warranties of merchantability, fitness for a particular purpose and +non-infringement. + + +****************************** + +trough +1.0.1 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +ts-custom-error +3.3.1 +The MIT License + +Copyright (c) 2019 Adrien Gibrat https://github.com/adriengibrat + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +ts-interface-checker +0.1.13 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +tslib +1.14.1 +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +****************************** + +tslib +2.6.2 +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +****************************** + +ts-mixer +6.0.4 +MIT License + +Copyright (c) 2024 Tanner Nielsen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +tweetnacl +1.0.3 +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + + +****************************** + +tweetnacl-util +0.15.1 +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + + +****************************** + +typedarray +0.0.6 +/* + Copyright (c) 2010, Linden Research, Inc. + Copyright (c) 2012, Joshua Bell + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + $/LicenseInfo$ + */ + +// Original can be found at: +// https://bitbucket.org/lindenlab/llsd +// Modifications by Joshua Bell inexorabletash@gmail.com +// https://github.com/inexorabletash/polyfill + +// ES3/ES5 implementation of the Krhonos Typed Array Specification +// Ref: http://www.khronos.org/registry/typedarray/specs/latest/ +// Date: 2011-02-01 +// +// Variations: +// * Allows typed_array.get/set() as alias for subscripts (typed_array[]) + + +****************************** + +type-fest +0.20.2 +MIT License + +Copyright (c) Sindre Sorhus (https:/sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +type-fest +4.15.0 +license: (MIT OR CC0-1.0) +authors: Sindre Sorhus + +****************************** + +typeforce +1.18.0 +MIT License + +Copyright (c) 2018 Daniel Cousens + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@types/bn.js +5.1.5 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/color-name +1.1.1 + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/connect +3.4.38 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/debug +4.1.7 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/deep-freeze-strict +1.1.0 +license: MIT +authors: Mohamed Hegazy + +****************************** + +@types/hast +2.3.1 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/jsonwebtoken +9.0.2 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/lodash +4.14.184 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/mdast +3.0.10 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/ms +0.7.31 + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/node +12.20.55 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/node +20.12.7 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/pbkdf2 +3.1.0 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/prop-types +15.7.3 + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/punycode +2.1.0 + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/react +16.9.53 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/react-transition-group +4.4.6 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/secp256k1 +4.0.3 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/unist +2.0.6 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/uuid +8.3.0 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/uuid +9.0.8 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/w3c-web-usb +1.0.10 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +@types/web +0.0.138 +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of this License; and + +You must cause any modified files to carry prominent notices stating that You changed the files; and + +You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + + +****************************** + +@types/ws +7.4.7 + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + + +****************************** + +ua-parser-js +1.0.37 +MIT License + +Copyright (c) 2012-2023 Faisal Salman <> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +uint8arrays +2.1.5 +license: MIT +authors: Alex Potsides + +****************************** + +uint8arrays +3.1.1 +license: MIT +authors: Alex Potsides + +****************************** + +undici +5.28.4 +MIT License + +Copyright (c) Matteo Collina and Undici contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +undici-types +5.26.5 +license: MIT +authors: Daniele Belardi , Ethan Arrowood , Matteo Collina , Matthew Aitken , Robert Nagy , Szymon Marczak , Tomas Della Vedova + +****************************** + +unicode-confusables +0.1.1 <> +MIT License + +Copyright (c) 2020 Ty + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +unified +9.2.0 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +unist-builder +2.0.3 +The MIT License (MIT) + +Copyright (c) 2015 Eugene Sharygin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +unist-util-generated +1.1.6 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +unist-util-is +4.0.2 +(The MIT license) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +unist-util-position +3.1.0 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +unist-util-stringify-position +2.0.1 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +unist-util-visit +2.0.3 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +unist-util-visit-parents +3.1.0 +(The MIT License) + +Copyright (c) 2016 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +update-browserslist-db +1.0.13 +The MIT License (MIT) + +Copyright 2022 Andrey Sitnik and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +uri-js +4.4.1 +Copyright 2011 Gary Court. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY GARY COURT "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARY COURT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of Gary Court. + + +****************************** + +usb +2.12.0 +Copyright (c) 2012 Nonolith Labs, LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +****************************** + +use-callback-ref +1.3.0 +MIT License + +Copyright (c) 2017 Anton Korzunov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +use-memo-one +1.1.3 +MIT License + +Copyright (c) 2019 Alexander Reardon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +****************************** + +use-sidecar +1.1.2 +MIT License + +Copyright (c) 2017 Anton Korzunov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +utf8 +3.0.0 +Copyright Mathias Bynens + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +utf-8-validate +5.0.10 +This project is licensed for use as follows: + +""" +Copyright (c) 2011 Einar Otto Stangvik (http://2x.io) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +""" + +This license applies to parts originating from +https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c: + +""" +Markus Kuhn -- 2005-03-30 +License: http://www.cl.cam.ac.uk/~mgk25/short-license.html +""" + + +****************************** + +util +0.12.5 +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + + +****************************** + +util-deprecate +1.0.2 +(The MIT License) + +Copyright (c) 2014 Nathan Rajlich + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +uuid +7.0.3 +The MIT License (MIT) + +Copyright (c) 2010-2016 Robert Kieffer and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +uuid +8.3.2 +The MIT License (MIT) + +Copyright (c) 2010-2020 Robert Kieffer and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +uuid +9.0.1 +The MIT License (MIT) + +Copyright (c) 2010-2020 Robert Kieffer and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +validate-npm-package-name +5.0.0 +Copyright (c) 2015, npm, Inc + + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +valid-url +1.0.9 +Copyright (c) 2013 Odysseas Tsatalos and oDesk Corporation + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +value-equal +1.0.1 +MIT License + +Copyright (c) Michael Jackson 2016-2018 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +varint +5.0.2 +license: MIT +authors: Chris Dickinson + +****************************** + +varint +6.0.0 +license: MIT +authors: Chris Dickinson + +****************************** + +varuint-bitcoin +1.1.2 +The MIT License (MIT) + +Copyright (c) 2016 Kirill Fomichev + +Parts of this software are based on https://github.com/mappum/bitcoin-protocol +Copyright (c) 2016 Matt Bell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +vfile +4.0.1 +(The MIT License) + +Copyright (c) 2015 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +vfile-message +2.0.1 +(The MIT License) + +Copyright (c) 2017 Titus Wormer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +warning +3.0.0 +BSD License + +For React software + +Copyright (c) 2013-2015, Facebook, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name Facebook nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +warning +4.0.3 +MIT License + +Copyright (c) 2013-present, Facebook, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +web3-stream-provider +5.0.0 +license: ISC +authors: kumavis + +****************************** + +web-encoding +1.1.5 <> +license: MIT +authors: Irakli Gozalishvili + +****************************** + +webextension-polyfill +0.10.0 +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + +****************************** + +webextension-polyfill +0.8.0 +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + + +****************************** + +webidl-conversions +3.0.1 +# The BSD 2-Clause License + +Copyright (c) 2014, Domenic Denicola +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +****************************** + +websocket-driver +0.7.0 +# The MIT License + +Copyright (c) 2010-2017 James Coglan + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the 'Software'), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +websocket-extensions +0.1.4 +Copyright 2014-2020 James Coglan + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. + + +****************************** + +whatwg-url +5.0.0 +The MIT License (MIT) + +Copyright (c) 2015–2016 Sebastian Mayr + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +which +2.0.2 +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +which-boxed-primitive +1.0.2 +MIT License + +Copyright (c) 2019 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +which-collection +1.0.1 +MIT License + +Copyright (c) 2019 Inspect JS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +which-typed-array +1.1.9 +The MIT License (MIT) + +Copyright (c) 2015 Jordan Harband + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +wif +4.0.0 +The MIT License (MIT) + +Copyright (c) 2015 Daniel Cousens + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +wrap-ansi +7.0.0 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +wrap-ansi +8.1.0 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +wrappy +1.0.2 +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +write-file-atomic +2.4.3 +Copyright (c) 2015, Rebecca Turner + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + + +****************************** + +ws +7.4.6 +The MIT License (MIT) + +Copyright (c) 2011 Einar Otto Stangvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +ws +7.5.9 +The MIT License (MIT) + +Copyright (c) 2011 Einar Otto Stangvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +ws +8.16.0 +Copyright (c) 2011 Einar Otto Stangvik +Copyright (c) 2013 Arnout Kazemier and contributors +Copyright (c) 2016 Luigi Pinca and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +xcode +3.0.1 + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +xhr2 +0.2.1 +Copyright (c) 2013 Victor Costan + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +xml +1.0.1 +(The MIT License) + +Copyright (c) 2011-2016 Dylan Greene + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +xml2js +0.6.0 +Copyright 2010, 2011, 2012, 2013. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + + +****************************** + +xmlbuilder +11.0.1 +The MIT License (MIT) + +Copyright (c) 2013 Ozgur Ozcitak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +xmlbuilder +14.0.0 +The MIT License (MIT) + +Copyright (c) 2013 Ozgur Ozcitak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +xmlbuilder +15.1.1 +The MIT License (MIT) + +Copyright (c) 2013 Ozgur Ozcitak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +@xmldom/xmldom +0.7.13 +Copyright 2019 - present Christopher J. Brody and other contributors, as listed in: https://github.com/xmldom/xmldom/graphs/contributors +Copyright 2012 - 2017 @jindw and other contributors, as listed in: https://github.com/jindw/xmldom/graphs/contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@xmldom/xmldom +0.8.10 +Copyright 2019 - present Christopher J. Brody and other contributors, as listed in: https://github.com/xmldom/xmldom/graphs/contributors +Copyright 2012 - 2017 @jindw and other contributors, as listed in: https://github.com/jindw/xmldom/graphs/contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@xstate/fsm +2.0.0 +The MIT License (MIT) + +Copyright (c) 2015 David Khourshid + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +****************************** + +xtend +4.0.2 +The MIT License (MIT) +Copyright (c) 2012-2014 Raynos. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +y18n +5.0.5 +Copyright (c) 2015, Contributors + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. + + +****************************** + +yallist +3.1.1 +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +yallist +4.0.0 +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +yargs +17.7.2 +MIT License + +Copyright 2010 James Halliday (mail@substack.net); Modified work Copyright 2014 Contributors (ben@npmjs.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************** + +yargs-parser +21.1.1 +Copyright (c) 2016, Contributors + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice +appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE +LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +yocto-queue +0.1.0 +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +zod +3.22.4 +MIT License + +Copyright (c) 2020 Colin McDonnell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +zxcvbn +4.4.2 +Copyright (c) 2012-2016 Dan Wheeler and Dropbox, Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +@zxing/browser +0.1.4 +MIT License + +Copyright (c) 2018 ZXing for JS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@zxing/library +0.20.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +======================================================================== +jai-imageio +======================================================================== + +Copyright (c) 2005 Sun Microsystems, Inc. +Copyright © 2010-2014 University of Manchester +Copyright © 2010-2015 Stian Soiland-Reyes +Copyright © 2015 Peter Hull +All Rights Reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistribution of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +- Redistribution in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +Neither the name of Sun Microsystems, Inc. or the names of +contributors may be used to endorse or promote products derived +from this software without specific prior written permission. + +This software is provided "AS IS," without a warranty of any +kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND +WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY +EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL +NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF +USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS +DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR +ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, +CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND +REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR +INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +You acknowledge that this software is not designed or intended for +use in the design, construction, operation or maintenance of any +nuclear facility. + + +****************************** + +@zxing/text-encoding +0.9.0 +The encoding indexes, algorithms, and many comments in the code +derive from the Encoding Standard https://encoding.spec.whatwg.org/ + +Otherwise, the code of this repository is released under the Unlicense +license and is also dual-licensed under an Apache 2.0 license. Both +are included below. + +# Unlicense + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + +# Apache 2.0 License + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/builds.yml b/builds.yml index acdf5a71198d..500be3b4de4b 100644 --- a/builds.yml +++ b/builds.yml @@ -27,8 +27,9 @@ buildTypes: - SEGMENT_WRITE_KEY_REF: SEGMENT_PROD_WRITE_KEY - ALLOW_LOCAL_SNAPS: false - REQUIRE_SNAPS_ALLOWLIST: true - - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/5.0.3/index.html + - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/6.4.0/index.html - ACCOUNT_SNAPS_DIRECTORY_URL: https://snaps.metamask.io/account-management + - BTC_BETA_SUPPORT: false # Main build uses the default browser manifest manifestOverrides: false # Build name used in multiple user-readable places @@ -38,11 +39,18 @@ buildTypes: beta: features: - build-beta + - snaps + - keyring-snaps + - blockaid env: - INFURA_BETA_PROJECT_ID - SEGMENT_BETA_WRITE_KEY - INFURA_ENV_KEY_REF: INFURA_BETA_PROJECT_ID - SEGMENT_WRITE_KEY_REF: SEGMENT_BETA_WRITE_KEY + - ALLOW_LOCAL_SNAPS: false + - REQUIRE_SNAPS_ALLOWLIST: true + - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/6.4.0/index.html + - ACCOUNT_SNAPS_DIRECTORY_URL: https://snaps.metamask.io/account-management # Modifies how the version is displayed. # eg. instead of 10.25.0 -> 10.25.0-beta.2 isPrerelease: true @@ -55,62 +63,43 @@ buildTypes: # will not be removed features: - snaps - - desktop - build-flask - keyring-snaps - blockaid - - petnames env: - INFURA_FLASK_PROJECT_ID - SEGMENT_FLASK_WRITE_KEY - ALLOW_LOCAL_SNAPS: true - REQUIRE_SNAPS_ALLOWLIST: false - - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/5.0.3/index.html + - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/6.4.0/index.html - SUPPORT_LINK: https://metamask-flask.zendesk.com/hc - SUPPORT_REQUEST_LINK: https://metamask-flask.zendesk.com/hc/en-us/requests/new - INFURA_ENV_KEY_REF: INFURA_FLASK_PROJECT_ID - SEGMENT_WRITE_KEY_REF: SEGMENT_FLASK_WRITE_KEY - ACCOUNT_SNAPS_DIRECTORY_URL: https://metamask.github.io/snaps-directory-staging/main/account-management + - EIP_4337_ENTRYPOINT: '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789' + - BTC_BETA_SUPPORT: false isPrerelease: true manifestOverrides: ./app/build-types/flask/manifest/ buildNameOverride: MetaMask Flask - desktop: - features: - - snaps - - desktop - - build-flask - - keyring-snaps - env: - - INFURA_FLASK_PROJECT_ID - - SEGMENT_FLASK_WRITE_KEY - - ALLOW_LOCAL_SNAPS: true - - REQUIRE_SNAPS_ALLOWLIST: false - - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/5.0.3/index.html - - SUPPORT_LINK: https://metamask-flask.zendesk.com/hc - - SUPPORT_REQUEST_LINK: https://metamask-flask.zendesk.com/hc/en-us/requests/new - - INFURA_ENV_KEY_REF: INFURA_FLASK_PROJECT_ID - - SEGMENT_WRITE_KEY_REF: SEGMENT_FLASK_WRITE_KEY - - ACCOUNT_SNAPS_DIRECTORY_URL: https://snaps.metamask.io/account-management - isPrerelease: true - manifestOverrides: ./app/build-types/desktop/manifest/ - buildNameOverride: false - mmi: features: - build-mmi - snaps + - blockaid env: - INFURA_MMI_PROJECT_ID - SEGMENT_MMI_WRITE_KEY + - SENTRY_MMI_DSN - INFURA_ENV_KEY_REF: INFURA_MMI_PROJECT_ID - SEGMENT_WRITE_KEY_REF: SEGMENT_MMI_WRITE_KEY - ALLOW_LOCAL_SNAPS: false - REQUIRE_SNAPS_ALLOWLIST: true - - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/5.0.3/index.html + - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/6.4.0/index.html - MMI_CONFIGURATION_SERVICE_URL: https://configuration.metamask-institutional.io/v2/configuration/default - - SUPPORT_LINK: https://mmi-support.zendesk.com/hc/en-us - - SUPPORT_REQUEST_LINK: https://mmi-support.zendesk.com/hc/en-us/requests/new + - SUPPORT_LINK: https://mmi-support.metamask.io/hc/en-us + - SUPPORT_REQUEST_LINK: https://mmi-support.metamask.io/hc/en-us/requests/new - SENTRY_DSN: SENTRY_MMI_DSN # For some reason, MMI uses this type of versioning # Leaving it on for backwards compatibility @@ -133,18 +122,10 @@ features: - IFRAME_EXECUTION_ENVIRONMENT_URL assets: - ./{app,shared,ui}/**/snaps/** - desktop: - env: - - COMPATIBILITY_VERSION_EXTENSION: 1 - - DISABLE_WEB_SOCKET_ENCRYPTION: false - - SKIP_OTP_PAIRING_FLOW: false - - WEB_SOCKET_PORT: null blockaid: env: - BLOCKAID_FILE_CDN: static.cx.metamask.io/api/v1/confirmations/ppom - BLOCKAID_PUBLIC_KEY: 066ad3e8af5583385e312c156d238055215d5f25247c1e91055afa756cb98a88 - petnames: - conf-redesign: ### # Build Type code extensions. Things like different support links, warning pages, banners ### @@ -183,20 +164,51 @@ env: - TRANSACTION_SECURITY_PROVIDER: false # The unlock password - PASSWORD: null + - TEST_SRP: null + - SKIP_ONBOARDING: null # Also see METAMASK_DEBUG and NODE_DEBUG - DEBUG: null - SUPPORT_LINK: https://support.metamask.io - SUPPORT_REQUEST_LINK: https://metamask.zendesk.com/hc/en-us - SKIP_BACKGROUND_INITIALIZATION: false - # TODO(ritave): Move ManifestV3 into a feature? - - ENABLE_MV3: false + - ENABLE_MV3: true # These are exclusively used for MV3 + - USE_SNOW - APPLY_LAVAMOAT - FILE_NAMES # This variable is read by Trezor's source and breaks build if not included - ASSET_PREFIX: null + - SUITE_TYPE: null + - COMMITHASH: null + - VERSION: null + - IS_CODESIGN_BUILD: null + + - SENTRY_MMI_DSN: '' + + ### + # Notifications Feature + ### + - AUTH_API: https://authentication.api.cx.metamask.io + - OIDC_API: https://oidc.api.cx.metamask.io + - OIDC_CLIENT_ID: 1132f10a-b4e5-4390-a5f2-d9c6022db564 + - OIDC_GRANT_TYPE: urn:ietf:params:oauth:grant-type:jwt-bearer + - USER_STORAGE_API: https://user-storage.api.cx.metamask.io + - CONTENTFUL_ACCESS_SPACE_ID: + - CONTENTFUL_ACCESS_TOKEN: + - NOTIFICATIONS_SERVICE_URL: https://notification.api.cx.metamask.io + - TRIGGERS_SERVICE_URL: https://trigger.api.cx.metamask.io + - PUSH_NOTIFICATIONS_SERVICE_URL: https://push.api.cx.metamask.io + - VAPID_KEY: + - FIREBASE_API_KEY: + - FIREBASE_AUTH_DOMAIN: + - FIREBASE_STORAGE_BUCKET: + - FIREBASE_PROJECT_ID: + - FIREBASE_MESSAGING_SENDER_ID: + - FIREBASE_APP_ID: + - FIREBASE_MEASUREMENT_ID: + - __FIREBASE_DEFAULTS__: null ### # API keys to 3rd party services @@ -222,6 +234,10 @@ env: # Variables that are modified with hardcoded code ### + # Used to enable confirmation redesigned pages + - ENABLE_CONFIRMATION_REDESIGN: '' + # Determines if feature flagged Settings Page - Developer Options should be used + - ENABLE_SETTINGS_PAGE_DEV_OPTIONS: false # Used for debugging changes to the phishing warning page. # Modified in /development/build/scripts.js:@getPhishingWarningPageUrl - PHISHING_WARNING_PAGE_URL: null @@ -259,10 +275,17 @@ env: - BLOCKAID_FILE_CDN # Blockaid public key for verifying signatures of data files downloaded from CDN - BLOCKAID_PUBLIC_KEY - # Determines if feature flagged Multichain UI should be used - - MULTICHAIN: '' # Determines if feature flagged Multichain Transactions should be used - TRANSACTION_MULTICHAIN: '' + # Determines if feature flagged Chain permissions + - CHAIN_PERMISSIONS: '' + # Enables use of test gas fee flow to debug gas fee estimation + - TEST_GAS_FEE_FLOWS: false + # Determines if feature flagged network ui new design + - ENABLE_NETWORK_UI_REDESIGN: '' + + # Enables the notifications feature within the build: + - NOTIFICATIONS: '' ### # Meta variables diff --git a/coverage-targets.js b/coverage-targets.js deleted file mode 100644 index 631a8b6e737d..000000000000 --- a/coverage-targets.js +++ /dev/null @@ -1,20 +0,0 @@ -// Codecov uses a yaml file for its configuration and it targets line coverage. -// To keep our policy in place we have thile file separate from our -// codecov.yml file that specifies coverage targets for each project in the -// codecov.yml file. These targets are read by the test/merge-coverage.js -// script, and the paths from the codecov.yml file are used to figure out which -// subset of files to check against these targets. -module.exports = { - global: { - lines: 70.85, - branches: 59.07, - statements: 70.3, - functions: 63.52, - }, - transforms: { - branches: 100, - functions: 100, - lines: 100, - statements: 100, - }, -}; diff --git a/development/README.md b/development/README.md index d00880addb83..21422e72b3de 100644 --- a/development/README.md +++ b/development/README.md @@ -76,7 +76,18 @@ To debug in a production Sentry environment: Errors reported whilst using the extension will be displayed in Sentry's `Issues` page. -To debug in test build we need to comment out the IF condition https://github.com/MetaMask/metamask-extension/blob/develop/app/scripts/lib/setupSentry.js#L392 +To debug in test build we need to comment out the below:-
+- `setupSentry` function comment the return statement in the `app/scripts/lib +/setupSentry.js` https://github.com/MetaMask/metamask-extension/blob/e3c76ca699e94bacfc43793d28291fa5ddf06752/app/scripts/lib/setupSentry.js#L496 +- `setupStateHooks` function set the if condition to true in the `ui +/index.js` https://github.com/MetaMask/metamask-extension/blob/e3c76ca699e94bacfc43793d28291fa5ddf06752/ui/index.js#L242 + +How to trigger Sentry error:- +1. Open the background console. +2. Load the extension app and open the developer console. +3. Toggle the `Participate in MetaMetrics` menu option to the `ON` position. +4. Enter `window.stateHooks.throwTestBackgroundError()` into the developer console. +5. There should now be requests sent to sentry in the background network tab. ## Source Maps diff --git a/development/attributions-check.sh b/development/attributions-check.sh new file mode 100755 index 000000000000..56ae63e7e1d3 --- /dev/null +++ b/development/attributions-check.sh @@ -0,0 +1,12 @@ +#!/bin/bash +yarn attributions:generate + +ATTRIBUTIONS_FILE="./attribution.txt" + +# check to see if there's changes on the attributions file +if ! git diff --exit-code "$ATTRIBUTIONS_FILE"; then + echo "The set of attributions kept in \`attribution.txt\` are out of date." + echo "Run \`yarn attributions:generate\` to regenerate them and commit and push the changes." + echo "If you're looking at a pull request, you can also post the comment \`@metamaskbot update-attributions\` and the file will be automatically regenerated for you." + exit 1 +fi diff --git a/development/build/config.js b/development/build/config.js index 4e4ee1ea9c8a..030b9e04dad0 100644 --- a/development/build/config.js +++ b/development/build/config.js @@ -15,7 +15,7 @@ const VARIABLES_REQUIRED_IN_PRODUCTION = { 'INFURA_MMI_PROJECT_ID', 'MMI_CONFIGURATION_SERVICE_URL', 'SEGMENT_MMI_WRITE_KEY', - 'SENTRY_DSN', + 'SENTRY_MMI_DSN', ], }; diff --git a/development/build/etc.js b/development/build/etc.js index 0479f5eeebd9..3abccd827f76 100644 --- a/development/build/etc.js +++ b/development/build/etc.js @@ -4,7 +4,7 @@ const sort = require('gulp-sort'); const gulpZip = require('gulp-zip'); const del = require('del'); const pify = require('pify'); -const pump = pify(require('pump')); +const pipeline = pify(require('readable-stream').pipeline); const { loadBuildTypesConfig } = require('../lib/build-type'); const { TASKS } = require('./constants'); @@ -45,7 +45,7 @@ function createZipTask(platform, buildType, version) { buildType === loadBuildTypesConfig().default ? `metamask-${platform}-${version}` : `metamask-${buildType}-${platform}-${version}`; - await pump( + await pipeline( gulp.src(`dist/${platform}/**`), // sort files and set `mtime` to epoch to ensure zip build is deterministic sort(), diff --git a/development/build/index.js b/development/build/index.js index cc89cb6ad1e6..f9a778ed8966 100755 --- a/development/build/index.js +++ b/development/build/index.js @@ -26,7 +26,12 @@ const createScriptTasks = require('./scripts'); const createStyleTasks = require('./styles'); const createStaticAssetTasks = require('./static'); const createEtcTasks = require('./etc'); -const { getBrowserVersionMap, getEnvironment } = require('./utils'); +const { + getBrowserVersionMap, + getEnvironment, + isDevBuild, + isTestBuild, +} = require('./utils'); const { getConfig } = require('./config'); /* eslint-disable no-constant-condition, node/global-require */ @@ -90,6 +95,7 @@ async function defineAndRunBuildTasks() { let scuttleGlobalThisExceptions = [ // globals used by different mm deps outside of lm compartment + 'Proxy', 'toString', 'getComputedStyle', 'addEventListener', @@ -109,6 +115,8 @@ async function defineAndRunBuildTasks() { 'WeakSet', 'Event', 'Image', // Used by browser to generate notifications + 'fetch', // Used by browser to generate notifications + 'OffscreenCanvas', // Used by browser to generate notifications // globals chromedriver needs to function /cdc_[a-zA-Z0-9]+_[a-zA-Z]+/iu, 'performance', @@ -190,6 +198,7 @@ async function defineAndRunBuildTasks() { const styleTasks = createStyleTasks({ livereload }); const scriptTasks = createScriptTasks({ + shouldIncludeSnow, applyLavaMoat, browserPlatforms, buildType, @@ -380,8 +389,9 @@ testDev: Create an unoptimized, live-reloading build for debugging e2e tests.`, platform, } = argv; - // Manually default this to `false` for dev builds only. - const shouldLintFenceFiles = lintFenceFiles ?? !/dev/iu.test(task); + // Manually default this to `false` for dev and test builds. + const shouldLintFenceFiles = + lintFenceFiles ?? (!isDevBuild(task) && !isTestBuild(task)); const version = getVersion(buildType, buildVersion); diff --git a/development/build/manifest.js b/development/build/manifest.js index a12f1c455558..c15107564c9a 100644 --- a/development/build/manifest.js +++ b/development/build/manifest.js @@ -3,7 +3,10 @@ const path = require('path'); const childProcess = require('child_process'); const { mergeWith, cloneDeep } = require('lodash'); -const baseManifest = process.env.ENABLE_MV3 +const IS_MV3_ENABLED = + process.env.ENABLE_MV3 === 'true' || process.env.ENABLE_MV3 === undefined; + +const baseManifest = IS_MV3_ENABLED ? require('../../app/manifest/v3/_base.json') : require('../../app/manifest/v2/_base.json'); const { loadBuildTypesConfig } = require('../lib/build-type'); @@ -32,7 +35,7 @@ function createManifestTasks({ '..', '..', 'app', - process.env.ENABLE_MV3 ? 'manifest/v3' : 'manifest/v2', + IS_MV3_ENABLED ? 'manifest/v3' : 'manifest/v2', `${platform}.json`, ), ); @@ -136,7 +139,7 @@ function createManifestTasks({ buildType, applyLavaMoat, shouldIncludeSnow, - shouldIncludeMV3: process.env.ENABLE_MV3, + shouldIncludeMV3: IS_MV3_ENABLED, }); manifest.description = `${environment} build from git id: ${gitRevisionStr}`; diff --git a/development/build/scripts.js b/development/build/scripts.js index 9e0ebd53715c..de01b9665174 100644 --- a/development/build/scripts.js +++ b/development/build/scripts.js @@ -1,10 +1,8 @@ // TODO(ritave): Remove switches on hardcoded build types - const { callbackify } = require('util'); const path = require('path'); const { writeFileSync, readFileSync, unlinkSync } = require('fs'); const EventEmitter = require('events'); -const assert = require('assert'); const gulp = require('gulp'); const watch = require('gulp-watch'); const Vinyl = require('vinyl'); @@ -14,13 +12,13 @@ const log = require('fancy-log'); const browserify = require('browserify'); const watchify = require('watchify'); const babelify = require('babelify'); -const brfs = require('brfs'); + const envify = require('loose-envify/custom'); const sourcemaps = require('gulp-sourcemaps'); const applySourceMap = require('vinyl-sourcemaps-apply'); const pify = require('pify'); const through = require('through2'); -const endOfStream = pify(require('end-of-stream')); +const finished = pify(require('readable-stream').finished); const labeledStreamSplicer = require('labeled-stream-splicer').obj; const wrapInStream = require('pumpify').obj; const { Eta } = require('eta'); @@ -30,9 +28,9 @@ const terser = require('terser'); const bifyModuleGroups = require('bify-module-groups'); -const phishingWarningManifest = require('@metamask/phishing-warning/package.json'); const { streamFlatMap } = require('../stream-flat-map'); -const { BUILD_TARGETS, ENVIRONMENT } = require('./constants'); +const { setEnvironmentVariables } = require('./set-environment-variables'); +const { BUILD_TARGETS } = require('./constants'); const { getConfig } = require('./config'); const { isDevBuild, @@ -41,8 +39,6 @@ const { logError, wrapAgainstScuttling, getBuildName, - getBuildAppId, - getBuildIcon, makeSelfInjecting, } = require('./utils'); @@ -56,9 +52,12 @@ const { createRemoveFencedCodeTransform, } = require('./transforms/remove-fenced-code'); +const isEnableMV3 = + process.env.ENABLE_MV3 === 'true' || process.env.ENABLE_MV3 === undefined; + // map dist files to bag of needed native APIs against LM scuttling const scuttlingConfigBase = { - 'sentry-install.js': { + 'scripts/sentry-install.js': { // globals sentry need to function window: '', navigator: '', @@ -96,128 +95,12 @@ const mv3ScuttlingConfig = { ...scuttlingConfigBase }; const standardScuttlingConfig = { ...scuttlingConfigBase, - 'sentry-install.js': { - ...scuttlingConfigBase['sentry-install.js'], + 'scripts/sentry-install.js': { + ...scuttlingConfigBase['scripts/sentry-install.js'], document: '', }, }; -/** - * Get the appropriate Infura project ID. - * - * @param {object} options - The Infura project ID options. - * @param {string} options.buildType - The current build type. - * @param {ENVIRONMENT[keyof ENVIRONMENT]} options.environment - The build environment. - * @param {boolean} options.testing - Whether this is a test build or not. - * @param options.variables - * @returns {string} The Infura project ID. - */ -function getInfuraProjectId({ buildType, variables, environment, testing }) { - const EMPTY_PROJECT_ID = '00000000000000000000000000000000'; - if (testing) { - return EMPTY_PROJECT_ID; - } else if (environment !== ENVIRONMENT.PRODUCTION) { - // Skip validation because this is unset on PRs from forks. - // For forks, return empty project ID if we don't have one. - if ( - !variables.isDefined('INFURA_PROJECT_ID') && - environment === ENVIRONMENT.PULL_REQUEST - ) { - return EMPTY_PROJECT_ID; - } - return variables.get('INFURA_PROJECT_ID'); - } - /** @type {string|undefined} */ - const infuraKeyReference = variables.get('INFURA_ENV_KEY_REF'); - assert( - typeof infuraKeyReference === 'string' && infuraKeyReference.length > 0, - `Build type "${buildType}" has improperly set INFURA_ENV_KEY_REF in builds.yml. Current value: "${infuraKeyReference}"`, - ); - /** @type {string|undefined} */ - const infuraProjectId = variables.get(infuraKeyReference); - assert( - typeof infuraProjectId === 'string' && infuraProjectId.length > 0, - `Infura Project ID environmental variable "${infuraKeyReference}" is set improperly.`, - ); - return infuraProjectId; -} - -/** - * Get the appropriate Segment write key. - * - * @param {object} options - The Segment write key options. - * @param {string} options.buildType - The current build type. - * @param {keyof ENVIRONMENT} options.environment - The current build environment. - * @param {import('../lib/variables').Variables} options.variables - Object containing all variables that modify the build pipeline - * @returns {string} The Segment write key. - */ -function getSegmentWriteKey({ buildType, variables, environment }) { - if (environment !== ENVIRONMENT.PRODUCTION) { - // Skip validation because this is unset on PRs from forks, and isn't necessary for development builds. - return variables.get('SEGMENT_WRITE_KEY'); - } - - const segmentKeyReference = variables.get('SEGMENT_WRITE_KEY_REF'); - assert( - typeof segmentKeyReference === 'string' && segmentKeyReference.length > 0, - `Build type "${buildType}" has improperly set SEGMENT_WRITE_KEY_REF in builds.yml. Current value: "${segmentKeyReference}"`, - ); - - const segmentWriteKey = variables.get(segmentKeyReference); - assert( - typeof segmentWriteKey === 'string' && segmentWriteKey.length > 0, - `Segment Write Key environmental variable "${segmentKeyReference}" is set improperly.`, - ); - return segmentWriteKey; -} - -/** - * Get the URL for the phishing warning page, if it has been set. - * - * @param {object} options - The phishing warning page options. - * @param {boolean} options.testing - Whether this is a test build or not. - * @param {import('../lib/variables').Variables} options.variables - Object containing all variables that modify the build pipeline - * @returns {string} The URL for the phishing warning page, or `undefined` if no URL is set. - */ -function getPhishingWarningPageUrl({ variables, testing }) { - let phishingWarningPageUrl = variables.get('PHISHING_WARNING_PAGE_URL'); - - assert( - phishingWarningPageUrl === null || - typeof phishingWarningPageUrl === 'string', - ); - if (phishingWarningPageUrl === null) { - phishingWarningPageUrl = testing - ? 'http://localhost:9999/' - : `https://metamask.github.io/phishing-warning/v${phishingWarningManifest.version}/`; - } - - // We add a hash/fragment to the URL dynamically, so we need to ensure it - // has a valid pathname to append a hash to. - const normalizedUrl = phishingWarningPageUrl.endsWith('/') - ? phishingWarningPageUrl - : `${phishingWarningPageUrl}/`; - - let phishingWarningPageUrlObject; - try { - // eslint-disable-next-line no-new - phishingWarningPageUrlObject = new URL(normalizedUrl); - } catch (error) { - throw new Error( - `Invalid phishing warning page URL: '${normalizedUrl}'`, - error, - ); - } - if (phishingWarningPageUrlObject.hash) { - // The URL fragment must be set dynamically - throw new Error( - `URL fragment not allowed in phishing warning page URL: '${normalizedUrl}'`, - ); - } - - return normalizedUrl; -} - const noopWriteStream = through.obj((_file, _fileEncoding, callback) => callback(), ); @@ -247,9 +130,12 @@ module.exports = createScriptTasks; * @param {boolean} options.shouldLintFenceFiles - Whether files with code * fences should be linted after fences have been removed. * @param {string} options.version - The current version of the extension. + * @param options.shouldIncludeSnow - Whether the build should use + * Snow at runtime or not. * @returns {object} A set of tasks, one for each build target. */ function createScriptTasks({ + shouldIncludeSnow, applyLavaMoat, browserPlatforms, buildType, @@ -305,13 +191,14 @@ function createScriptTasks({ // In MV3 we will need to build our offscreen entry point bundle and any // entry points for iframes that we want to lockdown with LavaMoat. - if (process.env.ENABLE_MV3 === 'true') { + if (isEnableMV3) { standardEntryPoints.push('offscreen'); } const standardSubtask = createTask( `${taskPrefix}:standardEntryPoints`, createFactoredBuild({ + shouldIncludeSnow, applyLavaMoat, browserPlatforms, buildTarget, @@ -376,6 +263,7 @@ function createScriptTasks({ installSentrySubtask, ].map((subtask) => runInChildProcess(subtask, { + shouldIncludeSnow, applyLavaMoat, buildType, isLavaMoat, @@ -400,7 +288,7 @@ function createScriptTasks({ browserPlatforms, buildTarget, buildType, - destFilepath: `${label}.js`, + destFilepath: `scripts/${label}.js`, entryFilepath: `./app/scripts/${label}.js`, ignoredFiles, label, @@ -424,7 +312,7 @@ function createScriptTasks({ browserPlatforms, buildTarget, buildType, - destFilepath: `${label}.js`, + destFilepath: `scripts/${label}.js`, entryFilepath: `./app/scripts/${label}.js`, ignoredFiles, label, @@ -452,7 +340,7 @@ function createScriptTasks({ buildTarget, buildType, browserPlatforms, - destFilepath: `${inpage}.js`, + destFilepath: `scripts/${inpage}.js`, entryFilepath: `./app/scripts/${inpage}.js`, label: inpage, ignoredFiles, @@ -464,28 +352,32 @@ function createScriptTasks({ () => { // MV3 injects inpage into the tab's main world, but in MV2 we need // to do it manually: - if (process.env.ENABLE_MV3) { + if (isEnableMV3) { return; } - // stringify inpage.js into itself, and then make it inject itself into the page + // stringify scripts/inpage.js into itself, and then make it inject itself into the page browserPlatforms.forEach((browser) => { makeSelfInjecting( - path.join(__dirname, `../../dist/${browser}/${inpage}.js`), + path.join(__dirname, `../../dist/${browser}/scripts/${inpage}.js`), ); }); - // delete the inpage.js source map, as it no longer represents inpage.js - // and so `yarn source-map-explorer` can't handle it. It's also not - // useful anyway, as inpage.js is injected as a `script.textContent`, - // and not tracked in Sentry or browsers devtools anyway. + // delete the scripts/inpage.js source map, as it no longer represents + // scripts/inpage.js and so `yarn source-map-explorer` can't handle it. + // It's also not useful anyway, as scripts/inpage.js is injected as a + // `script.textContent`, and not tracked in Sentry or browsers devtools + // anyway. unlinkSync( - path.join(__dirname, `../../dist/sourcemaps/${inpage}.js.map`), + path.join( + __dirname, + `../../dist/sourcemaps/scripts/${inpage}.js.map`, + ), ); }, createNormalBundle({ buildTarget, buildType, browserPlatforms, - destFilepath: `${contentscript}.js`, + destFilepath: `scripts/${contentscript}.js`, entryFilepath: `./app/scripts/${contentscript}.js`, label: contentscript, ignoredFiles, @@ -523,9 +415,12 @@ function createScriptTasks({ * @param {boolean} options.shouldLintFenceFiles - Whether files with code * fences should be linted after fences have been removed. * @param {string} options.version - The current version of the extension. + * @param options.shouldIncludeSnow - Whether the build should use + * Snow at runtime or not. * @returns {Function} A function that creates the set of bundles. */ async function createManifestV3AppInitializationBundle({ + shouldIncludeSnow, applyLavaMoat, browserPlatforms, buildTarget, @@ -551,6 +446,7 @@ async function createManifestV3AppInitializationBundle({ } const extraEnvironmentVariables = { + USE_SNOW: shouldIncludeSnow, APPLY_LAVAMOAT: applyLavaMoat, FILE_NAMES: jsBundles.join(','), }; @@ -559,7 +455,7 @@ async function createManifestV3AppInitializationBundle({ browserPlatforms: mv3BrowserPlatforms, buildTarget, buildType, - destFilepath: 'app-init.js', + destFilepath: 'scripts/app-init.js', entryFilepath: './app/scripts/app-init.js', extraEnvironmentVariables, ignoredFiles, @@ -573,9 +469,12 @@ async function createManifestV3AppInitializationBundle({ // Code below is used to set statsMode to true when testing in MV3 // This is used to capture module initialisation stats using lavamoat. if (isTestBuild(buildTarget)) { - const content = readFileSync('./dist/chrome/runtime-lavamoat.js', 'utf8'); + const content = readFileSync( + './dist/chrome/scripts/runtime-lavamoat.js', + 'utf8', + ); const fileOutput = content.replace('statsMode = false', 'statsMode = true'); - writeFileSync('./dist/chrome/runtime-lavamoat.js', fileOutput); + writeFileSync('./dist/chrome/scripts/runtime-lavamoat.js', fileOutput); } console.log(`Bundle end: service worker app-init.js`); @@ -609,9 +508,12 @@ async function createManifestV3AppInitializationBundle({ * @param {boolean} options.shouldLintFenceFiles - Whether files with code * fences should be linted after fences have been removed. * @param {string} options.version - The current version of the extension. + * @param options.shouldIncludeSnow - Whether the build should use + * Snow at runtime or not. * @returns {Function} A function that creates the set of bundles. */ function createFactoredBuild({ + shouldIncludeSnow, applyLavaMoat, browserPlatforms, buildTarget, @@ -635,12 +537,16 @@ function createFactoredBuild({ const environment = getEnvironment({ buildTarget }); const config = await getConfig(buildType, environment); const { variables, activeBuild } = config; - await setEnvironmentVariables({ - buildTarget, + setEnvironmentVariables({ + isDevBuild: reloadOnChange, + isTestBuild: isTestBuild(buildTarget), + buildName: getBuildName({ + environment, + buildType, + }), buildType, environment, variables, - activeBuild, version, }); const features = { @@ -670,12 +576,17 @@ function createFactoredBuild({ __dirname, `../../lavamoat/browserify/${buildType}/policy.json`, ), + policyDebug: path.resolve( + __dirname, + `../../lavamoat/browserify/${buildType}/policy-debug.json`, + ), policyName: buildType, policyOverride: path.resolve( __dirname, `../../lavamoat/browserify/policy-override.json`, ), writeAutoPolicy: process.env.WRITE_AUTO_POLICY, + writeAutoPolicyDebug: process.env.WRITE_AUTO_POLICY_DEBUG, }; Object.assign(bundlerOpts, lavamoatBrowserify.args); bundlerOpts.plugin.push([lavamoatBrowserify, lavamoatOpts]); @@ -718,7 +629,7 @@ function createFactoredBuild({ // add lavamoat policy loader file to packer output moduleGroupPackerStream.push( new Vinyl({ - path: 'policy-load.js', + path: 'scripts/policy-load.js', contents: lavapack.makePolicyLoaderStream(lavamoatOpts), }), ); @@ -749,14 +660,23 @@ function createFactoredBuild({ buildTarget === BUILD_TARGETS.TEST_DEV; switch (groupLabel) { case 'ui': { + renderHtmlFile({ + htmlName: 'loading', + browserPlatforms, + shouldIncludeSnow, + applyLavaMoat, + isMMI: buildType === 'mmi', + }); renderHtmlFile({ htmlName: 'popup', browserPlatforms, + shouldIncludeSnow, applyLavaMoat, }); renderHtmlFile({ htmlName: 'notification', browserPlatforms, + shouldIncludeSnow, applyLavaMoat, isMMI: buildType === 'mmi', isTest, @@ -764,6 +684,7 @@ function createFactoredBuild({ renderHtmlFile({ htmlName: 'home', browserPlatforms, + shouldIncludeSnow, applyLavaMoat, isMMI: buildType === 'mmi', isTest, @@ -772,6 +693,7 @@ function createFactoredBuild({ groupSet, commonSet, browserPlatforms, + shouldIncludeSnow, applyLavaMoat, destinationFileName: 'load-app.js', }); @@ -783,21 +705,24 @@ function createFactoredBuild({ groupSet, commonSet, browserPlatforms, + shouldIncludeSnow, applyLavaMoat, }); renderJavaScriptLoader({ groupSet, commonSet, browserPlatforms, + shouldIncludeSnow, applyLavaMoat, destinationFileName: 'load-background.js', }); - if (process.env.ENABLE_MV3) { + if (isEnableMV3) { const jsBundles = [ ...commonSet.values(), ...groupSet.values(), - ].map((label) => `./${label}.js`); + ].map((label) => `../${label}.js`); await createManifestV3AppInitializationBundle({ + shouldIncludeSnow, applyLavaMoat, browserPlatforms, buildTarget, @@ -817,6 +742,7 @@ function createFactoredBuild({ groupSet, commonSet, browserPlatforms, + shouldIncludeSnow, applyLavaMoat: false, }); break; @@ -826,6 +752,7 @@ function createFactoredBuild({ groupSet, commonSet, browserPlatforms, + shouldIncludeSnow, applyLavaMoat, destinationFileName: 'load-offscreen.js', }); @@ -900,12 +827,16 @@ function createNormalBundle({ const environment = getEnvironment({ buildTarget }); const config = await getConfig(buildType, environment); const { activeBuild, variables } = config; - await setEnvironmentVariables({ - buildTarget, + setEnvironmentVariables({ + buildName: getBuildName({ + environment, + buildType, + }), + isDevBuild: devMode, + isTestBuild: isTestBuild(buildTarget), buildType, variables, environment, - activeBuild, version, }); Object.entries(extraEnvironmentVariables ?? {}).forEach(([key, value]) => @@ -993,8 +924,14 @@ function setupBundlerDefaults( extensions, }, ], - // Inline `fs.readFileSync` files - brfs, + // We are transpelling the firebase package to be compatible with the lavaMoat restrictions + [ + babelify, + { + only: ['./**/node_modules/firebase', './**/node_modules/@firebase'], + global: true, + }, + ], ], // Look for TypeScript files when walking the dependency tree extensions, @@ -1092,7 +1029,9 @@ function setupMinification(buildConfiguration) { function setupScuttlingWrapping(buildConfiguration, applyLavaMoat, envVars) { const scuttlingConfig = - envVars.ENABLE_MV3 === 'true' + envVars.ENABLE_MV3 === 'true' || + envVars.ENABLE_MV3 === undefined || + envVars.ENABLE_MV3 === true ? mv3ScuttlingConfig : standardScuttlingConfig; const { events } = buildConfiguration; @@ -1191,81 +1130,18 @@ async function createBundle(buildConfiguration, { reloadOnChange }) { // nothing will consume pipeline, so let it flow pipeline.resume(); - await endOfStream(pipeline); + await finished(pipeline); // call the completion event to handle any post-processing events.emit('bundleDone'); } } -/** - * Sets environment variables to inject in the current build. - * - * @param {object} options - Build options. - * @param {BUILD_TARGETS} options.buildTarget - The current build target. - * @param {string} options.buildType - The current build type (e.g. "main", - * "flask", etc.). - * @param {string} options.version - The current version of the extension. - * @param options.activeBuild - * @param options.variables - * @param options.environment - */ -async function setEnvironmentVariables({ - buildTarget, - buildType, - activeBuild, - environment, - variables, - version, -}) { - const devMode = isDevBuild(buildTarget); - const testing = isTestBuild(buildTarget); - - variables.set({ - DEBUG: devMode || testing ? variables.getMaybe('DEBUG') : undefined, - EIP_4337_ENTRYPOINT: - variables.getMaybe('EIP_4337_ENTRYPOINT') || - (testing ? '0x18b06605539dc02ecD3f7AB314e38eB7c1dA5c9b' : undefined), - IN_TEST: testing, - INFURA_PROJECT_ID: getInfuraProjectId({ - buildType, - activeBuild, - variables, - environment, - testing, - }), - METAMASK_DEBUG: devMode || variables.getMaybe('METAMASK_DEBUG') === true, - METAMASK_BUILD_NAME: getBuildName({ - environment, - buildType, - }), - METAMASK_BUILD_APP_ID: getBuildAppId({ - buildType, - }), - METAMASK_BUILD_ICON: getBuildIcon({ - buildType, - }), - METAMASK_ENVIRONMENT: environment, - METAMASK_VERSION: version, - METAMASK_BUILD_TYPE: buildType, - NODE_ENV: devMode ? ENVIRONMENT.DEVELOPMENT : ENVIRONMENT.PRODUCTION, - PHISHING_WARNING_PAGE_URL: getPhishingWarningPageUrl({ - variables, - testing, - }), - SEGMENT_WRITE_KEY: getSegmentWriteKey({ - buildType, - activeBuild, - variables, - environment, - }), - }); -} - function renderJavaScriptLoader({ groupSet, commonSet, browserPlatforms, + shouldIncludeSnow, applyLavaMoat, destinationFileName, }) { @@ -1280,18 +1156,23 @@ function renderJavaScriptLoader({ ); const securityScripts = applyLavaMoat - ? ['./runtime-lavamoat.js', './lockdown-more.js', './policy-load.js'] + ? [ + './scripts/runtime-lavamoat.js', + './scripts/lockdown-more.js', + './scripts/policy-load.js', + ] : [ - './lockdown-install.js', - './lockdown-run.js', - './lockdown-more.js', - './runtime-cjs.js', + './scripts/lockdown-install.js', + './scripts/lockdown-run.js', + './scripts/lockdown-more.js', + './scripts/runtime-cjs.js', ]; const requiredScripts = [ - './snow.js', - './use-snow.js', - './sentry-install.js', + ...(shouldIncludeSnow + ? ['./scripts/snow.js', './scripts/use-snow.js'] + : []), + './scripts/sentry-install.js', ...securityScripts, ...jsBundles, ]; @@ -1313,6 +1194,7 @@ function renderJavaScriptLoader({ function renderHtmlFile({ htmlName, browserPlatforms, + shouldIncludeSnow, applyLavaMoat, isMMI, isTest, @@ -1322,11 +1204,21 @@ function renderHtmlFile({ 'build/scripts/renderHtmlFile - must specify "applyLavaMoat" option', ); } + if (shouldIncludeSnow === undefined) { + throw new Error( + 'build/scripts/renderHtmlFile - must specify "shouldIncludeSnow" option', + ); + } + const htmlFilePath = `./app/${htmlName}.html`; const htmlTemplate = readFileSync(htmlFilePath, 'utf8'); const eta = new Eta(); - const htmlOutput = eta.renderString(htmlTemplate, { isMMI, isTest }); + const htmlOutput = eta.renderString(htmlTemplate, { + isMMI, + isTest, + shouldIncludeSnow, + }); browserPlatforms.forEach((platform) => { const dest = `./dist/${platform}/${htmlName}.html`; // we dont have a way of creating async events atm diff --git a/development/build/set-environment-variables.js b/development/build/set-environment-variables.js new file mode 100644 index 000000000000..f8d96c34d76e --- /dev/null +++ b/development/build/set-environment-variables.js @@ -0,0 +1,216 @@ +const { readFileSync } = require('node:fs'); +const assert = require('node:assert'); +const { ENVIRONMENT } = require('./constants'); + +/** + * Sets environment variables to inject in the current build. + * + * @param {object} options - Build options. + * @param {string} options.buildName - The name of the build. + * @param {boolean} options.isDevBuild - Whether the build is a development build. + * @param {boolean} options.isTestBuild - Whether the build is a test build. + * @param {string} options.buildType - The current build type (e.g. "main", + * "flask", etc.). + * @param {string} options.version - The current version of the extension. + * @param {import('../lib/variables').Variables} options.variables + * @param {ENVIRONMENT[keyof ENVIRONMENT]} options.environment - The build environment. + */ +module.exports.setEnvironmentVariables = function setEnvironmentVariables({ + buildName, + isDevBuild, + isTestBuild, + buildType, + environment, + variables, + version, +}) { + variables.set({ + DEBUG: isDevBuild || isTestBuild ? variables.getMaybe('DEBUG') : undefined, + EIP_4337_ENTRYPOINT: isTestBuild + ? '0x18b06605539dc02ecD3f7AB314e38eB7c1dA5c9b' + : variables.getMaybe('EIP_4337_ENTRYPOINT'), + IN_TEST: isTestBuild, + INFURA_PROJECT_ID: getInfuraProjectId({ + buildType, + variables, + environment, + testing: isTestBuild, + }), + METAMASK_DEBUG: isDevBuild || variables.getMaybe('METAMASK_DEBUG') === true, + METAMASK_BUILD_NAME: buildName, + METAMASK_BUILD_APP_ID: getBuildAppId({ + buildType, + }), + METAMASK_BUILD_ICON: getBuildIcon({ + buildType, + }), + METAMASK_ENVIRONMENT: environment, + METAMASK_VERSION: version, + METAMASK_BUILD_TYPE: buildType, + NODE_ENV: isDevBuild ? ENVIRONMENT.DEVELOPMENT : ENVIRONMENT.PRODUCTION, + PHISHING_WARNING_PAGE_URL: getPhishingWarningPageUrl({ + variables, + testing: isTestBuild, + }), + SEGMENT_WRITE_KEY: getSegmentWriteKey({ + buildType, + variables, + environment, + }), + TEST_GAS_FEE_FLOWS: + isDevBuild && variables.getMaybe('TEST_GAS_FEE_FLOWS') === true, + }); +}; + +const BUILD_TYPES_TO_SVG_LOGO_PATH = { + main: './app/images/logo/metamask-fox.svg', + beta: './app/build-types/beta/images/logo/metamask-fox.svg', + flask: './app/build-types/flask/images/logo/metamask-fox.svg', + mmi: './app/build-types/mmi/images/logo/mmi-logo.svg', +}; + +/** + * Get the image data uri for the svg icon for the current build. + * + * @param {object} options - The build options. + * @param {string} options.buildType - The build type of the current build. + * @returns {string} The image data uri for the icon. + */ +function getBuildIcon({ buildType }) { + const svgLogoPath = + BUILD_TYPES_TO_SVG_LOGO_PATH[buildType] || + BUILD_TYPES_TO_SVG_LOGO_PATH.main; + // encode as base64 as its more space-efficient for most SVGs than a data uri + return `data:image/svg+xml;base64,${readFileSync(svgLogoPath, 'base64')}`; +} + +/** + * Get the app ID for the current build. Should be valid reverse FQDN. + * + * @param {object} options - The build options. + * @param {string} options.buildType - The build type of the current build. + * @returns {string} The build app ID. + */ +function getBuildAppId({ buildType }) { + const baseDomain = 'io.metamask'; + return buildType === 'main' ? baseDomain : `${baseDomain}.${buildType}`; +} + +/** + * Get the appropriate Infura project ID. + * + * @param {object} options - The Infura project ID options. + * @param {string} options.buildType - The current build type. + * @param {ENVIRONMENT[keyof ENVIRONMENT]} options.environment - The build environment. + * @param {boolean} options.testing - Whether this is a test build or not. + * @param options.variables + * @returns {string} The Infura project ID. + */ +function getInfuraProjectId({ buildType, variables, environment, testing }) { + const EMPTY_PROJECT_ID = '00000000000000000000000000000000'; + if (testing) { + return EMPTY_PROJECT_ID; + } else if (environment !== ENVIRONMENT.PRODUCTION) { + // Skip validation because this is unset on PRs from forks. + // For forks, return empty project ID if we don't have one. + if ( + !variables.isDefined('INFURA_PROJECT_ID') && + environment === ENVIRONMENT.PULL_REQUEST + ) { + return EMPTY_PROJECT_ID; + } + return variables.get('INFURA_PROJECT_ID'); + } + /** @type {string|undefined} */ + const infuraKeyReference = variables.get('INFURA_ENV_KEY_REF'); + assert( + typeof infuraKeyReference === 'string' && infuraKeyReference.length > 0, + `Build type "${buildType}" has improperly set INFURA_ENV_KEY_REF in builds.yml. Current value: "${infuraKeyReference}"`, + ); + /** @type {string|undefined} */ + const infuraProjectId = variables.get(infuraKeyReference); + assert( + typeof infuraProjectId === 'string' && infuraProjectId.length > 0, + `Infura Project ID environmental variable "${infuraKeyReference}" is set improperly.`, + ); + return infuraProjectId; +} + +/** + * Get the appropriate Segment write key. + * + * @param {object} options - The Segment write key options. + * @param {string} options.buildType - The current build type. + * @param {keyof ENVIRONMENT} options.environment - The current build environment. + * @param {import('../lib/variables').Variables} options.variables - Object containing all variables that modify the build pipeline + * @returns {string} The Segment write key. + */ +function getSegmentWriteKey({ buildType, variables, environment }) { + if (environment !== ENVIRONMENT.PRODUCTION) { + // Skip validation because this is unset on PRs from forks, and isn't necessary for development builds. + return variables.get('SEGMENT_WRITE_KEY'); + } + + const segmentKeyReference = variables.get('SEGMENT_WRITE_KEY_REF'); + assert( + typeof segmentKeyReference === 'string' && segmentKeyReference.length > 0, + `Build type "${buildType}" has improperly set SEGMENT_WRITE_KEY_REF in builds.yml. Current value: "${segmentKeyReference}"`, + ); + + const segmentWriteKey = variables.get(segmentKeyReference); + assert( + typeof segmentWriteKey === 'string' && segmentWriteKey.length > 0, + `Segment Write Key environmental variable "${segmentKeyReference}" is set improperly.`, + ); + return segmentWriteKey; +} + +/** + * Get the URL for the phishing warning page, if it has been set. + * + * @param {object} options - The phishing warning page options. + * @param {boolean} options.testing - Whether this is a test build or not. + * @param {import('../lib/variables').Variables} options.variables - Object containing all variables that modify the build pipeline + * @returns {string} The URL for the phishing warning page, or `undefined` if no URL is set. + */ +function getPhishingWarningPageUrl({ variables, testing }) { + let phishingWarningPageUrl = variables.get('PHISHING_WARNING_PAGE_URL'); + + assert( + phishingWarningPageUrl === null || + typeof phishingWarningPageUrl === 'string', + ); + if (phishingWarningPageUrl === null) { + phishingWarningPageUrl = testing + ? 'http://localhost:9999/' + : `https://metamask.github.io/phishing-warning/v${ + // eslint-disable-next-line node/global-require + require('@metamask/phishing-warning/package.json').version + }/`; + } + + // We add a hash/fragment to the URL dynamically, so we need to ensure it + // has a valid pathname to append a hash to. + const normalizedUrl = phishingWarningPageUrl.endsWith('/') + ? phishingWarningPageUrl + : `${phishingWarningPageUrl}/`; + + let phishingWarningPageUrlObject; + try { + // eslint-disable-next-line no-new + phishingWarningPageUrlObject = new URL(normalizedUrl); + } catch (error) { + throw new Error( + `Invalid phishing warning page URL: '${normalizedUrl}'`, + error, + ); + } + if (phishingWarningPageUrlObject.hash) { + // The URL fragment must be set dynamically + throw new Error( + `URL fragment not allowed in phishing warning page URL: '${normalizedUrl}'`, + ); + } + + return normalizedUrl; +} diff --git a/development/build/static.js b/development/build/static.js index c8eb7d6d5ef2..ecff5d2501c0 100644 --- a/development/build/static.js +++ b/development/build/static.js @@ -147,54 +147,54 @@ function getCopyTargets( pattern: `*.css`, dest: ``, }, - { - src: `./app/loading.html`, - dest: `loading.html`, - }, - { - src: shouldIncludeSnow - ? `./node_modules/@lavamoat/snow/snow.prod.js` - : EMPTY_JS_FILE, - dest: `snow.js`, - }, - { - src: shouldIncludeSnow ? `./app/scripts/use-snow.js` : EMPTY_JS_FILE, - dest: `use-snow.js`, - }, + ...(shouldIncludeSnow + ? [ + { + src: shouldIncludeSnow + ? `./node_modules/@lavamoat/snow/snow.prod.js` + : EMPTY_JS_FILE, + dest: `scripts/snow.js`, + }, + { + src: `./app/scripts/use-snow.js`, + dest: `scripts/use-snow.js`, + }, + ] + : []), { src: shouldIncludeLockdown ? getPathInsideNodeModules('ses', 'dist/lockdown.umd.min.js') : EMPTY_JS_FILE, - dest: `lockdown-install.js`, + dest: `scripts/lockdown-install.js`, }, { src: './app/scripts/init-globals.js', - dest: 'init-globals.js', + dest: 'scripts/init-globals.js', }, { src: './app/scripts/load-app.js', - dest: 'load-app.js', + dest: 'scripts/load-app.js', }, { src: shouldIncludeLockdown ? `./app/scripts/lockdown-run.js` : EMPTY_JS_FILE, - dest: `lockdown-run.js`, + dest: `scripts/lockdown-run.js`, }, { src: shouldIncludeLockdown ? `./app/scripts/lockdown-more.js` : EMPTY_JS_FILE, - dest: `lockdown-more.js`, + dest: `scripts/lockdown-more.js`, }, { src: getPathInsideNodeModules('@lavamoat/lavapack', 'src/runtime-cjs.js'), - dest: `runtime-cjs.js`, + dest: `scripts/runtime-cjs.js`, pattern: '', }, { src: getPathInsideNodeModules('@lavamoat/lavapack', 'src/runtime.js'), - dest: `runtime-lavamoat.js`, + dest: `scripts/runtime-lavamoat.js`, pattern: '', }, { @@ -202,13 +202,38 @@ function getCopyTargets( pattern: `*.html`, dest: '', }, + ...(process.env.ENABLE_MV3 === 'true' || + process.env.ENABLE_MV3 === undefined + ? [ + { + src: getPathInsideNodeModules( + '@metamask/snaps-execution-environments', + 'dist/browserify/iframe/index.html', + ), + dest: `snaps/index.html`, + pattern: '', + }, + { + src: getPathInsideNodeModules( + '@metamask/snaps-execution-environments', + 'dist/browserify/iframe/bundle.js', + ), + dest: `snaps/bundle.js`, + pattern: '', + }, + ] + : []), ]; if (activeFeatures.includes('blockaid')) { allCopyTargets.push({ src: getPathInsideNodeModules('@blockaid/ppom_release', '/'), pattern: '*.wasm', - dest: '', + dest: + process.env.ENABLE_MV3 === 'true' || + process.env.ENABLE_MV3 === undefined + ? 'scripts/' + : '', }); } diff --git a/development/build/styles.js b/development/build/styles.js index fd47582cac61..a8ac03c96ea5 100644 --- a/development/build/styles.js +++ b/development/build/styles.js @@ -6,7 +6,7 @@ const watch = require('gulp-watch'); const sourcemaps = require('gulp-sourcemaps'); const rtlcss = require('postcss-rtlcss'); const postcss = require('gulp-postcss'); -const pump = pify(require('pump')); +const pipeline = pify(require('readable-stream').pipeline); const sass = require('sass-embedded'); const gulpSass = require('gulp-sass')(sass); const { TASKS } = require('./constants'); @@ -64,7 +64,7 @@ function createStyleTasks({ livereload }) { } async function buildScssPipeline(src, dest, devMode) { - await pump( + await pipeline( ...[ // pre-process gulp.src(src), diff --git a/development/build/task.js b/development/build/task.js index 1b28a15f6783..cbbc1ea22578 100644 --- a/development/build/task.js +++ b/development/build/task.js @@ -51,7 +51,14 @@ function createTask(taskName, taskFn) { function runInChildProcess( task, - { applyLavaMoat, buildType, isLavaMoat, policyOnly, shouldLintFenceFiles }, + { + shouldIncludeSnow, + applyLavaMoat, + buildType, + isLavaMoat, + policyOnly, + shouldLintFenceFiles, + }, ) { const taskName = typeof task === 'string' ? task : task.taskName; if (!taskName) { @@ -68,6 +75,7 @@ function runInChildProcess( // LavaMoat if the parent process also ran in LavaMoat. isLavaMoat ? 'build' : 'build:dev', taskName, + `--snow=${shouldIncludeSnow ? 'true' : 'false'}`, `--apply-lavamoat=${applyLavaMoat ? 'true' : 'false'}`, `--build-type=${buildType}`, `--lint-fence-files=${shouldLintFenceFiles ? 'true' : 'false'}`, diff --git a/development/build/utils.js b/development/build/utils.js index 07349c88db28..746290fb8e2b 100644 --- a/development/build/utils.js +++ b/development/build/utils.js @@ -5,14 +5,6 @@ const { capitalize } = require('lodash'); const { loadBuildTypesConfig } = require('../lib/build-type'); const { BUILD_TARGETS, ENVIRONMENT } = require('./constants'); -const BUILD_TYPES_TO_SVG_LOGO_PATH = { - main: './app/images/logo/metamask-fox.svg', - beta: './app/build-types/beta/images/logo/metamask-fox.svg', - flask: './app/build-types/flask/images/logo/metamask-fox.svg', - mmi: './app/build-types/mmi/images/logo/mmi-logo.svg', - desktop: './app/build-types/desktop/images/logo/metamask-fox.svg', -}; - /** * Returns whether the current build is a development build or not. * @@ -261,32 +253,6 @@ function getBuildName({ return name; } -/** - * Get the app ID for the current build. Should be valid reverse FQDN. - * - * @param {object} options - The build options. - * @param {string} options.buildType - The build type of the current build. - * @returns {string} The build app ID. - */ -function getBuildAppId({ buildType }) { - const baseDomain = 'io.metamask'; - return buildType === 'main' ? baseDomain : `${baseDomain}.${buildType}`; -} - -/** - * Get the image data uri for the svg icon for the current build. - * - * @param {object} options - The build options. - * @param {string} options.buildType - The build type of the current build. - * @returns {string} The image data uri for the icon. - */ -function getBuildIcon({ buildType }) { - const svgLogoPath = - BUILD_TYPES_TO_SVG_LOGO_PATH[buildType] || - BUILD_TYPES_TO_SVG_LOGO_PATH.main; - const svg = readFileSync(svgLogoPath, 'utf8'); - return `data:image/svg+xml,${encodeURIComponent(svg)}`; -} /** * Takes the given JavaScript file at `filePath` and replaces its contents with * a script that injects the original file contents into the document in which @@ -306,8 +272,6 @@ function makeSelfInjecting(filePath) { module.exports = { getBrowserVersionMap, getBuildName, - getBuildAppId, - getBuildIcon, getEnvironment, isDevBuild, isTestBuild, diff --git a/development/charts/flamegraph/chart/index.html b/development/charts/flamegraph/chart/index.html index 7afe9f9d0dcb..ce53076ad9e4 100644 --- a/development/charts/flamegraph/chart/index.html +++ b/development/charts/flamegraph/chart/index.html @@ -9,7 +9,7 @@ rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" /> - +
- + diff --git a/development/ts-migration-dashboard/common/build-module-partitions.ts b/development/ts-migration-dashboard/common/build-module-partitions.ts index aa58568b3d58..14fa31900eed 100644 --- a/development/ts-migration-dashboard/common/build-module-partitions.ts +++ b/development/ts-migration-dashboard/common/build-module-partitions.ts @@ -1,7 +1,7 @@ import fs from 'fs'; import path from 'path'; import fg from 'fast-glob'; -import madge from 'madge'; +import madge from '@lgbot/madge'; import { ROOT_DIRECTORY_PATH, ENTRYPOINT_PATTERNS, diff --git a/development/ts-migration-dashboard/common/partitions-file.ts b/development/ts-migration-dashboard/common/partitions-file.ts index e14c9a24fc12..4b754b715cfc 100644 --- a/development/ts-migration-dashboard/common/partitions-file.ts +++ b/development/ts-migration-dashboard/common/partitions-file.ts @@ -1,40 +1,19 @@ +import { mkdirSync, writeFileSync } from 'fs'; +import { dirname, join } from 'path'; import { ModulePartition } from './build-module-partitions'; import { INTERMEDIATE_BUILD_DIRECTORY_PATH } from './constants'; -// The `brfs` transform for browserify calls `fs.readLineSync` and -// `path.resolve` at build time and inlines file contents into the source code. -// To accomplish this we have to bring in `fs` and `path` using `require` and -// not `import`. This is weird in a TypeScript file, and typescript-eslint -// (rightly) complains about this, but it's actually okay because the above -// `import` lines will actually get turned into `require`s anyway before passing -// through the rest of browserify. However, `brfs` should handle this. There is -// an active bug for this, but there isn't a known workaround yet: -// -/* eslint-disable-next-line @typescript-eslint/no-require-imports,@typescript-eslint/no-var-requires */ -const fs = require('fs'); -/* eslint-disable-next-line @typescript-eslint/no-require-imports,@typescript-eslint/no-var-requires */ -const path = require('path'); - -export const PARTITIONS_FILE = path.join( +export const PARTITIONS_FILE = join( INTERMEDIATE_BUILD_DIRECTORY_PATH, 'partitions.json', ); export function readPartitionsFile() { - const content = fs.readFileSync( - // As this function is called within the app code, which is compiled by - // Browserify and not executed by Node, this needs to be here — it cannot be - // extracted — for the reasons explained above. - path.resolve(__dirname, '../build/intermediate/partitions.json'), - { encoding: 'utf-8' }, - ); - return JSON.parse(content) as ModulePartition[]; + // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires + return require('../build/intermediate/partitions.json') as ModulePartition[]; } export function writePartitionsFile(partitions: ModulePartition[]) { - fs.mkdirSync(path.dirname(PARTITIONS_FILE), { recursive: true }); - return fs.writeFileSync( - PARTITIONS_FILE, - JSON.stringify(partitions, null, ' '), - ); + mkdirSync(dirname(PARTITIONS_FILE), { recursive: true }); + return writeFileSync(PARTITIONS_FILE, JSON.stringify(partitions, null, ' ')); } diff --git a/development/ts-migration-dashboard/files-to-convert.json b/development/ts-migration-dashboard/files-to-convert.json index 9f63dc841229..ed5615e8c9d0 100644 --- a/development/ts-migration-dashboard/files-to-convert.json +++ b/development/ts-migration-dashboard/files-to-convert.json @@ -1,7 +1,5 @@ [ ".eslintrc.js", - "app/scripts/account-import-strategies/account-import-strategies.test.js", - "app/scripts/account-import-strategies/index.js", "app/scripts/background.js", "app/scripts/constants/contracts.js", "app/scripts/constants/on-ramp.js", @@ -318,7 +316,6 @@ "test/lib/mock-encryptor.js", "test/lib/render-helpers.js", "test/lib/tick.js", - "test/lib/wait-until-called.js", "test/mocks/permissions.js", "test/stub/provider.js", "test/stub/tx-meta-stub.js", @@ -947,10 +944,6 @@ "ui/components/ui/show-hide-toggle/show-hide-toggle.js", "ui/components/ui/show-hide-toggle/show-hide-toggle.stories.js", "ui/components/ui/show-hide-toggle/show-hide-toggle.test.js", - "ui/components/ui/site-icon/index.js", - "ui/components/ui/site-icon/site-icon.js", - "ui/components/ui/site-icon/site-icon.stories.js", - "ui/components/ui/site-icon/site-icon.test.js", "ui/components/ui/site-origin/index.js", "ui/components/ui/site-origin/site-origin.js", "ui/components/ui/site-origin/site-origin.stories.js", @@ -1076,7 +1069,6 @@ "ui/helpers/utils/metrics.js", "ui/helpers/utils/optimism/buildUnserializedTransaction.js", "ui/helpers/utils/optimism/buildUnserializedTransaction.test.js", - "ui/helpers/utils/optimism/fetchEstimatedL1Fee.js", "ui/helpers/utils/permission.js", "ui/helpers/utils/settings-search.js", "ui/helpers/utils/settings-search.test.js", diff --git a/development/ts-migration-dashboard/scripts/build-app.ts b/development/ts-migration-dashboard/scripts/build-app.ts index 8a78980c09ae..ed1c8e03f58a 100644 --- a/development/ts-migration-dashboard/scripts/build-app.ts +++ b/development/ts-migration-dashboard/scripts/build-app.ts @@ -5,8 +5,10 @@ import { hideBin } from 'yargs/helpers'; import chokidar from 'chokidar'; import browserify from 'browserify'; import pify from 'pify'; -import endOfStream from 'end-of-stream'; -import pump from 'pump'; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-expect-error types/readable-stream.d.ts does not get picked up by ts-node +import { finished, pipeline } from 'readable-stream'; import gulp from 'gulp'; import gulpSass from 'gulp-sass'; import * as sass from 'sass-embedded'; @@ -25,7 +27,7 @@ import { FINAL_BUILD_DIRECTORY_PATH, } from '../common/constants'; -const promisifiedPump = pify(pump); +const promisifiedPipeline = pify(pipeline); main().catch((error) => { console.error(error); @@ -67,15 +69,13 @@ async function compileScripts(src: string, dest: string) { bundler.add(src); // Run TypeScript files through Babel bundler.transform('babelify', { extensions }); - // Inline `fs.readFileSync` files - bundler.transform('brfs'); const bundleStream = bundler.bundle(); bundleStream.pipe(fs.createWriteStream(dest)); bundleStream.on('error', (error: unknown) => { console.error(`Couldn't compile scripts: ${error}`); }); - await pify(endOfStream(bundleStream)); + await pify(finished)(bundleStream); console.log( `- Compiled scripts: ${path.relative( @@ -92,7 +92,7 @@ async function compileScripts(src: string, dest: string) { * @param dest - The path to the compiled CSS file. */ async function compileStylesheets(src: string, dest: string): Promise { - await promisifiedPump( + await promisifiedPipeline( gulp.src(src), sourcemaps.init(), gulpSass(sass)().on('error', (error: unknown) => { diff --git a/development/ts-migration-dashboard/scripts/write-list-of-files-to-convert.ts b/development/ts-migration-dashboard/scripts/write-list-of-files-to-convert.ts index ead0cb218716..4fd95a8366e3 100644 --- a/development/ts-migration-dashboard/scripts/write-list-of-files-to-convert.ts +++ b/development/ts-migration-dashboard/scripts/write-list-of-files-to-convert.ts @@ -1,7 +1,7 @@ import path from 'path'; import fs from 'fs'; import fg from 'fast-glob'; -import madge from 'madge'; +import madge from '@lgbot/madge'; import { ROOT_DIRECTORY_PATH, ENTRYPOINT_PATTERNS, diff --git a/development/verify-locale-strings.js b/development/verify-locale-strings.js index 2a1e73cb8557..fd679815d52f 100755 --- a/development/verify-locale-strings.js +++ b/development/verify-locale-strings.js @@ -192,6 +192,7 @@ async function verifyEnglishLocale() { 'app/scripts/constants/**/*.js', 'app/scripts/constants/**/*.ts', 'app/scripts/platforms/**/*.js', + 'app/scripts/controllers/push-platform-notifications/utils/get-notification-message.ts', ], { ignore: [...globsToStrictSearch, testGlob], diff --git a/jest.config.js b/jest.config.js index b5c4d27fb59e..f52466a9d183 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,25 +1,8 @@ module.exports = { collectCoverageFrom: [ - '/app/scripts/constants/error-utils.js', - '/app/scripts/controllers/permissions/**/*.js', - '/app/scripts/controllers/sign.ts', - '/app/scripts/controllers/decrypt-message.ts', - '/app/scripts/controllers/transactions/etherscan.ts', - '/app/scripts/controllers/transactions/EtherscanRemoteTransactionSource.ts', - '/app/scripts/controllers/transactions/IncomingTransactionHelper.ts', - '/app/scripts/controllers/preferences.js', - '/app/scripts/flask/**/*.js', - '/app/scripts/lib/**/*.(js|ts)', - '/app/scripts/lib/createRPCMethodTrackingMiddleware.js', - '/app/scripts/metamask-controller.js', - '/app/scripts/migrations/*.js', - '/app/scripts/migrations/*.ts', - '!/app/scripts/migrations/*.test.(js|ts)', - '/app/scripts/platforms/*.js', + '/app/scripts/**/*.(js|ts|tsx)', '/shared/**/*.(js|ts|tsx)', '/ui/**/*.(js|ts|tsx)', - '/development/fitness-functions/**/*.test.(js|ts|tsx)', - '/test/e2e/helpers.test.js', ], coverageDirectory: './coverage', coveragePathIgnorePatterns: ['.stories.*', '.snap'], @@ -40,24 +23,8 @@ module.exports = { setupFiles: ['/test/setup.js', '/test/env.js'], setupFilesAfterEnv: ['/test/jest/setup.js'], testMatch: [ - '/app/scripts/constants/error-utils.test.js', - '/app/scripts/controllers/app-state.test.js', - '/app/scripts/controllers/transactions/etherscan.test.ts', - '/app/scripts/controllers/transactions/EtherscanRemoteTransactionSource.test.ts', - '/app/scripts/controllers/transactions/IncomingTransactionHelper.test.ts', - '/app/scripts/controllers/mmi-controller.test.ts', - '/app/scripts/controllers/permissions/**/*.test.js', - '/app/scripts/controllers/preferences.test.js', - '/app/scripts/controllers/sign.test.ts', - '/app/scripts/controllers/decrypt-message.test.ts', - '/app/scripts/flask/**/*.test.js', - '/app/scripts/lib/**/*.test.(js|ts)', - '/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js', - '/app/scripts/metamask-controller.test.js', - '/app/scripts/migrations/*.test.(js|ts)', - '/app/scripts/platforms/*.test.js', - '/app/scripts/translate.test.ts', - '/shared/**/*.test.(js|ts)', + '/app/scripts/**/*.test.(js|ts|tsx)', + '/shared/**/*.test.(js|ts|tsx)', '/ui/**/*.test.(js|ts|tsx)', '/development/fitness-functions/**/*.test.(js|ts|tsx)', '/test/e2e/helpers.test.js', diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index d852d2cc8c24..8415dbd75002 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -5,6 +5,11 @@ "regeneratorRuntime": "write" } }, + "@contentful/rich-text-html-renderer": { + "globals": { + "SuppressedError": true + } + }, "@ensdomains/content-hash": { "globals": { "console.warn": true @@ -108,30 +113,30 @@ "browserify>util": true } }, - "@ethereumjs/common": { + "@ethereumjs/tx": { + "packages": { + "@ethereumjs/tx>@ethereumjs/common": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true + } + }, + "@ethereumjs/tx>@ethereumjs/common": { "packages": { - "@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, "webpack>events": true } }, - "@ethereumjs/common>crc-32": { + "@ethereumjs/tx>@ethereumjs/common>crc-32": { "globals": { "DO_NOT_EXPORT_CRC": true, "define": true } }, - "@ethereumjs/tx": { - "packages": { - "@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethereumjs/tx>ethereum-cryptography": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true - } - }, "@ethereumjs/tx>@ethereumjs/rlp": { "globals": { "TextEncoder": true @@ -184,13 +189,7 @@ "TextEncoder": true }, "packages": { - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true } }, "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { @@ -201,9 +200,23 @@ }, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": { "packages": { - "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, - "@metamask/utils>@scure/base": true, - "@noble/hashes": true + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/curves": true, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true, + "@metamask/utils>@scure/base": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/curves": { + "globals": { + "TextEncoder": true + }, + "packages": { + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethersproject/abi": { @@ -214,12 +227,12 @@ "@ethersproject/abi>@ethersproject/address": true, "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/abi>@ethersproject/constants": true, - "@ethersproject/abi>@ethersproject/hash": true, "@ethersproject/abi>@ethersproject/keccak256": true, "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/abi>@ethersproject/strings": true, - "@ethersproject/bignumber": true + "@ethersproject/bignumber": true, + "@ethersproject/hash": true } }, "@ethersproject/abi>@ethersproject/address": { @@ -241,18 +254,6 @@ "@ethersproject/bignumber": true } }, - "@ethersproject/abi>@ethersproject/hash": { - "packages": { - "@ethersproject/abi>@ethersproject/address": true, - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/keccak256": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/abi>@ethersproject/strings": true, - "@ethersproject/bignumber": true, - "@ethersproject/providers>@ethersproject/base64": true - } - }, "@ethersproject/abi>@ethersproject/keccak256": { "packages": { "@ethersproject/abi>@ethersproject/bytes": true, @@ -294,9 +295,36 @@ "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/bignumber": true, - "@ethersproject/hdnode>@ethersproject/abstract-signer": true, + "@ethersproject/hash>@ethersproject/abstract-signer": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@metamask/test-bundler>@ethersproject/abstract-provider": true + "@ethersproject/wallet>@ethersproject/abstract-provider": true + } + }, + "@ethersproject/hash": { + "packages": { + "@ethersproject/abi>@ethersproject/address": true, + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/keccak256": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/abi>@ethersproject/strings": true, + "@ethersproject/bignumber": true, + "@ethersproject/hash>@ethersproject/base64": true + } + }, + "@ethersproject/hash>@ethersproject/abstract-signer": { + "packages": { + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true + } + }, + "@ethersproject/hash>@ethersproject/base64": { + "globals": { + "atob": true, + "btoa": true + }, + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true } }, "@ethersproject/hdnode": { @@ -314,12 +342,6 @@ "@ethersproject/hdnode>@ethersproject/wordlists": true } }, - "@ethersproject/hdnode>@ethersproject/abstract-signer": { - "packages": { - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true - } - }, "@ethersproject/hdnode>@ethersproject/basex": { "packages": { "@ethersproject/abi>@ethersproject/bytes": true, @@ -363,10 +385,10 @@ "@ethersproject/hdnode>@ethersproject/wordlists": { "packages": { "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/hash": true, "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/abi>@ethersproject/strings": true + "@ethersproject/abi>@ethersproject/strings": true, + "@ethersproject/hash": true } }, "@ethersproject/providers": { @@ -383,39 +405,26 @@ "@ethersproject/abi>@ethersproject/address": true, "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/abi>@ethersproject/constants": true, - "@ethersproject/abi>@ethersproject/hash": true, "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/abi>@ethersproject/strings": true, "@ethersproject/bignumber": true, - "@ethersproject/hdnode>@ethersproject/abstract-signer": true, + "@ethersproject/hash": true, + "@ethersproject/hash>@ethersproject/abstract-signer": true, + "@ethersproject/hash>@ethersproject/base64": true, "@ethersproject/hdnode>@ethersproject/basex": true, "@ethersproject/hdnode>@ethersproject/sha2": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/base64": true, - "@ethersproject/providers>@ethersproject/random": true, "@ethersproject/providers>@ethersproject/web": true, "@ethersproject/providers>bech32": true, - "@metamask/test-bundler>@ethersproject/abstract-provider": true, + "@ethersproject/wallet>@ethersproject/abstract-provider": true, + "@ethersproject/wallet>@ethersproject/random": true, "@metamask/test-bundler>@ethersproject/networks": true } }, - "@ethersproject/providers>@ethersproject/base64": { - "globals": { - "atob": true, - "btoa": true - }, - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true - } - }, "@ethersproject/providers>@ethersproject/random": { "globals": { "crypto.getRandomValues": true - }, - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true } }, "@ethersproject/providers>@ethersproject/rlp": { @@ -435,7 +444,59 @@ "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/abi>@ethersproject/strings": true, - "@ethersproject/providers>@ethersproject/base64": true + "@ethersproject/hash>@ethersproject/base64": true + } + }, + "@ethersproject/wallet": { + "packages": { + "@ethersproject/abi>@ethersproject/address": true, + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/keccak256": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/hash": true, + "@ethersproject/hash>@ethersproject/abstract-signer": true, + "@ethersproject/hdnode": true, + "@ethersproject/hdnode>@ethersproject/signing-key": true, + "@ethersproject/hdnode>@ethersproject/transactions": true, + "@ethersproject/wallet>@ethersproject/abstract-provider": true, + "@ethersproject/wallet>@ethersproject/json-wallets": true, + "@ethersproject/wallet>@ethersproject/random": true + } + }, + "@ethersproject/wallet>@ethersproject/abstract-provider": { + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/bignumber": true + } + }, + "@ethersproject/wallet>@ethersproject/json-wallets": { + "packages": { + "@ethersproject/abi>@ethersproject/address": true, + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/keccak256": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/abi>@ethersproject/strings": true, + "@ethersproject/hdnode": true, + "@ethersproject/hdnode>@ethersproject/pbkdf2": true, + "@ethersproject/hdnode>@ethersproject/transactions": true, + "@ethersproject/wallet>@ethersproject/json-wallets>aes-js": true, + "@ethersproject/wallet>@ethersproject/random": true, + "ethereumjs-util>ethereum-cryptography>scrypt-js": true + } + }, + "@ethersproject/wallet>@ethersproject/json-wallets>aes-js": { + "globals": { + "define": true + } + }, + "@ethersproject/wallet>@ethersproject/random": { + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/logger": true } }, "@keystonehq/bc-ur-registry-eth": { @@ -453,9 +514,10 @@ }, "packages": { "@ngraveio/bc-ur": true, + "@trezor/connect-web>tslib": true, "browserify>buffer": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, - "mockttp>graphql-tag>tslib": true + "ganache>abstract-level>buffer": true } }, "@keystonehq/metamask-airgapped-keyring": { @@ -464,8 +526,8 @@ "@keystonehq/bc-ur-registry-eth": true, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, - "@keystonehq/metamask-airgapped-keyring>rlp": true, "browserify>buffer": true, + "ethereumjs-util>rlp": true, "uuid": true, "webpack>events": true } @@ -475,33 +537,65 @@ "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "@keystonehq/bc-ur-registry-eth": true, + "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, - "eth-lattice-keyring>rlp": true, "uuid": true } }, + "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": { + "globals": { + "TextEncoder": true + } + }, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": { "packages": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": true, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": true, - "@metamask/safe-event-emitter": true, "stream-browserify": true } }, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": { + "globals": { + "setTimeout": true + }, + "packages": { + "webpack>events": true + } + }, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": { "packages": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream": true, "browserify>process": true, "browserify>util": true, - "readable-stream": true, "watchify>xtend": true } }, - "@keystonehq/metamask-airgapped-keyring>rlp": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream": { + "packages": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>isarray": true, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": true, + "browserify>browser-resolve": true, + "browserify>process": true, + "browserify>timers-browserify": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true, + "webpack>events": true + } + }, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": { "packages": { - "bn.js": true, "browserify>buffer": true } }, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": { + "packages": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true + } + }, "@lavamoat/lavadome-react": { "globals": { "Document.prototype": true, @@ -702,25 +796,43 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/base-controller": true, + "@metamask/accounts-controller>@metamask/base-controller": true, + "@metamask/accounts-controller>@metamask/keyring-api": true, "@metamask/eth-snap-keyring": true, - "@metamask/keyring-api": true, "@metamask/keyring-controller": true, + "@metamask/snaps-utils": true, + "@metamask/utils": true, "uuid": true } }, - "@metamask/address-book-controller": { + "@metamask/accounts-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, "packages": { - "@metamask/address-book-controller>@metamask/base-controller": true, - "@metamask/address-book-controller>@metamask/controller-utils": true + "immer": true } }, - "@metamask/address-book-controller>@metamask/base-controller": { + "@metamask/accounts-controller>@metamask/keyring-api": { "globals": { - "setTimeout": true + "URL": true }, "packages": { - "immer": true + "@metamask/accounts-controller>@metamask/keyring-api>uuid": true, + "@metamask/keyring-api>bech32": true, + "@metamask/utils": true, + "superstruct": true + } + }, + "@metamask/accounts-controller>@metamask/keyring-api>uuid": { + "globals": { + "crypto": true + } + }, + "@metamask/address-book-controller": { + "packages": { + "@metamask/address-book-controller>@metamask/controller-utils": true, + "@metamask/base-controller": true } }, "@metamask/address-book-controller>@metamask/controller-utils": { @@ -731,32 +843,14 @@ "setTimeout": true }, "packages": { - "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": true, - "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, + "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true - } - }, - "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, - "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": { - "packages": { - "@metamask/ethjs>ethjs-abi>number-to-bn": true, - "bn.js": true + "eth-ens-namehash": true } }, "@metamask/announcement-controller": { @@ -765,6 +859,9 @@ } }, "@metamask/announcement-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, "packages": { "immer": true } @@ -774,9 +871,17 @@ "console.info": true }, "packages": { + "@metamask/approval-controller>@metamask/base-controller": true, "@metamask/approval-controller>nanoid": true, - "@metamask/base-controller": true, - "@metamask/providers>@metamask/rpc-errors": true + "@metamask/rpc-errors": true + } + }, + "@metamask/approval-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true } }, "@metamask/approval-controller>nanoid": { @@ -789,6 +894,7 @@ "AbortController": true, "Headers": true, "URL": true, + "URLSearchParams": true, "clearInterval": true, "clearTimeout": true, "console.error": true, @@ -803,6 +909,7 @@ "@ethersproject/providers": true, "@metamask/abi-utils": true, "@metamask/assets-controllers>@metamask/polling-controller": true, + "@metamask/assets-controllers>async-mutex": true, "@metamask/assets-controllers>cockatiel": true, "@metamask/assets-controllers>multiformats": true, "@metamask/base-controller": true, @@ -810,8 +917,7 @@ "@metamask/controller-utils": true, "@metamask/eth-query": true, "@metamask/metamask-eth-abis": true, - "@metamask/name-controller>async-mutex": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/utils": true, "bn.js": true, "lodash": true, @@ -832,6 +938,14 @@ "uuid": true } }, + "@metamask/assets-controllers>async-mutex": { + "globals": { + "setTimeout": true + }, + "packages": { + "@trezor/connect-web>tslib": true + } + }, "@metamask/assets-controllers>cockatiel": { "globals": { "AbortController": true, @@ -901,7 +1015,8 @@ "console.log": true }, "packages": { - "@metamask/controller-utils>@spruceid/siwe-parser>apg-js": true + "@metamask/controller-utils>@spruceid/siwe-parser>apg-js": true, + "@noble/hashes": true } }, "@metamask/controller-utils>@spruceid/siwe-parser>apg-js": { @@ -932,21 +1047,38 @@ "packages": { "@ethersproject/providers": true, "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@metamask/ens-controller>@metamask/controller-utils": true, "@metamask/utils": true, - "ethereum-ens-network-map": true, "punycode": true } }, + "@metamask/ens-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/eth-json-rpc-filters": { "globals": { "console.error": true }, "packages": { "@metamask/eth-json-rpc-filters>@metamask/eth-query": true, - "@metamask/eth-json-rpc-filters>@metamask/safe-event-emitter": true, - "@metamask/name-controller>async-mutex": true, - "@metamask/providers>@metamask/json-rpc-engine": true, + "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine": true, + "@metamask/eth-json-rpc-filters>async-mutex": true, + "@metamask/safe-event-emitter": true, "pify": true } }, @@ -956,12 +1088,19 @@ "watchify>xtend": true } }, - "@metamask/eth-json-rpc-filters>@metamask/safe-event-emitter": { + "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine": { + "packages": { + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true + } + }, + "@metamask/eth-json-rpc-filters>async-mutex": { "globals": { "setTimeout": true }, "packages": { - "webpack>events": true + "@trezor/connect-web>tslib": true } }, "@metamask/eth-json-rpc-middleware": { @@ -971,52 +1110,33 @@ "setTimeout": true }, "packages": { + "@metamask/eth-json-rpc-middleware>@metamask/json-rpc-engine": true, "@metamask/eth-json-rpc-middleware>safe-stable-stringify": true, "@metamask/eth-sig-util": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/utils": true, "pify": true, "sass-loader>klona": true } }, - "@metamask/eth-keyring-controller": { - "globals": { - "console.error": true - }, + "@metamask/eth-json-rpc-middleware>@metamask/eth-json-rpc-provider": { "packages": { - "@metamask/browser-passworder": true, - "@metamask/eth-keyring-controller>@metamask/obs-store": true, - "@metamask/eth-sig-util": true, - "@metamask/keyring-controller>@metamask/eth-hd-keyring": true, - "@metamask/keyring-controller>@metamask/eth-simple-keyring": true, - "@metamask/utils": true, - "webpack>events": true - } - }, - "@metamask/eth-keyring-controller>@metamask/obs-store": { - "packages": { - "@metamask/eth-keyring-controller>@metamask/obs-store>@metamask/safe-event-emitter": true, - "@metamask/eth-keyring-controller>@metamask/obs-store>readable-stream": true + "@metamask/eth-json-rpc-middleware>@metamask/eth-json-rpc-provider>@metamask/json-rpc-engine": true, + "@metamask/safe-event-emitter": true } }, - "@metamask/eth-keyring-controller>@metamask/obs-store>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, + "@metamask/eth-json-rpc-middleware>@metamask/eth-json-rpc-provider>@metamask/json-rpc-engine": { "packages": { - "webpack>events": true + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true } }, - "@metamask/eth-keyring-controller>@metamask/obs-store>readable-stream": { + "@metamask/eth-json-rpc-middleware>@metamask/json-rpc-engine": { "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true } }, "@metamask/eth-ledger-bridge-keyring": { @@ -1076,25 +1196,19 @@ }, "@metamask/eth-snap-keyring": { "globals": { + "URL": true, "console.error": true }, "packages": { "@ethereumjs/tx": true, "@metamask/eth-sig-util": true, - "@metamask/eth-snap-keyring>@metamask/keyring-api": true, "@metamask/eth-snap-keyring>uuid": true, + "@metamask/keyring-api": true, "@metamask/utils": true, "superstruct": true, "webpack>events": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-api": { - "packages": { - "@metamask/eth-snap-keyring>uuid": true, - "@metamask/utils": true, - "superstruct": true - } - }, "@metamask/eth-snap-keyring>uuid": { "globals": { "crypto": true @@ -1106,21 +1220,26 @@ }, "packages": { "@babel/runtime": true, - "@metamask/eth-token-tracker>@metamask/safe-event-emitter": true, + "@metamask/eth-token-tracker>@metamask/eth-block-tracker": true, "@metamask/eth-token-tracker>deep-equal": true, - "@metamask/eth-token-tracker>eth-block-tracker": true, "@metamask/ethjs-contract": true, "@metamask/ethjs-query": true, + "@metamask/safe-event-emitter": true, "bn.js": true, "human-standard-token-abi": true } }, - "@metamask/eth-token-tracker>@metamask/safe-event-emitter": { + "@metamask/eth-token-tracker>@metamask/eth-block-tracker": { "globals": { + "clearTimeout": true, + "console.error": true, "setTimeout": true }, "packages": { - "webpack>events": true + "@metamask/eth-query>json-rpc-random-id": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true, + "pify": true } }, "@metamask/eth-token-tracker>deep-equal": { @@ -1211,27 +1330,6 @@ "string.prototype.matchall>get-intrinsic": true } }, - "@metamask/eth-token-tracker>eth-block-tracker": { - "globals": { - "clearTimeout": true, - "console.error": true, - "setTimeout": true - }, - "packages": { - "@metamask/eth-query>json-rpc-random-id": true, - "@metamask/eth-token-tracker>eth-block-tracker>@metamask/safe-event-emitter": true, - "@metamask/utils": true, - "pify": true - } - }, - "@metamask/eth-token-tracker>eth-block-tracker>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, "@metamask/eth-trezor-keyring": { "globals": { "setTimeout": true @@ -1240,15 +1338,47 @@ "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": true, + "@metamask/eth-trezor-keyring>@trezor/connect-web": true, "@metamask/eth-trezor-keyring>hdkey": true, - "@trezor/connect-web": true, "browserify>buffer": true, "webpack>events": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": { "packages": { - "@metamask/eth-sig-util": true + "@metamask/eth-sig-util": true, + "@trezor/connect-web>tslib": true + } + }, + "@metamask/eth-trezor-keyring>@trezor/connect-web": { + "globals": { + "URLSearchParams": true, + "__TREZOR_CONNECT_SRC": true, + "addEventListener": true, + "btoa": true, + "chrome": true, + "clearInterval": true, + "clearTimeout": true, + "console.warn": true, + "document.body": true, + "document.createElement": true, + "document.createTextNode": true, + "document.getElementById": true, + "document.querySelectorAll": true, + "location": true, + "navigator": true, + "open": true, + "origin": true, + "removeEventListener": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@trezor/connect-web>@trezor/connect": true, + "@trezor/connect-web>@trezor/connect-common": true, + "@trezor/connect-web>@trezor/utils": true, + "@trezor/connect-web>tslib": true, + "webpack>events": true } }, "@metamask/eth-trezor-keyring>hdkey": { @@ -1388,13 +1518,30 @@ }, "packages": { "@metamask/assets-controllers>@metamask/polling-controller": true, - "@metamask/controller-utils": true, "@metamask/eth-query": true, - "@metamask/ethjs>@metamask/ethjs-unit": true, - "ethereumjs-util": true, + "@metamask/gas-fee-controller>@metamask/controller-utils": true, + "bn.js": true, "uuid": true } }, + "@metamask/gas-fee-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/jazzicon": { "globals": { "document.createElement": true, @@ -1428,7 +1575,11 @@ } }, "@metamask/keyring-api": { + "globals": { + "URL": true + }, "packages": { + "@metamask/keyring-api>bech32": true, "@metamask/keyring-api>uuid": true, "@metamask/utils": true, "superstruct": true @@ -1505,18 +1656,12 @@ "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>create-hash": true - } - }, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": { - "packages": { - "bn.js": true, - "browserify>buffer": true + "ethereumjs-util>create-hash": true, + "ethereumjs-util>rlp": true } }, "@metamask/logging-controller": { @@ -1541,9 +1686,9 @@ }, "@metamask/message-manager": { "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, "@metamask/eth-sig-util": true, + "@metamask/message-manager>@metamask/base-controller": true, + "@metamask/message-manager>@metamask/controller-utils": true, "@metamask/message-manager>jsonschema": true, "@metamask/utils": true, "browserify>buffer": true, @@ -1551,27 +1696,89 @@ "webpack>events": true } }, + "@metamask/message-manager>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/message-manager>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true } }, + "@metamask/message-signing-snap>@noble/curves": { + "globals": { + "TextEncoder": true + }, + "packages": { + "@noble/hashes": true + } + }, "@metamask/name-controller": { "globals": { "fetch": true }, "packages": { - "@metamask/base-controller": true, + "@metamask/name-controller>@metamask/base-controller": true, + "@metamask/name-controller>@metamask/controller-utils": true, "@metamask/name-controller>async-mutex": true, "@metamask/utils": true } }, + "@metamask/name-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/name-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/name-controller>async-mutex": { "globals": { + "clearTimeout": true, "setTimeout": true }, "packages": { - "mockttp>graphql-tag>tslib": true + "@trezor/connect-web>tslib": true } }, "@metamask/network-controller": { @@ -1582,45 +1789,97 @@ "setTimeout": true }, "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, "@metamask/eth-json-rpc-middleware": true, "@metamask/eth-query": true, - "@metamask/eth-token-tracker>eth-block-tracker": true, + "@metamask/eth-token-tracker>@metamask/eth-block-tracker": true, + "@metamask/network-controller>@metamask/base-controller": true, + "@metamask/network-controller>@metamask/controller-utils": true, "@metamask/network-controller>@metamask/eth-json-rpc-infura": true, "@metamask/network-controller>@metamask/eth-json-rpc-provider": true, "@metamask/network-controller>@metamask/swappable-obj-proxy": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true, "@metamask/utils": true, "browserify>assert": true, "uuid": true } }, + "@metamask/network-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/network-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/network-controller>@metamask/eth-json-rpc-infura": { "globals": { "setTimeout": true }, "packages": { - "@metamask/network-controller>@metamask/eth-json-rpc-provider": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/eth-json-rpc-middleware>@metamask/eth-json-rpc-provider": true, + "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/json-rpc-engine": true, + "@metamask/rpc-errors": true, "@metamask/utils": true, "node-fetch": true } }, + "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/json-rpc-engine": { + "packages": { + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true + } + }, "@metamask/network-controller>@metamask/eth-json-rpc-provider": { "packages": { - "@metamask/network-controller>@metamask/eth-json-rpc-provider>@metamask/safe-event-emitter": true, - "@metamask/providers>@metamask/json-rpc-engine": true + "@metamask/safe-event-emitter": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true + } + }, + "@metamask/notification-controller": { + "packages": { + "@metamask/notification-controller>@metamask/base-controller": true, + "@metamask/notification-controller>@metamask/utils": true, + "@metamask/notification-controller>nanoid": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-provider>@metamask/safe-event-emitter": { + "@metamask/notification-controller>@metamask/base-controller": { "globals": { "setTimeout": true }, "packages": { - "webpack>events": true + "immer": true + } + }, + "@metamask/notification-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true } }, "@metamask/notification-controller>nanoid": { @@ -1628,19 +1887,24 @@ "crypto.getRandomValues": true } }, - "@metamask/obs-store": { + "@metamask/object-multiplex": { + "globals": { + "console.warn": true + }, "packages": { - "@metamask/obs-store>through2": true, - "@metamask/safe-event-emitter": true, - "stream-browserify": true + "@metamask/object-multiplex>once": true, + "readable-stream": true } }, - "@metamask/obs-store>through2": { + "@metamask/object-multiplex>once": { "packages": { - "browserify>process": true, - "browserify>util": true, - "readable-stream": true, - "watchify>xtend": true + "@metamask/object-multiplex>once>wrappy": true + } + }, + "@metamask/obs-store": { + "packages": { + "@metamask/safe-event-emitter": true, + "readable-stream": true } }, "@metamask/permission-controller": { @@ -1648,33 +1912,59 @@ "console.error": true }, "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/base-controller": true, + "@metamask/permission-controller>@metamask/controller-utils": true, "@metamask/permission-controller>nanoid": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true, "@metamask/utils": true, "deep-freeze-strict": true, "immer": true } }, - "@metamask/permission-controller>nanoid": { + "@metamask/permission-controller>@metamask/base-controller": { "globals": { - "crypto.getRandomValues": true - } - }, - "@metamask/permission-log-controller": { + "setTimeout": true + }, "packages": { - "@metamask/base-controller": true, - "@metamask/utils": true + "immer": true } }, - "@metamask/phishing-controller": { + "@metamask/permission-controller>@metamask/controller-utils": { "globals": { - "fetch": true + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true }, "packages": { - "@metamask/base-controller": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/permission-controller>nanoid": { + "globals": { + "crypto.getRandomValues": true + } + }, + "@metamask/permission-log-controller": { + "packages": { + "@metamask/base-controller": true, + "@metamask/utils": true + } + }, + "@metamask/phishing-controller": { + "globals": { + "fetch": true + }, + "packages": { + "@metamask/base-controller": true, "@metamask/controller-utils": true, "@metamask/phishing-warning>eth-phishing-detect": true, "punycode": true @@ -1685,6 +1975,74 @@ "eslint>optionator>fast-levenshtein": true } }, + "@metamask/post-message-stream": { + "globals": { + "MessageEvent.prototype": true, + "WorkerGlobalScope": true, + "addEventListener": true, + "browser": true, + "chrome": true, + "location.origin": true, + "postMessage": true, + "removeEventListener": true + }, + "packages": { + "@metamask/utils": true, + "readable-stream": true + } + }, + "@metamask/ppom-validator": { + "globals": { + "URL": true, + "console.error": true, + "crypto": true + }, + "packages": { + "@metamask/eth-query>json-rpc-random-id": true, + "@metamask/ppom-validator>@metamask/base-controller": true, + "@metamask/ppom-validator>@metamask/controller-utils": true, + "@metamask/ppom-validator>crypto-js": true, + "@metamask/ppom-validator>elliptic": true, + "await-semaphore": true, + "browserify>buffer": true + } + }, + "@metamask/ppom-validator>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/ppom-validator>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/ppom-validator>crypto-js": { + "globals": { + "crypto": true, + "define": true, + "msCrypto": true + }, + "packages": { + "browserify>browser-resolve": true + } + }, "@metamask/ppom-validator>elliptic": { "packages": { "@metamask/ppom-validator>elliptic>brorand": true, @@ -1712,34 +2070,37 @@ "ethereumjs-util>ethereum-cryptography>hash.js": true } }, - "@metamask/providers>@metamask/json-rpc-engine": { + "@metamask/queued-request-controller": { "packages": { - "@metamask/providers>@metamask/json-rpc-engine>@metamask/safe-event-emitter": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/queued-request-controller>@metamask/base-controller": true, + "@metamask/rpc-errors": true, + "@metamask/selected-network-controller": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true, "@metamask/utils": true } }, - "@metamask/providers>@metamask/json-rpc-engine>@metamask/safe-event-emitter": { + "@metamask/queued-request-controller>@metamask/base-controller": { "globals": { "setTimeout": true }, "packages": { - "webpack>events": true + "immer": true } }, - "@metamask/providers>@metamask/rpc-errors": { + "@metamask/rate-limit-controller": { + "globals": { + "setTimeout": true + }, "packages": { - "@metamask/utils": true, - "eth-rpc-errors>fast-safe-stringify": true + "@metamask/base-controller": true, + "@metamask/rpc-errors": true, + "@metamask/utils": true } }, - "@metamask/queued-request-controller": { + "@metamask/rpc-errors": { "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/selected-network-controller": true + "@metamask/utils": true, + "eth-rpc-errors>fast-safe-stringify": true } }, "@metamask/rpc-methods-flask>nanoid": { @@ -1777,8 +2138,16 @@ }, "@metamask/selected-network-controller": { "packages": { - "@metamask/base-controller": true, - "@metamask/network-controller>@metamask/swappable-obj-proxy": true + "@metamask/network-controller>@metamask/swappable-obj-proxy": true, + "@metamask/selected-network-controller>@metamask/base-controller": true + } + }, + "@metamask/selected-network-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true } }, "@metamask/signature-controller": { @@ -1787,16 +2156,46 @@ }, "packages": { "@metamask/base-controller": true, - "@metamask/controller-utils": true, "@metamask/logging-controller": true, - "@metamask/message-manager": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, + "@metamask/signature-controller>@metamask/controller-utils": true, + "@metamask/signature-controller>@metamask/message-manager": true, + "@metamask/utils": true, "browserify>buffer": true, - "ethereumjs-util": true, "lodash": true, "webpack>events": true } }, + "@metamask/signature-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/signature-controller>@metamask/message-manager": { + "packages": { + "@metamask/base-controller": true, + "@metamask/eth-sig-util": true, + "@metamask/message-manager>jsonschema": true, + "@metamask/signature-controller>@metamask/controller-utils": true, + "@metamask/utils": true, + "browserify>buffer": true, + "uuid": true, + "webpack>events": true + } + }, "@metamask/smart-transactions-controller": { "globals": { "URLSearchParams": true, @@ -1808,65 +2207,423 @@ }, "packages": { "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/bignumber": true, - "@ethersproject/providers": true, - "@metamask/smart-transactions-controller>@metamask/base-controller": true, + "@metamask/assets-controllers>@metamask/polling-controller": true, + "@metamask/eth-query": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx": true, + "@metamask/smart-transactions-controller>@ethereumjs/util": true, "@metamask/smart-transactions-controller>@metamask/controller-utils": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller": true, "@metamask/smart-transactions-controller>bignumber.js": true, + "browserify>buffer": true, "fast-json-patch": true, - "lodash": true + "lodash": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@babel/runtime": { + "globals": { + "regeneratorRuntime": "write" + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx": { + "packages": { + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": true, + "@metamask/smart-transactions-controller>@ethereumjs/util": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": { + "packages": { + "@metamask/smart-transactions-controller>@ethereumjs/util": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/util": { + "globals": { + "console.warn": true, + "fetch": true + }, + "packages": { + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@ethereumjs/util>@ethereumjs/rlp": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/util>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, + "@metamask/smart-transactions-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/smart-transactions-controller>@metamask/controller-utils>@ethereumjs/util": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/smart-transactions-controller>@metamask/controller-utils>@ethereumjs/util": { + "globals": { + "console.warn": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@metamask/controllers>nanoid": { + "globals": { + "crypto.getRandomValues": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller": { + "globals": { + "clearTimeout": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/common": true, + "@ethersproject/abi": true, + "@ethersproject/contracts": true, + "@ethersproject/providers": true, + "@metamask/eth-query": true, + "@metamask/metamask-eth-abis": true, + "@metamask/name-controller>async-mutex": true, + "@metamask/network-controller": true, + "@metamask/rpc-errors": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/base-controller": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/controller-utils": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry": true, + "@metamask/transaction-controller>@metamask/nonce-tracker": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "fast-json-patch": true, + "lodash": true, + "uuid": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx": { + "packages": { + "@ethereumjs/tx>@ethereumjs/common": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": { + "globals": { + "console.warn": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller": { + "globals": { + "clearInterval": true, + "console.error": true, + "setInterval": true + }, + "packages": { + "@metamask/eth-query": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/controller-utils": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/polling-controller": true, + "bn.js": true, + "browserify>buffer": true, + "uuid": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/controller-utils>@ethereumjs/util": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/controller-utils>@ethereumjs/util": { + "globals": { + "console.warn": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/polling-controller": { + "globals": { + "clearTimeout": true, + "console.error": true, + "setTimeout": true + }, + "packages": { + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/base-controller": true, + "@metamask/snaps-utils>fast-json-stable-stringify": true, + "uuid": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry": { + "packages": { + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract": { + "packages": { + "@metamask/ethjs>ethjs-abi": true, + "@metamask/ethjs>js-sha3": true, + "@metamask/smart-transactions-controller>@babel/runtime": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-filter": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-util": true, + "promise-to-callback": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-filter": { + "globals": { + "clearInterval": true, + "setInterval": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-util": { + "packages": { + "@metamask/ethjs>@metamask/ethjs-util>is-hex-prefixed": true, + "@metamask/ethjs>@metamask/ethjs-util>strip-hex-prefix": true, + "browserify>buffer": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query>@metamask/ethjs-format": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query>@metamask/ethjs-rpc": true, + "promise-to-callback": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query>@metamask/ethjs-format": { + "packages": { + "@metamask/ethjs-query>@metamask/ethjs-format>ethjs-schema": true, + "@metamask/ethjs>@metamask/ethjs-util>strip-hex-prefix": true, + "@metamask/ethjs>@metamask/number-to-bn": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-util": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query>@metamask/ethjs-rpc": { + "packages": { + "promise-to-callback": true + } + }, + "@metamask/smart-transactions-controller>bignumber.js": { + "globals": { + "crypto": true, + "define": true + } + }, + "@metamask/snaps-controllers": { + "globals": { + "DecompressionStream": true, + "URL": true, + "clearTimeout": true, + "document.getElementById": true, + "fetch.bind": true, + "setTimeout": true + }, + "packages": { + "@metamask/object-multiplex": true, + "@metamask/permission-controller": true, + "@metamask/post-message-stream": true, + "@metamask/rpc-errors": true, + "@metamask/snaps-controllers>@metamask/base-controller": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true, + "@metamask/snaps-controllers>@metamask/json-rpc-middleware-stream": true, + "@metamask/snaps-controllers>@xstate/fsm": true, + "@metamask/snaps-controllers>concat-stream": true, + "@metamask/snaps-controllers>get-npm-tarball-url": true, + "@metamask/snaps-controllers>nanoid": true, + "@metamask/snaps-controllers>readable-web-to-node-stream": true, + "@metamask/snaps-controllers>tar-stream": true, + "@metamask/snaps-rpc-methods": true, + "@metamask/snaps-sdk": true, + "@metamask/snaps-utils": true, + "@metamask/snaps-utils>@metamask/snaps-registry": true, + "@metamask/utils": true, + "browserify>browserify-zlib": true, + "eslint>fast-deep-equal": true, + "readable-stream": true + } + }, + "@metamask/snaps-controllers-flask>nanoid": { + "globals": { + "crypto.getRandomValues": true + } + }, + "@metamask/snaps-controllers>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": { + "packages": { + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true + } + }, + "@metamask/snaps-controllers>@metamask/json-rpc-middleware-stream": { + "globals": { + "console.warn": true, + "setTimeout": true + }, + "packages": { + "@metamask/safe-event-emitter": true, + "readable-stream": true + } + }, + "@metamask/snaps-controllers>concat-stream": { + "packages": { + "browserify>buffer": true, + "browserify>concat-stream>typedarray": true, + "pumpify>inherits": true, + "readable-stream": true, + "terser>source-map-support>buffer-from": true } }, - "@metamask/smart-transactions-controller>@metamask/base-controller": { + "@metamask/snaps-controllers>nanoid": { "globals": { - "setTimeout": true - }, + "crypto.getRandomValues": true + } + }, + "@metamask/snaps-controllers>readable-web-to-node-stream": { "packages": { - "immer": true + "readable-stream": true } }, - "@metamask/smart-transactions-controller>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, + "@metamask/snaps-controllers>tar-stream": { "packages": { - "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/utils": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true + "@metamask/snaps-controllers>tar-stream>b4a": true, + "@metamask/snaps-controllers>tar-stream>fast-fifo": true, + "@metamask/snaps-controllers>tar-stream>streamx": true, + "browserify>browser-resolve": true } }, - "@metamask/smart-transactions-controller>@metamask/controllers>nanoid": { + "@metamask/snaps-controllers>tar-stream>b4a": { "globals": { - "crypto.getRandomValues": true + "TextDecoder": true, + "TextEncoder": true } }, - "@metamask/smart-transactions-controller>bignumber.js": { - "globals": { - "crypto": true, - "define": true + "@metamask/snaps-controllers>tar-stream>streamx": { + "packages": { + "@metamask/snaps-controllers>tar-stream>fast-fifo": true, + "@metamask/snaps-controllers>tar-stream>streamx>queue-tick": true, + "webpack>events": true } }, - "@metamask/snaps-controllers-flask>nanoid": { + "@metamask/snaps-controllers>tar-stream>streamx>queue-tick": { "globals": { - "crypto.getRandomValues": true + "queueMicrotask": true } }, - "@metamask/snaps-controllers>nanoid": { + "@metamask/snaps-execution-environments": { "globals": { - "crypto.getRandomValues": true + "document.getElementById": true + }, + "packages": { + "@metamask/post-message-stream": true, + "@metamask/snaps-utils": true, + "@metamask/utils": true } }, "@metamask/snaps-rpc-methods": { "packages": { "@metamask/permission-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/snaps-sdk": true, "@metamask/snaps-sdk>@metamask/key-tree": true, "@metamask/snaps-utils": true, @@ -1880,50 +2637,18 @@ "fetch": true }, "packages": { - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/snaps-sdk>fast-xml-parser": true, + "@metamask/rpc-errors": true, "@metamask/utils": true, "superstruct": true } }, "@metamask/snaps-sdk>@metamask/key-tree": { "packages": { + "@metamask/message-signing-snap>@noble/curves": true, "@metamask/scure-bip39": true, - "@metamask/snaps-sdk>@metamask/key-tree>@metamask/utils": true, - "@metamask/snaps-sdk>@metamask/key-tree>@noble/ed25519": true, + "@metamask/utils": true, "@metamask/utils>@scure/base": true, - "@noble/hashes": true, - "eth-lattice-keyring>@noble/secp256k1": true - } - }, - "@metamask/snaps-sdk>@metamask/key-tree>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, - "@metamask/snaps-sdk>@metamask/key-tree>@noble/ed25519": { - "globals": { - "crypto": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "@metamask/snaps-sdk>fast-xml-parser": { - "globals": { - "entityName": true, - "val": true - }, - "packages": { - "@metamask/snaps-sdk>fast-xml-parser>strnum": true + "@noble/hashes": true } }, "@metamask/snaps-utils": { @@ -1931,6 +2656,7 @@ "File": true, "FileReader": true, "TextDecoder": true, + "TextEncoder": true, "URL": true, "console.error": true, "console.log": true, @@ -1942,12 +2668,13 @@ }, "packages": { "@metamask/permission-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/snaps-sdk": true, "@metamask/snaps-sdk>@metamask/key-tree": true, "@metamask/snaps-utils>@metamask/slip44": true, "@metamask/snaps-utils>cron-parser": true, "@metamask/snaps-utils>fast-json-stable-stringify": true, + "@metamask/snaps-utils>fast-xml-parser": true, "@metamask/snaps-utils>marked": true, "@metamask/snaps-utils>rfdc": true, "@metamask/snaps-utils>validate-npm-package-name": true, @@ -1959,32 +2686,34 @@ "superstruct": true } }, + "@metamask/snaps-utils>@metamask/snaps-registry": { + "packages": { + "@metamask/message-signing-snap>@noble/curves": true, + "@metamask/utils": true, + "@noble/hashes": true, + "superstruct": true + } + }, "@metamask/snaps-utils>cron-parser": { "packages": { "browserify>browser-resolve": true, "luxon": true } }, + "@metamask/snaps-utils>fast-xml-parser": { + "globals": { + "entityName": true, + "val": true + }, + "packages": { + "@metamask/snaps-utils>fast-xml-parser>strnum": true + } + }, "@metamask/snaps-utils>marked": { "globals": { - "Hooks": true, - "Lexer": true, - "Parser": true, - "Renderer": true, - "TextRenderer": true, - "Tokenizer": true, "console.error": true, "console.warn": true, - "defaults": true, - "define": true, - "inlineQueue": true, - "passThroughHooks": true, - "renderer": true, - "rules": true, - "state": true, - "textRenderer": true, - "tokenizer": true, - "tokens": true + "define": true } }, "@metamask/snaps-utils>rfdc": { @@ -2003,14 +2732,6 @@ "semver": true } }, - "@metamask/test-bundler>@ethersproject/abstract-provider": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/bignumber": true - } - }, "@metamask/test-bundler>@ethersproject/networks": { "packages": { "@ethersproject/abi>@ethersproject/logger": true @@ -2020,24 +2741,28 @@ "globals": { "clearTimeout": true, "console.error": true, + "fetch": true, "setTimeout": true }, "packages": { - "@ethereumjs/common": true, "@ethereumjs/tx": true, + "@ethereumjs/tx>@ethereumjs/common": true, "@ethereumjs/tx>@ethereumjs/util": true, "@ethersproject/abi": true, - "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@ethersproject/contracts": true, + "@ethersproject/providers": true, "@metamask/eth-query": true, "@metamask/gas-fee-controller": true, "@metamask/metamask-eth-abis": true, "@metamask/name-controller>async-mutex": true, "@metamask/network-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/transaction-controller>nonce-tracker": true, + "@metamask/rpc-errors": true, + "@metamask/transaction-controller>@metamask/base-controller": true, + "@metamask/transaction-controller>@metamask/controller-utils": true, + "@metamask/transaction-controller>@metamask/nonce-tracker": true, "@metamask/utils": true, "bn.js": true, + "browserify>buffer": true, "eth-method-registry": true, "fast-json-patch": true, "lodash": true, @@ -2045,21 +2770,46 @@ "webpack>events": true } }, - "@metamask/transaction-controller>nonce-tracker": { + "@metamask/transaction-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/transaction-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/transaction-controller>@metamask/nonce-tracker": { "packages": { "@ethersproject/providers": true, - "@metamask/eth-token-tracker>eth-block-tracker": true, - "@metamask/transaction-controller>nonce-tracker>async-mutex": true, + "@metamask/transaction-controller>@metamask/nonce-tracker>async-mutex": true, "browserify>assert": true } }, - "@metamask/transaction-controller>nonce-tracker>async-mutex": { + "@metamask/transaction-controller>@metamask/nonce-tracker>async-mutex": { "globals": { "clearTimeout": true, "setTimeout": true }, "packages": { - "mockttp>graphql-tag>tslib": true + "@trezor/connect-web>tslib": true } }, "@metamask/user-operation-controller": { @@ -2069,19 +2819,37 @@ "packages": { "@metamask/assets-controllers>@metamask/polling-controller": true, "@metamask/base-controller": true, - "@metamask/controller-utils": true, "@metamask/eth-query": true, "@metamask/gas-fee-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/transaction-controller": true, + "@metamask/user-operation-controller>@metamask/controller-utils": true, "@metamask/utils": true, - "ethereumjs-util": true, + "bn.js": true, "lodash": true, "superstruct": true, "uuid": true, "webpack>events": true } }, + "@metamask/user-operation-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/utils": { "globals": { "TextDecoder": true, @@ -2105,7 +2873,7 @@ }, "@ngraveio/bc-ur": { "packages": { - "@ngraveio/bc-ur>@apocentre/alias-sampling": true, + "@ngraveio/bc-ur>@keystonehq/alias-sampling": true, "@ngraveio/bc-ur>bignumber.js": true, "@ngraveio/bc-ur>cbor-sync": true, "@ngraveio/bc-ur>crc": true, @@ -2145,6 +2913,13 @@ "define": true } }, + "@noble/ciphers": { + "globals": { + "TextDecoder": true, + "TextEncoder": true, + "crypto": true + } + }, "@noble/hashes": { "globals": { "TextEncoder": true, @@ -2167,12 +2942,14 @@ "AbortController": true, "__REDUX_DEVTOOLS_EXTENSION_COMPOSE__": true, "__REDUX_DEVTOOLS_EXTENSION__": true, - "console.error": true, - "console.info": true, - "console.warn": true + "console": true, + "queueMicrotask": true, + "requestAnimationFrame": true, + "setTimeout": true }, "packages": { "@reduxjs/toolkit>reselect": true, + "browserify>process": true, "immer": true, "redux": true, "redux-thunk": true @@ -2317,6 +3094,11 @@ "browserify>process": true } }, + "@storybook/addon-docs>remark-external-links>mdast-util-definitions": { + "packages": { + "react-markdown>unist-util-visit": true + } + }, "@storybook/addon-knobs>qs": { "packages": { "string.prototype.matchall>side-channel": true @@ -2324,6 +3106,7 @@ }, "@trezor/connect-web": { "globals": { + "URLSearchParams": true, "__TREZOR_CONNECT_SRC": true, "addEventListener": true, "btoa": true, @@ -2339,42 +3122,105 @@ "location": true, "navigator": true, "open": true, + "origin": true, "removeEventListener": true, "setInterval": true, "setTimeout": true }, "packages": { "@trezor/connect-web>@trezor/connect": true, + "@trezor/connect-web>@trezor/connect-common": true, "@trezor/connect-web>@trezor/utils": true, - "mockttp>graphql-tag>tslib": true, + "@trezor/connect-web>tslib": true, "webpack>events": true } }, "@trezor/connect-web>@trezor/connect": { + "packages": { + "@trezor/connect-web>@trezor/connect>@trezor/protobuf": true, + "@trezor/connect-web>@trezor/connect>@trezor/schema-utils": true, + "@trezor/connect-web>@trezor/connect>@trezor/transport": true, + "@trezor/connect-web>@trezor/utils": true, + "@trezor/connect-web>tslib": true + } + }, + "@trezor/connect-web>@trezor/connect-common": { "globals": { - "console.error": true, - "console.log": true, - "console.warn": true + "console.warn": true, + "localStorage.getItem": true, + "localStorage.setItem": true, + "navigator": true, + "setTimeout": true, + "window": true }, "packages": { - "@trezor/connect-web>@trezor/connect>@trezor/transport": true, - "@trezor/connect-web>@trezor/connect>tslib": true + "@trezor/connect-web>@trezor/connect-common>@trezor/env-utils": true, + "@trezor/connect-web>@trezor/utils": true, + "@trezor/connect-web>tslib": true + } + }, + "@trezor/connect-web>@trezor/connect-common>@trezor/env-utils": { + "globals": { + "innerHeight": true, + "innerWidth": true, + "location.hostname": true, + "location.origin": true, + "navigator.languages": true, + "navigator.platform": true, + "navigator.userAgent": true, + "screen.height": true, + "screen.width": true + }, + "packages": { + "@trezor/connect-web>@trezor/connect-common>@trezor/env-utils>ua-parser-js": true, + "@trezor/connect-web>tslib": true, + "browserify>process": true } }, - "@trezor/connect-web>@trezor/connect>tslib": { + "@trezor/connect-web>@trezor/connect-common>@trezor/env-utils>ua-parser-js": { "globals": { "define": true } }, + "@trezor/connect-web>@trezor/connect>@trezor/protobuf": { + "packages": { + "@trezor/connect-web>@trezor/connect>@trezor/schema-utils": true, + "@trezor/connect-web>tslib": true, + "browserify>buffer": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs": true + } + }, + "@trezor/connect-web>@trezor/connect>@trezor/schema-utils": { + "globals": { + "console.warn": true + }, + "packages": { + "@trezor/connect-web>@trezor/connect>@trezor/schema-utils>@sinclair/typebox": true, + "browserify>buffer": true, + "ts-mixer": true + } + }, "@trezor/connect-web>@trezor/utils": { "globals": { "AbortController": true, "Intl.NumberFormat": true, "clearTimeout": true, + "console.error": true, + "console.info": true, + "console.log": true, + "console.warn": true, "setTimeout": true }, "packages": { - "browserify>buffer": true + "@trezor/connect-web>tslib": true, + "browserify>buffer": true, + "webpack>events": true + } + }, + "@trezor/connect-web>tslib": { + "globals": { + "SuppressedError": true, + "define": true } }, "@zxing/browser": { @@ -2452,15 +3298,6 @@ "define": true } }, - "brfs>static-module>object-inspect": { - "globals": { - "HTMLElement": true, - "WeakRef": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "browserify>assert": { "globals": { "Buffer": true @@ -2654,6 +3491,11 @@ "browserify>url": true } }, + "browserify>path-browserify": { + "packages": { + "browserify>process": true + } + }, "browserify>process": { "globals": { "clearTimeout": true, @@ -2683,23 +3525,12 @@ "browserify>buffer": true, "browserify>process": true, "browserify>stream-http>builtin-status-codes": true, - "browserify>stream-http>readable-stream": true, "browserify>url": true, "pumpify>inherits": true, + "readable-stream": true, "watchify>xtend": true } }, - "browserify>stream-http>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, "browserify>string_decoder": { "packages": { "koa>content-disposition>safe-buffer": true @@ -2792,41 +3623,20 @@ }, "chart.js": { "globals": { - "$animations": true, "Intl.NumberFormat": true, "MutationObserver": true, "OffscreenCanvas": true, "Path2D": true, "ResizeObserver": true, - "active": true, "addEventListener": true, - "circumference": true, "clearTimeout": true, "console.error": true, "console.warn": true, - "dataElementType": true, - "datasetElementType": true, - "defaultRoutes": true, - "defaults": true, - "descriptors": true, "devicePixelRatio": true, "document": true, - "endAngle": true, - "fullCircles": true, - "id": true, - "innerRadius": true, - "options": true, - "outerRadius": true, - "overrides": true, - "parsed": true, - "pixelMargin": true, "removeEventListener": true, "requestAnimationFrame": true, - "setTimeout": true, - "startAngle": true, - "stop": true, - "x": true, - "y": true + "setTimeout": true }, "packages": { "chart.js>@kurkle/color": true @@ -2923,12 +3733,6 @@ "crypto.getRandomValues": true } }, - "end-of-stream": { - "packages": { - "browserify>process": true, - "pump>once": true - } - }, "eslint-plugin-react>array-includes>is-string": { "packages": { "koa>is-generator-function>has-tostringtag": true @@ -2989,7 +3793,7 @@ }, "eth-lattice-keyring>@ethereumjs/tx": { "packages": { - "@ethereumjs/common": true, + "@ethereumjs/tx>@ethereumjs/common": true, "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util": true, "@ethersproject/providers": true, @@ -3030,14 +3834,6 @@ "crypto": true } }, - "eth-lattice-keyring>@noble/secp256k1": { - "globals": { - "crypto": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -3053,23 +3849,23 @@ "setTimeout": true }, "packages": { - "@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethersproject/abi": true, "@metamask/ethjs>js-sha3": true, + "@metamask/keyring-api>bech32": true, "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>buffer": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, - "eth-lattice-keyring>gridplus-sdk>bech32": true, "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, + "eth-lattice-keyring>gridplus-sdk>rlp": true, "eth-lattice-keyring>gridplus-sdk>secp256k1": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, - "eth-lattice-keyring>rlp": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>hash.js": true, "lodash": true @@ -3077,7 +3873,7 @@ }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": { "packages": { - "@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, "webpack>events": true @@ -3097,7 +3893,7 @@ }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { "packages": { - "@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, "webpack>events": true @@ -3165,16 +3961,12 @@ "packages": { "@metamask/ethjs>js-sha3": true, "bn.js": true, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": true + "ganache>abstract-level>buffer": true } }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": { + "eth-lattice-keyring>gridplus-sdk>rlp": { "globals": { - "console": true - }, - "packages": { - "base64-js": true, - "browserify>buffer>ieee754": true + "TextEncoder": true } }, "eth-lattice-keyring>gridplus-sdk>secp256k1": { @@ -3240,20 +4032,9 @@ }, "ethereumjs-util>create-hash>md5.js>hash-base": { "packages": { - "ethereumjs-util>create-hash>md5.js>hash-base>readable-stream": true, "koa>content-disposition>safe-buffer": true, - "pumpify>inherits": true - } - }, - "ethereumjs-util>create-hash>md5.js>hash-base>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "readable-stream": true } }, "ethereumjs-util>create-hash>ripemd160": { @@ -3357,27 +4138,172 @@ "setTimeout": true } }, + "firebase": { + "packages": { + "firebase>@firebase/app": true, + "firebase>@firebase/messaging": true + } + }, + "firebase>@firebase/app": { + "globals": { + "FinalizationRegistry": true, + "console.warn": true + }, + "packages": { + "firebase>@firebase/app>@firebase/component": true, + "firebase>@firebase/app>@firebase/logger": true, + "firebase>@firebase/app>idb": true, + "firebase>@firebase/util": true + } + }, + "firebase>@firebase/app>@firebase/component": { + "packages": { + "firebase>@firebase/util": true + } + }, + "firebase>@firebase/app>@firebase/logger": { + "globals": { + "console": true + }, + "packages": { + "@trezor/connect-web>tslib": true + } + }, + "firebase>@firebase/app>idb": { + "globals": { + "DOMException": true, + "IDBCursor": true, + "IDBDatabase": true, + "IDBIndex": true, + "IDBObjectStore": true, + "IDBRequest": true, + "IDBTransaction": true, + "indexedDB.deleteDatabase": true, + "indexedDB.open": true + } + }, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs": { + "globals": { + "process": true, + "setTimeout": true + }, + "packages": { + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/aspromise": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/base64": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/codegen": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/eventemitter": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/fetch": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/float": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/inquire": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/path": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/pool": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/utf8": true + } + }, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/codegen": { + "globals": { + "console.log": true + } + }, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/fetch": { + "globals": { + "XMLHttpRequest": true + }, + "packages": { + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/aspromise": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/inquire": true + } + }, + "firebase>@firebase/installations": { + "globals": { + "BroadcastChannel": true, + "Headers": true, + "btoa": true, + "console.error": true, + "crypto": true, + "fetch": true, + "msCrypto": true, + "navigator.onLine": true, + "setTimeout": true + }, + "packages": { + "firebase>@firebase/app": true, + "firebase>@firebase/app>@firebase/component": true, + "firebase>@firebase/app>idb": true, + "firebase>@firebase/util": true + } + }, + "firebase>@firebase/messaging": { + "globals": { + "Headers": true, + "Notification.maxActions": true, + "Notification.permission": true, + "Notification.requestPermission": true, + "PushSubscription.prototype.hasOwnProperty": true, + "ServiceWorkerRegistration": true, + "URL": true, + "addEventListener": true, + "atob": true, + "btoa": true, + "clients.matchAll": true, + "clients.openWindow": true, + "console.warn": true, + "document": true, + "fetch": true, + "indexedDB": true, + "location.href": true, + "location.origin": true, + "navigator": true, + "origin.replace": true, + "registration.showNotification": true, + "setTimeout": true + }, + "packages": { + "@trezor/connect-web>tslib": true, + "firebase>@firebase/app": true, + "firebase>@firebase/app>@firebase/component": true, + "firebase>@firebase/app>idb": true, + "firebase>@firebase/installations": true, + "firebase>@firebase/util": true + } + }, + "firebase>@firebase/util": { + "globals": { + "atob": true, + "browser": true, + "btoa": true, + "chrome": true, + "console": true, + "document": true, + "indexedDB": true, + "navigator": true, + "process": true, + "self": true, + "setTimeout": true + }, + "packages": { + "browserify>process": true + } + }, "fuse.js": { "globals": { "console": true, "define": true } }, - "ganache>keccak": { + "ganache>abstract-level>buffer": { + "globals": { + "console": true + }, "packages": { - "browserify>buffer": true, - "ganache>keccak>readable-stream": true + "base64-js": true, + "browserify>buffer>ieee754": true } }, - "ganache>keccak>readable-stream": { + "ganache>keccak": { "packages": { - "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "readable-stream": true } }, "ganache>secp256k1": { @@ -3393,39 +4319,33 @@ "string.prototype.matchall>has-symbols": true } }, + "he": { + "globals": { + "define": true + } + }, "json-rpc-engine": { "packages": { - "@metamask/safe-event-emitter": true, - "eth-rpc-errors": true + "eth-rpc-errors": true, + "json-rpc-engine>@metamask/safe-event-emitter": true } }, - "json-rpc-middleware-stream": { + "json-rpc-engine>@metamask/safe-event-emitter": { "globals": { - "console.warn": true, "setTimeout": true }, "packages": { - "json-rpc-middleware-stream>@metamask/safe-event-emitter": true, - "json-rpc-middleware-stream>readable-stream": true + "webpack>events": true } }, - "json-rpc-middleware-stream>@metamask/safe-event-emitter": { + "json-rpc-middleware-stream": { "globals": { + "console.warn": true, "setTimeout": true }, "packages": { - "webpack>events": true - } - }, - "json-rpc-middleware-stream>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "@metamask/safe-event-emitter": true, + "readable-stream": true } }, "koa>content-disposition>safe-buffer": { @@ -3503,12 +4423,6 @@ "koa>content-disposition>safe-buffer": true } }, - "mockttp>graphql-tag>tslib": { - "globals": { - "SuppressedError": true, - "define": true - } - }, "nanoid": { "globals": { "crypto": true, @@ -3537,16 +4451,6 @@ "fetch": true } }, - "obj-multiplex": { - "globals": { - "console.warn": true - }, - "packages": { - "end-of-stream": true, - "pump>once": true, - "readable-stream": true - } - }, "promise-to-callback": { "packages": { "promise-to-callback>is-fn": true, @@ -3575,19 +4479,6 @@ "console": true } }, - "pump": { - "packages": { - "browserify>browser-resolve": true, - "browserify>process": true, - "end-of-stream": true, - "pump>once": true - } - }, - "pump>once": { - "packages": { - "pump>once>wrappy": true - } - }, "qrcode-generator": { "globals": { "define": true @@ -3599,8 +4490,6 @@ "devicePixelRatio": true }, "packages": { - "prop-types": true, - "qrcode.react>qr.js": true, "react": true } }, @@ -3765,7 +4654,7 @@ "setTimeout": true }, "packages": { - "mockttp>graphql-tag>tslib": true + "@trezor/connect-web>tslib": true } }, "react-focus-lock>react-clientside-effect": { @@ -3784,7 +4673,7 @@ "console.error": true }, "packages": { - "mockttp>graphql-tag>tslib": true, + "@trezor/connect-web>tslib": true, "react": true, "react-focus-lock>use-sidecar>detect-node-es": true } @@ -3810,6 +4699,110 @@ "react": true } }, + "react-markdown": { + "globals": { + "console.warn": true + }, + "packages": { + "prop-types": true, + "react": true, + "react-markdown>comma-separated-tokens": true, + "react-markdown>property-information": true, + "react-markdown>react-is": true, + "react-markdown>remark-parse": true, + "react-markdown>remark-rehype": true, + "react-markdown>space-separated-tokens": true, + "react-markdown>style-to-object": true, + "react-markdown>unified": true, + "react-markdown>unist-util-visit": true, + "react-markdown>vfile": true + } + }, + "react-markdown>property-information": { + "packages": { + "watchify>xtend": true + } + }, + "react-markdown>react-is": { + "globals": { + "console": true + } + }, + "react-markdown>remark-parse": { + "packages": { + "react-markdown>remark-parse>mdast-util-from-markdown": true + } + }, + "react-markdown>remark-parse>mdast-util-from-markdown": { + "packages": { + "react-markdown>remark-parse>mdast-util-from-markdown>mdast-util-to-string": true, + "react-markdown>remark-parse>mdast-util-from-markdown>micromark": true, + "react-markdown>remark-parse>mdast-util-from-markdown>unist-util-stringify-position": true, + "react-syntax-highlighter>refractor>parse-entities": true + } + }, + "react-markdown>remark-parse>mdast-util-from-markdown>micromark": { + "packages": { + "react-syntax-highlighter>refractor>parse-entities": true + } + }, + "react-markdown>remark-rehype": { + "packages": { + "react-markdown>remark-rehype>mdast-util-to-hast": true + } + }, + "react-markdown>remark-rehype>mdast-util-to-hast": { + "globals": { + "console.warn": true + }, + "packages": { + "@storybook/addon-docs>remark-external-links>mdast-util-definitions": true, + "react-markdown>remark-rehype>mdast-util-to-hast>mdurl": true, + "react-markdown>remark-rehype>mdast-util-to-hast>unist-builder": true, + "react-markdown>remark-rehype>mdast-util-to-hast>unist-util-generated": true, + "react-markdown>remark-rehype>mdast-util-to-hast>unist-util-position": true, + "react-markdown>unist-util-visit": true + } + }, + "react-markdown>style-to-object": { + "packages": { + "react-markdown>style-to-object>inline-style-parser": true + } + }, + "react-markdown>unified": { + "packages": { + "mocha>yargs-unparser>is-plain-obj": true, + "react-markdown>unified>bail": true, + "react-markdown>unified>extend": true, + "react-markdown>unified>is-buffer": true, + "react-markdown>unified>trough": true, + "react-markdown>vfile": true + } + }, + "react-markdown>unist-util-visit": { + "packages": { + "react-markdown>unist-util-visit>unist-util-visit-parents": true + } + }, + "react-markdown>unist-util-visit>unist-util-visit-parents": { + "packages": { + "react-markdown>unist-util-visit>unist-util-is": true + } + }, + "react-markdown>vfile": { + "packages": { + "browserify>path-browserify": true, + "browserify>process": true, + "react-markdown>vfile>is-buffer": true, + "react-markdown>vfile>vfile-message": true, + "vinyl>replace-ext": true + } + }, + "react-markdown>vfile>vfile-message": { + "packages": { + "react-markdown>vfile>unist-util-stringify-position": true + } + }, "react-popper": { "globals": { "document": true @@ -3838,13 +4831,12 @@ "document": true }, "packages": { - "@babel/runtime": true, "prop-types": true, - "prop-types>react-is": true, "react": true, "react-dom": true, + "react-redux>@babel/runtime": true, "react-redux>hoist-non-react-statics": true, - "redux": true + "react-redux>react-is": true } }, "react-redux>hoist-non-react-statics": { @@ -3852,6 +4844,11 @@ "prop-types>react-is": true } }, + "react-redux>react-is": { + "globals": { + "console": true + } + }, "react-responsive-carousel": { "globals": { "HTMLElement": true, @@ -3964,6 +4961,11 @@ "react": true } }, + "react-syntax-highlighter>refractor>parse-entities": { + "globals": { + "document.createElement": true + } + }, "react-tippy": { "globals": { "Element": true, @@ -4023,38 +5025,24 @@ "readable-stream": { "packages": { "browserify>browser-resolve": true, + "browserify>buffer": true, "browserify>process": true, - "browserify>timers-browserify": true, + "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>core-util-is": true, - "readable-stream>isarray": true, - "readable-stream>process-nextick-args": true, - "readable-stream>safe-buffer": true, - "readable-stream>string_decoder": true, "readable-stream>util-deprecate": true, "webpack>events": true } }, - "readable-stream>core-util-is": { + "readable-stream-2>core-util-is": { "packages": { "browserify>insert-module-globals>is-buffer": true } }, - "readable-stream>process-nextick-args": { + "readable-stream-2>process-nextick-args": { "packages": { "browserify>process": true } }, - "readable-stream>safe-buffer": { - "packages": { - "browserify>buffer": true - } - }, - "readable-stream>string_decoder": { - "packages": { - "readable-stream>safe-buffer": true - } - }, "readable-stream>util-deprecate": { "globals": { "console.trace": true, @@ -4075,13 +5063,7 @@ "console.error": true }, "packages": { - "browserify>process": true, - "semver>lru-cache": true - } - }, - "semver>lru-cache": { - "packages": { - "semver>lru-cache>yallist": true + "browserify>process": true } }, "sinon>nise>path-to-regexp": { @@ -4092,18 +5074,7 @@ "stream-browserify": { "packages": { "pumpify>inherits": true, - "stream-browserify>readable-stream": true, - "webpack>events": true - } - }, - "stream-browserify>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, + "readable-stream": true, "webpack>events": true } }, @@ -4183,6 +5154,15 @@ "string.prototype.matchall>call-bind": true } }, + "string.prototype.matchall>es-abstract>object-inspect": { + "globals": { + "HTMLElement": true, + "WeakRef": true + }, + "packages": { + "browserify>browser-resolve": true + } + }, "string.prototype.matchall>get-intrinsic": { "globals": { "AggregateError": true, @@ -4220,8 +5200,8 @@ }, "string.prototype.matchall>side-channel": { "packages": { - "brfs>static-module>object-inspect": true, "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>es-abstract>object-inspect": true, "string.prototype.matchall>get-intrinsic": true } }, @@ -4231,12 +5211,22 @@ "define": true } }, + "terser>source-map-support>buffer-from": { + "packages": { + "browserify>buffer": true + } + }, "uuid": { "globals": { "crypto": true, "msCrypto": true } }, + "vinyl>replace-ext": { + "packages": { + "browserify>path-browserify": true + } + }, "web3": { "globals": { "XMLHttpRequest": true @@ -4254,8 +5244,7 @@ }, "web3-stream-provider>uuid": { "globals": { - "crypto": true, - "msCrypto": true + "crypto": true } }, "webextension-polyfill": { diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json deleted file mode 100644 index 3b16fae07ec8..000000000000 --- a/lavamoat/browserify/desktop/policy.json +++ /dev/null @@ -1,4685 +0,0 @@ -{ - "resources": { - "@babel/runtime": { - "globals": { - "regeneratorRuntime": "write" - } - }, - "@ensdomains/content-hash": { - "globals": { - "console.warn": true - }, - "packages": { - "@ensdomains/content-hash>cids": true, - "@ensdomains/content-hash>js-base64": true, - "@ensdomains/content-hash>multicodec": true, - "@ensdomains/content-hash>multihashes": true, - "browserify>buffer": true - } - }, - "@ensdomains/content-hash>cids": { - "packages": { - "@ensdomains/content-hash>cids>multibase": true, - "@ensdomains/content-hash>cids>multihashes": true, - "@ensdomains/content-hash>cids>uint8arrays": true, - "@ensdomains/content-hash>multicodec": true - } - }, - "@ensdomains/content-hash>cids>multibase": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@ensdomains/content-hash>cids>multibase>@multiformats/base-x": true - } - }, - "@ensdomains/content-hash>cids>multihashes": { - "packages": { - "@ensdomains/content-hash>cids>multibase": true, - "@ensdomains/content-hash>cids>multihashes>varint": true, - "@ensdomains/content-hash>cids>uint8arrays": true - } - }, - "@ensdomains/content-hash>cids>uint8arrays": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@ensdomains/content-hash>cids>multibase": true - } - }, - "@ensdomains/content-hash>js-base64": { - "globals": { - "Base64": "write", - "TextDecoder": true, - "TextEncoder": true, - "atob": true, - "btoa": true, - "define": true - }, - "packages": { - "browserify>buffer": true - } - }, - "@ensdomains/content-hash>multicodec": { - "packages": { - "@ensdomains/content-hash>multicodec>uint8arrays": true, - "sass-embedded>varint": true - } - }, - "@ensdomains/content-hash>multicodec>uint8arrays": { - "globals": { - "Buffer": true, - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/assets-controllers>multiformats": true - } - }, - "@ensdomains/content-hash>multihashes": { - "packages": { - "@ensdomains/content-hash>multihashes>multibase": true, - "@ensdomains/content-hash>multihashes>varint": true, - "@ensdomains/content-hash>multihashes>web-encoding": true, - "browserify>buffer": true - } - }, - "@ensdomains/content-hash>multihashes>multibase": { - "packages": { - "@ensdomains/content-hash>multihashes>multibase>base-x": true, - "@ensdomains/content-hash>multihashes>web-encoding": true, - "browserify>buffer": true - } - }, - "@ensdomains/content-hash>multihashes>multibase>base-x": { - "packages": { - "koa>content-disposition>safe-buffer": true - } - }, - "@ensdomains/content-hash>multihashes>web-encoding": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "browserify>util": true - } - }, - "@ethereumjs/common": { - "packages": { - "@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, - "webpack>events": true - } - }, - "@ethereumjs/common>crc-32": { - "globals": { - "DO_NOT_EXPORT_CRC": true, - "define": true - } - }, - "@ethereumjs/tx": { - "packages": { - "@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethereumjs/tx>ethereum-cryptography": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true - } - }, - "@ethereumjs/tx>@ethereumjs/rlp": { - "globals": { - "TextEncoder": true - } - }, - "@ethereumjs/tx>@ethereumjs/util": { - "globals": { - "console.warn": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, - "@ethereumjs/tx>ethereum-cryptography": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "webpack>events": true - } - }, - "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { - "globals": { - "Headers": true, - "TextDecoder": true, - "URL": true, - "btoa": true, - "fetch": true - }, - "packages": { - "browserify>browserify-zlib": true, - "browserify>buffer": true, - "browserify>https-browserify": true, - "browserify>process": true, - "browserify>stream-http": true, - "browserify>url": true, - "browserify>util": true - } - }, - "@ethereumjs/tx>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, - "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true, - "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves": { - "globals": { - "TextEncoder": true - }, - "packages": { - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": { - "packages": { - "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, - "@metamask/utils>@scure/base": true, - "@noble/hashes": true - } - }, - "@ethersproject/abi": { - "globals": { - "console.log": true - }, - "packages": { - "@ethersproject/abi>@ethersproject/address": true, - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/constants": true, - "@ethersproject/abi>@ethersproject/hash": true, - "@ethersproject/abi>@ethersproject/keccak256": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/abi>@ethersproject/strings": true, - "@ethersproject/bignumber": true - } - }, - "@ethersproject/abi>@ethersproject/address": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/keccak256": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/bignumber": true, - "@ethersproject/providers>@ethersproject/rlp": true - } - }, - "@ethersproject/abi>@ethersproject/bytes": { - "packages": { - "@ethersproject/abi>@ethersproject/logger": true - } - }, - "@ethersproject/abi>@ethersproject/constants": { - "packages": { - "@ethersproject/bignumber": true - } - }, - "@ethersproject/abi>@ethersproject/hash": { - "packages": { - "@ethersproject/abi>@ethersproject/address": true, - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/keccak256": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/abi>@ethersproject/strings": true, - "@ethersproject/bignumber": true, - "@ethersproject/providers>@ethersproject/base64": true - } - }, - "@ethersproject/abi>@ethersproject/keccak256": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@metamask/ethjs>js-sha3": true - } - }, - "@ethersproject/abi>@ethersproject/logger": { - "globals": { - "console": true - } - }, - "@ethersproject/abi>@ethersproject/properties": { - "packages": { - "@ethersproject/abi>@ethersproject/logger": true - } - }, - "@ethersproject/abi>@ethersproject/strings": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/constants": true, - "@ethersproject/abi>@ethersproject/logger": true - } - }, - "@ethersproject/bignumber": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true, - "bn.js": true - } - }, - "@ethersproject/contracts": { - "globals": { - "setTimeout": true - }, - "packages": { - "@ethersproject/abi": true, - "@ethersproject/abi>@ethersproject/address": true, - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/bignumber": true, - "@ethersproject/hdnode>@ethersproject/abstract-signer": true, - "@ethersproject/hdnode>@ethersproject/transactions": true, - "@metamask/test-bundler>@ethersproject/abstract-provider": true - } - }, - "@ethersproject/hdnode": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/abi>@ethersproject/strings": true, - "@ethersproject/bignumber": true, - "@ethersproject/hdnode>@ethersproject/basex": true, - "@ethersproject/hdnode>@ethersproject/pbkdf2": true, - "@ethersproject/hdnode>@ethersproject/sha2": true, - "@ethersproject/hdnode>@ethersproject/signing-key": true, - "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/hdnode>@ethersproject/wordlists": true - } - }, - "@ethersproject/hdnode>@ethersproject/abstract-signer": { - "packages": { - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true - } - }, - "@ethersproject/hdnode>@ethersproject/basex": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/properties": true - } - }, - "@ethersproject/hdnode>@ethersproject/pbkdf2": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/hdnode>@ethersproject/sha2": true - } - }, - "@ethersproject/hdnode>@ethersproject/sha2": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true, - "ethereumjs-util>ethereum-cryptography>hash.js": true - } - }, - "@ethersproject/hdnode>@ethersproject/signing-key": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@metamask/ppom-validator>elliptic": true - } - }, - "@ethersproject/hdnode>@ethersproject/transactions": { - "packages": { - "@ethersproject/abi>@ethersproject/address": true, - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/constants": true, - "@ethersproject/abi>@ethersproject/keccak256": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/bignumber": true, - "@ethersproject/hdnode>@ethersproject/signing-key": true, - "@ethersproject/providers>@ethersproject/rlp": true - } - }, - "@ethersproject/hdnode>@ethersproject/wordlists": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/hash": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/abi>@ethersproject/strings": true - } - }, - "@ethersproject/providers": { - "globals": { - "WebSocket": true, - "clearInterval": true, - "clearTimeout": true, - "console.log": true, - "console.warn": true, - "setInterval": true, - "setTimeout": true - }, - "packages": { - "@ethersproject/abi>@ethersproject/address": true, - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/constants": true, - "@ethersproject/abi>@ethersproject/hash": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/abi>@ethersproject/strings": true, - "@ethersproject/bignumber": true, - "@ethersproject/hdnode>@ethersproject/abstract-signer": true, - "@ethersproject/hdnode>@ethersproject/basex": true, - "@ethersproject/hdnode>@ethersproject/sha2": true, - "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/base64": true, - "@ethersproject/providers>@ethersproject/random": true, - "@ethersproject/providers>@ethersproject/web": true, - "@ethersproject/providers>bech32": true, - "@metamask/test-bundler>@ethersproject/abstract-provider": true, - "@metamask/test-bundler>@ethersproject/networks": true - } - }, - "@ethersproject/providers>@ethersproject/base64": { - "globals": { - "atob": true, - "btoa": true - }, - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true - } - }, - "@ethersproject/providers>@ethersproject/random": { - "globals": { - "crypto.getRandomValues": true - }, - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true - } - }, - "@ethersproject/providers>@ethersproject/rlp": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true - } - }, - "@ethersproject/providers>@ethersproject/web": { - "globals": { - "clearTimeout": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/abi>@ethersproject/strings": true, - "@ethersproject/providers>@ethersproject/base64": true - } - }, - "@keystonehq/bc-ur-registry-eth": { - "packages": { - "@ethereumjs/tx>@ethereumjs/util": true, - "@keystonehq/bc-ur-registry-eth>@keystonehq/bc-ur-registry": true, - "@metamask/eth-trezor-keyring>hdkey": true, - "browserify>buffer": true, - "uuid": true - } - }, - "@keystonehq/bc-ur-registry-eth>@keystonehq/bc-ur-registry": { - "globals": { - "define": true - }, - "packages": { - "@ngraveio/bc-ur": true, - "browserify>buffer": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, - "mockttp>graphql-tag>tslib": true - } - }, - "@keystonehq/metamask-airgapped-keyring": { - "packages": { - "@ethereumjs/tx": true, - "@keystonehq/bc-ur-registry-eth": true, - "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, - "@keystonehq/metamask-airgapped-keyring>rlp": true, - "browserify>buffer": true, - "uuid": true, - "webpack>events": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": { - "packages": { - "@ethereumjs/tx": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@keystonehq/bc-ur-registry-eth": true, - "@metamask/eth-trezor-keyring>hdkey": true, - "browserify>buffer": true, - "eth-lattice-keyring>rlp": true, - "uuid": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": { - "packages": { - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": true, - "@metamask/safe-event-emitter": true, - "stream-browserify": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": { - "packages": { - "browserify>process": true, - "browserify>util": true, - "readable-stream": true, - "watchify>xtend": true - } - }, - "@keystonehq/metamask-airgapped-keyring>rlp": { - "packages": { - "bn.js": true, - "browserify>buffer": true - } - }, - "@lavamoat/lavadome-react": { - "globals": { - "Document.prototype": true, - "DocumentFragment.prototype": true, - "Element.prototype": true, - "Node.prototype": true, - "console.warn": true, - "document": true - }, - "packages": { - "react": true - } - }, - "@material-ui/core": { - "globals": { - "Image": true, - "_formatMuiErrorMessage": true, - "addEventListener": true, - "clearInterval": true, - "clearTimeout": true, - "console.error": true, - "console.warn": true, - "document": true, - "getComputedStyle": true, - "getSelection": true, - "innerHeight": true, - "innerWidth": true, - "matchMedia": true, - "navigator": true, - "performance.now": true, - "removeEventListener": true, - "requestAnimationFrame": true, - "setInterval": true, - "setTimeout": true - }, - "packages": { - "@babel/runtime": true, - "@material-ui/core>@material-ui/styles": true, - "@material-ui/core>@material-ui/system": true, - "@material-ui/core>@material-ui/utils": true, - "@material-ui/core>clsx": true, - "@material-ui/core>popper.js": true, - "@material-ui/core>react-transition-group": true, - "prop-types": true, - "prop-types>react-is": true, - "react": true, - "react-dom": true, - "react-redux>hoist-non-react-statics": true - } - }, - "@material-ui/core>@material-ui/styles": { - "globals": { - "console.error": true, - "console.warn": true, - "document.createComment": true, - "document.head": true - }, - "packages": { - "@babel/runtime": true, - "@material-ui/core>@material-ui/styles>jss": true, - "@material-ui/core>@material-ui/styles>jss-plugin-camel-case": true, - "@material-ui/core>@material-ui/styles>jss-plugin-default-unit": true, - "@material-ui/core>@material-ui/styles>jss-plugin-global": true, - "@material-ui/core>@material-ui/styles>jss-plugin-nested": true, - "@material-ui/core>@material-ui/styles>jss-plugin-props-sort": true, - "@material-ui/core>@material-ui/styles>jss-plugin-rule-value-function": true, - "@material-ui/core>@material-ui/styles>jss-plugin-vendor-prefixer": true, - "@material-ui/core>@material-ui/utils": true, - "@material-ui/core>clsx": true, - "prop-types": true, - "react": true, - "react-redux>hoist-non-react-statics": true - } - }, - "@material-ui/core>@material-ui/styles>jss": { - "globals": { - "CSS": true, - "document.createElement": true, - "document.querySelector": true - }, - "packages": { - "@babel/runtime": true, - "@material-ui/core>@material-ui/styles>jss>is-in-browser": true, - "react-router-dom>tiny-warning": true - } - }, - "@material-ui/core>@material-ui/styles>jss-plugin-camel-case": { - "packages": { - "@material-ui/core>@material-ui/styles>jss-plugin-camel-case>hyphenate-style-name": true - } - }, - "@material-ui/core>@material-ui/styles>jss-plugin-default-unit": { - "globals": { - "CSS": true - }, - "packages": { - "@material-ui/core>@material-ui/styles>jss": true - } - }, - "@material-ui/core>@material-ui/styles>jss-plugin-global": { - "packages": { - "@babel/runtime": true, - "@material-ui/core>@material-ui/styles>jss": true - } - }, - "@material-ui/core>@material-ui/styles>jss-plugin-nested": { - "packages": { - "@babel/runtime": true, - "react-router-dom>tiny-warning": true - } - }, - "@material-ui/core>@material-ui/styles>jss-plugin-rule-value-function": { - "packages": { - "@material-ui/core>@material-ui/styles>jss": true, - "react-router-dom>tiny-warning": true - } - }, - "@material-ui/core>@material-ui/styles>jss-plugin-vendor-prefixer": { - "packages": { - "@material-ui/core>@material-ui/styles>jss": true, - "@material-ui/core>@material-ui/styles>jss-plugin-vendor-prefixer>css-vendor": true - } - }, - "@material-ui/core>@material-ui/styles>jss-plugin-vendor-prefixer>css-vendor": { - "globals": { - "document.createElement": true, - "document.documentElement": true, - "getComputedStyle": true - }, - "packages": { - "@babel/runtime": true, - "@material-ui/core>@material-ui/styles>jss>is-in-browser": true - } - }, - "@material-ui/core>@material-ui/styles>jss>is-in-browser": { - "globals": { - "document": true - } - }, - "@material-ui/core>@material-ui/system": { - "globals": { - "console.error": true - }, - "packages": { - "@babel/runtime": true, - "@material-ui/core>@material-ui/utils": true, - "prop-types": true - } - }, - "@material-ui/core>@material-ui/utils": { - "packages": { - "@babel/runtime": true, - "prop-types": true, - "prop-types>react-is": true - } - }, - "@material-ui/core>popper.js": { - "globals": { - "MSInputMethodContext": true, - "Node.DOCUMENT_POSITION_FOLLOWING": true, - "cancelAnimationFrame": true, - "console.warn": true, - "define": true, - "devicePixelRatio": true, - "document": true, - "getComputedStyle": true, - "innerHeight": true, - "innerWidth": true, - "navigator": true, - "requestAnimationFrame": true, - "setTimeout": true - } - }, - "@material-ui/core>react-transition-group": { - "globals": { - "Element": true, - "setTimeout": true - }, - "packages": { - "@material-ui/core>react-transition-group>dom-helpers": true, - "prop-types": true, - "react": true, - "react-dom": true - } - }, - "@material-ui/core>react-transition-group>dom-helpers": { - "packages": { - "@babel/runtime": true - } - }, - "@metamask/abi-utils": { - "packages": { - "@metamask/utils": true, - "superstruct": true - } - }, - "@metamask/accounts-controller": { - "packages": { - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/base-controller": true, - "@metamask/eth-snap-keyring": true, - "@metamask/keyring-api": true, - "@metamask/keyring-controller": true, - "uuid": true - } - }, - "@metamask/address-book-controller": { - "packages": { - "@metamask/address-book-controller>@metamask/base-controller": true, - "@metamask/address-book-controller>@metamask/controller-utils": true - } - }, - "@metamask/address-book-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/address-book-controller>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": true, - "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true - } - }, - "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, - "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": { - "packages": { - "@metamask/ethjs>ethjs-abi>number-to-bn": true, - "bn.js": true - } - }, - "@metamask/announcement-controller": { - "packages": { - "@metamask/base-controller": true - } - }, - "@metamask/announcement-controller>@metamask/base-controller": { - "packages": { - "immer": true - } - }, - "@metamask/approval-controller": { - "globals": { - "console.info": true - }, - "packages": { - "@metamask/approval-controller>nanoid": true, - "@metamask/base-controller": true, - "@metamask/providers>@metamask/rpc-errors": true - } - }, - "@metamask/approval-controller>nanoid": { - "globals": { - "crypto.getRandomValues": true - } - }, - "@metamask/assets-controllers": { - "globals": { - "AbortController": true, - "Headers": true, - "URL": true, - "clearInterval": true, - "clearTimeout": true, - "console.error": true, - "console.log": true, - "setInterval": true, - "setTimeout": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/abi>@ethersproject/address": true, - "@ethersproject/contracts": true, - "@ethersproject/providers": true, - "@metamask/abi-utils": true, - "@metamask/assets-controllers>@metamask/polling-controller": true, - "@metamask/assets-controllers>cockatiel": true, - "@metamask/assets-controllers>multiformats": true, - "@metamask/base-controller": true, - "@metamask/contract-metadata": true, - "@metamask/controller-utils": true, - "@metamask/eth-query": true, - "@metamask/metamask-eth-abis": true, - "@metamask/name-controller>async-mutex": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/utils": true, - "bn.js": true, - "lodash": true, - "single-call-balance-checker-abi": true, - "uuid": true, - "webpack>events": true - } - }, - "@metamask/assets-controllers>@metamask/polling-controller": { - "globals": { - "clearTimeout": true, - "console.error": true, - "setTimeout": true - }, - "packages": { - "@metamask/base-controller": true, - "@metamask/snaps-utils>fast-json-stable-stringify": true, - "uuid": true - } - }, - "@metamask/assets-controllers>cockatiel": { - "globals": { - "AbortController": true, - "AbortSignal": true, - "WeakRef": true, - "clearTimeout": true, - "performance": true, - "setTimeout": true - }, - "packages": { - "browserify>process": true - } - }, - "@metamask/assets-controllers>multiformats": { - "globals": { - "TextDecoder": true, - "TextEncoder": true, - "console.warn": true, - "crypto.subtle.digest": true - } - }, - "@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/browser-passworder": { - "globals": { - "CryptoKey": true, - "btoa": true, - "crypto.getRandomValues": true, - "crypto.subtle.decrypt": true, - "crypto.subtle.deriveKey": true, - "crypto.subtle.encrypt": true, - "crypto.subtle.exportKey": true, - "crypto.subtle.importKey": true - }, - "packages": { - "@metamask/utils": true, - "browserify>buffer": true - } - }, - "@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/ethjs>@metamask/ethjs-unit": true, - "@metamask/utils": true, - "bn.js": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true - } - }, - "@metamask/controller-utils>@spruceid/siwe-parser": { - "globals": { - "console.error": true, - "console.log": true - }, - "packages": { - "@metamask/controller-utils>@spruceid/siwe-parser>apg-js": true - } - }, - "@metamask/controller-utils>@spruceid/siwe-parser>apg-js": { - "globals": { - "mode": true - }, - "packages": { - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true - } - }, - "@metamask/controllers>web3": { - "globals": { - "XMLHttpRequest": true - } - }, - "@metamask/controllers>web3-provider-engine>cross-fetch>node-fetch": { - "globals": { - "fetch": true - } - }, - "@metamask/controllers>web3-provider-engine>eth-json-rpc-middleware>node-fetch": { - "globals": { - "fetch": true - } - }, - "@metamask/desktop": { - "globals": { - "TextDecoder": true, - "TextEncoder": true, - "WebSocket": true, - "clearInterval": true, - "clearTimeout": true, - "crypto.getRandomValues": true, - "crypto.subtle.decrypt": true, - "crypto.subtle.digest": true, - "crypto.subtle.encrypt": true, - "crypto.subtle.exportKey": true, - "crypto.subtle.generateKey": true, - "crypto.subtle.importKey": true, - "isDesktopApp": true, - "setInterval": true, - "setTimeout": true - }, - "packages": { - "@metamask/desktop>@metamask/obs-store": true, - "@metamask/desktop>eciesjs": true, - "@metamask/desktop>extension-port-stream": true, - "@metamask/desktop>otpauth": true, - "browserify>buffer": true, - "end-of-stream": true, - "loglevel": true, - "obj-multiplex": true, - "stream-browserify": true, - "uuid": true, - "webextension-polyfill": true, - "webpack>events": true - } - }, - "@metamask/desktop>@metamask/obs-store": { - "globals": { - "localStorage": true - }, - "packages": { - "@metamask/desktop>@metamask/obs-store>through2": true, - "@metamask/safe-event-emitter": true, - "stream-browserify": true - } - }, - "@metamask/desktop>@metamask/obs-store>through2": { - "packages": { - "browserify>process": true, - "browserify>util": true, - "readable-stream": true, - "watchify>xtend": true - } - }, - "@metamask/desktop>eciesjs": { - "packages": { - "@metamask/desktop>eciesjs>futoin-hkdf": true, - "browserify>buffer": true, - "browserify>crypto-browserify": true, - "ganache>secp256k1": true - } - }, - "@metamask/desktop>eciesjs>futoin-hkdf": { - "packages": { - "browserify>buffer": true, - "browserify>crypto-browserify": true - } - }, - "@metamask/desktop>extension-port-stream": { - "packages": { - "browserify>buffer": true, - "stream-browserify": true - } - }, - "@metamask/desktop>otpauth": { - "globals": { - "__GLOBALTHIS__": true, - "define": true - } - }, - "@metamask/ens-controller": { - "packages": { - "@ethersproject/providers": true, - "@metamask/base-controller": true, - "@metamask/controller-utils": true, - "@metamask/utils": true, - "ethereum-ens-network-map": true, - "punycode": true - } - }, - "@metamask/eth-json-rpc-filters": { - "globals": { - "console.error": true - }, - "packages": { - "@metamask/eth-json-rpc-filters>@metamask/eth-query": true, - "@metamask/eth-json-rpc-filters>@metamask/safe-event-emitter": true, - "@metamask/name-controller>async-mutex": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "pify": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/eth-query": { - "packages": { - "@metamask/eth-query>json-rpc-random-id": true, - "watchify>xtend": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, - "@metamask/eth-json-rpc-middleware": { - "globals": { - "URL": true, - "console.error": true, - "setTimeout": true - }, - "packages": { - "@metamask/eth-json-rpc-middleware>safe-stable-stringify": true, - "@metamask/eth-sig-util": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/utils": true, - "pify": true, - "sass-loader>klona": true - } - }, - "@metamask/eth-keyring-controller": { - "globals": { - "console.error": true - }, - "packages": { - "@metamask/browser-passworder": true, - "@metamask/eth-keyring-controller>@metamask/obs-store": true, - "@metamask/eth-sig-util": true, - "@metamask/keyring-controller>@metamask/eth-hd-keyring": true, - "@metamask/keyring-controller>@metamask/eth-simple-keyring": true, - "@metamask/utils": true, - "webpack>events": true - } - }, - "@metamask/eth-keyring-controller>@metamask/obs-store": { - "packages": { - "@metamask/eth-keyring-controller>@metamask/obs-store>@metamask/safe-event-emitter": true, - "@metamask/eth-keyring-controller>@metamask/obs-store>readable-stream": true - } - }, - "@metamask/eth-keyring-controller>@metamask/obs-store>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, - "@metamask/eth-keyring-controller>@metamask/obs-store>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "@metamask/eth-ledger-bridge-keyring": { - "globals": { - "addEventListener": true, - "console.log": true, - "document.createElement": true, - "document.head.appendChild": true, - "fetch": true, - "removeEventListener": true - }, - "packages": { - "@ethereumjs/tx": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/eth-sig-util": true, - "@metamask/eth-trezor-keyring>hdkey": true, - "browserify>buffer": true, - "webpack>events": true - } - }, - "@metamask/eth-query": { - "packages": { - "@metamask/eth-query>json-rpc-random-id": true, - "watchify>xtend": true - } - }, - "@metamask/eth-sig-util": { - "packages": { - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/abi-utils": true, - "@metamask/eth-sig-util>tweetnacl": true, - "@metamask/eth-sig-util>tweetnacl-util": true, - "@metamask/utils": true, - "browserify>buffer": true - } - }, - "@metamask/eth-sig-util>tweetnacl": { - "globals": { - "crypto": true, - "msCrypto": true, - "nacl": "write" - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "@metamask/eth-sig-util>tweetnacl-util": { - "globals": { - "atob": true, - "btoa": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "@metamask/eth-snap-keyring": { - "globals": { - "console.error": true - }, - "packages": { - "@ethereumjs/tx": true, - "@metamask/eth-sig-util": true, - "@metamask/eth-snap-keyring>@metamask/keyring-api": true, - "@metamask/eth-snap-keyring>uuid": true, - "@metamask/utils": true, - "superstruct": true, - "webpack>events": true - } - }, - "@metamask/eth-snap-keyring>@metamask/keyring-api": { - "packages": { - "@metamask/eth-snap-keyring>uuid": true, - "@metamask/utils": true, - "superstruct": true - } - }, - "@metamask/eth-snap-keyring>uuid": { - "globals": { - "crypto": true - } - }, - "@metamask/eth-token-tracker": { - "globals": { - "console.warn": true - }, - "packages": { - "@babel/runtime": true, - "@metamask/eth-token-tracker>@metamask/safe-event-emitter": true, - "@metamask/eth-token-tracker>deep-equal": true, - "@metamask/eth-token-tracker>eth-block-tracker": true, - "@metamask/ethjs-contract": true, - "@metamask/ethjs-query": true, - "bn.js": true, - "human-standard-token-abi": true - } - }, - "@metamask/eth-token-tracker>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, - "@metamask/eth-token-tracker>deep-equal": { - "packages": { - "@lavamoat/lavapack>json-stable-stringify>isarray": true, - "@lavamoat/lavapack>json-stable-stringify>object-keys": true, - "@metamask/eth-token-tracker>deep-equal>es-get-iterator": true, - "@metamask/eth-token-tracker>deep-equal>is-date-object": true, - "@metamask/eth-token-tracker>deep-equal>which-boxed-primitive": true, - "@metamask/eth-token-tracker>deep-equal>which-collection": true, - "@ngraveio/bc-ur>assert>object-is": true, - "browserify>util>is-arguments": true, - "browserify>util>which-typed-array": true, - "gulp>vinyl-fs>object.assign": true, - "string.prototype.matchall>call-bind": true, - "string.prototype.matchall>es-abstract>array-buffer-byte-length": true, - "string.prototype.matchall>es-abstract>is-array-buffer": true, - "string.prototype.matchall>es-abstract>is-regex": true, - "string.prototype.matchall>es-abstract>is-shared-array-buffer": true, - "string.prototype.matchall>get-intrinsic": true, - "string.prototype.matchall>regexp.prototype.flags": true, - "string.prototype.matchall>side-channel": true - } - }, - "@metamask/eth-token-tracker>deep-equal>es-get-iterator": { - "packages": { - "@lavamoat/lavapack>json-stable-stringify>isarray": true, - "@metamask/eth-token-tracker>deep-equal>es-get-iterator>is-map": true, - "@metamask/eth-token-tracker>deep-equal>es-get-iterator>is-set": true, - "@metamask/eth-token-tracker>deep-equal>es-get-iterator>stop-iteration-iterator": true, - "browserify>process": true, - "browserify>util>is-arguments": true, - "eslint-plugin-react>array-includes>is-string": true, - "string.prototype.matchall>call-bind": true, - "string.prototype.matchall>get-intrinsic": true, - "string.prototype.matchall>has-symbols": true - } - }, - "@metamask/eth-token-tracker>deep-equal>es-get-iterator>stop-iteration-iterator": { - "globals": { - "StopIteration": true - }, - "packages": { - "string.prototype.matchall>internal-slot": true - } - }, - "@metamask/eth-token-tracker>deep-equal>is-date-object": { - "packages": { - "koa>is-generator-function>has-tostringtag": true - } - }, - "@metamask/eth-token-tracker>deep-equal>which-boxed-primitive": { - "packages": { - "@metamask/eth-token-tracker>deep-equal>which-boxed-primitive>is-bigint": true, - "@metamask/eth-token-tracker>deep-equal>which-boxed-primitive>is-boolean-object": true, - "@metamask/eth-token-tracker>deep-equal>which-boxed-primitive>is-number-object": true, - "eslint-plugin-react>array-includes>is-string": true, - "string.prototype.matchall>es-abstract>es-to-primitive>is-symbol": true - } - }, - "@metamask/eth-token-tracker>deep-equal>which-boxed-primitive>is-bigint": { - "packages": { - "string.prototype.matchall>es-abstract>unbox-primitive>has-bigints": true - } - }, - "@metamask/eth-token-tracker>deep-equal>which-boxed-primitive>is-boolean-object": { - "packages": { - "koa>is-generator-function>has-tostringtag": true, - "string.prototype.matchall>call-bind": true - } - }, - "@metamask/eth-token-tracker>deep-equal>which-boxed-primitive>is-number-object": { - "packages": { - "koa>is-generator-function>has-tostringtag": true - } - }, - "@metamask/eth-token-tracker>deep-equal>which-collection": { - "packages": { - "@metamask/eth-token-tracker>deep-equal>es-get-iterator>is-map": true, - "@metamask/eth-token-tracker>deep-equal>es-get-iterator>is-set": true, - "@metamask/eth-token-tracker>deep-equal>which-collection>is-weakmap": true, - "@metamask/eth-token-tracker>deep-equal>which-collection>is-weakset": true - } - }, - "@metamask/eth-token-tracker>deep-equal>which-collection>is-weakset": { - "packages": { - "string.prototype.matchall>call-bind": true, - "string.prototype.matchall>get-intrinsic": true - } - }, - "@metamask/eth-token-tracker>eth-block-tracker": { - "globals": { - "clearTimeout": true, - "console.error": true, - "setTimeout": true - }, - "packages": { - "@metamask/eth-query>json-rpc-random-id": true, - "@metamask/eth-token-tracker>eth-block-tracker>@metamask/safe-event-emitter": true, - "@metamask/utils": true, - "pify": true - } - }, - "@metamask/eth-token-tracker>eth-block-tracker>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, - "@metamask/eth-trezor-keyring": { - "globals": { - "setTimeout": true - }, - "packages": { - "@ethereumjs/tx": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": true, - "@metamask/eth-trezor-keyring>hdkey": true, - "@trezor/connect-web": true, - "browserify>buffer": true, - "webpack>events": true - } - }, - "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": { - "packages": { - "@metamask/eth-sig-util": true - } - }, - "@metamask/eth-trezor-keyring>hdkey": { - "packages": { - "browserify>assert": true, - "browserify>crypto-browserify": true, - "ethereumjs-util>create-hash>ripemd160": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, - "ganache>secp256k1": true, - "koa>content-disposition>safe-buffer": true - } - }, - "@metamask/etherscan-link": { - "globals": { - "URL": true - } - }, - "@metamask/ethjs": { - "globals": { - "clearInterval": true, - "setInterval": true - }, - "packages": { - "@metamask/ethjs-contract": true, - "@metamask/ethjs-query": true, - "@metamask/ethjs>@metamask/ethjs-filter": true, - "@metamask/ethjs>@metamask/ethjs-provider-http": true, - "@metamask/ethjs>@metamask/ethjs-unit": true, - "@metamask/ethjs>@metamask/ethjs-util": true, - "@metamask/ethjs>@metamask/number-to-bn": true, - "@metamask/ethjs>ethjs-abi": true, - "@metamask/ethjs>js-sha3": true, - "bn.js": true, - "browserify>buffer": true - } - }, - "@metamask/ethjs-contract": { - "packages": { - "@babel/runtime": true, - "@metamask/ethjs>@metamask/ethjs-filter": true, - "@metamask/ethjs>@metamask/ethjs-util": true, - "@metamask/ethjs>ethjs-abi": true, - "@metamask/ethjs>js-sha3": true, - "promise-to-callback": true - } - }, - "@metamask/ethjs-query": { - "globals": { - "console": true - }, - "packages": { - "@metamask/ethjs-query>@metamask/ethjs-format": true, - "@metamask/ethjs-query>@metamask/ethjs-rpc": true, - "promise-to-callback": true - } - }, - "@metamask/ethjs-query>@metamask/ethjs-format": { - "packages": { - "@metamask/ethjs-query>@metamask/ethjs-format>ethjs-schema": true, - "@metamask/ethjs>@metamask/ethjs-util": true, - "@metamask/ethjs>@metamask/ethjs-util>strip-hex-prefix": true, - "@metamask/ethjs>@metamask/number-to-bn": true - } - }, - "@metamask/ethjs-query>@metamask/ethjs-rpc": { - "packages": { - "promise-to-callback": true - } - }, - "@metamask/ethjs>@metamask/ethjs-filter": { - "globals": { - "clearInterval": true, - "setInterval": true - } - }, - "@metamask/ethjs>@metamask/ethjs-provider-http": { - "packages": { - "@metamask/ethjs>@metamask/ethjs-provider-http>xhr2": true - } - }, - "@metamask/ethjs>@metamask/ethjs-provider-http>xhr2": { - "globals": { - "XMLHttpRequest": true - } - }, - "@metamask/ethjs>@metamask/ethjs-unit": { - "packages": { - "@metamask/ethjs>@metamask/number-to-bn": true, - "bn.js": true - } - }, - "@metamask/ethjs>@metamask/ethjs-util": { - "packages": { - "@metamask/ethjs>@metamask/ethjs-util>is-hex-prefixed": true, - "@metamask/ethjs>@metamask/ethjs-util>strip-hex-prefix": true, - "browserify>buffer": true - } - }, - "@metamask/ethjs>@metamask/ethjs-util>strip-hex-prefix": { - "packages": { - "@metamask/ethjs>@metamask/ethjs-util>is-hex-prefixed": true - } - }, - "@metamask/ethjs>@metamask/number-to-bn": { - "packages": { - "@metamask/ethjs>@metamask/ethjs-util>strip-hex-prefix": true, - "bn.js": true - } - }, - "@metamask/ethjs>ethjs-abi": { - "packages": { - "@metamask/ethjs>ethjs-abi>number-to-bn": true, - "@metamask/ethjs>js-sha3": true, - "bn.js": true, - "browserify>buffer": true - } - }, - "@metamask/ethjs>ethjs-abi>number-to-bn": { - "packages": { - "@metamask/ethjs>@metamask/ethjs-util>strip-hex-prefix": true, - "bn.js": true - } - }, - "@metamask/ethjs>js-sha3": { - "globals": { - "define": true - }, - "packages": { - "browserify>process": true - } - }, - "@metamask/gas-fee-controller": { - "globals": { - "clearInterval": true, - "console.error": true, - "setInterval": true - }, - "packages": { - "@metamask/assets-controllers>@metamask/polling-controller": true, - "@metamask/controller-utils": true, - "@metamask/eth-query": true, - "@metamask/ethjs>@metamask/ethjs-unit": true, - "ethereumjs-util": true, - "uuid": true - } - }, - "@metamask/jazzicon": { - "globals": { - "document.createElement": true, - "document.createElementNS": true - }, - "packages": { - "@metamask/jazzicon>color": true, - "@metamask/jazzicon>mersenne-twister": true - } - }, - "@metamask/jazzicon>color": { - "packages": { - "@metamask/jazzicon>color>clone": true, - "@metamask/jazzicon>color>color-convert": true, - "@metamask/jazzicon>color>color-string": true - } - }, - "@metamask/jazzicon>color>clone": { - "packages": { - "browserify>buffer": true - } - }, - "@metamask/jazzicon>color>color-convert": { - "packages": { - "@metamask/jazzicon>color>color-convert>color-name": true - } - }, - "@metamask/jazzicon>color>color-string": { - "packages": { - "jest-canvas-mock>moo-color>color-name": true - } - }, - "@metamask/keyring-api": { - "packages": { - "@metamask/keyring-api>uuid": true, - "@metamask/utils": true, - "superstruct": true - } - }, - "@metamask/keyring-api>uuid": { - "globals": { - "crypto": true - } - }, - "@metamask/keyring-controller": { - "packages": { - "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/base-controller": true, - "@metamask/browser-passworder": true, - "@metamask/eth-sig-util": true, - "@metamask/keyring-controller>@metamask/eth-hd-keyring": true, - "@metamask/keyring-controller>@metamask/eth-simple-keyring": true, - "@metamask/keyring-controller>ethereumjs-wallet": true, - "@metamask/name-controller>async-mutex": true, - "@metamask/utils": true - } - }, - "@metamask/keyring-controller>@metamask/eth-hd-keyring": { - "globals": { - "TextEncoder": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-sig-util": true, - "@metamask/scure-bip39": true, - "@metamask/utils": true, - "browserify>buffer": true - } - }, - "@metamask/keyring-controller>@metamask/eth-simple-keyring": { - "packages": { - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/eth-sig-util": true, - "@metamask/utils": true, - "browserify>buffer": true, - "mocha>serialize-javascript>randombytes": true - } - }, - "@metamask/keyring-controller>ethereumjs-wallet": { - "packages": { - "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": true, - "@metamask/keyring-controller>ethereumjs-wallet>utf8": true, - "browserify>buffer": true, - "browserify>crypto-browserify": true, - "eth-lattice-keyring>gridplus-sdk>aes-js": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, - "ethereumjs-util>ethereum-cryptography>scrypt-js": true, - "mocha>serialize-javascript>randombytes": true, - "uuid": true - } - }, - "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": { - "packages": { - "browserify>assert": true, - "browserify>buffer": true, - "browserify>crypto-browserify>create-hmac": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, - "ethereumjs-util>ethereum-cryptography>hash.js": true, - "ganache>keccak": true, - "ganache>secp256k1": true, - "koa>content-disposition>safe-buffer": true, - "mocha>serialize-javascript>randombytes": true - } - }, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { - "packages": { - "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": true, - "bn.js": true, - "browserify>assert": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>create-hash": true - } - }, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": { - "packages": { - "bn.js": true, - "browserify>buffer": true - } - }, - "@metamask/logging-controller": { - "packages": { - "@metamask/base-controller": true, - "uuid": true - } - }, - "@metamask/logo": { - "globals": { - "addEventListener": true, - "document.body.appendChild": true, - "document.createElementNS": true, - "innerHeight": true, - "innerWidth": true, - "requestAnimationFrame": true - }, - "packages": { - "@metamask/logo>gl-mat4": true, - "@metamask/logo>gl-vec3": true - } - }, - "@metamask/message-manager": { - "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, - "@metamask/eth-sig-util": true, - "@metamask/message-manager>jsonschema": true, - "@metamask/utils": true, - "browserify>buffer": true, - "uuid": true, - "webpack>events": true - } - }, - "@metamask/message-manager>jsonschema": { - "packages": { - "browserify>url": true - } - }, - "@metamask/name-controller": { - "globals": { - "fetch": true - }, - "packages": { - "@metamask/base-controller": true, - "@metamask/name-controller>async-mutex": true, - "@metamask/utils": true - } - }, - "@metamask/name-controller>async-mutex": { - "globals": { - "setTimeout": true - }, - "packages": { - "mockttp>graphql-tag>tslib": true - } - }, - "@metamask/network-controller": { - "globals": { - "URL": true, - "btoa": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, - "@metamask/eth-json-rpc-middleware": true, - "@metamask/eth-query": true, - "@metamask/eth-token-tracker>eth-block-tracker": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura": true, - "@metamask/network-controller>@metamask/eth-json-rpc-provider": true, - "@metamask/network-controller>@metamask/swappable-obj-proxy": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/utils": true, - "browserify>assert": true, - "uuid": true - } - }, - "@metamask/network-controller>@metamask/eth-json-rpc-infura": { - "globals": { - "setTimeout": true - }, - "packages": { - "@metamask/network-controller>@metamask/eth-json-rpc-provider": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/utils": true, - "node-fetch": true - } - }, - "@metamask/network-controller>@metamask/eth-json-rpc-provider": { - "packages": { - "@metamask/network-controller>@metamask/eth-json-rpc-provider>@metamask/safe-event-emitter": true, - "@metamask/providers>@metamask/json-rpc-engine": true - } - }, - "@metamask/network-controller>@metamask/eth-json-rpc-provider>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, - "@metamask/notification-controller": { - "packages": { - "@metamask/notification-controller>@metamask/base-controller": true, - "@metamask/notification-controller>@metamask/utils": true, - "@metamask/notification-controller>nanoid": true - } - }, - "@metamask/notification-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/notification-controller>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, - "@metamask/notification-controller>nanoid": { - "globals": { - "crypto.getRandomValues": true - } - }, - "@metamask/obs-store": { - "packages": { - "@metamask/obs-store>through2": true, - "@metamask/safe-event-emitter": true, - "stream-browserify": true - } - }, - "@metamask/obs-store>through2": { - "packages": { - "browserify>process": true, - "browserify>util": true, - "readable-stream": true, - "watchify>xtend": true - } - }, - "@metamask/permission-controller": { - "globals": { - "console.error": true - }, - "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, - "@metamask/permission-controller>nanoid": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/utils": true, - "deep-freeze-strict": true, - "immer": true - } - }, - "@metamask/permission-controller>nanoid": { - "globals": { - "crypto.getRandomValues": true - } - }, - "@metamask/permission-log-controller": { - "packages": { - "@metamask/base-controller": true, - "@metamask/utils": true - } - }, - "@metamask/phishing-controller": { - "globals": { - "fetch": true - }, - "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, - "@metamask/phishing-warning>eth-phishing-detect": true, - "punycode": true - } - }, - "@metamask/phishing-warning>eth-phishing-detect": { - "packages": { - "eslint>optionator>fast-levenshtein": true - } - }, - "@metamask/post-message-stream": { - "globals": { - "MessageEvent.prototype": true, - "WorkerGlobalScope": true, - "addEventListener": true, - "browser": true, - "chrome": true, - "location.origin": true, - "postMessage": true, - "removeEventListener": true - }, - "packages": { - "@metamask/post-message-stream>readable-stream": true, - "@metamask/utils": true - } - }, - "@metamask/post-message-stream>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "@metamask/ppom-validator>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethereumjs-util>ethereum-cryptography>hash.js": true, - "pumpify>inherits": true - } - }, - "@metamask/ppom-validator>elliptic>brorand": { - "globals": { - "crypto": true, - "msCrypto": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "@metamask/ppom-validator>elliptic>hmac-drbg": { - "packages": { - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "ethereumjs-util>ethereum-cryptography>hash.js": true - } - }, - "@metamask/providers>@metamask/json-rpc-engine": { - "packages": { - "@metamask/providers>@metamask/json-rpc-engine>@metamask/safe-event-emitter": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/utils": true - } - }, - "@metamask/providers>@metamask/json-rpc-engine>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, - "@metamask/providers>@metamask/object-multiplex": { - "globals": { - "console.warn": true - }, - "packages": { - "@metamask/providers>@metamask/object-multiplex>readable-stream": true, - "pump>once": true - } - }, - "@metamask/providers>@metamask/object-multiplex>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "@metamask/providers>@metamask/rpc-errors": { - "packages": { - "@metamask/utils": true, - "eth-rpc-errors>fast-safe-stringify": true - } - }, - "@metamask/queued-request-controller": { - "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/selected-network-controller": true - } - }, - "@metamask/rate-limit-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "@metamask/rate-limit-controller>@metamask/base-controller": true, - "eth-rpc-errors": true - } - }, - "@metamask/rate-limit-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/rpc-methods-flask>nanoid": { - "globals": { - "crypto.getRandomValues": true - } - }, - "@metamask/rpc-methods>nanoid": { - "globals": { - "crypto.getRandomValues": true - } - }, - "@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, - "@metamask/scure-bip39": { - "globals": { - "TextEncoder": true - }, - "packages": { - "@metamask/scure-bip39>@noble/hashes": true, - "@metamask/utils>@scure/base": true - } - }, - "@metamask/scure-bip39>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, - "@metamask/selected-network-controller": { - "packages": { - "@metamask/base-controller": true, - "@metamask/network-controller>@metamask/swappable-obj-proxy": true - } - }, - "@metamask/signature-controller": { - "globals": { - "console.info": true - }, - "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, - "@metamask/logging-controller": true, - "@metamask/message-manager": true, - "@metamask/providers>@metamask/rpc-errors": true, - "browserify>buffer": true, - "ethereumjs-util": true, - "lodash": true, - "webpack>events": true - } - }, - "@metamask/smart-transactions-controller": { - "globals": { - "URLSearchParams": true, - "clearInterval": true, - "console.error": true, - "console.log": true, - "fetch": true, - "setInterval": true - }, - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/bignumber": true, - "@ethersproject/providers": true, - "@metamask/smart-transactions-controller>@metamask/base-controller": true, - "@metamask/smart-transactions-controller>@metamask/controller-utils": true, - "@metamask/smart-transactions-controller>bignumber.js": true, - "fast-json-patch": true, - "lodash": true - } - }, - "@metamask/smart-transactions-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/smart-transactions-controller>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/utils": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true - } - }, - "@metamask/smart-transactions-controller>@metamask/controllers>nanoid": { - "globals": { - "crypto.getRandomValues": true - } - }, - "@metamask/smart-transactions-controller>bignumber.js": { - "globals": { - "crypto": true, - "define": true - } - }, - "@metamask/snaps-controllers": { - "globals": { - "DecompressionStream": true, - "URL": true, - "chrome.offscreen.createDocument": true, - "chrome.offscreen.hasDocument": true, - "clearTimeout": true, - "document.getElementById": true, - "fetch.bind": true, - "setTimeout": true - }, - "packages": { - "@metamask/base-controller": true, - "@metamask/permission-controller": true, - "@metamask/post-message-stream": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/object-multiplex": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/snaps-controllers>@xstate/fsm": true, - "@metamask/snaps-controllers>concat-stream": true, - "@metamask/snaps-controllers>get-npm-tarball-url": true, - "@metamask/snaps-controllers>nanoid": true, - "@metamask/snaps-controllers>readable-stream": true, - "@metamask/snaps-controllers>readable-web-to-node-stream": true, - "@metamask/snaps-controllers>tar-stream": true, - "@metamask/snaps-rpc-methods": true, - "@metamask/snaps-sdk": true, - "@metamask/snaps-utils": true, - "@metamask/snaps-utils>@metamask/snaps-registry": true, - "@metamask/utils": true, - "browserify>browserify-zlib": true, - "json-rpc-middleware-stream": true - } - }, - "@metamask/snaps-controllers-flask>nanoid": { - "globals": { - "crypto.getRandomValues": true - } - }, - "@metamask/snaps-controllers>concat-stream": { - "packages": { - "@metamask/snaps-controllers>readable-stream": true, - "browserify>buffer": true, - "browserify>concat-stream>typedarray": true, - "pumpify>inherits": true, - "terser>source-map-support>buffer-from": true - } - }, - "@metamask/snaps-controllers>nanoid": { - "globals": { - "crypto.getRandomValues": true - } - }, - "@metamask/snaps-controllers>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "@metamask/snaps-controllers>readable-web-to-node-stream": { - "packages": { - "@metamask/snaps-controllers>readable-web-to-node-stream>readable-stream": true - } - }, - "@metamask/snaps-controllers>readable-web-to-node-stream>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "@metamask/snaps-controllers>tar-stream": { - "packages": { - "@metamask/snaps-controllers>tar-stream>b4a": true, - "@metamask/snaps-controllers>tar-stream>fast-fifo": true, - "@metamask/snaps-controllers>tar-stream>streamx": true, - "browserify>browser-resolve": true - } - }, - "@metamask/snaps-controllers>tar-stream>b4a": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - } - }, - "@metamask/snaps-controllers>tar-stream>streamx": { - "packages": { - "@metamask/snaps-controllers>tar-stream>fast-fifo": true, - "@metamask/snaps-controllers>tar-stream>streamx>queue-tick": true, - "webpack>events": true - } - }, - "@metamask/snaps-controllers>tar-stream>streamx>queue-tick": { - "globals": { - "queueMicrotask": true - } - }, - "@metamask/snaps-rpc-methods": { - "packages": { - "@metamask/permission-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/snaps-sdk": true, - "@metamask/snaps-sdk>@metamask/key-tree": true, - "@metamask/snaps-utils": true, - "@metamask/utils": true, - "@noble/hashes": true, - "superstruct": true - } - }, - "@metamask/snaps-sdk": { - "globals": { - "fetch": true - }, - "packages": { - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/snaps-sdk>fast-xml-parser": true, - "@metamask/utils": true, - "superstruct": true - } - }, - "@metamask/snaps-sdk>@metamask/key-tree": { - "packages": { - "@metamask/scure-bip39": true, - "@metamask/snaps-sdk>@metamask/key-tree>@metamask/utils": true, - "@metamask/snaps-sdk>@metamask/key-tree>@noble/ed25519": true, - "@metamask/utils>@scure/base": true, - "@noble/hashes": true, - "eth-lattice-keyring>@noble/secp256k1": true - } - }, - "@metamask/snaps-sdk>@metamask/key-tree>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, - "@metamask/snaps-sdk>@metamask/key-tree>@noble/ed25519": { - "globals": { - "crypto": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "@metamask/snaps-sdk>fast-xml-parser": { - "globals": { - "entityName": true, - "val": true - }, - "packages": { - "@metamask/snaps-sdk>fast-xml-parser>strnum": true - } - }, - "@metamask/snaps-utils": { - "globals": { - "File": true, - "FileReader": true, - "TextDecoder": true, - "URL": true, - "console.error": true, - "console.log": true, - "console.warn": true, - "crypto": true, - "document.body.appendChild": true, - "document.createElement": true, - "fetch": true - }, - "packages": { - "@metamask/permission-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/snaps-sdk": true, - "@metamask/snaps-sdk>@metamask/key-tree": true, - "@metamask/snaps-utils>@metamask/slip44": true, - "@metamask/snaps-utils>cron-parser": true, - "@metamask/snaps-utils>fast-json-stable-stringify": true, - "@metamask/snaps-utils>marked": true, - "@metamask/snaps-utils>rfdc": true, - "@metamask/snaps-utils>validate-npm-package-name": true, - "@metamask/utils": true, - "@metamask/utils>@scure/base": true, - "@noble/hashes": true, - "chalk": true, - "semver": true, - "superstruct": true - } - }, - "@metamask/snaps-utils>@metamask/snaps-registry": { - "packages": { - "@metamask/snaps-utils>@metamask/snaps-registry>@noble/curves": true, - "@metamask/utils": true, - "@noble/hashes": true, - "superstruct": true - } - }, - "@metamask/snaps-utils>@metamask/snaps-registry>@noble/curves": { - "globals": { - "TextEncoder": true - }, - "packages": { - "@noble/hashes": true - } - }, - "@metamask/snaps-utils>cron-parser": { - "packages": { - "browserify>browser-resolve": true, - "luxon": true - } - }, - "@metamask/snaps-utils>marked": { - "globals": { - "Hooks": true, - "Lexer": true, - "Parser": true, - "Renderer": true, - "TextRenderer": true, - "Tokenizer": true, - "console.error": true, - "console.warn": true, - "defaults": true, - "define": true, - "inlineQueue": true, - "passThroughHooks": true, - "renderer": true, - "rules": true, - "state": true, - "textRenderer": true, - "tokenizer": true, - "tokens": true - } - }, - "@metamask/snaps-utils>rfdc": { - "packages": { - "browserify>buffer": true - } - }, - "@metamask/snaps-utils>validate-npm-package-name": { - "packages": { - "@metamask/snaps-utils>validate-npm-package-name>builtins": true - } - }, - "@metamask/snaps-utils>validate-npm-package-name>builtins": { - "packages": { - "browserify>process": true, - "semver": true - } - }, - "@metamask/test-bundler>@ethersproject/abstract-provider": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/bignumber": true - } - }, - "@metamask/test-bundler>@ethersproject/networks": { - "packages": { - "@ethersproject/abi>@ethersproject/logger": true - } - }, - "@metamask/transaction-controller": { - "globals": { - "clearTimeout": true, - "console.error": true, - "setTimeout": true - }, - "packages": { - "@ethereumjs/common": true, - "@ethereumjs/tx": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/abi": true, - "@metamask/base-controller": true, - "@metamask/controller-utils": true, - "@metamask/eth-query": true, - "@metamask/gas-fee-controller": true, - "@metamask/metamask-eth-abis": true, - "@metamask/name-controller>async-mutex": true, - "@metamask/network-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/transaction-controller>nonce-tracker": true, - "@metamask/utils": true, - "bn.js": true, - "eth-method-registry": true, - "fast-json-patch": true, - "lodash": true, - "uuid": true, - "webpack>events": true - } - }, - "@metamask/transaction-controller>nonce-tracker": { - "packages": { - "@ethersproject/providers": true, - "@metamask/eth-token-tracker>eth-block-tracker": true, - "@metamask/transaction-controller>nonce-tracker>async-mutex": true, - "browserify>assert": true - } - }, - "@metamask/transaction-controller>nonce-tracker>async-mutex": { - "globals": { - "clearTimeout": true, - "setTimeout": true - }, - "packages": { - "mockttp>graphql-tag>tslib": true - } - }, - "@metamask/user-operation-controller": { - "globals": { - "fetch": true - }, - "packages": { - "@metamask/assets-controllers>@metamask/polling-controller": true, - "@metamask/base-controller": true, - "@metamask/controller-utils": true, - "@metamask/eth-query": true, - "@metamask/gas-fee-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/transaction-controller": true, - "@metamask/utils": true, - "ethereumjs-util": true, - "lodash": true, - "superstruct": true, - "uuid": true, - "webpack>events": true - } - }, - "@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, - "@metamask/utils>@scure/base": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - } - }, - "@ngraveio/bc-ur": { - "packages": { - "@ngraveio/bc-ur>@apocentre/alias-sampling": true, - "@ngraveio/bc-ur>bignumber.js": true, - "@ngraveio/bc-ur>cbor-sync": true, - "@ngraveio/bc-ur>crc": true, - "@ngraveio/bc-ur>jsbi": true, - "addons-linter>sha.js": true, - "browserify>assert": true, - "browserify>buffer": true - } - }, - "@ngraveio/bc-ur>assert>object-is": { - "packages": { - "string.prototype.matchall>call-bind": true, - "string.prototype.matchall>define-properties": true - } - }, - "@ngraveio/bc-ur>bignumber.js": { - "globals": { - "crypto": true, - "define": true - } - }, - "@ngraveio/bc-ur>cbor-sync": { - "globals": { - "define": true - }, - "packages": { - "browserify>buffer": true - } - }, - "@ngraveio/bc-ur>crc": { - "packages": { - "browserify>buffer": true - } - }, - "@ngraveio/bc-ur>jsbi": { - "globals": { - "define": true - } - }, - "@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, - "@popperjs/core": { - "globals": { - "Element": true, - "HTMLElement": true, - "ShadowRoot": true, - "console.error": true, - "console.warn": true, - "document": true, - "navigator.userAgent": true - } - }, - "@reduxjs/toolkit": { - "globals": { - "AbortController": true, - "__REDUX_DEVTOOLS_EXTENSION_COMPOSE__": true, - "__REDUX_DEVTOOLS_EXTENSION__": true, - "console.error": true, - "console.info": true, - "console.warn": true - }, - "packages": { - "@reduxjs/toolkit>reselect": true, - "immer": true, - "redux": true, - "redux-thunk": true - } - }, - "@segment/loosely-validate-event": { - "packages": { - "@segment/loosely-validate-event>component-type": true, - "@segment/loosely-validate-event>join-component": true, - "browserify>assert": true, - "browserify>buffer": true - } - }, - "@sentry/browser": { - "globals": { - "TextDecoder": true, - "TextEncoder": true, - "XMLHttpRequest": true, - "__SENTRY_DEBUG__": true, - "__SENTRY_RELEASE__": true, - "indexedDB.open": true, - "setTimeout": true - }, - "packages": { - "@sentry/browser>@sentry-internal/tracing": true, - "@sentry/browser>@sentry/core": true, - "@sentry/browser>@sentry/replay": true, - "@sentry/utils": true - } - }, - "@sentry/browser>@sentry-internal/tracing": { - "globals": { - "Headers": true, - "PerformanceObserver": true, - "Request": true, - "__SENTRY_DEBUG__": true, - "addEventListener": true, - "performance.getEntriesByType": true, - "removeEventListener": true - }, - "packages": { - "@sentry/browser>@sentry/core": true, - "@sentry/utils": true - } - }, - "@sentry/browser>@sentry/core": { - "globals": { - "__SENTRY_DEBUG__": true, - "__SENTRY_TRACING__": true, - "clearInterval": true, - "clearTimeout": true, - "console.warn": true, - "setInterval": true, - "setTimeout": true - }, - "packages": { - "@sentry/utils": true - } - }, - "@sentry/browser>@sentry/replay": { - "globals": { - "Blob": true, - "CSSConditionRule": true, - "CSSGroupingRule": true, - "CSSMediaRule": true, - "CSSSupportsRule": true, - "DragEvent": true, - "Element": true, - "FormData": true, - "HTMLCanvasElement": true, - "HTMLElement.prototype": true, - "HTMLFormElement": true, - "HTMLImageElement": true, - "HTMLInputElement.prototype": true, - "HTMLOptionElement.prototype": true, - "HTMLSelectElement.prototype": true, - "HTMLTextAreaElement.prototype": true, - "Headers": true, - "ImageData": true, - "MouseEvent": true, - "MutationObserver": true, - "Node.prototype.contains": true, - "PerformanceObserver": true, - "TextEncoder": true, - "URL": true, - "URLSearchParams": true, - "Worker": true, - "Zone": true, - "__SENTRY_DEBUG__": true, - "__rrMutationObserver": true, - "clearTimeout": true, - "console.error": true, - "console.warn": true, - "document": true, - "innerHeight": true, - "innerWidth": true, - "location.href": true, - "pageXOffset": true, - "pageYOffset": true, - "requestAnimationFrame": true, - "setTimeout": true - }, - "packages": { - "@sentry/browser>@sentry/core": true, - "@sentry/utils": true, - "browserify>process": true - } - }, - "@sentry/integrations": { - "globals": { - "Request": true, - "__SENTRY_DEBUG__": true, - "console.log": true - }, - "packages": { - "@sentry/utils": true, - "localforage": true - } - }, - "@sentry/utils": { - "globals": { - "CustomEvent": true, - "DOMError": true, - "DOMException": true, - "Element": true, - "ErrorEvent": true, - "Event": true, - "Headers": true, - "Request": true, - "Response": true, - "TextEncoder": true, - "URL": true, - "XMLHttpRequest.prototype": true, - "__SENTRY_BROWSER_BUNDLE__": true, - "__SENTRY_DEBUG__": true, - "clearTimeout": true, - "console.error": true, - "document": true, - "setTimeout": true - }, - "packages": { - "browserify>process": true - } - }, - "@storybook/addon-docs>remark-external-links>mdast-util-definitions": { - "packages": { - "react-markdown>unist-util-visit": true - } - }, - "@storybook/addon-knobs>qs": { - "packages": { - "string.prototype.matchall>side-channel": true - } - }, - "@trezor/connect-web": { - "globals": { - "__TREZOR_CONNECT_SRC": true, - "addEventListener": true, - "btoa": true, - "chrome": true, - "clearInterval": true, - "clearTimeout": true, - "console.warn": true, - "document.body": true, - "document.createElement": true, - "document.createTextNode": true, - "document.getElementById": true, - "document.querySelectorAll": true, - "location": true, - "navigator": true, - "open": true, - "removeEventListener": true, - "setInterval": true, - "setTimeout": true - }, - "packages": { - "@trezor/connect-web>@trezor/connect": true, - "@trezor/connect-web>@trezor/utils": true, - "mockttp>graphql-tag>tslib": true, - "webpack>events": true - } - }, - "@trezor/connect-web>@trezor/connect": { - "globals": { - "console.error": true, - "console.log": true, - "console.warn": true - }, - "packages": { - "@trezor/connect-web>@trezor/connect>@trezor/transport": true, - "@trezor/connect-web>@trezor/connect>tslib": true - } - }, - "@trezor/connect-web>@trezor/connect>tslib": { - "globals": { - "define": true - } - }, - "@trezor/connect-web>@trezor/utils": { - "globals": { - "AbortController": true, - "Intl.NumberFormat": true, - "clearTimeout": true, - "setTimeout": true - }, - "packages": { - "browserify>buffer": true - } - }, - "@zxing/browser": { - "globals": { - "HTMLElement": true, - "HTMLImageElement": true, - "HTMLVideoElement": true, - "clearTimeout": true, - "console.error": true, - "console.warn": true, - "document": true, - "navigator": true, - "setTimeout": true - }, - "packages": { - "@zxing/library": true - } - }, - "@zxing/library": { - "globals": { - "HTMLImageElement": true, - "HTMLVideoElement": true, - "TextDecoder": true, - "TextEncoder": true, - "URL.createObjectURL": true, - "btoa": true, - "console.log": true, - "console.warn": true, - "document": true, - "navigator": true, - "setTimeout": true - }, - "packages": { - "@zxing/library>ts-custom-error": true - } - }, - "addons-linter>sha.js": { - "packages": { - "koa>content-disposition>safe-buffer": true, - "pumpify>inherits": true - } - }, - "await-semaphore": { - "packages": { - "browserify>process": true, - "browserify>timers-browserify": true - } - }, - "base32-encode": { - "packages": { - "base32-encode>to-data-view": true - } - }, - "bignumber.js": { - "globals": { - "crypto": true, - "define": true - } - }, - "blo": { - "globals": { - "btoa": true - } - }, - "bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "bowser": { - "globals": { - "define": true - } - }, - "brfs>static-module>object-inspect": { - "globals": { - "HTMLElement": true, - "WeakRef": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "browserify>assert": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>assert>util": true, - "react>object-assign": true - } - }, - "browserify>assert>util": { - "globals": { - "console.error": true, - "console.log": true, - "console.trace": true, - "process": true - }, - "packages": { - "browserify>assert>util>inherits": true, - "browserify>process": true - } - }, - "browserify>browserify-zlib": { - "packages": { - "browserify>assert": true, - "browserify>browserify-zlib>pako": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>util": true, - "stream-browserify": true - } - }, - "browserify>buffer": { - "globals": { - "console": true - }, - "packages": { - "base64-js": true, - "browserify>buffer>ieee754": true - } - }, - "browserify>crypto-browserify": { - "packages": { - "browserify>crypto-browserify>browserify-cipher": true, - "browserify>crypto-browserify>browserify-sign": true, - "browserify>crypto-browserify>create-ecdh": true, - "browserify>crypto-browserify>create-hmac": true, - "browserify>crypto-browserify>diffie-hellman": true, - "browserify>crypto-browserify>pbkdf2": true, - "browserify>crypto-browserify>public-encrypt": true, - "browserify>crypto-browserify>randomfill": true, - "ethereumjs-util>create-hash": true, - "mocha>serialize-javascript>randombytes": true - } - }, - "browserify>crypto-browserify>browserify-cipher": { - "packages": { - "browserify>crypto-browserify>browserify-cipher>browserify-des": true, - "browserify>crypto-browserify>browserify-cipher>evp_bytestokey": true, - "ethereumjs-util>ethereum-cryptography>browserify-aes": true - } - }, - "browserify>crypto-browserify>browserify-cipher>browserify-des": { - "packages": { - "browserify>buffer": true, - "browserify>crypto-browserify>browserify-cipher>browserify-des>des.js": true, - "ethereumjs-util>create-hash>cipher-base": true, - "pumpify>inherits": true - } - }, - "browserify>crypto-browserify>browserify-cipher>browserify-des>des.js": { - "packages": { - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "pumpify>inherits": true - } - }, - "browserify>crypto-browserify>browserify-cipher>evp_bytestokey": { - "packages": { - "ethereumjs-util>create-hash>md5.js": true, - "koa>content-disposition>safe-buffer": true - } - }, - "browserify>crypto-browserify>browserify-sign": { - "packages": { - "@metamask/ppom-validator>elliptic": true, - "bn.js": true, - "browserify>buffer": true, - "browserify>crypto-browserify>create-hmac": true, - "browserify>crypto-browserify>public-encrypt>browserify-rsa": true, - "browserify>crypto-browserify>public-encrypt>parse-asn1": true, - "ethereumjs-util>create-hash": true, - "pumpify>inherits": true, - "stream-browserify": true - } - }, - "browserify>crypto-browserify>create-ecdh": { - "packages": { - "@metamask/ppom-validator>elliptic": true, - "bn.js": true, - "browserify>buffer": true - } - }, - "browserify>crypto-browserify>create-hmac": { - "packages": { - "addons-linter>sha.js": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>create-hash>cipher-base": true, - "ethereumjs-util>create-hash>ripemd160": true, - "koa>content-disposition>safe-buffer": true, - "pumpify>inherits": true - } - }, - "browserify>crypto-browserify>diffie-hellman": { - "packages": { - "bn.js": true, - "browserify>buffer": true, - "browserify>crypto-browserify>diffie-hellman>miller-rabin": true, - "mocha>serialize-javascript>randombytes": true - } - }, - "browserify>crypto-browserify>diffie-hellman>miller-rabin": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "bn.js": true - } - }, - "browserify>crypto-browserify>pbkdf2": { - "globals": { - "crypto": true, - "process": true, - "queueMicrotask": true, - "setImmediate": true, - "setTimeout": true - }, - "packages": { - "addons-linter>sha.js": true, - "browserify>process": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>create-hash>ripemd160": true, - "koa>content-disposition>safe-buffer": true - } - }, - "browserify>crypto-browserify>public-encrypt": { - "packages": { - "bn.js": true, - "browserify>buffer": true, - "browserify>crypto-browserify>public-encrypt>browserify-rsa": true, - "browserify>crypto-browserify>public-encrypt>parse-asn1": true, - "ethereumjs-util>create-hash": true, - "mocha>serialize-javascript>randombytes": true - } - }, - "browserify>crypto-browserify>public-encrypt>browserify-rsa": { - "packages": { - "bn.js": true, - "browserify>buffer": true, - "mocha>serialize-javascript>randombytes": true - } - }, - "browserify>crypto-browserify>public-encrypt>parse-asn1": { - "packages": { - "browserify>buffer": true, - "browserify>crypto-browserify>browserify-cipher>evp_bytestokey": true, - "browserify>crypto-browserify>pbkdf2": true, - "browserify>crypto-browserify>public-encrypt>parse-asn1>asn1.js": true, - "ethereumjs-util>ethereum-cryptography>browserify-aes": true - } - }, - "browserify>crypto-browserify>public-encrypt>parse-asn1>asn1.js": { - "packages": { - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "bn.js": true, - "browserify>buffer": true, - "browserify>vm-browserify": true, - "pumpify>inherits": true - } - }, - "browserify>crypto-browserify>randomfill": { - "globals": { - "crypto": true, - "msCrypto": true - }, - "packages": { - "browserify>process": true, - "koa>content-disposition>safe-buffer": true, - "mocha>serialize-javascript>randombytes": true - } - }, - "browserify>https-browserify": { - "packages": { - "browserify>stream-http": true, - "browserify>url": true - } - }, - "browserify>path-browserify": { - "packages": { - "browserify>process": true - } - }, - "browserify>process": { - "globals": { - "clearTimeout": true, - "setTimeout": true - } - }, - "browserify>punycode": { - "globals": { - "define": true - } - }, - "browserify>stream-http": { - "globals": { - "AbortController": true, - "Blob": true, - "MSStreamReader": true, - "ReadableStream": true, - "WritableStream": true, - "XDomainRequest": true, - "XMLHttpRequest": true, - "clearTimeout": true, - "fetch": true, - "location.protocol.search": true, - "setTimeout": true - }, - "packages": { - "browserify>buffer": true, - "browserify>process": true, - "browserify>stream-http>builtin-status-codes": true, - "browserify>stream-http>readable-stream": true, - "browserify>url": true, - "pumpify>inherits": true, - "watchify>xtend": true - } - }, - "browserify>stream-http>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "browserify>string_decoder": { - "packages": { - "koa>content-disposition>safe-buffer": true - } - }, - "browserify>timers-browserify": { - "globals": { - "clearInterval": true, - "clearTimeout": true, - "setInterval": true, - "setTimeout": true - }, - "packages": { - "browserify>process": true - } - }, - "browserify>url": { - "packages": { - "@storybook/addon-knobs>qs": true, - "browserify>punycode": true - } - }, - "browserify>util": { - "globals": { - "console.error": true, - "console.log": true, - "console.trace": true - }, - "packages": { - "browserify>process": true, - "browserify>util>is-arguments": true, - "browserify>util>is-typed-array": true, - "browserify>util>which-typed-array": true, - "koa>is-generator-function": true, - "pumpify>inherits": true - } - }, - "browserify>util>is-arguments": { - "packages": { - "koa>is-generator-function>has-tostringtag": true, - "string.prototype.matchall>call-bind": true - } - }, - "browserify>util>is-typed-array": { - "packages": { - "browserify>util>is-typed-array>for-each": true, - "koa>is-generator-function>has-tostringtag": true, - "string.prototype.matchall>call-bind": true, - "string.prototype.matchall>es-abstract>available-typed-arrays": true, - "string.prototype.matchall>es-abstract>gopd": true - } - }, - "browserify>util>is-typed-array>for-each": { - "packages": { - "string.prototype.matchall>es-abstract>is-callable": true - } - }, - "browserify>util>which-typed-array": { - "packages": { - "browserify>util>is-typed-array": true, - "browserify>util>is-typed-array>for-each": true, - "koa>is-generator-function>has-tostringtag": true, - "string.prototype.matchall>call-bind": true, - "string.prototype.matchall>es-abstract>available-typed-arrays": true, - "string.prototype.matchall>es-abstract>gopd": true - } - }, - "browserify>vm-browserify": { - "globals": { - "document.body.appendChild": true, - "document.body.removeChild": true, - "document.createElement": true - } - }, - "chalk": { - "packages": { - "chalk>ansi-styles": true, - "chalk>supports-color": true - } - }, - "chalk>ansi-styles": { - "packages": { - "chalk>ansi-styles>color-convert": true - } - }, - "chalk>ansi-styles>color-convert": { - "packages": { - "jest-canvas-mock>moo-color>color-name": true - } - }, - "chart.js": { - "globals": { - "$animations": true, - "Intl.NumberFormat": true, - "MutationObserver": true, - "OffscreenCanvas": true, - "Path2D": true, - "ResizeObserver": true, - "active": true, - "addEventListener": true, - "circumference": true, - "clearTimeout": true, - "console.error": true, - "console.warn": true, - "dataElementType": true, - "datasetElementType": true, - "defaultRoutes": true, - "defaults": true, - "descriptors": true, - "devicePixelRatio": true, - "document": true, - "endAngle": true, - "fullCircles": true, - "id": true, - "innerRadius": true, - "options": true, - "outerRadius": true, - "overrides": true, - "parsed": true, - "pixelMargin": true, - "removeEventListener": true, - "requestAnimationFrame": true, - "setTimeout": true, - "startAngle": true, - "stop": true, - "x": true, - "y": true - }, - "packages": { - "chart.js>@kurkle/color": true - } - }, - "chart.js>@kurkle/color": { - "globals": { - "define": true - } - }, - "classnames": { - "globals": { - "classNames": "write", - "define": true - } - }, - "copy-to-clipboard": { - "globals": { - "clipboardData": true, - "console.error": true, - "console.warn": true, - "document.body.appendChild": true, - "document.body.removeChild": true, - "document.createElement": true, - "document.createRange": true, - "document.execCommand": true, - "document.getSelection": true, - "navigator.userAgent": true, - "prompt": true - }, - "packages": { - "copy-to-clipboard>toggle-selection": true - } - }, - "copy-to-clipboard>toggle-selection": { - "globals": { - "document.activeElement": true, - "document.getSelection": true - } - }, - "currency-formatter": { - "packages": { - "currency-formatter>accounting": true, - "currency-formatter>locale-currency": true, - "react>object-assign": true - } - }, - "currency-formatter>accounting": { - "globals": { - "define": true - } - }, - "currency-formatter>locale-currency": { - "globals": { - "countryCode": true - } - }, - "debounce-stream": { - "packages": { - "debounce-stream>debounce": true, - "debounce-stream>duplexer": true, - "debounce-stream>through": true - } - }, - "debounce-stream>debounce": { - "globals": { - "clearTimeout": true, - "setTimeout": true - } - }, - "debounce-stream>duplexer": { - "packages": { - "stream-browserify": true - } - }, - "debounce-stream>through": { - "packages": { - "browserify>process": true, - "stream-browserify": true - } - }, - "depcheck>@vue/compiler-sfc>postcss>nanoid": { - "globals": { - "crypto.getRandomValues": true - } - }, - "depcheck>is-core-module>hasown": { - "packages": { - "browserify>has>function-bind": true - } - }, - "dependency-tree>precinct>detective-postcss>postcss>nanoid": { - "globals": { - "crypto.getRandomValues": true - } - }, - "end-of-stream": { - "packages": { - "browserify>process": true, - "pump>once": true - } - }, - "eslint-plugin-react>array-includes>is-string": { - "packages": { - "koa>is-generator-function>has-tostringtag": true - } - }, - "eslint>optionator>fast-levenshtein": { - "globals": { - "Intl": true, - "Levenshtein": "write", - "console.log": true, - "define": true, - "importScripts": true, - "postMessage": true - } - }, - "eth-ens-namehash": { - "globals": { - "name": "write" - }, - "packages": { - "@metamask/ethjs>js-sha3": true, - "browserify>buffer": true, - "eth-ens-namehash>idna-uts46-hx": true - } - }, - "eth-ens-namehash>idna-uts46-hx": { - "globals": { - "define": true - }, - "packages": { - "browserify>punycode": true - } - }, - "eth-keyring-controller>@metamask/browser-passworder": { - "globals": { - "crypto": true - } - }, - "eth-lattice-keyring": { - "globals": { - "addEventListener": true, - "browser": true, - "clearInterval": true, - "fetch": true, - "open": true, - "setInterval": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util": true, - "bn.js": true, - "browserify>buffer": true, - "browserify>crypto-browserify": true, - "eth-lattice-keyring>@ethereumjs/tx": true, - "eth-lattice-keyring>gridplus-sdk": true, - "eth-lattice-keyring>rlp": true, - "webpack>events": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx": { - "packages": { - "@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "browserify": true, - "browserify>buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "browserify": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, - "eth-lattice-keyring>@noble/secp256k1": { - "globals": { - "crypto": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "eth-lattice-keyring>gridplus-sdk": { - "globals": { - "AbortController": true, - "Request": true, - "URL": true, - "__values": true, - "caches": true, - "clearTimeout": true, - "console.error": true, - "console.log": true, - "console.warn": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@ethereumjs/common>crc-32": true, - "@ethersproject/abi": true, - "@metamask/ethjs>js-sha3": true, - "@metamask/ppom-validator>elliptic": true, - "bn.js": true, - "browserify>buffer": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, - "eth-lattice-keyring>gridplus-sdk>aes-js": true, - "eth-lattice-keyring>gridplus-sdk>bech32": true, - "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, - "eth-lattice-keyring>gridplus-sdk>bitwise": true, - "eth-lattice-keyring>gridplus-sdk>borc": true, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, - "eth-lattice-keyring>gridplus-sdk>secp256k1": true, - "eth-lattice-keyring>gridplus-sdk>uuid": true, - "eth-lattice-keyring>rlp": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, - "ethereumjs-util>ethereum-cryptography>hash.js": true, - "lodash": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": { - "packages": { - "@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, - "webpack>events": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { - "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { - "packages": { - "@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, - "webpack>events": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, - "eth-lattice-keyring>gridplus-sdk>aes-js": { - "globals": { - "define": true - } - }, - "eth-lattice-keyring>gridplus-sdk>bignumber.js": { - "globals": { - "crypto": true, - "define": true - } - }, - "eth-lattice-keyring>gridplus-sdk>bitwise": { - "packages": { - "browserify>buffer": true - } - }, - "eth-lattice-keyring>gridplus-sdk>borc": { - "globals": { - "console": true - }, - "packages": { - "browserify>buffer": true, - "browserify>buffer>ieee754": true, - "eth-lattice-keyring>gridplus-sdk>borc>bignumber.js": true, - "eth-lattice-keyring>gridplus-sdk>borc>iso-url": true - } - }, - "eth-lattice-keyring>gridplus-sdk>borc>bignumber.js": { - "globals": { - "crypto": true, - "define": true - } - }, - "eth-lattice-keyring>gridplus-sdk>borc>iso-url": { - "globals": { - "URL": true, - "URLSearchParams": true, - "location": true - } - }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": { - "globals": { - "intToBuffer": true - }, - "packages": { - "@metamask/ethjs>js-sha3": true, - "bn.js": true, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": true - } - }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": { - "globals": { - "console": true - }, - "packages": { - "base64-js": true, - "browserify>buffer>ieee754": true - } - }, - "eth-lattice-keyring>gridplus-sdk>secp256k1": { - "packages": { - "@metamask/ppom-validator>elliptic": true - } - }, - "eth-lattice-keyring>gridplus-sdk>uuid": { - "globals": { - "crypto": true - } - }, - "eth-lattice-keyring>rlp": { - "globals": { - "TextEncoder": true - } - }, - "eth-method-registry": { - "packages": { - "@metamask/ethjs-contract": true, - "@metamask/ethjs-query": true - } - }, - "eth-rpc-errors": { - "packages": { - "eth-rpc-errors>fast-safe-stringify": true - } - }, - "ethereumjs-util": { - "packages": { - "bn.js": true, - "browserify>assert": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, - "ethereumjs-util>rlp": true - } - }, - "ethereumjs-util>create-hash": { - "packages": { - "addons-linter>sha.js": true, - "ethereumjs-util>create-hash>cipher-base": true, - "ethereumjs-util>create-hash>md5.js": true, - "ethereumjs-util>create-hash>ripemd160": true, - "pumpify>inherits": true - } - }, - "ethereumjs-util>create-hash>cipher-base": { - "packages": { - "browserify>string_decoder": true, - "koa>content-disposition>safe-buffer": true, - "pumpify>inherits": true, - "stream-browserify": true - } - }, - "ethereumjs-util>create-hash>md5.js": { - "packages": { - "ethereumjs-util>create-hash>md5.js>hash-base": true, - "koa>content-disposition>safe-buffer": true, - "pumpify>inherits": true - } - }, - "ethereumjs-util>create-hash>md5.js>hash-base": { - "packages": { - "ethereumjs-util>create-hash>md5.js>hash-base>readable-stream": true, - "koa>content-disposition>safe-buffer": true, - "pumpify>inherits": true - } - }, - "ethereumjs-util>create-hash>md5.js>hash-base>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "ethereumjs-util>create-hash>ripemd160": { - "packages": { - "browserify>buffer": true, - "ethereumjs-util>create-hash>md5.js>hash-base": true, - "pumpify>inherits": true - } - }, - "ethereumjs-util>ethereum-cryptography": { - "packages": { - "browserify>buffer": true, - "ganache>keccak": true, - "ganache>secp256k1": true, - "mocha>serialize-javascript>randombytes": true - } - }, - "ethereumjs-util>ethereum-cryptography>browserify-aes": { - "packages": { - "browserify>buffer": true, - "browserify>crypto-browserify>browserify-cipher>evp_bytestokey": true, - "ethereumjs-util>create-hash>cipher-base": true, - "ethereumjs-util>ethereum-cryptography>browserify-aes>buffer-xor": true, - "koa>content-disposition>safe-buffer": true, - "pumpify>inherits": true - } - }, - "ethereumjs-util>ethereum-cryptography>browserify-aes>buffer-xor": { - "packages": { - "browserify>buffer": true - } - }, - "ethereumjs-util>ethereum-cryptography>bs58check": { - "packages": { - "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography>bs58check>bs58": true, - "koa>content-disposition>safe-buffer": true - } - }, - "ethereumjs-util>ethereum-cryptography>bs58check>bs58": { - "packages": { - "@ensdomains/content-hash>multihashes>multibase>base-x": true - } - }, - "ethereumjs-util>ethereum-cryptography>hash.js": { - "packages": { - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "pumpify>inherits": true - } - }, - "ethereumjs-util>ethereum-cryptography>scrypt-js": { - "globals": { - "define": true, - "setTimeout": true - }, - "packages": { - "browserify>timers-browserify": true - } - }, - "ethereumjs-util>rlp": { - "packages": { - "bn.js": true, - "browserify>buffer": true - } - }, - "ethereumjs-wallet>randombytes": { - "globals": { - "crypto.getRandomValues": true - } - }, - "extension-port-stream": { - "packages": { - "browserify>buffer": true, - "extension-port-stream>readable-stream": true - } - }, - "extension-port-stream>readable-stream": { - "globals": { - "AbortController": true, - "AggregateError": true, - "Blob": true - }, - "packages": { - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "extension-port-stream>readable-stream>abort-controller": true, - "webpack>events": true - } - }, - "extension-port-stream>readable-stream>abort-controller": { - "globals": { - "AbortController": true - } - }, - "fast-json-patch": { - "globals": { - "addEventListener": true, - "clearTimeout": true, - "removeEventListener": true, - "setTimeout": true - } - }, - "fuse.js": { - "globals": { - "console": true, - "define": true - } - }, - "ganache>keccak": { - "packages": { - "browserify>buffer": true, - "ganache>keccak>readable-stream": true - } - }, - "ganache>keccak>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "ganache>secp256k1": { - "packages": { - "@metamask/ppom-validator>elliptic": true - } - }, - "gulp>vinyl-fs>object.assign": { - "packages": { - "@lavamoat/lavapack>json-stable-stringify>object-keys": true, - "string.prototype.matchall>call-bind": true, - "string.prototype.matchall>define-properties": true, - "string.prototype.matchall>has-symbols": true - } - }, - "json-rpc-engine": { - "packages": { - "@metamask/safe-event-emitter": true, - "eth-rpc-errors": true - } - }, - "json-rpc-middleware-stream": { - "globals": { - "console.warn": true, - "setTimeout": true - }, - "packages": { - "json-rpc-middleware-stream>@metamask/safe-event-emitter": true, - "json-rpc-middleware-stream>readable-stream": true - } - }, - "json-rpc-middleware-stream>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, - "json-rpc-middleware-stream>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "koa>content-disposition>safe-buffer": { - "packages": { - "browserify>buffer": true - } - }, - "koa>is-generator-function": { - "packages": { - "koa>is-generator-function>has-tostringtag": true - } - }, - "koa>is-generator-function>has-tostringtag": { - "packages": { - "string.prototype.matchall>has-symbols": true - } - }, - "localforage": { - "globals": { - "Blob": true, - "BlobBuilder": true, - "FileReader": true, - "IDBKeyRange": true, - "MSBlobBuilder": true, - "MozBlobBuilder": true, - "OIndexedDB": true, - "WebKitBlobBuilder": true, - "atob": true, - "btoa": true, - "console.error": true, - "console.info": true, - "console.warn": true, - "define": true, - "fetch": true, - "indexedDB": true, - "localStorage": true, - "mozIndexedDB": true, - "msIndexedDB": true, - "navigator.platform": true, - "navigator.userAgent": true, - "openDatabase": true, - "setTimeout": true, - "webkitIndexedDB": true - } - }, - "lodash": { - "globals": { - "clearTimeout": true, - "define": true, - "setTimeout": true - } - }, - "loglevel": { - "globals": { - "console": true, - "define": true, - "document.cookie": true, - "localStorage": true, - "log": "write", - "navigator": true - } - }, - "luxon": { - "globals": { - "Intl": true - } - }, - "mocha>serialize-javascript>randombytes": { - "globals": { - "crypto": true, - "msCrypto": true - }, - "packages": { - "browserify>process": true, - "koa>content-disposition>safe-buffer": true - } - }, - "mockttp>graphql-tag>tslib": { - "globals": { - "SuppressedError": true, - "define": true - } - }, - "nanoid": { - "globals": { - "crypto": true, - "msCrypto": true, - "navigator": true - } - }, - "nock>debug": { - "globals": { - "console": true, - "document": true, - "localStorage": true, - "navigator": true, - "process": true - }, - "packages": { - "browserify>process": true, - "nock>debug>ms": true - } - }, - "node-fetch": { - "globals": { - "Headers": true, - "Request": true, - "Response": true, - "fetch": true - } - }, - "obj-multiplex": { - "globals": { - "console.warn": true - }, - "packages": { - "end-of-stream": true, - "pump>once": true, - "readable-stream": true - } - }, - "promise-to-callback": { - "packages": { - "promise-to-callback>is-fn": true, - "promise-to-callback>set-immediate-shim": true - } - }, - "promise-to-callback>set-immediate-shim": { - "globals": { - "setTimeout.apply": true - }, - "packages": { - "browserify>timers-browserify": true - } - }, - "prop-types": { - "globals": { - "console": true - }, - "packages": { - "prop-types>react-is": true, - "react>object-assign": true - } - }, - "prop-types>react-is": { - "globals": { - "console": true - } - }, - "pump": { - "packages": { - "browserify>browser-resolve": true, - "browserify>process": true, - "end-of-stream": true, - "pump>once": true - } - }, - "pump>once": { - "packages": { - "pump>once>wrappy": true - } - }, - "qrcode-generator": { - "globals": { - "define": true - } - }, - "qrcode.react": { - "globals": { - "Path2D": true, - "devicePixelRatio": true - }, - "packages": { - "prop-types": true, - "qrcode.react>qr.js": true, - "react": true - } - }, - "react": { - "globals": { - "console": true - }, - "packages": { - "prop-types": true, - "react>object-assign": true - } - }, - "react-beautiful-dnd": { - "globals": { - "Element.prototype": true, - "__REDUX_DEVTOOLS_EXTENSION_COMPOSE__": true, - "addEventListener": true, - "cancelAnimationFrame": true, - "clearTimeout": true, - "console": true, - "document": true, - "getComputedStyle": true, - "pageXOffset": true, - "pageYOffset": true, - "removeEventListener": true, - "requestAnimationFrame": true, - "scrollBy": true, - "setTimeout": true - }, - "packages": { - "@babel/runtime": true, - "react": true, - "react-beautiful-dnd>css-box-model": true, - "react-beautiful-dnd>memoize-one": true, - "react-beautiful-dnd>raf-schd": true, - "react-beautiful-dnd>use-memo-one": true, - "react-dom": true, - "react-redux": true, - "redux": true - } - }, - "react-beautiful-dnd>css-box-model": { - "globals": { - "getComputedStyle": true, - "pageXOffset": true, - "pageYOffset": true - }, - "packages": { - "react-router-dom>tiny-invariant": true - } - }, - "react-beautiful-dnd>raf-schd": { - "globals": { - "cancelAnimationFrame": true, - "requestAnimationFrame": true - } - }, - "react-beautiful-dnd>use-memo-one": { - "packages": { - "react": true - } - }, - "react-chartjs-2": { - "globals": { - "setTimeout": true - }, - "packages": { - "chart.js": true, - "react": true - } - }, - "react-devtools": { - "packages": { - "react-devtools>react-devtools-core": true - } - }, - "react-devtools>react-devtools-core": { - "globals": { - "WebSocket": true, - "setTimeout": true - } - }, - "react-dnd-html5-backend": { - "globals": { - "addEventListener": true, - "clearTimeout": true, - "removeEventListener": true - } - }, - "react-dom": { - "globals": { - "HTMLIFrameElement": true, - "MSApp": true, - "__REACT_DEVTOOLS_GLOBAL_HOOK__": true, - "addEventListener": true, - "clearTimeout": true, - "clipboardData": true, - "console": true, - "dispatchEvent": true, - "document": true, - "event": "write", - "jest": true, - "location.protocol": true, - "navigator.userAgent.indexOf": true, - "performance": true, - "removeEventListener": true, - "self": true, - "setTimeout": true, - "top": true, - "trustedTypes": true - }, - "packages": { - "prop-types": true, - "react": true, - "react-dom>scheduler": true, - "react>object-assign": true - } - }, - "react-dom>scheduler": { - "globals": { - "MessageChannel": true, - "cancelAnimationFrame": true, - "clearTimeout": true, - "console": true, - "navigator": true, - "performance": true, - "requestAnimationFrame": true, - "setTimeout": true - } - }, - "react-focus-lock": { - "globals": { - "addEventListener": true, - "console.error": true, - "console.warn": true, - "document": true, - "removeEventListener": true, - "setTimeout": true - }, - "packages": { - "@babel/runtime": true, - "prop-types": true, - "react": true, - "react-focus-lock>focus-lock": true, - "react-focus-lock>react-clientside-effect": true, - "react-focus-lock>use-callback-ref": true, - "react-focus-lock>use-sidecar": true - } - }, - "react-focus-lock>focus-lock": { - "globals": { - "HTMLIFrameElement": true, - "Node.DOCUMENT_FRAGMENT_NODE": true, - "Node.DOCUMENT_NODE": true, - "Node.DOCUMENT_POSITION_CONTAINED_BY": true, - "Node.DOCUMENT_POSITION_CONTAINS": true, - "Node.ELEMENT_NODE": true, - "console.error": true, - "console.warn": true, - "document": true, - "getComputedStyle": true, - "setTimeout": true - }, - "packages": { - "mockttp>graphql-tag>tslib": true - } - }, - "react-focus-lock>react-clientside-effect": { - "packages": { - "@babel/runtime": true, - "react": true - } - }, - "react-focus-lock>use-callback-ref": { - "packages": { - "react": true - } - }, - "react-focus-lock>use-sidecar": { - "globals": { - "console.error": true - }, - "packages": { - "mockttp>graphql-tag>tslib": true, - "react": true, - "react-focus-lock>use-sidecar>detect-node-es": true - } - }, - "react-idle-timer": { - "globals": { - "clearTimeout": true, - "document": true, - "setTimeout": true - }, - "packages": { - "prop-types": true, - "react": true - } - }, - "react-inspector": { - "globals": { - "Node": true, - "chromeDark": true, - "chromeLight": true - }, - "packages": { - "react": true - } - }, - "react-markdown": { - "globals": { - "console.warn": true - }, - "packages": { - "prop-types": true, - "react": true, - "react-markdown>comma-separated-tokens": true, - "react-markdown>property-information": true, - "react-markdown>react-is": true, - "react-markdown>remark-parse": true, - "react-markdown>remark-rehype": true, - "react-markdown>space-separated-tokens": true, - "react-markdown>style-to-object": true, - "react-markdown>unified": true, - "react-markdown>unist-util-visit": true, - "react-markdown>vfile": true - } - }, - "react-markdown>property-information": { - "packages": { - "watchify>xtend": true - } - }, - "react-markdown>react-is": { - "globals": { - "console": true - } - }, - "react-markdown>remark-parse": { - "packages": { - "react-markdown>remark-parse>mdast-util-from-markdown": true - } - }, - "react-markdown>remark-parse>mdast-util-from-markdown": { - "packages": { - "react-markdown>remark-parse>mdast-util-from-markdown>mdast-util-to-string": true, - "react-markdown>remark-parse>mdast-util-from-markdown>micromark": true, - "react-markdown>remark-parse>mdast-util-from-markdown>unist-util-stringify-position": true, - "react-syntax-highlighter>refractor>parse-entities": true - } - }, - "react-markdown>remark-parse>mdast-util-from-markdown>micromark": { - "packages": { - "react-syntax-highlighter>refractor>parse-entities": true - } - }, - "react-markdown>remark-rehype": { - "packages": { - "react-markdown>remark-rehype>mdast-util-to-hast": true - } - }, - "react-markdown>remark-rehype>mdast-util-to-hast": { - "globals": { - "console.warn": true - }, - "packages": { - "@storybook/addon-docs>remark-external-links>mdast-util-definitions": true, - "react-markdown>remark-rehype>mdast-util-to-hast>mdurl": true, - "react-markdown>remark-rehype>mdast-util-to-hast>unist-builder": true, - "react-markdown>remark-rehype>mdast-util-to-hast>unist-util-generated": true, - "react-markdown>remark-rehype>mdast-util-to-hast>unist-util-position": true, - "react-markdown>unist-util-visit": true - } - }, - "react-markdown>style-to-object": { - "packages": { - "react-markdown>style-to-object>inline-style-parser": true - } - }, - "react-markdown>unified": { - "packages": { - "mocha>yargs-unparser>is-plain-obj": true, - "react-markdown>unified>bail": true, - "react-markdown>unified>extend": true, - "react-markdown>unified>is-buffer": true, - "react-markdown>unified>trough": true, - "react-markdown>vfile": true - } - }, - "react-markdown>unist-util-visit": { - "packages": { - "react-markdown>unist-util-visit>unist-util-visit-parents": true - } - }, - "react-markdown>unist-util-visit>unist-util-visit-parents": { - "packages": { - "react-markdown>unist-util-visit>unist-util-is": true - } - }, - "react-markdown>vfile": { - "packages": { - "browserify>path-browserify": true, - "browserify>process": true, - "react-markdown>vfile>is-buffer": true, - "react-markdown>vfile>vfile-message": true, - "vinyl>replace-ext": true - } - }, - "react-markdown>vfile>vfile-message": { - "packages": { - "react-markdown>vfile>unist-util-stringify-position": true - } - }, - "react-popper": { - "globals": { - "document": true - }, - "packages": { - "@popperjs/core": true, - "react": true, - "react-popper>react-fast-compare": true, - "react-popper>warning": true - } - }, - "react-popper>react-fast-compare": { - "globals": { - "Element": true, - "console.warn": true - } - }, - "react-popper>warning": { - "globals": { - "console": true - } - }, - "react-redux": { - "globals": { - "console": true, - "document": true - }, - "packages": { - "@babel/runtime": true, - "prop-types": true, - "prop-types>react-is": true, - "react": true, - "react-dom": true, - "react-redux>hoist-non-react-statics": true, - "redux": true - } - }, - "react-redux>hoist-non-react-statics": { - "packages": { - "prop-types>react-is": true - } - }, - "react-responsive-carousel": { - "globals": { - "HTMLElement": true, - "addEventListener": true, - "clearTimeout": true, - "console.warn": true, - "document": true, - "getComputedStyle": true, - "removeEventListener": true, - "setTimeout": true - }, - "packages": { - "classnames": true, - "react": true, - "react-dom": true, - "react-responsive-carousel>react-easy-swipe": true - } - }, - "react-responsive-carousel>react-easy-swipe": { - "globals": { - "addEventListener": true, - "define": true, - "document.addEventListener": true, - "document.removeEventListener": true - }, - "packages": { - "prop-types": true, - "react": true - } - }, - "react-router-dom": { - "packages": { - "prop-types": true, - "react": true, - "react-router-dom>history": true, - "react-router-dom>react-router": true, - "react-router-dom>tiny-invariant": true, - "react-router-dom>tiny-warning": true - } - }, - "react-router-dom>history": { - "globals": { - "addEventListener": true, - "confirm": true, - "document": true, - "history": true, - "location": true, - "navigator.userAgent": true, - "removeEventListener": true - }, - "packages": { - "react-router-dom>history>resolve-pathname": true, - "react-router-dom>history>value-equal": true, - "react-router-dom>tiny-invariant": true, - "react-router-dom>tiny-warning": true - } - }, - "react-router-dom>react-router": { - "packages": { - "prop-types": true, - "prop-types>react-is": true, - "react": true, - "react-redux>hoist-non-react-statics": true, - "react-router-dom>react-router>history": true, - "react-router-dom>react-router>mini-create-react-context": true, - "react-router-dom>tiny-invariant": true, - "react-router-dom>tiny-warning": true, - "sinon>nise>path-to-regexp": true - } - }, - "react-router-dom>react-router>history": { - "globals": { - "addEventListener": true, - "confirm": true, - "document": true, - "history": true, - "location": true, - "navigator.userAgent": true, - "removeEventListener": true - }, - "packages": { - "react-router-dom>history>resolve-pathname": true, - "react-router-dom>history>value-equal": true, - "react-router-dom>tiny-invariant": true, - "react-router-dom>tiny-warning": true - } - }, - "react-router-dom>react-router>mini-create-react-context": { - "packages": { - "@babel/runtime": true, - "prop-types": true, - "react": true, - "react-router-dom>react-router>mini-create-react-context>gud": true, - "react-router-dom>tiny-warning": true - } - }, - "react-router-dom>tiny-warning": { - "globals": { - "console": true - } - }, - "react-simple-file-input": { - "globals": { - "File": true, - "FileReader": true, - "console.warn": true - }, - "packages": { - "prop-types": true, - "react": true - } - }, - "react-syntax-highlighter>refractor>parse-entities": { - "globals": { - "document.createElement": true - } - }, - "react-tippy": { - "globals": { - "Element": true, - "MSStream": true, - "MutationObserver": true, - "addEventListener": true, - "clearTimeout": true, - "console.error": true, - "console.warn": true, - "define": true, - "document": true, - "getComputedStyle": true, - "innerHeight": true, - "innerWidth": true, - "navigator.maxTouchPoints": true, - "navigator.msMaxTouchPoints": true, - "navigator.userAgent": true, - "performance": true, - "requestAnimationFrame": true, - "setTimeout": true - }, - "packages": { - "react": true, - "react-dom": true, - "react-tippy>popper.js": true - } - }, - "react-tippy>popper.js": { - "globals": { - "MSInputMethodContext": true, - "Node.DOCUMENT_POSITION_FOLLOWING": true, - "cancelAnimationFrame": true, - "console.warn": true, - "define": true, - "devicePixelRatio": true, - "document": true, - "getComputedStyle": true, - "innerHeight": true, - "innerWidth": true, - "navigator.userAgent": true, - "requestAnimationFrame": true, - "setTimeout": true - } - }, - "react-toggle-button": { - "globals": { - "clearTimeout": true, - "console.warn": true, - "define": true, - "performance": true, - "setTimeout": true - }, - "packages": { - "react": true - } - }, - "readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>process": true, - "browserify>timers-browserify": true, - "pumpify>inherits": true, - "readable-stream>core-util-is": true, - "readable-stream>isarray": true, - "readable-stream>process-nextick-args": true, - "readable-stream>safe-buffer": true, - "readable-stream>string_decoder": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "readable-stream>core-util-is": { - "packages": { - "browserify>insert-module-globals>is-buffer": true - } - }, - "readable-stream>process-nextick-args": { - "packages": { - "browserify>process": true - } - }, - "readable-stream>safe-buffer": { - "packages": { - "browserify>buffer": true - } - }, - "readable-stream>string_decoder": { - "packages": { - "readable-stream>safe-buffer": true - } - }, - "readable-stream>util-deprecate": { - "globals": { - "console.trace": true, - "console.warn": true, - "localStorage": true - } - }, - "redux": { - "globals": { - "console": true - }, - "packages": { - "@babel/runtime": true - } - }, - "semver": { - "globals": { - "console.error": true - }, - "packages": { - "browserify>process": true, - "semver>lru-cache": true - } - }, - "semver>lru-cache": { - "packages": { - "semver>lru-cache>yallist": true - } - }, - "sinon>nise>path-to-regexp": { - "packages": { - "sinon>nise>path-to-regexp>isarray": true - } - }, - "stream-browserify": { - "packages": { - "pumpify>inherits": true, - "stream-browserify>readable-stream": true, - "webpack>events": true - } - }, - "stream-browserify>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "string.prototype.matchall>call-bind": { - "packages": { - "browserify>has>function-bind": true, - "string.prototype.matchall>call-bind>es-errors": true, - "string.prototype.matchall>call-bind>set-function-length": true, - "string.prototype.matchall>get-intrinsic": true - } - }, - "string.prototype.matchall>call-bind>set-function-length": { - "packages": { - "string.prototype.matchall>call-bind>es-errors": true, - "string.prototype.matchall>define-properties>define-data-property": true, - "string.prototype.matchall>es-abstract>gopd": true, - "string.prototype.matchall>es-abstract>has-property-descriptors": true, - "string.prototype.matchall>get-intrinsic": true - } - }, - "string.prototype.matchall>define-properties": { - "packages": { - "@lavamoat/lavapack>json-stable-stringify>object-keys": true, - "string.prototype.matchall>define-properties>define-data-property": true, - "string.prototype.matchall>es-abstract>has-property-descriptors": true - } - }, - "string.prototype.matchall>define-properties>define-data-property": { - "packages": { - "string.prototype.matchall>call-bind>es-errors": true, - "string.prototype.matchall>es-abstract>gopd": true, - "string.prototype.matchall>es-abstract>has-property-descriptors": true, - "string.prototype.matchall>get-intrinsic": true - } - }, - "string.prototype.matchall>es-abstract>array-buffer-byte-length": { - "packages": { - "string.prototype.matchall>call-bind": true, - "string.prototype.matchall>es-abstract>is-array-buffer": true - } - }, - "string.prototype.matchall>es-abstract>es-to-primitive>is-symbol": { - "packages": { - "string.prototype.matchall>has-symbols": true - } - }, - "string.prototype.matchall>es-abstract>gopd": { - "packages": { - "string.prototype.matchall>get-intrinsic": true - } - }, - "string.prototype.matchall>es-abstract>has-property-descriptors": { - "packages": { - "string.prototype.matchall>get-intrinsic": true - } - }, - "string.prototype.matchall>es-abstract>is-array-buffer": { - "packages": { - "browserify>util>is-typed-array": true, - "string.prototype.matchall>call-bind": true, - "string.prototype.matchall>get-intrinsic": true - } - }, - "string.prototype.matchall>es-abstract>is-callable": { - "globals": { - "document": true - } - }, - "string.prototype.matchall>es-abstract>is-regex": { - "packages": { - "koa>is-generator-function>has-tostringtag": true, - "string.prototype.matchall>call-bind": true - } - }, - "string.prototype.matchall>es-abstract>is-shared-array-buffer": { - "packages": { - "string.prototype.matchall>call-bind": true - } - }, - "string.prototype.matchall>get-intrinsic": { - "globals": { - "AggregateError": true, - "FinalizationRegistry": true, - "WeakRef": true - }, - "packages": { - "browserify>has>function-bind": true, - "depcheck>is-core-module>hasown": true, - "string.prototype.matchall>call-bind>es-errors": true, - "string.prototype.matchall>es-abstract>has-proto": true, - "string.prototype.matchall>has-symbols": true - } - }, - "string.prototype.matchall>internal-slot": { - "packages": { - "depcheck>is-core-module>hasown": true, - "string.prototype.matchall>get-intrinsic": true, - "string.prototype.matchall>side-channel": true - } - }, - "string.prototype.matchall>regexp.prototype.flags": { - "packages": { - "string.prototype.matchall>call-bind": true, - "string.prototype.matchall>define-properties": true, - "string.prototype.matchall>regexp.prototype.flags>set-function-name": true - } - }, - "string.prototype.matchall>regexp.prototype.flags>set-function-name": { - "packages": { - "string.prototype.matchall>define-properties>define-data-property": true, - "string.prototype.matchall>es-abstract>function.prototype.name>functions-have-names": true, - "string.prototype.matchall>es-abstract>has-property-descriptors": true - } - }, - "string.prototype.matchall>side-channel": { - "packages": { - "brfs>static-module>object-inspect": true, - "string.prototype.matchall>call-bind": true, - "string.prototype.matchall>get-intrinsic": true - } - }, - "superstruct": { - "globals": { - "console.warn": true, - "define": true - } - }, - "terser>source-map-support>buffer-from": { - "packages": { - "browserify>buffer": true - } - }, - "uuid": { - "globals": { - "crypto": true, - "msCrypto": true - } - }, - "vinyl>replace-ext": { - "packages": { - "browserify>path-browserify": true - } - }, - "web3": { - "globals": { - "XMLHttpRequest": true - } - }, - "web3-stream-provider": { - "globals": { - "setTimeout": true - }, - "packages": { - "browserify>util": true, - "readable-stream": true, - "web3-stream-provider>uuid": true - } - }, - "web3-stream-provider>uuid": { - "globals": { - "crypto": true, - "msCrypto": true - } - }, - "webextension-polyfill": { - "globals": { - "browser": true, - "chrome": true, - "console.error": true, - "console.warn": true, - "define": true - } - }, - "webpack>events": { - "globals": { - "console": true - } - } - } -} \ No newline at end of file diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index fdb1c4524cdf..8415dbd75002 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -5,6 +5,11 @@ "regeneratorRuntime": "write" } }, + "@contentful/rich-text-html-renderer": { + "globals": { + "SuppressedError": true + } + }, "@ensdomains/content-hash": { "globals": { "console.warn": true @@ -108,30 +113,30 @@ "browserify>util": true } }, - "@ethereumjs/common": { + "@ethereumjs/tx": { + "packages": { + "@ethereumjs/tx>@ethereumjs/common": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true + } + }, + "@ethereumjs/tx>@ethereumjs/common": { "packages": { - "@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, "webpack>events": true } }, - "@ethereumjs/common>crc-32": { + "@ethereumjs/tx>@ethereumjs/common>crc-32": { "globals": { "DO_NOT_EXPORT_CRC": true, "define": true } }, - "@ethereumjs/tx": { - "packages": { - "@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethereumjs/tx>ethereum-cryptography": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true - } - }, "@ethereumjs/tx>@ethereumjs/rlp": { "globals": { "TextEncoder": true @@ -184,13 +189,7 @@ "TextEncoder": true }, "packages": { - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true } }, "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { @@ -201,9 +200,23 @@ }, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": { "packages": { - "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, - "@metamask/utils>@scure/base": true, - "@noble/hashes": true + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/curves": true, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true, + "@metamask/utils>@scure/base": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/curves": { + "globals": { + "TextEncoder": true + }, + "packages": { + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethersproject/abi": { @@ -214,12 +227,12 @@ "@ethersproject/abi>@ethersproject/address": true, "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/abi>@ethersproject/constants": true, - "@ethersproject/abi>@ethersproject/hash": true, "@ethersproject/abi>@ethersproject/keccak256": true, "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/abi>@ethersproject/strings": true, - "@ethersproject/bignumber": true + "@ethersproject/bignumber": true, + "@ethersproject/hash": true } }, "@ethersproject/abi>@ethersproject/address": { @@ -241,18 +254,6 @@ "@ethersproject/bignumber": true } }, - "@ethersproject/abi>@ethersproject/hash": { - "packages": { - "@ethersproject/abi>@ethersproject/address": true, - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/keccak256": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/abi>@ethersproject/strings": true, - "@ethersproject/bignumber": true, - "@ethersproject/providers>@ethersproject/base64": true - } - }, "@ethersproject/abi>@ethersproject/keccak256": { "packages": { "@ethersproject/abi>@ethersproject/bytes": true, @@ -294,9 +295,36 @@ "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/bignumber": true, - "@ethersproject/hdnode>@ethersproject/abstract-signer": true, + "@ethersproject/hash>@ethersproject/abstract-signer": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@metamask/test-bundler>@ethersproject/abstract-provider": true + "@ethersproject/wallet>@ethersproject/abstract-provider": true + } + }, + "@ethersproject/hash": { + "packages": { + "@ethersproject/abi>@ethersproject/address": true, + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/keccak256": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/abi>@ethersproject/strings": true, + "@ethersproject/bignumber": true, + "@ethersproject/hash>@ethersproject/base64": true + } + }, + "@ethersproject/hash>@ethersproject/abstract-signer": { + "packages": { + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true + } + }, + "@ethersproject/hash>@ethersproject/base64": { + "globals": { + "atob": true, + "btoa": true + }, + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true } }, "@ethersproject/hdnode": { @@ -314,12 +342,6 @@ "@ethersproject/hdnode>@ethersproject/wordlists": true } }, - "@ethersproject/hdnode>@ethersproject/abstract-signer": { - "packages": { - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true - } - }, "@ethersproject/hdnode>@ethersproject/basex": { "packages": { "@ethersproject/abi>@ethersproject/bytes": true, @@ -363,10 +385,10 @@ "@ethersproject/hdnode>@ethersproject/wordlists": { "packages": { "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/hash": true, "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/abi>@ethersproject/strings": true + "@ethersproject/abi>@ethersproject/strings": true, + "@ethersproject/hash": true } }, "@ethersproject/providers": { @@ -383,39 +405,26 @@ "@ethersproject/abi>@ethersproject/address": true, "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/abi>@ethersproject/constants": true, - "@ethersproject/abi>@ethersproject/hash": true, "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/abi>@ethersproject/strings": true, "@ethersproject/bignumber": true, - "@ethersproject/hdnode>@ethersproject/abstract-signer": true, + "@ethersproject/hash": true, + "@ethersproject/hash>@ethersproject/abstract-signer": true, + "@ethersproject/hash>@ethersproject/base64": true, "@ethersproject/hdnode>@ethersproject/basex": true, "@ethersproject/hdnode>@ethersproject/sha2": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/base64": true, - "@ethersproject/providers>@ethersproject/random": true, "@ethersproject/providers>@ethersproject/web": true, "@ethersproject/providers>bech32": true, - "@metamask/test-bundler>@ethersproject/abstract-provider": true, + "@ethersproject/wallet>@ethersproject/abstract-provider": true, + "@ethersproject/wallet>@ethersproject/random": true, "@metamask/test-bundler>@ethersproject/networks": true } }, - "@ethersproject/providers>@ethersproject/base64": { - "globals": { - "atob": true, - "btoa": true - }, - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true - } - }, "@ethersproject/providers>@ethersproject/random": { "globals": { "crypto.getRandomValues": true - }, - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true } }, "@ethersproject/providers>@ethersproject/rlp": { @@ -435,7 +444,59 @@ "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/abi>@ethersproject/strings": true, - "@ethersproject/providers>@ethersproject/base64": true + "@ethersproject/hash>@ethersproject/base64": true + } + }, + "@ethersproject/wallet": { + "packages": { + "@ethersproject/abi>@ethersproject/address": true, + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/keccak256": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/hash": true, + "@ethersproject/hash>@ethersproject/abstract-signer": true, + "@ethersproject/hdnode": true, + "@ethersproject/hdnode>@ethersproject/signing-key": true, + "@ethersproject/hdnode>@ethersproject/transactions": true, + "@ethersproject/wallet>@ethersproject/abstract-provider": true, + "@ethersproject/wallet>@ethersproject/json-wallets": true, + "@ethersproject/wallet>@ethersproject/random": true + } + }, + "@ethersproject/wallet>@ethersproject/abstract-provider": { + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/bignumber": true + } + }, + "@ethersproject/wallet>@ethersproject/json-wallets": { + "packages": { + "@ethersproject/abi>@ethersproject/address": true, + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/keccak256": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/abi>@ethersproject/strings": true, + "@ethersproject/hdnode": true, + "@ethersproject/hdnode>@ethersproject/pbkdf2": true, + "@ethersproject/hdnode>@ethersproject/transactions": true, + "@ethersproject/wallet>@ethersproject/json-wallets>aes-js": true, + "@ethersproject/wallet>@ethersproject/random": true, + "ethereumjs-util>ethereum-cryptography>scrypt-js": true + } + }, + "@ethersproject/wallet>@ethersproject/json-wallets>aes-js": { + "globals": { + "define": true + } + }, + "@ethersproject/wallet>@ethersproject/random": { + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/logger": true } }, "@keystonehq/bc-ur-registry-eth": { @@ -453,9 +514,10 @@ }, "packages": { "@ngraveio/bc-ur": true, + "@trezor/connect-web>tslib": true, "browserify>buffer": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, - "mockttp>graphql-tag>tslib": true + "ganache>abstract-level>buffer": true } }, "@keystonehq/metamask-airgapped-keyring": { @@ -464,8 +526,8 @@ "@keystonehq/bc-ur-registry-eth": true, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, - "@keystonehq/metamask-airgapped-keyring>rlp": true, "browserify>buffer": true, + "ethereumjs-util>rlp": true, "uuid": true, "webpack>events": true } @@ -475,33 +537,65 @@ "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "@keystonehq/bc-ur-registry-eth": true, + "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, - "eth-lattice-keyring>rlp": true, "uuid": true } }, + "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": { + "globals": { + "TextEncoder": true + } + }, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": { "packages": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": true, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": true, - "@metamask/safe-event-emitter": true, "stream-browserify": true } }, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": { + "globals": { + "setTimeout": true + }, + "packages": { + "webpack>events": true + } + }, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": { "packages": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream": true, "browserify>process": true, "browserify>util": true, - "readable-stream": true, "watchify>xtend": true } }, - "@keystonehq/metamask-airgapped-keyring>rlp": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream": { + "packages": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>isarray": true, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": true, + "browserify>browser-resolve": true, + "browserify>process": true, + "browserify>timers-browserify": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true, + "webpack>events": true + } + }, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": { "packages": { - "bn.js": true, "browserify>buffer": true } }, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": { + "packages": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true + } + }, "@lavamoat/lavadome-react": { "globals": { "Document.prototype": true, @@ -702,25 +796,43 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/base-controller": true, + "@metamask/accounts-controller>@metamask/base-controller": true, + "@metamask/accounts-controller>@metamask/keyring-api": true, "@metamask/eth-snap-keyring": true, - "@metamask/keyring-api": true, "@metamask/keyring-controller": true, + "@metamask/snaps-utils": true, + "@metamask/utils": true, "uuid": true } }, - "@metamask/address-book-controller": { + "@metamask/accounts-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, "packages": { - "@metamask/address-book-controller>@metamask/base-controller": true, - "@metamask/address-book-controller>@metamask/controller-utils": true + "immer": true } }, - "@metamask/address-book-controller>@metamask/base-controller": { + "@metamask/accounts-controller>@metamask/keyring-api": { "globals": { - "setTimeout": true + "URL": true }, "packages": { - "immer": true + "@metamask/accounts-controller>@metamask/keyring-api>uuid": true, + "@metamask/keyring-api>bech32": true, + "@metamask/utils": true, + "superstruct": true + } + }, + "@metamask/accounts-controller>@metamask/keyring-api>uuid": { + "globals": { + "crypto": true + } + }, + "@metamask/address-book-controller": { + "packages": { + "@metamask/address-book-controller>@metamask/controller-utils": true, + "@metamask/base-controller": true } }, "@metamask/address-book-controller>@metamask/controller-utils": { @@ -731,32 +843,14 @@ "setTimeout": true }, "packages": { - "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": true, - "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, + "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true - } - }, - "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, - "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": { - "packages": { - "@metamask/ethjs>ethjs-abi>number-to-bn": true, - "bn.js": true + "eth-ens-namehash": true } }, "@metamask/announcement-controller": { @@ -765,6 +859,9 @@ } }, "@metamask/announcement-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, "packages": { "immer": true } @@ -774,9 +871,17 @@ "console.info": true }, "packages": { + "@metamask/approval-controller>@metamask/base-controller": true, "@metamask/approval-controller>nanoid": true, - "@metamask/base-controller": true, - "@metamask/providers>@metamask/rpc-errors": true + "@metamask/rpc-errors": true + } + }, + "@metamask/approval-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true } }, "@metamask/approval-controller>nanoid": { @@ -789,6 +894,7 @@ "AbortController": true, "Headers": true, "URL": true, + "URLSearchParams": true, "clearInterval": true, "clearTimeout": true, "console.error": true, @@ -803,6 +909,7 @@ "@ethersproject/providers": true, "@metamask/abi-utils": true, "@metamask/assets-controllers>@metamask/polling-controller": true, + "@metamask/assets-controllers>async-mutex": true, "@metamask/assets-controllers>cockatiel": true, "@metamask/assets-controllers>multiformats": true, "@metamask/base-controller": true, @@ -810,8 +917,7 @@ "@metamask/controller-utils": true, "@metamask/eth-query": true, "@metamask/metamask-eth-abis": true, - "@metamask/name-controller>async-mutex": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/utils": true, "bn.js": true, "lodash": true, @@ -832,6 +938,14 @@ "uuid": true } }, + "@metamask/assets-controllers>async-mutex": { + "globals": { + "setTimeout": true + }, + "packages": { + "@trezor/connect-web>tslib": true + } + }, "@metamask/assets-controllers>cockatiel": { "globals": { "AbortController": true, @@ -901,7 +1015,8 @@ "console.log": true }, "packages": { - "@metamask/controller-utils>@spruceid/siwe-parser>apg-js": true + "@metamask/controller-utils>@spruceid/siwe-parser>apg-js": true, + "@noble/hashes": true } }, "@metamask/controller-utils>@spruceid/siwe-parser>apg-js": { @@ -928,102 +1043,42 @@ "fetch": true } }, - "@metamask/desktop": { + "@metamask/ens-controller": { + "packages": { + "@ethersproject/providers": true, + "@metamask/base-controller": true, + "@metamask/ens-controller>@metamask/controller-utils": true, + "@metamask/utils": true, + "punycode": true + } + }, + "@metamask/ens-controller>@metamask/controller-utils": { "globals": { - "TextDecoder": true, - "TextEncoder": true, - "WebSocket": true, - "clearInterval": true, - "clearTimeout": true, - "crypto.getRandomValues": true, - "crypto.subtle.decrypt": true, - "crypto.subtle.digest": true, - "crypto.subtle.encrypt": true, - "crypto.subtle.exportKey": true, - "crypto.subtle.generateKey": true, - "crypto.subtle.importKey": true, - "isDesktopApp": true, - "setInterval": true, + "URL": true, + "console.error": true, + "fetch": true, "setTimeout": true }, "packages": { - "@metamask/desktop>@metamask/obs-store": true, - "@metamask/desktop>eciesjs": true, - "@metamask/desktop>extension-port-stream": true, - "@metamask/desktop>otpauth": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, "browserify>buffer": true, - "end-of-stream": true, - "loglevel": true, - "obj-multiplex": true, - "stream-browserify": true, - "uuid": true, - "webextension-polyfill": true, - "webpack>events": true + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true } }, - "@metamask/desktop>@metamask/obs-store": { + "@metamask/eth-json-rpc-filters": { "globals": { - "localStorage": true - }, - "packages": { - "@metamask/desktop>@metamask/obs-store>through2": true, - "@metamask/safe-event-emitter": true, - "stream-browserify": true - } - }, - "@metamask/desktop>@metamask/obs-store>through2": { - "packages": { - "browserify>process": true, - "browserify>util": true, - "readable-stream": true, - "watchify>xtend": true - } - }, - "@metamask/desktop>eciesjs": { - "packages": { - "@metamask/desktop>eciesjs>futoin-hkdf": true, - "browserify>buffer": true, - "browserify>crypto-browserify": true, - "ganache>secp256k1": true - } - }, - "@metamask/desktop>eciesjs>futoin-hkdf": { - "packages": { - "browserify>buffer": true, - "browserify>crypto-browserify": true - } - }, - "@metamask/desktop>extension-port-stream": { - "packages": { - "browserify>buffer": true, - "stream-browserify": true - } - }, - "@metamask/desktop>otpauth": { - "globals": { - "__GLOBALTHIS__": true, - "define": true - } - }, - "@metamask/ens-controller": { - "packages": { - "@ethersproject/providers": true, - "@metamask/base-controller": true, - "@metamask/controller-utils": true, - "@metamask/utils": true, - "ethereum-ens-network-map": true, - "punycode": true - } - }, - "@metamask/eth-json-rpc-filters": { - "globals": { - "console.error": true + "console.error": true }, "packages": { "@metamask/eth-json-rpc-filters>@metamask/eth-query": true, - "@metamask/eth-json-rpc-filters>@metamask/safe-event-emitter": true, - "@metamask/name-controller>async-mutex": true, - "@metamask/providers>@metamask/json-rpc-engine": true, + "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine": true, + "@metamask/eth-json-rpc-filters>async-mutex": true, + "@metamask/safe-event-emitter": true, "pify": true } }, @@ -1033,12 +1088,19 @@ "watchify>xtend": true } }, - "@metamask/eth-json-rpc-filters>@metamask/safe-event-emitter": { + "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine": { + "packages": { + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true + } + }, + "@metamask/eth-json-rpc-filters>async-mutex": { "globals": { "setTimeout": true }, "packages": { - "webpack>events": true + "@trezor/connect-web>tslib": true } }, "@metamask/eth-json-rpc-middleware": { @@ -1048,52 +1110,33 @@ "setTimeout": true }, "packages": { + "@metamask/eth-json-rpc-middleware>@metamask/json-rpc-engine": true, "@metamask/eth-json-rpc-middleware>safe-stable-stringify": true, "@metamask/eth-sig-util": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/utils": true, "pify": true, "sass-loader>klona": true } }, - "@metamask/eth-keyring-controller": { - "globals": { - "console.error": true - }, - "packages": { - "@metamask/browser-passworder": true, - "@metamask/eth-keyring-controller>@metamask/obs-store": true, - "@metamask/eth-sig-util": true, - "@metamask/keyring-controller>@metamask/eth-hd-keyring": true, - "@metamask/keyring-controller>@metamask/eth-simple-keyring": true, - "@metamask/utils": true, - "webpack>events": true - } - }, - "@metamask/eth-keyring-controller>@metamask/obs-store": { + "@metamask/eth-json-rpc-middleware>@metamask/eth-json-rpc-provider": { "packages": { - "@metamask/eth-keyring-controller>@metamask/obs-store>@metamask/safe-event-emitter": true, - "@metamask/eth-keyring-controller>@metamask/obs-store>readable-stream": true + "@metamask/eth-json-rpc-middleware>@metamask/eth-json-rpc-provider>@metamask/json-rpc-engine": true, + "@metamask/safe-event-emitter": true } }, - "@metamask/eth-keyring-controller>@metamask/obs-store>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, + "@metamask/eth-json-rpc-middleware>@metamask/eth-json-rpc-provider>@metamask/json-rpc-engine": { "packages": { - "webpack>events": true + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true } }, - "@metamask/eth-keyring-controller>@metamask/obs-store>readable-stream": { + "@metamask/eth-json-rpc-middleware>@metamask/json-rpc-engine": { "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true } }, "@metamask/eth-ledger-bridge-keyring": { @@ -1153,25 +1196,19 @@ }, "@metamask/eth-snap-keyring": { "globals": { + "URL": true, "console.error": true }, "packages": { "@ethereumjs/tx": true, "@metamask/eth-sig-util": true, - "@metamask/eth-snap-keyring>@metamask/keyring-api": true, "@metamask/eth-snap-keyring>uuid": true, + "@metamask/keyring-api": true, "@metamask/utils": true, "superstruct": true, "webpack>events": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-api": { - "packages": { - "@metamask/eth-snap-keyring>uuid": true, - "@metamask/utils": true, - "superstruct": true - } - }, "@metamask/eth-snap-keyring>uuid": { "globals": { "crypto": true @@ -1183,21 +1220,26 @@ }, "packages": { "@babel/runtime": true, - "@metamask/eth-token-tracker>@metamask/safe-event-emitter": true, + "@metamask/eth-token-tracker>@metamask/eth-block-tracker": true, "@metamask/eth-token-tracker>deep-equal": true, - "@metamask/eth-token-tracker>eth-block-tracker": true, "@metamask/ethjs-contract": true, "@metamask/ethjs-query": true, + "@metamask/safe-event-emitter": true, "bn.js": true, "human-standard-token-abi": true } }, - "@metamask/eth-token-tracker>@metamask/safe-event-emitter": { + "@metamask/eth-token-tracker>@metamask/eth-block-tracker": { "globals": { + "clearTimeout": true, + "console.error": true, "setTimeout": true }, "packages": { - "webpack>events": true + "@metamask/eth-query>json-rpc-random-id": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true, + "pify": true } }, "@metamask/eth-token-tracker>deep-equal": { @@ -1288,27 +1330,6 @@ "string.prototype.matchall>get-intrinsic": true } }, - "@metamask/eth-token-tracker>eth-block-tracker": { - "globals": { - "clearTimeout": true, - "console.error": true, - "setTimeout": true - }, - "packages": { - "@metamask/eth-query>json-rpc-random-id": true, - "@metamask/eth-token-tracker>eth-block-tracker>@metamask/safe-event-emitter": true, - "@metamask/utils": true, - "pify": true - } - }, - "@metamask/eth-token-tracker>eth-block-tracker>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, "@metamask/eth-trezor-keyring": { "globals": { "setTimeout": true @@ -1317,15 +1338,47 @@ "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": true, + "@metamask/eth-trezor-keyring>@trezor/connect-web": true, "@metamask/eth-trezor-keyring>hdkey": true, - "@trezor/connect-web": true, "browserify>buffer": true, "webpack>events": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": { "packages": { - "@metamask/eth-sig-util": true + "@metamask/eth-sig-util": true, + "@trezor/connect-web>tslib": true + } + }, + "@metamask/eth-trezor-keyring>@trezor/connect-web": { + "globals": { + "URLSearchParams": true, + "__TREZOR_CONNECT_SRC": true, + "addEventListener": true, + "btoa": true, + "chrome": true, + "clearInterval": true, + "clearTimeout": true, + "console.warn": true, + "document.body": true, + "document.createElement": true, + "document.createTextNode": true, + "document.getElementById": true, + "document.querySelectorAll": true, + "location": true, + "navigator": true, + "open": true, + "origin": true, + "removeEventListener": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@trezor/connect-web>@trezor/connect": true, + "@trezor/connect-web>@trezor/connect-common": true, + "@trezor/connect-web>@trezor/utils": true, + "@trezor/connect-web>tslib": true, + "webpack>events": true } }, "@metamask/eth-trezor-keyring>hdkey": { @@ -1465,13 +1518,30 @@ }, "packages": { "@metamask/assets-controllers>@metamask/polling-controller": true, - "@metamask/controller-utils": true, "@metamask/eth-query": true, - "@metamask/ethjs>@metamask/ethjs-unit": true, - "ethereumjs-util": true, + "@metamask/gas-fee-controller>@metamask/controller-utils": true, + "bn.js": true, "uuid": true } }, + "@metamask/gas-fee-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/jazzicon": { "globals": { "document.createElement": true, @@ -1505,7 +1575,11 @@ } }, "@metamask/keyring-api": { + "globals": { + "URL": true + }, "packages": { + "@metamask/keyring-api>bech32": true, "@metamask/keyring-api>uuid": true, "@metamask/utils": true, "superstruct": true @@ -1582,18 +1656,12 @@ "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>create-hash": true - } - }, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": { - "packages": { - "bn.js": true, - "browserify>buffer": true + "ethereumjs-util>create-hash": true, + "ethereumjs-util>rlp": true } }, "@metamask/logging-controller": { @@ -1618,9 +1686,9 @@ }, "@metamask/message-manager": { "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, "@metamask/eth-sig-util": true, + "@metamask/message-manager>@metamask/base-controller": true, + "@metamask/message-manager>@metamask/controller-utils": true, "@metamask/message-manager>jsonschema": true, "@metamask/utils": true, "browserify>buffer": true, @@ -1628,27 +1696,89 @@ "webpack>events": true } }, + "@metamask/message-manager>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/message-manager>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true } }, + "@metamask/message-signing-snap>@noble/curves": { + "globals": { + "TextEncoder": true + }, + "packages": { + "@noble/hashes": true + } + }, "@metamask/name-controller": { "globals": { "fetch": true }, "packages": { - "@metamask/base-controller": true, + "@metamask/name-controller>@metamask/base-controller": true, + "@metamask/name-controller>@metamask/controller-utils": true, "@metamask/name-controller>async-mutex": true, "@metamask/utils": true } }, + "@metamask/name-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/name-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/name-controller>async-mutex": { "globals": { + "clearTimeout": true, "setTimeout": true }, "packages": { - "mockttp>graphql-tag>tslib": true + "@trezor/connect-web>tslib": true } }, "@metamask/network-controller": { @@ -1659,48 +1789,73 @@ "setTimeout": true }, "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, "@metamask/eth-json-rpc-middleware": true, "@metamask/eth-query": true, - "@metamask/eth-token-tracker>eth-block-tracker": true, + "@metamask/eth-token-tracker>@metamask/eth-block-tracker": true, + "@metamask/network-controller>@metamask/base-controller": true, + "@metamask/network-controller>@metamask/controller-utils": true, "@metamask/network-controller>@metamask/eth-json-rpc-infura": true, "@metamask/network-controller>@metamask/eth-json-rpc-provider": true, "@metamask/network-controller>@metamask/swappable-obj-proxy": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true, "@metamask/utils": true, "browserify>assert": true, "uuid": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-infura": { + "@metamask/network-controller>@metamask/base-controller": { "globals": { "setTimeout": true }, "packages": { - "@metamask/network-controller>@metamask/eth-json-rpc-provider": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/utils": true, - "node-fetch": true + "immer": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-provider": { + "@metamask/network-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, "packages": { - "@metamask/network-controller>@metamask/eth-json-rpc-provider>@metamask/safe-event-emitter": true, - "@metamask/providers>@metamask/json-rpc-engine": true + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-provider>@metamask/safe-event-emitter": { + "@metamask/network-controller>@metamask/eth-json-rpc-infura": { "globals": { "setTimeout": true }, "packages": { - "webpack>events": true + "@metamask/eth-json-rpc-middleware>@metamask/eth-json-rpc-provider": true, + "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/json-rpc-engine": true, + "@metamask/rpc-errors": true, + "@metamask/utils": true, + "node-fetch": true } }, - "@metamask/notification-controller": { + "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/json-rpc-engine": { + "packages": { + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true + } + }, + "@metamask/network-controller>@metamask/eth-json-rpc-provider": { + "packages": { + "@metamask/safe-event-emitter": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true + } + }, + "@metamask/notification-controller": { "packages": { "@metamask/notification-controller>@metamask/base-controller": true, "@metamask/notification-controller>@metamask/utils": true, @@ -1732,19 +1887,24 @@ "crypto.getRandomValues": true } }, - "@metamask/obs-store": { + "@metamask/object-multiplex": { + "globals": { + "console.warn": true + }, "packages": { - "@metamask/obs-store>through2": true, - "@metamask/safe-event-emitter": true, - "stream-browserify": true + "@metamask/object-multiplex>once": true, + "readable-stream": true } }, - "@metamask/obs-store>through2": { + "@metamask/object-multiplex>once": { "packages": { - "browserify>process": true, - "browserify>util": true, - "readable-stream": true, - "watchify>xtend": true + "@metamask/object-multiplex>once>wrappy": true + } + }, + "@metamask/obs-store": { + "packages": { + "@metamask/safe-event-emitter": true, + "readable-stream": true } }, "@metamask/permission-controller": { @@ -1752,16 +1912,42 @@ "console.error": true }, "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/base-controller": true, + "@metamask/permission-controller>@metamask/controller-utils": true, "@metamask/permission-controller>nanoid": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true, "@metamask/utils": true, "deep-freeze-strict": true, "immer": true } }, + "@metamask/permission-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/permission-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/permission-controller>nanoid": { "globals": { "crypto.getRandomValues": true @@ -1801,19 +1987,8 @@ "removeEventListener": true }, "packages": { - "@metamask/post-message-stream>readable-stream": true, - "@metamask/utils": true - } - }, - "@metamask/post-message-stream>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "@metamask/utils": true, + "readable-stream": true } }, "@metamask/ppom-validator": { @@ -1823,9 +1998,9 @@ "crypto": true }, "packages": { - "@metamask/controller-utils": true, "@metamask/eth-query>json-rpc-random-id": true, "@metamask/ppom-validator>@metamask/base-controller": true, + "@metamask/ppom-validator>@metamask/controller-utils": true, "@metamask/ppom-validator>crypto-js": true, "@metamask/ppom-validator>elliptic": true, "await-semaphore": true, @@ -1840,6 +2015,24 @@ "immer": true } }, + "@metamask/ppom-validator>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/ppom-validator>crypto-js": { "globals": { "crypto": true, @@ -1877,14 +2070,50 @@ "ethereumjs-util>ethereum-cryptography>hash.js": true } }, - "@metamask/providers>@metamask/json-rpc-engine": { + "@metamask/queued-request-controller": { "packages": { - "@metamask/providers>@metamask/json-rpc-engine>@metamask/safe-event-emitter": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/queued-request-controller>@metamask/base-controller": true, + "@metamask/rpc-errors": true, + "@metamask/selected-network-controller": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true, "@metamask/utils": true } }, - "@metamask/providers>@metamask/json-rpc-engine>@metamask/safe-event-emitter": { + "@metamask/queued-request-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/rate-limit-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "@metamask/base-controller": true, + "@metamask/rpc-errors": true, + "@metamask/utils": true + } + }, + "@metamask/rpc-errors": { + "packages": { + "@metamask/utils": true, + "eth-rpc-errors>fast-safe-stringify": true + } + }, + "@metamask/rpc-methods-flask>nanoid": { + "globals": { + "crypto.getRandomValues": true + } + }, + "@metamask/rpc-methods>nanoid": { + "globals": { + "crypto.getRandomValues": true + } + }, + "@metamask/safe-event-emitter": { "globals": { "setTimeout": true }, @@ -1892,161 +2121,379 @@ "webpack>events": true } }, - "@metamask/providers>@metamask/object-multiplex": { + "@metamask/scure-bip39": { "globals": { - "console.warn": true + "TextEncoder": true }, "packages": { - "@metamask/providers>@metamask/object-multiplex>readable-stream": true, - "pump>once": true + "@metamask/scure-bip39>@noble/hashes": true, + "@metamask/utils>@scure/base": true } }, - "@metamask/providers>@metamask/object-multiplex>readable-stream": { + "@metamask/scure-bip39>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, + "@metamask/selected-network-controller": { "packages": { - "browserify>browser-resolve": true, + "@metamask/network-controller>@metamask/swappable-obj-proxy": true, + "@metamask/selected-network-controller>@metamask/base-controller": true + } + }, + "@metamask/selected-network-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/signature-controller": { + "globals": { + "console.info": true + }, + "packages": { + "@metamask/base-controller": true, + "@metamask/logging-controller": true, + "@metamask/rpc-errors": true, + "@metamask/signature-controller>@metamask/controller-utils": true, + "@metamask/signature-controller>@metamask/message-manager": true, + "@metamask/utils": true, "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, + "lodash": true, "webpack>events": true } }, - "@metamask/providers>@metamask/rpc-errors": { + "@metamask/signature-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, "@metamask/utils": true, - "eth-rpc-errors>fast-safe-stringify": true + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true } }, - "@metamask/queued-request-controller": { + "@metamask/signature-controller>@metamask/message-manager": { "packages": { "@metamask/base-controller": true, - "@metamask/controller-utils": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/selected-network-controller": true + "@metamask/eth-sig-util": true, + "@metamask/message-manager>jsonschema": true, + "@metamask/signature-controller>@metamask/controller-utils": true, + "@metamask/utils": true, + "browserify>buffer": true, + "uuid": true, + "webpack>events": true } }, - "@metamask/rate-limit-controller": { + "@metamask/smart-transactions-controller": { "globals": { - "setTimeout": true + "URLSearchParams": true, + "clearInterval": true, + "console.error": true, + "console.log": true, + "fetch": true, + "setInterval": true + }, + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true, + "@metamask/assets-controllers>@metamask/polling-controller": true, + "@metamask/eth-query": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx": true, + "@metamask/smart-transactions-controller>@ethereumjs/util": true, + "@metamask/smart-transactions-controller>@metamask/controller-utils": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller": true, + "@metamask/smart-transactions-controller>bignumber.js": true, + "browserify>buffer": true, + "fast-json-patch": true, + "lodash": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@babel/runtime": { + "globals": { + "regeneratorRuntime": "write" + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx": { + "packages": { + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": true, + "@metamask/smart-transactions-controller>@ethereumjs/util": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": { + "packages": { + "@metamask/smart-transactions-controller>@ethereumjs/util": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/util": { + "globals": { + "console.warn": true, + "fetch": true }, "packages": { - "@metamask/rate-limit-controller>@metamask/base-controller": true, - "eth-rpc-errors": true + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@ethereumjs/util>@ethereumjs/rlp": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/util>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true } }, - "@metamask/rate-limit-controller>@metamask/base-controller": { + "@metamask/smart-transactions-controller>@metamask/controller-utils": { "globals": { + "URL": true, + "console.error": true, + "fetch": true, "setTimeout": true }, "packages": { - "immer": true + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/smart-transactions-controller>@metamask/controller-utils>@ethereumjs/util": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true } }, - "@metamask/rpc-methods-flask>nanoid": { + "@metamask/smart-transactions-controller>@metamask/controller-utils>@ethereumjs/util": { "globals": { - "crypto.getRandomValues": true + "console.warn": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "webpack>events": true } }, - "@metamask/rpc-methods>nanoid": { + "@metamask/smart-transactions-controller>@metamask/controllers>nanoid": { "globals": { "crypto.getRandomValues": true } }, - "@metamask/safe-event-emitter": { + "@metamask/smart-transactions-controller>@metamask/transaction-controller": { "globals": { + "clearTimeout": true, + "console.error": true, + "fetch": true, "setTimeout": true }, "packages": { + "@ethereumjs/tx>@ethereumjs/common": true, + "@ethersproject/abi": true, + "@ethersproject/contracts": true, + "@ethersproject/providers": true, + "@metamask/eth-query": true, + "@metamask/metamask-eth-abis": true, + "@metamask/name-controller>async-mutex": true, + "@metamask/network-controller": true, + "@metamask/rpc-errors": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/base-controller": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/controller-utils": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry": true, + "@metamask/transaction-controller>@metamask/nonce-tracker": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "fast-json-patch": true, + "lodash": true, + "uuid": true, "webpack>events": true } }, - "@metamask/scure-bip39": { + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx": { + "packages": { + "@ethereumjs/tx>@ethereumjs/common": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": { "globals": { - "TextEncoder": true + "console.warn": true }, "packages": { - "@metamask/scure-bip39>@noble/hashes": true, - "@metamask/utils>@scure/base": true + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "webpack>events": true } }, - "@metamask/scure-bip39>@noble/hashes": { + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/base-controller": { "globals": { - "TextEncoder": true, - "crypto": true + "setTimeout": true + }, + "packages": { + "immer": true } }, - "@metamask/selected-network-controller": { + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, "packages": { - "@metamask/base-controller": true, - "@metamask/network-controller>@metamask/swappable-obj-proxy": true + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller": { + "globals": { + "clearInterval": true, + "console.error": true, + "setInterval": true + }, + "packages": { + "@metamask/eth-query": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/controller-utils": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/polling-controller": true, + "bn.js": true, + "browserify>buffer": true, + "uuid": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/controller-utils>@ethereumjs/util": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/controller-utils>@ethereumjs/util": { + "globals": { + "console.warn": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/polling-controller": { + "globals": { + "clearTimeout": true, + "console.error": true, + "setTimeout": true + }, + "packages": { + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/base-controller": true, + "@metamask/snaps-utils>fast-json-stable-stringify": true, + "uuid": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry": { + "packages": { + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query": true } }, - "@metamask/signature-controller": { - "globals": { - "console.info": true - }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract": { "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, - "@metamask/logging-controller": true, - "@metamask/message-manager": true, - "@metamask/providers>@metamask/rpc-errors": true, - "browserify>buffer": true, - "ethereumjs-util": true, - "lodash": true, - "webpack>events": true + "@metamask/ethjs>ethjs-abi": true, + "@metamask/ethjs>js-sha3": true, + "@metamask/smart-transactions-controller>@babel/runtime": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-filter": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-util": true, + "promise-to-callback": true } }, - "@metamask/smart-transactions-controller": { + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-filter": { "globals": { - "URLSearchParams": true, "clearInterval": true, - "console.error": true, - "console.log": true, - "fetch": true, "setInterval": true - }, + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-util": { "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/bignumber": true, - "@ethersproject/providers": true, - "@metamask/smart-transactions-controller>@metamask/base-controller": true, - "@metamask/smart-transactions-controller>@metamask/controller-utils": true, - "@metamask/smart-transactions-controller>bignumber.js": true, - "fast-json-patch": true, - "lodash": true + "@metamask/ethjs>@metamask/ethjs-util>is-hex-prefixed": true, + "@metamask/ethjs>@metamask/ethjs-util>strip-hex-prefix": true, + "browserify>buffer": true } }, - "@metamask/smart-transactions-controller>@metamask/base-controller": { + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query": { "globals": { - "setTimeout": true + "console": true }, "packages": { - "immer": true + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query>@metamask/ethjs-format": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query>@metamask/ethjs-rpc": true, + "promise-to-callback": true } }, - "@metamask/smart-transactions-controller>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query>@metamask/ethjs-format": { "packages": { - "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/utils": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true + "@metamask/ethjs-query>@metamask/ethjs-format>ethjs-schema": true, + "@metamask/ethjs>@metamask/ethjs-util>strip-hex-prefix": true, + "@metamask/ethjs>@metamask/number-to-bn": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-util": true } }, - "@metamask/smart-transactions-controller>@metamask/controllers>nanoid": { - "globals": { - "crypto.getRandomValues": true + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query>@metamask/ethjs-rpc": { + "packages": { + "promise-to-callback": true } }, "@metamask/smart-transactions-controller>bignumber.js": { @@ -2059,25 +2506,23 @@ "globals": { "DecompressionStream": true, "URL": true, - "chrome.offscreen.createDocument": true, - "chrome.offscreen.hasDocument": true, "clearTimeout": true, "document.getElementById": true, "fetch.bind": true, "setTimeout": true }, "packages": { - "@metamask/base-controller": true, + "@metamask/object-multiplex": true, "@metamask/permission-controller": true, "@metamask/post-message-stream": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/object-multiplex": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, + "@metamask/snaps-controllers>@metamask/base-controller": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true, + "@metamask/snaps-controllers>@metamask/json-rpc-middleware-stream": true, "@metamask/snaps-controllers>@xstate/fsm": true, "@metamask/snaps-controllers>concat-stream": true, "@metamask/snaps-controllers>get-npm-tarball-url": true, "@metamask/snaps-controllers>nanoid": true, - "@metamask/snaps-controllers>readable-stream": true, "@metamask/snaps-controllers>readable-web-to-node-stream": true, "@metamask/snaps-controllers>tar-stream": true, "@metamask/snaps-rpc-methods": true, @@ -2086,7 +2531,8 @@ "@metamask/snaps-utils>@metamask/snaps-registry": true, "@metamask/utils": true, "browserify>browserify-zlib": true, - "json-rpc-middleware-stream": true + "eslint>fast-deep-equal": true, + "readable-stream": true } }, "@metamask/snaps-controllers-flask>nanoid": { @@ -2094,12 +2540,37 @@ "crypto.getRandomValues": true } }, + "@metamask/snaps-controllers>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": { + "packages": { + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true + } + }, + "@metamask/snaps-controllers>@metamask/json-rpc-middleware-stream": { + "globals": { + "console.warn": true, + "setTimeout": true + }, + "packages": { + "@metamask/safe-event-emitter": true, + "readable-stream": true + } + }, "@metamask/snaps-controllers>concat-stream": { "packages": { - "@metamask/snaps-controllers>readable-stream": true, "browserify>buffer": true, "browserify>concat-stream>typedarray": true, "pumpify>inherits": true, + "readable-stream": true, "terser>source-map-support>buffer-from": true } }, @@ -2108,31 +2579,9 @@ "crypto.getRandomValues": true } }, - "@metamask/snaps-controllers>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, "@metamask/snaps-controllers>readable-web-to-node-stream": { "packages": { - "@metamask/snaps-controllers>readable-web-to-node-stream>readable-stream": true - } - }, - "@metamask/snaps-controllers>readable-web-to-node-stream>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "readable-stream": true } }, "@metamask/snaps-controllers>tar-stream": { @@ -2161,10 +2610,20 @@ "queueMicrotask": true } }, + "@metamask/snaps-execution-environments": { + "globals": { + "document.getElementById": true + }, + "packages": { + "@metamask/post-message-stream": true, + "@metamask/snaps-utils": true, + "@metamask/utils": true + } + }, "@metamask/snaps-rpc-methods": { "packages": { "@metamask/permission-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/snaps-sdk": true, "@metamask/snaps-sdk>@metamask/key-tree": true, "@metamask/snaps-utils": true, @@ -2178,50 +2637,18 @@ "fetch": true }, "packages": { - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/snaps-sdk>fast-xml-parser": true, + "@metamask/rpc-errors": true, "@metamask/utils": true, "superstruct": true } }, "@metamask/snaps-sdk>@metamask/key-tree": { "packages": { + "@metamask/message-signing-snap>@noble/curves": true, "@metamask/scure-bip39": true, - "@metamask/snaps-sdk>@metamask/key-tree>@metamask/utils": true, - "@metamask/snaps-sdk>@metamask/key-tree>@noble/ed25519": true, + "@metamask/utils": true, "@metamask/utils>@scure/base": true, - "@noble/hashes": true, - "eth-lattice-keyring>@noble/secp256k1": true - } - }, - "@metamask/snaps-sdk>@metamask/key-tree>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, - "@metamask/snaps-sdk>@metamask/key-tree>@noble/ed25519": { - "globals": { - "crypto": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "@metamask/snaps-sdk>fast-xml-parser": { - "globals": { - "entityName": true, - "val": true - }, - "packages": { - "@metamask/snaps-sdk>fast-xml-parser>strnum": true + "@noble/hashes": true } }, "@metamask/snaps-utils": { @@ -2229,6 +2656,7 @@ "File": true, "FileReader": true, "TextDecoder": true, + "TextEncoder": true, "URL": true, "console.error": true, "console.log": true, @@ -2240,12 +2668,13 @@ }, "packages": { "@metamask/permission-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/snaps-sdk": true, "@metamask/snaps-sdk>@metamask/key-tree": true, "@metamask/snaps-utils>@metamask/slip44": true, "@metamask/snaps-utils>cron-parser": true, "@metamask/snaps-utils>fast-json-stable-stringify": true, + "@metamask/snaps-utils>fast-xml-parser": true, "@metamask/snaps-utils>marked": true, "@metamask/snaps-utils>rfdc": true, "@metamask/snaps-utils>validate-npm-package-name": true, @@ -2259,46 +2688,32 @@ }, "@metamask/snaps-utils>@metamask/snaps-registry": { "packages": { - "@metamask/snaps-utils>@metamask/snaps-registry>@noble/curves": true, + "@metamask/message-signing-snap>@noble/curves": true, "@metamask/utils": true, "@noble/hashes": true, "superstruct": true } }, - "@metamask/snaps-utils>@metamask/snaps-registry>@noble/curves": { - "globals": { - "TextEncoder": true - }, - "packages": { - "@noble/hashes": true - } - }, "@metamask/snaps-utils>cron-parser": { "packages": { "browserify>browser-resolve": true, "luxon": true } }, + "@metamask/snaps-utils>fast-xml-parser": { + "globals": { + "entityName": true, + "val": true + }, + "packages": { + "@metamask/snaps-utils>fast-xml-parser>strnum": true + } + }, "@metamask/snaps-utils>marked": { "globals": { - "Hooks": true, - "Lexer": true, - "Parser": true, - "Renderer": true, - "TextRenderer": true, - "Tokenizer": true, "console.error": true, "console.warn": true, - "defaults": true, - "define": true, - "inlineQueue": true, - "passThroughHooks": true, - "renderer": true, - "rules": true, - "state": true, - "textRenderer": true, - "tokenizer": true, - "tokens": true + "define": true } }, "@metamask/snaps-utils>rfdc": { @@ -2317,14 +2732,6 @@ "semver": true } }, - "@metamask/test-bundler>@ethersproject/abstract-provider": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/bignumber": true - } - }, "@metamask/test-bundler>@ethersproject/networks": { "packages": { "@ethersproject/abi>@ethersproject/logger": true @@ -2334,24 +2741,28 @@ "globals": { "clearTimeout": true, "console.error": true, + "fetch": true, "setTimeout": true }, "packages": { - "@ethereumjs/common": true, "@ethereumjs/tx": true, + "@ethereumjs/tx>@ethereumjs/common": true, "@ethereumjs/tx>@ethereumjs/util": true, "@ethersproject/abi": true, - "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@ethersproject/contracts": true, + "@ethersproject/providers": true, "@metamask/eth-query": true, "@metamask/gas-fee-controller": true, "@metamask/metamask-eth-abis": true, "@metamask/name-controller>async-mutex": true, "@metamask/network-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/transaction-controller>nonce-tracker": true, + "@metamask/rpc-errors": true, + "@metamask/transaction-controller>@metamask/base-controller": true, + "@metamask/transaction-controller>@metamask/controller-utils": true, + "@metamask/transaction-controller>@metamask/nonce-tracker": true, "@metamask/utils": true, "bn.js": true, + "browserify>buffer": true, "eth-method-registry": true, "fast-json-patch": true, "lodash": true, @@ -2359,21 +2770,46 @@ "webpack>events": true } }, - "@metamask/transaction-controller>nonce-tracker": { + "@metamask/transaction-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/transaction-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/transaction-controller>@metamask/nonce-tracker": { "packages": { "@ethersproject/providers": true, - "@metamask/eth-token-tracker>eth-block-tracker": true, - "@metamask/transaction-controller>nonce-tracker>async-mutex": true, + "@metamask/transaction-controller>@metamask/nonce-tracker>async-mutex": true, "browserify>assert": true } }, - "@metamask/transaction-controller>nonce-tracker>async-mutex": { + "@metamask/transaction-controller>@metamask/nonce-tracker>async-mutex": { "globals": { "clearTimeout": true, "setTimeout": true }, "packages": { - "mockttp>graphql-tag>tslib": true + "@trezor/connect-web>tslib": true } }, "@metamask/user-operation-controller": { @@ -2383,19 +2819,37 @@ "packages": { "@metamask/assets-controllers>@metamask/polling-controller": true, "@metamask/base-controller": true, - "@metamask/controller-utils": true, "@metamask/eth-query": true, "@metamask/gas-fee-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/transaction-controller": true, + "@metamask/user-operation-controller>@metamask/controller-utils": true, "@metamask/utils": true, - "ethereumjs-util": true, + "bn.js": true, "lodash": true, "superstruct": true, "uuid": true, "webpack>events": true } }, + "@metamask/user-operation-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/utils": { "globals": { "TextDecoder": true, @@ -2419,7 +2873,7 @@ }, "@ngraveio/bc-ur": { "packages": { - "@ngraveio/bc-ur>@apocentre/alias-sampling": true, + "@ngraveio/bc-ur>@keystonehq/alias-sampling": true, "@ngraveio/bc-ur>bignumber.js": true, "@ngraveio/bc-ur>cbor-sync": true, "@ngraveio/bc-ur>crc": true, @@ -2459,6 +2913,13 @@ "define": true } }, + "@noble/ciphers": { + "globals": { + "TextDecoder": true, + "TextEncoder": true, + "crypto": true + } + }, "@noble/hashes": { "globals": { "TextEncoder": true, @@ -2481,12 +2942,14 @@ "AbortController": true, "__REDUX_DEVTOOLS_EXTENSION_COMPOSE__": true, "__REDUX_DEVTOOLS_EXTENSION__": true, - "console.error": true, - "console.info": true, - "console.warn": true + "console": true, + "queueMicrotask": true, + "requestAnimationFrame": true, + "setTimeout": true }, "packages": { "@reduxjs/toolkit>reselect": true, + "browserify>process": true, "immer": true, "redux": true, "redux-thunk": true @@ -2643,6 +3106,7 @@ }, "@trezor/connect-web": { "globals": { + "URLSearchParams": true, "__TREZOR_CONNECT_SRC": true, "addEventListener": true, "btoa": true, @@ -2658,42 +3122,105 @@ "location": true, "navigator": true, "open": true, + "origin": true, "removeEventListener": true, "setInterval": true, "setTimeout": true }, "packages": { "@trezor/connect-web>@trezor/connect": true, + "@trezor/connect-web>@trezor/connect-common": true, "@trezor/connect-web>@trezor/utils": true, - "mockttp>graphql-tag>tslib": true, + "@trezor/connect-web>tslib": true, "webpack>events": true } }, "@trezor/connect-web>@trezor/connect": { + "packages": { + "@trezor/connect-web>@trezor/connect>@trezor/protobuf": true, + "@trezor/connect-web>@trezor/connect>@trezor/schema-utils": true, + "@trezor/connect-web>@trezor/connect>@trezor/transport": true, + "@trezor/connect-web>@trezor/utils": true, + "@trezor/connect-web>tslib": true + } + }, + "@trezor/connect-web>@trezor/connect-common": { "globals": { - "console.error": true, - "console.log": true, - "console.warn": true + "console.warn": true, + "localStorage.getItem": true, + "localStorage.setItem": true, + "navigator": true, + "setTimeout": true, + "window": true }, "packages": { - "@trezor/connect-web>@trezor/connect>@trezor/transport": true, - "@trezor/connect-web>@trezor/connect>tslib": true + "@trezor/connect-web>@trezor/connect-common>@trezor/env-utils": true, + "@trezor/connect-web>@trezor/utils": true, + "@trezor/connect-web>tslib": true + } + }, + "@trezor/connect-web>@trezor/connect-common>@trezor/env-utils": { + "globals": { + "innerHeight": true, + "innerWidth": true, + "location.hostname": true, + "location.origin": true, + "navigator.languages": true, + "navigator.platform": true, + "navigator.userAgent": true, + "screen.height": true, + "screen.width": true + }, + "packages": { + "@trezor/connect-web>@trezor/connect-common>@trezor/env-utils>ua-parser-js": true, + "@trezor/connect-web>tslib": true, + "browserify>process": true } }, - "@trezor/connect-web>@trezor/connect>tslib": { + "@trezor/connect-web>@trezor/connect-common>@trezor/env-utils>ua-parser-js": { "globals": { "define": true } }, + "@trezor/connect-web>@trezor/connect>@trezor/protobuf": { + "packages": { + "@trezor/connect-web>@trezor/connect>@trezor/schema-utils": true, + "@trezor/connect-web>tslib": true, + "browserify>buffer": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs": true + } + }, + "@trezor/connect-web>@trezor/connect>@trezor/schema-utils": { + "globals": { + "console.warn": true + }, + "packages": { + "@trezor/connect-web>@trezor/connect>@trezor/schema-utils>@sinclair/typebox": true, + "browserify>buffer": true, + "ts-mixer": true + } + }, "@trezor/connect-web>@trezor/utils": { "globals": { "AbortController": true, "Intl.NumberFormat": true, "clearTimeout": true, + "console.error": true, + "console.info": true, + "console.log": true, + "console.warn": true, "setTimeout": true }, "packages": { - "browserify>buffer": true + "@trezor/connect-web>tslib": true, + "browserify>buffer": true, + "webpack>events": true + } + }, + "@trezor/connect-web>tslib": { + "globals": { + "SuppressedError": true, + "define": true } }, "@zxing/browser": { @@ -2771,15 +3298,6 @@ "define": true } }, - "brfs>static-module>object-inspect": { - "globals": { - "HTMLElement": true, - "WeakRef": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "browserify>assert": { "globals": { "Buffer": true @@ -3007,23 +3525,12 @@ "browserify>buffer": true, "browserify>process": true, "browserify>stream-http>builtin-status-codes": true, - "browserify>stream-http>readable-stream": true, "browserify>url": true, "pumpify>inherits": true, + "readable-stream": true, "watchify>xtend": true } }, - "browserify>stream-http>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, "browserify>string_decoder": { "packages": { "koa>content-disposition>safe-buffer": true @@ -3116,41 +3623,20 @@ }, "chart.js": { "globals": { - "$animations": true, "Intl.NumberFormat": true, "MutationObserver": true, "OffscreenCanvas": true, "Path2D": true, "ResizeObserver": true, - "active": true, "addEventListener": true, - "circumference": true, "clearTimeout": true, "console.error": true, "console.warn": true, - "dataElementType": true, - "datasetElementType": true, - "defaultRoutes": true, - "defaults": true, - "descriptors": true, "devicePixelRatio": true, "document": true, - "endAngle": true, - "fullCircles": true, - "id": true, - "innerRadius": true, - "options": true, - "outerRadius": true, - "overrides": true, - "parsed": true, - "pixelMargin": true, "removeEventListener": true, "requestAnimationFrame": true, - "setTimeout": true, - "startAngle": true, - "stop": true, - "x": true, - "y": true + "setTimeout": true }, "packages": { "chart.js>@kurkle/color": true @@ -3247,12 +3733,6 @@ "crypto.getRandomValues": true } }, - "end-of-stream": { - "packages": { - "browserify>process": true, - "pump>once": true - } - }, "eslint-plugin-react>array-includes>is-string": { "packages": { "koa>is-generator-function>has-tostringtag": true @@ -3313,7 +3793,7 @@ }, "eth-lattice-keyring>@ethereumjs/tx": { "packages": { - "@ethereumjs/common": true, + "@ethereumjs/tx>@ethereumjs/common": true, "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util": true, "@ethersproject/providers": true, @@ -3354,14 +3834,6 @@ "crypto": true } }, - "eth-lattice-keyring>@noble/secp256k1": { - "globals": { - "crypto": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -3377,23 +3849,23 @@ "setTimeout": true }, "packages": { - "@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethersproject/abi": true, "@metamask/ethjs>js-sha3": true, + "@metamask/keyring-api>bech32": true, "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>buffer": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, - "eth-lattice-keyring>gridplus-sdk>bech32": true, "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, + "eth-lattice-keyring>gridplus-sdk>rlp": true, "eth-lattice-keyring>gridplus-sdk>secp256k1": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, - "eth-lattice-keyring>rlp": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>hash.js": true, "lodash": true @@ -3401,7 +3873,7 @@ }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": { "packages": { - "@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, "webpack>events": true @@ -3421,7 +3893,7 @@ }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { "packages": { - "@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, "webpack>events": true @@ -3489,16 +3961,12 @@ "packages": { "@metamask/ethjs>js-sha3": true, "bn.js": true, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": true + "ganache>abstract-level>buffer": true } }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": { + "eth-lattice-keyring>gridplus-sdk>rlp": { "globals": { - "console": true - }, - "packages": { - "base64-js": true, - "browserify>buffer>ieee754": true + "TextEncoder": true } }, "eth-lattice-keyring>gridplus-sdk>secp256k1": { @@ -3564,20 +4032,9 @@ }, "ethereumjs-util>create-hash>md5.js>hash-base": { "packages": { - "ethereumjs-util>create-hash>md5.js>hash-base>readable-stream": true, "koa>content-disposition>safe-buffer": true, - "pumpify>inherits": true - } - }, - "ethereumjs-util>create-hash>md5.js>hash-base>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "readable-stream": true } }, "ethereumjs-util>create-hash>ripemd160": { @@ -3681,27 +4138,172 @@ "setTimeout": true } }, + "firebase": { + "packages": { + "firebase>@firebase/app": true, + "firebase>@firebase/messaging": true + } + }, + "firebase>@firebase/app": { + "globals": { + "FinalizationRegistry": true, + "console.warn": true + }, + "packages": { + "firebase>@firebase/app>@firebase/component": true, + "firebase>@firebase/app>@firebase/logger": true, + "firebase>@firebase/app>idb": true, + "firebase>@firebase/util": true + } + }, + "firebase>@firebase/app>@firebase/component": { + "packages": { + "firebase>@firebase/util": true + } + }, + "firebase>@firebase/app>@firebase/logger": { + "globals": { + "console": true + }, + "packages": { + "@trezor/connect-web>tslib": true + } + }, + "firebase>@firebase/app>idb": { + "globals": { + "DOMException": true, + "IDBCursor": true, + "IDBDatabase": true, + "IDBIndex": true, + "IDBObjectStore": true, + "IDBRequest": true, + "IDBTransaction": true, + "indexedDB.deleteDatabase": true, + "indexedDB.open": true + } + }, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs": { + "globals": { + "process": true, + "setTimeout": true + }, + "packages": { + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/aspromise": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/base64": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/codegen": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/eventemitter": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/fetch": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/float": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/inquire": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/path": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/pool": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/utf8": true + } + }, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/codegen": { + "globals": { + "console.log": true + } + }, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/fetch": { + "globals": { + "XMLHttpRequest": true + }, + "packages": { + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/aspromise": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/inquire": true + } + }, + "firebase>@firebase/installations": { + "globals": { + "BroadcastChannel": true, + "Headers": true, + "btoa": true, + "console.error": true, + "crypto": true, + "fetch": true, + "msCrypto": true, + "navigator.onLine": true, + "setTimeout": true + }, + "packages": { + "firebase>@firebase/app": true, + "firebase>@firebase/app>@firebase/component": true, + "firebase>@firebase/app>idb": true, + "firebase>@firebase/util": true + } + }, + "firebase>@firebase/messaging": { + "globals": { + "Headers": true, + "Notification.maxActions": true, + "Notification.permission": true, + "Notification.requestPermission": true, + "PushSubscription.prototype.hasOwnProperty": true, + "ServiceWorkerRegistration": true, + "URL": true, + "addEventListener": true, + "atob": true, + "btoa": true, + "clients.matchAll": true, + "clients.openWindow": true, + "console.warn": true, + "document": true, + "fetch": true, + "indexedDB": true, + "location.href": true, + "location.origin": true, + "navigator": true, + "origin.replace": true, + "registration.showNotification": true, + "setTimeout": true + }, + "packages": { + "@trezor/connect-web>tslib": true, + "firebase>@firebase/app": true, + "firebase>@firebase/app>@firebase/component": true, + "firebase>@firebase/app>idb": true, + "firebase>@firebase/installations": true, + "firebase>@firebase/util": true + } + }, + "firebase>@firebase/util": { + "globals": { + "atob": true, + "browser": true, + "btoa": true, + "chrome": true, + "console": true, + "document": true, + "indexedDB": true, + "navigator": true, + "process": true, + "self": true, + "setTimeout": true + }, + "packages": { + "browserify>process": true + } + }, "fuse.js": { "globals": { "console": true, "define": true } }, - "ganache>keccak": { + "ganache>abstract-level>buffer": { + "globals": { + "console": true + }, "packages": { - "browserify>buffer": true, - "ganache>keccak>readable-stream": true + "base64-js": true, + "browserify>buffer>ieee754": true } }, - "ganache>keccak>readable-stream": { + "ganache>keccak": { "packages": { - "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "readable-stream": true } }, "ganache>secp256k1": { @@ -3717,39 +4319,33 @@ "string.prototype.matchall>has-symbols": true } }, + "he": { + "globals": { + "define": true + } + }, "json-rpc-engine": { "packages": { - "@metamask/safe-event-emitter": true, - "eth-rpc-errors": true + "eth-rpc-errors": true, + "json-rpc-engine>@metamask/safe-event-emitter": true } }, - "json-rpc-middleware-stream": { + "json-rpc-engine>@metamask/safe-event-emitter": { "globals": { - "console.warn": true, "setTimeout": true }, "packages": { - "json-rpc-middleware-stream>@metamask/safe-event-emitter": true, - "json-rpc-middleware-stream>readable-stream": true + "webpack>events": true } }, - "json-rpc-middleware-stream>@metamask/safe-event-emitter": { + "json-rpc-middleware-stream": { "globals": { + "console.warn": true, "setTimeout": true }, "packages": { - "webpack>events": true - } - }, - "json-rpc-middleware-stream>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "@metamask/safe-event-emitter": true, + "readable-stream": true } }, "koa>content-disposition>safe-buffer": { @@ -3827,12 +4423,6 @@ "koa>content-disposition>safe-buffer": true } }, - "mockttp>graphql-tag>tslib": { - "globals": { - "SuppressedError": true, - "define": true - } - }, "nanoid": { "globals": { "crypto": true, @@ -3861,16 +4451,6 @@ "fetch": true } }, - "obj-multiplex": { - "globals": { - "console.warn": true - }, - "packages": { - "end-of-stream": true, - "pump>once": true, - "readable-stream": true - } - }, "promise-to-callback": { "packages": { "promise-to-callback>is-fn": true, @@ -3899,19 +4479,6 @@ "console": true } }, - "pump": { - "packages": { - "browserify>browser-resolve": true, - "browserify>process": true, - "end-of-stream": true, - "pump>once": true - } - }, - "pump>once": { - "packages": { - "pump>once>wrappy": true - } - }, "qrcode-generator": { "globals": { "define": true @@ -3923,8 +4490,6 @@ "devicePixelRatio": true }, "packages": { - "prop-types": true, - "qrcode.react>qr.js": true, "react": true } }, @@ -4089,7 +4654,7 @@ "setTimeout": true }, "packages": { - "mockttp>graphql-tag>tslib": true + "@trezor/connect-web>tslib": true } }, "react-focus-lock>react-clientside-effect": { @@ -4108,7 +4673,7 @@ "console.error": true }, "packages": { - "mockttp>graphql-tag>tslib": true, + "@trezor/connect-web>tslib": true, "react": true, "react-focus-lock>use-sidecar>detect-node-es": true } @@ -4266,13 +4831,12 @@ "document": true }, "packages": { - "@babel/runtime": true, "prop-types": true, - "prop-types>react-is": true, "react": true, "react-dom": true, + "react-redux>@babel/runtime": true, "react-redux>hoist-non-react-statics": true, - "redux": true + "react-redux>react-is": true } }, "react-redux>hoist-non-react-statics": { @@ -4280,6 +4844,11 @@ "prop-types>react-is": true } }, + "react-redux>react-is": { + "globals": { + "console": true + } + }, "react-responsive-carousel": { "globals": { "HTMLElement": true, @@ -4456,38 +5025,24 @@ "readable-stream": { "packages": { "browserify>browser-resolve": true, + "browserify>buffer": true, "browserify>process": true, - "browserify>timers-browserify": true, + "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>core-util-is": true, - "readable-stream>isarray": true, - "readable-stream>process-nextick-args": true, - "readable-stream>safe-buffer": true, - "readable-stream>string_decoder": true, "readable-stream>util-deprecate": true, "webpack>events": true } }, - "readable-stream>core-util-is": { + "readable-stream-2>core-util-is": { "packages": { "browserify>insert-module-globals>is-buffer": true } }, - "readable-stream>process-nextick-args": { + "readable-stream-2>process-nextick-args": { "packages": { "browserify>process": true } }, - "readable-stream>safe-buffer": { - "packages": { - "browserify>buffer": true - } - }, - "readable-stream>string_decoder": { - "packages": { - "readable-stream>safe-buffer": true - } - }, "readable-stream>util-deprecate": { "globals": { "console.trace": true, @@ -4508,13 +5063,7 @@ "console.error": true }, "packages": { - "browserify>process": true, - "semver>lru-cache": true - } - }, - "semver>lru-cache": { - "packages": { - "semver>lru-cache>yallist": true + "browserify>process": true } }, "sinon>nise>path-to-regexp": { @@ -4525,18 +5074,7 @@ "stream-browserify": { "packages": { "pumpify>inherits": true, - "stream-browserify>readable-stream": true, - "webpack>events": true - } - }, - "stream-browserify>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, + "readable-stream": true, "webpack>events": true } }, @@ -4616,6 +5154,15 @@ "string.prototype.matchall>call-bind": true } }, + "string.prototype.matchall>es-abstract>object-inspect": { + "globals": { + "HTMLElement": true, + "WeakRef": true + }, + "packages": { + "browserify>browser-resolve": true + } + }, "string.prototype.matchall>get-intrinsic": { "globals": { "AggregateError": true, @@ -4653,8 +5200,8 @@ }, "string.prototype.matchall>side-channel": { "packages": { - "brfs>static-module>object-inspect": true, "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>es-abstract>object-inspect": true, "string.prototype.matchall>get-intrinsic": true } }, @@ -4697,8 +5244,7 @@ }, "web3-stream-provider>uuid": { "globals": { - "crypto": true, - "msCrypto": true + "crypto": true } }, "webextension-polyfill": { diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 6b0066a20fad..8415dbd75002 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -5,6 +5,11 @@ "regeneratorRuntime": "write" } }, + "@contentful/rich-text-html-renderer": { + "globals": { + "SuppressedError": true + } + }, "@ensdomains/content-hash": { "globals": { "console.warn": true @@ -108,30 +113,30 @@ "browserify>util": true } }, - "@ethereumjs/common": { + "@ethereumjs/tx": { + "packages": { + "@ethereumjs/tx>@ethereumjs/common": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true + } + }, + "@ethereumjs/tx>@ethereumjs/common": { "packages": { - "@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, "webpack>events": true } }, - "@ethereumjs/common>crc-32": { + "@ethereumjs/tx>@ethereumjs/common>crc-32": { "globals": { "DO_NOT_EXPORT_CRC": true, "define": true } }, - "@ethereumjs/tx": { - "packages": { - "@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethereumjs/tx>ethereum-cryptography": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true - } - }, "@ethereumjs/tx>@ethereumjs/rlp": { "globals": { "TextEncoder": true @@ -184,13 +189,7 @@ "TextEncoder": true }, "packages": { - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true } }, "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { @@ -201,9 +200,23 @@ }, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": { "packages": { - "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, - "@metamask/utils>@scure/base": true, - "@noble/hashes": true + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/curves": true, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true, + "@metamask/utils>@scure/base": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/curves": { + "globals": { + "TextEncoder": true + }, + "packages": { + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethersproject/abi": { @@ -214,12 +227,12 @@ "@ethersproject/abi>@ethersproject/address": true, "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/abi>@ethersproject/constants": true, - "@ethersproject/abi>@ethersproject/hash": true, "@ethersproject/abi>@ethersproject/keccak256": true, "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/abi>@ethersproject/strings": true, - "@ethersproject/bignumber": true + "@ethersproject/bignumber": true, + "@ethersproject/hash": true } }, "@ethersproject/abi>@ethersproject/address": { @@ -241,18 +254,6 @@ "@ethersproject/bignumber": true } }, - "@ethersproject/abi>@ethersproject/hash": { - "packages": { - "@ethersproject/abi>@ethersproject/address": true, - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/keccak256": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/abi>@ethersproject/strings": true, - "@ethersproject/bignumber": true, - "@ethersproject/providers>@ethersproject/base64": true - } - }, "@ethersproject/abi>@ethersproject/keccak256": { "packages": { "@ethersproject/abi>@ethersproject/bytes": true, @@ -294,9 +295,36 @@ "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/bignumber": true, - "@ethersproject/hdnode>@ethersproject/abstract-signer": true, + "@ethersproject/hash>@ethersproject/abstract-signer": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@metamask/test-bundler>@ethersproject/abstract-provider": true + "@ethersproject/wallet>@ethersproject/abstract-provider": true + } + }, + "@ethersproject/hash": { + "packages": { + "@ethersproject/abi>@ethersproject/address": true, + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/keccak256": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/abi>@ethersproject/strings": true, + "@ethersproject/bignumber": true, + "@ethersproject/hash>@ethersproject/base64": true + } + }, + "@ethersproject/hash>@ethersproject/abstract-signer": { + "packages": { + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true + } + }, + "@ethersproject/hash>@ethersproject/base64": { + "globals": { + "atob": true, + "btoa": true + }, + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true } }, "@ethersproject/hdnode": { @@ -314,12 +342,6 @@ "@ethersproject/hdnode>@ethersproject/wordlists": true } }, - "@ethersproject/hdnode>@ethersproject/abstract-signer": { - "packages": { - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true - } - }, "@ethersproject/hdnode>@ethersproject/basex": { "packages": { "@ethersproject/abi>@ethersproject/bytes": true, @@ -363,10 +385,10 @@ "@ethersproject/hdnode>@ethersproject/wordlists": { "packages": { "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/hash": true, "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/abi>@ethersproject/strings": true + "@ethersproject/abi>@ethersproject/strings": true, + "@ethersproject/hash": true } }, "@ethersproject/providers": { @@ -383,39 +405,26 @@ "@ethersproject/abi>@ethersproject/address": true, "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/abi>@ethersproject/constants": true, - "@ethersproject/abi>@ethersproject/hash": true, "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/abi>@ethersproject/strings": true, "@ethersproject/bignumber": true, - "@ethersproject/hdnode>@ethersproject/abstract-signer": true, + "@ethersproject/hash": true, + "@ethersproject/hash>@ethersproject/abstract-signer": true, + "@ethersproject/hash>@ethersproject/base64": true, "@ethersproject/hdnode>@ethersproject/basex": true, "@ethersproject/hdnode>@ethersproject/sha2": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/base64": true, - "@ethersproject/providers>@ethersproject/random": true, "@ethersproject/providers>@ethersproject/web": true, "@ethersproject/providers>bech32": true, - "@metamask/test-bundler>@ethersproject/abstract-provider": true, + "@ethersproject/wallet>@ethersproject/abstract-provider": true, + "@ethersproject/wallet>@ethersproject/random": true, "@metamask/test-bundler>@ethersproject/networks": true } }, - "@ethersproject/providers>@ethersproject/base64": { - "globals": { - "atob": true, - "btoa": true - }, - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true - } - }, "@ethersproject/providers>@ethersproject/random": { "globals": { "crypto.getRandomValues": true - }, - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true } }, "@ethersproject/providers>@ethersproject/rlp": { @@ -435,7 +444,59 @@ "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/abi>@ethersproject/strings": true, - "@ethersproject/providers>@ethersproject/base64": true + "@ethersproject/hash>@ethersproject/base64": true + } + }, + "@ethersproject/wallet": { + "packages": { + "@ethersproject/abi>@ethersproject/address": true, + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/keccak256": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/hash": true, + "@ethersproject/hash>@ethersproject/abstract-signer": true, + "@ethersproject/hdnode": true, + "@ethersproject/hdnode>@ethersproject/signing-key": true, + "@ethersproject/hdnode>@ethersproject/transactions": true, + "@ethersproject/wallet>@ethersproject/abstract-provider": true, + "@ethersproject/wallet>@ethersproject/json-wallets": true, + "@ethersproject/wallet>@ethersproject/random": true + } + }, + "@ethersproject/wallet>@ethersproject/abstract-provider": { + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/bignumber": true + } + }, + "@ethersproject/wallet>@ethersproject/json-wallets": { + "packages": { + "@ethersproject/abi>@ethersproject/address": true, + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/keccak256": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/abi>@ethersproject/strings": true, + "@ethersproject/hdnode": true, + "@ethersproject/hdnode>@ethersproject/pbkdf2": true, + "@ethersproject/hdnode>@ethersproject/transactions": true, + "@ethersproject/wallet>@ethersproject/json-wallets>aes-js": true, + "@ethersproject/wallet>@ethersproject/random": true, + "ethereumjs-util>ethereum-cryptography>scrypt-js": true + } + }, + "@ethersproject/wallet>@ethersproject/json-wallets>aes-js": { + "globals": { + "define": true + } + }, + "@ethersproject/wallet>@ethersproject/random": { + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/logger": true } }, "@keystonehq/bc-ur-registry-eth": { @@ -453,9 +514,10 @@ }, "packages": { "@ngraveio/bc-ur": true, + "@trezor/connect-web>tslib": true, "browserify>buffer": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, - "mockttp>graphql-tag>tslib": true + "ganache>abstract-level>buffer": true } }, "@keystonehq/metamask-airgapped-keyring": { @@ -464,8 +526,8 @@ "@keystonehq/bc-ur-registry-eth": true, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, - "@keystonehq/metamask-airgapped-keyring>rlp": true, "browserify>buffer": true, + "ethereumjs-util>rlp": true, "uuid": true, "webpack>events": true } @@ -475,33 +537,65 @@ "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "@keystonehq/bc-ur-registry-eth": true, + "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, - "eth-lattice-keyring>rlp": true, "uuid": true } }, + "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": { + "globals": { + "TextEncoder": true + } + }, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": { "packages": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": true, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": true, - "@metamask/safe-event-emitter": true, "stream-browserify": true } }, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": { + "globals": { + "setTimeout": true + }, + "packages": { + "webpack>events": true + } + }, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": { "packages": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream": true, "browserify>process": true, "browserify>util": true, - "readable-stream": true, "watchify>xtend": true } }, - "@keystonehq/metamask-airgapped-keyring>rlp": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream": { + "packages": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>isarray": true, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": true, + "browserify>browser-resolve": true, + "browserify>process": true, + "browserify>timers-browserify": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true, + "webpack>events": true + } + }, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": { "packages": { - "bn.js": true, "browserify>buffer": true } }, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": { + "packages": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true + } + }, "@lavamoat/lavadome-react": { "globals": { "Document.prototype": true, @@ -702,25 +796,43 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/base-controller": true, + "@metamask/accounts-controller>@metamask/base-controller": true, + "@metamask/accounts-controller>@metamask/keyring-api": true, "@metamask/eth-snap-keyring": true, - "@metamask/keyring-api": true, "@metamask/keyring-controller": true, + "@metamask/snaps-utils": true, + "@metamask/utils": true, "uuid": true } }, - "@metamask/address-book-controller": { + "@metamask/accounts-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, "packages": { - "@metamask/address-book-controller>@metamask/base-controller": true, - "@metamask/address-book-controller>@metamask/controller-utils": true + "immer": true } }, - "@metamask/address-book-controller>@metamask/base-controller": { + "@metamask/accounts-controller>@metamask/keyring-api": { "globals": { - "setTimeout": true + "URL": true }, "packages": { - "immer": true + "@metamask/accounts-controller>@metamask/keyring-api>uuid": true, + "@metamask/keyring-api>bech32": true, + "@metamask/utils": true, + "superstruct": true + } + }, + "@metamask/accounts-controller>@metamask/keyring-api>uuid": { + "globals": { + "crypto": true + } + }, + "@metamask/address-book-controller": { + "packages": { + "@metamask/address-book-controller>@metamask/controller-utils": true, + "@metamask/base-controller": true } }, "@metamask/address-book-controller>@metamask/controller-utils": { @@ -731,32 +843,14 @@ "setTimeout": true }, "packages": { - "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": true, - "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, + "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true - } - }, - "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, - "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": { - "packages": { - "@metamask/ethjs>ethjs-abi>number-to-bn": true, - "bn.js": true + "eth-ens-namehash": true } }, "@metamask/announcement-controller": { @@ -765,6 +859,9 @@ } }, "@metamask/announcement-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, "packages": { "immer": true } @@ -774,9 +871,17 @@ "console.info": true }, "packages": { + "@metamask/approval-controller>@metamask/base-controller": true, "@metamask/approval-controller>nanoid": true, - "@metamask/base-controller": true, - "@metamask/providers>@metamask/rpc-errors": true + "@metamask/rpc-errors": true + } + }, + "@metamask/approval-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true } }, "@metamask/approval-controller>nanoid": { @@ -789,6 +894,7 @@ "AbortController": true, "Headers": true, "URL": true, + "URLSearchParams": true, "clearInterval": true, "clearTimeout": true, "console.error": true, @@ -803,6 +909,7 @@ "@ethersproject/providers": true, "@metamask/abi-utils": true, "@metamask/assets-controllers>@metamask/polling-controller": true, + "@metamask/assets-controllers>async-mutex": true, "@metamask/assets-controllers>cockatiel": true, "@metamask/assets-controllers>multiformats": true, "@metamask/base-controller": true, @@ -810,8 +917,7 @@ "@metamask/controller-utils": true, "@metamask/eth-query": true, "@metamask/metamask-eth-abis": true, - "@metamask/name-controller>async-mutex": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/utils": true, "bn.js": true, "lodash": true, @@ -832,6 +938,14 @@ "uuid": true } }, + "@metamask/assets-controllers>async-mutex": { + "globals": { + "setTimeout": true + }, + "packages": { + "@trezor/connect-web>tslib": true + } + }, "@metamask/assets-controllers>cockatiel": { "globals": { "AbortController": true, @@ -901,7 +1015,8 @@ "console.log": true }, "packages": { - "@metamask/controller-utils>@spruceid/siwe-parser>apg-js": true + "@metamask/controller-utils>@spruceid/siwe-parser>apg-js": true, + "@noble/hashes": true } }, "@metamask/controller-utils>@spruceid/siwe-parser>apg-js": { @@ -932,21 +1047,38 @@ "packages": { "@ethersproject/providers": true, "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@metamask/ens-controller>@metamask/controller-utils": true, "@metamask/utils": true, - "ethereum-ens-network-map": true, "punycode": true } }, + "@metamask/ens-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/eth-json-rpc-filters": { "globals": { "console.error": true }, "packages": { "@metamask/eth-json-rpc-filters>@metamask/eth-query": true, - "@metamask/eth-json-rpc-filters>@metamask/safe-event-emitter": true, - "@metamask/name-controller>async-mutex": true, - "@metamask/providers>@metamask/json-rpc-engine": true, + "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine": true, + "@metamask/eth-json-rpc-filters>async-mutex": true, + "@metamask/safe-event-emitter": true, "pify": true } }, @@ -956,12 +1088,19 @@ "watchify>xtend": true } }, - "@metamask/eth-json-rpc-filters>@metamask/safe-event-emitter": { + "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine": { + "packages": { + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true + } + }, + "@metamask/eth-json-rpc-filters>async-mutex": { "globals": { "setTimeout": true }, "packages": { - "webpack>events": true + "@trezor/connect-web>tslib": true } }, "@metamask/eth-json-rpc-middleware": { @@ -971,52 +1110,33 @@ "setTimeout": true }, "packages": { + "@metamask/eth-json-rpc-middleware>@metamask/json-rpc-engine": true, "@metamask/eth-json-rpc-middleware>safe-stable-stringify": true, "@metamask/eth-sig-util": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/utils": true, "pify": true, "sass-loader>klona": true } }, - "@metamask/eth-keyring-controller": { - "globals": { - "console.error": true - }, + "@metamask/eth-json-rpc-middleware>@metamask/eth-json-rpc-provider": { "packages": { - "@metamask/browser-passworder": true, - "@metamask/eth-keyring-controller>@metamask/obs-store": true, - "@metamask/eth-sig-util": true, - "@metamask/keyring-controller>@metamask/eth-hd-keyring": true, - "@metamask/keyring-controller>@metamask/eth-simple-keyring": true, - "@metamask/utils": true, - "webpack>events": true - } - }, - "@metamask/eth-keyring-controller>@metamask/obs-store": { - "packages": { - "@metamask/eth-keyring-controller>@metamask/obs-store>@metamask/safe-event-emitter": true, - "@metamask/eth-keyring-controller>@metamask/obs-store>readable-stream": true + "@metamask/eth-json-rpc-middleware>@metamask/eth-json-rpc-provider>@metamask/json-rpc-engine": true, + "@metamask/safe-event-emitter": true } }, - "@metamask/eth-keyring-controller>@metamask/obs-store>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, + "@metamask/eth-json-rpc-middleware>@metamask/eth-json-rpc-provider>@metamask/json-rpc-engine": { "packages": { - "webpack>events": true + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true } }, - "@metamask/eth-keyring-controller>@metamask/obs-store>readable-stream": { + "@metamask/eth-json-rpc-middleware>@metamask/json-rpc-engine": { "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true } }, "@metamask/eth-ledger-bridge-keyring": { @@ -1076,25 +1196,19 @@ }, "@metamask/eth-snap-keyring": { "globals": { + "URL": true, "console.error": true }, "packages": { "@ethereumjs/tx": true, "@metamask/eth-sig-util": true, - "@metamask/eth-snap-keyring>@metamask/keyring-api": true, "@metamask/eth-snap-keyring>uuid": true, + "@metamask/keyring-api": true, "@metamask/utils": true, "superstruct": true, "webpack>events": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-api": { - "packages": { - "@metamask/eth-snap-keyring>uuid": true, - "@metamask/utils": true, - "superstruct": true - } - }, "@metamask/eth-snap-keyring>uuid": { "globals": { "crypto": true @@ -1106,21 +1220,26 @@ }, "packages": { "@babel/runtime": true, - "@metamask/eth-token-tracker>@metamask/safe-event-emitter": true, + "@metamask/eth-token-tracker>@metamask/eth-block-tracker": true, "@metamask/eth-token-tracker>deep-equal": true, - "@metamask/eth-token-tracker>eth-block-tracker": true, "@metamask/ethjs-contract": true, "@metamask/ethjs-query": true, + "@metamask/safe-event-emitter": true, "bn.js": true, "human-standard-token-abi": true } }, - "@metamask/eth-token-tracker>@metamask/safe-event-emitter": { + "@metamask/eth-token-tracker>@metamask/eth-block-tracker": { "globals": { + "clearTimeout": true, + "console.error": true, "setTimeout": true }, "packages": { - "webpack>events": true + "@metamask/eth-query>json-rpc-random-id": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true, + "pify": true } }, "@metamask/eth-token-tracker>deep-equal": { @@ -1211,27 +1330,6 @@ "string.prototype.matchall>get-intrinsic": true } }, - "@metamask/eth-token-tracker>eth-block-tracker": { - "globals": { - "clearTimeout": true, - "console.error": true, - "setTimeout": true - }, - "packages": { - "@metamask/eth-query>json-rpc-random-id": true, - "@metamask/eth-token-tracker>eth-block-tracker>@metamask/safe-event-emitter": true, - "@metamask/utils": true, - "pify": true - } - }, - "@metamask/eth-token-tracker>eth-block-tracker>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, "@metamask/eth-trezor-keyring": { "globals": { "setTimeout": true @@ -1240,15 +1338,47 @@ "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": true, + "@metamask/eth-trezor-keyring>@trezor/connect-web": true, "@metamask/eth-trezor-keyring>hdkey": true, - "@trezor/connect-web": true, "browserify>buffer": true, "webpack>events": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": { "packages": { - "@metamask/eth-sig-util": true + "@metamask/eth-sig-util": true, + "@trezor/connect-web>tslib": true + } + }, + "@metamask/eth-trezor-keyring>@trezor/connect-web": { + "globals": { + "URLSearchParams": true, + "__TREZOR_CONNECT_SRC": true, + "addEventListener": true, + "btoa": true, + "chrome": true, + "clearInterval": true, + "clearTimeout": true, + "console.warn": true, + "document.body": true, + "document.createElement": true, + "document.createTextNode": true, + "document.getElementById": true, + "document.querySelectorAll": true, + "location": true, + "navigator": true, + "open": true, + "origin": true, + "removeEventListener": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@trezor/connect-web>@trezor/connect": true, + "@trezor/connect-web>@trezor/connect-common": true, + "@trezor/connect-web>@trezor/utils": true, + "@trezor/connect-web>tslib": true, + "webpack>events": true } }, "@metamask/eth-trezor-keyring>hdkey": { @@ -1388,13 +1518,30 @@ }, "packages": { "@metamask/assets-controllers>@metamask/polling-controller": true, - "@metamask/controller-utils": true, "@metamask/eth-query": true, - "@metamask/ethjs>@metamask/ethjs-unit": true, - "ethereumjs-util": true, + "@metamask/gas-fee-controller>@metamask/controller-utils": true, + "bn.js": true, "uuid": true } }, + "@metamask/gas-fee-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/jazzicon": { "globals": { "document.createElement": true, @@ -1428,7 +1575,11 @@ } }, "@metamask/keyring-api": { + "globals": { + "URL": true + }, "packages": { + "@metamask/keyring-api>bech32": true, "@metamask/keyring-api>uuid": true, "@metamask/utils": true, "superstruct": true @@ -1505,18 +1656,12 @@ "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>create-hash": true - } - }, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": { - "packages": { - "bn.js": true, - "browserify>buffer": true + "ethereumjs-util>create-hash": true, + "ethereumjs-util>rlp": true } }, "@metamask/logging-controller": { @@ -1541,9 +1686,9 @@ }, "@metamask/message-manager": { "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, "@metamask/eth-sig-util": true, + "@metamask/message-manager>@metamask/base-controller": true, + "@metamask/message-manager>@metamask/controller-utils": true, "@metamask/message-manager>jsonschema": true, "@metamask/utils": true, "browserify>buffer": true, @@ -1551,27 +1696,89 @@ "webpack>events": true } }, + "@metamask/message-manager>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/message-manager>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true } }, + "@metamask/message-signing-snap>@noble/curves": { + "globals": { + "TextEncoder": true + }, + "packages": { + "@noble/hashes": true + } + }, "@metamask/name-controller": { "globals": { "fetch": true }, "packages": { - "@metamask/base-controller": true, + "@metamask/name-controller>@metamask/base-controller": true, + "@metamask/name-controller>@metamask/controller-utils": true, "@metamask/name-controller>async-mutex": true, "@metamask/utils": true } }, + "@metamask/name-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/name-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/name-controller>async-mutex": { "globals": { + "clearTimeout": true, "setTimeout": true }, "packages": { - "mockttp>graphql-tag>tslib": true + "@trezor/connect-web>tslib": true } }, "@metamask/network-controller": { @@ -1582,45 +1789,70 @@ "setTimeout": true }, "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, "@metamask/eth-json-rpc-middleware": true, "@metamask/eth-query": true, - "@metamask/eth-token-tracker>eth-block-tracker": true, + "@metamask/eth-token-tracker>@metamask/eth-block-tracker": true, + "@metamask/network-controller>@metamask/base-controller": true, + "@metamask/network-controller>@metamask/controller-utils": true, "@metamask/network-controller>@metamask/eth-json-rpc-infura": true, "@metamask/network-controller>@metamask/eth-json-rpc-provider": true, "@metamask/network-controller>@metamask/swappable-obj-proxy": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true, "@metamask/utils": true, "browserify>assert": true, "uuid": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-infura": { + "@metamask/network-controller>@metamask/base-controller": { "globals": { "setTimeout": true }, "packages": { - "@metamask/network-controller>@metamask/eth-json-rpc-provider": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/utils": true, - "node-fetch": true + "immer": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-provider": { + "@metamask/network-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, "packages": { - "@metamask/network-controller>@metamask/eth-json-rpc-provider>@metamask/safe-event-emitter": true, - "@metamask/providers>@metamask/json-rpc-engine": true + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-provider>@metamask/safe-event-emitter": { + "@metamask/network-controller>@metamask/eth-json-rpc-infura": { "globals": { "setTimeout": true }, "packages": { - "webpack>events": true + "@metamask/eth-json-rpc-middleware>@metamask/eth-json-rpc-provider": true, + "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/json-rpc-engine": true, + "@metamask/rpc-errors": true, + "@metamask/utils": true, + "node-fetch": true + } + }, + "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/json-rpc-engine": { + "packages": { + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true + } + }, + "@metamask/network-controller>@metamask/eth-json-rpc-provider": { + "packages": { + "@metamask/safe-event-emitter": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true } }, "@metamask/notification-controller": { @@ -1655,19 +1887,24 @@ "crypto.getRandomValues": true } }, - "@metamask/obs-store": { + "@metamask/object-multiplex": { + "globals": { + "console.warn": true + }, "packages": { - "@metamask/obs-store>through2": true, - "@metamask/safe-event-emitter": true, - "stream-browserify": true + "@metamask/object-multiplex>once": true, + "readable-stream": true } }, - "@metamask/obs-store>through2": { + "@metamask/object-multiplex>once": { "packages": { - "browserify>process": true, - "browserify>util": true, - "readable-stream": true, - "watchify>xtend": true + "@metamask/object-multiplex>once>wrappy": true + } + }, + "@metamask/obs-store": { + "packages": { + "@metamask/safe-event-emitter": true, + "readable-stream": true } }, "@metamask/permission-controller": { @@ -1675,16 +1912,42 @@ "console.error": true }, "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/base-controller": true, + "@metamask/permission-controller>@metamask/controller-utils": true, "@metamask/permission-controller>nanoid": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true, "@metamask/utils": true, "deep-freeze-strict": true, "immer": true } }, + "@metamask/permission-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/permission-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/permission-controller>nanoid": { "globals": { "crypto.getRandomValues": true @@ -1724,19 +1987,8 @@ "removeEventListener": true }, "packages": { - "@metamask/post-message-stream>readable-stream": true, - "@metamask/utils": true - } - }, - "@metamask/post-message-stream>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "@metamask/utils": true, + "readable-stream": true } }, "@metamask/ppom-validator": { @@ -1746,9 +1998,9 @@ "crypto": true }, "packages": { - "@metamask/controller-utils": true, "@metamask/eth-query>json-rpc-random-id": true, "@metamask/ppom-validator>@metamask/base-controller": true, + "@metamask/ppom-validator>@metamask/controller-utils": true, "@metamask/ppom-validator>crypto-js": true, "@metamask/ppom-validator>elliptic": true, "await-semaphore": true, @@ -1763,6 +2015,24 @@ "immer": true } }, + "@metamask/ppom-validator>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/ppom-validator>crypto-js": { "globals": { "crypto": true, @@ -1800,54 +2070,21 @@ "ethereumjs-util>ethereum-cryptography>hash.js": true } }, - "@metamask/providers>@metamask/json-rpc-engine": { + "@metamask/queued-request-controller": { "packages": { - "@metamask/providers>@metamask/json-rpc-engine>@metamask/safe-event-emitter": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/queued-request-controller>@metamask/base-controller": true, + "@metamask/rpc-errors": true, + "@metamask/selected-network-controller": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true, "@metamask/utils": true } }, - "@metamask/providers>@metamask/json-rpc-engine>@metamask/safe-event-emitter": { + "@metamask/queued-request-controller>@metamask/base-controller": { "globals": { "setTimeout": true }, "packages": { - "webpack>events": true - } - }, - "@metamask/providers>@metamask/object-multiplex": { - "globals": { - "console.warn": true - }, - "packages": { - "@metamask/providers>@metamask/object-multiplex>readable-stream": true, - "pump>once": true - } - }, - "@metamask/providers>@metamask/object-multiplex>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "@metamask/providers>@metamask/rpc-errors": { - "packages": { - "@metamask/utils": true, - "eth-rpc-errors>fast-safe-stringify": true - } - }, - "@metamask/queued-request-controller": { - "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/selected-network-controller": true + "immer": true } }, "@metamask/rate-limit-controller": { @@ -1855,16 +2092,15 @@ "setTimeout": true }, "packages": { - "@metamask/rate-limit-controller>@metamask/base-controller": true, - "eth-rpc-errors": true + "@metamask/base-controller": true, + "@metamask/rpc-errors": true, + "@metamask/utils": true } }, - "@metamask/rate-limit-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, + "@metamask/rpc-errors": { "packages": { - "immer": true + "@metamask/utils": true, + "eth-rpc-errors>fast-safe-stringify": true } }, "@metamask/rpc-methods-flask>nanoid": { @@ -1902,8 +2138,16 @@ }, "@metamask/selected-network-controller": { "packages": { - "@metamask/base-controller": true, - "@metamask/network-controller>@metamask/swappable-obj-proxy": true + "@metamask/network-controller>@metamask/swappable-obj-proxy": true, + "@metamask/selected-network-controller>@metamask/base-controller": true + } + }, + "@metamask/selected-network-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true } }, "@metamask/signature-controller": { @@ -1912,16 +2156,46 @@ }, "packages": { "@metamask/base-controller": true, - "@metamask/controller-utils": true, "@metamask/logging-controller": true, - "@metamask/message-manager": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, + "@metamask/signature-controller>@metamask/controller-utils": true, + "@metamask/signature-controller>@metamask/message-manager": true, + "@metamask/utils": true, "browserify>buffer": true, - "ethereumjs-util": true, "lodash": true, "webpack>events": true } }, + "@metamask/signature-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/signature-controller>@metamask/message-manager": { + "packages": { + "@metamask/base-controller": true, + "@metamask/eth-sig-util": true, + "@metamask/message-manager>jsonschema": true, + "@metamask/signature-controller>@metamask/controller-utils": true, + "@metamask/utils": true, + "browserify>buffer": true, + "uuid": true, + "webpack>events": true + } + }, "@metamask/smart-transactions-controller": { "globals": { "URLSearchParams": true, @@ -1933,21 +2207,57 @@ }, "packages": { "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/bignumber": true, - "@ethersproject/providers": true, - "@metamask/smart-transactions-controller>@metamask/base-controller": true, + "@metamask/assets-controllers>@metamask/polling-controller": true, + "@metamask/eth-query": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx": true, + "@metamask/smart-transactions-controller>@ethereumjs/util": true, "@metamask/smart-transactions-controller>@metamask/controller-utils": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller": true, "@metamask/smart-transactions-controller>bignumber.js": true, + "browserify>buffer": true, "fast-json-patch": true, - "lodash": true + "lodash": true, + "webpack>events": true } }, - "@metamask/smart-transactions-controller>@metamask/base-controller": { + "@metamask/smart-transactions-controller>@babel/runtime": { "globals": { - "setTimeout": true + "regeneratorRuntime": "write" + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx": { + "packages": { + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": true, + "@metamask/smart-transactions-controller>@ethereumjs/util": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": { + "packages": { + "@metamask/smart-transactions-controller>@ethereumjs/util": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/util": { + "globals": { + "console.warn": true, + "fetch": true }, "packages": { - "immer": true + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@ethereumjs/util>@ethereumjs/rlp": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/util>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true } }, "@metamask/smart-transactions-controller>@metamask/controller-utils": { @@ -1958,13 +2268,27 @@ "setTimeout": true }, "packages": { - "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/smart-transactions-controller>@metamask/controller-utils>@ethereumjs/util": true, "@metamask/utils": true, + "bn.js": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true + "eth-ens-namehash": true + } + }, + "@metamask/smart-transactions-controller>@metamask/controller-utils>@ethereumjs/util": { + "globals": { + "console.warn": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "webpack>events": true } }, "@metamask/smart-transactions-controller>@metamask/controllers>nanoid": { @@ -1972,6 +2296,206 @@ "crypto.getRandomValues": true } }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller": { + "globals": { + "clearTimeout": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/common": true, + "@ethersproject/abi": true, + "@ethersproject/contracts": true, + "@ethersproject/providers": true, + "@metamask/eth-query": true, + "@metamask/metamask-eth-abis": true, + "@metamask/name-controller>async-mutex": true, + "@metamask/network-controller": true, + "@metamask/rpc-errors": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/base-controller": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/controller-utils": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry": true, + "@metamask/transaction-controller>@metamask/nonce-tracker": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "fast-json-patch": true, + "lodash": true, + "uuid": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx": { + "packages": { + "@ethereumjs/tx>@ethereumjs/common": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": { + "globals": { + "console.warn": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller": { + "globals": { + "clearInterval": true, + "console.error": true, + "setInterval": true + }, + "packages": { + "@metamask/eth-query": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/controller-utils": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/polling-controller": true, + "bn.js": true, + "browserify>buffer": true, + "uuid": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/controller-utils>@ethereumjs/util": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/controller-utils>@ethereumjs/util": { + "globals": { + "console.warn": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/polling-controller": { + "globals": { + "clearTimeout": true, + "console.error": true, + "setTimeout": true + }, + "packages": { + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/base-controller": true, + "@metamask/snaps-utils>fast-json-stable-stringify": true, + "uuid": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry": { + "packages": { + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract": { + "packages": { + "@metamask/ethjs>ethjs-abi": true, + "@metamask/ethjs>js-sha3": true, + "@metamask/smart-transactions-controller>@babel/runtime": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-filter": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-util": true, + "promise-to-callback": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-filter": { + "globals": { + "clearInterval": true, + "setInterval": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-util": { + "packages": { + "@metamask/ethjs>@metamask/ethjs-util>is-hex-prefixed": true, + "@metamask/ethjs>@metamask/ethjs-util>strip-hex-prefix": true, + "browserify>buffer": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query>@metamask/ethjs-format": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query>@metamask/ethjs-rpc": true, + "promise-to-callback": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query>@metamask/ethjs-format": { + "packages": { + "@metamask/ethjs-query>@metamask/ethjs-format>ethjs-schema": true, + "@metamask/ethjs>@metamask/ethjs-util>strip-hex-prefix": true, + "@metamask/ethjs>@metamask/number-to-bn": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-util": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query>@metamask/ethjs-rpc": { + "packages": { + "promise-to-callback": true + } + }, "@metamask/smart-transactions-controller>bignumber.js": { "globals": { "crypto": true, @@ -1982,25 +2506,23 @@ "globals": { "DecompressionStream": true, "URL": true, - "chrome.offscreen.createDocument": true, - "chrome.offscreen.hasDocument": true, "clearTimeout": true, "document.getElementById": true, "fetch.bind": true, "setTimeout": true }, "packages": { - "@metamask/base-controller": true, + "@metamask/object-multiplex": true, "@metamask/permission-controller": true, "@metamask/post-message-stream": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/object-multiplex": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, + "@metamask/snaps-controllers>@metamask/base-controller": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true, + "@metamask/snaps-controllers>@metamask/json-rpc-middleware-stream": true, "@metamask/snaps-controllers>@xstate/fsm": true, "@metamask/snaps-controllers>concat-stream": true, "@metamask/snaps-controllers>get-npm-tarball-url": true, "@metamask/snaps-controllers>nanoid": true, - "@metamask/snaps-controllers>readable-stream": true, "@metamask/snaps-controllers>readable-web-to-node-stream": true, "@metamask/snaps-controllers>tar-stream": true, "@metamask/snaps-rpc-methods": true, @@ -2009,7 +2531,8 @@ "@metamask/snaps-utils>@metamask/snaps-registry": true, "@metamask/utils": true, "browserify>browserify-zlib": true, - "json-rpc-middleware-stream": true + "eslint>fast-deep-equal": true, + "readable-stream": true } }, "@metamask/snaps-controllers-flask>nanoid": { @@ -2017,12 +2540,37 @@ "crypto.getRandomValues": true } }, + "@metamask/snaps-controllers>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": { + "packages": { + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true + } + }, + "@metamask/snaps-controllers>@metamask/json-rpc-middleware-stream": { + "globals": { + "console.warn": true, + "setTimeout": true + }, + "packages": { + "@metamask/safe-event-emitter": true, + "readable-stream": true + } + }, "@metamask/snaps-controllers>concat-stream": { "packages": { - "@metamask/snaps-controllers>readable-stream": true, "browserify>buffer": true, "browserify>concat-stream>typedarray": true, "pumpify>inherits": true, + "readable-stream": true, "terser>source-map-support>buffer-from": true } }, @@ -2031,31 +2579,9 @@ "crypto.getRandomValues": true } }, - "@metamask/snaps-controllers>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, "@metamask/snaps-controllers>readable-web-to-node-stream": { "packages": { - "@metamask/snaps-controllers>readable-web-to-node-stream>readable-stream": true - } - }, - "@metamask/snaps-controllers>readable-web-to-node-stream>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "readable-stream": true } }, "@metamask/snaps-controllers>tar-stream": { @@ -2084,10 +2610,20 @@ "queueMicrotask": true } }, + "@metamask/snaps-execution-environments": { + "globals": { + "document.getElementById": true + }, + "packages": { + "@metamask/post-message-stream": true, + "@metamask/snaps-utils": true, + "@metamask/utils": true + } + }, "@metamask/snaps-rpc-methods": { "packages": { "@metamask/permission-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/snaps-sdk": true, "@metamask/snaps-sdk>@metamask/key-tree": true, "@metamask/snaps-utils": true, @@ -2101,50 +2637,18 @@ "fetch": true }, "packages": { - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/snaps-sdk>fast-xml-parser": true, + "@metamask/rpc-errors": true, "@metamask/utils": true, "superstruct": true } }, "@metamask/snaps-sdk>@metamask/key-tree": { "packages": { + "@metamask/message-signing-snap>@noble/curves": true, "@metamask/scure-bip39": true, - "@metamask/snaps-sdk>@metamask/key-tree>@metamask/utils": true, - "@metamask/snaps-sdk>@metamask/key-tree>@noble/ed25519": true, + "@metamask/utils": true, "@metamask/utils>@scure/base": true, - "@noble/hashes": true, - "eth-lattice-keyring>@noble/secp256k1": true - } - }, - "@metamask/snaps-sdk>@metamask/key-tree>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, - "@metamask/snaps-sdk>@metamask/key-tree>@noble/ed25519": { - "globals": { - "crypto": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "@metamask/snaps-sdk>fast-xml-parser": { - "globals": { - "entityName": true, - "val": true - }, - "packages": { - "@metamask/snaps-sdk>fast-xml-parser>strnum": true + "@noble/hashes": true } }, "@metamask/snaps-utils": { @@ -2152,6 +2656,7 @@ "File": true, "FileReader": true, "TextDecoder": true, + "TextEncoder": true, "URL": true, "console.error": true, "console.log": true, @@ -2163,12 +2668,13 @@ }, "packages": { "@metamask/permission-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/snaps-sdk": true, "@metamask/snaps-sdk>@metamask/key-tree": true, "@metamask/snaps-utils>@metamask/slip44": true, "@metamask/snaps-utils>cron-parser": true, "@metamask/snaps-utils>fast-json-stable-stringify": true, + "@metamask/snaps-utils>fast-xml-parser": true, "@metamask/snaps-utils>marked": true, "@metamask/snaps-utils>rfdc": true, "@metamask/snaps-utils>validate-npm-package-name": true, @@ -2182,46 +2688,32 @@ }, "@metamask/snaps-utils>@metamask/snaps-registry": { "packages": { - "@metamask/snaps-utils>@metamask/snaps-registry>@noble/curves": true, + "@metamask/message-signing-snap>@noble/curves": true, "@metamask/utils": true, "@noble/hashes": true, "superstruct": true } }, - "@metamask/snaps-utils>@metamask/snaps-registry>@noble/curves": { - "globals": { - "TextEncoder": true - }, - "packages": { - "@noble/hashes": true - } - }, "@metamask/snaps-utils>cron-parser": { "packages": { "browserify>browser-resolve": true, "luxon": true } }, + "@metamask/snaps-utils>fast-xml-parser": { + "globals": { + "entityName": true, + "val": true + }, + "packages": { + "@metamask/snaps-utils>fast-xml-parser>strnum": true + } + }, "@metamask/snaps-utils>marked": { "globals": { - "Hooks": true, - "Lexer": true, - "Parser": true, - "Renderer": true, - "TextRenderer": true, - "Tokenizer": true, "console.error": true, "console.warn": true, - "defaults": true, - "define": true, - "inlineQueue": true, - "passThroughHooks": true, - "renderer": true, - "rules": true, - "state": true, - "textRenderer": true, - "tokenizer": true, - "tokens": true + "define": true } }, "@metamask/snaps-utils>rfdc": { @@ -2240,14 +2732,6 @@ "semver": true } }, - "@metamask/test-bundler>@ethersproject/abstract-provider": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/bignumber": true - } - }, "@metamask/test-bundler>@ethersproject/networks": { "packages": { "@ethersproject/abi>@ethersproject/logger": true @@ -2257,24 +2741,28 @@ "globals": { "clearTimeout": true, "console.error": true, + "fetch": true, "setTimeout": true }, "packages": { - "@ethereumjs/common": true, "@ethereumjs/tx": true, + "@ethereumjs/tx>@ethereumjs/common": true, "@ethereumjs/tx>@ethereumjs/util": true, "@ethersproject/abi": true, - "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@ethersproject/contracts": true, + "@ethersproject/providers": true, "@metamask/eth-query": true, "@metamask/gas-fee-controller": true, "@metamask/metamask-eth-abis": true, "@metamask/name-controller>async-mutex": true, "@metamask/network-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/transaction-controller>nonce-tracker": true, + "@metamask/rpc-errors": true, + "@metamask/transaction-controller>@metamask/base-controller": true, + "@metamask/transaction-controller>@metamask/controller-utils": true, + "@metamask/transaction-controller>@metamask/nonce-tracker": true, "@metamask/utils": true, "bn.js": true, + "browserify>buffer": true, "eth-method-registry": true, "fast-json-patch": true, "lodash": true, @@ -2282,21 +2770,46 @@ "webpack>events": true } }, - "@metamask/transaction-controller>nonce-tracker": { + "@metamask/transaction-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/transaction-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/transaction-controller>@metamask/nonce-tracker": { "packages": { "@ethersproject/providers": true, - "@metamask/eth-token-tracker>eth-block-tracker": true, - "@metamask/transaction-controller>nonce-tracker>async-mutex": true, + "@metamask/transaction-controller>@metamask/nonce-tracker>async-mutex": true, "browserify>assert": true } }, - "@metamask/transaction-controller>nonce-tracker>async-mutex": { + "@metamask/transaction-controller>@metamask/nonce-tracker>async-mutex": { "globals": { "clearTimeout": true, "setTimeout": true }, "packages": { - "mockttp>graphql-tag>tslib": true + "@trezor/connect-web>tslib": true } }, "@metamask/user-operation-controller": { @@ -2306,19 +2819,37 @@ "packages": { "@metamask/assets-controllers>@metamask/polling-controller": true, "@metamask/base-controller": true, - "@metamask/controller-utils": true, "@metamask/eth-query": true, "@metamask/gas-fee-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/transaction-controller": true, + "@metamask/user-operation-controller>@metamask/controller-utils": true, "@metamask/utils": true, - "ethereumjs-util": true, + "bn.js": true, "lodash": true, "superstruct": true, "uuid": true, "webpack>events": true } }, + "@metamask/user-operation-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/utils": { "globals": { "TextDecoder": true, @@ -2342,7 +2873,7 @@ }, "@ngraveio/bc-ur": { "packages": { - "@ngraveio/bc-ur>@apocentre/alias-sampling": true, + "@ngraveio/bc-ur>@keystonehq/alias-sampling": true, "@ngraveio/bc-ur>bignumber.js": true, "@ngraveio/bc-ur>cbor-sync": true, "@ngraveio/bc-ur>crc": true, @@ -2382,6 +2913,13 @@ "define": true } }, + "@noble/ciphers": { + "globals": { + "TextDecoder": true, + "TextEncoder": true, + "crypto": true + } + }, "@noble/hashes": { "globals": { "TextEncoder": true, @@ -2404,12 +2942,14 @@ "AbortController": true, "__REDUX_DEVTOOLS_EXTENSION_COMPOSE__": true, "__REDUX_DEVTOOLS_EXTENSION__": true, - "console.error": true, - "console.info": true, - "console.warn": true + "console": true, + "queueMicrotask": true, + "requestAnimationFrame": true, + "setTimeout": true }, "packages": { "@reduxjs/toolkit>reselect": true, + "browserify>process": true, "immer": true, "redux": true, "redux-thunk": true @@ -2566,6 +3106,7 @@ }, "@trezor/connect-web": { "globals": { + "URLSearchParams": true, "__TREZOR_CONNECT_SRC": true, "addEventListener": true, "btoa": true, @@ -2581,42 +3122,105 @@ "location": true, "navigator": true, "open": true, + "origin": true, "removeEventListener": true, "setInterval": true, "setTimeout": true }, "packages": { "@trezor/connect-web>@trezor/connect": true, + "@trezor/connect-web>@trezor/connect-common": true, "@trezor/connect-web>@trezor/utils": true, - "mockttp>graphql-tag>tslib": true, + "@trezor/connect-web>tslib": true, "webpack>events": true } }, "@trezor/connect-web>@trezor/connect": { + "packages": { + "@trezor/connect-web>@trezor/connect>@trezor/protobuf": true, + "@trezor/connect-web>@trezor/connect>@trezor/schema-utils": true, + "@trezor/connect-web>@trezor/connect>@trezor/transport": true, + "@trezor/connect-web>@trezor/utils": true, + "@trezor/connect-web>tslib": true + } + }, + "@trezor/connect-web>@trezor/connect-common": { "globals": { - "console.error": true, - "console.log": true, - "console.warn": true + "console.warn": true, + "localStorage.getItem": true, + "localStorage.setItem": true, + "navigator": true, + "setTimeout": true, + "window": true }, "packages": { - "@trezor/connect-web>@trezor/connect>@trezor/transport": true, - "@trezor/connect-web>@trezor/connect>tslib": true + "@trezor/connect-web>@trezor/connect-common>@trezor/env-utils": true, + "@trezor/connect-web>@trezor/utils": true, + "@trezor/connect-web>tslib": true } }, - "@trezor/connect-web>@trezor/connect>tslib": { + "@trezor/connect-web>@trezor/connect-common>@trezor/env-utils": { + "globals": { + "innerHeight": true, + "innerWidth": true, + "location.hostname": true, + "location.origin": true, + "navigator.languages": true, + "navigator.platform": true, + "navigator.userAgent": true, + "screen.height": true, + "screen.width": true + }, + "packages": { + "@trezor/connect-web>@trezor/connect-common>@trezor/env-utils>ua-parser-js": true, + "@trezor/connect-web>tslib": true, + "browserify>process": true + } + }, + "@trezor/connect-web>@trezor/connect-common>@trezor/env-utils>ua-parser-js": { "globals": { "define": true } }, + "@trezor/connect-web>@trezor/connect>@trezor/protobuf": { + "packages": { + "@trezor/connect-web>@trezor/connect>@trezor/schema-utils": true, + "@trezor/connect-web>tslib": true, + "browserify>buffer": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs": true + } + }, + "@trezor/connect-web>@trezor/connect>@trezor/schema-utils": { + "globals": { + "console.warn": true + }, + "packages": { + "@trezor/connect-web>@trezor/connect>@trezor/schema-utils>@sinclair/typebox": true, + "browserify>buffer": true, + "ts-mixer": true + } + }, "@trezor/connect-web>@trezor/utils": { "globals": { "AbortController": true, "Intl.NumberFormat": true, "clearTimeout": true, + "console.error": true, + "console.info": true, + "console.log": true, + "console.warn": true, "setTimeout": true }, "packages": { - "browserify>buffer": true + "@trezor/connect-web>tslib": true, + "browserify>buffer": true, + "webpack>events": true + } + }, + "@trezor/connect-web>tslib": { + "globals": { + "SuppressedError": true, + "define": true } }, "@zxing/browser": { @@ -2694,15 +3298,6 @@ "define": true } }, - "brfs>static-module>object-inspect": { - "globals": { - "HTMLElement": true, - "WeakRef": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "browserify>assert": { "globals": { "Buffer": true @@ -2930,23 +3525,12 @@ "browserify>buffer": true, "browserify>process": true, "browserify>stream-http>builtin-status-codes": true, - "browserify>stream-http>readable-stream": true, "browserify>url": true, "pumpify>inherits": true, + "readable-stream": true, "watchify>xtend": true } }, - "browserify>stream-http>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, "browserify>string_decoder": { "packages": { "koa>content-disposition>safe-buffer": true @@ -3039,41 +3623,20 @@ }, "chart.js": { "globals": { - "$animations": true, "Intl.NumberFormat": true, "MutationObserver": true, "OffscreenCanvas": true, "Path2D": true, "ResizeObserver": true, - "active": true, "addEventListener": true, - "circumference": true, "clearTimeout": true, "console.error": true, "console.warn": true, - "dataElementType": true, - "datasetElementType": true, - "defaultRoutes": true, - "defaults": true, - "descriptors": true, "devicePixelRatio": true, "document": true, - "endAngle": true, - "fullCircles": true, - "id": true, - "innerRadius": true, - "options": true, - "outerRadius": true, - "overrides": true, - "parsed": true, - "pixelMargin": true, "removeEventListener": true, "requestAnimationFrame": true, - "setTimeout": true, - "startAngle": true, - "stop": true, - "x": true, - "y": true + "setTimeout": true }, "packages": { "chart.js>@kurkle/color": true @@ -3170,12 +3733,6 @@ "crypto.getRandomValues": true } }, - "end-of-stream": { - "packages": { - "browserify>process": true, - "pump>once": true - } - }, "eslint-plugin-react>array-includes>is-string": { "packages": { "koa>is-generator-function>has-tostringtag": true @@ -3236,7 +3793,7 @@ }, "eth-lattice-keyring>@ethereumjs/tx": { "packages": { - "@ethereumjs/common": true, + "@ethereumjs/tx>@ethereumjs/common": true, "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util": true, "@ethersproject/providers": true, @@ -3277,14 +3834,6 @@ "crypto": true } }, - "eth-lattice-keyring>@noble/secp256k1": { - "globals": { - "crypto": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -3300,23 +3849,23 @@ "setTimeout": true }, "packages": { - "@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethersproject/abi": true, "@metamask/ethjs>js-sha3": true, + "@metamask/keyring-api>bech32": true, "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>buffer": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, - "eth-lattice-keyring>gridplus-sdk>bech32": true, "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, + "eth-lattice-keyring>gridplus-sdk>rlp": true, "eth-lattice-keyring>gridplus-sdk>secp256k1": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, - "eth-lattice-keyring>rlp": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>hash.js": true, "lodash": true @@ -3324,7 +3873,7 @@ }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": { "packages": { - "@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, "webpack>events": true @@ -3344,7 +3893,7 @@ }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { "packages": { - "@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, "webpack>events": true @@ -3412,16 +3961,12 @@ "packages": { "@metamask/ethjs>js-sha3": true, "bn.js": true, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": true + "ganache>abstract-level>buffer": true } }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": { + "eth-lattice-keyring>gridplus-sdk>rlp": { "globals": { - "console": true - }, - "packages": { - "base64-js": true, - "browserify>buffer>ieee754": true + "TextEncoder": true } }, "eth-lattice-keyring>gridplus-sdk>secp256k1": { @@ -3487,20 +4032,9 @@ }, "ethereumjs-util>create-hash>md5.js>hash-base": { "packages": { - "ethereumjs-util>create-hash>md5.js>hash-base>readable-stream": true, "koa>content-disposition>safe-buffer": true, - "pumpify>inherits": true - } - }, - "ethereumjs-util>create-hash>md5.js>hash-base>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "readable-stream": true } }, "ethereumjs-util>create-hash>ripemd160": { @@ -3604,27 +4138,172 @@ "setTimeout": true } }, + "firebase": { + "packages": { + "firebase>@firebase/app": true, + "firebase>@firebase/messaging": true + } + }, + "firebase>@firebase/app": { + "globals": { + "FinalizationRegistry": true, + "console.warn": true + }, + "packages": { + "firebase>@firebase/app>@firebase/component": true, + "firebase>@firebase/app>@firebase/logger": true, + "firebase>@firebase/app>idb": true, + "firebase>@firebase/util": true + } + }, + "firebase>@firebase/app>@firebase/component": { + "packages": { + "firebase>@firebase/util": true + } + }, + "firebase>@firebase/app>@firebase/logger": { + "globals": { + "console": true + }, + "packages": { + "@trezor/connect-web>tslib": true + } + }, + "firebase>@firebase/app>idb": { + "globals": { + "DOMException": true, + "IDBCursor": true, + "IDBDatabase": true, + "IDBIndex": true, + "IDBObjectStore": true, + "IDBRequest": true, + "IDBTransaction": true, + "indexedDB.deleteDatabase": true, + "indexedDB.open": true + } + }, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs": { + "globals": { + "process": true, + "setTimeout": true + }, + "packages": { + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/aspromise": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/base64": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/codegen": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/eventemitter": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/fetch": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/float": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/inquire": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/path": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/pool": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/utf8": true + } + }, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/codegen": { + "globals": { + "console.log": true + } + }, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/fetch": { + "globals": { + "XMLHttpRequest": true + }, + "packages": { + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/aspromise": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/inquire": true + } + }, + "firebase>@firebase/installations": { + "globals": { + "BroadcastChannel": true, + "Headers": true, + "btoa": true, + "console.error": true, + "crypto": true, + "fetch": true, + "msCrypto": true, + "navigator.onLine": true, + "setTimeout": true + }, + "packages": { + "firebase>@firebase/app": true, + "firebase>@firebase/app>@firebase/component": true, + "firebase>@firebase/app>idb": true, + "firebase>@firebase/util": true + } + }, + "firebase>@firebase/messaging": { + "globals": { + "Headers": true, + "Notification.maxActions": true, + "Notification.permission": true, + "Notification.requestPermission": true, + "PushSubscription.prototype.hasOwnProperty": true, + "ServiceWorkerRegistration": true, + "URL": true, + "addEventListener": true, + "atob": true, + "btoa": true, + "clients.matchAll": true, + "clients.openWindow": true, + "console.warn": true, + "document": true, + "fetch": true, + "indexedDB": true, + "location.href": true, + "location.origin": true, + "navigator": true, + "origin.replace": true, + "registration.showNotification": true, + "setTimeout": true + }, + "packages": { + "@trezor/connect-web>tslib": true, + "firebase>@firebase/app": true, + "firebase>@firebase/app>@firebase/component": true, + "firebase>@firebase/app>idb": true, + "firebase>@firebase/installations": true, + "firebase>@firebase/util": true + } + }, + "firebase>@firebase/util": { + "globals": { + "atob": true, + "browser": true, + "btoa": true, + "chrome": true, + "console": true, + "document": true, + "indexedDB": true, + "navigator": true, + "process": true, + "self": true, + "setTimeout": true + }, + "packages": { + "browserify>process": true + } + }, "fuse.js": { "globals": { "console": true, "define": true } }, - "ganache>keccak": { + "ganache>abstract-level>buffer": { + "globals": { + "console": true + }, "packages": { - "browserify>buffer": true, - "ganache>keccak>readable-stream": true + "base64-js": true, + "browserify>buffer>ieee754": true } }, - "ganache>keccak>readable-stream": { + "ganache>keccak": { "packages": { - "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "readable-stream": true } }, "ganache>secp256k1": { @@ -3640,39 +4319,33 @@ "string.prototype.matchall>has-symbols": true } }, + "he": { + "globals": { + "define": true + } + }, "json-rpc-engine": { "packages": { - "@metamask/safe-event-emitter": true, - "eth-rpc-errors": true + "eth-rpc-errors": true, + "json-rpc-engine>@metamask/safe-event-emitter": true } }, - "json-rpc-middleware-stream": { + "json-rpc-engine>@metamask/safe-event-emitter": { "globals": { - "console.warn": true, "setTimeout": true }, "packages": { - "json-rpc-middleware-stream>@metamask/safe-event-emitter": true, - "json-rpc-middleware-stream>readable-stream": true + "webpack>events": true } }, - "json-rpc-middleware-stream>@metamask/safe-event-emitter": { + "json-rpc-middleware-stream": { "globals": { + "console.warn": true, "setTimeout": true }, "packages": { - "webpack>events": true - } - }, - "json-rpc-middleware-stream>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "@metamask/safe-event-emitter": true, + "readable-stream": true } }, "koa>content-disposition>safe-buffer": { @@ -3750,12 +4423,6 @@ "koa>content-disposition>safe-buffer": true } }, - "mockttp>graphql-tag>tslib": { - "globals": { - "SuppressedError": true, - "define": true - } - }, "nanoid": { "globals": { "crypto": true, @@ -3784,16 +4451,6 @@ "fetch": true } }, - "obj-multiplex": { - "globals": { - "console.warn": true - }, - "packages": { - "end-of-stream": true, - "pump>once": true, - "readable-stream": true - } - }, "promise-to-callback": { "packages": { "promise-to-callback>is-fn": true, @@ -3822,19 +4479,6 @@ "console": true } }, - "pump": { - "packages": { - "browserify>browser-resolve": true, - "browserify>process": true, - "end-of-stream": true, - "pump>once": true - } - }, - "pump>once": { - "packages": { - "pump>once>wrappy": true - } - }, "qrcode-generator": { "globals": { "define": true @@ -3846,8 +4490,6 @@ "devicePixelRatio": true }, "packages": { - "prop-types": true, - "qrcode.react>qr.js": true, "react": true } }, @@ -4012,7 +4654,7 @@ "setTimeout": true }, "packages": { - "mockttp>graphql-tag>tslib": true + "@trezor/connect-web>tslib": true } }, "react-focus-lock>react-clientside-effect": { @@ -4031,7 +4673,7 @@ "console.error": true }, "packages": { - "mockttp>graphql-tag>tslib": true, + "@trezor/connect-web>tslib": true, "react": true, "react-focus-lock>use-sidecar>detect-node-es": true } @@ -4189,13 +4831,12 @@ "document": true }, "packages": { - "@babel/runtime": true, "prop-types": true, - "prop-types>react-is": true, "react": true, "react-dom": true, + "react-redux>@babel/runtime": true, "react-redux>hoist-non-react-statics": true, - "redux": true + "react-redux>react-is": true } }, "react-redux>hoist-non-react-statics": { @@ -4203,6 +4844,11 @@ "prop-types>react-is": true } }, + "react-redux>react-is": { + "globals": { + "console": true + } + }, "react-responsive-carousel": { "globals": { "HTMLElement": true, @@ -4379,38 +5025,24 @@ "readable-stream": { "packages": { "browserify>browser-resolve": true, + "browserify>buffer": true, "browserify>process": true, - "browserify>timers-browserify": true, + "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>core-util-is": true, - "readable-stream>isarray": true, - "readable-stream>process-nextick-args": true, - "readable-stream>safe-buffer": true, - "readable-stream>string_decoder": true, "readable-stream>util-deprecate": true, "webpack>events": true } }, - "readable-stream>core-util-is": { + "readable-stream-2>core-util-is": { "packages": { "browserify>insert-module-globals>is-buffer": true } }, - "readable-stream>process-nextick-args": { + "readable-stream-2>process-nextick-args": { "packages": { "browserify>process": true } }, - "readable-stream>safe-buffer": { - "packages": { - "browserify>buffer": true - } - }, - "readable-stream>string_decoder": { - "packages": { - "readable-stream>safe-buffer": true - } - }, "readable-stream>util-deprecate": { "globals": { "console.trace": true, @@ -4431,13 +5063,7 @@ "console.error": true }, "packages": { - "browserify>process": true, - "semver>lru-cache": true - } - }, - "semver>lru-cache": { - "packages": { - "semver>lru-cache>yallist": true + "browserify>process": true } }, "sinon>nise>path-to-regexp": { @@ -4448,18 +5074,7 @@ "stream-browserify": { "packages": { "pumpify>inherits": true, - "stream-browserify>readable-stream": true, - "webpack>events": true - } - }, - "stream-browserify>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, + "readable-stream": true, "webpack>events": true } }, @@ -4539,6 +5154,15 @@ "string.prototype.matchall>call-bind": true } }, + "string.prototype.matchall>es-abstract>object-inspect": { + "globals": { + "HTMLElement": true, + "WeakRef": true + }, + "packages": { + "browserify>browser-resolve": true + } + }, "string.prototype.matchall>get-intrinsic": { "globals": { "AggregateError": true, @@ -4576,8 +5200,8 @@ }, "string.prototype.matchall>side-channel": { "packages": { - "brfs>static-module>object-inspect": true, "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>es-abstract>object-inspect": true, "string.prototype.matchall>get-intrinsic": true } }, @@ -4620,8 +5244,7 @@ }, "web3-stream-provider>uuid": { "globals": { - "crypto": true, - "msCrypto": true + "crypto": true } }, "webextension-polyfill": { diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 0422d27c3ae7..3863648c3f02 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -5,6 +5,11 @@ "regeneratorRuntime": "write" } }, + "@contentful/rich-text-html-renderer": { + "globals": { + "SuppressedError": true + } + }, "@ensdomains/content-hash": { "globals": { "console.warn": true @@ -108,30 +113,30 @@ "browserify>util": true } }, - "@ethereumjs/common": { + "@ethereumjs/tx": { + "packages": { + "@ethereumjs/tx>@ethereumjs/common": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true + } + }, + "@ethereumjs/tx>@ethereumjs/common": { "packages": { - "@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, "webpack>events": true } }, - "@ethereumjs/common>crc-32": { + "@ethereumjs/tx>@ethereumjs/common>crc-32": { "globals": { "DO_NOT_EXPORT_CRC": true, "define": true } }, - "@ethereumjs/tx": { - "packages": { - "@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethereumjs/tx>ethereum-cryptography": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true - } - }, "@ethereumjs/tx>@ethereumjs/rlp": { "globals": { "TextEncoder": true @@ -184,13 +189,7 @@ "TextEncoder": true }, "packages": { - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": true - } - }, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true } }, "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { @@ -201,9 +200,23 @@ }, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": { "packages": { - "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, - "@metamask/utils>@scure/base": true, - "@noble/hashes": true + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/curves": true, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true, + "@metamask/utils>@scure/base": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/curves": { + "globals": { + "TextEncoder": true + }, + "packages": { + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethersproject/abi": { @@ -214,12 +227,12 @@ "@ethersproject/abi>@ethersproject/address": true, "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/abi>@ethersproject/constants": true, - "@ethersproject/abi>@ethersproject/hash": true, "@ethersproject/abi>@ethersproject/keccak256": true, "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/abi>@ethersproject/strings": true, - "@ethersproject/bignumber": true + "@ethersproject/bignumber": true, + "@ethersproject/hash": true } }, "@ethersproject/abi>@ethersproject/address": { @@ -241,18 +254,6 @@ "@ethersproject/bignumber": true } }, - "@ethersproject/abi>@ethersproject/hash": { - "packages": { - "@ethersproject/abi>@ethersproject/address": true, - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/keccak256": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/abi>@ethersproject/strings": true, - "@ethersproject/bignumber": true, - "@ethersproject/providers>@ethersproject/base64": true - } - }, "@ethersproject/abi>@ethersproject/keccak256": { "packages": { "@ethersproject/abi>@ethersproject/bytes": true, @@ -294,9 +295,36 @@ "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/bignumber": true, - "@ethersproject/hdnode>@ethersproject/abstract-signer": true, + "@ethersproject/hash>@ethersproject/abstract-signer": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@metamask/test-bundler>@ethersproject/abstract-provider": true + "@ethersproject/wallet>@ethersproject/abstract-provider": true + } + }, + "@ethersproject/hash": { + "packages": { + "@ethersproject/abi>@ethersproject/address": true, + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/keccak256": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/abi>@ethersproject/strings": true, + "@ethersproject/bignumber": true, + "@ethersproject/hash>@ethersproject/base64": true + } + }, + "@ethersproject/hash>@ethersproject/abstract-signer": { + "packages": { + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true + } + }, + "@ethersproject/hash>@ethersproject/base64": { + "globals": { + "atob": true, + "btoa": true + }, + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true } }, "@ethersproject/hdnode": { @@ -314,12 +342,6 @@ "@ethersproject/hdnode>@ethersproject/wordlists": true } }, - "@ethersproject/hdnode>@ethersproject/abstract-signer": { - "packages": { - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true - } - }, "@ethersproject/hdnode>@ethersproject/basex": { "packages": { "@ethersproject/abi>@ethersproject/bytes": true, @@ -363,10 +385,10 @@ "@ethersproject/hdnode>@ethersproject/wordlists": { "packages": { "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/hash": true, "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/abi>@ethersproject/strings": true + "@ethersproject/abi>@ethersproject/strings": true, + "@ethersproject/hash": true } }, "@ethersproject/providers": { @@ -383,39 +405,26 @@ "@ethersproject/abi>@ethersproject/address": true, "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/abi>@ethersproject/constants": true, - "@ethersproject/abi>@ethersproject/hash": true, "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/abi>@ethersproject/strings": true, "@ethersproject/bignumber": true, - "@ethersproject/hdnode>@ethersproject/abstract-signer": true, + "@ethersproject/hash": true, + "@ethersproject/hash>@ethersproject/abstract-signer": true, + "@ethersproject/hash>@ethersproject/base64": true, "@ethersproject/hdnode>@ethersproject/basex": true, "@ethersproject/hdnode>@ethersproject/sha2": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/base64": true, - "@ethersproject/providers>@ethersproject/random": true, "@ethersproject/providers>@ethersproject/web": true, "@ethersproject/providers>bech32": true, - "@metamask/test-bundler>@ethersproject/abstract-provider": true, + "@ethersproject/wallet>@ethersproject/abstract-provider": true, + "@ethersproject/wallet>@ethersproject/random": true, "@metamask/test-bundler>@ethersproject/networks": true } }, - "@ethersproject/providers>@ethersproject/base64": { - "globals": { - "atob": true, - "btoa": true - }, - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true - } - }, "@ethersproject/providers>@ethersproject/random": { "globals": { "crypto.getRandomValues": true - }, - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true } }, "@ethersproject/providers>@ethersproject/rlp": { @@ -435,7 +444,59 @@ "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/abi>@ethersproject/strings": true, - "@ethersproject/providers>@ethersproject/base64": true + "@ethersproject/hash>@ethersproject/base64": true + } + }, + "@ethersproject/wallet": { + "packages": { + "@ethersproject/abi>@ethersproject/address": true, + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/keccak256": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/hash": true, + "@ethersproject/hash>@ethersproject/abstract-signer": true, + "@ethersproject/hdnode": true, + "@ethersproject/hdnode>@ethersproject/signing-key": true, + "@ethersproject/hdnode>@ethersproject/transactions": true, + "@ethersproject/wallet>@ethersproject/abstract-provider": true, + "@ethersproject/wallet>@ethersproject/json-wallets": true, + "@ethersproject/wallet>@ethersproject/random": true + } + }, + "@ethersproject/wallet>@ethersproject/abstract-provider": { + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/bignumber": true + } + }, + "@ethersproject/wallet>@ethersproject/json-wallets": { + "packages": { + "@ethersproject/abi>@ethersproject/address": true, + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/keccak256": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/abi>@ethersproject/strings": true, + "@ethersproject/hdnode": true, + "@ethersproject/hdnode>@ethersproject/pbkdf2": true, + "@ethersproject/hdnode>@ethersproject/transactions": true, + "@ethersproject/wallet>@ethersproject/json-wallets>aes-js": true, + "@ethersproject/wallet>@ethersproject/random": true, + "ethereumjs-util>ethereum-cryptography>scrypt-js": true + } + }, + "@ethersproject/wallet>@ethersproject/json-wallets>aes-js": { + "globals": { + "define": true + } + }, + "@ethersproject/wallet>@ethersproject/random": { + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/logger": true } }, "@keystonehq/bc-ur-registry-eth": { @@ -453,9 +514,10 @@ }, "packages": { "@ngraveio/bc-ur": true, + "@trezor/connect-web>tslib": true, "browserify>buffer": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, - "mockttp>graphql-tag>tslib": true + "ganache>abstract-level>buffer": true } }, "@keystonehq/metamask-airgapped-keyring": { @@ -464,8 +526,8 @@ "@keystonehq/bc-ur-registry-eth": true, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, - "@keystonehq/metamask-airgapped-keyring>rlp": true, "browserify>buffer": true, + "ethereumjs-util>rlp": true, "uuid": true, "webpack>events": true } @@ -475,33 +537,65 @@ "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "@keystonehq/bc-ur-registry-eth": true, + "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, - "eth-lattice-keyring>rlp": true, "uuid": true } }, + "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": { + "globals": { + "TextEncoder": true + } + }, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": { "packages": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": true, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": true, - "@metamask/safe-event-emitter": true, "stream-browserify": true } }, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": { + "globals": { + "setTimeout": true + }, + "packages": { + "webpack>events": true + } + }, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": { "packages": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream": true, "browserify>process": true, "browserify>util": true, - "readable-stream": true, "watchify>xtend": true } }, - "@keystonehq/metamask-airgapped-keyring>rlp": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream": { + "packages": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>isarray": true, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": true, + "browserify>browser-resolve": true, + "browserify>process": true, + "browserify>timers-browserify": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true, + "webpack>events": true + } + }, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": { "packages": { - "bn.js": true, "browserify>buffer": true } }, + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": { + "packages": { + "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true + } + }, "@lavamoat/lavadome-react": { "globals": { "Document.prototype": true, @@ -701,6 +795,7 @@ }, "@metamask-institutional/custody-keyring": { "globals": { + "console.error": true, "console.log": true, "console.warn": true }, @@ -728,7 +823,8 @@ "packages": { "@metamask-institutional/custody-controller": true, "@metamask-institutional/sdk": true, - "@metamask-institutional/sdk>@metamask-institutional/types": true + "@metamask-institutional/sdk>@metamask-institutional/types": true, + "gulp-sass>lodash.clonedeep": true } }, "@metamask-institutional/institutional-features": { @@ -737,67 +833,25 @@ "@metamask/obs-store": true } }, - "@metamask-institutional/portfolio-dashboard": { + "@metamask-institutional/rpc-allowlist": { "globals": { - "console.log": true, - "fetch": true + "URL": true } }, "@metamask-institutional/sdk": { "globals": { "URLSearchParams": true, "console.debug": true, + "console.error": true, "console.log": true, - "console.warn": true, "fetch": true }, "packages": { "@metamask-institutional/sdk>@metamask-institutional/simplecache": true, - "@metamask-institutional/sdk>jsonwebtoken": true, "browserify>crypto-browserify": true, "webpack>events": true } }, - "@metamask-institutional/sdk>jsonwebtoken": { - "packages": { - "@metamask-institutional/sdk>jsonwebtoken>jws": true, - "browserify>buffer": true, - "browserify>crypto-browserify": true, - "browserify>process": true, - "lodash": true, - "mocha>ms": true, - "semver": true - } - }, - "@metamask-institutional/sdk>jsonwebtoken>jws": { - "packages": { - "@metamask-institutional/sdk>jsonwebtoken>jws>jwa": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>util": true, - "koa>content-disposition>safe-buffer": true, - "stream-browserify": true - } - }, - "@metamask-institutional/sdk>jsonwebtoken>jws>jwa": { - "packages": { - "@metamask-institutional/sdk>jsonwebtoken>jws>jwa>buffer-equal-constant-time": true, - "@metamask-institutional/sdk>jsonwebtoken>jws>jwa>ecdsa-sig-formatter": true, - "browserify>crypto-browserify": true, - "browserify>util": true, - "koa>content-disposition>safe-buffer": true - } - }, - "@metamask-institutional/sdk>jsonwebtoken>jws>jwa>buffer-equal-constant-time": { - "packages": { - "browserify>buffer": true - } - }, - "@metamask-institutional/sdk>jsonwebtoken>jws>jwa>ecdsa-sig-formatter": { - "packages": { - "koa>content-disposition>safe-buffer": true - } - }, "@metamask-institutional/transaction-update": { "globals": { "clearInterval": true, @@ -806,10 +860,10 @@ "setInterval": true }, "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, "@metamask-institutional/sdk": true, "@metamask-institutional/transaction-update>@metamask-institutional/websocket-client": true, "@metamask/obs-store": true, - "ethereumjs-util": true, "webpack>events": true } }, @@ -834,25 +888,43 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/base-controller": true, + "@metamask/accounts-controller>@metamask/base-controller": true, + "@metamask/accounts-controller>@metamask/keyring-api": true, "@metamask/eth-snap-keyring": true, - "@metamask/keyring-api": true, "@metamask/keyring-controller": true, + "@metamask/snaps-utils": true, + "@metamask/utils": true, "uuid": true } }, - "@metamask/address-book-controller": { + "@metamask/accounts-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, "packages": { - "@metamask/address-book-controller>@metamask/base-controller": true, - "@metamask/address-book-controller>@metamask/controller-utils": true + "immer": true } }, - "@metamask/address-book-controller>@metamask/base-controller": { + "@metamask/accounts-controller>@metamask/keyring-api": { "globals": { - "setTimeout": true + "URL": true }, "packages": { - "immer": true + "@metamask/accounts-controller>@metamask/keyring-api>uuid": true, + "@metamask/keyring-api>bech32": true, + "@metamask/utils": true, + "superstruct": true + } + }, + "@metamask/accounts-controller>@metamask/keyring-api>uuid": { + "globals": { + "crypto": true + } + }, + "@metamask/address-book-controller": { + "packages": { + "@metamask/address-book-controller>@metamask/controller-utils": true, + "@metamask/base-controller": true } }, "@metamask/address-book-controller>@metamask/controller-utils": { @@ -863,32 +935,14 @@ "setTimeout": true }, "packages": { - "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": true, - "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, + "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true - } - }, - "@metamask/address-book-controller>@metamask/controller-utils>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, - "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": { - "packages": { - "@metamask/ethjs>ethjs-abi>number-to-bn": true, - "bn.js": true + "eth-ens-namehash": true } }, "@metamask/announcement-controller": { @@ -897,6 +951,9 @@ } }, "@metamask/announcement-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, "packages": { "immer": true } @@ -906,9 +963,17 @@ "console.info": true }, "packages": { + "@metamask/approval-controller>@metamask/base-controller": true, "@metamask/approval-controller>nanoid": true, - "@metamask/base-controller": true, - "@metamask/providers>@metamask/rpc-errors": true + "@metamask/rpc-errors": true + } + }, + "@metamask/approval-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true } }, "@metamask/approval-controller>nanoid": { @@ -921,6 +986,7 @@ "AbortController": true, "Headers": true, "URL": true, + "URLSearchParams": true, "clearInterval": true, "clearTimeout": true, "console.error": true, @@ -935,6 +1001,7 @@ "@ethersproject/providers": true, "@metamask/abi-utils": true, "@metamask/assets-controllers>@metamask/polling-controller": true, + "@metamask/assets-controllers>async-mutex": true, "@metamask/assets-controllers>cockatiel": true, "@metamask/assets-controllers>multiformats": true, "@metamask/base-controller": true, @@ -942,8 +1009,7 @@ "@metamask/controller-utils": true, "@metamask/eth-query": true, "@metamask/metamask-eth-abis": true, - "@metamask/name-controller>async-mutex": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/utils": true, "bn.js": true, "lodash": true, @@ -964,9 +1030,17 @@ "uuid": true } }, - "@metamask/assets-controllers>cockatiel": { + "@metamask/assets-controllers>async-mutex": { "globals": { - "AbortController": true, + "setTimeout": true + }, + "packages": { + "@trezor/connect-web>tslib": true + } + }, + "@metamask/assets-controllers>cockatiel": { + "globals": { + "AbortController": true, "AbortSignal": true, "WeakRef": true, "clearTimeout": true, @@ -1033,7 +1107,8 @@ "console.log": true }, "packages": { - "@metamask/controller-utils>@spruceid/siwe-parser>apg-js": true + "@metamask/controller-utils>@spruceid/siwe-parser>apg-js": true, + "@noble/hashes": true } }, "@metamask/controller-utils>@spruceid/siwe-parser>apg-js": { @@ -1064,21 +1139,38 @@ "packages": { "@ethersproject/providers": true, "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@metamask/ens-controller>@metamask/controller-utils": true, "@metamask/utils": true, - "ethereum-ens-network-map": true, "punycode": true } }, + "@metamask/ens-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/eth-json-rpc-filters": { "globals": { "console.error": true }, "packages": { "@metamask/eth-json-rpc-filters>@metamask/eth-query": true, - "@metamask/eth-json-rpc-filters>@metamask/safe-event-emitter": true, - "@metamask/name-controller>async-mutex": true, - "@metamask/providers>@metamask/json-rpc-engine": true, + "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine": true, + "@metamask/eth-json-rpc-filters>async-mutex": true, + "@metamask/safe-event-emitter": true, "pify": true } }, @@ -1088,12 +1180,19 @@ "watchify>xtend": true } }, - "@metamask/eth-json-rpc-filters>@metamask/safe-event-emitter": { + "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine": { + "packages": { + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true + } + }, + "@metamask/eth-json-rpc-filters>async-mutex": { "globals": { "setTimeout": true }, "packages": { - "webpack>events": true + "@trezor/connect-web>tslib": true } }, "@metamask/eth-json-rpc-middleware": { @@ -1103,52 +1202,33 @@ "setTimeout": true }, "packages": { + "@metamask/eth-json-rpc-middleware>@metamask/json-rpc-engine": true, "@metamask/eth-json-rpc-middleware>safe-stable-stringify": true, "@metamask/eth-sig-util": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/utils": true, "pify": true, "sass-loader>klona": true } }, - "@metamask/eth-keyring-controller": { - "globals": { - "console.error": true - }, - "packages": { - "@metamask/browser-passworder": true, - "@metamask/eth-keyring-controller>@metamask/obs-store": true, - "@metamask/eth-sig-util": true, - "@metamask/keyring-controller>@metamask/eth-hd-keyring": true, - "@metamask/keyring-controller>@metamask/eth-simple-keyring": true, - "@metamask/utils": true, - "webpack>events": true - } - }, - "@metamask/eth-keyring-controller>@metamask/obs-store": { + "@metamask/eth-json-rpc-middleware>@metamask/eth-json-rpc-provider": { "packages": { - "@metamask/eth-keyring-controller>@metamask/obs-store>@metamask/safe-event-emitter": true, - "@metamask/eth-keyring-controller>@metamask/obs-store>readable-stream": true + "@metamask/eth-json-rpc-middleware>@metamask/eth-json-rpc-provider>@metamask/json-rpc-engine": true, + "@metamask/safe-event-emitter": true } }, - "@metamask/eth-keyring-controller>@metamask/obs-store>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, + "@metamask/eth-json-rpc-middleware>@metamask/eth-json-rpc-provider>@metamask/json-rpc-engine": { "packages": { - "webpack>events": true + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true } }, - "@metamask/eth-keyring-controller>@metamask/obs-store>readable-stream": { + "@metamask/eth-json-rpc-middleware>@metamask/json-rpc-engine": { "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true } }, "@metamask/eth-ledger-bridge-keyring": { @@ -1208,25 +1288,19 @@ }, "@metamask/eth-snap-keyring": { "globals": { + "URL": true, "console.error": true }, "packages": { "@ethereumjs/tx": true, "@metamask/eth-sig-util": true, - "@metamask/eth-snap-keyring>@metamask/keyring-api": true, "@metamask/eth-snap-keyring>uuid": true, + "@metamask/keyring-api": true, "@metamask/utils": true, "superstruct": true, "webpack>events": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-api": { - "packages": { - "@metamask/eth-snap-keyring>uuid": true, - "@metamask/utils": true, - "superstruct": true - } - }, "@metamask/eth-snap-keyring>uuid": { "globals": { "crypto": true @@ -1238,21 +1312,26 @@ }, "packages": { "@babel/runtime": true, - "@metamask/eth-token-tracker>@metamask/safe-event-emitter": true, + "@metamask/eth-token-tracker>@metamask/eth-block-tracker": true, "@metamask/eth-token-tracker>deep-equal": true, - "@metamask/eth-token-tracker>eth-block-tracker": true, "@metamask/ethjs-contract": true, "@metamask/ethjs-query": true, + "@metamask/safe-event-emitter": true, "bn.js": true, "human-standard-token-abi": true } }, - "@metamask/eth-token-tracker>@metamask/safe-event-emitter": { + "@metamask/eth-token-tracker>@metamask/eth-block-tracker": { "globals": { + "clearTimeout": true, + "console.error": true, "setTimeout": true }, "packages": { - "webpack>events": true + "@metamask/eth-query>json-rpc-random-id": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true, + "pify": true } }, "@metamask/eth-token-tracker>deep-equal": { @@ -1343,27 +1422,6 @@ "string.prototype.matchall>get-intrinsic": true } }, - "@metamask/eth-token-tracker>eth-block-tracker": { - "globals": { - "clearTimeout": true, - "console.error": true, - "setTimeout": true - }, - "packages": { - "@metamask/eth-query>json-rpc-random-id": true, - "@metamask/eth-token-tracker>eth-block-tracker>@metamask/safe-event-emitter": true, - "@metamask/utils": true, - "pify": true - } - }, - "@metamask/eth-token-tracker>eth-block-tracker>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, "@metamask/eth-trezor-keyring": { "globals": { "setTimeout": true @@ -1372,15 +1430,47 @@ "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": true, + "@metamask/eth-trezor-keyring>@trezor/connect-web": true, "@metamask/eth-trezor-keyring>hdkey": true, - "@trezor/connect-web": true, "browserify>buffer": true, "webpack>events": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": { "packages": { - "@metamask/eth-sig-util": true + "@metamask/eth-sig-util": true, + "@trezor/connect-web>tslib": true + } + }, + "@metamask/eth-trezor-keyring>@trezor/connect-web": { + "globals": { + "URLSearchParams": true, + "__TREZOR_CONNECT_SRC": true, + "addEventListener": true, + "btoa": true, + "chrome": true, + "clearInterval": true, + "clearTimeout": true, + "console.warn": true, + "document.body": true, + "document.createElement": true, + "document.createTextNode": true, + "document.getElementById": true, + "document.querySelectorAll": true, + "location": true, + "navigator": true, + "open": true, + "origin": true, + "removeEventListener": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@trezor/connect-web>@trezor/connect": true, + "@trezor/connect-web>@trezor/connect-common": true, + "@trezor/connect-web>@trezor/utils": true, + "@trezor/connect-web>tslib": true, + "webpack>events": true } }, "@metamask/eth-trezor-keyring>hdkey": { @@ -1520,13 +1610,30 @@ }, "packages": { "@metamask/assets-controllers>@metamask/polling-controller": true, - "@metamask/controller-utils": true, "@metamask/eth-query": true, - "@metamask/ethjs>@metamask/ethjs-unit": true, - "ethereumjs-util": true, + "@metamask/gas-fee-controller>@metamask/controller-utils": true, + "bn.js": true, "uuid": true } }, + "@metamask/gas-fee-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/jazzicon": { "globals": { "document.createElement": true, @@ -1560,7 +1667,11 @@ } }, "@metamask/keyring-api": { + "globals": { + "URL": true + }, "packages": { + "@metamask/keyring-api>bech32": true, "@metamask/keyring-api>uuid": true, "@metamask/utils": true, "superstruct": true @@ -1637,18 +1748,12 @@ "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>create-hash": true - } - }, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": { - "packages": { - "bn.js": true, - "browserify>buffer": true + "ethereumjs-util>create-hash": true, + "ethereumjs-util>rlp": true } }, "@metamask/logging-controller": { @@ -1673,9 +1778,9 @@ }, "@metamask/message-manager": { "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, "@metamask/eth-sig-util": true, + "@metamask/message-manager>@metamask/base-controller": true, + "@metamask/message-manager>@metamask/controller-utils": true, "@metamask/message-manager>jsonschema": true, "@metamask/utils": true, "browserify>buffer": true, @@ -1683,27 +1788,89 @@ "webpack>events": true } }, + "@metamask/message-manager>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/message-manager>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true } }, + "@metamask/message-signing-snap>@noble/curves": { + "globals": { + "TextEncoder": true + }, + "packages": { + "@noble/hashes": true + } + }, "@metamask/name-controller": { "globals": { "fetch": true }, "packages": { - "@metamask/base-controller": true, + "@metamask/name-controller>@metamask/base-controller": true, + "@metamask/name-controller>@metamask/controller-utils": true, "@metamask/name-controller>async-mutex": true, "@metamask/utils": true } }, + "@metamask/name-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/name-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/name-controller>async-mutex": { "globals": { + "clearTimeout": true, "setTimeout": true }, "packages": { - "mockttp>graphql-tag>tslib": true + "@trezor/connect-web>tslib": true } }, "@metamask/network-controller": { @@ -1714,45 +1881,70 @@ "setTimeout": true }, "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, "@metamask/eth-json-rpc-middleware": true, "@metamask/eth-query": true, - "@metamask/eth-token-tracker>eth-block-tracker": true, + "@metamask/eth-token-tracker>@metamask/eth-block-tracker": true, + "@metamask/network-controller>@metamask/base-controller": true, + "@metamask/network-controller>@metamask/controller-utils": true, "@metamask/network-controller>@metamask/eth-json-rpc-infura": true, "@metamask/network-controller>@metamask/eth-json-rpc-provider": true, "@metamask/network-controller>@metamask/swappable-obj-proxy": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true, "@metamask/utils": true, "browserify>assert": true, "uuid": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-infura": { + "@metamask/network-controller>@metamask/base-controller": { "globals": { "setTimeout": true }, "packages": { - "@metamask/network-controller>@metamask/eth-json-rpc-provider": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/utils": true, - "node-fetch": true + "immer": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-provider": { + "@metamask/network-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, "packages": { - "@metamask/network-controller>@metamask/eth-json-rpc-provider>@metamask/safe-event-emitter": true, - "@metamask/providers>@metamask/json-rpc-engine": true + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-provider>@metamask/safe-event-emitter": { + "@metamask/network-controller>@metamask/eth-json-rpc-infura": { "globals": { "setTimeout": true }, "packages": { - "webpack>events": true + "@metamask/eth-json-rpc-middleware>@metamask/eth-json-rpc-provider": true, + "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/json-rpc-engine": true, + "@metamask/rpc-errors": true, + "@metamask/utils": true, + "node-fetch": true + } + }, + "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/json-rpc-engine": { + "packages": { + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true + } + }, + "@metamask/network-controller>@metamask/eth-json-rpc-provider": { + "packages": { + "@metamask/safe-event-emitter": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true } }, "@metamask/notification-controller": { @@ -1787,19 +1979,24 @@ "crypto.getRandomValues": true } }, - "@metamask/obs-store": { + "@metamask/object-multiplex": { + "globals": { + "console.warn": true + }, "packages": { - "@metamask/obs-store>through2": true, - "@metamask/safe-event-emitter": true, - "stream-browserify": true + "@metamask/object-multiplex>once": true, + "readable-stream": true } }, - "@metamask/obs-store>through2": { + "@metamask/object-multiplex>once": { "packages": { - "browserify>process": true, - "browserify>util": true, - "readable-stream": true, - "watchify>xtend": true + "@metamask/object-multiplex>once>wrappy": true + } + }, + "@metamask/obs-store": { + "packages": { + "@metamask/safe-event-emitter": true, + "readable-stream": true } }, "@metamask/permission-controller": { @@ -1807,16 +2004,42 @@ "console.error": true }, "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/base-controller": true, + "@metamask/permission-controller>@metamask/controller-utils": true, "@metamask/permission-controller>nanoid": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true, "@metamask/utils": true, "deep-freeze-strict": true, "immer": true } }, + "@metamask/permission-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/permission-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/permission-controller>nanoid": { "globals": { "crypto.getRandomValues": true @@ -1856,19 +2079,60 @@ "removeEventListener": true }, "packages": { - "@metamask/post-message-stream>readable-stream": true, - "@metamask/utils": true + "@metamask/utils": true, + "readable-stream": true } }, - "@metamask/post-message-stream>readable-stream": { + "@metamask/ppom-validator": { + "globals": { + "URL": true, + "console.error": true, + "crypto": true + }, "packages": { - "browserify>browser-resolve": true, + "@metamask/eth-query>json-rpc-random-id": true, + "@metamask/ppom-validator>@metamask/base-controller": true, + "@metamask/ppom-validator>@metamask/controller-utils": true, + "@metamask/ppom-validator>crypto-js": true, + "@metamask/ppom-validator>elliptic": true, + "await-semaphore": true, + "browserify>buffer": true + } + }, + "@metamask/ppom-validator>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/ppom-validator>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/ppom-validator>crypto-js": { + "globals": { + "crypto": true, + "define": true, + "msCrypto": true + }, + "packages": { + "browserify>browser-resolve": true } }, "@metamask/ppom-validator>elliptic": { @@ -1898,54 +2162,21 @@ "ethereumjs-util>ethereum-cryptography>hash.js": true } }, - "@metamask/providers>@metamask/json-rpc-engine": { + "@metamask/queued-request-controller": { "packages": { - "@metamask/providers>@metamask/json-rpc-engine>@metamask/safe-event-emitter": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/queued-request-controller>@metamask/base-controller": true, + "@metamask/rpc-errors": true, + "@metamask/selected-network-controller": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true, "@metamask/utils": true } }, - "@metamask/providers>@metamask/json-rpc-engine>@metamask/safe-event-emitter": { + "@metamask/queued-request-controller>@metamask/base-controller": { "globals": { "setTimeout": true }, "packages": { - "webpack>events": true - } - }, - "@metamask/providers>@metamask/object-multiplex": { - "globals": { - "console.warn": true - }, - "packages": { - "@metamask/providers>@metamask/object-multiplex>readable-stream": true, - "pump>once": true - } - }, - "@metamask/providers>@metamask/object-multiplex>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "@metamask/providers>@metamask/rpc-errors": { - "packages": { - "@metamask/utils": true, - "eth-rpc-errors>fast-safe-stringify": true - } - }, - "@metamask/queued-request-controller": { - "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/selected-network-controller": true + "immer": true } }, "@metamask/rate-limit-controller": { @@ -1953,16 +2184,15 @@ "setTimeout": true }, "packages": { - "@metamask/rate-limit-controller>@metamask/base-controller": true, - "eth-rpc-errors": true + "@metamask/base-controller": true, + "@metamask/rpc-errors": true, + "@metamask/utils": true } }, - "@metamask/rate-limit-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, + "@metamask/rpc-errors": { "packages": { - "immer": true + "@metamask/utils": true, + "eth-rpc-errors>fast-safe-stringify": true } }, "@metamask/rpc-methods-flask>nanoid": { @@ -2000,8 +2230,16 @@ }, "@metamask/selected-network-controller": { "packages": { - "@metamask/base-controller": true, - "@metamask/network-controller>@metamask/swappable-obj-proxy": true + "@metamask/network-controller>@metamask/swappable-obj-proxy": true, + "@metamask/selected-network-controller>@metamask/base-controller": true + } + }, + "@metamask/selected-network-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true } }, "@metamask/signature-controller": { @@ -2010,16 +2248,46 @@ }, "packages": { "@metamask/base-controller": true, - "@metamask/controller-utils": true, "@metamask/logging-controller": true, - "@metamask/message-manager": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, + "@metamask/signature-controller>@metamask/controller-utils": true, + "@metamask/signature-controller>@metamask/message-manager": true, + "@metamask/utils": true, "browserify>buffer": true, - "ethereumjs-util": true, "lodash": true, "webpack>events": true } }, + "@metamask/signature-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/signature-controller>@metamask/message-manager": { + "packages": { + "@metamask/base-controller": true, + "@metamask/eth-sig-util": true, + "@metamask/message-manager>jsonschema": true, + "@metamask/signature-controller>@metamask/controller-utils": true, + "@metamask/utils": true, + "browserify>buffer": true, + "uuid": true, + "webpack>events": true + } + }, "@metamask/smart-transactions-controller": { "globals": { "URLSearchParams": true, @@ -2031,16 +2299,193 @@ }, "packages": { "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/bignumber": true, - "@ethersproject/providers": true, - "@metamask/smart-transactions-controller>@metamask/base-controller": true, + "@metamask/assets-controllers>@metamask/polling-controller": true, + "@metamask/eth-query": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx": true, + "@metamask/smart-transactions-controller>@ethereumjs/util": true, "@metamask/smart-transactions-controller>@metamask/controller-utils": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller": true, "@metamask/smart-transactions-controller>bignumber.js": true, + "browserify>buffer": true, "fast-json-patch": true, - "lodash": true + "lodash": true, + "webpack>events": true } }, - "@metamask/smart-transactions-controller>@metamask/base-controller": { + "@metamask/smart-transactions-controller>@babel/runtime": { + "globals": { + "regeneratorRuntime": "write" + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx": { + "packages": { + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": true, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": true, + "@metamask/smart-transactions-controller>@ethereumjs/util": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": { + "packages": { + "@metamask/smart-transactions-controller>@ethereumjs/util": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/util": { + "globals": { + "console.warn": true, + "fetch": true + }, + "packages": { + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@ethereumjs/util>@ethereumjs/rlp": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@ethereumjs/util>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, + "@metamask/smart-transactions-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/smart-transactions-controller>@metamask/controller-utils>@ethereumjs/util": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/smart-transactions-controller>@metamask/controller-utils>@ethereumjs/util": { + "globals": { + "console.warn": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@metamask/controllers>nanoid": { + "globals": { + "crypto.getRandomValues": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller": { + "globals": { + "clearTimeout": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/common": true, + "@ethersproject/abi": true, + "@ethersproject/contracts": true, + "@ethersproject/providers": true, + "@metamask/eth-query": true, + "@metamask/metamask-eth-abis": true, + "@metamask/name-controller>async-mutex": true, + "@metamask/network-controller": true, + "@metamask/rpc-errors": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/base-controller": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/controller-utils": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry": true, + "@metamask/transaction-controller>@metamask/nonce-tracker": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "fast-json-patch": true, + "lodash": true, + "uuid": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx": { + "packages": { + "@ethereumjs/tx>@ethereumjs/common": true, + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": { + "globals": { + "console.warn": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller": { + "globals": { + "clearInterval": true, + "console.error": true, + "setInterval": true + }, + "packages": { + "@metamask/eth-query": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/controller-utils": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/polling-controller": true, + "bn.js": true, + "browserify>buffer": true, + "uuid": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/base-controller": { "globals": { "setTimeout": true }, @@ -2048,26 +2493,99 @@ "immer": true } }, - "@metamask/smart-transactions-controller>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/controller-utils>@ethereumjs/util": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/controller-utils>@ethereumjs/util": { + "globals": { + "console.warn": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "webpack>events": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/polling-controller": { + "globals": { + "clearTimeout": true, + "console.error": true, + "setTimeout": true + }, + "packages": { + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@metamask/gas-fee-controller>@metamask/base-controller": true, + "@metamask/snaps-utils>fast-json-stable-stringify": true, + "uuid": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry": { + "packages": { + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract": { + "packages": { + "@metamask/ethjs>ethjs-abi": true, + "@metamask/ethjs>js-sha3": true, + "@metamask/smart-transactions-controller>@babel/runtime": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-filter": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-util": true, + "promise-to-callback": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-filter": { + "globals": { + "clearInterval": true, + "setInterval": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-util": { + "packages": { + "@metamask/ethjs>@metamask/ethjs-util>is-hex-prefixed": true, + "@metamask/ethjs>@metamask/ethjs-util>strip-hex-prefix": true, + "browserify>buffer": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query>@metamask/ethjs-format": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query>@metamask/ethjs-rpc": true, + "promise-to-callback": true + } + }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query>@metamask/ethjs-format": { "packages": { - "@metamask/address-book-controller>@metamask/controller-utils>ethjs-unit": true, - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/utils": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true + "@metamask/ethjs-query>@metamask/ethjs-format>ethjs-schema": true, + "@metamask/ethjs>@metamask/ethjs-util>strip-hex-prefix": true, + "@metamask/ethjs>@metamask/number-to-bn": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-contract>@metamask/ethjs-util": true } }, - "@metamask/smart-transactions-controller>@metamask/controllers>nanoid": { - "globals": { - "crypto.getRandomValues": true + "@metamask/smart-transactions-controller>@metamask/transaction-controller>eth-method-registry>@metamask/ethjs-query>@metamask/ethjs-rpc": { + "packages": { + "promise-to-callback": true } }, "@metamask/smart-transactions-controller>bignumber.js": { @@ -2080,25 +2598,23 @@ "globals": { "DecompressionStream": true, "URL": true, - "chrome.offscreen.createDocument": true, - "chrome.offscreen.hasDocument": true, "clearTimeout": true, "document.getElementById": true, "fetch.bind": true, "setTimeout": true }, "packages": { - "@metamask/base-controller": true, + "@metamask/object-multiplex": true, "@metamask/permission-controller": true, "@metamask/post-message-stream": true, - "@metamask/providers>@metamask/json-rpc-engine": true, - "@metamask/providers>@metamask/object-multiplex": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, + "@metamask/snaps-controllers>@metamask/base-controller": true, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": true, + "@metamask/snaps-controllers>@metamask/json-rpc-middleware-stream": true, "@metamask/snaps-controllers>@xstate/fsm": true, "@metamask/snaps-controllers>concat-stream": true, "@metamask/snaps-controllers>get-npm-tarball-url": true, "@metamask/snaps-controllers>nanoid": true, - "@metamask/snaps-controllers>readable-stream": true, "@metamask/snaps-controllers>readable-web-to-node-stream": true, "@metamask/snaps-controllers>tar-stream": true, "@metamask/snaps-rpc-methods": true, @@ -2107,7 +2623,8 @@ "@metamask/snaps-utils>@metamask/snaps-registry": true, "@metamask/utils": true, "browserify>browserify-zlib": true, - "json-rpc-middleware-stream": true + "eslint>fast-deep-equal": true, + "readable-stream": true } }, "@metamask/snaps-controllers-flask>nanoid": { @@ -2115,12 +2632,37 @@ "crypto.getRandomValues": true } }, + "@metamask/snaps-controllers>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/snaps-controllers>@metamask/json-rpc-engine": { + "packages": { + "@metamask/rpc-errors": true, + "@metamask/safe-event-emitter": true, + "@metamask/utils": true + } + }, + "@metamask/snaps-controllers>@metamask/json-rpc-middleware-stream": { + "globals": { + "console.warn": true, + "setTimeout": true + }, + "packages": { + "@metamask/safe-event-emitter": true, + "readable-stream": true + } + }, "@metamask/snaps-controllers>concat-stream": { "packages": { - "@metamask/snaps-controllers>readable-stream": true, "browserify>buffer": true, "browserify>concat-stream>typedarray": true, "pumpify>inherits": true, + "readable-stream": true, "terser>source-map-support>buffer-from": true } }, @@ -2129,31 +2671,9 @@ "crypto.getRandomValues": true } }, - "@metamask/snaps-controllers>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, "@metamask/snaps-controllers>readable-web-to-node-stream": { "packages": { - "@metamask/snaps-controllers>readable-web-to-node-stream>readable-stream": true - } - }, - "@metamask/snaps-controllers>readable-web-to-node-stream>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "readable-stream": true } }, "@metamask/snaps-controllers>tar-stream": { @@ -2182,10 +2702,20 @@ "queueMicrotask": true } }, + "@metamask/snaps-execution-environments": { + "globals": { + "document.getElementById": true + }, + "packages": { + "@metamask/post-message-stream": true, + "@metamask/snaps-utils": true, + "@metamask/utils": true + } + }, "@metamask/snaps-rpc-methods": { "packages": { "@metamask/permission-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/snaps-sdk": true, "@metamask/snaps-sdk>@metamask/key-tree": true, "@metamask/snaps-utils": true, @@ -2199,50 +2729,18 @@ "fetch": true }, "packages": { - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/snaps-sdk>fast-xml-parser": true, + "@metamask/rpc-errors": true, "@metamask/utils": true, "superstruct": true } }, "@metamask/snaps-sdk>@metamask/key-tree": { "packages": { + "@metamask/message-signing-snap>@noble/curves": true, "@metamask/scure-bip39": true, - "@metamask/snaps-sdk>@metamask/key-tree>@metamask/utils": true, - "@metamask/snaps-sdk>@metamask/key-tree>@noble/ed25519": true, + "@metamask/utils": true, "@metamask/utils>@scure/base": true, - "@noble/hashes": true, - "eth-lattice-keyring>@noble/secp256k1": true - } - }, - "@metamask/snaps-sdk>@metamask/key-tree>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, - "@metamask/snaps-sdk>@metamask/key-tree>@noble/ed25519": { - "globals": { - "crypto": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "@metamask/snaps-sdk>fast-xml-parser": { - "globals": { - "entityName": true, - "val": true - }, - "packages": { - "@metamask/snaps-sdk>fast-xml-parser>strnum": true + "@noble/hashes": true } }, "@metamask/snaps-utils": { @@ -2250,6 +2748,7 @@ "File": true, "FileReader": true, "TextDecoder": true, + "TextEncoder": true, "URL": true, "console.error": true, "console.log": true, @@ -2261,12 +2760,13 @@ }, "packages": { "@metamask/permission-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/snaps-sdk": true, "@metamask/snaps-sdk>@metamask/key-tree": true, "@metamask/snaps-utils>@metamask/slip44": true, "@metamask/snaps-utils>cron-parser": true, "@metamask/snaps-utils>fast-json-stable-stringify": true, + "@metamask/snaps-utils>fast-xml-parser": true, "@metamask/snaps-utils>marked": true, "@metamask/snaps-utils>rfdc": true, "@metamask/snaps-utils>validate-npm-package-name": true, @@ -2280,46 +2780,32 @@ }, "@metamask/snaps-utils>@metamask/snaps-registry": { "packages": { - "@metamask/snaps-utils>@metamask/snaps-registry>@noble/curves": true, + "@metamask/message-signing-snap>@noble/curves": true, "@metamask/utils": true, "@noble/hashes": true, "superstruct": true } }, - "@metamask/snaps-utils>@metamask/snaps-registry>@noble/curves": { - "globals": { - "TextEncoder": true - }, - "packages": { - "@noble/hashes": true - } - }, "@metamask/snaps-utils>cron-parser": { "packages": { "browserify>browser-resolve": true, "luxon": true } }, + "@metamask/snaps-utils>fast-xml-parser": { + "globals": { + "entityName": true, + "val": true + }, + "packages": { + "@metamask/snaps-utils>fast-xml-parser>strnum": true + } + }, "@metamask/snaps-utils>marked": { "globals": { - "Hooks": true, - "Lexer": true, - "Parser": true, - "Renderer": true, - "TextRenderer": true, - "Tokenizer": true, "console.error": true, "console.warn": true, - "defaults": true, - "define": true, - "inlineQueue": true, - "passThroughHooks": true, - "renderer": true, - "rules": true, - "state": true, - "textRenderer": true, - "tokenizer": true, - "tokens": true + "define": true } }, "@metamask/snaps-utils>rfdc": { @@ -2338,14 +2824,6 @@ "semver": true } }, - "@metamask/test-bundler>@ethersproject/abstract-provider": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/bignumber": true - } - }, "@metamask/test-bundler>@ethersproject/networks": { "packages": { "@ethersproject/abi>@ethersproject/logger": true @@ -2355,24 +2833,28 @@ "globals": { "clearTimeout": true, "console.error": true, + "fetch": true, "setTimeout": true }, "packages": { - "@ethereumjs/common": true, "@ethereumjs/tx": true, + "@ethereumjs/tx>@ethereumjs/common": true, "@ethereumjs/tx>@ethereumjs/util": true, "@ethersproject/abi": true, - "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@ethersproject/contracts": true, + "@ethersproject/providers": true, "@metamask/eth-query": true, "@metamask/gas-fee-controller": true, "@metamask/metamask-eth-abis": true, "@metamask/name-controller>async-mutex": true, "@metamask/network-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, - "@metamask/transaction-controller>nonce-tracker": true, + "@metamask/rpc-errors": true, + "@metamask/transaction-controller>@metamask/base-controller": true, + "@metamask/transaction-controller>@metamask/controller-utils": true, + "@metamask/transaction-controller>@metamask/nonce-tracker": true, "@metamask/utils": true, "bn.js": true, + "browserify>buffer": true, "eth-method-registry": true, "fast-json-patch": true, "lodash": true, @@ -2380,21 +2862,46 @@ "webpack>events": true } }, - "@metamask/transaction-controller>nonce-tracker": { + "@metamask/transaction-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/transaction-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, + "@metamask/transaction-controller>@metamask/nonce-tracker": { "packages": { "@ethersproject/providers": true, - "@metamask/eth-token-tracker>eth-block-tracker": true, - "@metamask/transaction-controller>nonce-tracker>async-mutex": true, + "@metamask/transaction-controller>@metamask/nonce-tracker>async-mutex": true, "browserify>assert": true } }, - "@metamask/transaction-controller>nonce-tracker>async-mutex": { + "@metamask/transaction-controller>@metamask/nonce-tracker>async-mutex": { "globals": { "clearTimeout": true, "setTimeout": true }, "packages": { - "mockttp>graphql-tag>tslib": true + "@trezor/connect-web>tslib": true } }, "@metamask/user-operation-controller": { @@ -2404,19 +2911,37 @@ "packages": { "@metamask/assets-controllers>@metamask/polling-controller": true, "@metamask/base-controller": true, - "@metamask/controller-utils": true, "@metamask/eth-query": true, "@metamask/gas-fee-controller": true, - "@metamask/providers>@metamask/rpc-errors": true, + "@metamask/rpc-errors": true, "@metamask/transaction-controller": true, + "@metamask/user-operation-controller>@metamask/controller-utils": true, "@metamask/utils": true, - "ethereumjs-util": true, + "bn.js": true, "lodash": true, "superstruct": true, "uuid": true, "webpack>events": true } }, + "@metamask/user-operation-controller>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/ethjs>@metamask/ethjs-unit": true, + "@metamask/utils": true, + "bn.js": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true + } + }, "@metamask/utils": { "globals": { "TextDecoder": true, @@ -2440,7 +2965,7 @@ }, "@ngraveio/bc-ur": { "packages": { - "@ngraveio/bc-ur>@apocentre/alias-sampling": true, + "@ngraveio/bc-ur>@keystonehq/alias-sampling": true, "@ngraveio/bc-ur>bignumber.js": true, "@ngraveio/bc-ur>cbor-sync": true, "@ngraveio/bc-ur>crc": true, @@ -2480,6 +3005,13 @@ "define": true } }, + "@noble/ciphers": { + "globals": { + "TextDecoder": true, + "TextEncoder": true, + "crypto": true + } + }, "@noble/hashes": { "globals": { "TextEncoder": true, @@ -2502,12 +3034,14 @@ "AbortController": true, "__REDUX_DEVTOOLS_EXTENSION_COMPOSE__": true, "__REDUX_DEVTOOLS_EXTENSION__": true, - "console.error": true, - "console.info": true, - "console.warn": true + "console": true, + "queueMicrotask": true, + "requestAnimationFrame": true, + "setTimeout": true }, "packages": { "@reduxjs/toolkit>reselect": true, + "browserify>process": true, "immer": true, "redux": true, "redux-thunk": true @@ -2664,6 +3198,7 @@ }, "@trezor/connect-web": { "globals": { + "URLSearchParams": true, "__TREZOR_CONNECT_SRC": true, "addEventListener": true, "btoa": true, @@ -2679,42 +3214,105 @@ "location": true, "navigator": true, "open": true, + "origin": true, "removeEventListener": true, "setInterval": true, "setTimeout": true }, "packages": { "@trezor/connect-web>@trezor/connect": true, + "@trezor/connect-web>@trezor/connect-common": true, "@trezor/connect-web>@trezor/utils": true, - "mockttp>graphql-tag>tslib": true, + "@trezor/connect-web>tslib": true, "webpack>events": true } }, "@trezor/connect-web>@trezor/connect": { + "packages": { + "@trezor/connect-web>@trezor/connect>@trezor/protobuf": true, + "@trezor/connect-web>@trezor/connect>@trezor/schema-utils": true, + "@trezor/connect-web>@trezor/connect>@trezor/transport": true, + "@trezor/connect-web>@trezor/utils": true, + "@trezor/connect-web>tslib": true + } + }, + "@trezor/connect-web>@trezor/connect-common": { "globals": { - "console.error": true, - "console.log": true, - "console.warn": true + "console.warn": true, + "localStorage.getItem": true, + "localStorage.setItem": true, + "navigator": true, + "setTimeout": true, + "window": true }, "packages": { - "@trezor/connect-web>@trezor/connect>@trezor/transport": true, - "@trezor/connect-web>@trezor/connect>tslib": true + "@trezor/connect-web>@trezor/connect-common>@trezor/env-utils": true, + "@trezor/connect-web>@trezor/utils": true, + "@trezor/connect-web>tslib": true + } + }, + "@trezor/connect-web>@trezor/connect-common>@trezor/env-utils": { + "globals": { + "innerHeight": true, + "innerWidth": true, + "location.hostname": true, + "location.origin": true, + "navigator.languages": true, + "navigator.platform": true, + "navigator.userAgent": true, + "screen.height": true, + "screen.width": true + }, + "packages": { + "@trezor/connect-web>@trezor/connect-common>@trezor/env-utils>ua-parser-js": true, + "@trezor/connect-web>tslib": true, + "browserify>process": true } }, - "@trezor/connect-web>@trezor/connect>tslib": { + "@trezor/connect-web>@trezor/connect-common>@trezor/env-utils>ua-parser-js": { "globals": { "define": true } }, + "@trezor/connect-web>@trezor/connect>@trezor/protobuf": { + "packages": { + "@trezor/connect-web>@trezor/connect>@trezor/schema-utils": true, + "@trezor/connect-web>tslib": true, + "browserify>buffer": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs": true + } + }, + "@trezor/connect-web>@trezor/connect>@trezor/schema-utils": { + "globals": { + "console.warn": true + }, + "packages": { + "@trezor/connect-web>@trezor/connect>@trezor/schema-utils>@sinclair/typebox": true, + "browserify>buffer": true, + "ts-mixer": true + } + }, "@trezor/connect-web>@trezor/utils": { "globals": { "AbortController": true, "Intl.NumberFormat": true, "clearTimeout": true, + "console.error": true, + "console.info": true, + "console.log": true, + "console.warn": true, "setTimeout": true }, "packages": { - "browserify>buffer": true + "@trezor/connect-web>tslib": true, + "browserify>buffer": true, + "webpack>events": true + } + }, + "@trezor/connect-web>tslib": { + "globals": { + "SuppressedError": true, + "define": true } }, "@zxing/browser": { @@ -2792,15 +3390,6 @@ "define": true } }, - "brfs>static-module>object-inspect": { - "globals": { - "HTMLElement": true, - "WeakRef": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "browserify>assert": { "globals": { "Buffer": true @@ -3023,26 +3612,15 @@ "fetch": true, "location.protocol.search": true, "setTimeout": true - }, - "packages": { - "browserify>buffer": true, - "browserify>process": true, - "browserify>stream-http>builtin-status-codes": true, - "browserify>stream-http>readable-stream": true, - "browserify>url": true, - "pumpify>inherits": true, - "watchify>xtend": true - } - }, - "browserify>stream-http>readable-stream": { + }, "packages": { - "browserify>browser-resolve": true, "browserify>buffer": true, "browserify>process": true, - "browserify>string_decoder": true, + "browserify>stream-http>builtin-status-codes": true, + "browserify>url": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "readable-stream": true, + "watchify>xtend": true } }, "browserify>string_decoder": { @@ -3135,6 +3713,32 @@ "jest-canvas-mock>moo-color>color-name": true } }, + "chart.js": { + "globals": { + "Intl.NumberFormat": true, + "MutationObserver": true, + "OffscreenCanvas": true, + "Path2D": true, + "ResizeObserver": true, + "addEventListener": true, + "clearTimeout": true, + "console.error": true, + "console.warn": true, + "devicePixelRatio": true, + "document": true, + "removeEventListener": true, + "requestAnimationFrame": true, + "setTimeout": true + }, + "packages": { + "chart.js>@kurkle/color": true + } + }, + "chart.js>@kurkle/color": { + "globals": { + "define": true + } + }, "classnames": { "globals": { "classNames": "write", @@ -3221,12 +3825,6 @@ "crypto.getRandomValues": true } }, - "end-of-stream": { - "packages": { - "browserify>process": true, - "pump>once": true - } - }, "eslint-plugin-react>array-includes>is-string": { "packages": { "koa>is-generator-function>has-tostringtag": true @@ -3287,7 +3885,7 @@ }, "eth-lattice-keyring>@ethereumjs/tx": { "packages": { - "@ethereumjs/common": true, + "@ethereumjs/tx>@ethereumjs/common": true, "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util": true, "@ethersproject/providers": true, @@ -3328,14 +3926,6 @@ "crypto": true } }, - "eth-lattice-keyring>@noble/secp256k1": { - "globals": { - "crypto": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -3351,23 +3941,23 @@ "setTimeout": true }, "packages": { - "@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethersproject/abi": true, "@metamask/ethjs>js-sha3": true, + "@metamask/keyring-api>bech32": true, "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>buffer": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, - "eth-lattice-keyring>gridplus-sdk>bech32": true, "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, + "eth-lattice-keyring>gridplus-sdk>rlp": true, "eth-lattice-keyring>gridplus-sdk>secp256k1": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, - "eth-lattice-keyring>rlp": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>hash.js": true, "lodash": true @@ -3375,7 +3965,7 @@ }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": { "packages": { - "@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, "webpack>events": true @@ -3395,7 +3985,7 @@ }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { "packages": { - "@ethereumjs/common>crc-32": true, + "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, "webpack>events": true @@ -3463,16 +4053,12 @@ "packages": { "@metamask/ethjs>js-sha3": true, "bn.js": true, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": true + "ganache>abstract-level>buffer": true } }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": { + "eth-lattice-keyring>gridplus-sdk>rlp": { "globals": { - "console": true - }, - "packages": { - "base64-js": true, - "browserify>buffer>ieee754": true + "TextEncoder": true } }, "eth-lattice-keyring>gridplus-sdk>secp256k1": { @@ -3538,20 +4124,9 @@ }, "ethereumjs-util>create-hash>md5.js>hash-base": { "packages": { - "ethereumjs-util>create-hash>md5.js>hash-base>readable-stream": true, "koa>content-disposition>safe-buffer": true, - "pumpify>inherits": true - } - }, - "ethereumjs-util>create-hash>md5.js>hash-base>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "readable-stream": true } }, "ethereumjs-util>create-hash>ripemd160": { @@ -3655,27 +4230,172 @@ "setTimeout": true } }, + "firebase": { + "packages": { + "firebase>@firebase/app": true, + "firebase>@firebase/messaging": true + } + }, + "firebase>@firebase/app": { + "globals": { + "FinalizationRegistry": true, + "console.warn": true + }, + "packages": { + "firebase>@firebase/app>@firebase/component": true, + "firebase>@firebase/app>@firebase/logger": true, + "firebase>@firebase/app>idb": true, + "firebase>@firebase/util": true + } + }, + "firebase>@firebase/app>@firebase/component": { + "packages": { + "firebase>@firebase/util": true + } + }, + "firebase>@firebase/app>@firebase/logger": { + "globals": { + "console": true + }, + "packages": { + "@trezor/connect-web>tslib": true + } + }, + "firebase>@firebase/app>idb": { + "globals": { + "DOMException": true, + "IDBCursor": true, + "IDBDatabase": true, + "IDBIndex": true, + "IDBObjectStore": true, + "IDBRequest": true, + "IDBTransaction": true, + "indexedDB.deleteDatabase": true, + "indexedDB.open": true + } + }, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs": { + "globals": { + "process": true, + "setTimeout": true + }, + "packages": { + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/aspromise": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/base64": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/codegen": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/eventemitter": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/fetch": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/float": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/inquire": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/path": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/pool": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/utf8": true + } + }, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/codegen": { + "globals": { + "console.log": true + } + }, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/fetch": { + "globals": { + "XMLHttpRequest": true + }, + "packages": { + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/aspromise": true, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs>@protobufjs/inquire": true + } + }, + "firebase>@firebase/installations": { + "globals": { + "BroadcastChannel": true, + "Headers": true, + "btoa": true, + "console.error": true, + "crypto": true, + "fetch": true, + "msCrypto": true, + "navigator.onLine": true, + "setTimeout": true + }, + "packages": { + "firebase>@firebase/app": true, + "firebase>@firebase/app>@firebase/component": true, + "firebase>@firebase/app>idb": true, + "firebase>@firebase/util": true + } + }, + "firebase>@firebase/messaging": { + "globals": { + "Headers": true, + "Notification.maxActions": true, + "Notification.permission": true, + "Notification.requestPermission": true, + "PushSubscription.prototype.hasOwnProperty": true, + "ServiceWorkerRegistration": true, + "URL": true, + "addEventListener": true, + "atob": true, + "btoa": true, + "clients.matchAll": true, + "clients.openWindow": true, + "console.warn": true, + "document": true, + "fetch": true, + "indexedDB": true, + "location.href": true, + "location.origin": true, + "navigator": true, + "origin.replace": true, + "registration.showNotification": true, + "setTimeout": true + }, + "packages": { + "@trezor/connect-web>tslib": true, + "firebase>@firebase/app": true, + "firebase>@firebase/app>@firebase/component": true, + "firebase>@firebase/app>idb": true, + "firebase>@firebase/installations": true, + "firebase>@firebase/util": true + } + }, + "firebase>@firebase/util": { + "globals": { + "atob": true, + "browser": true, + "btoa": true, + "chrome": true, + "console": true, + "document": true, + "indexedDB": true, + "navigator": true, + "process": true, + "self": true, + "setTimeout": true + }, + "packages": { + "browserify>process": true + } + }, "fuse.js": { "globals": { "console": true, "define": true } }, - "ganache>keccak": { + "ganache>abstract-level>buffer": { + "globals": { + "console": true + }, "packages": { - "browserify>buffer": true, - "ganache>keccak>readable-stream": true + "base64-js": true, + "browserify>buffer>ieee754": true } }, - "ganache>keccak>readable-stream": { + "ganache>keccak": { "packages": { - "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "readable-stream": true } }, "ganache>secp256k1": { @@ -3691,39 +4411,33 @@ "string.prototype.matchall>has-symbols": true } }, + "he": { + "globals": { + "define": true + } + }, "json-rpc-engine": { "packages": { - "@metamask/safe-event-emitter": true, - "eth-rpc-errors": true + "eth-rpc-errors": true, + "json-rpc-engine>@metamask/safe-event-emitter": true } }, - "json-rpc-middleware-stream": { + "json-rpc-engine>@metamask/safe-event-emitter": { "globals": { - "console.warn": true, "setTimeout": true }, "packages": { - "json-rpc-middleware-stream>@metamask/safe-event-emitter": true, - "json-rpc-middleware-stream>readable-stream": true + "webpack>events": true } }, - "json-rpc-middleware-stream>@metamask/safe-event-emitter": { + "json-rpc-middleware-stream": { "globals": { + "console.warn": true, "setTimeout": true }, "packages": { - "webpack>events": true - } - }, - "json-rpc-middleware-stream>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, - "webpack>events": true + "@metamask/safe-event-emitter": true, + "readable-stream": true } }, "koa>content-disposition>safe-buffer": { @@ -3801,12 +4515,6 @@ "koa>content-disposition>safe-buffer": true } }, - "mockttp>graphql-tag>tslib": { - "globals": { - "SuppressedError": true, - "define": true - } - }, "nanoid": { "globals": { "crypto": true, @@ -3835,16 +4543,6 @@ "fetch": true } }, - "obj-multiplex": { - "globals": { - "console.warn": true - }, - "packages": { - "end-of-stream": true, - "pump>once": true, - "readable-stream": true - } - }, "promise-to-callback": { "packages": { "promise-to-callback>is-fn": true, @@ -3873,19 +4571,6 @@ "console": true } }, - "pump": { - "packages": { - "browserify>browser-resolve": true, - "browserify>process": true, - "end-of-stream": true, - "pump>once": true - } - }, - "pump>once": { - "packages": { - "pump>once>wrappy": true - } - }, "qrcode-generator": { "globals": { "define": true @@ -3897,8 +4582,6 @@ "devicePixelRatio": true }, "packages": { - "prop-types": true, - "qrcode.react>qr.js": true, "react": true } }, @@ -3961,6 +4644,15 @@ "react": true } }, + "react-chartjs-2": { + "globals": { + "setTimeout": true + }, + "packages": { + "chart.js": true, + "react": true + } + }, "react-devtools": { "packages": { "react-devtools>react-devtools-core": true @@ -4054,7 +4746,7 @@ "setTimeout": true }, "packages": { - "mockttp>graphql-tag>tslib": true + "@trezor/connect-web>tslib": true } }, "react-focus-lock>react-clientside-effect": { @@ -4073,7 +4765,7 @@ "console.error": true }, "packages": { - "mockttp>graphql-tag>tslib": true, + "@trezor/connect-web>tslib": true, "react": true, "react-focus-lock>use-sidecar>detect-node-es": true } @@ -4231,13 +4923,12 @@ "document": true }, "packages": { - "@babel/runtime": true, "prop-types": true, - "prop-types>react-is": true, "react": true, "react-dom": true, + "react-redux>@babel/runtime": true, "react-redux>hoist-non-react-statics": true, - "redux": true + "react-redux>react-is": true } }, "react-redux>hoist-non-react-statics": { @@ -4245,6 +4936,11 @@ "prop-types>react-is": true } }, + "react-redux>react-is": { + "globals": { + "console": true + } + }, "react-responsive-carousel": { "globals": { "addEventListener": true, @@ -4397,38 +5093,24 @@ "readable-stream": { "packages": { "browserify>browser-resolve": true, + "browserify>buffer": true, "browserify>process": true, - "browserify>timers-browserify": true, + "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>core-util-is": true, - "readable-stream>isarray": true, - "readable-stream>process-nextick-args": true, - "readable-stream>safe-buffer": true, - "readable-stream>string_decoder": true, "readable-stream>util-deprecate": true, "webpack>events": true } }, - "readable-stream>core-util-is": { + "readable-stream-2>core-util-is": { "packages": { "browserify>insert-module-globals>is-buffer": true } }, - "readable-stream>process-nextick-args": { + "readable-stream-2>process-nextick-args": { "packages": { "browserify>process": true } }, - "readable-stream>safe-buffer": { - "packages": { - "browserify>buffer": true - } - }, - "readable-stream>string_decoder": { - "packages": { - "readable-stream>safe-buffer": true - } - }, "readable-stream>util-deprecate": { "globals": { "console.trace": true, @@ -4449,13 +5131,7 @@ "console.error": true }, "packages": { - "browserify>process": true, - "semver>lru-cache": true - } - }, - "semver>lru-cache": { - "packages": { - "semver>lru-cache>yallist": true + "browserify>process": true } }, "sinon>nise>path-to-regexp": { @@ -4466,18 +5142,7 @@ "stream-browserify": { "packages": { "pumpify>inherits": true, - "stream-browserify>readable-stream": true, - "webpack>events": true - } - }, - "stream-browserify>readable-stream": { - "packages": { - "browserify>browser-resolve": true, - "browserify>buffer": true, - "browserify>process": true, - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true, + "readable-stream": true, "webpack>events": true } }, @@ -4557,6 +5222,15 @@ "string.prototype.matchall>call-bind": true } }, + "string.prototype.matchall>es-abstract>object-inspect": { + "globals": { + "HTMLElement": true, + "WeakRef": true + }, + "packages": { + "browserify>browser-resolve": true + } + }, "string.prototype.matchall>get-intrinsic": { "globals": { "AggregateError": true, @@ -4594,8 +5268,8 @@ }, "string.prototype.matchall>side-channel": { "packages": { - "brfs>static-module>object-inspect": true, "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>es-abstract>object-inspect": true, "string.prototype.matchall>get-intrinsic": true } }, @@ -4638,8 +5312,7 @@ }, "web3-stream-provider>uuid": { "globals": { - "crypto": true, - "msCrypto": true + "crypto": true } }, "webextension-polyfill": { diff --git a/lavamoat/browserify/policy-override.json b/lavamoat/browserify/policy-override.json index 72ded77f19ac..3ece77c837c6 100644 --- a/lavamoat/browserify/policy-override.json +++ b/lavamoat/browserify/policy-override.json @@ -1,5 +1,12 @@ { "resources": { + "@metamask/snaps-execution-environments": { + "packages": { + "@metamask/post-message-stream": true, + "@metamask/snaps-utils": true, + "@metamask/utils": true + } + }, "@metamask/controllers>web3-provider-engine>eth-json-rpc-middleware>node-fetch": { "globals": { "fetch": true @@ -150,6 +157,9 @@ } }, "@metamask/announcement-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, "packages": { "immer": true } diff --git a/lavamoat/build-system/policy-override.json b/lavamoat/build-system/policy-override.json index 79026de48598..c5e8950556e7 100644 --- a/lavamoat/build-system/policy-override.json +++ b/lavamoat/build-system/policy-override.json @@ -178,7 +178,6 @@ "@typescript-eslint/eslint-plugin>tsutils": true, "eslint-plugin-jest>@typescript-eslint/utils": true, "eslint>debug": true, - "madge>debug": true, "typescript": true, "nock>debug": true } diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index 3553f931c264..02078b5d39fc 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -3,18 +3,22 @@ "@babel/code-frame": { "globals": { "console.warn": true, - "process.emitWarning": true + "process": true }, "packages": { "@babel/code-frame>@babel/highlight": true, - "@babel/code-frame>chalk": true + "postcss>picocolors": true } }, "@babel/code-frame>@babel/highlight": { + "globals": { + "process": true + }, "packages": { "@babel/code-frame>@babel/highlight>chalk": true, "lavamoat>@babel/highlight>@babel/helper-validator-identifier": true, - "loose-envify>js-tokens": true + "loose-envify>js-tokens": true, + "postcss>picocolors": true } }, "@babel/code-frame>@babel/highlight>chalk": { @@ -30,12 +34,7 @@ }, "@babel/code-frame>@babel/highlight>chalk>ansi-styles": { "packages": { - "@babel/code-frame>@babel/highlight>chalk>ansi-styles>color-convert": true - } - }, - "@babel/code-frame>@babel/highlight>chalk>ansi-styles>color-convert": { - "packages": { - "@babel/code-frame>@babel/highlight>chalk>ansi-styles>color-convert>color-name": true + "@metamask/jazzicon>color>color-convert": true } }, "@babel/code-frame>@babel/highlight>chalk>supports-color": { @@ -53,42 +52,6 @@ "gulp-livereload>chalk>supports-color>has-flag": true } }, - "@babel/code-frame>chalk": { - "globals": { - "process.env.TERM": true, - "process.platform": true - }, - "packages": { - "@babel/code-frame>chalk>ansi-styles": true, - "@babel/code-frame>chalk>escape-string-regexp": true, - "@babel/code-frame>chalk>supports-color": true - } - }, - "@babel/code-frame>chalk>ansi-styles": { - "packages": { - "@babel/code-frame>chalk>ansi-styles>color-convert": true - } - }, - "@babel/code-frame>chalk>ansi-styles>color-convert": { - "packages": { - "@babel/code-frame>chalk>ansi-styles>color-convert>color-name": true - } - }, - "@babel/code-frame>chalk>supports-color": { - "builtin": { - "os.release": true - }, - "globals": { - "process.env": true, - "process.platform": true, - "process.stderr": true, - "process.stdout": true, - "process.versions.node.split": true - }, - "packages": { - "gulp-livereload>chalk>supports-color>has-flag": true - } - }, "@babel/core": { "builtin": { "assert": true, @@ -978,7 +941,7 @@ "@babel/core>@babel/helper-compilation-targets": true, "@babel/preset-env>@babel/helper-plugin-utils": true, "@babel/preset-env>babel-plugin-polyfill-corejs2>@babel/helper-define-polyfill-provider>lodash.debounce": true, - "brfs>resolve": true + "depcheck>resolve": true } }, "@babel/preset-env>babel-plugin-polyfill-corejs2>@babel/helper-define-polyfill-provider>lodash.debounce": { @@ -1178,11 +1141,11 @@ "@lavamoat/lavapack>combine-source-map": true, "@lavamoat/lavapack>convert-source-map": true, "@lavamoat/lavapack>json-stable-stringify": true, - "@lavamoat/lavapack>lavamoat-core": true, - "@lavamoat/lavapack>readable-stream": true, "@lavamoat/lavapack>umd": true, "browserify>JSONStream": true, "eslint>espree": true, + "lavamoat-viz>lavamoat-core": true, + "readable-stream": true, "through2": true } }, @@ -1198,7 +1161,7 @@ "@lavamoat/lavapack>combine-source-map>inline-source-map": true, "@lavamoat/lavapack>combine-source-map>lodash.memoize": true, "@lavamoat/lavapack>combine-source-map>source-map": true, - "nyc>convert-source-map": true + "gulp-sourcemaps>convert-source-map": true } }, "@lavamoat/lavapack>combine-source-map>inline-source-map": { @@ -1225,63 +1188,6 @@ "string.prototype.matchall>call-bind": true } }, - "@lavamoat/lavapack>lavamoat-core": { - "builtin": { - "events": true, - "fs.readFileSync": true, - "node:fs/promises.readFile": true, - "node:fs/promises.writeFile": true, - "path.extname": true, - "path.join": true - }, - "globals": { - "__dirname": true, - "ast": true, - "console.error": true, - "console.warn": true, - "content": true, - "define": true, - "file": true, - "importMap": true, - "moduleInitializer": true, - "packageName": true, - "specifier": true, - "type": true - }, - "packages": { - "@lavamoat/lavapack>json-stable-stringify": true, - "@lavamoat/lavapack>lavamoat-core>lavamoat-tofu": true, - "lavamoat>lavamoat-core>merge-deep": true - } - }, - "@lavamoat/lavapack>lavamoat-core>lavamoat-tofu": { - "globals": { - "console.log": true - }, - "packages": { - "@babel/core>@babel/parser": true, - "depcheck>@babel/traverse": true - } - }, - "@lavamoat/lavapack>readable-stream": { - "builtin": { - "buffer.Buffer": true, - "events.EventEmitter": true, - "stream": true, - "util": true - }, - "globals": { - "process.env.READABLE_STREAM": true, - "process.nextTick": true, - "process.stderr": true, - "process.stdout": true - }, - "packages": { - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true - } - }, "@metamask/build-utils": { "packages": { "@metamask/utils": true @@ -1297,6 +1203,16 @@ "Buffer": true } }, + "@metamask/jazzicon>color>color-convert": { + "packages": { + "@metamask/jazzicon>color>color-convert>color-name": true + } + }, + "@metamask/object-multiplex>once": { + "packages": { + "@metamask/object-multiplex>once>wrappy": true + } + }, "@metamask/utils": { "globals": { "Buffer": true, @@ -1324,21 +1240,6 @@ "crypto": true } }, - "@sentry/cli>which": { - "builtin": { - "path.join": true - }, - "globals": { - "process.cwd": true, - "process.env.OSTYPE": true, - "process.env.PATH": true, - "process.env.PATHEXT": true, - "process.platform": true - }, - "packages": { - "@sentry/cli>which>isexe": true - } - }, "@sentry/cli>which>isexe": { "builtin": { "fs": true @@ -1386,6 +1287,11 @@ "define": true } }, + "@storybook/test-runner>jest-circus>p-limit": { + "packages": { + "@storybook/test-runner>jest-circus>p-limit>yocto-queue": true + } + }, "@typescript-eslint/eslint-plugin": { "packages": { "@typescript-eslint/eslint-plugin>@typescript-eslint/type-utils": true, @@ -1408,7 +1314,6 @@ "@typescript-eslint/eslint-plugin>tsutils": true, "eslint-plugin-jest>@typescript-eslint/utils": true, "eslint>debug": true, - "madge>debug": true, "nock>debug": true, "typescript": true } @@ -1471,7 +1376,7 @@ "packages": { "bify-module-groups>through2": true, "pify": true, - "pump": true + "pumpify>pump": true } }, "bify-module-groups>through2": { @@ -1482,56 +1387,80 @@ "process.nextTick": true }, "packages": { - "bify-module-groups>through2>readable-stream": true + "readable-stream": true } }, - "bify-module-groups>through2>readable-stream": { + "browserify": { "builtin": { - "buffer.Buffer": true, "events.EventEmitter": true, - "stream": true, - "util": true + "fs.realpath": true, + "path.dirname": true, + "path.join": true, + "path.relative": true, + "path.resolve": true, + "path.sep": true }, "globals": { - "process.env.READABLE_STREAM": true, + "__dirname": true, + "process.cwd": true, "process.nextTick": true, - "process.stderr": true, - "process.stdout": true + "process.platform": true }, "packages": { - "browserify>string_decoder": true, + "browserify>browser-pack": true, + "browserify>browser-resolve": true, + "browserify>cached-path-relative": true, + "browserify>concat-stream": true, + "browserify>deps-sort": true, + "browserify>has": true, + "browserify>insert-module-globals": true, + "browserify>module-deps": true, + "browserify>read-only-stream": true, + "browserify>shasum-object": true, + "browserify>syntax-error": true, + "browserify>through2": true, + "depcheck>resolve": true, + "labeled-stream-splicer": true, + "lavamoat>htmlescape": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "watchify>defined": true, + "watchify>xtend": true } }, - "brfs": { - "builtin": { - "fs.createReadStream": true, - "fs.readdir": true, - "path": true + "browserify>JSONStream": { + "globals": { + "Buffer": true }, "packages": { - "brfs>quote-stream": true, - "brfs>resolve": true, - "brfs>static-module": true, - "brfs>through2": true + "browserify>JSONStream>jsonparse": true, + "debounce-stream>through": true } }, - "brfs>quote-stream": { + "browserify>JSONStream>jsonparse": { "globals": { "Buffer": true - }, - "packages": { - "brfs>quote-stream>buffer-equal": true, - "brfs>quote-stream>through2": true } }, - "brfs>quote-stream>buffer-equal": { + "browserify>browser-pack": { "builtin": { - "buffer.Buffer.isBuffer": true + "fs.readFileSync": true, + "path.join": true, + "path.relative": true + }, + "globals": { + "__dirname": true, + "process.cwd": true + }, + "packages": { + "@lavamoat/lavapack>combine-source-map": true, + "@lavamoat/lavapack>umd": true, + "browserify>JSONStream": true, + "browserify>browser-pack>through2": true, + "koa>content-disposition>safe-buffer": true, + "watchify>defined": true } }, - "brfs>quote-stream>through2": { + "browserify>browser-pack>through2": { "builtin": { "util.inherits": true }, @@ -1539,189 +1468,124 @@ "process.nextTick": true }, "packages": { - "readable-stream": true, + "browserify>browser-pack>through2>readable-stream": true, "watchify>xtend": true } }, - "brfs>resolve": { + "browserify>browser-pack>through2>readable-stream": { "builtin": { - "fs.readFile": true, - "fs.readFileSync": true, - "fs.realpath": true, - "fs.realpathSync": true, - "fs.stat": true, - "fs.statSync": true, - "os.homedir": true, - "path.dirname": true, - "path.join": true, - "path.parse": true, - "path.relative": true, - "path.resolve": true + "events.EventEmitter": true, + "stream": true, + "util": true }, "globals": { - "process.env.HOME": true, - "process.env.HOMEDRIVE": true, - "process.env.HOMEPATH": true, - "process.env.LNAME": true, - "process.env.LOGNAME": true, - "process.env.USER": true, - "process.env.USERNAME": true, - "process.env.USERPROFILE": true, - "process.getuid": true, - "process.nextTick": true, - "process.platform": true, - "process.versions.pnp": true + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true }, "packages": { - "brfs>resolve>path-parse": true, - "depcheck>is-core-module": true - } - }, - "brfs>resolve>path-parse": { - "globals": { - "process.platform": true + "browserify>browser-pack>through2>readable-stream>isarray": true, + "browserify>browser-pack>through2>readable-stream>safe-buffer": true, + "browserify>browser-pack>through2>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true } }, - "brfs>static-module": { - "packages": { - "brfs>static-module>acorn-node": true, - "brfs>static-module>escodegen": true, - "brfs>static-module>magic-string": true, - "brfs>static-module>merge-source-map": true, - "brfs>static-module>object-inspect": true, - "brfs>static-module>scope-analyzer": true, - "brfs>static-module>shallow-copy": true, - "brfs>static-module>static-eval": true, - "brfs>static-module>through2": true, - "browserify>concat-stream": true, - "browserify>duplexer2": true, - "browserify>has": true, - "nyc>convert-source-map": true, - "readable-stream": true + "browserify>browser-pack>through2>readable-stream>safe-buffer": { + "builtin": { + "buffer": true } }, - "brfs>static-module>acorn-node": { + "browserify>browser-pack>through2>readable-stream>string_decoder": { "packages": { - "@storybook/react>acorn-walk": true, - "brfs>static-module>acorn-node>acorn": true, - "watchify>xtend": true + "browserify>browser-pack>through2>readable-stream>string_decoder>safe-buffer": true } }, - "brfs>static-module>acorn-node>acorn": { - "globals": { - "define": true + "browserify>browser-pack>through2>readable-stream>string_decoder>safe-buffer": { + "builtin": { + "buffer": true } }, - "brfs>static-module>escodegen": { - "globals": { - "sourceMap.SourceNode": true + "browserify>browser-resolve": { + "builtin": { + "fs.readFile": true, + "fs.readFileSync": true, + "path": true }, - "packages": { - "brfs>static-module>escodegen>estraverse": true, - "brfs>static-module>escodegen>source-map": true, - "eslint>esutils": true - } - }, - "brfs>static-module>magic-string": { "globals": { - "Buffer": true, - "btoa": true, - "console.warn": true + "__dirname": true, + "process.platform": true }, "packages": { - "brfs>static-module>magic-string>sourcemap-codec": true + "depcheck>resolve": true } }, - "brfs>static-module>magic-string>sourcemap-codec": { + "browserify>cached-path-relative": { + "builtin": { + "path": true + }, "globals": { - "define": true + "process.cwd": true } }, - "brfs>static-module>merge-source-map": { + "browserify>concat-stream": { + "globals": { + "Buffer.concat": true, + "Buffer.isBuffer": true + }, "packages": { - "brfs>static-module>merge-source-map>source-map": true + "browserify>concat-stream>readable-stream": true, + "browserify>concat-stream>typedarray": true, + "pumpify>inherits": true, + "terser>source-map-support>buffer-from": true } }, - "brfs>static-module>object-inspect": { + "browserify>concat-stream>readable-stream": { "builtin": { - "util.inspect": true + "events.EventEmitter": true, + "stream": true, + "util": true }, "globals": { - "HTMLElement": true, - "WeakRef": true - } - }, - "brfs>static-module>scope-analyzer": { - "builtin": { - "assert.ok": true, - "assert.strictEqual": true + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true }, "packages": { - "brfs>static-module>scope-analyzer>array-from": true, - "brfs>static-module>scope-analyzer>dash-ast": true, - "brfs>static-module>scope-analyzer>es6-map": true, - "brfs>static-module>scope-analyzer>es6-set": true, - "brfs>static-module>scope-analyzer>estree-is-function": true, - "brfs>static-module>scope-analyzer>get-assigned-identifiers": true, - "resolve-url-loader>es6-iterator>es6-symbol": true - } - }, - "brfs>static-module>scope-analyzer>dash-ast": { - "builtin": { - "assert": true - } - }, - "brfs>static-module>scope-analyzer>es6-map": { - "packages": { - "gulp-sourcemaps>debug-fabulous>memoizee>event-emitter": true, - "resolve-url-loader>es6-iterator": true, - "resolve-url-loader>es6-iterator>d": true, - "resolve-url-loader>es6-iterator>es5-ext": true, - "resolve-url-loader>es6-iterator>es6-symbol": true - } - }, - "brfs>static-module>scope-analyzer>es6-set": { - "packages": { - "gulp-sourcemaps>debug-fabulous>memoizee>event-emitter": true, - "resolve-url-loader>es6-iterator": true, - "resolve-url-loader>es6-iterator>d": true, - "resolve-url-loader>es6-iterator>es5-ext": true, - "resolve-url-loader>es6-iterator>es6-symbol": true + "browserify>concat-stream>readable-stream>isarray": true, + "browserify>concat-stream>readable-stream>safe-buffer": true, + "browserify>concat-stream>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true } }, - "brfs>static-module>scope-analyzer>get-assigned-identifiers": { + "browserify>concat-stream>readable-stream>safe-buffer": { "builtin": { - "assert.equal": true - } - }, - "brfs>static-module>static-eval": { - "packages": { - "brfs>static-module>static-eval>escodegen": true + "buffer": true } }, - "brfs>static-module>static-eval>escodegen": { - "globals": { - "sourceMap.SourceNode": true - }, + "browserify>concat-stream>readable-stream>string_decoder": { "packages": { - "brfs>static-module>static-eval>escodegen>estraverse": true, - "brfs>static-module>static-eval>escodegen>source-map": true, - "eslint>esutils": true + "browserify>concat-stream>readable-stream>safe-buffer": true } }, - "brfs>static-module>through2": { - "builtin": { - "util.inherits": true - }, - "globals": { - "process.nextTick": true - }, + "browserify>deps-sort": { "packages": { - "readable-stream": true, - "watchify>xtend": true + "browserify>deps-sort>through2": true, + "browserify>shasum-object": true } }, - "brfs>through2": { + "browserify>deps-sort>through2": { "builtin": { "util.inherits": true }, @@ -1729,147 +1593,105 @@ "process.nextTick": true }, "packages": { - "readable-stream": true, + "browserify>deps-sort>through2>readable-stream": true, "watchify>xtend": true } }, - "browserify": { + "browserify>deps-sort>through2>readable-stream": { "builtin": { "events.EventEmitter": true, - "fs.realpath": true, - "path.dirname": true, - "path.join": true, - "path.relative": true, - "path.resolve": true, - "path.sep": true + "stream": true, + "util": true }, "globals": { - "__dirname": true, - "process.cwd": true, - "process.nextTick": true, - "process.platform": true + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true }, "packages": { - "brfs>resolve": true, - "browserify>browser-pack": true, - "browserify>browser-resolve": true, - "browserify>cached-path-relative": true, - "browserify>concat-stream": true, - "browserify>deps-sort": true, - "browserify>has": true, - "browserify>insert-module-globals": true, - "browserify>module-deps": true, - "browserify>read-only-stream": true, - "browserify>shasum-object": true, - "browserify>syntax-error": true, - "browserify>through2": true, - "labeled-stream-splicer": true, - "lavamoat>htmlescape": true, + "browserify>deps-sort>through2>readable-stream>isarray": true, + "browserify>deps-sort>through2>readable-stream>safe-buffer": true, + "browserify>deps-sort>through2>readable-stream>string_decoder": true, "pumpify>inherits": true, - "watchify>defined": true, - "watchify>xtend": true - } - }, - "browserify>JSONStream": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>JSONStream>jsonparse": true, - "debounce-stream>through": true + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true } }, - "browserify>JSONStream>jsonparse": { - "globals": { - "Buffer": true + "browserify>deps-sort>through2>readable-stream>safe-buffer": { + "builtin": { + "buffer": true } }, - "browserify>browser-pack": { - "builtin": { - "fs.readFileSync": true, - "path.join": true, - "path.relative": true - }, - "globals": { - "__dirname": true, - "process.cwd": true - }, + "browserify>deps-sort>through2>readable-stream>string_decoder": { "packages": { - "@lavamoat/lavapack>combine-source-map": true, - "@lavamoat/lavapack>umd": true, - "browserify>JSONStream": true, - "browserify>browser-pack>through2": true, - "koa>content-disposition>safe-buffer": true, - "watchify>defined": true + "browserify>deps-sort>through2>readable-stream>safe-buffer": true } }, - "browserify>browser-pack>through2": { - "builtin": { - "util.inherits": true - }, - "globals": { - "process.nextTick": true - }, + "browserify>duplexer2": { "packages": { - "readable-stream": true, - "watchify>xtend": true + "browserify>duplexer2>readable-stream": true } }, - "browserify>browser-resolve": { + "browserify>duplexer2>readable-stream": { "builtin": { - "fs.readFile": true, - "fs.readFileSync": true, - "path": true + "events.EventEmitter": true, + "stream": true, + "util": true }, "globals": { - "__dirname": true, - "process.platform": true + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true }, "packages": { - "brfs>resolve": true + "browserify>duplexer2>readable-stream>isarray": true, + "browserify>duplexer2>readable-stream>safe-buffer": true, + "browserify>duplexer2>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true } }, - "browserify>cached-path-relative": { + "browserify>duplexer2>readable-stream>safe-buffer": { "builtin": { - "path": true - }, - "globals": { - "process.cwd": true - } - }, - "browserify>concat-stream": { - "globals": { - "Buffer.concat": true, - "Buffer.isBuffer": true - }, - "packages": { - "browserify>concat-stream>typedarray": true, - "pumpify>inherits": true, - "readable-stream": true, - "terser>source-map-support>buffer-from": true + "buffer": true } }, - "browserify>deps-sort": { + "browserify>duplexer2>readable-stream>string_decoder": { "packages": { - "browserify>deps-sort>through2": true, - "browserify>shasum-object": true + "browserify>duplexer2>readable-stream>safe-buffer": true } }, - "browserify>deps-sort>through2": { + "browserify>glob": { "builtin": { - "util.inherits": true + "assert": true, + "events.EventEmitter": true, + "fs": true, + "path.join": true, + "path.resolve": true, + "util": true }, "globals": { - "process.nextTick": true + "console.error": true, + "process.cwd": true, + "process.nextTick": true, + "process.platform": true }, "packages": { - "readable-stream": true, - "watchify>xtend": true - } - }, - "browserify>duplexer2": { - "packages": { - "readable-stream": true + "@metamask/object-multiplex>once": true, + "eslint>minimatch": true, + "gulp-watch>path-is-absolute": true, + "mocha>glob>fs.realpath": true, + "mocha>glob>inflight": true, + "pumpify>inherits": true } }, "browserify>has": { @@ -1890,9 +1712,9 @@ }, "packages": { "@lavamoat/lavapack>combine-source-map": true, - "brfs>static-module>acorn-node": true, "browserify>insert-module-globals>through2": true, "browserify>insert-module-globals>undeclared-identifiers": true, + "browserify>syntax-error>acorn-node": true, "gulp-watch>path-is-absolute": true, "watchify>xtend": true } @@ -1905,17 +1727,56 @@ "process.nextTick": true }, "packages": { - "readable-stream": true, + "browserify>insert-module-globals>through2>readable-stream": true, "watchify>xtend": true } }, + "browserify>insert-module-globals>through2>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "browserify>insert-module-globals>through2>readable-stream>isarray": true, + "browserify>insert-module-globals>through2>readable-stream>safe-buffer": true, + "browserify>insert-module-globals>through2>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "browserify>insert-module-globals>through2>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "browserify>insert-module-globals>through2>readable-stream>string_decoder": { + "packages": { + "browserify>insert-module-globals>through2>readable-stream>safe-buffer": true + } + }, "browserify>insert-module-globals>undeclared-identifiers": { "packages": { - "brfs>static-module>acorn-node": true, - "brfs>static-module>scope-analyzer>get-assigned-identifiers": true, + "browserify>insert-module-globals>undeclared-identifiers>get-assigned-identifiers": true, + "browserify>syntax-error>acorn-node": true, "watchify>xtend": true } }, + "browserify>insert-module-globals>undeclared-identifiers>get-assigned-identifiers": { + "builtin": { + "assert.equal": true + } + }, "browserify>module-deps": { "builtin": { "fs.createReadStream": true, @@ -1934,32 +1795,100 @@ "tr": true }, "packages": { - "brfs>resolve": true, "browserify>browser-resolve": true, "browserify>cached-path-relative": true, "browserify>concat-stream": true, "browserify>duplexer2": true, "browserify>module-deps>detective": true, + "browserify>module-deps>readable-stream": true, "browserify>module-deps>stream-combiner2": true, "browserify>module-deps>through2": true, "browserify>parents": true, + "depcheck>resolve": true, "loose-envify": true, "pumpify>inherits": true, - "readable-stream": true, "watchify>defined": true, "watchify>xtend": true } }, "browserify>module-deps>detective": { "packages": { - "brfs>static-module>acorn-node": true, + "browserify>syntax-error>acorn-node": true, "watchify>defined": true } }, + "browserify>module-deps>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "browserify>module-deps>readable-stream>isarray": true, + "browserify>module-deps>readable-stream>safe-buffer": true, + "browserify>module-deps>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "browserify>module-deps>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "browserify>module-deps>readable-stream>string_decoder": { + "packages": { + "browserify>module-deps>readable-stream>safe-buffer": true + } + }, "browserify>module-deps>stream-combiner2": { "packages": { "browserify>duplexer2": true, - "readable-stream": true + "browserify>module-deps>stream-combiner2>readable-stream": true + } + }, + "browserify>module-deps>stream-combiner2>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "browserify>module-deps>stream-combiner2>readable-stream>isarray": true, + "browserify>module-deps>stream-combiner2>readable-stream>safe-buffer": true, + "browserify>module-deps>stream-combiner2>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "browserify>module-deps>stream-combiner2>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "browserify>module-deps>stream-combiner2>readable-stream>string_decoder": { + "packages": { + "browserify>module-deps>stream-combiner2>readable-stream>safe-buffer": true } }, "browserify>module-deps>through2": { @@ -1970,7 +1899,7 @@ "process.nextTick": true }, "packages": { - "readable-stream": true, + "browserify>module-deps>readable-stream": true, "watchify>xtend": true } }, @@ -1997,7 +1926,75 @@ }, "browserify>read-only-stream": { "packages": { - "readable-stream": true + "browserify>read-only-stream>readable-stream": true + } + }, + "browserify>read-only-stream>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "browserify>read-only-stream>readable-stream>isarray": true, + "browserify>read-only-stream>readable-stream>safe-buffer": true, + "browserify>read-only-stream>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "browserify>read-only-stream>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "browserify>read-only-stream>readable-stream>string_decoder": { + "packages": { + "browserify>read-only-stream>readable-stream>safe-buffer": true + } + }, + "browserify>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "browserify>readable-stream>isarray": true, + "browserify>readable-stream>safe-buffer": true, + "browserify>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "browserify>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "browserify>readable-stream>string_decoder": { + "packages": { + "browserify>readable-stream>safe-buffer": true } }, "browserify>shasum-object": { @@ -2018,7 +2015,19 @@ }, "browserify>syntax-error": { "packages": { - "brfs>static-module>acorn-node": true + "browserify>syntax-error>acorn-node": true + } + }, + "browserify>syntax-error>acorn-node": { + "packages": { + "@storybook/react>acorn-walk": true, + "browserify>syntax-error>acorn-node>acorn": true, + "watchify>xtend": true + } + }, + "browserify>syntax-error>acorn-node>acorn": { + "globals": { + "define": true } }, "browserify>through2": { @@ -2029,7 +2038,7 @@ "process.nextTick": true }, "packages": { - "readable-stream": true, + "browserify>readable-stream": true, "watchify>xtend": true } }, @@ -2180,11 +2189,6 @@ "chokidar>anymatch>picomatch": true } }, - "copy-webpack-plugin>p-limit": { - "packages": { - "copy-webpack-plugin>p-limit>yocto-queue": true - } - }, "cross-spawn": { "builtin": { "child_process.spawn": true, @@ -2204,9 +2208,9 @@ "process.platform": true }, "packages": { - "@sentry/cli>which": true, "cross-spawn>path-key": true, - "cross-spawn>shebang-command": true + "cross-spawn>shebang-command": true, + "cross-spawn>which": true } }, "cross-spawn>path-key": { @@ -2220,6 +2224,21 @@ "cross-spawn>shebang-command>shebang-regex": true } }, + "cross-spawn>which": { + "builtin": { + "path.join": true + }, + "globals": { + "process.cwd": true, + "process.env.OSTYPE": true, + "process.env.PATH": true, + "process.env.PATHEXT": true, + "process.platform": true + }, + "packages": { + "@sentry/cli>which>isexe": true + } + }, "debounce-stream>duplexer": { "builtin": { "stream": true @@ -2318,7 +2337,7 @@ "setTimeout": true }, "packages": { - "nyc>glob": true + "browserify>glob": true } }, "depcheck>@babel/traverse": { @@ -2376,17 +2395,56 @@ "process.versions": true }, "packages": { - "depcheck>is-core-module>hasown": true - } - }, - "depcheck>is-core-module>hasown": { - "packages": { - "browserify>has>function-bind": true + "depcheck>is-core-module>hasown": true + } + }, + "depcheck>is-core-module>hasown": { + "packages": { + "browserify>has>function-bind": true + } + }, + "depcheck>json5": { + "globals": { + "console.warn": true + } + }, + "depcheck>resolve": { + "builtin": { + "fs.readFile": true, + "fs.readFileSync": true, + "fs.realpath": true, + "fs.realpathSync": true, + "fs.stat": true, + "fs.statSync": true, + "os.homedir": true, + "path.dirname": true, + "path.join": true, + "path.parse": true, + "path.relative": true, + "path.resolve": true + }, + "globals": { + "process.env.HOME": true, + "process.env.HOMEDRIVE": true, + "process.env.HOMEPATH": true, + "process.env.LNAME": true, + "process.env.LOGNAME": true, + "process.env.USER": true, + "process.env.USERNAME": true, + "process.env.USERPROFILE": true, + "process.getuid": true, + "process.nextTick": true, + "process.platform": true, + "process.versions.pnp": true + }, + "packages": { + "depcheck>is-core-module": true, + "depcheck>resolve>path-parse": true } }, - "depcheck>json5": { + "depcheck>resolve>path-parse": { "globals": { - "console.warn": true + "process.platform": true } }, "duplexify": { @@ -2395,37 +2453,18 @@ "process.nextTick": true }, "packages": { - "duplexify>readable-stream": true, + "duplexify>end-of-stream": true, "duplexify>stream-shift": true, - "end-of-stream": true, - "pumpify>inherits": true - } - }, - "duplexify>readable-stream": { - "builtin": { - "buffer.Buffer": true, - "events.EventEmitter": true, - "stream": true, - "util": true - }, - "globals": { - "process.env.READABLE_STREAM": true, - "process.nextTick": true, - "process.stderr": true, - "process.stdout": true - }, - "packages": { - "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream": true } }, - "end-of-stream": { + "duplexify>end-of-stream": { "globals": { "process.nextTick": true }, "packages": { - "pump>once": true + "@metamask/object-multiplex>once": true } }, "eslint": { @@ -2507,7 +2546,7 @@ "path.resolve": true }, "packages": { - "brfs>resolve": true, + "depcheck>resolve": true, "eslint-import-resolver-node>debug": true } }, @@ -2537,11 +2576,11 @@ "process.cwd": true }, "packages": { - "brfs>resolve": true, + "browserify>glob": true, "del>is-glob": true, + "depcheck>resolve": true, "eslint-plugin-import>tsconfig-paths": true, - "nock>debug": true, - "nyc>glob": true + "nock>debug": true } }, "eslint-plugin-import": { @@ -2853,7 +2892,7 @@ "process.cwd": true }, "packages": { - "brfs>resolve": true, + "depcheck>resolve": true, "eslint-plugin-node>eslint-plugin-es": true, "eslint-plugin-node>eslint-utils": true, "eslint-plugin-node>semver": true, @@ -3016,8 +3055,8 @@ "process.versions.pnp": true }, "packages": { - "brfs>resolve>path-parse": true, - "depcheck>is-core-module": true + "depcheck>is-core-module": true, + "depcheck>resolve>path-parse": true } }, "eslint-plugin-react>semver": { @@ -3063,7 +3102,7 @@ "eslint-plugin-prettier": true, "eslint-plugin-react": true, "eslint-plugin-react-hooks": true, - "eslint>ajv": true, + "eslint>@eslint/eslintrc>ajv": true, "eslint>globals": true, "eslint>ignore": true, "eslint>minimatch": true, @@ -3071,6 +3110,17 @@ "nock>debug": true } }, + "eslint>@eslint/eslintrc>ajv": { + "globals": { + "console": true + }, + "packages": { + "@metamask/snaps-utils>fast-json-stable-stringify": true, + "eslint>@eslint/eslintrc>ajv>json-schema-traverse": true, + "eslint>ajv>uri-js": true, + "eslint>fast-deep-equal": true + } + }, "eslint>@eslint/eslintrc>import-fresh": { "builtin": { "path.dirname": true @@ -3334,6 +3384,7 @@ "fs.stat": true, "fs.statSync": true, "os.cpus": true, + "os.platform": true, "path.basename": true, "path.resolve": true, "stream.PassThrough": true, @@ -3367,6 +3418,30 @@ "chokidar>braces": true } }, + "firebase>@firebase/database>faye-websocket>websocket-driver": { + "builtin": { + "crypto.createHash": true, + "crypto.randomBytes": true, + "events.EventEmitter": true, + "stream.Stream": true, + "url.parse": true, + "util.inherits": true + }, + "globals": { + "Buffer": true, + "process.version.match": true + }, + "packages": { + "firebase>@firebase/database>faye-websocket>websocket-driver>http-parser-js": true, + "firebase>@firebase/database>faye-websocket>websocket-driver>websocket-extensions": true + } + }, + "firebase>@firebase/database>faye-websocket>websocket-driver>http-parser-js": { + "builtin": { + "assert.equal": true, + "assert.ok": true + } + }, "fs-extra": { "builtin": { "assert": true, @@ -3510,12 +3585,7 @@ }, "gulp-livereload>chalk>ansi-styles": { "packages": { - "gulp-livereload>chalk>ansi-styles>color-convert": true - } - }, - "gulp-livereload>chalk>ansi-styles>color-convert": { - "packages": { - "gulp-livereload>chalk>ansi-styles>color-convert>color-name": true + "@metamask/jazzicon>color>color-convert": true } }, "gulp-livereload>chalk>supports-color": { @@ -3697,31 +3767,7 @@ "setInterval": true }, "packages": { - "gulp-livereload>tiny-lr>faye-websocket>websocket-driver": true - } - }, - "gulp-livereload>tiny-lr>faye-websocket>websocket-driver": { - "builtin": { - "crypto.createHash": true, - "crypto.randomBytes": true, - "events.EventEmitter": true, - "stream.Stream": true, - "url.parse": true, - "util.inherits": true - }, - "globals": { - "Buffer": true, - "process.version.match": true - }, - "packages": { - "gulp-livereload>tiny-lr>faye-websocket>websocket-driver>http-parser-js": true, - "gulp-livereload>tiny-lr>faye-websocket>websocket-driver>websocket-extensions": true - } - }, - "gulp-livereload>tiny-lr>faye-websocket>websocket-driver>http-parser-js": { - "builtin": { - "assert.equal": true, - "assert.ok": true + "firebase>@firebase/database>faye-websocket>websocket-driver": true } }, "gulp-postcss": { @@ -3832,10 +3878,44 @@ "process.nextTick": true }, "packages": { - "readable-stream": true, + "gulp-sort>through2>readable-stream": true, "watchify>xtend": true } }, + "gulp-sort>through2>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "gulp-sort>through2>readable-stream>isarray": true, + "gulp-sort>through2>readable-stream>safe-buffer": true, + "gulp-sort>through2>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "gulp-sort>through2>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "gulp-sort>through2>readable-stream>string_decoder": { + "packages": { + "gulp-sort>through2>readable-stream>safe-buffer": true + } + }, "gulp-sourcemaps": { "builtin": { "path.dirname": true, @@ -3854,13 +3934,13 @@ "gulp-sourcemaps>@gulp-sourcemaps/identity-map": true, "gulp-sourcemaps>@gulp-sourcemaps/map-sources": true, "gulp-sourcemaps>acorn": true, + "gulp-sourcemaps>convert-source-map": true, "gulp-sourcemaps>css": true, "gulp-sourcemaps>debug-fabulous": true, "gulp-sourcemaps>detect-newline": true, "gulp-sourcemaps>source-map": true, "gulp-sourcemaps>strip-bom-string": true, - "gulp-sourcemaps>through2": true, - "nyc>convert-source-map": true + "gulp-sourcemaps>through2": true } }, "gulp-sourcemaps>@gulp-sourcemaps/identity-map": { @@ -3912,26 +3992,7 @@ "process.nextTick": true }, "packages": { - "gulp-sourcemaps>@gulp-sourcemaps/identity-map>through2>readable-stream": true - } - }, - "gulp-sourcemaps>@gulp-sourcemaps/identity-map>through2>readable-stream": { - "builtin": { - "buffer.Buffer": true, - "events.EventEmitter": true, - "stream": true, - "util": true - }, - "globals": { - "process.env.READABLE_STREAM": true, - "process.nextTick": true, - "process.stderr": true, - "process.stdout": true - }, - "packages": { - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream": true } }, "gulp-sourcemaps>@gulp-sourcemaps/map-sources": { @@ -3953,15 +4014,58 @@ "process.nextTick": true }, "packages": { - "readable-stream": true, + "gulp-sourcemaps>@gulp-sourcemaps/map-sources>through2>readable-stream": true, "watchify>xtend": true } }, + "gulp-sourcemaps>@gulp-sourcemaps/map-sources>through2>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "gulp-sourcemaps>@gulp-sourcemaps/map-sources>through2>readable-stream>isarray": true, + "gulp-sourcemaps>@gulp-sourcemaps/map-sources>through2>readable-stream>safe-buffer": true, + "gulp-sourcemaps>@gulp-sourcemaps/map-sources>through2>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "gulp-sourcemaps>@gulp-sourcemaps/map-sources>through2>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "gulp-sourcemaps>@gulp-sourcemaps/map-sources>through2>readable-stream>string_decoder": { + "packages": { + "gulp-sourcemaps>@gulp-sourcemaps/map-sources>through2>readable-stream>safe-buffer": true + } + }, "gulp-sourcemaps>acorn": { "globals": { "define": true } }, + "gulp-sourcemaps>convert-source-map": { + "builtin": { + "fs.readFileSync": true, + "path.join": true + }, + "globals": { + "Buffer.from": true + } + }, "gulp-sourcemaps>css": { "builtin": { "fs.readFileSync": true, @@ -4066,10 +4170,44 @@ "process.nextTick": true }, "packages": { - "readable-stream": true, + "gulp-sourcemaps>through2>readable-stream": true, "watchify>xtend": true } }, + "gulp-sourcemaps>through2>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "gulp-sourcemaps>through2>readable-stream>isarray": true, + "gulp-sourcemaps>through2>readable-stream>safe-buffer": true, + "gulp-sourcemaps>through2>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "gulp-sourcemaps>through2>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "gulp-sourcemaps>through2>readable-stream>string_decoder": { + "packages": { + "gulp-sourcemaps>through2>readable-stream>safe-buffer": true + } + }, "gulp-stylelint": { "builtin": { "fs.mkdir": true, @@ -4099,26 +4237,7 @@ "process.nextTick": true }, "packages": { - "gulp-stylelint>through2>readable-stream": true - } - }, - "gulp-stylelint>through2>readable-stream": { - "builtin": { - "buffer.Buffer": true, - "events.EventEmitter": true, - "stream": true, - "util": true - }, - "globals": { - "process.env.READABLE_STREAM": true, - "process.nextTick": true, - "process.stderr": true, - "process.stdout": true - }, - "packages": { - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream": true } }, "gulp-watch": { @@ -4141,11 +4260,11 @@ "gulp-watch>chokidar": true, "gulp-watch>fancy-log": true, "gulp-watch>path-is-absolute": true, + "gulp-watch>readable-stream": true, "gulp-watch>slash": true, "gulp-watch>vinyl-file": true, "gulp-zip>plugin-error": true, "react>object-assign": true, - "readable-stream": true, "vinyl": true } }, @@ -4995,7 +5114,7 @@ "packages": { "del>graceful-fs": true, "gulp-watch>chokidar>anymatch>micromatch": true, - "readable-stream": true + "gulp-watch>readable-stream": true } }, "gulp-watch>chokidar>upath": { @@ -5021,6 +5140,40 @@ "process.platform": true } }, + "gulp-watch>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "gulp-watch>readable-stream>isarray": true, + "gulp-watch>readable-stream>safe-buffer": true, + "gulp-watch>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "gulp-watch>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "gulp-watch>readable-stream>string_decoder": { + "packages": { + "gulp-watch>readable-stream>safe-buffer": true + } + }, "gulp-watch>vinyl-file": { "builtin": { "path.resolve": true @@ -5056,11 +5209,45 @@ "util.inherits": true }, "globals": { - "Buffer.concat": true, + "Buffer.concat": true, + "setImmediate": true + }, + "packages": { + "gulp-watch>vinyl-file>strip-bom-stream>first-chunk-stream>readable-stream": true + } + }, + "gulp-watch>vinyl-file>strip-bom-stream>first-chunk-stream>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, "setImmediate": true }, "packages": { - "readable-stream": true + "gulp-watch>vinyl-file>strip-bom-stream>first-chunk-stream>readable-stream>isarray": true, + "gulp-watch>vinyl-file>strip-bom-stream>first-chunk-stream>readable-stream>safe-buffer": true, + "gulp-watch>vinyl-file>strip-bom-stream>first-chunk-stream>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "gulp-watch>vinyl-file>strip-bom-stream>first-chunk-stream>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "gulp-watch>vinyl-file>strip-bom-stream>first-chunk-stream>readable-stream>string_decoder": { + "packages": { + "gulp-watch>vinyl-file>strip-bom-stream>first-chunk-stream>readable-stream>safe-buffer": true } }, "gulp-watch>vinyl-file>vinyl": { @@ -5118,7 +5305,7 @@ "Buffer.concat": true }, "packages": { - "pump": true + "pumpify>pump": true } }, "gulp-zip>plugin-error": { @@ -5151,26 +5338,7 @@ "process.nextTick": true }, "packages": { - "gulp-zip>through2>readable-stream": true - } - }, - "gulp-zip>through2>readable-stream": { - "builtin": { - "buffer.Buffer": true, - "events.EventEmitter": true, - "stream": true, - "util": true - }, - "globals": { - "process.env.READABLE_STREAM": true, - "process.nextTick": true, - "process.stderr": true, - "process.stdout": true - }, - "packages": { - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream": true } }, "gulp-zip>yazl": { @@ -5351,10 +5519,10 @@ "process.nextTick": true }, "packages": { - "end-of-stream": true, + "@metamask/object-multiplex>once": true, + "duplexify>end-of-stream": true, "gulp>glob-watcher>async-done>stream-exhaust": true, - "pump>once": true, - "readable-stream>process-nextick-args": true + "readable-stream-2>process-nextick-args": true } }, "gulp>glob-watcher>async-done>stream-exhaust": { @@ -5492,7 +5660,41 @@ "packages": { "del>graceful-fs": true, "gulp>glob-watcher>anymatch>micromatch": true, - "readable-stream": true + "gulp>glob-watcher>chokidar>readdirp>readable-stream": true + } + }, + "gulp>glob-watcher>chokidar>readdirp>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "gulp>glob-watcher>chokidar>readdirp>readable-stream>isarray": true, + "gulp>glob-watcher>chokidar>readdirp>readable-stream>safe-buffer": true, + "gulp>glob-watcher>chokidar>readdirp>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "gulp>glob-watcher>chokidar>readdirp>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "gulp>glob-watcher>chokidar>readdirp>readable-stream>string_decoder": { + "packages": { + "gulp>glob-watcher>chokidar>readdirp>readable-stream>safe-buffer": true } }, "gulp>glob-watcher>chokidar>upath": { @@ -5550,7 +5752,7 @@ "gulp>gulp-cli>matchdep>micromatch>fragment-cache": true, "gulp>gulp-cli>matchdep>micromatch>nanomatch>define-property": true, "gulp>gulp-cli>matchdep>micromatch>regex-not": true, - "nyc>spawn-wrap>is-windows": true + "gulp>gulp-cli>replace-homedir>is-absolute>is-windows": true } }, "gulp>gulp-cli>matchdep>micromatch>nanomatch>define-property": { @@ -5568,7 +5770,7 @@ "gulp>gulp-cli>replace-homedir>is-absolute": { "packages": { "gulp>gulp-cli>replace-homedir>is-absolute>is-relative": true, - "nyc>spawn-wrap>is-windows": true + "gulp>gulp-cli>replace-homedir>is-absolute>is-windows": true } }, "gulp>gulp-cli>replace-homedir>is-absolute>is-relative": { @@ -5581,6 +5783,13 @@ "gulp>gulp-cli>replace-homedir>is-absolute>is-relative>is-unc-path>unc-path-regex": true } }, + "gulp>gulp-cli>replace-homedir>is-absolute>is-windows": { + "globals": { + "define": true, + "isWindows": "write", + "process": true + } + }, "gulp>undertaker": { "builtin": { "assert": true, @@ -5722,6 +5931,7 @@ "gulp>vinyl-fs>lead": true, "gulp>vinyl-fs>object.assign": true, "gulp>vinyl-fs>pumpify": true, + "gulp>vinyl-fs>readable-stream": true, "gulp>vinyl-fs>remove-bom-buffer": true, "gulp>vinyl-fs>remove-bom-stream": true, "gulp>vinyl-fs>resolve-options": true, @@ -5729,7 +5939,6 @@ "gulp>vinyl-fs>to-through": true, "gulp>vinyl-fs>value-or-function": true, "gulp>vinyl-fs>vinyl-sourcemap": true, - "readable-stream": true, "vinyl": true } }, @@ -5754,10 +5963,44 @@ "process.nextTick": true }, "packages": { - "readable-stream": true, + "gulp>vinyl-fs>fs-mkdirp-stream>through2>readable-stream": true, "watchify>xtend": true } }, + "gulp>vinyl-fs>fs-mkdirp-stream>through2>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "gulp>vinyl-fs>fs-mkdirp-stream>through2>readable-stream>isarray": true, + "gulp>vinyl-fs>fs-mkdirp-stream>through2>readable-stream>safe-buffer": true, + "gulp>vinyl-fs>fs-mkdirp-stream>through2>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "gulp>vinyl-fs>fs-mkdirp-stream>through2>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "gulp>vinyl-fs>fs-mkdirp-stream>through2>readable-stream>string_decoder": { + "packages": { + "gulp>vinyl-fs>fs-mkdirp-stream>through2>readable-stream>safe-buffer": true + } + }, "gulp>vinyl-fs>glob-stream": { "builtin": { "util.inherits": true @@ -5767,15 +6010,15 @@ "process.nextTick": true }, "packages": { + "browserify>glob": true, "eslint>glob-parent": true, "gulp>glob-watcher>is-negated-glob": true, "gulp>vinyl-fs>glob-stream>ordered-read-streams": true, "gulp>vinyl-fs>glob-stream>pumpify": true, + "gulp>vinyl-fs>glob-stream>readable-stream": true, "gulp>vinyl-fs>glob-stream>to-absolute-glob": true, "gulp>vinyl-fs>glob-stream>unique-stream": true, - "nyc>glob": true, "react-markdown>unified>extend": true, - "readable-stream": true, "vinyl>remove-trailing-separator": true } }, @@ -5784,7 +6027,41 @@ "util.inherits": true }, "packages": { - "readable-stream": true + "gulp>vinyl-fs>glob-stream>ordered-read-streams>readable-stream": true + } + }, + "gulp>vinyl-fs>glob-stream>ordered-read-streams>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "gulp>vinyl-fs>glob-stream>ordered-read-streams>readable-stream>isarray": true, + "gulp>vinyl-fs>glob-stream>ordered-read-streams>readable-stream>safe-buffer": true, + "gulp>vinyl-fs>glob-stream>ordered-read-streams>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "gulp>vinyl-fs>glob-stream>ordered-read-streams>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "gulp>vinyl-fs>glob-stream>ordered-read-streams>readable-stream>string_decoder": { + "packages": { + "gulp>vinyl-fs>glob-stream>ordered-read-streams>readable-stream>safe-buffer": true } }, "gulp>vinyl-fs>glob-stream>pumpify": { @@ -5800,10 +6077,10 @@ "process.nextTick": true }, "packages": { + "duplexify>end-of-stream": true, "duplexify>stream-shift": true, - "end-of-stream": true, - "pumpify>inherits": true, - "readable-stream": true + "gulp>vinyl-fs>glob-stream>readable-stream": true, + "pumpify>inherits": true } }, "gulp>vinyl-fs>glob-stream>pumpify>pump": { @@ -5811,8 +6088,42 @@ "fs": true }, "packages": { - "end-of-stream": true, - "pump>once": true + "@metamask/object-multiplex>once": true, + "duplexify>end-of-stream": true + } + }, + "gulp>vinyl-fs>glob-stream>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "gulp>vinyl-fs>glob-stream>readable-stream>isarray": true, + "gulp>vinyl-fs>glob-stream>readable-stream>safe-buffer": true, + "gulp>vinyl-fs>glob-stream>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "gulp>vinyl-fs>glob-stream>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "gulp>vinyl-fs>glob-stream>readable-stream>string_decoder": { + "packages": { + "gulp>vinyl-fs>glob-stream>readable-stream>safe-buffer": true } }, "gulp>vinyl-fs>glob-stream>to-absolute-glob": { @@ -5848,16 +6159,84 @@ "process.nextTick": true }, "packages": { - "readable-stream": true, + "gulp>vinyl-fs>glob-stream>unique-stream>through2-filter>through2>readable-stream": true, "watchify>xtend": true } }, + "gulp>vinyl-fs>glob-stream>unique-stream>through2-filter>through2>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "gulp>vinyl-fs>glob-stream>unique-stream>through2-filter>through2>readable-stream>isarray": true, + "gulp>vinyl-fs>glob-stream>unique-stream>through2-filter>through2>readable-stream>safe-buffer": true, + "gulp>vinyl-fs>glob-stream>unique-stream>through2-filter>through2>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "gulp>vinyl-fs>glob-stream>unique-stream>through2-filter>through2>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "gulp>vinyl-fs>glob-stream>unique-stream>through2-filter>through2>readable-stream>string_decoder": { + "packages": { + "gulp>vinyl-fs>glob-stream>unique-stream>through2-filter>through2>readable-stream>safe-buffer": true + } + }, "gulp>vinyl-fs>lazystream": { "builtin": { "util.inherits": true }, "packages": { - "readable-stream": true + "gulp>vinyl-fs>lazystream>readable-stream": true + } + }, + "gulp>vinyl-fs>lazystream>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "gulp>vinyl-fs>lazystream>readable-stream>isarray": true, + "gulp>vinyl-fs>lazystream>readable-stream>safe-buffer": true, + "gulp>vinyl-fs>lazystream>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "gulp>vinyl-fs>lazystream>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "gulp>vinyl-fs>lazystream>readable-stream>string_decoder": { + "packages": { + "gulp>vinyl-fs>lazystream>readable-stream>safe-buffer": true } }, "gulp>vinyl-fs>lead": { @@ -5873,8 +6252,42 @@ "Buffer": true }, "packages": { + "gulp>vinyl-fs>lead>flush-write-stream>readable-stream": true, + "pumpify>inherits": true + } + }, + "gulp>vinyl-fs>lead>flush-write-stream>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "gulp>vinyl-fs>lead>flush-write-stream>readable-stream>isarray": true, + "gulp>vinyl-fs>lead>flush-write-stream>readable-stream>safe-buffer": true, + "gulp>vinyl-fs>lead>flush-write-stream>readable-stream>string_decoder": true, "pumpify>inherits": true, - "readable-stream": true + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "gulp>vinyl-fs>lead>flush-write-stream>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "gulp>vinyl-fs>lead>flush-write-stream>readable-stream>string_decoder": { + "packages": { + "gulp>vinyl-fs>lead>flush-write-stream>readable-stream>safe-buffer": true } }, "gulp>vinyl-fs>object.assign": { @@ -5898,19 +6311,53 @@ "process.nextTick": true }, "packages": { + "duplexify>end-of-stream": true, "duplexify>stream-shift": true, - "end-of-stream": true, + "gulp>vinyl-fs>readable-stream": true, + "pumpify>inherits": true + } + }, + "gulp>vinyl-fs>pumpify>pump": { + "builtin": { + "fs": true + }, + "packages": { + "@metamask/object-multiplex>once": true, + "duplexify>end-of-stream": true + } + }, + "gulp>vinyl-fs>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "gulp>vinyl-fs>readable-stream>isarray": true, + "gulp>vinyl-fs>readable-stream>safe-buffer": true, + "gulp>vinyl-fs>readable-stream>string_decoder": true, "pumpify>inherits": true, - "readable-stream": true + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "gulp>vinyl-fs>readable-stream>safe-buffer": { + "builtin": { + "buffer": true } }, - "gulp>vinyl-fs>pumpify>pump": { - "builtin": { - "fs": true - }, + "gulp>vinyl-fs>readable-stream>string_decoder": { "packages": { - "end-of-stream": true, - "pump>once": true + "gulp>vinyl-fs>readable-stream>safe-buffer": true } }, "gulp>vinyl-fs>remove-bom-buffer": { @@ -5934,10 +6381,49 @@ "process.nextTick": true }, "packages": { - "readable-stream": true, + "gulp>vinyl-fs>remove-bom-stream>through2>readable-stream": true, "watchify>xtend": true } }, + "gulp>vinyl-fs>remove-bom-stream>through2>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "gulp>vinyl-fs>remove-bom-stream>through2>readable-stream>isarray": true, + "gulp>vinyl-fs>remove-bom-stream>through2>readable-stream>safe-buffer": true, + "gulp>vinyl-fs>remove-bom-stream>through2>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "gulp>vinyl-fs>remove-bom-stream>through2>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "gulp>vinyl-fs>remove-bom-stream>through2>readable-stream>string_decoder": { + "packages": { + "gulp>vinyl-fs>remove-bom-stream>through2>readable-stream>string_decoder>safe-buffer": true + } + }, + "gulp>vinyl-fs>remove-bom-stream>through2>readable-stream>string_decoder>safe-buffer": { + "builtin": { + "buffer": true + } + }, "gulp>vinyl-fs>resolve-options": { "packages": { "gulp>vinyl-fs>value-or-function": true @@ -5951,7 +6437,7 @@ "process.nextTick": true }, "packages": { - "readable-stream": true, + "gulp>vinyl-fs>readable-stream": true, "watchify>xtend": true } }, @@ -5968,10 +6454,44 @@ "process.nextTick": true }, "packages": { - "readable-stream": true, + "gulp>vinyl-fs>to-through>through2>readable-stream": true, "watchify>xtend": true } }, + "gulp>vinyl-fs>to-through>through2>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "gulp>vinyl-fs>to-through>through2>readable-stream>isarray": true, + "gulp>vinyl-fs>to-through>through2>readable-stream>safe-buffer": true, + "gulp>vinyl-fs>to-through>through2>readable-stream>string_decoder": true, + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "gulp>vinyl-fs>to-through>through2>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "gulp>vinyl-fs>to-through>through2>readable-stream>string_decoder": { + "packages": { + "gulp>vinyl-fs>to-through>through2>readable-stream>safe-buffer": true + } + }, "gulp>vinyl-fs>vinyl-sourcemap": { "builtin": { "path.dirname": true, @@ -5984,11 +6504,11 @@ }, "packages": { "del>graceful-fs": true, + "gulp-sourcemaps>convert-source-map": true, "gulp>vinyl-fs>remove-bom-buffer": true, "gulp>vinyl-fs>vinyl-sourcemap>append-buffer": true, "gulp>vinyl-fs>vinyl-sourcemap>normalize-path": true, "gulp>vinyl-fs>vinyl-sourcemap>now-and-later": true, - "nyc>convert-source-map": true, "vinyl": true } }, @@ -6015,7 +6535,7 @@ }, "gulp>vinyl-fs>vinyl-sourcemap>now-and-later": { "packages": { - "pump>once": true + "@metamask/object-multiplex>once": true } }, "ini": { @@ -6051,8 +6571,42 @@ "setImmediate": true }, "packages": { + "labeled-stream-splicer>stream-splicer>readable-stream": true, + "pumpify>inherits": true + } + }, + "labeled-stream-splicer>stream-splicer>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "labeled-stream-splicer>stream-splicer>readable-stream>isarray": true, + "labeled-stream-splicer>stream-splicer>readable-stream>safe-buffer": true, + "labeled-stream-splicer>stream-splicer>readable-stream>string_decoder": true, "pumpify>inherits": true, - "readable-stream": true + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true + } + }, + "labeled-stream-splicer>stream-splicer>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "labeled-stream-splicer>stream-splicer>readable-stream>string_decoder": { + "packages": { + "labeled-stream-splicer>stream-splicer>readable-stream>safe-buffer": true } }, "lavamoat-browserify": { @@ -6074,12 +6628,12 @@ "packages": { "@lavamoat/lavapack": true, "@lavamoat/lavapack>json-stable-stringify": true, - "@lavamoat/lavapack>lavamoat-core": true, "browserify>browser-resolve": true, "duplexify": true, "lavamoat-browserify>concat-stream": true, - "lavamoat-browserify>readable-stream": true, + "lavamoat-viz>lavamoat-core": true, "lavamoat>@lavamoat/aa": true, + "readable-stream": true, "through2": true } }, @@ -6090,39 +6644,79 @@ }, "packages": { "browserify>concat-stream>typedarray": true, - "lavamoat-browserify>readable-stream": true, "pumpify>inherits": true, + "readable-stream": true, "terser>source-map-support>buffer-from": true } }, - "lavamoat-browserify>readable-stream": { + "lavamoat-viz>lavamoat-core": { "builtin": { - "buffer.Buffer": true, - "events.EventEmitter": true, - "stream": true, - "util": true + "node:events": true, + "node:fs.readFileSync": true, + "node:fs/promises.writeFile": true, + "node:path.extname": true, + "node:path.join": true }, "globals": { - "process.env.READABLE_STREAM": true, - "process.nextTick": true, - "process.stderr": true, - "process.stdout": true + "__dirname": true, + "console.error": true, + "console.warn": true, + "define": true }, "packages": { - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "@lavamoat/lavapack>json-stable-stringify": true, + "lavamoat-viz>lavamoat-core>lavamoat-tofu": true, + "lavamoat>lavamoat-core>merge-deep": true + } + }, + "lavamoat-viz>lavamoat-core>lavamoat-tofu": { + "globals": { + "console.log": true + }, + "packages": { + "lavamoat-viz>lavamoat-core>lavamoat-tofu>@babel/parser": true, + "lavamoat-viz>lavamoat-core>lavamoat-tofu>@babel/traverse": true + } + }, + "lavamoat-viz>lavamoat-core>lavamoat-tofu>@babel/traverse": { + "globals": { + "console.log": true + }, + "packages": { + "@babel/code-frame": true, + "@babel/core>@babel/generator": true, + "depcheck>@babel/traverse>@babel/helper-environment-visitor": true, + "depcheck>@babel/traverse>@babel/helper-function-name": true, + "depcheck>@babel/traverse>@babel/helper-hoist-variables": true, + "depcheck>@babel/traverse>@babel/helper-split-export-declaration": true, + "lavamoat-viz>lavamoat-core>lavamoat-tofu>@babel/traverse>@babel/parser": true, + "lavamoat-viz>lavamoat-core>lavamoat-tofu>@babel/traverse>@babel/types": true, + "lavamoat-viz>lavamoat-core>lavamoat-tofu>@babel/traverse>globals": true, + "nock>debug": true + } + }, + "lavamoat-viz>lavamoat-core>lavamoat-tofu>@babel/traverse>@babel/types": { + "globals": { + "console.warn": true, + "process.env.BABEL_TYPES_8_BREAKING": true + }, + "packages": { + "@babel/core>@babel/types>@babel/helper-string-parser": true, + "@babel/core>@babel/types>to-fast-properties": true, + "lavamoat>@babel/highlight>@babel/helper-validator-identifier": true } }, "lavamoat>@lavamoat/aa": { "builtin": { - "fs.readFileSync": true, - "path.dirname": true, - "path.join": true, - "path.relative": true + "node:fs.lstatSync": true, + "node:fs.readFileSync": true, + "node:fs.realpathSync": true, + "node:path.dirname": true, + "node:path.join": true, + "node:path.relative": true }, "packages": { - "brfs>resolve": true + "depcheck>resolve": true } }, "lavamoat>lavamoat-core>merge-deep": { @@ -6207,21 +6801,6 @@ "loose-envify>js-tokens": true } }, - "madge>detective-less>gonzales-pe": { - "globals": { - "console.error": true, - "define": true - } - }, - "madge>ora>is-unicode-supported": { - "globals": { - "process.env.CI": true, - "process.env.TERM": true, - "process.env.TERM_PROGRAM": true, - "process.env.WT_SESSION": true, - "process.platform": true - } - }, "mocha>find-up": { "builtin": { "path.dirname": true, @@ -6230,7 +6809,7 @@ }, "packages": { "mocha>find-up>locate-path": true, - "nyc>find-up>path-exists": true + "mocha>find-up>path-exists": true } }, "mocha>find-up>locate-path": { @@ -6251,96 +6830,17 @@ }, "mocha>find-up>locate-path>p-locate": { "packages": { - "copy-webpack-plugin>p-limit": true - } - }, - "mocha>log-symbols": { - "packages": { - "chalk": true, - "madge>ora>is-unicode-supported": true - } - }, - "mocha>supports-color": { - "builtin": { - "os.release": true, - "tty.isatty": true - }, - "globals": { - "process.env": true, - "process.platform": true - }, - "packages": { - "mocha>supports-color>has-flag": true - } - }, - "mocha>supports-color>has-flag": { - "globals": { - "process.argv": true - } - }, - "nock>debug": { - "builtin": { - "tty.isatty": true, - "util.deprecate": true, - "util.format": true, - "util.inspect": true - }, - "globals": { - "console": true, - "document": true, - "localStorage": true, - "navigator": true, - "process": true - }, - "packages": { - "mocha>supports-color": true, - "nock>debug>ms": true - } - }, - "node-sass": { - "native": true - }, - "nyc>convert-source-map": { - "builtin": { - "fs.readFileSync": true, - "path.join": true - }, - "globals": { - "Buffer.from": true + "@storybook/test-runner>jest-circus>p-limit": true } }, - "nyc>find-up>path-exists": { + "mocha>find-up>path-exists": { "builtin": { "fs.access": true, "fs.accessSync": true, "util.promisify": true } }, - "nyc>glob": { - "builtin": { - "assert": true, - "events.EventEmitter": true, - "fs": true, - "path.join": true, - "path.resolve": true, - "util": true - }, - "globals": { - "console.error": true, - "process.cwd": true, - "process.nextTick": true, - "process.platform": true - }, - "packages": { - "eslint>minimatch": true, - "gulp-watch>path-is-absolute": true, - "nyc>glob>fs.realpath": true, - "nyc>glob>inflight": true, - "pump>once": true, - "pumpify>inherits": true - } - }, - "nyc>glob>fs.realpath": { + "mocha>glob>fs.realpath": { "builtin": { "fs.lstat": true, "fs.lstatSync": true, @@ -6365,39 +6865,76 @@ "process.version": true } }, - "nyc>glob>inflight": { + "mocha>glob>inflight": { "globals": { "process.nextTick": true }, "packages": { - "pump>once": true, - "pump>once>wrappy": true + "@metamask/object-multiplex>once": true, + "@metamask/object-multiplex>once>wrappy": true + } + }, + "mocha>log-symbols": { + "packages": { + "chalk": true, + "mocha>log-symbols>is-unicode-supported": true + } + }, + "mocha>log-symbols>is-unicode-supported": { + "globals": { + "process.env.CI": true, + "process.env.TERM": true, + "process.env.TERM_PROGRAM": true, + "process.env.WT_SESSION": true, + "process.platform": true + } + }, + "mocha>supports-color": { + "builtin": { + "os.release": true, + "tty.isatty": true + }, + "globals": { + "process.env": true, + "process.platform": true + }, + "packages": { + "mocha>supports-color>has-flag": true + } + }, + "mocha>supports-color>has-flag": { + "globals": { + "process.argv": true } }, - "nyc>resolve-from": { + "mockttp>portfinder>mkdirp": { "builtin": { - "fs.realpathSync": true, - "module._nodeModulePaths": true, - "module._resolveFilename": true, - "path.join": true, + "fs": true, + "path.dirname": true, "path.resolve": true } }, - "nyc>signal-exit": { + "nock>debug": { "builtin": { - "assert.equal": true, - "events": true + "tty.isatty": true, + "util.deprecate": true, + "util.format": true, + "util.inspect": true }, "globals": { + "console": true, + "document": true, + "localStorage": true, + "navigator": true, "process": true + }, + "packages": { + "mocha>supports-color": true, + "nock>debug>ms": true } }, - "nyc>spawn-wrap>is-windows": { - "globals": { - "define": true, - "isWindows": "write", - "process": true - } + "node-sass": { + "native": true }, "nyc>yargs>set-blocking": { "globals": { @@ -6457,6 +6994,11 @@ "process.platform": true } }, + "postcss>source-map-js": { + "globals": { + "console": true + } + }, "prettier": { "builtin": { "assert": true, @@ -7267,28 +7809,11 @@ "process.env.NODE_ENV": true } }, - "pump": { - "builtin": { - "fs": true - }, - "globals": { - "process.version": true - }, - "packages": { - "end-of-stream": true, - "pump>once": true - } - }, - "pump>once": { - "packages": { - "pump>once>wrappy": true - } - }, "pumpify": { "packages": { "duplexify": true, - "pump": true, - "pumpify>inherits": true + "pumpify>inherits": true, + "pumpify>pump": true } }, "pumpify>inherits": { @@ -7296,6 +7821,18 @@ "util.inherits": true } }, + "pumpify>pump": { + "builtin": { + "fs": true + }, + "globals": { + "process.version": true + }, + "packages": { + "@metamask/object-multiplex>once": true, + "duplexify>end-of-stream": true + } + }, "randomcolor": { "globals": { "define": true @@ -7361,48 +7898,33 @@ }, "readable-stream": { "builtin": { + "buffer.Buffer": true, "events.EventEmitter": true, "stream": true, "util": true }, "globals": { - "process.browser": true, "process.env.READABLE_STREAM": true, + "process.nextTick": true, "process.stderr": true, - "process.stdout": true, - "process.version.slice": true, - "setImmediate": true + "process.stdout": true }, "packages": { + "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>core-util-is": true, - "readable-stream>isarray": true, - "readable-stream>process-nextick-args": true, - "readable-stream>safe-buffer": true, - "readable-stream>string_decoder": true, "readable-stream>util-deprecate": true } }, - "readable-stream>core-util-is": { + "readable-stream-2>core-util-is": { "globals": { "Buffer.isBuffer": true } }, - "readable-stream>process-nextick-args": { + "readable-stream-2>process-nextick-args": { "globals": { "process": true } }, - "readable-stream>safe-buffer": { - "builtin": { - "buffer": true - } - }, - "readable-stream>string_decoder": { - "packages": { - "readable-stream>safe-buffer": true - } - }, "readable-stream>util-deprecate": { "builtin": { "util.deprecate": true @@ -7534,14 +8056,6 @@ "globals": { "console.error": true, "process": true - }, - "packages": { - "semver>lru-cache": true - } - }, - "semver>lru-cache": { - "packages": { - "semver>lru-cache>yallist": true } }, "source-map": { @@ -7601,7 +8115,6 @@ }, "string.prototype.matchall>es-abstract": { "packages": { - "brfs>static-module>object-inspect": true, "browserify>has": true, "eslint-plugin-react>array-includes>is-string": true, "string.prototype.matchall>call-bind": true, @@ -7612,6 +8125,7 @@ "string.prototype.matchall>es-abstract>has-proto": true, "string.prototype.matchall>es-abstract>is-callable": true, "string.prototype.matchall>es-abstract>is-regex": true, + "string.prototype.matchall>es-abstract>object-inspect": true, "string.prototype.matchall>es-abstract>safe-regex-test": true, "string.prototype.matchall>es-abstract>string.prototype.trim": true, "string.prototype.matchall>get-intrinsic": true, @@ -7659,6 +8173,15 @@ "string.prototype.matchall>call-bind": true } }, + "string.prototype.matchall>es-abstract>object-inspect": { + "builtin": { + "util.inspect": true + }, + "globals": { + "HTMLElement": true, + "WeakRef": true + } + }, "string.prototype.matchall>es-abstract>safe-regex-test": { "packages": { "string.prototype.matchall>call-bind": true, @@ -7710,8 +8233,8 @@ }, "string.prototype.matchall>side-channel": { "packages": { - "brfs>static-module>object-inspect": true, "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>es-abstract>object-inspect": true, "string.prototype.matchall>get-intrinsic": true } }, @@ -7750,7 +8273,6 @@ "lodash": true, "mocha>log-symbols": true, "nock>debug": true, - "nyc>resolve-from": true, "stylelint>@stylelint/postcss-css-in-js": true, "stylelint>@stylelint/postcss-markdown": true, "stylelint>autoprefixer": true, @@ -7778,6 +8300,7 @@ "stylelint>postcss-selector-parser": true, "stylelint>postcss-syntax": true, "stylelint>postcss-value-parser": true, + "stylelint>resolve-from": true, "stylelint>specificity": true, "stylelint>style-search": true, "stylelint>sugarss": true, @@ -7978,7 +8501,7 @@ "setTimeout": true }, "packages": { - "nyc>glob": true + "browserify>glob": true } }, "stylelint>file-entry-cache>flat-cache>write": { @@ -7989,14 +8512,7 @@ "path.dirname": true }, "packages": { - "stylelint>file-entry-cache>flat-cache>write>mkdirp": true - } - }, - "stylelint>file-entry-cache>flat-cache>write>mkdirp": { - "builtin": { - "fs": true, - "path.dirname": true, - "path.resolve": true + "mockttp>portfinder>mkdirp": true } }, "stylelint>global-modules": { @@ -8097,11 +8613,11 @@ }, "packages": { "pumpify>inherits": true, + "readable-stream": true, "stylelint>postcss-html>htmlparser2>domelementtype": true, "stylelint>postcss-html>htmlparser2>domhandler": true, "stylelint>postcss-html>htmlparser2>domutils": true, - "stylelint>postcss-html>htmlparser2>entities": true, - "stylelint>postcss-html>htmlparser2>readable-stream": true + "stylelint>postcss-html>htmlparser2>entities": true } }, "stylelint>postcss-html>htmlparser2>domhandler": { @@ -8121,25 +8637,6 @@ "stylelint>postcss-html>htmlparser2>entities": true } }, - "stylelint>postcss-html>htmlparser2>readable-stream": { - "builtin": { - "buffer.Buffer": true, - "events.EventEmitter": true, - "stream": true, - "util": true - }, - "globals": { - "process.env.READABLE_STREAM": true, - "process.nextTick": true, - "process.stderr": true, - "process.stdout": true - }, - "packages": { - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true - } - }, "stylelint>postcss-less": { "packages": { "stylelint>postcss-less>postcss": true @@ -8211,10 +8708,16 @@ }, "stylelint>postcss-sass": { "packages": { - "madge>detective-less>gonzales-pe": true, + "stylelint>postcss-sass>gonzales-pe": true, "stylelint>postcss-sass>postcss": true } }, + "stylelint>postcss-sass>gonzales-pe": { + "globals": { + "console.error": true, + "define": true + } + }, "stylelint>postcss-sass>postcss": { "builtin": { "fs": true, @@ -8300,6 +8803,15 @@ "process.platform": true } }, + "stylelint>resolve-from": { + "builtin": { + "fs.realpathSync": true, + "module._nodeModulePaths": true, + "module._resolveFilename": true, + "path.join": true, + "path.resolve": true + } + }, "stylelint>specificity": { "globals": { "define": true @@ -8342,12 +8854,17 @@ "process.stdout.write": true }, "packages": { - "eslint>ajv": true, "lodash": true, + "stylelint>table>ajv": true, "stylelint>table>slice-ansi": true, "stylelint>table>string-width": true } }, + "stylelint>table>ajv": { + "packages": { + "eslint>fast-deep-equal": true + } + }, "stylelint>table>slice-ansi": { "packages": { "stylelint>table>slice-ansi>ansi-styles": true, @@ -8357,12 +8874,7 @@ }, "stylelint>table>slice-ansi>ansi-styles": { "packages": { - "stylelint>table>slice-ansi>ansi-styles>color-convert": true - } - }, - "stylelint>table>slice-ansi>ansi-styles>color-convert": { - "packages": { - "stylelint>table>slice-ansi>ansi-styles>color-convert>color-name": true + "@metamask/jazzicon>color>color-convert": true } }, "stylelint>table>string-width": { @@ -8411,11 +8923,20 @@ }, "packages": { "eslint>imurmurhash": true, - "nyc>signal-exit": true, "stylelint>write-file-atomic>is-typedarray": true, + "stylelint>write-file-atomic>signal-exit": true, "stylelint>write-file-atomic>typedarray-to-buffer": true } }, + "stylelint>write-file-atomic>signal-exit": { + "builtin": { + "assert.equal": true, + "events": true + }, + "globals": { + "process": true + } + }, "stylelint>write-file-atomic>typedarray-to-buffer": { "globals": { "Buffer.from": true @@ -8446,10 +8967,9 @@ } }, "terser>@jridgewell/source-map": { - "globals": { - "Buffer": true, - "TextDecoder": true, - "define": true + "packages": { + "terser>@jridgewell/source-map>@jridgewell/gen-mapping": true, + "terser>@jridgewell/source-map>@jridgewell/trace-mapping": true } }, "terser>@jridgewell/source-map>@jridgewell/gen-mapping": { @@ -8511,26 +9031,7 @@ }, "through2": { "packages": { - "through2>readable-stream": true - } - }, - "through2>readable-stream": { - "builtin": { - "buffer.Buffer": true, - "events.EventEmitter": true, - "stream": true, - "util": true - }, - "globals": { - "process.env.READABLE_STREAM": true, - "process.nextTick": true, - "process.stderr": true, - "process.stdout": true - }, - "packages": { - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream": true } }, "ts-node": { @@ -8736,7 +9237,46 @@ }, "packages": { "koa>content-disposition>safe-buffer": true, - "readable-stream": true + "vinyl-buffer>bl>readable-stream": true + } + }, + "vinyl-buffer>bl>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true, + "vinyl-buffer>bl>readable-stream>isarray": true, + "vinyl-buffer>bl>readable-stream>safe-buffer": true, + "vinyl-buffer>bl>readable-stream>string_decoder": true + } + }, + "vinyl-buffer>bl>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "vinyl-buffer>bl>readable-stream>string_decoder": { + "packages": { + "vinyl-buffer>bl>readable-stream>string_decoder>safe-buffer": true + } + }, + "vinyl-buffer>bl>readable-stream>string_decoder>safe-buffer": { + "builtin": { + "buffer": true } }, "vinyl-buffer>through2": { @@ -8747,7 +9287,7 @@ "process.nextTick": true }, "packages": { - "readable-stream": true, + "vinyl-buffer>bl>readable-stream": true, "watchify>xtend": true } }, @@ -8771,10 +9311,44 @@ "process.nextTick": true }, "packages": { - "readable-stream": true, + "vinyl-source-stream>through2>readable-stream": true, "watchify>xtend": true } }, + "vinyl-source-stream>through2>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream-2>process-nextick-args": true, + "readable-stream>util-deprecate": true, + "vinyl-source-stream>through2>readable-stream>isarray": true, + "vinyl-source-stream>through2>readable-stream>safe-buffer": true, + "vinyl-source-stream>through2>readable-stream>string_decoder": true + } + }, + "vinyl-source-stream>through2>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "vinyl-source-stream>through2>readable-stream>string_decoder": { + "packages": { + "vinyl-source-stream>through2>readable-stream>safe-buffer": true + } + }, "vinyl-sourcemaps-apply": { "packages": { "vinyl-sourcemaps-apply>source-map": true @@ -8816,10 +9390,49 @@ "process.nextTick": true }, "packages": { - "readable-stream": true, + "vinyl>cloneable-readable>through2>readable-stream": true, "watchify>xtend": true } }, + "vinyl>cloneable-readable>through2>readable-stream": { + "builtin": { + "events.EventEmitter": true, + "stream": true, + "util": true + }, + "globals": { + "process.browser": true, + "process.env.READABLE_STREAM": true, + "process.stderr": true, + "process.stdout": true, + "process.version.slice": true, + "setImmediate": true + }, + "packages": { + "pumpify>inherits": true, + "readable-stream-2>core-util-is": true, + "readable-stream>util-deprecate": true, + "vinyl>cloneable-readable>through2>readable-stream>isarray": true, + "vinyl>cloneable-readable>through2>readable-stream>process-nextick-args": true, + "vinyl>cloneable-readable>through2>readable-stream>safe-buffer": true, + "vinyl>cloneable-readable>through2>readable-stream>string_decoder": true + } + }, + "vinyl>cloneable-readable>through2>readable-stream>process-nextick-args": { + "globals": { + "process": true + } + }, + "vinyl>cloneable-readable>through2>readable-stream>safe-buffer": { + "builtin": { + "buffer": true + } + }, + "vinyl>cloneable-readable>through2>readable-stream>string_decoder": { + "packages": { + "vinyl>cloneable-readable>through2>readable-stream>safe-buffer": true + } + }, "vinyl>remove-trailing-separator": { "globals": { "process.platform": true @@ -8867,6 +9480,7 @@ "path.basename": true, "path.dirname": true, "path.join": true, + "path.relative": true, "path.resolve": true }, "globals": { diff --git a/nyc.config.js b/nyc.config.js deleted file mode 100644 index 408ea27b427b..000000000000 --- a/nyc.config.js +++ /dev/null @@ -1,17 +0,0 @@ -// nyc is our coverage reporter for mocha, and currently is collecting -// coverage for .yarn folder. all of these are default excludes except the -// .yarn/** entry. This entire file should be removable once we complete the -// migration from mocha to jest in the app folder. -module.exports = { - exclude: [ - 'coverage/**', - 'packages/*/test/**', - 'test/**', - 'test{,-*}.js', - '**/*{.,-}test.js', - '**/__tests__/**', - '**/node_modules/**', - '**/babel.config.js', - '.yarn/**', - ], -}; diff --git a/offscreen/offscreen.html b/offscreen/offscreen.html index 7290b9b945c5..ea5ad76dd7a7 100644 --- a/offscreen/offscreen.html +++ b/offscreen/offscreen.html @@ -5,10 +5,6 @@ MetaMask Offscreen Page - - + diff --git a/offscreen/scripts/callback-processor.ts b/offscreen/scripts/callback-processor.ts index 83b062811173..36fa3ae9f9c4 100644 --- a/offscreen/scripts/callback-processor.ts +++ b/offscreen/scripts/callback-processor.ts @@ -11,8 +11,12 @@ export class CallbackProcessor { currentMessageId = 0; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any messageCallbacks = new Map void>(); + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any registerCallback(callback: (response?: any) => void) { this.currentMessageId += 1; this.messageCallbacks.set(this.currentMessageId, callback); diff --git a/offscreen/scripts/ledger.ts b/offscreen/scripts/ledger.ts index 6ed42b0dc858..9fe1f4f10c37 100644 --- a/offscreen/scripts/ledger.ts +++ b/offscreen/scripts/ledger.ts @@ -17,7 +17,10 @@ const LEDGER_KEYRING_IFRAME_CONNECTED_EVENT = 'ledger-connection-event'; const callbackProcessor = new CallbackProcessor(); export default function init() { - const iframe = document.querySelector('iframe'); + const iframe = document.createElement('iframe'); + iframe.src = 'https://metamask.github.io/eth-ledger-bridge-keyring'; + iframe.allow = 'hid'; + document.body.appendChild(iframe); // This listener receives action responses from the live ledger iframe // Then forwards the response to the offscreen bridge window.addEventListener('message', ({ origin, data, source }) => { @@ -50,6 +53,8 @@ export default function init() { msg: { target: string; action: LedgerAction; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any params: any; }, _sender, diff --git a/offscreen/scripts/offscreen.ts b/offscreen/scripts/offscreen.ts index 8c0598b4bd3f..654c99151c28 100644 --- a/offscreen/scripts/offscreen.ts +++ b/offscreen/scripts/offscreen.ts @@ -1,5 +1,6 @@ import { BrowserRuntimePostMessageStream } from '@metamask/post-message-stream'; import { ProxySnapExecutor } from '@metamask/snaps-execution-environments'; +import { OffscreenCommunicationTarget } from '../../shared/constants/offscreen-communication'; import initLedger from './ledger'; import initTrezor from './trezor'; import initLattice from './lattice'; @@ -19,4 +20,9 @@ const parentStream = new BrowserRuntimePostMessageStream({ target: 'parent', }); -ProxySnapExecutor.initialize(parentStream); +ProxySnapExecutor.initialize(parentStream, './snaps/index.html'); + +chrome.runtime.sendMessage({ + target: OffscreenCommunicationTarget.extensionMain, + isBooted: true, +}); diff --git a/offscreen/scripts/trezor.ts b/offscreen/scripts/trezor.ts index 34274be8652c..e9482a03c575 100644 --- a/offscreen/scripts/trezor.ts +++ b/offscreen/scripts/trezor.ts @@ -18,6 +18,8 @@ export default function init() { msg: { target: string; action: TrezorAction; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any params: any; }, _sender, diff --git a/package.json b/package.json index 301b8e61bc8a..afb8a17584f6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "11.10.0", + "version": "11.16.7", "private": true, "repository": { "type": "git", @@ -8,58 +8,59 @@ }, "scripts": { "start": "yarn build:dev dev --apply-lavamoat=false --snow=false", - "start:mv3": "ENABLE_MV3=true yarn build:dev dev --apply-lavamoat=false", + "start:skip-onboarding": "SKIP_ONBOARDING=true yarn start", + "start:mv2": "ENABLE_MV3=false yarn build:dev dev --apply-lavamoat=false --snow=false", "start:flask": "yarn start --build-type flask", "start:mmi": "yarn start --build-type mmi", "start:lavamoat": "yarn build:dev dev --apply-lavamoat=true", "dist": "yarn build dist", - "dist:mv3": "ENABLE_MV3=true yarn build dist", + "dist:mv2": "ENABLE_MV3=false yarn build dist", "dist:mmi": "yarn dist --build-type mmi", - "dist:mmi:debug": "yarn dist --build-type mmi --apply-lavamoat=false", + "dist:mmi:debug": "yarn dist --build-type mmi --apply-lavamoat=false --snow=false", "build": "yarn lavamoat:build", "build:dev": "node development/build/index.js", - "start:test": "BLOCKAID_FILE_CDN=static.cx.metamask.io/api/v1/confirmations/ppom SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 yarn build:dev testDev --apply-lavamoat=false --snow=false", + "start:test": "SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 yarn build:dev testDev", "start:test:flask": "SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 yarn build:dev testDev --build-type flask --apply-lavamoat=false --snow=false", - "start:test:mv3": "ENABLE_MV3=true SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 yarn build:dev testDev", + "start:test:mv2:flask": "ENABLE_MV3=false SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 yarn build:dev testDev --build-type flask --apply-lavamoat=false --snow=false", + "start:test:mv2": "ENABLE_MV3=false BLOCKAID_FILE_CDN=static.cx.metamask.io/api/v1/confirmations/ppom SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 yarn build:dev testDev --apply-lavamoat=false --snow=false", "benchmark:chrome": "SELENIUM_BROWSER=chrome ts-node test/e2e/benchmark.js", - "mv3:stats:chrome": "SELENIUM_BROWSER=chrome ENABLE_MV3=true ts-node test/e2e/mv3-perf-stats/index.js", + "mv3:stats:chrome": "SELENIUM_BROWSER=chrome ts-node test/e2e/mv3-perf-stats/index.js", "user-actions-benchmark:chrome": "SELENIUM_BROWSER=chrome ts-node test/e2e/user-actions-benchmark.js", "benchmark:firefox": "SELENIUM_BROWSER=firefox ts-node test/e2e/benchmark.js", - "build:test": "BLOCKAID_FILE_CDN=static.cx.metamask.io/api/v1/confirmations/ppom SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 yarn build test", + "build:test": "SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 yarn build test", + "build:test:dev": "SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 yarn build:dev testDev --apply-lavamoat=false", "build:test:flask": "SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' yarn build test --build-type flask", + "build:test:flask:mv2": "ENABLE_MV3=false SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' yarn build test --build-type flask", "build:test:mmi": "SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' yarn build test --build-type mmi", - "build:test:mv3": "ENABLE_MV3=true SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 yarn build test", - "build:test:dev:mv3": "ENABLE_MV3=true SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 yarn build:dev testDev --apply-lavamoat=false", + "build:test:mv2": "ENABLE_MV3=false BLOCKAID_FILE_CDN=static.cx.metamask.io/api/v1/confirmations/ppom SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 yarn build test", "test": "yarn lint && yarn test:unit && yarn test:unit:jest", "dapp": "node development/static-server.js node_modules/@metamask/test-dapp/dist --port 8080", "dapp-chain": "GANACHE_ARGS='-b 2' concurrently -k -n ganache,dapp -p '[{time}][{name}]' 'yarn ganache:start' 'sleep 5 && yarn dapp'", "forwarder": "node ./development/static-server.js ./node_modules/@metamask/forwarder/dist/ --port 9010", "dapp-forwarder": "concurrently -k -n forwarder,dapp -p '[{time}][{name}]' 'yarn forwarder' 'yarn dapp'", - "test:unit": "node ./test/run-unit-tests.js --mocha --jestGlobal --jestDev", + "test:unit": "node ./test/run-unit-tests.js --jestGlobal --jestDev", "test:unit:jest": "node ./test/run-unit-tests.js --jestGlobal --jestDev", "test:unit:jest:watch": "node --inspect ./node_modules/.bin/jest --watch", "test:unit:global": "mocha test/unit-global/*.test.js", - "test:unit:mocha": "node ./test/run-unit-tests.js --mocha", "test:e2e:chrome": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js", "test:e2e:chrome:mmi": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --mmi", "test:e2e:chrome:flask": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --build-type flask", + "test:api-specs": "SELENIUM_BROWSER=chrome ts-node test/e2e/run-openrpc-api-test-coverage.ts", "test:e2e:mmi:ci": "yarn playwright test", "test:e2e:mmi:all": "yarn playwright test --project=mmi && yarn test:e2e:mmi:visual", "test:e2e:mmi:regular": "yarn playwright test --project=mmi", "test:e2e:mmi:visual": "./test/e2e/mmi/scripts/run-visual-test.sh check", "test:e2e:mmi:visual:update": "./test/e2e/mmi/scripts/run-visual-test.sh update", "test:e2e:pw:report": "yarn playwright show-report public/playwright/playwright-reports/html", - "test:e2e:chrome:mv3": "ENABLE_MV3=true SELENIUM_BROWSER=chrome node test/e2e/run-all.js", + "test:e2e:chrome:confirmation-redesign": "ENABLE_CONFIRMATION_REDESIGN=true SELENIUM_BROWSER=chrome node test/e2e/run-all.js", "test:e2e:chrome:rpc": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --rpc", "test:e2e:chrome:multi-provider": "MULTIPROVIDER=true SELENIUM_BROWSER=chrome node test/e2e/run-all.js --multi-provider", "test:e2e:firefox": "SELENIUM_BROWSER=firefox node test/e2e/run-all.js", "test:e2e:firefox:flask": "SELENIUM_BROWSER=firefox node test/e2e/run-all.js --build-type flask", "test:e2e:single": "node test/e2e/run-e2e-test.js", - "test:coverage:mocha": "node ./test/run-unit-tests.js --mocha --coverage", "test:coverage:jest": "node ./test/run-unit-tests.js --jestGlobal --coverage", "test:coverage:jest:dev": "node ./test/run-unit-tests.js --jestDev --coverage", - "test:coverage:validate": "node ./test/merge-coverage.js", - "test:coverage": "node ./test/run-unit-tests.js --mocha --jestGlobal --jestDev --coverage && yarn test:coverage:validate", + "test:coverage": "node ./test/run-unit-tests.js --jestGlobal --jestDev --coverage", "test:coverage:html": "yarn test:coverage --html", "ganache:start": "./development/run-ganache.sh", "sentry:publish": "node ./development/sentry-publish.js", @@ -96,8 +97,9 @@ "lavamoat:build": "lavamoat development/build/index.js --policy lavamoat/build-system/policy.json --policyOverride lavamoat/build-system/policy-override.json", "lavamoat:build:auto": "yarn lavamoat:build --writeAutoPolicy", "lavamoat:debug:build": "yarn lavamoat:build --writeAutoPolicyDebug --policydebug lavamoat/build-system/policy-debug.json", - "lavamoat:webapp:auto": "node ./development/generate-lavamoat-policies.js --devMode=true", - "lavamoat:webapp:auto:ci": "node ./development/generate-lavamoat-policies.js --parallel=false", + "lavamoat:debug:webapp": "WRITE_AUTO_POLICY_DEBUG=1 yarn lavamoat:webapp:auto", + "lavamoat:webapp:auto": "ENABLE_MV3=true node ./development/generate-lavamoat-policies.js --devMode=true", + "lavamoat:webapp:auto:ci": "ENABLE_MV3=true node ./development/generate-lavamoat-policies.js --parallel=false", "lavamoat:auto": "yarn lavamoat:build:auto && yarn lavamoat:webapp:auto", "ts-migration:dashboard:build": "ts-node development/ts-migration-dashboard/scripts/build-app.ts", "ts-migration:dashboard:deploy": "gh-pages --dist development/ts-migration-dashboard/build/final --remote ts-migration-dashboard", @@ -110,18 +112,21 @@ "generate-beta-commit": "node ./development/generate-beta-commit.js", "validate-branch-name": "validate-branch-name", "add-release-label-to-pr-and-linked-issues": "ts-node ./.github/scripts/add-release-label-to-pr-and-linked-issues.ts", + "add-team-label-to-pr": "ts-node ./.github/scripts/add-team-label-to-pr.ts", "check-pr-has-required-labels": "ts-node ./.github/scripts/check-pr-has-required-labels.ts", "close-release-bug-report-issue": "ts-node ./.github/scripts/close-release-bug-report-issue.ts", "check-template-and-add-labels": "ts-node ./.github/scripts/check-template-and-add-labels.ts", "audit": "yarn npm audit --recursive --environment production --severity moderate --ignore '@metamask/types (deprecation)'", "download-builds": "tsx .devcontainer/download-builds.ts prep-build", "download-builds:test": "tsx .devcontainer/download-builds.ts prep-build-test", - "master-sync": "node development/master-sync.js" + "master-sync": "node development/master-sync.js", + "update-mock-cdn": "node test/e2e/mock-cdn/update-mock-cdn-files.js", + "attributions:check": "./development/attributions-check.sh", + "attributions:generate": "./development/generate-attributions.sh" }, "resolutions": { "simple-update-notifier@^1.0.0": "^2.0.0", "@babel/core": "patch:@babel/core@npm%3A7.23.2#~/.yarn/patches/@babel-core-npm-7.23.2-b93f586907.patch", - "@babel/runtime": "patch:@babel/runtime@npm%3A7.23.2#~/.yarn/patches/@babel-runtime-npm-7.23.2-d013d6cf7e.patch", "@types/react": "^16.9.53", "analytics-node/axios": "^0.21.2", "bn.js": "^5.2.1", @@ -184,15 +189,15 @@ "regenerator-runtime@^0.13.4": "patch:regenerator-runtime@npm%3A0.13.7#./.yarn/patches/regenerator-runtime-npm-0.13.7-41bcbe64ea.patch", "regenerator-runtime@^0.13.7": "patch:regenerator-runtime@npm%3A0.13.7#./.yarn/patches/regenerator-runtime-npm-0.13.7-41bcbe64ea.patch", "regenerator-runtime@^0.11.0": "patch:regenerator-runtime@npm%3A0.13.7#./.yarn/patches/regenerator-runtime-npm-0.13.7-41bcbe64ea.patch", + "ws@8.13.0": "^8.17.1", + "ws@7.4.6": "^7.5.10", "jsdom@^16.7.0": "patch:jsdom@npm%3A16.7.0#./.yarn/patches/jsdom-npm-16.7.0-216c5c4bf9.patch", "trim": "^0.0.3", "@eslint/eslintrc@npm:^2.1.4": "patch:@eslint/eslintrc@npm%3A2.1.4#~/.yarn/patches/@eslint-eslintrc-npm-2.1.4-1ff4b5f908.patch", "@fortawesome/fontawesome-free@^5.13.0": "patch:@fortawesome/fontawesome-free@npm%3A5.13.0#./.yarn/patches/@fortawesome-fontawesome-free-npm-5.13.0-f20fc0388d.patch", "@keystonehq/bc-ur-registry@^0.5.0-alpha.5": "patch:@keystonehq/bc-ur-registry@npm%3A0.5.0-alpha.5#./.yarn/patches/@keystonehq-bc-ur-registry-npm-0.5.0-alpha.5-b95c7992a6.patch", "fast-json-patch@^3.1.0": "patch:fast-json-patch@npm%3A3.1.1#./.yarn/patches/fast-json-patch-npm-3.1.1-7e8bb70a45.patch", - "@reduxjs/toolkit@^1.6.2": "patch:@reduxjs/toolkit@npm%3A1.6.2#./.yarn/patches/@reduxjs-toolkit-npm-1.6.2-67af09515f.patch", "parse5@^7.0.0": "patch:parse5@npm%3A7.1.2#./.yarn/patches/parse5-npm-7.1.2-aa9a92c270.patch", - "@types/madge@^5.0.0": "patch:@types/madge@npm%3A5.0.0#./.yarn/patches/@types-madge-npm-5.0.0-654566c2d2.patch", "zxcvbn@^4.4.2": "patch:zxcvbn@npm%3A4.4.2#./.yarn/patches/zxcvbn-npm-4.4.2-6527983856.patch", "web3@^0.20.7": "patch:web3@npm%3A0.20.7#./.yarn/patches/web3-npm-0.20.7-ee7ef00c57.patch", "watchify@^4.0.0": "patch:watchify@npm%3A4.0.0#./.yarn/patches/watchify-npm-4.0.0-4fd965dd49.patch", @@ -205,126 +210,166 @@ "async-done@^1.2.0": "patch:async-done@npm%3A1.3.2#./.yarn/patches/async-done-npm-1.3.2-1f0a4a8997.patch", "async-done@^1.2.2": "patch:async-done@npm%3A1.3.2#./.yarn/patches/async-done-npm-1.3.2-1f0a4a8997.patch", "fast-json-patch@^3.1.1": "patch:fast-json-patch@npm%3A3.1.1#./.yarn/patches/fast-json-patch-npm-3.1.1-7e8bb70a45.patch", + "@types/readable-stream-2@^2.3.15": "npm:@types/readable-stream@^2.3.15", + "@types/readable-stream-3@^4.0.4": "npm:@types/readable-stream@^4.0.4", + "readable-stream-2@^2.3.3": "npm:readable-stream@^2.3.3", + "readable-stream-3@^3.6.2": "npm:readable-stream@^3.6.2", "request@^2.83.0": "patch:request@npm%3A2.88.2#./.yarn/patches/request-npm-2.88.2-f4a57c72c4.patch", "request@^2.88.2": "patch:request@npm%3A2.88.2#./.yarn/patches/request-npm-2.88.2-f4a57c72c4.patch", "request@^2.85.0": "patch:request@npm%3A2.88.2#./.yarn/patches/request-npm-2.88.2-f4a57c72c4.patch", "semver@7.3.7": "^7.5.4", "semver@7.3.8": "^7.5.4", - "nonce-tracker@npm:^3.0.0": "patch:nonce-tracker@npm%3A3.0.0#~/.yarn/patches/nonce-tracker-npm-3.0.0-c5e9a93f9d.patch", - "@trezor/connect-web": "9.0.11", + "@trezor/schema-utils@npm:1.0.2": "patch:@trezor/schema-utils@npm%3A1.0.2#~/.yarn/patches/@trezor-schema-utils-npm-1.0.2-7dd48689b2.patch", "lavamoat-core@npm:^15.1.1": "patch:lavamoat-core@npm%3A15.1.1#~/.yarn/patches/lavamoat-core-npm-15.1.1-51fbe39988.patch", - "@metamask/snaps-sdk": "^3.1.1" + "@metamask/snaps-sdk": "^5.0.0", + "@metamask/transaction-controller": "^32.0.0", + "@babel/runtime@npm:^7.7.6": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.9.2": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.12.5": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.10.3": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.5.5": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.3.1": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.0.0": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.1.2": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.12.13": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.4.4": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.10.2": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.21.0": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.17.8": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.13.10": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.12.0": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.8.7": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.4.0": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.18.3": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.8.3": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@babel/runtime@npm:^7.8.4": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@spruceid/siwe-parser@npm:1.1.3": "patch:@spruceid/siwe-parser@npm%3A2.1.0#~/.yarn/patches/@spruceid-siwe-parser-npm-2.1.0-060b7ede7a.patch", + "@spruceid/siwe-parser@npm:2.1.0": "patch:@spruceid/siwe-parser@npm%3A2.1.0#~/.yarn/patches/@spruceid-siwe-parser-npm-2.1.0-060b7ede7a.patch", + "@trezor/connect-web@npm:^9.2.2": "patch:@trezor/connect-web@npm%3A9.2.2#~/.yarn/patches/@trezor-connect-web-npm-9.2.2-a4de8e45fc.patch", + "ts-mixer@npm:^6.0.3": "patch:ts-mixer@npm%3A6.0.4#~/.yarn/patches/ts-mixer-npm-6.0.4-5d9747bdf5.patch", + "sucrase@npm:3.34.0": "^3.35.0", + "@expo/config/glob": "^10.3.10", + "@expo/config-plugins/glob": "^10.3.10", + "@metamask/network-controller": "patch:@metamask/network-controller@npm%3A19.0.0#~/.yarn/patches/@metamask-network-controller-npm-19.0.0-a5e0d1fe14.patch", + "@solana/web3.js/rpc-websockets": "^8.0.1", + "@metamask/network-controller@npm:^19.0.0": "patch:@metamask/network-controller@npm%3A19.0.0#~/.yarn/patches/@metamask-network-controller-npm-19.0.0-a5e0d1fe14.patch", + "@metamask/gas-fee-controller@npm:^15.1.1": "patch:@metamask/gas-fee-controller@npm%3A15.1.2#~/.yarn/patches/@metamask-gas-fee-controller-npm-15.1.2-db4d2976aa.patch", + "@metamask/nonce-tracker@npm:^5.0.0": "patch:@metamask/nonce-tracker@npm%3A5.0.0#~/.yarn/patches/@metamask-nonce-tracker-npm-5.0.0-d81478218e.patch" }, "dependencies": { - "@babel/runtime": "^7.23.2", - "@blockaid/ppom_release": "^1.4.4", + "@babel/runtime": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", + "@blockaid/ppom_release": "^1.4.8", + "@contentful/rich-text-html-renderer": "^16.3.5", "@ensdomains/content-hash": "^2.5.7", - "@ethereumjs/common": "^3.1.1", "@ethereumjs/tx": "^4.1.1", "@ethersproject/abi": "^5.6.4", "@ethersproject/bignumber": "^5.7.0", "@ethersproject/contracts": "^5.7.0", + "@ethersproject/hash": "^5.7.0", "@ethersproject/hdnode": "^5.6.2", "@ethersproject/providers": "^5.7.2", + "@ethersproject/wallet": "^5.7.0", "@fortawesome/fontawesome-free": "^5.13.0", "@keystonehq/bc-ur-registry-eth": "^0.19.1", "@keystonehq/metamask-airgapped-keyring": "^0.13.1", "@lavamoat/lavadome-react": "0.0.17", "@lavamoat/snow": "^2.0.1", "@material-ui/core": "^4.11.0", - "@metamask-institutional/custody-controller": "^0.2.22", - "@metamask-institutional/custody-keyring": "^1.0.10", - "@metamask-institutional/extension": "^0.3.16", - "@metamask-institutional/institutional-features": "^1.2.11", - "@metamask-institutional/portfolio-dashboard": "^1.4.0", - "@metamask-institutional/rpc-allowlist": "^1.0.0", - "@metamask-institutional/sdk": "^0.1.23", - "@metamask-institutional/transaction-update": "^0.1.32", + "@metamask-institutional/custody-controller": "^0.2.30", + "@metamask-institutional/custody-keyring": "^2.0.3", + "@metamask-institutional/extension": "^0.3.27", + "@metamask-institutional/institutional-features": "^1.3.5", + "@metamask-institutional/portfolio-dashboard": "^1.4.1", + "@metamask-institutional/rpc-allowlist": "^1.0.3", + "@metamask-institutional/sdk": "^0.1.30", + "@metamask-institutional/transaction-update": "^0.2.5", "@metamask/abi-utils": "^2.0.2", - "@metamask/accounts-controller": "^11.0.0", - "@metamask/address-book-controller": "^3.0.0", - "@metamask/announcement-controller": "^5.0.1", - "@metamask/approval-controller": "^5.1.2", - "@metamask/assets-controllers": "^26.0.0", - "@metamask/base-controller": "^4.1.0", + "@metamask/accounts-controller": "^16.0.0", + "@metamask/address-book-controller": "^4.0.1", + "@metamask/announcement-controller": "^6.1.0", + "@metamask/approval-controller": "^7.0.0", + "@metamask/assets-controllers": "patch:@metamask/assets-controllers@patch%3A@metamask/assets-controllers@patch%253A@metamask/assets-controllers@npm%25253A30.0.0%2523~/.yarn/patches/@metamask-assets-controllers-npm-30.0.0-8747c20871.patch%253A%253Aversion=30.0.0&hash=9269c8%23~/.yarn/patches/@metamask-assets-controllers-patch-26d4328777.patch%3A%3Aversion=30.0.0&hash=1ba1a6#~/.yarn/patches/@metamask-assets-controllers-patch-a3b39b55a6.patch", + "@metamask/base-controller": "^5.0.1", "@metamask/browser-passworder": "^4.3.0", - "@metamask/contract-metadata": "^2.3.1", - "@metamask/controller-utils": "^8.0.4", - "@metamask/design-tokens": "^2.1.1", - "@metamask/desktop": "^0.3.0", - "@metamask/ens-controller": "^9.0.0", + "@metamask/contract-metadata": "^2.5.0", + "@metamask/controller-utils": "^10.0.0", + "@metamask/design-tokens": "^4.0.0", + "@metamask/ens-controller": "^10.0.1", "@metamask/eth-json-rpc-filters": "^7.0.0", - "@metamask/eth-json-rpc-middleware": "^12.1.0", - "@metamask/eth-keyring-controller": "^16.0.0", + "@metamask/eth-json-rpc-middleware": "^12.1.1", "@metamask/eth-ledger-bridge-keyring": "^2.0.1", "@metamask/eth-query": "^4.0.0", "@metamask/eth-sig-util": "^7.0.1", - "@metamask/eth-snap-keyring": "^2.1.2", - "@metamask/eth-token-tracker": "^7.0.2", - "@metamask/eth-trezor-keyring": "^3.0.0", + "@metamask/eth-snap-keyring": "^4.3.1", + "@metamask/eth-token-tracker": "^8.0.0", + "@metamask/eth-trezor-keyring": "^3.1.0", "@metamask/etherscan-link": "^3.0.0", "@metamask/ethjs": "^0.6.0", "@metamask/ethjs-contract": "^0.4.1", "@metamask/ethjs-query": "^0.7.1", - "@metamask/gas-fee-controller": "^13.0.0", + "@metamask/gas-fee-controller": "patch:@metamask/gas-fee-controller@npm%3A15.1.2#~/.yarn/patches/@metamask-gas-fee-controller-npm-15.1.2-db4d2976aa.patch", "@metamask/jazzicon": "^2.0.0", - "@metamask/keyring-api": "^3.0.0", - "@metamask/keyring-controller": "^13.0.0", - "@metamask/logging-controller": "^2.0.2", + "@metamask/keyring-api": "^8.0.0", + "@metamask/keyring-controller": "^16.1.0", + "@metamask/logging-controller": "^3.0.1", "@metamask/logo": "^3.1.2", "@metamask/message-manager": "^7.3.0", - "@metamask/metamask-eth-abis": "^3.0.0", - "@metamask/name-controller": "^4.2.0", - "@metamask/network-controller": "^17.2.0", + "@metamask/message-signing-snap": "^0.3.3", + "@metamask/metamask-eth-abis": "^3.1.1", + "@metamask/name-controller": "^8.0.0", + "@metamask/network-controller": "patch:@metamask/network-controller@npm%3A19.0.0#~/.yarn/patches/@metamask-network-controller-npm-19.0.0-a5e0d1fe14.patch", "@metamask/notification-controller": "^3.0.0", - "@metamask/obs-store": "^8.1.0", - "@metamask/permission-controller": "^8.0.0", - "@metamask/permission-log-controller": "^1.0.0", - "@metamask/phishing-controller": "^8.0.0", + "@metamask/object-multiplex": "^2.0.0", + "@metamask/obs-store": "^9.0.0", + "@metamask/permission-controller": "^10.0.0", + "@metamask/permission-log-controller": "^2.0.1", + "@metamask/phishing-controller": "^9.0.3", "@metamask/post-message-stream": "^8.0.0", - "@metamask/ppom-validator": "^0.27.0", + "@metamask/ppom-validator": "^0.31.0", "@metamask/providers": "^14.0.2", - "@metamask/queued-request-controller": "^0.3.0", - "@metamask/rate-limit-controller": "^3.0.0", - "@metamask/safe-event-emitter": "^2.0.0", + "@metamask/queued-request-controller": "^1.0.0", + "@metamask/rate-limit-controller": "^5.0.1", + "@metamask/rpc-errors": "^6.2.1", + "@metamask/safe-event-emitter": "^3.1.1", "@metamask/scure-bip39": "^2.0.3", - "@metamask/selected-network-controller": "^9.0.0", - "@metamask/signature-controller": "^12.0.0", - "@metamask/smart-transactions-controller": "^6.2.2", - "@metamask/snaps-controllers": "^6.0.3", - "@metamask/snaps-execution-environments": "^5.0.3", - "@metamask/snaps-rpc-methods": "^7.0.1", - "@metamask/snaps-sdk": "^3.1.1", - "@metamask/snaps-utils": "^7.0.3", - "@metamask/transaction-controller": "^23.1.0", - "@metamask/user-operation-controller": "^4.0.0", + "@metamask/selected-network-controller": "^15.0.2", + "@metamask/signature-controller": "^16.0.0", + "@metamask/smart-transactions-controller": "^10.1.2", + "@metamask/snaps-controllers": "^9.0.0", + "@metamask/snaps-execution-environments": "^6.4.0", + "@metamask/snaps-rpc-methods": "^9.1.3", + "@metamask/snaps-sdk": "^5.0.0", + "@metamask/snaps-utils": "^7.6.0", + "@metamask/transaction-controller": "^32.0.0", + "@metamask/user-operation-controller": "^10.0.0", "@metamask/utils": "^8.2.1", - "@ngraveio/bc-ur": "^1.1.6", + "@ngraveio/bc-ur": "^1.1.12", + "@noble/ciphers": "^0.5.2", "@noble/hashes": "^1.3.3", "@popperjs/core": "^2.4.0", - "@reduxjs/toolkit": "^1.6.2", + "@reduxjs/toolkit": "patch:@reduxjs/toolkit@npm%3A1.9.7#~/.yarn/patches/@reduxjs-toolkit-npm-1.9.7-b14925495c.patch", "@segment/loosely-validate-event": "^2.0.0", "@sentry/browser": "^7.53.0", "@sentry/integrations": "^7.53.0", "@sentry/types": "^7.53.0", "@sentry/utils": "^7.53.0", - "@trezor/connect-web": "9.0.11", + "@trezor/connect-web": "patch:@trezor/connect-web@npm%3A9.2.2#~/.yarn/patches/@trezor-connect-web-npm-9.2.2-a4de8e45fc.patch", "@zxing/browser": "^0.1.4", "@zxing/library": "0.20.0", "await-semaphore": "^0.1.1", "base32-encode": "^1.2.0", "base64-js": "^1.5.1", "bignumber.js": "^4.1.0", - "blo": "1.1.1", + "blo": "1.2.0", "bn.js": "^5.2.1", "bowser": "^2.11.0", "chart.js": "^4.4.1", "classnames": "^2.2.6", + "contentful": "^10.8.7", "copy-to-clipboard": "^3.3.3", "currency-formatter": "^1.4.2", "debounce-stream": "^2.0.0", "deep-freeze-strict": "1.1.1", - "end-of-stream": "^1.4.4", "eth-ens-namehash": "^2.0.8", "eth-lattice-keyring": "^0.12.4", "eth-method-registry": "^4.0.0", @@ -333,7 +378,9 @@ "ethereumjs-util": "^7.0.10", "extension-port-stream": "^3.0.0", "fast-json-patch": "^3.1.1", + "firebase": "^10.11.0", "fuse.js": "^3.2.0", + "he": "^1.2.0", "human-standard-token-abi": "^2.0.0", "immer": "^9.0.6", "is-retry-allowed": "^2.2.0", @@ -346,14 +393,12 @@ "loglevel": "^1.8.1", "luxon": "^3.2.1", "nanoid": "^2.1.6", - "obj-multiplex": "^1.0.0", "pify": "^5.0.0", "promise-to-callback": "^1.0.0", "prop-types": "^15.6.1", - "pump": "^3.0.0", "punycode": "^2.1.1", "qrcode-generator": "1.4.1", - "qrcode.react": "^1.0.1", + "qrcode.react": "^3.1.0", "react": "^16.12.0", "react-beautiful-dnd": "^13.1.1", "react-chartjs-2": "^5.2.0", @@ -363,14 +408,14 @@ "react-inspector": "^6.0.2", "react-markdown": "^6.0.3", "react-popper": "^2.2.3", - "react-redux": "^7.2.0", + "react-redux": "^7.2.9", "react-responsive-carousel": "^3.2.21", "react-router-dom": "^5.1.2", "react-simple-file-input": "^2.0.0", "react-tippy": "^1.2.2", "react-toggle-button": "^2.2.0", "react-transition-group": "^1.2.1", - "readable-stream": "^2.3.3", + "readable-stream": "^3.6.2", "redux": "^4.0.5", "redux-thunk": "^2.3.0", "remove-trailing-slash": "^0.1.1", @@ -378,9 +423,10 @@ "ses": "^1.1.0", "simple-git": "^3.20.0", "single-call-balance-checker-abi": "^1.0.0", + "ts-mixer": "patch:ts-mixer@npm%3A6.0.4#~/.yarn/patches/ts-mixer-npm-6.0.4-5d9747bdf5.patch", "unicode-confusables": "^0.1.1", "uuid": "^8.3.2", - "web3-stream-provider": "^4.0.0", + "web3-stream-provider": "^5.0.0", "zxcvbn": "^4.4.2" }, "devDependencies": { @@ -395,9 +441,11 @@ "@babel/preset-react": "^7.22.15", "@babel/preset-typescript": "^7.23.2", "@babel/register": "^7.22.15", - "@lavamoat/allow-scripts": "^3.0.1", + "@lavamoat/allow-scripts": "^3.0.4", "@lavamoat/lavadome-core": "0.0.10", "@lavamoat/lavapack": "^6.1.0", + "@lgbot/madge": "^6.2.0", + "@metamask/api-specs": "^0.9.3", "@metamask/auto-changelog": "^2.1.0", "@metamask/build-utils": "^1.0.0", "@metamask/eslint-config": "^9.0.0", @@ -405,29 +453,35 @@ "@metamask/eslint-config-mocha": "^9.0.0", "@metamask/eslint-config-nodejs": "^9.0.0", "@metamask/eslint-config-typescript": "^9.0.1", + "@metamask/eslint-plugin-design-tokens": "^1.1.0", "@metamask/forwarder": "^1.1.0", "@metamask/phishing-warning": "^3.0.3", "@metamask/test-bundler": "^1.0.0", - "@metamask/test-dapp": "^8.3.0", + "@metamask/test-dapp": "^8.4.0", + "@octokit/core": "^3.6.0", + "@open-rpc/meta-schema": "^1.14.6", + "@open-rpc/mock-server": "^1.7.5", + "@open-rpc/schema-utils-js": "^1.16.2", + "@open-rpc/test-coverage": "^2.2.2", "@playwright/test": "^1.39.0", "@sentry/cli": "^2.19.4", - "@storybook/addon-a11y": "^7.4.6", - "@storybook/addon-actions": "^7.4.6", - "@storybook/addon-designs": "^7.0.5", - "@storybook/addon-docs": "^7.4.6", - "@storybook/addon-essentials": "^7.4.6", + "@storybook/addon-a11y": "^7.6.19", + "@storybook/addon-actions": "^7.6.19", + "@storybook/addon-designs": "^7.0.9", + "@storybook/addon-docs": "^7.6.19", + "@storybook/addon-essentials": "^7.6.19", "@storybook/addon-knobs": "^7.0.2", - "@storybook/addon-mdx-gfm": "^7.4.6", - "@storybook/addons": "^7.4.6", - "@storybook/api": "^7.4.6", - "@storybook/client-api": "^7.4.6", - "@storybook/components": "^7.4.6", - "@storybook/core-events": "^7.4.6", - "@storybook/react": "^7.4.6", - "@storybook/react-webpack5": "^7.4.6", + "@storybook/addon-mdx-gfm": "^7.6.19", + "@storybook/addons": "^7.6.19", + "@storybook/api": "^7.6.19", + "@storybook/client-api": "^7.6.19", + "@storybook/components": "^7.6.19", + "@storybook/core-events": "^7.6.19", + "@storybook/react": "^7.6.19", + "@storybook/react-webpack5": "^7.6.19", "@storybook/storybook-deployer": "^2.8.16", "@storybook/test-runner": "^0.14.1", - "@storybook/theming": "^7.4.6", + "@storybook/theming": "^7.6.19", "@testing-library/jest-dom": "^5.11.10", "@testing-library/react": "^10.4.8", "@testing-library/react-hooks": "^8.0.1", @@ -436,24 +490,25 @@ "@types/babelify": "^7.3.7", "@types/browserify": "^12.0.37", "@types/currency-formatter": "^1.5.1", - "@types/end-of-stream": "^1.4.1", "@types/fs-extra": "^9.0.13", "@types/gulp": "^4.0.9", "@types/gulp-autoprefixer": "^0.0.33", "@types/gulp-sass": "^5.0.0", "@types/gulp-sourcemaps": "^0.0.35", - "@types/jest": "^29.1.2", - "@types/madge": "^5.0.0", + "@types/he": "^1", + "@types/jest": "^29.5.12", + "@types/luxon": "^3.4.2", "@types/mocha": "^10.0.3", "@types/node": "^20", "@types/pify": "^5.0.1", - "@types/pump": "^1.1.1", "@types/react": "^16.9.53", "@types/react-beautiful-dnd": "^13", "@types/react-dom": "^17.0.11", "@types/react-redux": "^7.1.25", "@types/react-router-dom": "^5.3.3", - "@types/readable-stream": "^4.0.4", + "@types/readable-stream": "4.0.4", + "@types/readable-stream-2": "^2.3.15", + "@types/readable-stream-3": "^4.0.4", "@types/redux-mock-store": "1.0.6", "@types/remote-redux-devtools": "^0.5.5", "@types/selenium-webdriver": "^4.1.19", @@ -462,30 +517,29 @@ "@types/w3c-web-hid": "^1.0.3", "@types/watchify": "^3.11.1", "@types/webextension-polyfill": "^0.10.4", - "@types/yargs": "^17.0.8", - "@typescript-eslint/eslint-plugin": "^6.21.0", - "@typescript-eslint/parser": "^6.21.0", + "@types/yargs": "^17.0.32", + "@typescript-eslint/eslint-plugin": "^7.10.0", + "@typescript-eslint/parser": "^7.10.0", "@whitespace/storybook-addon-html": "^5.1.6", - "addons-linter": "^6.24.0", - "autoprefixer": "^10.4.16", + "addons-linter": "^6.28.0", + "autoprefixer": "^10.4.19", "axios": "^1.1.3", "babelify": "^10.0.0", "bify-module-groups": "^2.0.0", - "brfs": "^2.0.2", "browserify": "^17.0.0", "chalk": "^4.1.2", "chokidar": "^3.5.3", "concurrently": "^8.2.2", - "copy-webpack-plugin": "^6.0.3", + "copy-webpack-plugin": "^12.0.2", "cross-spawn": "^7.0.3", - "css-loader": "^2.1.1", + "css-loader": "^6.10.0", "css-to-xpath": "^0.1.0", "csstype": "^3.0.11", "del": "^6.1.1", "depcheck": "^1.4.3", "dependency-tree": "^10.0.9", "detect-port": "^1.5.1", - "dotenv": "^16.3.1", + "dotenv": "^16.4.5", "duplexify": "^4.1.1", "eslint": "patch:eslint@npm%3A8.57.0#~/.yarn/patches/eslint-npm-8.57.0-4286e12a3a.patch", "eslint-config-prettier": "^8.5.0", @@ -521,38 +575,33 @@ "history": "^5.0.0", "husky": "^8.0.3", "ini": "^3.0.0", - "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-reports": "^3.1.5", - "jest": "^29.1.2", + "jest": "^29.7.0", "jest-canvas-mock": "^2.3.1", - "jest-environment-jsdom": "^29.1.2", + "jest-environment-jsdom": "^29.7.0", "jsdom": "^16.7.0", "koa": "^2.7.0", "lavamoat": "^8.0.2", "lavamoat-browserify": "^17.0.4", - "lavamoat-viz": "^7.0.2", + "lavamoat-viz": "^7.0.5", "lockfile-lint": "^4.10.6", "loose-envify": "^1.4.0", - "madge": "^6.1.0", "mocha": "^10.2.0", "mocha-junit-reporter": "^2.2.1", "mockttp": "^3.10.1", - "nock": "^13.2.9", + "nock": "patch:nock@npm%3A13.5.4#~/.yarn/patches/nock-npm-13.5.4-2c4f77b249.patch", "node-fetch": "^2.6.1", - "nyc": "^15.0.0", - "polyfill-crypto.getrandomvalues": "^1.0.0", "postcss": "^8.4.32", "postcss-rtlcss": "^4.0.9", "prettier": "^2.7.1", "prettier-eslint": "^16.3.0", "prettier-plugin-sort-json": "^1.0.0", - "proxyquire": "^2.1.3", "pumpify": "^2.0.1", "randomcolor": "^0.5.4", "react-devtools": "^4.11.0", "react-syntax-highlighter": "^15.5.0", "read-installed": "^4.0.3", + "readable-stream-2": "^2.3.3", + "readable-stream-3": "^3.6.2", "redux-mock-store": "^1.5.4", "remote-redux-devtools": "^0.5.16", "resolve-url-loader": "^3.1.5", @@ -565,8 +614,8 @@ "source-map": "^0.7.4", "source-map-explorer": "^2.4.2", "sprintf-js": "^1.1.3", - "storybook": "^7.4.6", - "storybook-dark-mode": "^3.0.1", + "storybook": "^7.6.19", + "storybook-dark-mode": "^3.0.3", "stream-browserify": "^3.0.0", "string.prototype.matchall": "^4.0.2", "style-loader": "^0.21.0", @@ -577,7 +626,7 @@ "ts-node": "^10.9.2", "tsx": "^4.7.1", "ttest": "^2.1.1", - "typescript": "~5.3.3", + "typescript": "~5.4.5", "vinyl": "^2.2.1", "vinyl-buffer": "^1.0.1", "vinyl-source-stream": "^2.0.0", @@ -585,9 +634,9 @@ "wait-on": "^7.0.1", "watchify": "^4.0.0", "webextension-polyfill": "^0.8.0", - "webpack": "^5.75.0", + "webpack": "^5.91.0", "yaml": "^2.4.1", - "yargs": "^17.0.1" + "yargs": "^17.7.2" }, "engines": { "node": ">= 20", @@ -611,9 +660,10 @@ "eth-json-rpc-filters>eth-json-rpc-middleware>ethereumjs-util>keccak": false, "eth-json-rpc-filters>eth-json-rpc-middleware>ethereumjs-util>secp256k1": false, "eth-lattice-keyring>gridplus-sdk": false, - "eth-trezor-keyring>hdkey>secp256k1": false, "ethereumjs-util>ethereum-cryptography>keccak": false, "ganache>@trufflesuite/bigint-buffer": false, + "ganache>@trufflesuite/uws-js-unofficial>bufferutil": false, + "ganache>@trufflesuite/uws-js-unofficial>utf-8-validate": false, "ganache>bufferutil": false, "ganache>keccak": false, "ganache>leveldown": false, @@ -639,25 +689,24 @@ "@storybook/core>@storybook/core-server>webpack>watchpack>watchpack-chokidar2>chokidar>fsevents": false, "resolve-url-loader>es6-iterator>es5-ext": false, "@storybook/test-runner>playwright": true, - "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport>protobufjs": false, - "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/utxo-lib>blake-hash": false, - "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/utxo-lib>tiny-secp256k1": false, - "@metamask/eth-trezor-keyring>hdkey>secp256k1": false, "@storybook/addon-knobs>core-js": false, "@storybook/manager-webpack5>core-js": false, "@storybook/react-webpack5>@storybook/preset-react-webpack>@pmmmwh/react-refresh-webpack-plugin>core-js-pure": false, "ts-node>@swc/core": false, "jsdom>ws>bufferutil": false, "jsdom>ws>utf-8-validate": false, - "@trezor/connect-web>@trezor/connect>@trezor/transport>protobufjs": false, + "@trezor/connect-web>@trezor/connect>@trezor/protobuf>protobufjs": false, "@trezor/connect-web>@trezor/connect>@trezor/transport>usb": false, + "@trezor/connect-web>@trezor/connect>@trezor/blockchain-link>@solana/web3.js>bigint-buffer": false, "@trezor/connect-web>@trezor/connect>@trezor/utxo-lib>blake-hash": false, "@trezor/connect-web>@trezor/connect>@trezor/utxo-lib>tiny-secp256k1": false, - "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport>usb": false, "@storybook/test-runner>@swc/core": false, "@lavamoat/lavadome-react>@lavamoat/preinstall-always-fail": false, - "tsx>esbuild": false + "tsx>esbuild": false, + "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/protobuf>protobufjs": false, + "firebase>@firebase/firestore>@grpc/proto-loader>protobufjs": false, + "@lavamoat/lavadome-core>@lavamoat/preinstall-always-fail": false } }, - "packageManager": "yarn@4.0.2" + "packageManager": "yarn@4.2.2" } diff --git a/playwright.config.ts b/playwright.config.ts index cfd20b9e8fbf..6937e6faf8b6 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,6 +1,7 @@ import type { PlaywrightTestConfig } from '@playwright/test'; import { devices } from '@playwright/test'; import dotenv from 'dotenv'; +import { isHeadless } from './test/helpers/env'; dotenv.config({ path: './test/e2e/mmi/.env' }); const logOutputFolder = './public/playwright/playwright-reports'; @@ -42,8 +43,8 @@ const config: PlaywrightTestConfig = { /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on', video: 'off', - // Run tests headless in local - headless: process.env.HEADLESS === 'true', + /* Run tests headless in local */ + headless: isHeadless('PLAYWRIGHT'), }, /* Configure projects for major browsers */ diff --git a/privacy-snapshot.json b/privacy-snapshot.json index 83c7595aaae2..b45cf79a6e8f 100644 --- a/privacy-snapshot.json +++ b/privacy-snapshot.json @@ -7,13 +7,14 @@ "bafkreifvhjdf6ve4jfv6qytqtux5nd4nwnelioeiqx5x2ez5yrgrzk7ypi.ipfs.dweb.link", "bafybeidxfmwycgzcp4v2togflpqh2gnibuexjy4m4qqwxp7nh3jx5zlh4y.ipfs.dweb.link", "cdn.segment.com", + "cdn.segment.io", "cdnjs.cloudflare.com", "chainid.network", "configuration.dev.metamask-institutional.io", "configuration.metamask-institutional.io", "connect.trezor.io", - "customnetwork.com", - "doesntexist.abc", + "customnetwork.test", + "doesntexist.test", "etherscan.io", "execution.metamask.io", "fonts.gstatic.com", @@ -25,22 +26,29 @@ "mainnet.infura.io", "metamask.github.io", "min-api.cryptocompare.com", - "phishing-detection.metafi.codefi.network", + "nft.api.cx.metamask.io", + "phishing-detection.api.cx.metamask.io", "portfolio.metamask.io", - "price-api.metafi.codefi.network", - "proxy.metafi.codefi.network", + "price.api.cx.metamask.io", + "proxy.api.cx.metamask.io", "raw.githubusercontent.com", "registry.npmjs.org", - "responsive-rpc.url", + "responsive-rpc.test", "sentry.io", + "snaps.metamask.io", "start.metamask.io", - "static.metafi-dev.codefi.network", - "static.metafi.codefi.network", "static.cx.metamask.io", - "swap.metaswap.codefi.network", + "swap.api.cx.metamask.io", "test.metamask-phishing.io", - "token-api.metaswap.codefi.network", - "tx-insights.metaswap.codefi.network", + "token.api.cx.metamask.io", + "tokens.api.cx.metamask.io", + "tx-sentinel-ethereum-mainnet.api.cx.metamask.io", "unresponsive-rpc.url", - "www.4byte.directory" + "www.4byte.directory", + "lattice.gridplus.io", + "unresponsive-rpc.test", + "authentication.api.cx.metamask.io", + "oidc.api.cx.metamask.io", + "price.api.cx.metamask.io", + "token.api.cx.metamask.io" ] diff --git a/shared/constants/app.ts b/shared/constants/app.ts index e2c3412496ed..9aeb58235c5c 100644 --- a/shared/constants/app.ts +++ b/shared/constants/app.ts @@ -34,8 +34,12 @@ export const MESSAGE_TYPE = { ETH_GET_ENCRYPTION_PUBLIC_KEY: 'eth_getEncryptionPublicKey', ETH_GET_BLOCK_BY_NUMBER: 'eth_getBlockByNumber', ETH_REQUEST_ACCOUNTS: 'eth_requestAccounts', + ETH_SEND_TRANSACTION: 'eth_sendTransaction', + ETH_SEND_RAW_TRANSACTION: 'eth_sendRawTransaction', ETH_SIGN: 'eth_sign', + ETH_SIGN_TRANSACTION: 'eth_signTransaction', ETH_SIGN_TYPED_DATA: 'eth_signTypedData', + ETH_SIGN_TYPED_DATA_V1: 'eth_signTypedData_v1', ETH_SIGN_TYPED_DATA_V3: 'eth_signTypedData_v3', ETH_SIGN_TYPED_DATA_V4: 'eth_signTypedData_v4', GET_PROVIDER_STATE: 'metamask_getProviderState', @@ -81,6 +85,11 @@ export const SNAP_MANAGE_ACCOUNTS_CONFIRMATION_TYPES = { }; ///: END:ONLY_INCLUDE_IF +export const SMART_TRANSACTION_CONFIRMATION_TYPES = { + showSmartTransactionStatusPage: + 'smartTransaction:showSmartTransactionStatusPage', +}; + /** * Custom messages to send and be received by the extension */ diff --git a/shared/constants/desktop.ts b/shared/constants/desktop.ts deleted file mode 100644 index 9eca08b3259c..000000000000 --- a/shared/constants/desktop.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const EXTENSION_ERROR_PAGE_TYPES = { - NOT_FOUND: 'not-found', - CONNECTION_LOST: 'connection-lost', - DESKTOP_OUTDATED: 'desktop-outdated', - EXTENSION_OUTDATED: 'extension-outdated', - CRITICAL_ERROR: 'critical-error', - ROUTE_NOT_FOUND: 'route-not-found', - PAIRING_KEY_NOT_MATCH: 'pairing-key-not-match', -}; diff --git a/shared/constants/eth-methods.ts b/shared/constants/eth-methods.ts new file mode 100644 index 000000000000..3eea6c662594 --- /dev/null +++ b/shared/constants/eth-methods.ts @@ -0,0 +1,16 @@ +import { EthMethod } from '@metamask/keyring-api'; + +export const ETH_EOA_METHODS = [ + EthMethod.PersonalSign, + EthMethod.Sign, + EthMethod.SignTransaction, + EthMethod.SignTypedDataV1, + EthMethod.SignTypedDataV3, + EthMethod.SignTypedDataV4, +]; + +export const ETH_4337_METHODS = [ + EthMethod.PrepareUserOperation, + EthMethod.PatchUserOperation, + EthMethod.SignUserOperation, +]; diff --git a/shared/constants/first-party-contracts.ts b/shared/constants/first-party-contracts.ts index b961895f2841..100ef1ec6c7c 100644 --- a/shared/constants/first-party-contracts.ts +++ b/shared/constants/first-party-contracts.ts @@ -1,20 +1,35 @@ import { Hex } from '@metamask/utils'; import { CHAIN_IDS } from './network'; +export enum EXPERIENCES_TYPE { + METAMASK_VALIDATOR_STAKING = 'MetaMask Validator Staking', + METAMASK_POOLED_STAKING = 'MetaMask Pooled Staking', + METAMASK_THIRD_PARTY_STAKING = 'MetaMask Third Party Staking', + METAMASK_POOLED_STAKING_V1 = 'MetaMask Pool Staking (v1)', + METAMASK_BRIDGE = 'MetaMask Bridge', + METAMASK_SWAPS = 'MetaMask Swaps', +} + /** * A map of first-party contract names to their addresses on various chains. */ -export const FIRST_PARTY_CONTRACT_NAMES: Record> = { - 'MetaMask Validator Staking': { +export const FIRST_PARTY_CONTRACT_NAMES: Record< + EXPERIENCES_TYPE, + Record +> = { + [EXPERIENCES_TYPE.METAMASK_VALIDATOR_STAKING]: { [CHAIN_IDS.MAINNET]: '0xDc71aFFC862fceB6aD32BE58E098423A7727bEbd', }, - 'MetaMask Pool Staking': { + [EXPERIENCES_TYPE.METAMASK_POOLED_STAKING]: { + [CHAIN_IDS.MAINNET]: '0x4FEF9D741011476750A243aC70b9789a63dd47Df', + }, + [EXPERIENCES_TYPE.METAMASK_THIRD_PARTY_STAKING]: { [CHAIN_IDS.MAINNET]: '0x1f6692E78dDE07FF8da75769B6d7c716215bC7D0', }, - 'MetaMask Pool Staking (v1)': { + [EXPERIENCES_TYPE.METAMASK_POOLED_STAKING_V1]: { [CHAIN_IDS.MAINNET]: '0xc7bE520a13dC023A1b34C03F4Abdab8A43653F7B', }, - 'MetaMask Bridge': { + [EXPERIENCES_TYPE.METAMASK_BRIDGE]: { [CHAIN_IDS.MAINNET]: '0x0439e60F02a8900a951603950d8D4527f400C3f1', [CHAIN_IDS.OPTIMISM]: '0xB90357f2b86dbfD59c3502215d4060f71DF8ca0e', [CHAIN_IDS.BSC]: '0xaEc23140408534b378bf5832defc426dF8604B59', @@ -25,7 +40,7 @@ export const FIRST_PARTY_CONTRACT_NAMES: Record> = { [CHAIN_IDS.AVALANCHE]: '0x29106d08382d3c73bF477A94333C61Db1142E1B6', [CHAIN_IDS.LINEA_MAINNET]: '0xE3d0d2607182Af5B24f5C3C2E4990A053aDd64e3', }, - 'MetaMask Swaps': { + [EXPERIENCES_TYPE.METAMASK_SWAPS]: { [CHAIN_IDS.MAINNET]: '0x881D40237659C251811CEC9c364ef91dC08D300C', [CHAIN_IDS.BSC]: '0x1a1ec25DC08e98e5E93F1104B5e5cdD298707d31', [CHAIN_IDS.POLYGON]: '0x1a1ec25DC08e98e5E93F1104B5e5cdD298707d31', diff --git a/shared/constants/hardware-wallets.ts b/shared/constants/hardware-wallets.ts index e20222ff2e5e..a5decda5ac32 100644 --- a/shared/constants/hardware-wallets.ts +++ b/shared/constants/hardware-wallets.ts @@ -38,6 +38,7 @@ export enum HardwareAffiliateLinks { coolwallet = 'https://www.coolwallet.io/', dcent = 'https://dcentwallet.com/', imtoken = 'https://token.im/', + onekey = 'https://onekey.so/products/onekey-pro-hardware-wallet/', } export enum HardwareAffiliateTutorialLinks { @@ -49,6 +50,7 @@ export enum HardwareAffiliateTutorialLinks { coolwallet = 'https://www.coolwallet.io/metamask-step-by-step-guides/', dcent = 'https://medium.com/dcentwallet/dcent-wallet-now-supports-qr-based-protocol-to-link-with-metamask-57555f02603f', imtoken = 'https://support.token.im/hc/en-us/articles/24652624775961/', + onekey = 'https://help.onekey.so/hc/articles/9426592069903', } /** diff --git a/shared/constants/metametrics.ts b/shared/constants/metametrics.ts index 403468926551..82c6a557be4f 100644 --- a/shared/constants/metametrics.ts +++ b/shared/constants/metametrics.ts @@ -358,10 +358,6 @@ export type MetaMetricsUserTraits = { * Does the user have native currency enabled? */ use_native_as_primary_currency?: boolean; - /** - * Does the user have desktop enabled? - */ - desktop_enabled?: boolean; /** * Whether the security provider feature has been enabled. */ @@ -383,6 +379,14 @@ export type MetaMetricsUserTraits = { }; export enum MetaMetricsUserTrait { + /** + * Identifies if the user has opted in for MetaMetrics + */ + IsMetricsOptedIn = 'is_metrics_opted_in', + /** + * Identifies is the user has given marketing consent + */ + HasMarketingConsent = 'has_marketing_consent', /** * Identified when the user adds or modifies addresses in the address book. */ @@ -445,10 +449,6 @@ export enum MetaMetricsUserTrait { * Identified when the user enables native currency. */ UseNativeCurrencyAsPrimaryCurrency = 'use_native_currency_as_primary_currency', - /** - * Identified when the user enables desktop. - */ - DesktopEnabled = 'desktop_enabled', /** * Identified when the security provider feature is enabled. */ @@ -499,11 +499,13 @@ export enum MetaMetricsEventName { AccountAdded = 'Account Added', AccountAddSelected = 'Account Add Selected', AccountAddFailed = 'Account Add Failed', + AccountDetailsOpened = 'Account Details Opened', AccountPasswordCreated = 'Account Password Created', AccountReset = 'Account Reset', AccountRenamed = 'Account Renamed', ActivityDetailsOpened = 'Activity Details Opened', ActivityDetailsClosed = 'Activity Details Closed', + AnalyticsPreferenceSelected = 'Analytics Preference Selected', AppInstalled = 'App Installed', AppUnlocked = 'App Unlocked', AppUnlockedFailed = 'App Unlocked Failed', @@ -514,16 +516,23 @@ export enum MetaMetricsEventName { DecryptionApproved = 'Decryption Approved', DecryptionRejected = 'Decryption Rejected', DecryptionRequested = 'Decryption Requested', + DisablingAccountNotifications = 'Disabling Account Notifications', + EnablingAccountNotifications = 'Enabling Account Notifications', + DisablingNotifications = 'Disabling Notifications', + DismissEnablingNotificationsFlow = 'Dismiss Enabling Notifications Flow', EmptyBuyBannerDisplayed = 'Empty Buy Banner Displayed', EmptyBuyBannerClicked = 'Empty Buy Banner Clicked', EmptyReceiveBannerDisplayed = 'Empty Receive Banner Displayed', EmptyReceiveBannerClicked = 'Empty Receive Banner Clicked', EmptyNftsBannerDisplayed = 'Empty NFTs Banner Displayed', EmptyNftsBannerClicked = 'Empty NFTs Banner Clicked', + EnablingNotifications = 'Enabling Notifications', EncryptionPublicKeyApproved = 'Encryption Approved', EncryptionPublicKeyRejected = 'Encryption Rejected', EncryptionPublicKeyRequested = 'Encryption Requested', ExternalLinkClicked = 'External Link Clicked', + FeatureAnnouncementEnabled = 'Feature Announcement Enabled', + FeatureAnnouncementDisabled = 'Feature Announcement Disabled', KeyExportSelected = 'Key Export Selected', KeyExportRequested = 'Key Export Requested', KeyExportFailed = 'Key Export Failed', @@ -536,10 +545,10 @@ export enum MetaMetricsEventName { KeyGasFeeEstimationBuySwapTokens = 'Key Show Gas Fee Estimation, Buy Crypto and Swap Tokens', KeyAutoDetectTokens = 'Key Autodetect tokens', KeyBatchAccountBalanceRequests = 'Key Batch account balance requests', + MarkAllNotificationsRead = 'Mark All Notifications Read', MetricsOptIn = 'Metrics Opt In', MetricsOptOut = 'Metrics Opt Out', NavAccountMenuOpened = 'Account Menu Opened', - NavAccountDetailsOpened = 'Account Details Opened', NavConnectedSitesOpened = 'Connected Sites Opened', NavMainMenuOpened = 'Main Menu Opened', NavPermissionsOpened = 'Permissions Opened', @@ -551,6 +560,9 @@ export enum MetaMetricsEventName { NavSendButtonClicked = 'Send Button Clicked', NavSwapButtonClicked = 'Swap Button Clicked', NftAdded = 'NFT Added', + NotificationPageOpened = 'Notification Page Opened', + NotificationItemClicked = 'Notification Item Clicked', + NotificationDetailClicked = 'Notification Detail Clicked', OnboardingWalletCreationStarted = 'Wallet Setup Selected', OnboardingWalletImportStarted = 'Wallet Import Started', OnboardingWalletCreationAttempted = 'Wallet Password Created', @@ -562,8 +574,13 @@ export enum MetaMetricsEventName { OnboardingWalletSecurityPhraseWrittenDown = 'SRP Backup Confirm Display', OnboardingWalletSecurityPhraseConfirmed = 'SRP Backup Confirmed', OnboardingWalletCreationComplete = 'Wallet Created', + OnboardingWalletCreationCompleteWithAuthenticating = 'Wallet Created with Authenticating', OnboardingWalletSetupComplete = 'Application Opened', OnboardingWalletAdvancedSettings = 'Settings Updated', + OnboardingWalletAdvancedSettingsWithAuthenticating = 'Settings Updated with Authenticating', + OnboardingWalletAdvancedSettingsWithoutAuthenticating = 'Settings Updated without Authenticating', + OnboardingWalletAdvancedSettingsTurnOffProfileSyncing = 'Turn Off Profile Syncing', + OnboardingWalletAdvancedSettingsTurnOnProfileSyncing = 'Turn On Profile Syncing', OnboardingWalletImportAttempted = 'Wallet Import Attempted', OnboardingWalletVideoPlay = 'SRP Intro Video Played', OnboardingTwitterClick = 'External Link Clicked', @@ -587,6 +604,7 @@ export enum MetaMetricsEventName { SignatureRejected = 'Signature Rejected', SignatureRequested = 'Signature Requested', SimulationFails = 'Simulation Fails', + SimulationIncompleteAssetDisplayed = 'Incomplete Asset Displayed', SrpRevealStarted = 'Reveal SRP Initiated', SrpRevealClicked = 'Clicked Reveal Secret Recovery', SrpRevealViewed = 'Views Reveal Secret Recovery', @@ -603,12 +621,15 @@ export enum MetaMetricsEventName { SrpCopiedToClipboard = 'Copies SRP to clipboard', SrpToConfirmBackup = 'SRP Backup Confirm Displayed', StakingEntryPointClicked = 'Stake Button Clicked', + StartEnablingNotificationsFlow = 'Start Enabling Notifications Flow', SupportLinkClicked = 'Support Link Clicked', TermsOfUseShown = 'Terms of Use Shown', TermsOfUseAccepted = 'Terms of Use Accepted', TokenImportButtonClicked = 'Import Token Button Clicked', TokenScreenOpened = 'Token Screen Opened', TokenAdded = 'Token Added', + TokenRemoved = 'Token Removed', + NFTRemoved = 'NFT Removed', TokenDetected = 'Token Detected', TokenHidden = 'Token Hidden', TokenImportCanceled = 'Token Import Canceled', @@ -644,6 +665,7 @@ export enum MetaMetricsEventName { CustomNetworkAdded = 'Custom Network Added', TokenDetailsOpened = 'Token Details Opened', NftScreenOpened = 'NFT Screen Opened', + NftDetailsOpened = 'NFT Details Opened', ActivityScreenOpened = 'Activity Screen Opened', WhatsNewViewed = `What's New Viewed`, WhatsNewClicked = `What's New Link Clicked`, @@ -663,7 +685,7 @@ export enum MetaMetricsEventName { ///: BEGIN:ONLY_INCLUDE_IF(snaps) SnapInstallStarted = 'Snap Install Started', SnapInstallFailed = 'Snap Install Failed', - SnapInstallRejected = 'Snap Update Rejected', + SnapInstallRejected = 'Snap Install Rejected', SnapInstalled = 'Snap Installed', SnapUninstalled = 'Snap Uninstalled', SnapUpdateStarted = 'Snap Update Started', @@ -671,8 +693,6 @@ export enum MetaMetricsEventName { SnapUpdateFailed = 'Snap Update Failed', SnapUpdated = 'Snap Updated', SnapExportUsed = 'Snap Export Used', - ///: END:ONLY_INCLUDE_IF - ///: BEGIN:ONLY_INCLUDE_IF(build-flask) InsightSnapViewed = 'Insight Snap Viewed', ///: END:ONLY_INCLUDE_IF ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) @@ -692,7 +712,26 @@ export enum MetaMetricsEventName { SnapAccountTransactionFinalizeRedirectGoToSiteClicked = 'Snap Account Transaction Finalize Redirect "Go To Site" Clicked', SnapAccountTransactionFinalizeRedirectSnapUrlClicked = 'Snap Account Transaction Finalize Redirect "Snap URL" Clicked', SnapAccountTransactionFinalizeClosed = 'Snap Account Transaction Finalize Closed', + TokenAutoDetectionEnableModal = 'Token Autodetection Enabled from modal', + TokenAutoDetectionDisableModal = 'Token Autodetection Disabled from modal', ///: END:ONLY_INCLUDE_IF + TurnOffProfileSyncing = 'Turn Off Profile Syncing', + TurnOnProfileSyncing = 'Turn On Profile Syncing', + TurnOnMetaMetrics = 'Turn On MetaMetrics', + TurnOffMetaMetrics = 'Turn Off MetaMetrics', + // Notifications + PushNotificationReceived = 'Push Notification Received', + PushNotificationClicked = 'Push Notification Clicked', + + NftAutoDetectionEnableModal = 'Nft Autodetection Enabled from modal', + NftAutoDetectionDisableModal = 'Nft Autodetection Disabled from modal', + // Send + sendAssetSelected = 'Send Asset Selected', + sendFlowExited = 'Send Flow Exited', + sendRecipientSelected = 'Send Recipient Selected', + sendSwapQuoteError = 'Send Swap Quote Error', + sendSwapQuoteFetched = 'Send Swap Quote Fetched', + sendTokenModalOpened = 'Send Token Modal Opened', } export enum MetaMetricsEventAccountType { @@ -715,7 +754,6 @@ export enum MetaMetricsEventCategory { App = 'App', Auth = 'Auth', Background = 'Background', - Desktop = 'Desktop', // The TypeScript ESLint rule is incorrectly marking this line. /* eslint-disable-next-line @typescript-eslint/no-shadow */ Error = 'Error', @@ -726,10 +764,15 @@ export enum MetaMetricsEventCategory { Messages = 'Messages', Navigation = 'Navigation', Network = 'Network', + EnableNotifications = 'Enable Notifications', Onboarding = 'Onboarding', + NotificationInteraction = 'Notification Interaction', + NotificationSettings = 'Notification Settings', Petnames = 'Petnames', Phishing = 'Phishing', + PushNotifications = 'Notifications', Retention = 'Retention', + Send = 'Send', Settings = 'Settings', Snaps = 'Snaps', Swaps = 'Swaps', @@ -762,6 +805,8 @@ export enum MetaMetricsNetworkEventSource { CustomNetworkForm = 'custom_network_form', PopularNetworkList = 'popular_network_list', Dapp = 'dapp', + DeprecatedNetworkModal = 'deprecated_network_modal', + NewAddNetworkFlow = 'new_add_network_flow', } export enum MetaMetricsSwapsEventSource { @@ -782,6 +827,7 @@ export enum MetaMetricsTransactionEventSource { } export enum MetaMetricsEventLocation { + SignatureConfirmation = 'signature_confirmation', TokenDetails = 'token_details', TokenDetection = 'token_detection', TokenMenu = 'token_menu', @@ -792,8 +838,10 @@ export enum MetaMetricsEventUiCustomization { FlaggedAsSafetyUnknown = 'flagged_as_safety_unknown', FlaggedAsWarning = 'flagged_as_warning', GasEstimationFailed = 'gas_estimation_failed', + RedesignedConfirmation = 'redesigned_confirmation', SecurityAlertError = 'security_alert_error', Siwe = 'sign_in_with_ethereum', + Permit = 'permit', } /** diff --git a/shared/constants/methods-tags.ts b/shared/constants/methods-tags.ts new file mode 100644 index 000000000000..a770fd733cd2 --- /dev/null +++ b/shared/constants/methods-tags.ts @@ -0,0 +1,32 @@ +/** + * This is a list of methods that require the globally selected network + * to match the dapp selected network before being processed. These can + * be for UI/UX reasons where the currently selected network is displayed + * in the confirmation even though it will be submitted on the correct + * network for the dapp. It could also be that a method expects the + * globally selected network to match some value in the request params itself. + */ +export const methodsRequiringNetworkSwitch = [ + 'eth_sendTransaction', + 'eth_sendRawTransaction', + 'wallet_switchEthereumChain', + 'wallet_addEthereumChain', + 'wallet_watchAsset', + 'eth_signTypedData_v4', + 'personal_sign', +] as const; + +/** + * This is a list of methods that can cause a confirmation to be + * presented to the user. Note that some of these methods may + * only sometimes cause a confirmation to appear. + */ +export const methodsWithConfirmation = [ + ...methodsRequiringNetworkSwitch, + 'wallet_requestPermissions', + 'wallet_requestSnaps', + 'eth_decrypt', + 'eth_sign', + 'eth_requestAccounts', + 'eth_getEncryptionPublicKey', +]; diff --git a/shared/constants/mmi-controller.ts b/shared/constants/mmi-controller.ts index 779c1aa99368..5caa775a9518 100644 --- a/shared/constants/mmi-controller.ts +++ b/shared/constants/mmi-controller.ts @@ -5,37 +5,59 @@ import { CustodyController } from '@metamask-institutional/custody-controller'; import { SignatureController } from '@metamask/signature-controller'; import { NetworkController } from '@metamask/network-controller'; import { PreferencesController } from '../../app/scripts/controllers/preferences'; -import AppStateController from '../../app/scripts/controllers/app-state'; +import { AppStateController } from '../../app/scripts/controllers/app-state'; import AccountTracker from '../../app/scripts/lib/account-tracker'; import MetaMetricsController from '../../app/scripts/controllers/metametrics'; export type MMIControllerOptions = { mmiConfigurationController: MmiConfigurationController; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any keyringController: any; preferencesController: PreferencesController; appStateController: AppStateController; transactionUpdateController: TransactionUpdateController; custodyController: CustodyController; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any messenger: any; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any getState: () => any; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any getPendingNonce: (address: string) => Promise; accountTracker: AccountTracker; metaMetricsController: MetaMetricsController; networkController: NetworkController; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any permissionController: any; signatureController: SignatureController; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any platform: any; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any extension: any; updateTransactionHash: (txId: string, txHash: string) => void; trackTransactionEvents: ( args: { transactionMeta: TransactionMeta }, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any event: any, ) => void; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any getTransactions: (query?: any, opts?: any, fullTx?: boolean) => any[]; setTxStatusSigned: (txId: string) => void; setTxStatusSubmitted: (txId: string) => void; setTxStatusFailed: (txId: string) => void; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any updateTransaction: (txMeta: any) => void; + setChannelId: (channelId: string) => void; + setConnectionRequest: (payload: ConnectionRequest | null) => void; }; export type ISignedEvent = { @@ -69,3 +91,9 @@ export type NetworkConfiguration = { chainId: string; setActiveNetwork: (chainId: string) => void; }; + +export type ConnectionRequest = { + payload: string; + traceId: string; + channelId: string; +}; diff --git a/shared/constants/multichain/networks.ts b/shared/constants/multichain/networks.ts new file mode 100644 index 000000000000..de5e50639374 --- /dev/null +++ b/shared/constants/multichain/networks.ts @@ -0,0 +1,38 @@ +import { ProviderConfig } from '@metamask/network-controller'; +import { CaipChainId } from '@metamask/utils'; + +export type ProviderConfigWithImageUrl = Omit & { + rpcPrefs?: { imageUrl?: string }; +}; + +export type MultichainProviderConfig = ProviderConfigWithImageUrl & { + chainId: CaipChainId; +}; + +export enum MultichainNetworks { + BITCOIN = 'bip122:000000000019d6689c085ae165831e93', + BITCOIN_TESTNET = 'bip122:000000000933ea01ad0ee984209779ba', +} + +export const BITCOIN_TOKEN_IMAGE_URL = './images/bitcoin-logo.svg'; + +export const MULTICHAIN_TOKEN_IMAGE_MAP = { + [MultichainNetworks.BITCOIN]: BITCOIN_TOKEN_IMAGE_URL, +} as const; + +export const MULTICHAIN_PROVIDER_CONFIGS: Record< + CaipChainId, + MultichainProviderConfig +> = { + [MultichainNetworks.BITCOIN]: { + chainId: MultichainNetworks.BITCOIN, + rpcUrl: '', // not used + ticker: 'BTC', + nickname: 'Bitcoin', + id: 'btc-mainnet', + type: 'rpc', + rpcPrefs: { + imageUrl: MULTICHAIN_TOKEN_IMAGE_MAP[MultichainNetworks.BITCOIN], + }, + }, +}; diff --git a/shared/constants/network.test.ts b/shared/constants/network.test.ts index 0c4f50b87b7f..ac427914fbaa 100644 --- a/shared/constants/network.test.ts +++ b/shared/constants/network.test.ts @@ -3,6 +3,7 @@ import { join } from 'path'; import { CHAIN_IDS, CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP, + FEATURED_RPCS, NETWORK_TO_NAME_MAP, } from './network'; @@ -24,4 +25,70 @@ describe('NetworkConstants', () => { expect(NETWORK_TO_NAME_MAP[CHAIN_IDS.OPTIMISM]).toBe('OP Mainnet'); expect(NETWORK_TO_NAME_MAP[CHAIN_IDS.POLYGON]).toBe('Polygon'); }); + describe('popularNetwork', () => { + it('should have correct chainIds for all popular network', () => { + const expectedChainIds: { [key: string]: string } = { + 'Arbitrum One': CHAIN_IDS.ARBITRUM, + 'Avalanche Network C-Chain': CHAIN_IDS.AVALANCHE, + 'BNB Chain': CHAIN_IDS.BSC, + 'OP Mainnet': CHAIN_IDS.OPTIMISM, + 'Polygon Mainnet': CHAIN_IDS.POLYGON, + 'zkSync Era Mainnet': CHAIN_IDS.ZKSYNC_ERA, + 'Base Mainnet': CHAIN_IDS.BASE, + }; + + FEATURED_RPCS.forEach((rpc) => { + expect(rpc.chainId).toBe(expectedChainIds[rpc.nickname]); + }); + }); + }); + + describe('FEATURED_RPCS Infura Usage Tests', () => { + it('arbitrum entry should use Infura', () => { + const arbitrumRpc = FEATURED_RPCS.find( + (rpc) => rpc.chainId === CHAIN_IDS.ARBITRUM, + ); + expect(arbitrumRpc?.rpcUrl).toContain('infura.io'); + }); + + it('avalanche entry should use Infura', () => { + const avalancheRpc = FEATURED_RPCS.find( + (rpc) => rpc.chainId === CHAIN_IDS.AVALANCHE, + ); + expect(avalancheRpc?.rpcUrl).toContain('infura.io'); + }); + + it('bsc entry should not use Infura', () => { + const bscRpc = FEATURED_RPCS.find((rpc) => rpc.chainId === CHAIN_IDS.BSC); + expect(bscRpc?.rpcUrl).not.toContain('infura.io'); + }); + + it('optimism entry should use Infura', () => { + const optimismRpc = FEATURED_RPCS.find( + (rpc) => rpc.chainId === CHAIN_IDS.OPTIMISM, + ); + expect(optimismRpc?.rpcUrl).toContain('infura.io'); + }); + + it('polygon entry should use Infura', () => { + const polygonRpc = FEATURED_RPCS.find( + (rpc) => rpc.chainId === CHAIN_IDS.POLYGON, + ); + expect(polygonRpc?.rpcUrl).toContain('infura.io'); + }); + + it('zkSync Era entry should not use Infura', () => { + const zksyncEraRpc = FEATURED_RPCS.find( + (rpc) => rpc.chainId === CHAIN_IDS.ZKSYNC_ERA, + ); + expect(zksyncEraRpc?.rpcUrl).not.toContain('infura.io'); + }); + + it('base entry should not use Infura', () => { + const baseRpc = FEATURED_RPCS.find( + (rpc) => rpc.chainId === CHAIN_IDS.BASE, + ); + expect(baseRpc?.rpcUrl).not.toContain('infura.io'); + }); + }); }); diff --git a/shared/constants/network.ts b/shared/constants/network.ts index ff7ca1ef7263..452f0584ffaa 100644 --- a/shared/constants/network.ts +++ b/shared/constants/network.ts @@ -96,6 +96,7 @@ export const NETWORK_TYPES = { RPC: 'rpc', SEPOLIA: 'sepolia', LINEA_GOERLI: 'linea-goerli', + LINEA_SEPOLIA: 'linea-sepolia', LINEA_MAINNET: 'linea-mainnet', } as const; @@ -137,6 +138,7 @@ export const CHAIN_IDS = { PALM: '0x2a15c308d', SEPOLIA: '0xaa36a7', LINEA_GOERLI: '0xe704', + LINEA_SEPOLIA: '0xe705', LINEA_MAINNET: '0xe708', AURORA: '0x4e454152', MOONBEAM: '0x504', @@ -148,9 +150,17 @@ export const CHAIN_IDS = { TEST_ETH: '0x539', ARBITRUM_GOERLI: '0x66eed', BLAST: '0x13e31', + FILECOIN: '0x13a', + POLYGON_ZKEVM: '0x44d', + SCROLL: '0x82750', + SCROLL_SEPOLIA: '0x8274f', + WETHIO: '0x4e', + CHZ: '0x15b38', + NUMBERS: '0x290b', + SEI: '0x531', } as const; -const CHAINLIST_CHAIN_IDS_MAP = { +export const CHAINLIST_CHAIN_IDS_MAP = { ...CHAIN_IDS, SCROLL: '0x82750', TAIKO_JOLNIR_L2_MAINNET: '0x28c5f', @@ -189,7 +199,6 @@ const CHAINLIST_CHAIN_IDS_MAP = { OASYS_MAINNET: '0xf8', OKXCHAIN_MAINNET: '0x42', PGN_PUBLIC_GOODS_NETWORK: '0x1a8', - POLYGON_ZKEVM: '0x44d', PULSECHAIN_MAINNET: '0x171', SHARDEUM_LIBERTY_2X: '0x1f91', SHARDEUM_SPHINX_1X: '0x1f92', @@ -201,16 +210,19 @@ const CHAINLIST_CHAIN_IDS_MAP = { VELAS_EVM_MAINNET: '0x6a', ZKATANA: '0x133e40', ZORA_MAINNET: '0x76adf1', + FILECOIN: '0x13a', + NUMBERS: '0x290b', } as const; // To add a deprecation warning to a network, add it to the array -// `DEPRECATED_NETWORKS` and as a new case to `getDeprecationWarningCopy() in +// `DEPRECATED_NETWORKS` and optionally add network specific logic to // `ui/components/ui/deprecated-networks/deprecated-networks.js`. export const DEPRECATED_NETWORKS = [ - CHAIN_IDS.AURORA, CHAIN_IDS.GOERLI, CHAIN_IDS.ARBITRUM_GOERLI, CHAIN_IDS.OPTIMISM_GOERLI, + CHAIN_IDS.POLYGON_TESTNET, + CHAIN_IDS.LINEA_GOERLI, ]; /** @@ -223,6 +235,7 @@ export const MAINNET_DISPLAY_NAME = 'Ethereum Mainnet'; export const GOERLI_DISPLAY_NAME = 'Goerli'; export const SEPOLIA_DISPLAY_NAME = 'Sepolia'; export const LINEA_GOERLI_DISPLAY_NAME = 'Linea Goerli'; +export const LINEA_SEPOLIA_DISPLAY_NAME = 'Linea Sepolia'; export const LINEA_MAINNET_DISPLAY_NAME = 'Linea Mainnet'; export const LOCALHOST_DISPLAY_NAME = 'Localhost 8545'; export const BSC_DISPLAY_NAME = 'Binance Smart Chain'; @@ -238,7 +251,14 @@ export const CELO_DISPLAY_NAME = 'Celo Mainnet'; export const GNOSIS_DISPLAY_NAME = 'Gnosis'; export const ZK_SYNC_ERA_DISPLAY_NAME = 'zkSync Era Mainnet'; export const BASE_DISPLAY_NAME = 'Base Mainnet'; -export const AURORA_ETH_DISPLAY_NAME = 'Aurora'; +export const AURORA_DISPLAY_NAME = 'Aurora Mainnet'; +export const CRONOS_DISPLAY_NAME = 'Cronos'; +export const POLYGON_ZKEVM_DISPLAY_NAME = 'Polygon zkEVM'; +export const MOONBEAM_DISPLAY_NAME = 'Moonbeam'; +export const MOONRIVER_DISPLAY_NAME = 'Moonriver'; +export const SCROLL_DISPLAY_NAME = 'Scroll'; +export const SCROLL_SEPOLIA_DISPLAY_NAME = 'Scroll Sepolia'; +export const OP_BNB_DISPLAY_NAME = 'opBNB'; export const infuraProjectId = process.env.INFURA_PROJECT_ID; export const getRpcUrl = ({ @@ -258,6 +278,9 @@ export const SEPOLIA_RPC_URL = getRpcUrl({ network: NETWORK_TYPES.SEPOLIA }); export const LINEA_GOERLI_RPC_URL = getRpcUrl({ network: NETWORK_TYPES.LINEA_GOERLI, }); +export const LINEA_SEPOLIA_RPC_URL = getRpcUrl({ + network: NETWORK_TYPES.LINEA_SEPOLIA, +}); export const LINEA_MAINNET_RPC_URL = getRpcUrl({ network: NETWORK_TYPES.LINEA_MAINNET, }); @@ -350,8 +373,14 @@ const CHAINLIST_CURRENCY_SYMBOLS_MAP = { ACALA_NETWORK: 'ACA', } as const; +export const CHAINLIST_CURRENCY_SYMBOLS_MAP_NETWORK_COLLISION = { + WETHIO: 'ZYN', + CHZ: 'CHZ', +}; + export const ETH_TOKEN_IMAGE_URL = './images/eth_logo.svg'; export const LINEA_GOERLI_TOKEN_IMAGE_URL = './images/linea-logo-testnet.png'; +export const LINEA_SEPOLIA_TOKEN_IMAGE_URL = './images/linea-logo-testnet.png'; export const LINEA_MAINNET_TOKEN_IMAGE_URL = './images/linea-logo-mainnet.svg'; export const TEST_ETH_TOKEN_IMAGE_URL = './images/black-eth-logo.svg'; export const BNB_TOKEN_IMAGE_URL = './images/bnb.svg'; @@ -383,7 +412,7 @@ export const ENDURANCE_SMART_CHAIN_MAINNET_IMAGE_URL = export const ETHEREUM_CLASSIC_MAINNET_IMAGE_URL = './images/eth_classic.svg'; export const EVMOS_IMAGE_URL = './images/evmos.svg'; export const FLARE_MAINNET_IMAGE_URL = './images/flare-mainnet.svg'; -export const FUSE_GOLD_MAINNET_IMAGE_URL = './images/fuse-mainnet.jpeg'; +export const FUSE_GOLD_MAINNET_IMAGE_URL = './images/fuse-mainnet.jpg'; export const HAQQ_NETWORK_IMAGE_URL = './images/haqq.svg'; export const KCC_MAINNET_IMAGE_URL = './images/kcc-mainnet.svg'; export const KLAYTN_MAINNET_IMAGE_URL = './images/klaytn.svg'; @@ -410,17 +439,22 @@ export const TENET_MAINNET_IMAGE_URL = './images/tenet.svg'; export const VELAS_EVM_MAINNET_IMAGE_URL = './images/velas.svg'; export const ZKATANA_MAINNET_IMAGE_URL = './images/zkatana.png'; export const ZORA_MAINNET_IMAGE_URL = './images/zora.svg'; +export const FILECOIN_MAINNET_IMAGE_URL = './images/filecoin.svg'; +export const SCROLL_IMAGE_URL = './images/scroll.svg'; +export const NUMBERS_MAINNET_IMAGE_URL = './images/numbers-mainnet.svg'; +export const NUMBERS_TOKEN_IMAGE_URL = './images/numbers-token.png'; +export const SEI_IMAGE_URL = './images/sei.svg'; export const INFURA_PROVIDER_TYPES = [ NETWORK_TYPES.MAINNET, NETWORK_TYPES.SEPOLIA, - NETWORK_TYPES.LINEA_GOERLI, + NETWORK_TYPES.LINEA_SEPOLIA, NETWORK_TYPES.LINEA_MAINNET, ] as const; export const TEST_CHAINS = [ CHAIN_IDS.SEPOLIA, - CHAIN_IDS.LINEA_GOERLI, + CHAIN_IDS.LINEA_SEPOLIA, CHAIN_IDS.LOCALHOST, ]; @@ -445,6 +479,7 @@ export const TEST_NETWORK_TICKER_MAP: { CURRENCY_SYMBOLS.ETH }`, [NETWORK_TYPES.LINEA_GOERLI]: `Linea${CURRENCY_SYMBOLS.ETH}`, + [NETWORK_TYPES.LINEA_SEPOLIA]: `Linea${CURRENCY_SYMBOLS.ETH}`, }; /** @@ -456,10 +491,10 @@ export const BUILT_IN_NETWORKS = { ticker: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.SEPOLIA], blockExplorerUrl: `https://${NETWORK_TYPES.SEPOLIA}.etherscan.io`, }, - [NETWORK_TYPES.LINEA_GOERLI]: { - chainId: CHAIN_IDS.LINEA_GOERLI, - ticker: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.LINEA_GOERLI], - blockExplorerUrl: 'https://goerli.lineascan.build', + [NETWORK_TYPES.LINEA_SEPOLIA]: { + chainId: CHAIN_IDS.LINEA_SEPOLIA, + ticker: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.LINEA_SEPOLIA], + blockExplorerUrl: 'https://sepolia.lineascan.build', }, [NETWORK_TYPES.MAINNET]: { chainId: CHAIN_IDS.MAINNET, @@ -493,6 +528,7 @@ export const NETWORK_TO_NAME_MAP = { [NETWORK_TYPES.GOERLI]: GOERLI_DISPLAY_NAME, [NETWORK_TYPES.MAINNET]: MAINNET_DISPLAY_NAME, [NETWORK_TYPES.LINEA_GOERLI]: LINEA_GOERLI_DISPLAY_NAME, + [NETWORK_TYPES.LINEA_SEPOLIA]: LINEA_SEPOLIA_DISPLAY_NAME, [NETWORK_TYPES.LINEA_MAINNET]: LINEA_MAINNET_DISPLAY_NAME, [NETWORK_TYPES.LOCALHOST]: LOCALHOST_DISPLAY_NAME, [NETWORK_TYPES.SEPOLIA]: SEPOLIA_DISPLAY_NAME, @@ -500,14 +536,19 @@ export const NETWORK_TO_NAME_MAP = { [CHAIN_IDS.ARBITRUM]: ARBITRUM_DISPLAY_NAME, [CHAIN_IDS.AVALANCHE]: AVALANCHE_DISPLAY_NAME, [CHAIN_IDS.BSC]: BSC_DISPLAY_NAME, + [CHAIN_IDS.BASE]: BASE_DISPLAY_NAME, [CHAIN_IDS.GOERLI]: GOERLI_DISPLAY_NAME, [CHAIN_IDS.MAINNET]: MAINNET_DISPLAY_NAME, [CHAIN_IDS.LINEA_GOERLI]: LINEA_GOERLI_DISPLAY_NAME, [CHAIN_IDS.LINEA_MAINNET]: LINEA_MAINNET_DISPLAY_NAME, + [CHAIN_IDS.LINEA_SEPOLIA]: LINEA_SEPOLIA_DISPLAY_NAME, [CHAIN_IDS.LOCALHOST]: LOCALHOST_DISPLAY_NAME, [CHAIN_IDS.OPTIMISM]: OPTIMISM_DISPLAY_NAME, [CHAIN_IDS.POLYGON]: POLYGON_DISPLAY_NAME, + [CHAIN_IDS.SCROLL]: SCROLL_DISPLAY_NAME, + [CHAIN_IDS.SCROLL_SEPOLIA]: SCROLL_SEPOLIA_DISPLAY_NAME, [CHAIN_IDS.SEPOLIA]: SEPOLIA_DISPLAY_NAME, + [CHAIN_IDS.OPBNB]: OP_BNB_DISPLAY_NAME, } as const; export const CHAIN_ID_TO_CURRENCY_SYMBOL_MAP = { @@ -529,6 +570,8 @@ export const CHAIN_ID_TO_CURRENCY_SYMBOL_MAP = { TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.SEPOLIA], [CHAINLIST_CHAIN_IDS_MAP.LINEA_GOERLI]: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.LINEA_GOERLI], + [CHAINLIST_CHAIN_IDS_MAP.LINEA_SEPOLIA]: + TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.LINEA_SEPOLIA], [CHAINLIST_CHAIN_IDS_MAP.SCROLL]: CHAINLIST_CURRENCY_SYMBOLS_MAP.SCROLL, [CHAINLIST_CHAIN_IDS_MAP.ZORA_MAINNET]: CHAINLIST_CURRENCY_SYMBOLS_MAP.ZORA_MAINNET, @@ -622,11 +665,29 @@ export const CHAIN_ID_TO_CURRENCY_SYMBOL_MAP = { CHAINLIST_CURRENCY_SYMBOLS_MAP.ACALA_NETWORK, } as const; +/** + * A mapping for networks with chain ID collisions to their currencies symbols. + * Useful for networks not listed on https://chainid.network/chains.json due to ID conflicts. + */ +export const CHAIN_ID_TO_CURRENCY_SYMBOL_MAP_NETWORK_COLLISION = { + [CHAINLIST_CHAIN_IDS_MAP.CHZ]: [ + { + currencySymbol: CHAINLIST_CURRENCY_SYMBOLS_MAP_NETWORK_COLLISION.CHZ, + }, + ], + [CHAINLIST_CHAIN_IDS_MAP.WETHIO]: [ + { + currencySymbol: CHAINLIST_CURRENCY_SYMBOLS_MAP_NETWORK_COLLISION.WETHIO, + }, + ], +}; + export const CHAIN_ID_TO_TYPE_MAP = { [CHAIN_IDS.MAINNET]: NETWORK_TYPES.MAINNET, [CHAIN_IDS.GOERLI]: NETWORK_TYPES.GOERLI, [CHAIN_IDS.SEPOLIA]: NETWORK_TYPES.SEPOLIA, [CHAIN_IDS.LINEA_GOERLI]: NETWORK_TYPES.LINEA_GOERLI, + [CHAIN_IDS.LINEA_SEPOLIA]: NETWORK_TYPES.LINEA_SEPOLIA, [CHAIN_IDS.LINEA_MAINNET]: NETWORK_TYPES.LINEA_MAINNET, [CHAIN_IDS.LOCALHOST]: NETWORK_TYPES.LOCALHOST, } as const; @@ -635,6 +696,7 @@ export const CHAIN_ID_TO_RPC_URL_MAP = { [CHAIN_IDS.GOERLI]: GOERLI_RPC_URL, [CHAIN_IDS.SEPOLIA]: SEPOLIA_RPC_URL, [CHAIN_IDS.LINEA_GOERLI]: LINEA_GOERLI_RPC_URL, + [CHAIN_IDS.LINEA_SEPOLIA]: LINEA_SEPOLIA_RPC_URL, [CHAIN_IDS.MAINNET]: MAINNET_RPC_URL, [CHAIN_IDS.LINEA_MAINNET]: LINEA_MAINNET_RPC_URL, [CHAIN_IDS.LOCALHOST]: LOCALHOST_RPC_URL, @@ -643,6 +705,7 @@ export const CHAIN_ID_TO_RPC_URL_MAP = { export const CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP = { [CHAIN_IDS.MAINNET]: ETH_TOKEN_IMAGE_URL, [CHAIN_IDS.LINEA_GOERLI]: LINEA_GOERLI_TOKEN_IMAGE_URL, + [CHAIN_IDS.LINEA_SEPOLIA]: LINEA_SEPOLIA_TOKEN_IMAGE_URL, [CHAIN_IDS.LINEA_MAINNET]: LINEA_MAINNET_TOKEN_IMAGE_URL, [CHAIN_IDS.AVALANCHE]: AVAX_TOKEN_IMAGE_URL, [CHAIN_IDS.BSC]: BNB_TOKEN_IMAGE_URL, @@ -701,12 +764,17 @@ export const CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP = { [CHAINLIST_CHAIN_IDS_MAP.VELAS_EVM_MAINNET]: VELAS_EVM_MAINNET_IMAGE_URL, [CHAINLIST_CHAIN_IDS_MAP.ZKATANA]: ZKATANA_MAINNET_IMAGE_URL, [CHAINLIST_CHAIN_IDS_MAP.ZORA_MAINNET]: ZORA_MAINNET_IMAGE_URL, + [CHAINLIST_CHAIN_IDS_MAP.FILECOIN]: FILECOIN_MAINNET_IMAGE_URL, + [CHAINLIST_CHAIN_IDS_MAP.BASE]: BASE_TOKEN_IMAGE_URL, + [CHAINLIST_CHAIN_IDS_MAP.NUMBERS]: NUMBERS_MAINNET_IMAGE_URL, + [CHAINLIST_CHAIN_IDS_MAP.SEI]: SEI_IMAGE_URL, } as const; export const CHAIN_ID_TO_ETHERS_NETWORK_NAME_MAP = { [CHAIN_IDS.GOERLI]: NETWORK_TYPES.GOERLI, [CHAIN_IDS.SEPOLIA]: NETWORK_TYPES.SEPOLIA, [CHAIN_IDS.LINEA_GOERLI]: NETWORK_TYPES.LINEA_GOERLI, + [CHAIN_IDS.LINEA_SEPOLIA]: NETWORK_TYPES.LINEA_SEPOLIA, [CHAIN_IDS.MAINNET]: NETWORK_NAMES.HOMESTEAD, [CHAIN_IDS.LINEA_MAINNET]: NETWORK_TYPES.LINEA_MAINNET, } as const; @@ -721,6 +789,11 @@ export const CHAIN_ID_TOKEN_IMAGE_MAP = { [CHAIN_IDS.CELO]: CELO_TOKEN_IMAGE_URL, [CHAIN_IDS.GNOSIS]: GNOSIS_TOKEN_IMAGE_URL, [CHAIN_IDS.FANTOM]: FTM_TOKEN_IMAGE_URL, + [CHAIN_IDS.FILECOIN]: FILECOIN_MAINNET_IMAGE_URL, + [CHAIN_IDS.SCROLL]: SCROLL_IMAGE_URL, + [CHAIN_IDS.SCROLL_SEPOLIA]: SCROLL_IMAGE_URL, + [CHAIN_IDS.NUMBERS]: NUMBERS_TOKEN_IMAGE_URL, + [CHAIN_IDS.SEI]: SEI_IMAGE_URL, } as const; export const INFURA_BLOCKED_KEY = 'countryBlocked'; @@ -752,6 +825,10 @@ export const ETHERSCAN_SUPPORTED_NETWORKS = { domain: 'lineascan.build', subdomain: 'goerli', }, + [CHAIN_IDS.LINEA_SEPOLIA]: { + domain: 'lineascan.build', + subdomain: 'sepolia', + }, [CHAIN_IDS.LINEA_MAINNET]: { domain: 'lineascan.build', subdomain: defaultEtherscanSubdomainPrefix, @@ -842,7 +919,6 @@ export const BUYABLE_CHAINS_MAP: { | typeof CHAIN_IDS.OPTIMISM_TESTNET | typeof CHAIN_IDS.OPTIMISM_GOERLI | typeof CHAIN_IDS.BASE_TESTNET - | typeof CHAIN_IDS.BASE | typeof CHAIN_IDS.OPBNB_TESTNET | typeof CHAIN_IDS.OPBNB | typeof CHAIN_IDS.BSC_TESTNET @@ -851,12 +927,21 @@ export const BUYABLE_CHAINS_MAP: { | typeof CHAIN_IDS.FANTOM_TESTNET | typeof CHAIN_IDS.MOONBEAM_TESTNET | typeof CHAIN_IDS.LINEA_GOERLI + | typeof CHAIN_IDS.LINEA_SEPOLIA | typeof CHAIN_IDS.GOERLI | typeof CHAIN_IDS.SEPOLIA | typeof CHAIN_IDS.GNOSIS | typeof CHAIN_IDS.AURORA | typeof CHAIN_IDS.ARBITRUM_GOERLI | typeof CHAIN_IDS.BLAST + | typeof CHAIN_IDS.FILECOIN + | typeof CHAIN_IDS.POLYGON_ZKEVM + | typeof CHAIN_IDS.SCROLL + | typeof CHAIN_IDS.SCROLL_SEPOLIA + | typeof CHAIN_IDS.WETHIO + | typeof CHAIN_IDS.CHZ + | typeof CHAIN_IDS.NUMBERS + | typeof CHAIN_IDS.SEI >]: BuyableChainSettings; } = { [CHAIN_IDS.MAINNET]: { @@ -919,6 +1004,10 @@ export const BUYABLE_CHAINS_MAP: { nativeCurrency: CURRENCY_SYMBOLS.ETH, network: 'zksync', }, + [CHAIN_IDS.BASE]: { + nativeCurrency: CURRENCY_SYMBOLS.ETH, + network: 'base', + }, }; export const FEATURED_RPCS: RPCDefinition[] = [ @@ -972,26 +1061,6 @@ export const FEATURED_RPCS: RPCDefinition[] = [ imageUrl: MATIC_TOKEN_IMAGE_URL, }, }, - { - chainId: CHAIN_IDS.CELO, - nickname: CELO_DISPLAY_NAME, - rpcUrl: `https://celo-mainnet.infura.io/v3/${infuraProjectId}`, - ticker: CURRENCY_SYMBOLS.CELO, - rpcPrefs: { - blockExplorerUrl: 'https://celoscan.io', - imageUrl: CELO_TOKEN_IMAGE_URL, - }, - }, - { - chainId: CHAIN_IDS.GNOSIS, - nickname: GNOSIS_DISPLAY_NAME, - rpcUrl: `https://rpc.gnosischain.com`, - ticker: CURRENCY_SYMBOLS.GNOSIS, - rpcPrefs: { - blockExplorerUrl: 'https://gnosisscan.io', - imageUrl: GNOSIS_TOKEN_IMAGE_URL, - }, - }, { chainId: CHAIN_IDS.ZKSYNC_ERA, nickname: ZK_SYNC_ERA_DISPLAY_NAME, @@ -1045,4 +1114,12 @@ export const TEST_NETWORKS = [ GOERLI_DISPLAY_NAME, SEPOLIA_DISPLAY_NAME, LINEA_GOERLI_DISPLAY_NAME, + LINEA_SEPOLIA_DISPLAY_NAME, +]; + +export const TEST_NETWORK_IDS = [ + CHAIN_IDS.GOERLI, + CHAIN_IDS.SEPOLIA, + CHAIN_IDS.LINEA_GOERLI, + CHAIN_IDS.LINEA_SEPOLIA, ]; diff --git a/shared/constants/notifications.ts b/shared/constants/notifications.ts new file mode 100644 index 000000000000..54254570d1b2 --- /dev/null +++ b/shared/constants/notifications.ts @@ -0,0 +1,2 @@ +export const NOTIFICATION_HEIGHT = 620; +export const NOTIFICATION_WIDTH = 360; diff --git a/shared/constants/offscreen-communication.ts b/shared/constants/offscreen-communication.ts index 3be4d5da32de..618239609956 100644 --- a/shared/constants/offscreen-communication.ts +++ b/shared/constants/offscreen-communication.ts @@ -7,6 +7,7 @@ export enum OffscreenCommunicationTarget { ledgerOffscreen = 'ledger-offscreen', latticeOffscreen = 'lattice-offscreen', extension = 'extension-offscreen', + extensionMain = 'extension', } /** @@ -39,7 +40,7 @@ export enum LedgerAction { unlock = 'ledger-unlock', getPublicKey = 'ledger-unlock', signTransaction = 'ledger-sign-transaction', - signMessage = 'ledger-sign-message', + signPersonalMessage = 'ledger-sign-personal-message', signTypedData = 'ledger-sign-typed-data', } diff --git a/shared/constants/onboarding.ts b/shared/constants/onboarding.ts new file mode 100644 index 000000000000..7dec861ad63f --- /dev/null +++ b/shared/constants/onboarding.ts @@ -0,0 +1,19 @@ +export enum FirstTimeFlowType { + /** + * When a user imports a wallet from a seed phrase they will have the + * 'import' firstTimeFlowType. + */ + import = 'import', + /** + * When a user creates a new wallet during onboarding they will have the + * 'create' firstTimeFlowType. + */ + create = 'create', + /** + * A special case for when a user's MetaMask encounters an error during the + * loading of state. They will be presented with an option to restore their + * MetaMask if their vault was backed up. This will set their + * firstTimeFlowType to 'restore'. + */ + restore = 'restore', +} diff --git a/shared/constants/permissions.test.js b/shared/constants/permissions.test.js index 38dc1e1c87a4..b63014359bb7 100644 --- a/shared/constants/permissions.test.js +++ b/shared/constants/permissions.test.js @@ -15,7 +15,6 @@ describe('EndowmentPermissions', () => { expect(Object.keys(EndowmentPermissions).sort()).toStrictEqual( [ 'endowment:name-lookup', - 'endowment:signature-insight', ...Object.keys(endowmentPermissionBuilders).filter( (targetName) => !Object.keys(ExcludedSnapEndowments).includes(targetName), diff --git a/shared/constants/permissions.ts b/shared/constants/permissions.ts index 1907744d2102..8f1cf4ced063 100644 --- a/shared/constants/permissions.ts +++ b/shared/constants/permissions.ts @@ -1,5 +1,10 @@ export const CaveatTypes = Object.freeze({ restrictReturnedAccounts: 'restrictReturnedAccounts' as const, + restrictNetworkSwitching: 'restrictNetworkSwitching' as const, +}); + +export const RestrictedEthMethods = Object.freeze({ + eth_accounts: 'eth_accounts', }); export const RestrictedMethods = Object.freeze({ @@ -20,6 +25,14 @@ export const RestrictedMethods = Object.freeze({ ///: END:ONLY_INCLUDE_IF } as const); +///: BEGIN:ONLY_INCLUDE_IF(snaps) +// ConnectionPermission is pseudo permission used to make possible +// displaying pre-approved connections in the UI seamlessly, alongside other permissions. +export const ConnectionPermission = Object.freeze({ + connection_permission: 'connection_permission', +}); +///: END:ONLY_INCLUDE_IF + ///: BEGIN:ONLY_INCLUDE_IF(snaps) export * from './snaps/permissions'; ///: END:ONLY_INCLUDE_IF diff --git a/shared/constants/security-provider.ts b/shared/constants/security-provider.ts index 537d0bd41e5c..1c8dd6433fac 100644 --- a/shared/constants/security-provider.ts +++ b/shared/constants/security-provider.ts @@ -1,3 +1,10 @@ +import { Hex } from '@metamask/utils'; +import { + SecurityAlertResponse, + TransactionType, +} from '@metamask/transaction-controller'; +import { CHAIN_IDS } from './network'; + export enum SecurityProvider { Blockaid = 'blockaid', } @@ -79,4 +86,29 @@ export const SECURITY_PROVIDER_MESSAGE_SEVERITY = { export const FALSE_POSITIVE_REPORT_BASE_URL = 'https://blockaid-false-positive-portal.metamask.io'; + export const SECURITY_PROVIDER_UTM_SOURCE = 'metamask-ppom'; + +export const SECURITY_PROVIDER_SUPPORTED_CHAIN_IDS: Hex[] = [ + CHAIN_IDS.ARBITRUM, + CHAIN_IDS.AVALANCHE, + CHAIN_IDS.BASE, + CHAIN_IDS.BSC, + CHAIN_IDS.LINEA_MAINNET, + CHAIN_IDS.MAINNET, + CHAIN_IDS.OPBNB, + CHAIN_IDS.OPTIMISM, + CHAIN_IDS.POLYGON, + CHAIN_IDS.SEPOLIA, +]; + +export const SECURITY_PROVIDER_EXCLUDED_TRANSACTION_TYPES = [ + TransactionType.swap, + TransactionType.swapApproval, + TransactionType.swapAndSend, +]; + +export const LOADING_SECURITY_ALERT_RESPONSE: SecurityAlertResponse = { + result_type: BlockaidResultType.Loading, + reason: BlockaidReason.inProgress, +}; diff --git a/shared/constants/smartTransactions.js b/shared/constants/smartTransactions.js deleted file mode 100644 index a77d993c7085..000000000000 --- a/shared/constants/smartTransactions.js +++ /dev/null @@ -1,5 +0,0 @@ -import { SECOND } from './time'; - -export const FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME = SECOND * 10; -export const FALLBACK_SMART_TRANSACTIONS_DEADLINE = 180; -export const FALLBACK_SMART_TRANSACTIONS_MAX_FEE_MULTIPLIER = 2; diff --git a/shared/constants/smartTransactions.test.ts b/shared/constants/smartTransactions.test.ts new file mode 100644 index 000000000000..47f4f8250c2b --- /dev/null +++ b/shared/constants/smartTransactions.test.ts @@ -0,0 +1,33 @@ +import { isProduction } from '../modules/environment'; +import { getAllowedSmartTransactionsChainIds } from './smartTransactions'; +import { CHAIN_IDS } from './network'; + +jest.mock('../modules/environment', () => ({ + isProduction: jest.fn(() => false), // Initially mock isProduction to return false +})); + +// Cast isProduction to jest.Mock to inform TypeScript about the mock type +const mockIsProduction = isProduction as jest.Mock; + +describe('smartTransactions', () => { + describe('getAllowedSmartTransactionsChainIds', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should return the correct chain IDs for development environment', () => { + mockIsProduction.mockReturnValue(false); + const allowedChainIds = getAllowedSmartTransactionsChainIds(); + expect(allowedChainIds).toStrictEqual([ + CHAIN_IDS.MAINNET, + CHAIN_IDS.SEPOLIA, + ]); + }); + + it('should return the correct chain IDs for production environment', () => { + mockIsProduction.mockReturnValue(true); + const allowedChainIds = getAllowedSmartTransactionsChainIds(); + expect(allowedChainIds).toStrictEqual([CHAIN_IDS.MAINNET]); + }); + }); +}); diff --git a/shared/constants/smartTransactions.ts b/shared/constants/smartTransactions.ts new file mode 100644 index 000000000000..4e39ec5ba234 --- /dev/null +++ b/shared/constants/smartTransactions.ts @@ -0,0 +1,31 @@ +import { isProduction } from '../modules/environment'; +import { SECOND } from './time'; +import { CHAIN_IDS } from './network'; + +export const FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME: number = SECOND * 10; +export const FALLBACK_SMART_TRANSACTIONS_DEADLINE: number = 180; +export const FALLBACK_SMART_TRANSACTIONS_EXPECTED_DEADLINE = 45; +export const FALLBACK_SMART_TRANSACTIONS_MAX_DEADLINE = 150; +export const FALLBACK_SMART_TRANSACTIONS_MAX_FEE_MULTIPLIER: number = 2; + +const ALLOWED_SMART_TRANSACTIONS_CHAIN_IDS_DEVELOPMENT: string[] = [ + CHAIN_IDS.MAINNET, + CHAIN_IDS.SEPOLIA, +]; + +const ALLOWED_SMART_TRANSACTIONS_CHAIN_IDS_PRODUCTION: string[] = [ + CHAIN_IDS.MAINNET, +]; + +export const getAllowedSmartTransactionsChainIds = (): string[] => { + return isProduction() + ? ALLOWED_SMART_TRANSACTIONS_CHAIN_IDS_PRODUCTION + : ALLOWED_SMART_TRANSACTIONS_CHAIN_IDS_DEVELOPMENT; +}; + +export const SKIP_STX_RPC_URL_CHECK_CHAIN_IDS: string[] = [CHAIN_IDS.SEPOLIA]; + +export const CANCEL_GAS_LIMIT_DEC = 21000; + +export const SMART_TRANSACTIONS_LEARN_MORE_URL = + 'https://support.metamask.io/transactions-and-gas/transactions/smart-transactions/'; diff --git a/shared/constants/snaps.ts b/shared/constants/snaps.ts deleted file mode 100644 index b94ff7c7ab31..000000000000 --- a/shared/constants/snaps.ts +++ /dev/null @@ -1,43 +0,0 @@ -///: BEGIN:ONLY_INCLUDE_IF(snaps) -type SnapsMetadata = { - [snapId: string]: { - name: string; - }; -}; - -// If a Snap ID is present in this object, its metadata is used before the info -// of the snap is fetched. Ideally this information would be fetched from the -// snap registry, but this is a temporary solution. -export const SNAPS_METADATA: SnapsMetadata = { - 'npm:@metamask/test-snap-error': { - name: 'Error Test Snap', - }, - 'npm:@metamask/test-snap-confirm': { - name: 'Confirm Test Snap', - }, - 'npm:@metamask/test-snap-dialog': { - name: 'Dialog Test Snap', - }, - 'npm:@metamask/test-snap-bip44': { - name: 'BIP-44 Test Snap', - }, - 'npm:@metamask/test-snap-managestate': { - name: 'Manage State Test Snap', - }, - 'npm:@metamask/test-snap-notification': { - name: 'Notification Test Snap', - }, - 'npm:@metamask/test-snap-bip32': { - name: 'BIP-32 Test Snap', - }, - 'npm:@metamask/test-snap-insights': { - name: 'Insights Test Snap', - }, - 'npm:@metamask/test-snap-rpc': { - name: 'RPC Test Snap', - }, - 'npm:@metamask/test-snap-cronjob': { - name: 'Cronjob Test Snap', - }, -}; -///: END:ONLY_INCLUDE_IF diff --git a/shared/constants/snaps/permissions.ts b/shared/constants/snaps/permissions.ts index f0c798e05e0b..aca6f5ef8023 100644 --- a/shared/constants/snaps/permissions.ts +++ b/shared/constants/snaps/permissions.ts @@ -7,8 +7,8 @@ export const EndowmentPermissions = Object.freeze({ 'endowment:webassembly': 'endowment:webassembly', 'endowment:lifecycle-hooks': 'endowment:lifecycle-hooks', 'endowment:page-home': 'endowment:page-home', - ///: BEGIN:ONLY_INCLUDE_IF(build-flask) 'endowment:signature-insight': 'endowment:signature-insight', + ///: BEGIN:ONLY_INCLUDE_IF(build-flask) 'endowment:name-lookup': 'endowment:name-lookup', ///: END:ONLY_INCLUDE_IF ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) @@ -26,8 +26,6 @@ export const ExcludedSnapEndowments = Object.freeze({ ///: BEGIN:ONLY_INCLUDE_IF(build-main) 'endowment:name-lookup': 'This endowment is experimental and therefore not available.', - 'endowment:signature-insight': - 'This endowment is experimental and therefore not available.', ///: END:ONLY_INCLUDE_IF }); diff --git a/shared/constants/swaps.ts b/shared/constants/swaps.ts index 5ec99e667e78..bd3db9d94a2f 100644 --- a/shared/constants/swaps.ts +++ b/shared/constants/swaps.ts @@ -49,6 +49,10 @@ export type SwapsTokenObject = { iconUrl: string; }; +type BlockExplorerUrlMap = { + [key: string]: string; +}; + export const ETH_SWAPS_TOKEN_OBJECT: SwapsTokenObject = { symbol: CURRENCY_SYMBOLS.ETH, name: 'Ether', @@ -121,6 +125,10 @@ export const LINEA_SWAPS_TOKEN_OBJECT: SwapsTokenObject = { ...ETH_SWAPS_TOKEN_OBJECT, } as const; +export const BASE_SWAPS_TOKEN_OBJECT: SwapsTokenObject = { + ...ETH_SWAPS_TOKEN_OBJECT, +} as const; + // A gas value for ERC20 approve calls that should be sufficient for all ERC20 approve implementations export const DEFAULT_ERC20_APPROVE_GAS = '0x1d4c0'; @@ -135,6 +143,7 @@ const ARBITRUM_CONTRACT_ADDRESS = '0x9dda6ef3d919c9bc8885d5560999a3640431e8e6'; const LINEA_CONTRACT_ADDRESS = '0x9dda6ef3d919c9bc8885d5560999a3640431e8e6'; const ZKSYNC_ERA_CONTRACT_ADDRESS = '0xf504c1fe13d14df615e66dcd0abf39e60c697f34'; +const BASE_CONTRACT_ADDRESS = '0x9dda6ef3d919c9bc8885d5560999a3640431e8e6'; export const WETH_CONTRACT_ADDRESS = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'; @@ -154,11 +163,14 @@ export const WETH_ZKSYNC_ERA_CONTRACT_ADDRESS = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91'; export const WETH_LINEA_CONTRACT_ADDRESS = '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f'; +export const WETH_BASE_CONTRACT_ADDRESS = + '0x4200000000000000000000000000000000000006'; const SWAPS_TESTNET_CHAIN_ID = '0x539'; -export const SWAPS_API_V2_BASE_URL = 'https://swap.metaswap.codefi.network'; +export const SWAPS_API_V2_BASE_URL = 'https://swap.api.cx.metamask.io'; export const SWAPS_DEV_API_V2_BASE_URL = 'https://swap.dev-api.cx.metamask.io'; +export const TOKEN_API_BASE_URL = 'https://tokens.api.cx.metamask.io'; export const GAS_API_BASE_URL = 'https://gas.api.cx.metamask.io'; export const GAS_DEV_API_BASE_URL = 'https://gas.uat-api.cx.metamask.io'; @@ -171,9 +183,7 @@ const OPTIMISM_DEFAULT_BLOCK_EXPLORER_URL = 'https://optimistic.etherscan.io/'; const ARBITRUM_DEFAULT_BLOCK_EXPLORER_URL = 'https://arbiscan.io/'; const ZKSYNC_DEFAULT_BLOCK_EXPLORER_URL = 'https://explorer.zksync.io/'; const LINEA_DEFAULT_BLOCK_EXPLORER_URL = 'https://lineascan.build/'; - -export const SMART_SWAPS_FAQ_AND_RISK_DISCLOSURES_URL = - 'https://support.metamask.io/hc/articles/9184393821211'; +const BASE_DEFAULT_BLOCK_EXPLORER_URL = 'https://basescan.org/'; export const ALLOWED_PROD_SWAPS_CHAIN_IDS = [ CHAIN_IDS.MAINNET, @@ -185,6 +195,7 @@ export const ALLOWED_PROD_SWAPS_CHAIN_IDS = [ CHAIN_IDS.ARBITRUM, CHAIN_IDS.ZKSYNC_ERA, CHAIN_IDS.LINEA_MAINNET, + CHAIN_IDS.BASE, ] as const; export const ALLOWED_DEV_SWAPS_CHAIN_IDS = [ @@ -208,6 +219,7 @@ export const SWAPS_CHAINID_CONTRACT_ADDRESS_MAP = { [CHAIN_IDS.ARBITRUM]: ARBITRUM_CONTRACT_ADDRESS, [CHAIN_IDS.ZKSYNC_ERA]: ZKSYNC_ERA_CONTRACT_ADDRESS, [CHAIN_IDS.LINEA_MAINNET]: LINEA_CONTRACT_ADDRESS, + [CHAIN_IDS.BASE]: BASE_CONTRACT_ADDRESS, } as const; export const SWAPS_WRAPPED_TOKENS_ADDRESSES = { @@ -221,6 +233,7 @@ export const SWAPS_WRAPPED_TOKENS_ADDRESSES = { [CHAIN_IDS.ARBITRUM]: WETH_ARBITRUM_CONTRACT_ADDRESS, [CHAIN_IDS.ZKSYNC_ERA]: WETH_ZKSYNC_ERA_CONTRACT_ADDRESS, [CHAIN_IDS.LINEA_MAINNET]: WETH_LINEA_CONTRACT_ADDRESS, + [CHAIN_IDS.BASE]: WETH_BASE_CONTRACT_ADDRESS, } as const; export const ALLOWED_CONTRACT_ADDRESSES = { @@ -264,6 +277,10 @@ export const ALLOWED_CONTRACT_ADDRESSES = { SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[CHAIN_IDS.LINEA_MAINNET], SWAPS_WRAPPED_TOKENS_ADDRESSES[CHAIN_IDS.LINEA_MAINNET], ], + [CHAIN_IDS.BASE]: [ + SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[CHAIN_IDS.BASE], + SWAPS_WRAPPED_TOKENS_ADDRESSES[CHAIN_IDS.BASE], + ], } as const; export const SWAPS_CHAINID_DEFAULT_TOKEN_MAP = { @@ -278,19 +295,22 @@ export const SWAPS_CHAINID_DEFAULT_TOKEN_MAP = { [CHAIN_IDS.ARBITRUM]: ARBITRUM_SWAPS_TOKEN_OBJECT, [CHAIN_IDS.ZKSYNC_ERA]: ZKSYNC_ERA_SWAPS_TOKEN_OBJECT, [CHAIN_IDS.LINEA_MAINNET]: LINEA_SWAPS_TOKEN_OBJECT, + [CHAIN_IDS.BASE]: BASE_SWAPS_TOKEN_OBJECT, } as const; -export const SWAPS_CHAINID_DEFAULT_BLOCK_EXPLORER_URL_MAP = { - [CHAIN_IDS.BSC]: BSC_DEFAULT_BLOCK_EXPLORER_URL, - [CHAIN_IDS.MAINNET]: MAINNET_DEFAULT_BLOCK_EXPLORER_URL, - [CHAIN_IDS.POLYGON]: POLYGON_DEFAULT_BLOCK_EXPLORER_URL, - [CHAIN_IDS.GOERLI]: GOERLI_DEFAULT_BLOCK_EXPLORER_URL, - [CHAIN_IDS.AVALANCHE]: AVALANCHE_DEFAULT_BLOCK_EXPLORER_URL, - [CHAIN_IDS.OPTIMISM]: OPTIMISM_DEFAULT_BLOCK_EXPLORER_URL, - [CHAIN_IDS.ARBITRUM]: ARBITRUM_DEFAULT_BLOCK_EXPLORER_URL, - [CHAIN_IDS.ZKSYNC_ERA]: ZKSYNC_DEFAULT_BLOCK_EXPLORER_URL, - [CHAIN_IDS.LINEA_MAINNET]: LINEA_DEFAULT_BLOCK_EXPLORER_URL, -} as const; +export const SWAPS_CHAINID_DEFAULT_BLOCK_EXPLORER_URL_MAP: BlockExplorerUrlMap = + { + [CHAIN_IDS.BSC]: BSC_DEFAULT_BLOCK_EXPLORER_URL, + [CHAIN_IDS.MAINNET]: MAINNET_DEFAULT_BLOCK_EXPLORER_URL, + [CHAIN_IDS.POLYGON]: POLYGON_DEFAULT_BLOCK_EXPLORER_URL, + [CHAIN_IDS.GOERLI]: GOERLI_DEFAULT_BLOCK_EXPLORER_URL, + [CHAIN_IDS.AVALANCHE]: AVALANCHE_DEFAULT_BLOCK_EXPLORER_URL, + [CHAIN_IDS.OPTIMISM]: OPTIMISM_DEFAULT_BLOCK_EXPLORER_URL, + [CHAIN_IDS.ARBITRUM]: ARBITRUM_DEFAULT_BLOCK_EXPLORER_URL, + [CHAIN_IDS.ZKSYNC_ERA]: ZKSYNC_DEFAULT_BLOCK_EXPLORER_URL, + [CHAIN_IDS.LINEA_MAINNET]: LINEA_DEFAULT_BLOCK_EXPLORER_URL, + [CHAIN_IDS.BASE]: BASE_DEFAULT_BLOCK_EXPLORER_URL, + } as const; export const ETHEREUM = 'ethereum'; export const POLYGON = 'polygon'; @@ -301,6 +321,7 @@ export const OPTIMISM = 'optimism'; export const ARBITRUM = 'arbitrum'; export const ZKSYNC_ERA = 'zksync'; export const LINEA = 'linea'; +export const BASE = 'base'; export const SWAPS_CLIENT_ID = 'extension'; diff --git a/shared/constants/tokens.js b/shared/constants/tokens.js index bf5dc151e3c4..26ca96258fed 100644 --- a/shared/constants/tokens.js +++ b/shared/constants/tokens.js @@ -41,7 +41,7 @@ export const STATIC_MAINNET_TOKEN_LIST = Object.keys(contractMap).reduce( ); export const TOKEN_API_METASWAP_CODEFI_URL = - 'https://token-api.metaswap.codefi.network/tokens/'; + 'https://token.api.cx.metamask.io/tokens/'; export const MAX_TOKEN_ALLOWANCE_AMOUNT = new BigNumber(2) .pow(256) .minus(1) diff --git a/shared/constants/transaction.ts b/shared/constants/transaction.ts index 713382c63ea2..726148865512 100644 --- a/shared/constants/transaction.ts +++ b/shared/constants/transaction.ts @@ -110,6 +110,10 @@ export enum TransactionGroupCategory { * will be shown. */ swap = 'swap', + /** + * Transaction group representing a token swap through MetaMask Swaps, where the final token is sent to another address. + */ + swapAndSend = 'swapAndSend', } /** @@ -191,3 +195,5 @@ export enum TokenStandard { /** Not a token, but rather the base asset of the selected chain. */ none = 'NONE', } + +export const EIP712_PRIMARY_TYPE_PERMIT = 'Permit'; diff --git a/shared/constants/urls.ts b/shared/constants/urls.ts new file mode 100644 index 000000000000..a44d7d2573c8 --- /dev/null +++ b/shared/constants/urls.ts @@ -0,0 +1,3 @@ +export enum BaseUrl { + Portfolio = 'https://portfolio.metamask.io', +} diff --git a/shared/constants/verification.ts b/shared/constants/verification.ts new file mode 100644 index 000000000000..ce6ddaed9ea9 --- /dev/null +++ b/shared/constants/verification.ts @@ -0,0 +1,28 @@ +import { Hex } from '@metamask/utils'; +import { + EXPERIENCES_TYPE, + FIRST_PARTY_CONTRACT_NAMES, +} from './first-party-contracts'; + +export const TX_SIG_LEN = 130; +export const EXPERIENCES_TO_VERIFY = [EXPERIENCES_TYPE.METAMASK_BRIDGE]; +export const TRUSTED_SIGNERS: Partial> = { + [EXPERIENCES_TYPE.METAMASK_BRIDGE]: + '0x533FbF047Ed13C20e263e2576e41c747206d1348', +}; + +// look up the corresponding experience provided an address on a chain id +export const getExperience = ( + address: Hex, + chainId: Hex, +): EXPERIENCES_TYPE | undefined => + ( + Object.entries(FIRST_PARTY_CONTRACT_NAMES) as [ + EXPERIENCES_TYPE, + Record, + ][] + ).find( + ([, chainMap]) => + (chainMap[chainId]?.toLowerCase() as Hex) === + (address.toLowerCase() as Hex), + )?.[0]; diff --git a/shared/lib/error-utils.js b/shared/lib/error-utils.js index cf2f29569f17..567337eb5ab4 100644 --- a/shared/lib/error-utils.js +++ b/shared/lib/error-utils.js @@ -1,14 +1,6 @@ -///: BEGIN:ONLY_INCLUDE_IF(desktop) -import browser from 'webextension-polyfill'; -///: END:ONLY_INCLUDE_IF import { memoize } from 'lodash'; import getFirstPreferredLangCode from '../../app/scripts/lib/get-first-preferred-lang-code'; import { fetchLocale, loadRelativeTimeFormatLocaleData } from '../modules/i18n'; -///: BEGIN:ONLY_INCLUDE_IF(desktop) -import { renderDesktopError } from '../../ui/pages/desktop-error/render-desktop-error'; -import { EXTENSION_ERROR_PAGE_TYPES } from '../constants/desktop'; -import { openCustomProtocol } from './deep-linking'; -///: END:ONLY_INCLUDE_IF import switchDirection from './switch-direction'; const _setupLocale = async (currentLocale) => { @@ -37,14 +29,7 @@ const getLocaleContext = (currentLocaleMessages, enLocaleMessages) => { }; }; -export async function getErrorHtml( - errorKey, - supportLink, - metamaskState, - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - err, - ///: END:ONLY_INCLUDE_IF -) { +export async function getErrorHtml(errorKey, supportLink, metamaskState) { let response, preferredLocale; if (metamaskState?.currentLocale) { preferredLocale = metamaskState.currentLocale; @@ -62,23 +47,6 @@ export async function getErrorHtml( const { currentLocaleMessages, enLocaleMessages } = response; const t = getLocaleContext(currentLocaleMessages, enLocaleMessages); - ///: BEGIN:ONLY_INCLUDE_IF(desktop) - const isDesktopEnabled = metamaskState?.desktopEnabled === true; - - if (isDesktopEnabled) { - let errorType = EXTENSION_ERROR_PAGE_TYPES.CRITICAL_ERROR; - - if (err?.message.includes('No response from RPC')) { - errorType = EXTENSION_ERROR_PAGE_TYPES.CONNECTION_LOST; - } - - return renderDesktopError({ - type: errorType, - t, - isHtmlError: true, - }); - } - ///: END:ONLY_INCLUDE_IF /** * The pattern ${errorKey === 'troubleStarting' ? t('troubleStarting') : ''} * is neccessary because we we need linter to see the string @@ -116,64 +84,3 @@ export async function getErrorHtml( `; } - -///: BEGIN:ONLY_INCLUDE_IF(desktop) -export const MMD_DOWNLOAD_LINK = - 'https://github.com/MetaMask/metamask-desktop/releases'; - -function disableDesktop(backgroundConnection) { - backgroundConnection.disableDesktopError(); -} - -export function downloadDesktopApp() { - global.platform.openTab({ - url: MMD_DOWNLOAD_LINK, - }); -} - -export function downloadExtension() { - global.platform.openTab({ url: 'https://metamask.io/' }); -} - -export function restartExtension() { - browser.runtime.reload(); -} - -export function openOrDownloadMMD() { - openCustomProtocol('metamask-desktop://pair').catch(() => { - window.open(MMD_DOWNLOAD_LINK, '_blank').focus(); - }); -} - -export function registerDesktopErrorActions(backgroundConnection) { - const disableDesktopButton = document.getElementById( - 'desktop-error-button-disable-mmd', - ); - const restartMMButton = document.getElementById( - 'desktop-error-button-restart-mm', - ); - const downloadMMDButton = document.getElementById( - 'desktop-error-button-download-mmd', - ); - - const openOrDownloadMMDButton = document.getElementById( - 'desktop-error-button-open-or-download-mmd', - ); - - disableDesktopButton?.addEventListener('click', (_) => { - disableDesktop(backgroundConnection); - }); - - restartMMButton?.addEventListener('click', (_) => { - restartExtension(); - }); - - downloadMMDButton?.addEventListener('click', (_) => { - downloadDesktopApp(); - }); - - openOrDownloadMMDButton?.addEventListener('click', (_) => { - openOrDownloadMMD(); - }); -} -///: END:ONLY_INCLUDE_IF diff --git a/shared/lib/error-utils.test.js b/shared/lib/error-utils.test.js index 9874d9b24c00..6efc6ec4584b 100644 --- a/shared/lib/error-utils.test.js +++ b/shared/lib/error-utils.test.js @@ -1,16 +1,6 @@ -import browser from 'webextension-polyfill'; import { fetchLocale } from '../modules/i18n'; import { SUPPORT_LINK } from './ui-utils'; -import { - downloadDesktopApp, - openOrDownloadMMD, - downloadExtension, - getErrorHtml, - restartExtension, - registerDesktopErrorActions, - MMD_DOWNLOAD_LINK, -} from './error-utils'; -import { openCustomProtocol } from './deep-linking'; +import { getErrorHtml } from './error-utils'; jest.mock('../modules/i18n', () => ({ fetchLocale: jest.fn(), @@ -85,93 +75,4 @@ describe('Error utils Tests', function () { expect(errorHtml).toContain(stillGettingMessageMessage); expect(errorHtml).toContain(sendBugReportMessage); }); - describe('desktop', () => { - it('downloadDesktopApp opens a new tab on metamask-desktop releases url', () => { - downloadDesktopApp(); - - expect(global.platform.openTab).toHaveBeenCalledTimes(1); - expect(global.platform.openTab).toHaveBeenCalledWith({ - url: MMD_DOWNLOAD_LINK, - }); - }); - - it('downloadExtension opens a new tab on metamask extension url', () => { - downloadExtension(); - - expect(global.platform.openTab).toHaveBeenCalledTimes(1); - expect(global.platform.openTab).toHaveBeenCalledWith({ - url: 'https://metamask.io/', - }); - }); - - it('restartExtension calls runtime reload method', () => { - restartExtension(); - - expect(browser.runtime.reload).toHaveBeenCalledTimes(1); - }); - - describe('openOrDownloadMMD', () => { - it('launches installed desktop app by calling openCustomProtocol successfully', () => { - openCustomProtocol.mockResolvedValue(); - openOrDownloadMMD(); - - expect(openCustomProtocol).toHaveBeenCalledTimes(1); - expect(openCustomProtocol).toHaveBeenCalledWith( - 'metamask-desktop://pair', - ); - }); - - it('opens metamask-desktop release url when fails to find and start a local metamask-desktop app', async () => { - openCustomProtocol.mockRejectedValue(); - const focusMock = jest.fn(); - jest.spyOn(window, 'open').mockReturnValue({ - focus: focusMock, - }); - - openOrDownloadMMD(); - - // this ensures that we are awaiting for pending promises to resolve - // as the openOrDownloadMMD calls a promise, but returns before it is resolved - await new Promise(process.nextTick); - - expect(openCustomProtocol).toHaveBeenCalledTimes(1); - expect(openCustomProtocol).toHaveBeenCalledWith( - 'metamask-desktop://pair', - ); - - expect(window.open).toHaveBeenCalledTimes(1); - expect(window.open).toHaveBeenCalledWith(MMD_DOWNLOAD_LINK, '_blank'); - expect(focusMock).toHaveBeenCalledTimes(1); - }); - }); - - it('registerDesktopErrorActions add click event listeners for each desktop error elements', async () => { - const addEventListenerMock = jest.fn(); - jest.spyOn(document, 'getElementById').mockReturnValue({ - addEventListener: addEventListenerMock, - }); - - registerDesktopErrorActions(); - - expect(document.getElementById).toHaveBeenCalledTimes(4); - expect(document.getElementById).toHaveBeenNthCalledWith( - 1, - 'desktop-error-button-disable-mmd', - ); - expect(document.getElementById).toHaveBeenNthCalledWith( - 2, - 'desktop-error-button-restart-mm', - ); - expect(document.getElementById).toHaveBeenNthCalledWith( - 3, - 'desktop-error-button-download-mmd', - ); - expect(document.getElementById).toHaveBeenNthCalledWith( - 4, - 'desktop-error-button-open-or-download-mmd', - ); - - expect(addEventListenerMock).toHaveBeenCalledTimes(4); - }); - }); }); diff --git a/shared/lib/fetch-with-cache.ts b/shared/lib/fetch-with-cache.ts index d66f11a32c7b..969fba9f869f 100644 --- a/shared/lib/fetch-with-cache.ts +++ b/shared/lib/fetch-with-cache.ts @@ -9,7 +9,11 @@ const fetchWithCache = async ({ functionName = '', }: { url: string; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any fetchOptions?: Record; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any cacheOptions?: Record; functionName: string; }) => { diff --git a/shared/lib/metamask-controller-utils.js b/shared/lib/metamask-controller-utils.js index dcc76476fdb8..c10e17c37763 100644 --- a/shared/lib/metamask-controller-utils.js +++ b/shared/lib/metamask-controller-utils.js @@ -1,3 +1,8 @@ +import { TransactionType } from '@metamask/transaction-controller'; + export function getTokenValueParam(tokenData = {}) { + if (tokenData?.name === TransactionType.tokenMethodIncreaseAllowance) { + return tokenData?.args?.increment?.toString(); + } return tokenData?.args?._value?.toString(); } diff --git a/shared/lib/swaps-utils.js b/shared/lib/swaps-utils.js index 5b5107b4495d..62c71ecbaadb 100644 --- a/shared/lib/swaps-utils.js +++ b/shared/lib/swaps-utils.js @@ -9,6 +9,7 @@ import { SWAPS_CLIENT_ID, SWAPS_DEV_API_V2_BASE_URL, SWAPS_WRAPPED_TOKENS_ADDRESSES, + TOKEN_API_BASE_URL, } from '../constants/swaps'; import { SECOND } from '../constants/time'; import { isValidHexAddress } from '../modules/hexstring-utils'; @@ -17,6 +18,8 @@ import { addHexPrefix } from '../../app/scripts/lib/util'; import { decimalToHex } from '../modules/conversion.utils'; import fetchWithCache from './fetch-with-cache'; +const FALLBACK_GAS_MULTIPLIER = 1.5; + const TEST_CHAIN_IDS = [CHAIN_IDS.GOERLI, CHAIN_IDS.LOCALHOST]; const clientIdHeader = { 'X-Client-Id': SWAPS_CLIENT_ID }; @@ -131,6 +134,7 @@ const getBaseUrlForNewSwapsApi = (type, chainId) => { ? SWAPS_DEV_API_V2_BASE_URL : SWAPS_API_V2_BASE_URL; const gasApiBaseUrl = useDevApis ? GAS_DEV_API_BASE_URL : GAS_API_BASE_URL; + const tokenApiBaseUrl = TOKEN_API_BASE_URL; const noNetworkSpecificTypes = ['refreshTime']; // These types don't need network info in the URL. if (noNetworkSpecificTypes.includes(type)) { return v2ApiBaseUrl; @@ -140,6 +144,10 @@ const getBaseUrlForNewSwapsApi = (type, chainId) => { if (gasApiTypes.includes(type)) { return `${gasApiBaseUrl}/networks/${chainIdDecimal}`; // Gas calculations are in its own repo. } + const tokenApiTypes = ['blockedTokens']; + if (tokenApiTypes.includes(type)) { + return `${tokenApiBaseUrl}/blocklist?chainId=${chainIdDecimal}`; // Token blocklist is in its own api + } return `${v2ApiBaseUrl}/networks/${chainIdDecimal}`; }; @@ -164,6 +172,8 @@ export const getBaseApi = function (type, chainId) { return `${baseUrl}/aggregatorMetadata`; case 'gasPrices': return `${baseUrl}/gasPrices`; + case 'blockedTokens': + return `${baseUrl}®ion=global`; case 'network': return baseUrl; default: @@ -317,3 +327,37 @@ export async function fetchTradesInfo( return newQuotes; } + +/** + * Given a gas estimate, gas multiplier, max gas, and custom max gas, returns the max gas limit + * to use for a transaction. + * + * @param {string} gasEstimate - The gas estimate for the transaction. + * @param {number} gasMultiplier - The gas multiplier to use. + * @param {number} maxGas - The max gas limit to use. + * @param {string} customMaxGas - The custom max gas limit to use. + * @returns {string} The max gas limit to use for the transaction. + */ + +export function calculateMaxGasLimit( + gasEstimate, + gasMultiplier = FALLBACK_GAS_MULTIPLIER, + maxGas, + customMaxGas, +) { + const gasLimitForMax = new BigNumber(gasEstimate || 0, 16) + .round(0) + .toString(16); + + const usedGasLimitWithMultiplier = new BigNumber(gasLimitForMax, 16) + .times(gasMultiplier, 10) + .round(0) + .toString(16); + + const nonCustomMaxGasLimit = gasEstimate + ? usedGasLimitWithMultiplier + : `0x${decimalToHex(maxGas || 0)}`; + const maxGasLimit = customMaxGas || nonCustomMaxGasLimit; + + return maxGasLimit; +} diff --git a/shared/lib/swaps-utils.test.js b/shared/lib/swaps-utils.test.js index 5979f1e931e1..4cbc0927e1f3 100644 --- a/shared/lib/swaps-utils.test.js +++ b/shared/lib/swaps-utils.test.js @@ -10,7 +10,11 @@ import { TOKENS, MOCK_TRADE_RESPONSE_2, } from '../../ui/pages/swaps/swaps-util-test-constants'; -import { fetchTradesInfo, shouldEnableDirectWrapping } from './swaps-utils'; +import { + fetchTradesInfo, + shouldEnableDirectWrapping, + calculateMaxGasLimit, +} from './swaps-utils'; jest.mock('./storage-helpers', () => ({ getStorageItem: jest.fn(), @@ -63,7 +67,7 @@ describe('Swaps Utils', () => { }, }; it('should fetch trade info on prod', async () => { - nock('https://swap.metaswap.codefi.network') + nock('https://swap.api.cx.metamask.io') .get('/networks/1/trades') .query(true) .reply(200, MOCK_TRADE_RESPONSE_2); @@ -224,4 +228,46 @@ describe('Swaps Utils', () => { expect(shouldEnableDirectWrapping(CHAIN_IDS.MAINNET)).toBe(false); }); }); + + describe('calculateMaxGasLimit', () => { + const gasEstimate = '0x37b15'; + const maxGas = 273740; + let expectedMaxGas = '42d4c'; + let gasMultiplier = 1.2; + let customMaxGas = ''; + + it('should return the max gas limit', () => { + const result = calculateMaxGasLimit( + gasEstimate, + gasMultiplier, + maxGas, + customMaxGas, + ); + expect(result).toStrictEqual(expectedMaxGas); + }); + + it('should return the custom max gas limit', () => { + customMaxGas = '46d4c'; + const result = calculateMaxGasLimit( + gasEstimate, + gasMultiplier, + maxGas, + customMaxGas, + ); + expect(result).toStrictEqual(customMaxGas); + }); + + it('should return the max gas limit with a gas multiplier of 4.5', () => { + gasMultiplier = 4.5; + expectedMaxGas = 'fa9df'; + customMaxGas = ''; + const result = calculateMaxGasLimit( + gasEstimate, + gasMultiplier, + maxGas, + customMaxGas, + ); + expect(result).toStrictEqual(expectedMaxGas); + }); + }); }); diff --git a/shared/lib/token-util.ts b/shared/lib/token-util.ts index 4f8e6b15b9df..18591b550ec7 100644 --- a/shared/lib/token-util.ts +++ b/shared/lib/token-util.ts @@ -17,6 +17,8 @@ import { Web3Provider } from '@ethersproject/providers'; * @param tokenData - ethers Interface token data. * @returns A decimal string value. */ +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any export function getTokenIdParam(tokenData: any = {}): string | undefined { return ( tokenData?.args?._tokenId?.toString() ?? tokenData?.args?.id?.toString() @@ -26,7 +28,11 @@ export function getTokenIdParam(tokenData: any = {}): string | undefined { export async function fetchTokenBalance( address: string, userAddress: string, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any provider: any, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any ): Promise { const ethersProvider = new Web3Provider(provider); const tokenContract = new Contract(address, abiERC20, ethersProvider); @@ -40,7 +46,11 @@ export async function fetchERC1155Balance( address: string, userAddress: string, tokenId: string, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any provider: any, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any ): Promise { if (!userAddress || !tokenId) { return null; diff --git a/shared/lib/transactions-controller-utils.js b/shared/lib/transactions-controller-utils.js index 555091161474..425ff33b6f32 100644 --- a/shared/lib/transactions-controller-utils.js +++ b/shared/lib/transactions-controller-utils.js @@ -39,11 +39,13 @@ export function getSwapsTokensReceivedFromTxMeta( tokenSymbol, txMeta, tokenAddress, - accountAddress, + senderAddress, tokenDecimals, approvalTxMeta, chainId, ) { + const accountAddress = txMeta?.swapAndSendRecipient ?? senderAddress; + const txReceipt = txMeta?.txReceipt; const networkAndAccountSupports1559 = txMeta?.txReceipt?.type === TransactionEnvelopeType.feeMarket; @@ -109,7 +111,7 @@ export function getSwapsTokensReceivedFromTxMeta( const isTransferFromGivenAddress = txReceiptLog.topics && txReceiptLog.topics[2] && - txReceiptLog.topics[2].match(accountAddress.slice(2)); + txReceiptLog.topics[2].match(accountAddress?.slice(2)); return ( isTokenTransfer && isTransferFromGivenToken && diff --git a/shared/lib/ui-utils.js b/shared/lib/ui-utils.js index 7957698efa5f..cbb28bf0bd16 100644 --- a/shared/lib/ui-utils.js +++ b/shared/lib/ui-utils.js @@ -5,6 +5,7 @@ export const SUPPORT_LINK = process.env.SUPPORT_LINK; export const COINGECKO_LINK = 'https://www.coingecko.com/'; export const CRYPTOCOMPARE_LINK = 'https://www.cryptocompare.com/'; export const PRIVACY_POLICY_LINK = 'https://consensys.io/privacy-policy/'; +export const SURVEY_LINK = 'https://www.getfeedback.com/r/Oczu1vP0'; // TODO make sure these links are correct export const ETHERSCAN_PRIVACY_LINK = 'https://etherscan.io/privacyPolicy'; @@ -13,4 +14,11 @@ export const AUTO_DETECT_TOKEN_LEARN_MORE_LINK = 'https://consensys.io/privacy-policy/'; export const CONSENSYS_TERMS_OF_USE = 'https://consensys.io/terms-of-use'; -export const OPENSEA_TERMS_OF_USE = 'https://opensea.io/securityproviderterms'; +export const SECURITY_ALERTS_LEARN_MORE_LINK = + 'https://support.metamask.io/hc/en-us/articles/19878220833947'; + +export const TRANSACTION_SIMULATIONS_LEARN_MORE_LINK = + 'https://support.metamask.io/transactions-and-gas/transactions/simulations/'; + +export const GAS_FEES_LEARN_MORE_URL = + 'https://community.metamask.io/t/what-is-gas-why-do-transactions-take-so-long/3172'; diff --git a/shared/modules/Numeric.test.ts b/shared/modules/Numeric.test.ts index f31d2413ec6d..7f0795b6a40a 100644 --- a/shared/modules/Numeric.test.ts +++ b/shared/modules/Numeric.test.ts @@ -359,6 +359,38 @@ describe('Numeric', () => { }); }); + describe('Absolute value', () => { + it('should return the absolute value of a positive number', () => { + expect(new Numeric(10, 10).abs().toString()).toStrictEqual('10'); + }); + + it('should return the absolute value of a negative number', () => { + expect(new Numeric(-10, 10).abs().toString()).toStrictEqual('10'); + }); + + it('should handle the absolute value of 0', () => { + expect(new Numeric(0, 10).abs().toString()).toStrictEqual('0'); + }); + }); + + describe('isZero', () => { + it('should return true for positive zero', () => { + expect(new Numeric(0, 10).isZero()).toStrictEqual(true); + }); + + it('should return true for negative 0', () => { + expect(new Numeric(-0, 10).isZero()).toStrictEqual(true); + }); + + it('should return false for positive non-zero', () => { + expect(new Numeric(10, 10).isZero()).toStrictEqual(false); + }); + + it('should return false for negative non-zero', () => { + expect(new Numeric(-10, 10).isZero()).toStrictEqual(false); + }); + }); + describe('applyConversionRate', () => { it('should multiply the value by the conversionRate supplied', () => { expect( diff --git a/shared/modules/Numeric.ts b/shared/modules/Numeric.ts index b32d3a9ffc17..d7a87a0050d4 100644 --- a/shared/modules/Numeric.ts +++ b/shared/modules/Numeric.ts @@ -11,7 +11,7 @@ export type NumericValue = string | number | BN | BigNumber; export type NumericBase = 10 | 16; /** - * All variations of isHexString from our own utilities and etherumjs-utils + * All variations of isHexString from our own utilities and ethereumjs-utils * return false for a '-' prefixed hex string. This utility method strips the * possible '-' from the string before testing its validity so that negative * hex values can be properly handled. @@ -25,7 +25,7 @@ function isHexStringOrNegatedHexString(value: string): value is string { /** * BigNumber supports hex strings with '.' (aka decimals) in the string. - * No version of isHexString returs true if the string contains a decimal so + * No version of isHexString returns true if the string contains a decimal so * this method is used to check if both parts of the string split by the * decimal are hex strings. If so we can feed this value into BigNumber to get * a valid Numeric. @@ -83,7 +83,7 @@ function decimalToBigNumber(value: string | number) { * string value must be provided. * * @param value - A hexadecimal or decimal string - * @param numericBase - Either 16 for a hexadeciaml or 10 for a decimal + * @param numericBase - Either 16 for a hexadecimal or 10 for a decimal * @returns A BigNumber representation of the value */ function stringToBigNumber(value: string, numericBase: NumericBase) { @@ -110,7 +110,7 @@ function stringToBigNumber(value: string, numericBase: NumericBase) { } /** - * This method will convert a hexadecimal or deciaml number into a BigNumber. + * This method will convert a hexadecimal or decimal number into a BigNumber. * The second parameter must be supplied and determines whether to treat the * value as a hexadecimal or decimal value. * @@ -241,7 +241,7 @@ function alignOperandDenominations( * decimal of GWEI. Prior to this class the method would call into our root * level 'conversionUtil' which was the proverbial kitchen sink doing * everything from denomination conversion, currency conversion (with provided - * conversionRate prop) and more. The same opeartion can now be expressed as: + * conversionRate prop) and more. The same operation can now be expressed as: * new Numeric(hexString, 16, EtherDenomination.WEI) * .toDenomination(EtherDenomination.GWEI) * .toBase(10) @@ -348,9 +348,9 @@ export class Numeric { * the predecessor to Numeric, 'conversionUtil', were programmed into this * method: * 1. You may supply a denomination that is undefined, which will result in - * nothing happening. Coincidently this is also useful due to the nature of + * nothing happening. Coincidentally this is also useful due to the nature of * chaining operations on Numeric. You may pass an undefined value in this - * method without breaking the chain to conditionally apply a operator. + * method without breaking the chain to conditionally apply an operator. * 2. If the numeric that .toDenomination is called on does not have a * denomination set, that is it was constructed without the third parameter, * then it is assumed to be in ETH. Otherwise we convert it to ETH prior to @@ -532,6 +532,21 @@ export class Numeric { ); } + /** + * Returns a numeric representing the absolute value of the current numeric, + * carrying over the base and denomination from the current Numeric. + */ + abs() { + return new Numeric(this.value.abs(), this.base, this.denomination); + } + + /** + * Checks if the Numeric value is zero. + */ + isZero() { + return this.value.isZero(); + } + greaterThan( comparator: Numeric | NumericValue, base?: NumericBase, @@ -609,7 +624,7 @@ export class Numeric { * Returns a fixed-point decimal string representation of the Numeric * * @param decimals - the amount of decimal precision to use when rounding - * @returns A fixed point decimal string represenation of the Numeric + * @returns A fixed point decimal string representation of the Numeric */ toFixed(decimals: number) { return this.value.toFixed(decimals); diff --git a/shared/modules/browser-runtime.utils.js b/shared/modules/browser-runtime.utils.js index 8f7b2afe71e8..c082ef9b8c78 100644 --- a/shared/modules/browser-runtime.utils.js +++ b/shared/modules/browser-runtime.utils.js @@ -2,8 +2,13 @@ * Utility Functions to support browser.runtime JavaScript API */ +import Bowser from 'bowser'; import browser from 'webextension-polyfill'; import log from 'loglevel'; +import { + BROKEN_PRERENDER_BROWSER_VERSIONS, + FIXED_PRERENDER_BROWSER_VERSIONS, +} from '../../ui/helpers/constants/common'; /** * Returns an Error if extension.runtime.lastError is present @@ -53,3 +58,21 @@ export function checkForLastErrorAndWarn() { return error; } + +/** + * Returns true if the browser is affected by a regression that causes the + * extension port stream established between the contentscript and background + * to be broken when a prerendered (eagerly rendered, hidden) page becomes active (visible to the user). + * + * @param {Bowser} bowser - optional Bowser instance to check against + * @returns {boolean} Whether the browser is affected by the prerender regression + */ +export function getIsBrowserPrerenderBroken( + bowser = Bowser.getParser(window.navigator.userAgent), +) { + return ( + (bowser.satisfies(BROKEN_PRERENDER_BROWSER_VERSIONS) && + !bowser.satisfies(FIXED_PRERENDER_BROWSER_VERSIONS)) ?? + false + ); +} diff --git a/shared/modules/browser-runtime.utils.test.js b/shared/modules/browser-runtime.utils.test.js index b116f2d7caf3..e580112fe29d 100644 --- a/shared/modules/browser-runtime.utils.test.js +++ b/shared/modules/browser-runtime.utils.test.js @@ -1,4 +1,5 @@ import sinon from 'sinon'; +import Bowser from 'bowser'; import browser from 'webextension-polyfill'; import log from 'loglevel'; import * as BrowserRuntimeUtil from './browser-runtime.utils'; @@ -51,4 +52,101 @@ describe('Browser Runtime Utils', () => { log.error.restore(); }); }); + + describe('getIsBrowserPrerenderBroken', () => { + it('should call Bowser.getParser when no parameter is passed', () => { + const spy = jest.spyOn(Bowser, 'getParser'); + BrowserRuntimeUtil.getIsBrowserPrerenderBroken(); + expect(spy).toHaveBeenCalled(); + }); + it.each([ + ['windows', '112.0.0.0', 'Windows NT 10.0; Win64; x64'], + ['windows', '120.0.0.0', 'Windows NT 10.0; Win64; x64'], + ['macos', '112.0.0.0', 'Macintosh; Intel Mac OS X 10_16_0'], + ['macos', '120.0.0.0', 'Macintosh; Intel Mac OS X 10_16_0'], + ['linux', '112.0.0.0', 'X11; Linux x86_64'], + ['linux', '121.0.0.0', 'X11; Linux x86_64'], + ])( + 'should return false when given a chrome browser with working prerender in %s on version %s', + (_, version, os) => { + const bowser = Bowser.getParser( + `Mozilla/5.0 (${os}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Safari/537.36`, + ); + const result = BrowserRuntimeUtil.getIsBrowserPrerenderBroken(bowser); + expect(result).toStrictEqual(false); + }, + ); + it.each([ + ['windows', '113.0.0.0', 'Windows NT 10.0; Win64; x64'], + ['windows', '119.0.0.0', 'Windows NT 10.0; Win64; x64'], + ['macos', '113.0.0.0', 'Macintosh; Intel Mac OS X 10_16_0'], + ['macos', '119.0.0.0', 'Macintosh; Intel Mac OS X 10_16_0'], + ['linux', '113.0.0.0', 'X11; Linux x86_64'], + ['linux', '120.0.0.0', 'X11; Linux x86_64'], + ])( + 'should return true when given a chrome browser with broken prerender in %s on version %s', + (_, version, os) => { + const bowser = Bowser.getParser( + `Mozilla/5.0 (${os}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Safari/537.36`, + ); + const result = BrowserRuntimeUtil.getIsBrowserPrerenderBroken(bowser); + expect(result).toStrictEqual(true); + }, + ); + it.each([ + ['windows', '112.0.0.0', 'Windows NT 10.0; Win64; x64'], + ['windows', '120.0.0.0', 'Windows NT 10.0; Win64; x64'], + ['macos', '112.0.0.0', 'Macintosh; Intel Mac OS X 10_16_0'], + ['macos', '120.0.0.0', 'Macintosh; Intel Mac OS X 10_16_0'], + ['linux', '112.0.0.0', 'X11; Linux x86_64'], + ['linux', '121.0.0.0', 'X11; Linux x86_64'], + ])( + 'should return false when given an edge browser with working prerender in %s on version %s', + (_, version, os) => { + const bowser = Bowser.getParser( + `Mozilla/5.0 (${os}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/i${version} Safari/537.36 Edg/${version}`, + ); + const result = BrowserRuntimeUtil.getIsBrowserPrerenderBroken(bowser); + expect(result).toStrictEqual(false); + }, + ); + it.each([ + ['windows', '113.0.0.0', 'Windows NT 10.0; Win64; x64'], + ['windows', '119.0.0.0', 'Windows NT 10.0; Win64; x64'], + ['macos', '113.0.0.0', 'Macintosh; Intel Mac OS X 10_16_0'], + ['macos', '119.0.0.0', 'Macintosh; Intel Mac OS X 10_16_0'], + ['linux', '113.0.0.0', 'X11; Linux x86_64'], + ['linux', '120.0.0.0', 'X11; Linux x86_64'], + ])( + 'should return true when given an edge browser with broken prerender in %s on version %s', + (_, version, os) => { + const bowser = Bowser.getParser( + `Mozilla/5.0 (${os}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/i${version} Safari/537.36 Edg/${version}`, + ); + const result = BrowserRuntimeUtil.getIsBrowserPrerenderBroken(bowser); + expect(result).toStrictEqual(true); + }, + ); + it('should return false when given a firefox browser', () => { + const bowser = Bowser.getParser( + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/91.0', + ); + const result = BrowserRuntimeUtil.getIsBrowserPrerenderBroken(bowser); + expect(result).toStrictEqual(false); + }); + it('should return false when given an opera browser', () => { + const bowser = Bowser.getParser( + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.3578.98 Safari/537.36 OPR/76.0.3135.47', + ); + const result = BrowserRuntimeUtil.getIsBrowserPrerenderBroken(bowser); + expect(result).toStrictEqual(false); + }); + it('should return false when given an unknown browser', () => { + const bowser = Bowser.getParser( + 'Mozilla/5.0 (Nintendo Switch; WebApplet) AppleWebKit/609.4 (KHTML, like Gecko) NF/6.0.2.21.3 NintendoBrowser/5.1.0.22474', + ); + const result = BrowserRuntimeUtil.getIsBrowserPrerenderBroken(bowser); + expect(result).toStrictEqual(false); + }); + }); }); diff --git a/shared/modules/environment.test.ts b/shared/modules/environment.test.ts new file mode 100644 index 000000000000..a6d8128cc764 --- /dev/null +++ b/shared/modules/environment.test.ts @@ -0,0 +1,29 @@ +import { ENVIRONMENT } from '../../development/build/constants'; +import { isProduction } from './environment'; + +describe('isProduction', () => { + let originalMetaMaskEnvironment: string | undefined; + + beforeAll(() => { + originalMetaMaskEnvironment = process.env.METAMASK_ENVIRONMENT; + }); + + afterAll(() => { + process.env.METAMASK_ENVIRONMENT = originalMetaMaskEnvironment; + }); + + it('should return true when ENVIRONMENT is "production"', () => { + process.env.METAMASK_ENVIRONMENT = ENVIRONMENT.PRODUCTION; + expect(isProduction()).toBe(true); + }); + + it('should return false when ENVIRONMENT is "development"', () => { + process.env.METAMASK_ENVIRONMENT = ENVIRONMENT.DEVELOPMENT; + expect(isProduction()).toBe(false); + }); + + it('should return false when ENVIRONMENT is "testing"', () => { + process.env.METAMASK_ENVIRONMENT = ENVIRONMENT.TESTING; + expect(isProduction()).toBe(false); + }); +}); diff --git a/shared/modules/environment.ts b/shared/modules/environment.ts new file mode 100644 index 000000000000..96631bdc6f9b --- /dev/null +++ b/shared/modules/environment.ts @@ -0,0 +1,8 @@ +import { ENVIRONMENT } from '../../development/build/constants'; + +export const isProduction = (): boolean => { + return ( + process.env.METAMASK_ENVIRONMENT !== ENVIRONMENT.DEVELOPMENT && + process.env.METAMASK_ENVIRONMENT !== ENVIRONMENT.TESTING + ); +}; diff --git a/shared/modules/feature-flags.ts b/shared/modules/feature-flags.ts new file mode 100644 index 000000000000..4c05c1919922 --- /dev/null +++ b/shared/modules/feature-flags.ts @@ -0,0 +1,41 @@ +import { CHAIN_IDS } from '../constants/network'; + +enum NetworkName { + Ethereum = 'ethereum', + Polygon = 'polygon', + Bsc = 'bsc', + Avalanche = 'avalanche', + Optimism = 'optimism', + Arbitrum = 'arbitrum', + ZkSyncEra = 'zksync', + Linea = 'linea', +} + +/** + * @param chainId + * @returns string e.g. ethereum, bsc or polygon + */ +export const getNetworkNameByChainId = (chainId: string): string => { + switch (chainId) { + case CHAIN_IDS.MAINNET: + case CHAIN_IDS.GOERLI: + case CHAIN_IDS.SEPOLIA: + return NetworkName.Ethereum; + case CHAIN_IDS.BSC: + return NetworkName.Bsc; + case CHAIN_IDS.POLYGON: + return NetworkName.Polygon; + case CHAIN_IDS.AVALANCHE: + return NetworkName.Avalanche; + case CHAIN_IDS.OPTIMISM: + return NetworkName.Optimism; + case CHAIN_IDS.ARBITRUM: + return NetworkName.Arbitrum; + case CHAIN_IDS.ZKSYNC_ERA: + return NetworkName.ZkSyncEra; + case CHAIN_IDS.LINEA_MAINNET: + return NetworkName.Linea; + default: + return ''; + } +}; diff --git a/shared/modules/i18n.test.ts b/shared/modules/i18n.test.ts index 3353e4732e64..8452ef48238c 100644 --- a/shared/modules/i18n.test.ts +++ b/shared/modules/i18n.test.ts @@ -281,7 +281,7 @@ describe('I18N Module', () => { it('returns json from locale file', async () => { const result = await fetchLocale(localeCodeMock); expect(result).toStrictEqual({ - url: `./_locales/${localeCodeMock}/messages.json`, + url: `../_locales/${localeCodeMock}/messages.json`, }); }); @@ -307,6 +307,8 @@ describe('I18N Module', () => { RelativeTimeFormat: { __addLocaleData: addMock, }, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any; await loadRelativeTimeFormatLocaleData(`${localeCodeMock}_test`); @@ -324,6 +326,8 @@ describe('I18N Module', () => { RelativeTimeFormat: { __addLocaleData: addMock, }, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any; await loadRelativeTimeFormatLocaleData(`${localeCodeMock}_test`); diff --git a/shared/modules/i18n.ts b/shared/modules/i18n.ts index 84c433c58d8e..d19cfa4b3b11 100644 --- a/shared/modules/i18n.ts +++ b/shared/modules/i18n.ts @@ -20,6 +20,8 @@ export type I18NMessageDict = { [translationKey: string]: I18NMessage; }; +// TODO: Replace `any` with type +// eslint-disable-next-line @typescript-eslint/no-explicit-any export type I18NSubstitution = string | (() => any) | object; // A parameterized type (or generic type) of maps that use the same structure (translationKey) key @@ -89,7 +91,7 @@ export async function fetchLocale( ): Promise { try { const response = await fetchWithTimeout( - `./_locales/${localeCode}/messages.json`, + `../_locales/${localeCode}/messages.json`, ); return await response.json(); } catch (error) { @@ -104,10 +106,14 @@ export async function loadRelativeTimeFormatLocaleData( const languageTag = localeCode.split('_')[0]; if ( Intl.RelativeTimeFormat && + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any typeof (Intl.RelativeTimeFormat as any).__addLocaleData === 'function' && !relativeTimeFormatLocaleData.has(languageTag) ) { const localeData = await fetchRelativeTimeFormatData(languageTag); + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any (Intl.RelativeTimeFormat as any).__addLocaleData(localeData); relativeTimeFormatLocaleData.add(languageTag); } diff --git a/shared/modules/metametrics.test.ts b/shared/modules/metametrics.test.ts new file mode 100644 index 000000000000..1227be64db6f --- /dev/null +++ b/shared/modules/metametrics.test.ts @@ -0,0 +1,151 @@ +import { Provider } from '@metamask/network-controller'; +import { + TransactionStatus, + TransactionType, +} from '@metamask/transaction-controller'; +import { createTestProviderTools } from '../../test/stub/provider'; +import { TransactionMetricsRequest } from '../../app/scripts/lib/transaction/metrics'; +import { CHAIN_IDS } from '../constants/network'; +import { getSmartTransactionMetricsProperties } from './metametrics'; + +const txHash = + '0x0302b75dfb9fd9eb34056af031efcaee2a8cbd799ea054a85966165cd82a7356'; +const address = '0x1678a085c290ebd122dc42cba69373b5953b831d'; +const providerResultStub = { + eth_getCode: '0x123', +}; +const { provider } = createTestProviderTools({ + scaffold: providerResultStub, + chainId: CHAIN_IDS.MAINNET, +}); + +const createTransactionMetricsRequest = (customProps = {}) => { + return { + createEventFragment: jest.fn(), + finalizeEventFragment: jest.fn(), + getEventFragmentById: jest.fn(), + updateEventFragment: jest.fn(), + getAccountType: jest.fn(), + getDeviceModel: jest.fn(), + getEIP1559GasFeeEstimates: jest.fn(), + getSelectedAddress: jest.fn(), + getParticipateInMetrics: jest.fn(), + getTokenStandardAndDetails: jest.fn(), + getTransaction: jest.fn(), + provider: provider as Provider, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + snapAndHardwareMessenger: jest.fn() as any, + trackEvent: jest.fn(), + getIsSmartTransaction: jest.fn(), + getSmartTransactionByMinedTxHash: jest.fn(), + ...customProps, + } as TransactionMetricsRequest; +}; + +const createTransactionMeta = () => { + return { + id: '1', + status: TransactionStatus.unapproved, + txParams: { + from: address, + to: address, + gasPrice: '0x77359400', + gas: '0x7b0d', + nonce: '0x4b', + }, + type: TransactionType.simpleSend, + chainId: CHAIN_IDS.MAINNET, + time: 1624408066355, + defaultGasEstimates: { + gas: '0x7b0d', + gasPrice: '0x77359400', + }, + securityProviderResponse: { + flagAsDangerous: 0, + }, + hash: txHash, + error: null, + }; +}; + +describe('getSmartTransactionMetricsProperties', () => { + it('returns all smart transaction properties', () => { + const transactionMetricsRequest = createTransactionMetricsRequest({ + getIsSmartTransaction: () => true, + getSmartTransactionByMinedTxHash: () => { + return { + uuid: 'uuid', + status: 'success', + cancellable: false, + statusMetadata: { + cancellationFeeWei: 36777567771000, + cancellationReason: 'not_cancelled', + deadlineRatio: 0.6400288486480713, + minedHash: txHash, + duplicated: true, + timedOut: true, + proxied: true, + minedTx: 'success', + }, + }; + }, + }); + const transactionMeta = createTransactionMeta(); + + const result = getSmartTransactionMetricsProperties( + transactionMetricsRequest, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + transactionMeta as any, + ); + + expect(result).toStrictEqual({ + is_smart_transaction: true, + smart_transaction_duplicated: true, + smart_transaction_proxied: true, + smart_transaction_timed_out: true, + }); + }); + + it('returns "is_smart_transaction: false" if it is not a smart transaction', () => { + const transactionMetricsRequest = createTransactionMetricsRequest({ + getIsSmartTransaction: () => false, + }); + const transactionMeta = createTransactionMeta(); + + const result = getSmartTransactionMetricsProperties( + transactionMetricsRequest, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + transactionMeta as any, + ); + + expect(result).toStrictEqual({ + is_smart_transaction: false, + }); + }); + + it('returns "is_smart_transaction: true" only if it is a smart transaction, but does not have statusMetadata', () => { + const transactionMetricsRequest = createTransactionMetricsRequest({ + getIsSmartTransaction: () => true, + getSmartTransactionByMinedTxHash: () => { + return { + statusMetadata: null, + }; + }, + }); + const transactionMeta = createTransactionMeta(); + + const result = getSmartTransactionMetricsProperties( + transactionMetricsRequest, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + transactionMeta as any, + ); + + expect(result).toStrictEqual({ + is_smart_transaction: true, + }); + }); +}); diff --git a/shared/modules/metametrics.ts b/shared/modules/metametrics.ts new file mode 100644 index 000000000000..af049231bdf5 --- /dev/null +++ b/shared/modules/metametrics.ts @@ -0,0 +1,36 @@ +import { TransactionMeta } from '@metamask/transaction-controller'; +import { TransactionMetricsRequest } from '../../app/scripts/lib/transaction/metrics'; + +type SmartTransactionMetricsProperties = { + is_smart_transaction: boolean; + smart_transaction_duplicated?: boolean; + smart_transaction_timed_out?: boolean; + smart_transaction_proxied?: boolean; +}; + +export const getSmartTransactionMetricsProperties = ( + transactionMetricsRequest: TransactionMetricsRequest, + transactionMeta: TransactionMeta, +) => { + const isSmartTransaction = transactionMetricsRequest.getIsSmartTransaction(); + const properties = { + is_smart_transaction: isSmartTransaction, + } as SmartTransactionMetricsProperties; + if (!isSmartTransaction) { + return properties; + } + const smartTransaction = + transactionMetricsRequest.getSmartTransactionByMinedTxHash( + transactionMeta.hash, + ); + const smartTransactionStatusMetadata = smartTransaction?.statusMetadata; + if (!smartTransactionStatusMetadata) { + return properties; + } + properties.smart_transaction_duplicated = + smartTransactionStatusMetadata.duplicated; + properties.smart_transaction_timed_out = + smartTransactionStatusMetadata.timedOut; + properties.smart_transaction_proxied = smartTransactionStatusMetadata.proxied; + return properties; +}; diff --git a/shared/modules/mv3.utils.js b/shared/modules/mv3.utils.js index 3f9388b07a6b..4307ebbd8920 100644 --- a/shared/modules/mv3.utils.js +++ b/shared/modules/mv3.utils.js @@ -1,4 +1,24 @@ import browser from 'webextension-polyfill'; +/** + * A boolean indicating whether the manifest of the current extension + * is set to manifest version 3. + */ export const isManifestV3 = browser.runtime.getManifest().manifest_version === 3; + +/** + * A boolean indicating whether the browser supports the offscreen document api. + * This is only available in when the manifest is version 3, and only in chromium + * versions 109 and higher. As of June 7, 2024, it is not available in firefox. + */ +export const isOffscreenAvailable = Boolean(browser.offscreen); + +/** + * A boolean indicating whether the current extension's manifest is version 3 + * while the current browser does not support the offscreen document. This can + * happen to users on MetaMask versions 11.16.7 and higher, who are using a + * chromium browser with a version below 109. + */ +export const isMv3ButOffscreenDocIsMissing = + isManifestV3 && !isOffscreenAvailable; diff --git a/shared/modules/network.utils.ts b/shared/modules/network.utils.ts index e6f0fd86ee7a..8985bdcf7f5a 100644 --- a/shared/modules/network.utils.ts +++ b/shared/modules/network.utils.ts @@ -42,11 +42,19 @@ export function isTokenDetectionEnabledForNetwork(chainId: string | undefined) { case CHAIN_IDS.POLYGON: case CHAIN_IDS.AVALANCHE: case CHAIN_IDS.LINEA_GOERLI: + case CHAIN_IDS.LINEA_SEPOLIA: case CHAIN_IDS.LINEA_MAINNET: case CHAIN_IDS.ARBITRUM: case CHAIN_IDS.OPTIMISM: case CHAIN_IDS.BASE: case CHAIN_IDS.ZKSYNC_ERA: + case CHAIN_IDS.CRONOS: + case CHAIN_IDS.CELO: + case CHAIN_IDS.GNOSIS: + case CHAIN_IDS.FANTOM: + case CHAIN_IDS.POLYGON_ZKEVM: + case CHAIN_IDS.MOONBEAM: + case CHAIN_IDS.MOONRIVER: return true; default: return false; @@ -64,10 +72,6 @@ function isSafeInteger(value: unknown): value is number { return Number.isSafeInteger(value); } -export function shouldShowLineaMainnet(): boolean { - return new Date().getTime() > Date.UTC(2023, 6, 11, 18); -} - /** * TODO: Delete when ready to remove `networkVersion` from provider object * Convert the given value into a valid network ID. The ID is accepted diff --git a/shared/modules/selectors/feature-flags.ts b/shared/modules/selectors/feature-flags.ts new file mode 100644 index 000000000000..930f478aa962 --- /dev/null +++ b/shared/modules/selectors/feature-flags.ts @@ -0,0 +1,35 @@ +import { getCurrentChainId } from '../../../ui/selectors/selectors'; // TODO: Migrate shared selectors to this file. +import { getNetworkNameByChainId } from '../feature-flags'; + +type FeatureFlagsMetaMaskState = { + metamask: { + swapsState: { + swapsFeatureFlags: { + [key: string]: { + extensionActive: boolean; + mobileActive: boolean; + smartTransactions: { + expectedDeadline?: number; + maxDeadline?: number; + returnTxHashAsap?: boolean; + }; + }; + }; + }; + }; +}; + +export function getFeatureFlagsByChainId(state: FeatureFlagsMetaMaskState) { + const chainId = getCurrentChainId(state); + const networkName = getNetworkNameByChainId(chainId); + const featureFlags = state.metamask.swapsState?.swapsFeatureFlags; + if (!featureFlags?.[networkName]) { + return null; + } + return { + smartTransactions: { + ...featureFlags.smartTransactions, + ...featureFlags[networkName].smartTransactions, + }, + }; +} diff --git a/shared/modules/selectors/index.test.ts b/shared/modules/selectors/index.test.ts new file mode 100644 index 000000000000..6f1298952d76 --- /dev/null +++ b/shared/modules/selectors/index.test.ts @@ -0,0 +1,253 @@ +import { createSwapsMockStore } from '../../../test/jest'; +import { CHAIN_IDS, CURRENCY_SYMBOLS } from '../../constants/network'; +import { + getSmartTransactionsOptInStatus, + getCurrentChainSupportsSmartTransactions, + getSmartTransactionsEnabled, + getIsSmartTransaction, +} from '.'; + +describe('Selectors', () => { + const createMockState = () => { + return { + metamask: { + preferences: { + smartTransactionsOptInStatus: true, + showTokenAutodetectModal: true, + }, + internalAccounts: { + selectedAccount: 'account1', + accounts: { + account1: { + metadata: { + keyring: { + type: 'Hardware', + }, + }, + }, + }, + }, + providerConfig: { + chainId: CHAIN_IDS.MAINNET, + }, + swapsState: { + swapsFeatureFlags: { + ethereum: { + extensionActive: true, + mobileActive: false, + smartTransactions: { + expectedDeadline: 45, + maxDeadline: 150, + returnTxHashAsap: false, + }, + }, + smartTransactions: { + extensionActive: true, + mobileActive: false, + }, + }, + }, + smartTransactionsState: { + liveness: true, + }, + networkConfigurations: { + 'network-configuration-id-1': { + chainId: CHAIN_IDS.MAINNET, + ticker: CURRENCY_SYMBOLS.ETH, + rpcUrl: 'https://mainnet.infura.io/v3/', + }, + }, + }, + }; + }; + + describe('getSmartTransactionsOptInStatus', () => { + it('should return the smart transactions opt-in status', () => { + const state = createMockState(); + const result = getSmartTransactionsOptInStatus(state); + expect(result).toBe(true); + }); + }); + + describe('getShowTokenAutodetectModal', () => { + it('should return show autodetection token modal status', () => { + const state = createMockState(); + const result = getSmartTransactionsOptInStatus(state); + expect(result).toBe(true); + }); + }); + + describe('getCurrentChainSupportsSmartTransactions', () => { + it('should return true if the chain ID is allowed for smart transactions', () => { + const state = createMockState(); + const result = getCurrentChainSupportsSmartTransactions(state); + expect(result).toBe(true); + }); + + it('should return false if the chain ID is not allowed for smart transactions', () => { + const state = createMockState(); + const newState = { + ...state, + metamask: { + ...state.metamask, + providerConfig: { + ...state.metamask.providerConfig, + chainId: CHAIN_IDS.POLYGON, + }, + }, + }; + const result = getCurrentChainSupportsSmartTransactions(newState); + expect(result).toBe(false); + }); + }); + + describe('getSmartTransactionsEnabled', () => { + it('returns true if feature flag is enabled, not a HW and is Ethereum network', () => { + const state = createSwapsMockStore(); + expect(getSmartTransactionsEnabled(state)).toBe(true); + }); + + it('returns false if feature flag is disabled, not a HW and is Ethereum network', () => { + const state = createSwapsMockStore(); + state.metamask.swapsState.swapsFeatureFlags.smartTransactions.extensionActive = + false; + expect(getSmartTransactionsEnabled(state)).toBe(false); + }); + + it('returns false if feature flag is enabled, not a HW, STX liveness is false and is Ethereum network', () => { + const state = createSwapsMockStore(); + state.metamask.smartTransactionsState.liveness = false; + expect(getSmartTransactionsEnabled(state)).toBe(false); + }); + + it('returns false if feature flag is enabled, is a HW and is Ethereum network', () => { + const state = createSwapsMockStore(); + const newState = { + ...state, + metamask: { + ...state.metamask, + internalAccounts: { + ...state.metamask.internalAccounts, + selectedAccount: 'account2', + accounts: { + account2: { + metadata: { + keyring: { + type: 'Trezor Hardware', + }, + }, + }, + }, + }, + }, + }; + expect(getSmartTransactionsEnabled(newState)).toBe(false); + }); + + it('returns false if feature flag is enabled, not a HW and is Polygon network', () => { + const state = createSwapsMockStore(); + const newState = { + ...state, + metamask: { + ...state.metamask, + providerConfig: { + ...state.metamask.providerConfig, + chainId: CHAIN_IDS.POLYGON, + }, + }, + }; + expect(getSmartTransactionsEnabled(newState)).toBe(false); + }); + + it('returns false if feature flag is enabled, not a HW and is BSC network', () => { + const state = createSwapsMockStore(); + const newState = { + ...state, + metamask: { + ...state.metamask, + providerConfig: { + ...state.metamask.providerConfig, + chainId: CHAIN_IDS.BSC, + }, + }, + }; + expect(getSmartTransactionsEnabled(newState)).toBe(false); + }); + + it('returns false if feature flag is enabled, not a HW and is Linea network', () => { + const state = createSwapsMockStore(); + const newState = { + ...state, + metamask: { + ...state.metamask, + providerConfig: { + ...state.metamask.providerConfig, + chainId: CHAIN_IDS.LINEA_MAINNET, + }, + }, + }; + expect(getSmartTransactionsEnabled(newState)).toBe(false); + }); + + it('returns false if a snap account is used', () => { + const state = createSwapsMockStore(); + state.metamask.internalAccounts.selectedAccount = + '36eb02e0-7925-47f0-859f-076608f09b69'; + expect(getSmartTransactionsEnabled(state)).toBe(false); + }); + }); + + describe('getIsSmartTransaction', () => { + it('should return true if smart transactions are opt-in and enabled', () => { + const state = createMockState(); + const result = getIsSmartTransaction(state); + expect(result).toBe(true); + }); + + it('should return false if smart transactions are not opt-in', () => { + const state = createMockState(); + const newState = { + ...state, + metamask: { + ...state.metamask, + preferences: { + ...state.metamask.preferences, + smartTransactionsOptInStatus: false, + }, + }, + }; + const result = getIsSmartTransaction(newState); + expect(result).toBe(false); + }); + + it('should return false if smart transactions are not enabled', () => { + const state = createMockState(); + const newState = { + ...state, + metamask: { + ...state.metamask, + swapsState: { + ...state.metamask.swapsState, + swapsFeatureFlags: { + ethereum: { + extensionActive: true, + mobileActive: false, + smartTransactions: { + expectedDeadline: 45, + maxDeadline: 150, + returnTxHashAsap: false, + }, + }, + smartTransactions: { + extensionActive: false, + mobileActive: false, + }, + }, + }, + }, + }; + const result = getIsSmartTransaction(newState); + expect(result).toBe(false); + }); + }); +}); diff --git a/shared/modules/selectors/index.ts b/shared/modules/selectors/index.ts new file mode 100644 index 000000000000..2274b562629b --- /dev/null +++ b/shared/modules/selectors/index.ts @@ -0,0 +1,4 @@ +export * from './smart-transactions'; +export * from './feature-flags'; +export * from './token-auto-detect'; +export * from './nft-auto-detect'; diff --git a/shared/modules/selectors/nft-auto-detect.ts b/shared/modules/selectors/nft-auto-detect.ts new file mode 100644 index 000000000000..889a0348f179 --- /dev/null +++ b/shared/modules/selectors/nft-auto-detect.ts @@ -0,0 +1,29 @@ +import { + getIsMainnet, + getUseNftDetection, +} from '../../../ui/selectors/selectors'; + +type NftAutoDetectionMetaMaskState = { + metamask: { + preferences: { + showNftAutodetectModal: boolean | null; + }; + }; +}; + +export const getShowNftAutodetectModal = ( + state: NftAutoDetectionMetaMaskState, +): boolean | null => { + return state.metamask.preferences?.showNftAutodetectModal; +}; + +export const getIsShowNftAutodetectModal = ( + state: NftAutoDetectionMetaMaskState, +) => { + return ( + !getUseNftDetection(state) && + getIsMainnet(state) && + (getShowNftAutodetectModal(state) === null || + getShowNftAutodetectModal(state) === undefined) + ); +}; diff --git a/shared/modules/selectors/smart-transactions.ts b/shared/modules/selectors/smart-transactions.ts new file mode 100644 index 000000000000..24994f1ec203 --- /dev/null +++ b/shared/modules/selectors/smart-transactions.ts @@ -0,0 +1,127 @@ +import type { Hex } from '@metamask/utils'; +import { + getAllowedSmartTransactionsChainIds, + SKIP_STX_RPC_URL_CHECK_CHAIN_IDS, +} from '../../constants/smartTransactions'; +import { + getCurrentChainId, + getCurrentNetwork, + accountSupportsSmartTx, +} from '../../../ui/selectors/selectors'; // TODO: Migrate shared selectors to this file. +import { isProduction } from '../environment'; + +type SmartTransactionsMetaMaskState = { + metamask: { + preferences: { + smartTransactionsOptInStatus?: boolean | null; + }; + internalAccounts: { + selectedAccount: string; + accounts: { + [key: string]: { + metadata: { + keyring: { + type: string; + }; + }; + }; + }; + }; + providerConfig: { + chainId: Hex; + }; + swapsState: { + swapsFeatureFlags: { + ethereum: { + extensionActive: boolean; + mobileActive: boolean; + smartTransactions: { + expectedDeadline?: number; + maxDeadline?: number; + returnTxHashAsap?: boolean; + }; + }; + smartTransactions: { + extensionActive: boolean; + mobileActive: boolean; + }; + }; + }; + smartTransactionsState: { + liveness: boolean; + }; + networkConfigurations: { + [key: string]: { + chainId: Hex; + rpcUrl: string; + }; + }; + }; +}; + +export const getSmartTransactionsOptInStatus = ( + state: SmartTransactionsMetaMaskState, +): boolean | null => { + return state.metamask.preferences?.smartTransactionsOptInStatus ?? null; +}; + +export const getCurrentChainSupportsSmartTransactions = ( + state: SmartTransactionsMetaMaskState, +): boolean => { + const chainId = getCurrentChainId(state); + return getAllowedSmartTransactionsChainIds().includes(chainId); +}; + +const getIsAllowedRpcUrlForSmartTransactions = ( + state: SmartTransactionsMetaMaskState, +) => { + const chainId = getCurrentChainId(state); + if (!isProduction() || SKIP_STX_RPC_URL_CHECK_CHAIN_IDS.includes(chainId)) { + // Allow any STX RPC URL in development and testing environments or for specific chain IDs. + return true; + } + const currentNetwork = getCurrentNetwork(state); + if (!currentNetwork?.rpcUrl) { + return false; + } + const rpcUrl = new URL(currentNetwork.rpcUrl); + // Only allow STX in prod if an Infura RPC URL is being used. + return rpcUrl?.hostname?.endsWith('.infura.io'); +}; + +export const getIsSmartTransactionsOptInModalAvailable = ( + state: SmartTransactionsMetaMaskState, +) => { + return ( + getCurrentChainSupportsSmartTransactions(state) && + getIsAllowedRpcUrlForSmartTransactions(state) && + getSmartTransactionsOptInStatus(state) === null + ); +}; + +export const getSmartTransactionsEnabled = ( + state: SmartTransactionsMetaMaskState, +): boolean => { + const supportedAccount = accountSupportsSmartTx(state); + // TODO: Create a new proxy service only for MM feature flags. + const smartTransactionsFeatureFlagEnabled = + state.metamask.swapsState?.swapsFeatureFlags?.smartTransactions + ?.extensionActive; + const smartTransactionsLiveness = + state.metamask.smartTransactionsState?.liveness; + return Boolean( + getCurrentChainSupportsSmartTransactions(state) && + getIsAllowedRpcUrlForSmartTransactions(state) && + supportedAccount && + smartTransactionsFeatureFlagEnabled && + smartTransactionsLiveness, + ); +}; + +export const getIsSmartTransaction = ( + state: SmartTransactionsMetaMaskState, +): boolean => { + const smartTransactionsOptInStatus = getSmartTransactionsOptInStatus(state); + const smartTransactionsEnabled = getSmartTransactionsEnabled(state); + return Boolean(smartTransactionsOptInStatus && smartTransactionsEnabled); +}; diff --git a/shared/modules/selectors/token-auto-detect.ts b/shared/modules/selectors/token-auto-detect.ts new file mode 100644 index 000000000000..a6680a47af8d --- /dev/null +++ b/shared/modules/selectors/token-auto-detect.ts @@ -0,0 +1,32 @@ +import { getUseTokenDetection } from '../../../ui/selectors/selectors'; + +type TokenAutoDetectionMetaMaskState = { + metamask: { + preferences: { + showTokenAutodetectModal: boolean | null; + }; + showTokenAutodetectModalOnUpgrade: boolean | null; + }; +}; + +export const getShowTokenAutodetectModal = ( + state: TokenAutoDetectionMetaMaskState, +): boolean | null => { + return state.metamask.preferences?.showTokenAutodetectModal; +}; + +export const getIsShowTokenAutodetectModal = ( + state: TokenAutoDetectionMetaMaskState, +) => { + // Upgrade case + if (state.metamask.showTokenAutodetectModalOnUpgrade === null) { + return ( + !getUseTokenDetection(state) && + state.metamask.showTokenAutodetectModalOnUpgrade === null + ); + } + + return ( + !getUseTokenDetection(state) && getShowTokenAutodetectModal(state) === null + ); +}; diff --git a/shared/modules/transaction.utils.test.js b/shared/modules/transaction.utils.test.js index 778abc198079..ad43a8aa227b 100644 --- a/shared/modules/transaction.utils.test.js +++ b/shared/modules/transaction.utils.test.js @@ -1,11 +1,13 @@ import EthQuery from '@metamask/ethjs-query'; import { TransactionType } from '@metamask/transaction-controller'; + import { createTestProviderTools } from '../../test/stub/provider'; import { determineTransactionType, isEIP1559Transaction, isLegacyTransaction, parseStandardTokenTransactionData, + parseTypedDataMessage, } from './transaction.utils'; describe('Transaction.utils', function () { @@ -387,5 +389,17 @@ describe('Transaction.utils', function () { getCodeResponse: '0x0a', }); }); + + describe('parseTypedDataMessage', () => { + it('parses data passed correctly', () => { + const result = parseTypedDataMessage('{"test": "dummy"}'); + expect(result.test).toBe('dummy'); + }); + it('throw error for invalid typedDataMessage', () => { + expect(() => { + parseTypedDataMessage(''); + }).toThrow(new Error('Unexpected end of JSON input')); + }); + }); }); }); diff --git a/shared/modules/transaction.utils.ts b/shared/modules/transaction.utils.ts index a2f2978ad11e..edf24d20be18 100644 --- a/shared/modules/transaction.utils.ts +++ b/shared/modules/transaction.utils.ts @@ -1,13 +1,18 @@ import { isHexString } from 'ethereumjs-util'; import { Interface } from '@ethersproject/abi'; -import { abiERC721, abiERC20, abiERC1155 } from '@metamask/metamask-eth-abis'; +import { + abiERC721, + abiERC20, + abiERC1155, + abiFiatTokenV2, +} from '@metamask/metamask-eth-abis'; import type EthQuery from '@metamask/eth-query'; import log from 'loglevel'; import { TransactionMeta, TransactionType, } from '@metamask/transaction-controller'; -import { TransactionParams } from '@metamask/transaction-controller/dist/types'; +import type { TransactionParams } from '@metamask/transaction-controller'; import { AssetType, TokenStandard } from '../constants/transaction'; import { readAddressAsContract } from './contract-utils'; @@ -18,6 +23,7 @@ const INFERRABLE_TRANSACTION_TYPES: TransactionType[] = [ TransactionType.tokenMethodSetApprovalForAll, TransactionType.tokenMethodTransfer, TransactionType.tokenMethodTransferFrom, + TransactionType.tokenMethodIncreaseAllowance, TransactionType.contractInteraction, TransactionType.simpleSend, ]; @@ -32,6 +38,7 @@ type InferTransactionTypeResult = { const erc20Interface = new Interface(abiERC20); const erc721Interface = new Interface(abiERC721); const erc1155Interface = new Interface(abiERC1155); +const USDCInterface = new Interface(abiFiatTokenV2); /** * Determines if the maxFeePerGas and maxPriorityFeePerGas fields are supplied @@ -116,6 +123,12 @@ export function parseStandardTokenTransactionData(data: string) { // ignore and return undefined } + try { + return USDCInterface.parseTransaction({ data }); + } catch { + // ignore and return undefined + } + return undefined; } @@ -169,6 +182,7 @@ export async function determineTransactionType( TransactionType.tokenMethodSetApprovalForAll, TransactionType.tokenMethodTransfer, TransactionType.tokenMethodTransferFrom, + TransactionType.tokenMethodIncreaseAllowance, TransactionType.tokenMethodSafeTransferFrom, ].find((methodName) => isEqualCaseInsensitive(methodName, name)); return { @@ -184,12 +198,12 @@ export async function determineTransactionType( return { type: TransactionType.simpleSend, getCodeResponse: contractCode }; } -type GetTokenStandardAndDetails = (to: string | undefined) => { +type GetTokenStandardAndDetails = (to: string | undefined) => Promise<{ decimals?: string; balance?: string; symbol?: string; standard?: TokenStandard; -}; +}>; /** * Given a transaction meta object, determine the asset type that the * transaction is dealing with, as well as the standard for the token if it @@ -227,6 +241,7 @@ export async function determineTransactionAssetType( TransactionType.tokenMethodSetApprovalForAll, TransactionType.tokenMethodTransfer, TransactionType.tokenMethodTransferFrom, + TransactionType.tokenMethodIncreaseAllowance, ].find((methodName) => methodName === inferrableType); if ( @@ -239,7 +254,7 @@ export async function determineTransactionAssetType( try { // We don't need a balance check, so the second parameter to // getTokenStandardAndDetails is omitted. - const details = getTokenStandardAndDetails(txMeta.txParams.to); + const details = await getTokenStandardAndDetails(txMeta.txParams.to); if (details.standard) { return { assetType: @@ -266,3 +281,6 @@ export async function determineTransactionAssetType( } return { assetType: AssetType.native, tokenStandard: TokenStandard.none }; } + +export const parseTypedDataMessage = (dataToParse: string) => + JSON.parse(dataToParse); diff --git a/shared/modules/updateTxData.js b/shared/modules/updateTxData.js index 99cd8dc3162d..980b546020f4 100644 --- a/shared/modules/updateTxData.js +++ b/shared/modules/updateTxData.js @@ -13,7 +13,11 @@ export default function updateTxData({ toAddress, name, }) { - if (txData.type === TransactionType.simpleSend) { + if ( + [TransactionType.simpleSend, TransactionType.swapAndSend].includes( + txData.type, + ) + ) { addToAddressBookIfNew(toAddress, toAccounts); } diff --git a/shared/notifications/index.ts b/shared/notifications/index.ts index 763f24b004ae..8a90a5c1ea5c 100644 --- a/shared/notifications/index.ts +++ b/shared/notifications/index.ts @@ -5,13 +5,6 @@ * into numbers in only one place. This should make merge conflicts easier. */ export const NOTIFICATION_DROP_LEDGER_FIREFOX = 25; -export const NOTIFICATION_OPEN_BETA_SNAPS = 26; -export const NOTIFICATION_BUY_SELL_BUTTON = 27; -export const NOTIFICATION_U2F_LEDGER_LIVE = 28; -export const NOTIFICATION_BLOCKAID_DEFAULT = 29; -export const NOTIFICATION_STAKING_PORTFOLIO = 30; -export const NOTIFICATION_PETNAMES = 31; -export const NOTIFICATION_PORTFOLIO_V2 = 32; type NotificationImage = { src: string; @@ -30,73 +23,11 @@ type UINotifications = { }; export const UI_NOTIFICATIONS: UINotifications = { - 8: { - id: 8, - date: '2021-11-01', - }, - 20: { - id: 20, - date: null, - }, - 24: { - id: 24, - date: null, - }, // This syntax is unusual, but very helpful here. It's equivalent to `UI_NOTIFICATIONS[NOTIFICATION_DROP_LEDGER_FIREFOX] =` [NOTIFICATION_DROP_LEDGER_FIREFOX]: { id: Number(NOTIFICATION_DROP_LEDGER_FIREFOX), date: null, }, - [NOTIFICATION_OPEN_BETA_SNAPS]: { - id: Number(NOTIFICATION_OPEN_BETA_SNAPS), - date: null, - image: { - src: 'images/introducing-snaps.svg', - width: '100%', - }, - }, - [NOTIFICATION_BUY_SELL_BUTTON]: { - id: Number(NOTIFICATION_BUY_SELL_BUTTON), - date: null, - image: { - src: 'images/sell_button_whatsnew.png', - width: '100%', - }, - }, - [NOTIFICATION_U2F_LEDGER_LIVE]: { - id: Number(NOTIFICATION_U2F_LEDGER_LIVE), - date: null, - }, - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - [NOTIFICATION_BLOCKAID_DEFAULT]: { - id: Number(NOTIFICATION_BLOCKAID_DEFAULT), - date: null, - }, - ///: END:ONLY_INCLUDE_IF - [NOTIFICATION_STAKING_PORTFOLIO]: { - id: Number(NOTIFICATION_STAKING_PORTFOLIO), - date: null, - image: { - src: 'images/staking-light-mode-preview.png', - width: '100%', - }, - }, - [NOTIFICATION_PETNAMES]: { - id: Number(NOTIFICATION_PETNAMES), - date: null, - image: { - src: 'images/petnames-whatsnew-banner.svg', - width: '100%', - }, - }, - [NOTIFICATION_PORTFOLIO_V2]: { - id: Number(NOTIFICATION_PORTFOLIO_V2), - date: null, - image: { - src: 'images/portfolio-v2-whatsnew-banner.png', - width: '100%', - }, - }, }; type TranslationFunction = (key: string) => string; @@ -136,42 +67,11 @@ const formatDate = ( export const getTranslatedUINotifications = ( t: TranslationFunction, locale: string, - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - theme: string, - ///: END:ONLY_INCLUDE_IF ): TranslatedUINotifications => { // Added return type here const formattedLocale = locale?.replace('_', '-'); return { - 8: { - ...UI_NOTIFICATIONS[8], - title: t('notifications8Title'), - description: [ - t('notifications8DescriptionOne'), - t('notifications8DescriptionTwo'), - ], - date: formatDate(UI_NOTIFICATIONS[8].date, formattedLocale), - actionText: t('notifications8ActionText'), - }, - 20: { - ...UI_NOTIFICATIONS[20], - title: t('notifications20Title'), - description: [t('notifications20Description')], - actionText: t('notifications20ActionText'), - date: UI_NOTIFICATIONS[20].date - ? formatDate(UI_NOTIFICATIONS[20].date, formattedLocale) - : '', - }, - 24: { - ...UI_NOTIFICATIONS[24], - title: t('notifications24Title'), - description: t('notifications24Description'), - actionText: t('notifications24ActionText'), - date: UI_NOTIFICATIONS[24].date - ? formatDate(UI_NOTIFICATIONS[24].date, formattedLocale) - : '', - }, // This syntax is unusual, but very helpful here. It's equivalent to `unnamedObject[NOTIFICATION_DROP_LEDGER_FIREFOX] =` [NOTIFICATION_DROP_LEDGER_FIREFOX]: { ...UI_NOTIFICATIONS[NOTIFICATION_DROP_LEDGER_FIREFOX], @@ -184,104 +84,5 @@ export const getTranslatedUINotifications = ( ) : '', }, - [NOTIFICATION_OPEN_BETA_SNAPS]: { - ...UI_NOTIFICATIONS[NOTIFICATION_OPEN_BETA_SNAPS], - title: t('notificationsOpenBetaSnapsTitle'), - description: [ - t('notificationsOpenBetaSnapsDescriptionOne'), - t('notificationsOpenBetaSnapsDescriptionTwo'), - t('notificationsOpenBetaSnapsDescriptionThree'), - ], - actionText: t('notificationsOpenBetaSnapsActionText'), - date: UI_NOTIFICATIONS[NOTIFICATION_OPEN_BETA_SNAPS].date - ? formatDate( - UI_NOTIFICATIONS[NOTIFICATION_OPEN_BETA_SNAPS].date, - formattedLocale, - ) - : '', - }, - [NOTIFICATION_BUY_SELL_BUTTON]: { - ...UI_NOTIFICATIONS[NOTIFICATION_BUY_SELL_BUTTON], - title: t('notificationsBuySellTitle'), - description: t('notificationsBuySellDescription'), - actionText: t('notificationsBuySellActionText'), - date: UI_NOTIFICATIONS[NOTIFICATION_BUY_SELL_BUTTON].date - ? formatDate( - UI_NOTIFICATIONS[NOTIFICATION_BUY_SELL_BUTTON].date, - formattedLocale, - ) - : '', - }, - [NOTIFICATION_U2F_LEDGER_LIVE]: { - ...UI_NOTIFICATIONS[NOTIFICATION_U2F_LEDGER_LIVE], - title: t('notificationsU2FLedgerLiveTitle'), - description: [t('notificationsU2FLedgerLiveDescription')], - date: UI_NOTIFICATIONS[NOTIFICATION_U2F_LEDGER_LIVE].date - ? formatDate( - UI_NOTIFICATIONS[NOTIFICATION_U2F_LEDGER_LIVE].date, - formattedLocale, - ) - : '', - }, - [NOTIFICATION_STAKING_PORTFOLIO]: { - ...UI_NOTIFICATIONS[NOTIFICATION_STAKING_PORTFOLIO], - title: t('notificationsStakingPortfolioTitle'), - description: [t('notificationsStakingPortfolioDescription')], - actionText: t('notificationsStakingPortfolioActionText'), - date: UI_NOTIFICATIONS[NOTIFICATION_STAKING_PORTFOLIO].date - ? formatDate( - UI_NOTIFICATIONS[NOTIFICATION_STAKING_PORTFOLIO].date, - formattedLocale, - ) - : '', - }, - ///: BEGIN:ONLY_INCLUDE_IF(blockaid) - [NOTIFICATION_BLOCKAID_DEFAULT]: { - ...UI_NOTIFICATIONS[NOTIFICATION_BLOCKAID_DEFAULT], - title: t('notificationsBlockaidDefaultTitle'), - description: [ - t('notificationsBlockaidDefaultDescriptionOne'), - t('notificationsBlockaidDefaultDescriptionTwo'), - ], - actionText: t('notificationsBlockaidDefaultDescriptionActionText'), - date: UI_NOTIFICATIONS[NOTIFICATION_BLOCKAID_DEFAULT].date - ? formatDate( - UI_NOTIFICATIONS[NOTIFICATION_BLOCKAID_DEFAULT].date, - formattedLocale, - ) - : '', - image: - theme === 'dark' - ? { - src: 'images/blockaid-whats-new-theme-dark.svg', - width: '100%', - } - : { - src: 'images/blockaid-whats-new.svg', - width: '100%', - }, - }, - ///: END:ONLY_INCLUDE_IF - [NOTIFICATION_PETNAMES]: { - ...UI_NOTIFICATIONS[NOTIFICATION_PETNAMES], - title: t('notificationsPetnamesTitle'), - description: [ - t('notificationsPetnamesDescriptionOne'), - t('notificationsPetnamesDescriptionTwo'), - ], - actionText: t('notificationsPetnamesActionText'), - date: '', - }, - [NOTIFICATION_PORTFOLIO_V2]: { - ...UI_NOTIFICATIONS[NOTIFICATION_PORTFOLIO_V2], - title: t('notificationsPortfolioV2Title'), - description: [ - t('notificationsPortfolioV2DescriptionOne'), - t('notificationsPortfolioV2DescriptionTwo'), - t('notificationsPortfolioV2DescriptionThree'), - ], - actionText: t('notificationsPortfolioV2ActionText'), - date: '', - }, }; }; diff --git a/sonar-project.properties b/sonar-project.properties index 4b696125ff11..de14094b965e 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -15,4 +15,4 @@ sonar.sources=app/ sonar.test.inclusions=**.test.** # Encoding of the source code. Default is default system encoding -sonar.sourceEncoding=UTF-8 \ No newline at end of file +sonar.sourceEncoding=UTF-8 diff --git a/test/data/confirmations/contract-interaction.ts b/test/data/confirmations/contract-interaction.ts new file mode 100644 index 000000000000..55bcb4b26ad0 --- /dev/null +++ b/test/data/confirmations/contract-interaction.ts @@ -0,0 +1,153 @@ +import { + TransactionStatus, + TransactionType, +} from '@metamask/transaction-controller'; +import { Confirmation } from '../../../ui/pages/confirmations/types/confirm'; + +export const PAYMASTER_AND_DATA = + '0x9d6ac51b972544251fcc0f2902e633e3f9bd3f2900000000000000000000000000000000000000000000000000000000666bfd410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003498a76eb88b702e5e52b00fbc16a36baf89ebe3e0dd23170949cffc0a623011383cced660ff67930308c22e5aa746a2d586629ddbd87046a146225bf80e9d6f1b'; + +export const CONTRACT_INTERACTION_SENDER_ADDRESS = + '0x2e0d7e8c45221fca00d74a3609a0f7097035d09b'; + +export const DEPOSIT_METHOD_DATA = '0xd0e30db0'; + +export const genUnapprovedContractInteractionConfirmation = ( + { address, txData } = { + address: CONTRACT_INTERACTION_SENDER_ADDRESS, + txData: DEPOSIT_METHOD_DATA, + }, +): Confirmation => ({ + actionId: String(400855682), + chainId: '0xaa36a7', + dappSuggestedGasFees: { + gas: '0xab77', + }, + defaultGasEstimates: { + estimateType: 'medium', + gas: '0xab77', + maxFeePerGas: '0xaa350353', + maxPriorityFeePerGas: '0x59682f00', + }, + gasFeeEstimatesLoaded: true, + history: [ + { + actionId: String(400855682), + chainId: '0xaa36a7', + dappSuggestedGasFees: { + gas: '0xab77', + }, + defaultGasEstimates: { + estimateType: 'medium', + gas: '0xab77', + maxFeePerGas: '0xaa350353', + maxPriorityFeePerGas: '0x59682f00', + }, + id: '1d7c08c0-fe54-11ee-9243-91b1e533746a', + origin: 'https://metamask.github.io', + securityAlertResponse: { + reason: 'loading', + result_type: 'validation_in_progress', + }, + sendFlowHistory: [], + status: TransactionStatus.unapproved, + time: 1713534772044, + txParams: { + data: txData, + from: address, + gas: '0xab77', + maxFeePerGas: '0xaa350353', + maxPriorityFeePerGas: '0x59682f00', + to: '0x88aa6343307ec9a652ccddda3646e62b2f1a5125', + value: '0x3782dace9d900000', + }, + type: TransactionType.contractInteraction, + userEditedGasLimit: false, + userFeeLevel: 'medium', + verifiedOnBlockchain: false, + }, + [ + { + note: 'TransactionController#updateSimulationData - Update simulation data', + op: 'add', + path: '/simulationData', + timestamp: 1713534772417, + value: { + nativeBalanceChange: { + difference: '0x3782dace9d900000', + isDecrease: true, + newBalance: '0xcc0ea4fb7ffa87d', + previousBalance: '0x4443c51e558fa87d', + }, + tokenBalanceChanges: [], + }, + }, + { + op: 'add', + path: '/gasFeeEstimatesLoaded', + value: true, + }, + ], + [ + { + note: 'TransactionController:updatesecurityAlertResponse - securityAlertResponse updated', + op: 'replace', + path: '/securityAlertResponse/result_type', + timestamp: 1713534773213, + value: 'Benign', + }, + { + op: 'replace', + path: '/securityAlertResponse/reason', + value: '', + }, + { + op: 'add', + path: '/securityAlertResponse/description', + value: '', + }, + { + op: 'add', + path: '/securityAlertResponse/features', + value: [], + }, + { + op: 'add', + path: '/securityAlertResponse/block', + value: 5732063, + }, + ], + ], + id: '1d7c08c0-fe54-11ee-9243-91b1e533746a', + origin: 'https://metamask.github.io', + securityAlertResponse: { + features: [], + reason: '', + result_type: 'Benign', + }, + sendFlowHistory: [], + simulationData: { + nativeBalanceChange: { + difference: '0x3782dace9d900000', + isDecrease: true, + newBalance: '0xcc0ea4fb7ffa87d', + previousBalance: '0x4443c51e558fa87d', + }, + tokenBalanceChanges: [], + }, + status: TransactionStatus.unapproved, + time: 1713534772044, + txParams: { + data: txData, + from: address, + gas: '0xab77', + maxFeePerGas: '0xaa350353', + maxPriorityFeePerGas: '0x59682f00', + to: '0x88aa6343307ec9a652ccddda3646e62b2f1a5125', + value: '0x3782dace9d900000', + }, + type: TransactionType.contractInteraction, + userEditedGasLimit: false, + userFeeLevel: 'medium', + verifiedOnBlockchain: false, +}); diff --git a/test/data/confirmations/personal_sign.ts b/test/data/confirmations/personal_sign.ts index fe632b37ccf2..bac5b3f9838a 100644 --- a/test/data/confirmations/personal_sign.ts +++ b/test/data/confirmations/personal_sign.ts @@ -1,13 +1,88 @@ -export const unapprovedPersonalMsg = { +import { SignatureRequestType } from '../../../ui/pages/confirmations/types/confirm'; + +export const PERSONAL_SIGN_SENDER_ADDRESS = + '0x8eeee1781fd885ff5ddef7789486676961873d12'; + +export const unapprovedPersonalSignMsg = { id: '0050d5b0-c023-11ee-a0cb-3390a510a0ab', status: 'unapproved', time: new Date().getTime(), type: 'personal_sign', securityProviderResponse: null, msgParams: { - from: '0x8eeee1781fd885ff5ddef7789486676961873d12', + from: PERSONAL_SIGN_SENDER_ADDRESS, data: '0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765', origin: 'https://metamask.github.io', siwe: { isSIWEMessage: false, parsedMessage: null }, }, -}; +} as SignatureRequestType; + +export const signatureRequestSIWE = { + id: '210ca3b0-1ccb-11ef-b096-89c4d726ebb5', + securityAlertResponse: { + reason: 'loading', + result_type: 'validation_in_progress', + securityAlertId: 'b826df20-2eda-41bf-becf-6a100141a8be', + }, + status: 'unapproved', + time: 1716884423019, + type: 'personal_sign', + msgParams: { + from: '0x935e73edb9ff52e23bac7f7e049a1ecd06d05477', + data: '0x6d6574616d61736b2e6769746875622e696f2077616e747320796f7520746f207369676e20696e207769746820796f757220457468657265756d206163636f756e743a0a3078393335653733656462396666353265323362616337663765303433613165636430366430353437370a0a492061636365707420746865204d6574614d61736b205465726d73206f6620536572766963653a2068747470733a2f2f636f6d6d756e6974792e6d6574616d61736b2e696f2f746f730a0a5552493a2068747470733a2f2f6d6574616d61736b2e6769746875622e696f0a56657273696f6e3a20310a436861696e2049443a20310a4e6f6e63653a2033323839313735370a4973737565642041743a20323032312d30392d33305431363a32353a32342e3030305a', + signatureMethod: 'personal_sign', + origin: 'https://metamask.github.io', + siwe: { + isSIWEMessage: true, + parsedMessage: { + domain: 'metamask.github.io', + address: '0x935e73edb9ff52e23bac7f7e049a1ecd06d05477', + statement: + 'I accept the MetaMask Terms of Service: https://community.metamask.io/tos', + uri: 'https://metamask.github.io', + version: '1', + chainId: 1, + nonce: '32891757', + issuedAt: '2021-09-30T16:25:24.000Z', + }, + }, + }, +} as SignatureRequestType; + +export const SignatureRequestSIWEWithResources = { + id: '210ca3b0-1ccb-11ef-b096-89c4d726ebb5', + securityAlertResponse: { + reason: 'loading', + result_type: 'validation_in_progress', + securityAlertId: 'b826df20-2eda-41bf-becf-6a100141a8be', + }, + status: 'unapproved', + time: 1716884423019, + type: 'personal_sign', + msgParams: { + from: '0x935e73edb9ff52e23bac7f7e049a1ecd06d05477', + data: '0x6d6574616d61736b2e6769746875622e696f2077616e747320796f7520746f207369676e20696e207769746820796f757220457468657265756d206163636f756e743a0a3078393335653733656462396666353265323362616337663765303433613165636430366430353437370a0a492061636365707420746865204d6574614d61736b205465726d73206f6620536572766963653a2068747470733a2f2f636f6d6d756e6974792e6d6574616d61736b2e696f2f746f730a0a5552493a2068747470733a2f2f6d6574616d61736b2e6769746875622e696f0a56657273696f6e3a20310a436861696e2049443a20310a4e6f6e63653a2033323839313735370a4973737565642041743a20323032312d30392d33305431363a32353a32342e3030305a', + signatureMethod: 'personal_sign', + origin: 'https://metamask.github.io', + siwe: { + isSIWEMessage: true, + parsedMessage: { + domain: 'metamask.github.io', + address: '0x935e73edb9ff52e23bac7f7e043a1ecd06d05477', + statement: + 'I accept the MetaMask Terms of Service: https://community.metamask.io/tos', + uri: 'https://metamask.github.io', + version: '1', + chainId: 1, + nonce: '32891757', + issuedAt: '2021-09-30T16:25:24.000Z', + notBefore: '2022-03-17T12:45:13.610Z', + requestId: 'some_id', + resources: [ + 'ipfs://Qme7ss3ARVgxv6rXqVPiikMJ8u2NLgmgszg13pYrDKEoiu', + 'https://example.com/my-web2-claim.json', + ], + }, + }, + }, +} as SignatureRequestType; diff --git a/test/data/confirmations/typed_sign.ts b/test/data/confirmations/typed_sign.ts index a648559d6a9b..61e6fa68713d 100644 --- a/test/data/confirmations/typed_sign.ts +++ b/test/data/confirmations/typed_sign.ts @@ -1,4 +1,81 @@ -const rawMessage = { +import { SignatureRequestType } from '../../../ui/pages/confirmations/types/confirm'; + +export const unapprovedTypedSignMsgV1 = { + id: '82ab2400-e2c6-11ee-9627-73cc88f00492', + securityAlertResponse: { + reason: 'loading', + result_type: 'validation_in_progress', + securityAlertId: '3a938cfc-301d-4af0-96c4-b51fe1a5d6ad', + }, + status: 'unapproved', + time: 1710505271872, + type: 'eth_signTypedData', + securityProviderResponse: null, + msgParams: { + from: '0x935e73edb9ff52e23bac7f7e043a1ecd06d05477', + data: [ + { type: 'string', name: 'Message', value: 'Hi, Alice!' }, + { type: 'uint32', name: 'A number', value: '1337' }, + ], + signatureMethod: 'eth_signTypedData', + version: 'V1', + origin: 'https://metamask.github.io', + }, +} as SignatureRequestType; + +const rawMessageV3 = { + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallet', type: 'address' }, + ], + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person' }, + { name: 'contents', type: 'string' }, + ], + }, + primaryType: 'Mail', + domain: { + name: 'Ether Mail', + version: '1', + chainId: 1, + verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + }, + message: { + from: { name: 'Cow', wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826' }, + to: { name: 'Bob', wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB' }, + contents: 'Hello, Bob!', + }, +}; + +export const unapprovedTypedSignMsgV3 = { + id: '17e41af0-e073-11ee-9eec-5fd284826685', + securityAlertResponse: { + reason: 'loading', + result_type: 'validation_in_progress', + securityAlertId: 'efefe1db-6c6e-4a2c-aa0d-6183ad3ec810', + }, + status: 'unapproved', + time: 1710249542175, + type: 'eth_signTypedData', + securityProviderResponse: null, + msgParams: { + data: JSON.stringify(rawMessageV3), + from: '0x935e73edb9ff52e23bac7f7e043a1ecd06d05477', + version: 'V3', + signatureMethod: 'eth_signTypedData_v3', + origin: 'https://metamask.github.io', + }, +} as SignatureRequestType; + +export const rawMessageV4 = { domain: { chainId: 97, name: 'Ether Mail', @@ -46,7 +123,7 @@ const rawMessage = { }, }; -export const unapprovedTypedSignMsg = { +export const unapprovedTypedSignMsgV4 = { id: '0050d5b0-c023-11ee-a0cb-3390a510a0ab', status: 'unapproved', time: new Date().getTime(), @@ -54,7 +131,26 @@ export const unapprovedTypedSignMsg = { securityProviderResponse: null, msgParams: { from: '0x8eeee1781fd885ff5ddef7789486676961873d12', - data: JSON.stringify(rawMessage), + data: JSON.stringify(rawMessageV4), origin: 'https://metamask.github.io', }, -}; +} as SignatureRequestType; + +export const permitSignatureMsg = { + id: '0b1787a0-1c44-11ef-b70d-e7064bd7b659', + securityAlertResponse: { + reason: 'loading', + result_type: 'validation_in_progress', + securityAlertId: 'ab21395f-2190-472f-8cfa-3d224e7529d8', + }, + status: 'unapproved', + time: 1716826404122, + type: 'eth_signTypedData', + msgParams: { + data: '{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Permit":[{"name":"owner","type":"address"},{"name":"spender","type":"address"},{"name":"value","type":"uint256"},{"name":"nonce","type":"uint256"},{"name":"deadline","type":"uint256"}]},"primaryType":"Permit","domain":{"name":"MyToken","version":"1","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","chainId":1},"message":{"owner":"0x935e73edb9ff52e23bac7f7e043a1ecd06d05477","spender":"0x5B38Da6a701c568545dCfcB03FcB875f56beddC4","value":3000,"nonce":0,"deadline":50000000000}}', + from: '0x935e73edb9ff52e23bac7f7e043a1ecd06d05477', + version: 'V4', + signatureMethod: 'eth_signTypedData_v4', + origin: 'https://metamask.github.io', + }, +} as SignatureRequestType; diff --git a/test/data/mock-accounts.ts b/test/data/mock-accounts.ts new file mode 100644 index 000000000000..ff6009ebd555 --- /dev/null +++ b/test/data/mock-accounts.ts @@ -0,0 +1,59 @@ +import { KeyringTypes } from '@metamask/keyring-controller'; +import { + InternalAccount, + EthAccountType, + BtcMethod, + BtcAccountType, +} from '@metamask/keyring-api'; +import { + ETH_EOA_METHODS, + ETH_4337_METHODS, +} from '../../shared/constants/eth-methods'; + +export const MOCK_ACCOUNT_EOA: InternalAccount = { + id: '4974fc00-c0fb-4a18-8535-8407ec6d1952', + address: '0x123', + options: {}, + methods: ETH_EOA_METHODS, + type: EthAccountType.Eoa, + metadata: { + name: 'Account 1', + keyring: { type: KeyringTypes.hd }, + importTime: 1691565967600, + lastSelected: 1691565967656, + }, +}; + +export const MOCK_ACCOUNT_ERC4337: InternalAccount = { + id: '4d5921f2-2022-44ce-a84f-9f6a0f142a5c', + address: '0x123', + options: {}, + methods: ETH_EOA_METHODS.concat(ETH_4337_METHODS), + type: EthAccountType.Erc4337, + metadata: { + name: 'Account 2', + keyring: { type: KeyringTypes.snap }, + importTime: 1691565967600, + lastSelected: 1691565967656, + }, +}; + +export const MOCK_ACCOUNT_BIP122_P2WPKH: InternalAccount = { + id: 'ae247df6-3911-47f7-9e36-28e6a7d96078', + address: 'bc1qaabb', + options: {}, + methods: [BtcMethod.SendMany], + type: BtcAccountType.P2wpkh, + metadata: { + name: 'Bitcoin Account', + keyring: { type: KeyringTypes.snap }, + importTime: 1691565967600, + lastSelected: 1955565967656, + }, +}; + +export const MOCK_ACCOUNTS = { + [MOCK_ACCOUNT_EOA.id]: MOCK_ACCOUNT_EOA, + [MOCK_ACCOUNT_ERC4337.id]: MOCK_ACCOUNT_ERC4337, + [MOCK_ACCOUNT_BIP122_P2WPKH.id]: MOCK_ACCOUNT_BIP122_P2WPKH, +}; diff --git a/test/e2e/tests/metrics/mock-data.js b/test/data/mock-data.js similarity index 99% rename from test/e2e/tests/metrics/mock-data.js rename to test/data/mock-data.js index fe68d8e7d29c..b39b2305cfdd 100644 --- a/test/e2e/tests/metrics/mock-data.js +++ b/test/data/mock-data.js @@ -1,3 +1,4 @@ +/* eslint-disable @metamask/design-tokens/color-no-hex*/ const TOKENS_API_MOCK_RESULT = [ { name: 'Ethereum', @@ -5,7 +6,7 @@ const TOKENS_API_MOCK_RESULT = [ decimals: 18, type: 'native', iconUrl: - 'https://token.metaswap.codefi.network/assets/nativeCurrencyLogos/ethereum.svg', + 'https://token.api.cx.metamask.io/assets/nativeCurrencyLogos/ethereum.svg', coingeckoId: 'ethereum', address: '0x0000000000000000000000000000000000000000', occurrences: 100, diff --git a/test/data/mock-send-state.json b/test/data/mock-send-state.json index badc99d28341..c8604c96c055 100644 --- a/test/data/mock-send-state.json +++ b/test/data/mock-send-state.json @@ -58,6 +58,9 @@ "state": "CLOSED", "networkName": "" }, + "localeMessages": { + "currentLocale": "en" + }, "metamask": { "ipfsGateway": "", "dismissSeedBackUpReminder": false, @@ -346,9 +349,31 @@ "decimals": "18" } ], - "contractExchangeRates": { - "0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d": 0.00039345803819379796, - "0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5": 0.00008189274407698049 + "marketData": { + "0x1": { + "0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d": { + "price": 0.00039345803819379796, + "contractPercentChange1d": 0.004, + "priceChange1d": 0.00004 + }, + "0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5": { + "price": 0.00008189274407698049, + "contractPercentChange1d": 0.01, + "priceChange1d": 0.001 + } + }, + "0x5": { + "0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d": { + "price": 0.00039345803819379796, + "contractPercentChange1d": 0.004, + "priceChange1d": 0.00004 + }, + "0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5": { + "price": 0.00008189274407698049, + "contractPercentChange1d": 0.01, + "priceChange1d": 0.001 + } + } }, "ticker": "ETH", "currentCurrency": "usd", @@ -1214,23 +1239,19 @@ ], "origin": "tmashuang.github.io" } - ] + ], + "swapsState": {} }, "send": { "amountMode": "INPUT", "currentTransactionUUID": "1-tx", + "disabledSwapAndSendNetworks": [], "draftTransactions": { "1-tx": { "amount": { "error": null, "value": "0xde0b6b3a7640000" }, - "asset": { - "balance": "0x1158e460913d00000", - "details": null, - "error": null, - "type": "NATIVE" - }, "fromAccount": null, "gas": { "error": null, @@ -1243,6 +1264,14 @@ }, "history": [], "id": null, + "isSwapQuoteLoading": false, + "quotes": null, + "receiveAsset": { + "balance": "0x0", + "details": null, + "error": null, + "type": "NATIVE" + }, "recipient": { "address": "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b", "error": null, @@ -1251,7 +1280,16 @@ "type": "", "recipientWarningAcknowledged": false }, + "sendAsset": { + "balance": "0x1158e460913d00000", + "details": null, + "error": null, + "type": "NATIVE" + }, "status": "VALID", + "swapQuotesError": null, + "swapQuotesLatestRequestTimestamp": null, + "timeToFetchQuotes": null, "transactionType": "0x2", "userInputHexData": null } @@ -1262,7 +1300,7 @@ "gasIsSetInModal": false, "gasPriceEstimate": "0x0", "gasLimitMinimum": "0x5208", - "gasTotalForLayer1": "0x0", + "gasTotalForLayer1": null, "recipientMode": "CONTACT_LIST", "recipientInput": "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b", "selectedAccount": { @@ -1271,6 +1309,33 @@ }, "stage": "DRAFT" }, + "swaps": { + "aggregatorMetadata": null, + "approveTxId": null, + "tradeTxId": null, + "balanceError": false, + "fetchingQuotes": false, + "fromToken": null, + "fromTokenInputValue": "", + "fromTokenError": null, + "isFeatureFlagLoaded": false, + "maxSlippage": "Slippage.default", + "quotesFetchStartTime": null, + "reviewSwapClickedTimestamp": null, + "topAssets": {}, + "toToken": null, + "customGas": { + "price": null, + "limit": null, + "loading": "GAS_PRICES_LOADING_STATES.INITIAL", + "priceEstimates": {}, + "fallBackPrice": null + }, + "currentSmartTransactionsError": "", + "swapsSTXLoading": false, + "transactionSettingsOpened": false, + "latestAddedTokenTo": "" + }, "unconnectedAccount": { "state": "CLOSED" } diff --git a/test/data/mock-state.json b/test/data/mock-state.json index 6e8b637c3778..920533023a58 100644 --- a/test/data/mock-state.json +++ b/test/data/mock-state.json @@ -30,6 +30,10 @@ "customTokenAmount": "10" }, "confirm": {}, + "confirmAlerts": { + "alerts": [], + "confirmed": [] + }, "confirmTransaction": { "txData": { "txParams": { @@ -148,6 +152,216 @@ "version": "5.1.2" } ] + }, + "npm:@metamask/test-snap-bip32": { + "id": "npm:@metamask/test-snap-bip32", + "origin": "npm:@metamask/test-snap-bip32", + "version": "5.1.2", + "iconUrl": null, + "initialPermissions": { + "endowment:ethereum-provider": {} + }, + "manifest": { + "description": "An example Snap that signs messages using BLS.", + "proposedName": "BIP-32 Test Snap", + "repository": { + "type": "git", + "url": "https://github.com/MetaMask/test-snaps.git" + }, + "source": { + "location": { + "npm": { + "filePath": "dist/bundle.js", + "packageName": "@metamask/test-snap-bip32", + "registry": "https://registry.npmjs.org" + } + }, + "shasum": "L1k+dT9Q+y3KfIqzaH09MpDZVPS9ZowEh9w01ZMTWMU=" + }, + "version": "5.1.2" + }, + "versionHistory": [ + { + "date": 1680686075921, + "origin": "https://metamask.github.io", + "version": "5.1.2" + } + ] + }, + "npm:@metamask/test-snap-getEntropy": { + "id": "npm:@metamask/test-snap-getEntropy", + "origin": "npm:@metamask/test-snap-getEntropy", + "version": "5.1.2", + "iconUrl": null, + "initialPermissions": { + "endowment:ethereum-provider": {} + }, + "manifest": { + "description": "An example Snap that can derive snap specific entropy.", + "proposedName": "Get Entropy Test Snap", + "repository": { + "type": "git", + "url": "https://github.com/MetaMask/test-snaps.git" + }, + "source": { + "location": { + "npm": { + "filePath": "dist/bundle.js", + "packageName": "@metamask/test-snap-getEntropy", + "registry": "https://registry.npmjs.org" + } + }, + "shasum": "L1k+dT9Q+y3KfIqzaH09MpDZVPS9ZowEh9w01ZMTWMU=" + }, + "version": "5.1.2" + }, + "versionHistory": [ + { + "date": 1680686075921, + "origin": "https://metamask.github.io", + "version": "5.1.2" + } + ] + }, + "npm:@metamask/test-snap-networkAccess": { + "id": "npm:@metamask/test-snap-networkAccess", + "origin": "npm:@metamask/test-snap-networkAccess", + "version": "5.1.2", + "iconUrl": null, + "initialPermissions": { + "endowment:ethereum-provider": {} + }, + "manifest": { + "description": "An example Snap that has network access.", + "proposedName": "Network Access Test Snap", + "repository": { + "type": "git", + "url": "https://github.com/MetaMask/test-snaps.git" + }, + "source": { + "location": { + "npm": { + "filePath": "dist/bundle.js", + "packageName": "@metamask/test-snap-networkAccess", + "registry": "https://registry.npmjs.org" + } + }, + "shasum": "L1k+dT9Q+y3KfIqzaH09MpDZVPS9ZowEh9w01ZMTWMU=" + }, + "version": "5.1.2" + }, + "versionHistory": [ + { + "date": 1680686075921, + "origin": "https://metamask.github.io", + "version": "5.1.2" + } + ] + }, + "npm:@metamask/test-snap-wasm": { + "id": "npm:@metamask/test-snap-wasm", + "origin": "npm:@metamask/test-snap-wasm", + "version": "5.1.2", + "iconUrl": null, + "initialPermissions": { + "endowment:ethereum-provider": {} + }, + "manifest": { + "description": "An example Snap that has WASM access.", + "proposedName": "WASM Test Snap", + "repository": { + "type": "git", + "url": "https://github.com/MetaMask/test-snaps.git" + }, + "source": { + "location": { + "npm": { + "filePath": "dist/bundle.js", + "packageName": "@metamask/test-snap-wasm", + "registry": "https://registry.npmjs.org" + } + }, + "shasum": "L1k+dT9Q+y3KfIqzaH09MpDZVPS9ZowEh9w01ZMTWMU=" + }, + "version": "5.1.2" + }, + "versionHistory": [ + { + "date": 1680686075921, + "origin": "https://metamask.github.io", + "version": "5.1.2" + } + ] + }, + "npm:@metamask/test-snap-notify": { + "id": "npm:@metamask/test-snap-notify", + "origin": "npm:@metamask/test-snap-notify", + "version": "5.1.2", + "iconUrl": null, + "initialPermissions": { + "endowment:ethereum-provider": {} + }, + "manifest": { + "description": "An example Snap that can send notifications.", + "proposedName": "Notification Test Snap", + "repository": { + "type": "git", + "url": "https://github.com/MetaMask/test-snaps.git" + }, + "source": { + "location": { + "npm": { + "filePath": "dist/bundle.js", + "packageName": "@metamask/test-snap-notify", + "registry": "https://registry.npmjs.org" + } + }, + "shasum": "L1k+dT9Q+y3KfIqzaH09MpDZVPS9ZowEh9w01ZMTWMU=" + }, + "version": "5.1.2" + }, + "versionHistory": [ + { + "date": 1680686075921, + "origin": "https://metamask.github.io", + "version": "5.1.2" + } + ] + }, + "npm:@metamask/test-snap-dialog": { + "id": "npm:@metamask/test-snap-dialog", + "origin": "npm:@metamask/test-snap-dialog", + "version": "5.1.2", + "iconUrl": null, + "initialPermissions": { + "endowment:ethereum-provider": {} + }, + "manifest": { + "description": "An example Snap that can send dialog prompts.", + "proposedName": "Dialog Test Snap", + "repository": { + "type": "git", + "url": "https://github.com/MetaMask/test-snaps.git" + }, + "source": { + "location": { + "npm": { + "filePath": "dist/bundle.js", + "packageName": "@metamask/test-snap-dialog", + "registry": "https://registry.npmjs.org" + } + }, + "shasum": "L1k+dT9Q+y3KfIqzaH09MpDZVPS9ZowEh9w01ZMTWMU=" + }, + "version": "5.1.2" + }, + "versionHistory": [ + { + "date": 1680686075921, + "origin": "https://metamask.github.io", + "version": "5.1.2" + } + ] } }, "preferences": { @@ -155,6 +369,7 @@ "showExtensionInFullSizeView": false, "showFiatInTestnets": false, "showTestNetworks": true, + "smartTransactionsOptInStatus": false, "useNativeCurrencyAsPrimaryCurrency": true, "petnamesEnabled": false }, @@ -379,6 +594,13 @@ "name": "@metamask/test-snap-bip44", "version": "1.2.3", "subjectType": "snap" + }, + "https://snaps.metamask.io": { + "extensionId": null, + "iconUrl": "https://snaps.metamask.io/favicon-32x32.png?v=96e4834dade94988977ec34e50a62b84", + "name": "MetaMask Snaps Directory", + "origin": "https://snaps.metamask.io", + "subjectType": "website" } }, "snapRegistryList": { @@ -472,9 +694,73 @@ "decimals": "18" } ], - "contractExchangeRates": { - "0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d": 0.00039345803819379796, - "0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5": 0.00008189274407698049 + "marketData": { + "0x89": { + "0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d": { + "price": 0.00039345803819379796, + "contractPercentChange1d": 0.004, + "priceChange1d": 0.00004 + }, + "0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5": { + "price": 0.00008189274407698049, + "contractPercentChange1d": 0.01, + "priceChange1d": 0.001 + }, + "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599": { + "price": 0.0017123, + "contractPercentChange1d": 0.006, + "priceChange1d": 0.001 + }, + "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": { + "price": 0.0000000018, + "contractPercentChange1d": 0.02, + "priceChange1d": 0.01 + } + }, + "0x5": { + "0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d": { + "price": 0.00039345803819379796, + "contractPercentChange1d": 0.004, + "priceChange1d": 0.00004 + }, + "0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5": { + "price": 0.00008189274407698049, + "contractPercentChange1d": 0.01, + "priceChange1d": 0.001 + }, + "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599": { + "price": 0.0017123, + "contractPercentChange1d": 0.006, + "priceChange1d": 0.001 + }, + "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": { + "price": 0.0000000018, + "contractPercentChange1d": 0.02, + "priceChange1d": 0.01 + } + }, + "0x1": { + "0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d": { + "price": 0.00039345803819379796, + "contractPercentChange1d": 0.004, + "priceChange1d": 0.00004 + }, + "0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5": { + "price": 0.00008189274407698049, + "contractPercentChange1d": 0.01, + "priceChange1d": 0.001 + }, + "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599": { + "price": 0.0017123, + "contractPercentChange1d": 0.006, + "priceChange1d": 0.001 + }, + "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": { + "price": 0.0000000018, + "contractPercentChange1d": 0.02, + "priceChange1d": 0.01 + } + } }, "ticker": "ETH", "currentCurrency": "usd", @@ -1592,7 +1878,6 @@ "origin": "tmashuang.github.io" } ], - "desktopEnabled": false, "addSnapAccountEnabled": false, "pendingApprovals": { "testApprovalId": { @@ -1661,6 +1946,7 @@ "send": { "amountMode": "INPUT", "currentTransactionUUID": null, + "disabledSwapAndSendNetworks": [], "draftTransactions": {}, "eip1559support": false, "gasEstimateIsLoading": true, diff --git a/test/data/transaction-data.json b/test/data/transaction-data.json index a9155363ff19..ad2dacfe082c 100644 --- a/test/data/transaction-data.json +++ b/test/data/transaction-data.json @@ -993,5 +993,1652 @@ }, "hasRetried": false, "hasCancelled": false + }, + { + "nonce": "0x72", + "transactions": [ + { + "actionId": 1716427210524.908, + "baseFeePerGas": "0x18205f063", + "blockTimestamp": "0x664e99d7", + "chainId": "0x1", + "defaultGasEstimates": { + "estimateType": "medium", + "gas": "0x3c3d6", + "maxFeePerGas": "0x1da1d1cff", + "maxPriorityFeePerGas": "0x53417a0" + }, + "destinationTokenAddress": "0x0000000000000000000000000000000000000000", + "destinationTokenAmount": "2223344229978020", + "destinationTokenDecimals": 18, + "destinationTokenSymbol": "ETH", + "firstRetryBlockNumber": "0x13018ad", + "gasFeeEstimates": { + "high": { + "maxFeePerGas": "0x254e7aa25", + "maxPriorityFeePerGas": "0x66ce5c0" + }, + "low": { + "maxFeePerGas": "0x15be9093e", + "maxPriorityFeePerGas": "0x91c2e5" + }, + "medium": { + "maxFeePerGas": "0x1da1d1cff", + "maxPriorityFeePerGas": "0x53417a0" + }, + "type": "fee-market" + }, + "gasFeeEstimatesLoaded": true, + "hash": "0x0ca5ca02c47906198c1d775322bfcaba096c612201140899c4362455960fb2a0", + "history": [], + "id": "9930b750-18a2-11ef-bd1c-15e344f5ad78", + "networkClientId": "mainnet", + "origin": "metamask", + "r": "0xfe8b1f779b35ab03867d4585ff23d2abfbcfcb55b5ab2d37a51757c13aa0cc6d", + "rawTx": "0x02f903d2017284053417a08501da1d1cff8303c3d6940fced0519f62abb5a22f95dca0e194af7b84c59880b90364048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef000000000000000000000000000000000000000000000001cfdfc9b39088e77000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000c6f6ca03d790168758285264bcbf7fb30d27322b0000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001cfdfc9b39088e7700000000000000000000000000000000000000000000000000007bdad6a2e309b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000011d98820b2d200000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000128d9627aa40000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000001cfdfc9b39088e7700000000000000000000000000000000000000000000000000007cf2b8e4e3c03000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb00000000000000000000000000000000bc9ecd80547f0598e8589d11198ba821000000000000000000000000000000000000000000000000c080a0fe8b1f779b35ab03867d4585ff23d2abfbcfcb55b5ab2d37a51757c13aa0cc6da019889e6c39e389c8b6fe18babaf21487f97b8fe7f914c3354f4d43cdcba0639f", + "s": "0x19889e6c39e389c8b6fe18babaf21487f97b8fe7f914c3354f4d43cdcba0639f", + "sendFlowHistory": [], + "sourceTokenAddress": "0x0d8775f648430679a709e98d2b0cb6250d2887ef", + "sourceTokenAmount": "33425656732428330864", + "sourceTokenDecimals": 18, + "sourceTokenSymbol": "BAT", + "status": "confirmed", + "submittedTime": 1716427211100, + "swapAndSendRecipient": "0xc6f6ca03d790168758285264bcbf7fb30d27322b", + "swapTokenValue": "33.425656732428330864", + "time": 1716427210565, + "txParams": { + "data": "0x048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef000000000000000000000000000000000000000000000001cfdfc9b39088e77000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000c6f6ca03d790168758285264bcbf7fb30d27322b0000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001cfdfc9b39088e7700000000000000000000000000000000000000000000000000007bdad6a2e309b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000011d98820b2d200000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000128d9627aa40000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000001cfdfc9b39088e7700000000000000000000000000000000000000000000000000007cf2b8e4e3c03000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb00000000000000000000000000000000bc9ecd80547f0598e8589d11198ba821000000000000000000000000000000000000000000000000", + "from": "0x0a985a957b490f4d05bef05bc7ec556dd8535946", + "gas": "0x3c3d6", + "gasLimit": "0x3c3d6", + "maxFeePerGas": "0x1da1d1cff", + "maxPriorityFeePerGas": "0x53417a0", + "nonce": "0x72", + "to": "0x0fced0519f62abb5a22f95dca0e194af7b84c598", + "type": "0x2", + "value": "0x0" + }, + "txReceipt": { + "blockHash": "0xe5e84d1ca327d4f3c6d9446da23425687e90108b52bebd3e75154827c81d4e28", + "blockNumber": "0x13018af", + "contractAddress": null, + "cumulativeGasUsed": "0xa1d718", + "effectiveGasPrice": "0x1873a0803", + "from": "0x0a985a957b490f4d05bef05bc7ec556dd8535946", + "gasUsed": "0x2fa69", + "logs": [], + "logsBloom": "0x00200040800000800000000080000400000020000000000000000000000000200000000000000000000000000001000002000000080000000000000000200020000100010000042000000008000000200000000000400000000000000000000000000000000000000000000000000040000000800000040008200010000000000000000000008000000000000000000000000100000000080000004200040000020000000000000000004000000000000000000010000000080000000000000000000002000000000000000000000000000000000000001000000002000000000010200000000002000000000000000000000000000000000000000000000000", + "status": "0x1", + "to": "0x0fced0519f62abb5a22f95dca0e194af7b84c598", + "transactionHash": "0x0ca5ca02c47906198c1d775322bfcaba096c612201140899c4362455960fb2a0", + "transactionIndex": "0x6e", + "type": "0x2" + }, + "type": "swapAndSend", + "userEditedGasLimit": false, + "userFeeLevel": "medium", + "v": "0x0", + "verifiedOnBlockchain": true + } + ], + "initialTransaction": { + "actionId": 1716427210524.908, + "baseFeePerGas": "0x18205f063", + "blockTimestamp": "0x664e99d7", + "chainId": "0x1", + "defaultGasEstimates": { + "estimateType": "medium", + "gas": "0x3c3d6", + "maxFeePerGas": "0x1da1d1cff", + "maxPriorityFeePerGas": "0x53417a0" + }, + "destinationTokenAddress": "0x0000000000000000000000000000000000000000", + "destinationTokenAmount": "2223344229978020", + "destinationTokenDecimals": 18, + "destinationTokenSymbol": "ETH", + "firstRetryBlockNumber": "0x13018ad", + "gasFeeEstimates": { + "high": { + "maxFeePerGas": "0x254e7aa25", + "maxPriorityFeePerGas": "0x66ce5c0" + }, + "low": { + "maxFeePerGas": "0x15be9093e", + "maxPriorityFeePerGas": "0x91c2e5" + }, + "medium": { + "maxFeePerGas": "0x1da1d1cff", + "maxPriorityFeePerGas": "0x53417a0" + }, + "type": "fee-market" + }, + "gasFeeEstimatesLoaded": true, + "hash": "0x0ca5ca02c47906198c1d775322bfcaba096c612201140899c4362455960fb2a0", + "history": [], + "id": "9930b750-18a2-11ef-bd1c-15e344f5ad78", + "networkClientId": "mainnet", + "origin": "metamask", + "r": "0xfe8b1f779b35ab03867d4585ff23d2abfbcfcb55b5ab2d37a51757c13aa0cc6d", + "rawTx": "0x02f903d2017284053417a08501da1d1cff8303c3d6940fced0519f62abb5a22f95dca0e194af7b84c59880b90364048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef000000000000000000000000000000000000000000000001cfdfc9b39088e77000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000c6f6ca03d790168758285264bcbf7fb30d27322b0000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001cfdfc9b39088e7700000000000000000000000000000000000000000000000000007bdad6a2e309b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000011d98820b2d200000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000128d9627aa40000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000001cfdfc9b39088e7700000000000000000000000000000000000000000000000000007cf2b8e4e3c03000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb00000000000000000000000000000000bc9ecd80547f0598e8589d11198ba821000000000000000000000000000000000000000000000000c080a0fe8b1f779b35ab03867d4585ff23d2abfbcfcb55b5ab2d37a51757c13aa0cc6da019889e6c39e389c8b6fe18babaf21487f97b8fe7f914c3354f4d43cdcba0639f", + "s": "0x19889e6c39e389c8b6fe18babaf21487f97b8fe7f914c3354f4d43cdcba0639f", + "sendFlowHistory": [], + "sourceTokenAddress": "0x0d8775f648430679a709e98d2b0cb6250d2887ef", + "sourceTokenAmount": "33425656732428330864", + "sourceTokenDecimals": 18, + "sourceTokenSymbol": "BAT", + "status": "confirmed", + "submittedTime": 1716427211100, + "swapAndSendRecipient": "0xc6f6ca03d790168758285264bcbf7fb30d27322b", + "swapTokenValue": "33.425656732428330864", + "time": 1716427210565, + "txParams": { + "data": "0x048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef000000000000000000000000000000000000000000000001cfdfc9b39088e77000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000c6f6ca03d790168758285264bcbf7fb30d27322b0000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001cfdfc9b39088e7700000000000000000000000000000000000000000000000000007bdad6a2e309b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000011d98820b2d200000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000128d9627aa40000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000001cfdfc9b39088e7700000000000000000000000000000000000000000000000000007cf2b8e4e3c03000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb00000000000000000000000000000000bc9ecd80547f0598e8589d11198ba821000000000000000000000000000000000000000000000000", + "from": "0x0a985a957b490f4d05bef05bc7ec556dd8535946", + "gas": "0x3c3d6", + "gasLimit": "0x3c3d6", + "maxFeePerGas": "0x1da1d1cff", + "maxPriorityFeePerGas": "0x53417a0", + "nonce": "0x72", + "to": "0x0fced0519f62abb5a22f95dca0e194af7b84c598", + "type": "0x2", + "value": "0x0" + }, + "txReceipt": { + "blockHash": "0xe5e84d1ca327d4f3c6d9446da23425687e90108b52bebd3e75154827c81d4e28", + "blockNumber": "0x13018af", + "contractAddress": null, + "cumulativeGasUsed": "0xa1d718", + "effectiveGasPrice": "0x1873a0803", + "from": "0x0a985a957b490f4d05bef05bc7ec556dd8535946", + "gasUsed": "0x2fa69", + "logs": [], + "logsBloom": "0x00200040800000800000000080000400000020000000000000000000000000200000000000000000000000000001000002000000080000000000000000200020000100010000042000000008000000200000000000400000000000000000000000000000000000000000000000000040000000800000040008200010000000000000000000008000000000000000000000000100000000080000004200040000020000000000000000004000000000000000000010000000080000000000000000000002000000000000000000000000000000000000001000000002000000000010200000000002000000000000000000000000000000000000000000000000", + "status": "0x1", + "to": "0x0fced0519f62abb5a22f95dca0e194af7b84c598", + "transactionHash": "0x0ca5ca02c47906198c1d775322bfcaba096c612201140899c4362455960fb2a0", + "transactionIndex": "0x6e", + "type": "0x2" + }, + "type": "swapAndSend", + "userEditedGasLimit": false, + "userFeeLevel": "medium", + "v": "0x0", + "verifiedOnBlockchain": true + }, + "primaryTransaction": { + "actionId": 1716427210524.908, + "baseFeePerGas": "0x18205f063", + "blockTimestamp": "0x664e99d7", + "chainId": "0x1", + "defaultGasEstimates": { + "estimateType": "medium", + "gas": "0x3c3d6", + "maxFeePerGas": "0x1da1d1cff", + "maxPriorityFeePerGas": "0x53417a0" + }, + "destinationTokenAddress": "0x0000000000000000000000000000000000000000", + "destinationTokenAmount": "2223344229978020", + "destinationTokenDecimals": 18, + "destinationTokenSymbol": "ETH", + "firstRetryBlockNumber": "0x13018ad", + "gasFeeEstimates": { + "high": { + "maxFeePerGas": "0x254e7aa25", + "maxPriorityFeePerGas": "0x66ce5c0" + }, + "low": { + "maxFeePerGas": "0x15be9093e", + "maxPriorityFeePerGas": "0x91c2e5" + }, + "medium": { + "maxFeePerGas": "0x1da1d1cff", + "maxPriorityFeePerGas": "0x53417a0" + }, + "type": "fee-market" + }, + "gasFeeEstimatesLoaded": true, + "hash": "0x0ca5ca02c47906198c1d775322bfcaba096c612201140899c4362455960fb2a0", + "history": [], + "id": "9930b750-18a2-11ef-bd1c-15e344f5ad78", + "networkClientId": "mainnet", + "origin": "metamask", + "r": "0xfe8b1f779b35ab03867d4585ff23d2abfbcfcb55b5ab2d37a51757c13aa0cc6d", + "rawTx": "0x02f903d2017284053417a08501da1d1cff8303c3d6940fced0519f62abb5a22f95dca0e194af7b84c59880b90364048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef000000000000000000000000000000000000000000000001cfdfc9b39088e77000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000c6f6ca03d790168758285264bcbf7fb30d27322b0000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001cfdfc9b39088e7700000000000000000000000000000000000000000000000000007bdad6a2e309b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000011d98820b2d200000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000128d9627aa40000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000001cfdfc9b39088e7700000000000000000000000000000000000000000000000000007cf2b8e4e3c03000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb00000000000000000000000000000000bc9ecd80547f0598e8589d11198ba821000000000000000000000000000000000000000000000000c080a0fe8b1f779b35ab03867d4585ff23d2abfbcfcb55b5ab2d37a51757c13aa0cc6da019889e6c39e389c8b6fe18babaf21487f97b8fe7f914c3354f4d43cdcba0639f", + "s": "0x19889e6c39e389c8b6fe18babaf21487f97b8fe7f914c3354f4d43cdcba0639f", + "sendFlowHistory": [], + "sourceTokenAddress": "0x0d8775f648430679a709e98d2b0cb6250d2887ef", + "sourceTokenAmount": "33425656732428330864", + "sourceTokenDecimals": 18, + "sourceTokenSymbol": "BAT", + "status": "confirmed", + "submittedTime": 1716427211100, + "swapAndSendRecipient": "0xc6f6ca03d790168758285264bcbf7fb30d27322b", + "swapTokenValue": "33.425656732428330864", + "time": 1716427210565, + "txParams": { + "data": "0x048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef000000000000000000000000000000000000000000000001cfdfc9b39088e77000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000c6f6ca03d790168758285264bcbf7fb30d27322b0000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001cfdfc9b39088e7700000000000000000000000000000000000000000000000000007bdad6a2e309b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000011d98820b2d200000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000128d9627aa40000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000001cfdfc9b39088e7700000000000000000000000000000000000000000000000000007cf2b8e4e3c03000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb00000000000000000000000000000000bc9ecd80547f0598e8589d11198ba821000000000000000000000000000000000000000000000000", + "from": "0x0a985a957b490f4d05bef05bc7ec556dd8535946", + "gas": "0x3c3d6", + "gasLimit": "0x3c3d6", + "maxFeePerGas": "0x1da1d1cff", + "maxPriorityFeePerGas": "0x53417a0", + "nonce": "0x72", + "to": "0x0fced0519f62abb5a22f95dca0e194af7b84c598", + "type": "0x2", + "value": "0x0" + }, + "txReceipt": { + "blockHash": "0xe5e84d1ca327d4f3c6d9446da23425687e90108b52bebd3e75154827c81d4e28", + "blockNumber": "0x13018af", + "contractAddress": null, + "cumulativeGasUsed": "0xa1d718", + "effectiveGasPrice": "0x1873a0803", + "from": "0x0a985a957b490f4d05bef05bc7ec556dd8535946", + "gasUsed": "0x2fa69", + "logs": [], + "logsBloom": "0x00200040800000800000000080000400000020000000000000000000000000200000000000000000000000000001000002000000080000000000000000200020000100010000042000000008000000200000000000400000000000000000000000000000000000000000000000000040000000800000040008200010000000000000000000008000000000000000000000000100000000080000004200040000020000000000000000004000000000000000000010000000080000000000000000000002000000000000000000000000000000000000001000000002000000000010200000000002000000000000000000000000000000000000000000000000", + "status": "0x1", + "to": "0x0fced0519f62abb5a22f95dca0e194af7b84c598", + "transactionHash": "0x0ca5ca02c47906198c1d775322bfcaba096c612201140899c4362455960fb2a0", + "transactionIndex": "0x6e", + "type": "0x2" + }, + "type": "swapAndSend", + "userEditedGasLimit": false, + "userFeeLevel": "medium", + "v": "0x0", + "verifiedOnBlockchain": true + }, + "hasRetried": false, + "hasCancelled": false + }, + { + "nonce": "0x9", + "transactions": [ + { + "actionId": 1718133500046.724, + "approvalTxId": "5ce4f880-2827-11ef-9c65-d1738f73c46f", + "baseFeePerGas": "0x0", + "blockTimestamp": "0x6668a2fd", + "chainId": "0x38", + "defaultGasEstimates": { + "estimateType": "medium", + "gas": "0x51fc6", + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00" + }, + "destinationTokenAddress": "0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3", + "destinationTokenAmount": "4990565483715933000", + "destinationTokenDecimals": 18, + "destinationTokenSymbol": "DAI", + "hash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "history": [], + "id": "5cf9b900-2827-11ef-9c65-d1738f73c46f", + "networkClientId": "899c28d9-9f01-43c6-be76-b5e9f3cfe8bc", + "origin": "metamask", + "r": "0x443ec5a1269c18767b078894d177b4067831ea9ddcb33ebf92670d6667940985", + "rawTx": "0x02f903f1380984b2d05e0084b2d05e0083051fc6943cb693656622fc470f0bb07d3f5813f7889bf82e80b90384048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d0000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c188380000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d0000000000000000000000001af3f329e8be154074d8769d1ffa4ee058b1dbc30000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000043df73024b82680400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000148c43c9ef600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000043df73024b826804000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d000000000000000000000000e9e7cea3dedca5984780bafc599bd69add087d560000000000000000000000001af3f329e8be154074d8769d1ffa4ee058b1dbc3869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb0000000000000000000000000000000000000000aca7f7533c2098f78f35db24000000000000000000000000000000000000000000000000c001a0443ec5a1269c18767b078894d177b4067831ea9ddcb33ebf92670d6667940985a0519c27715e9ce0cab31e7738ffad7d454088c3e3c855f54b8a0965a17d999c62", + "s": "0x519c27715e9ce0cab31e7738ffad7d454088c3e3c855f54b8a0965a17d999c62", + "sendFlowHistory": [], + "sourceTokenAddress": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "sourceTokenAmount": "5000000000000000000", + "sourceTokenDecimals": 18, + "sourceTokenSymbol": "USDC", + "status": "confirmed", + "submittedTime": 1718133500335, + "swapAndSendRecipient": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "swapTokenValue": "5", + "time": 1718133500048, + "txParams": { + "data": "0x048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d0000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c188380000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d0000000000000000000000001af3f329e8be154074d8769d1ffa4ee058b1dbc30000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000043df73024b82680400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000148c43c9ef600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000043df73024b826804000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d000000000000000000000000e9e7cea3dedca5984780bafc599bd69add087d560000000000000000000000001af3f329e8be154074d8769d1ffa4ee058b1dbc3869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb0000000000000000000000000000000000000000aca7f7533c2098f78f35db24000000000000000000000000000000000000000000000000", + "from": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "gas": "0x51fc6", + "gasLimit": "0x51fc6", + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00", + "nonce": "0x9", + "to": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "type": "0x2", + "value": "0x0" + }, + "txReceipt": { + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "contractAddress": null, + "cumulativeGasUsed": "0x30fb3e", + "effectiveGasPrice": "0xb2d05e00", + "from": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "gasUsed": "0x401d6", + "logs": [ + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000004563918244f40000", + "logIndex": "0x45", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c18838", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x46", + "removed": false, + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c18838", + "0x0000000000000000000000003cb693656622fc470f0bb07d3f5813f7889bf82e" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000004563918244f40000", + "logIndex": "0x47", + "removed": false, + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000004563918244f40000", + "logIndex": "0x48", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x0000000000000000000000002354ef4df11afacb85a5c7f98b624072eccddbb1" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x49", + "removed": false, + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0xe9e7cea3dedca5984780bafc599bd69add087d56", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x00000000000000000000000000000000000000000000000045351670c8c8eb16", + "logIndex": "0x4a", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000002354ef4df11afacb85a5c7f98b624072eccddbb1", + "0x00000000000000000000000066fdb2eccfb58cf098eaa419e5efde841368e489" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x2354ef4df11afacb85a5c7f98b624072eccddbb1", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x000000000000000000000000000000000000000000005cf210c436771e7d4016000000000000000000000000000000000000000000005cfaf19326e57b4c5707", + "logIndex": "0x4b", + "removed": false, + "topics": [ + "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x2354ef4df11afacb85a5c7f98b624072eccddbb1", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000004563918244f400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045351670c8c8eb16", + "logIndex": "0x4c", + "removed": false, + "topics": [ + "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff", + "0x00000000000000000000000066fdb2eccfb58cf098eaa419e5efde841368e489" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x000000000000000000000000000000000000000000000000453047e918796cfd", + "logIndex": "0x4d", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000066fdb2eccfb58cf098eaa419e5efde841368e489", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x66fdb2eccfb58cf098eaa419e5efde841368e489", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000020c638a3898eb7869dcf0000000000000000000000000000000000000000000020af974dbd9430b354c8", + "logIndex": "0x4e", + "removed": false, + "topics": [ + "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x66fdb2eccfb58cf098eaa419e5efde841368e489", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045351670c8c8eb16000000000000000000000000000000000000000000000000453047e918796cfd0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x4f", + "removed": false, + "topics": [ + "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x50", + "removed": false, + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x000000000000000000000000000000000000000000000000453047e918796cfd", + "logIndex": "0x51", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c18838" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000045357415000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x52", + "removed": false, + "topics": [ + "0x0c18aae526accb31b01cf9a15bdf435e70632ee31efc4c5c0752c4262ea45d2f" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + } + ], + "logsBloom": "0x006000000040001000000000800004000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000002000c0000000010000012000040008000000240000000000000088000000000000000008000000000000000000000004000040000000000000002008000010000000020000000000000001000000000040008000000000000800084000004000000100020000000000000000004000000000000000000000000000004000000000000000000002000000020000000000001000000040100000001000000020000000000010000000004002000000100000000000800000008000000000000001000000", + "status": "0x1", + "to": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21", + "type": "0x2" + }, + "type": "swapAndSend", + "userEditedGasLimit": false, + "userFeeLevel": "medium", + "v": "0x1", + "verifiedOnBlockchain": true + } + ], + "initialTransaction": { + "actionId": 1718133500046.724, + "approvalTxId": "5ce4f880-2827-11ef-9c65-d1738f73c46f", + "baseFeePerGas": "0x0", + "blockTimestamp": "0x6668a2fd", + "chainId": "0x38", + "defaultGasEstimates": { + "estimateType": "medium", + "gas": "0x51fc6", + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00" + }, + "destinationTokenAddress": "0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3", + "destinationTokenAmount": "4990565483715933000", + "destinationTokenDecimals": 18, + "destinationTokenSymbol": "DAI", + "hash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "history": [], + "id": "5cf9b900-2827-11ef-9c65-d1738f73c46f", + "networkClientId": "899c28d9-9f01-43c6-be76-b5e9f3cfe8bc", + "origin": "metamask", + "r": "0x443ec5a1269c18767b078894d177b4067831ea9ddcb33ebf92670d6667940985", + "rawTx": "0x02f903f1380984b2d05e0084b2d05e0083051fc6943cb693656622fc470f0bb07d3f5813f7889bf82e80b90384048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d0000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c188380000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d0000000000000000000000001af3f329e8be154074d8769d1ffa4ee058b1dbc30000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000043df73024b82680400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000148c43c9ef600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000043df73024b826804000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d000000000000000000000000e9e7cea3dedca5984780bafc599bd69add087d560000000000000000000000001af3f329e8be154074d8769d1ffa4ee058b1dbc3869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb0000000000000000000000000000000000000000aca7f7533c2098f78f35db24000000000000000000000000000000000000000000000000c001a0443ec5a1269c18767b078894d177b4067831ea9ddcb33ebf92670d6667940985a0519c27715e9ce0cab31e7738ffad7d454088c3e3c855f54b8a0965a17d999c62", + "s": "0x519c27715e9ce0cab31e7738ffad7d454088c3e3c855f54b8a0965a17d999c62", + "sendFlowHistory": [], + "sourceTokenAddress": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "sourceTokenAmount": "5000000000000000000", + "sourceTokenDecimals": 18, + "sourceTokenSymbol": "USDC", + "status": "confirmed", + "submittedTime": 1718133500335, + "swapAndSendRecipient": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "swapTokenValue": "5", + "time": 1718133500048, + "txParams": { + "data": "0x048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d0000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c188380000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d0000000000000000000000001af3f329e8be154074d8769d1ffa4ee058b1dbc30000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000043df73024b82680400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000148c43c9ef600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000043df73024b826804000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d000000000000000000000000e9e7cea3dedca5984780bafc599bd69add087d560000000000000000000000001af3f329e8be154074d8769d1ffa4ee058b1dbc3869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb0000000000000000000000000000000000000000aca7f7533c2098f78f35db24000000000000000000000000000000000000000000000000", + "from": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "gas": "0x51fc6", + "gasLimit": "0x51fc6", + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00", + "nonce": "0x9", + "to": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "type": "0x2", + "value": "0x0" + }, + "txReceipt": { + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "contractAddress": null, + "cumulativeGasUsed": "0x30fb3e", + "effectiveGasPrice": "0xb2d05e00", + "from": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "gasUsed": "0x401d6", + "logs": [ + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000004563918244f40000", + "logIndex": "0x45", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c18838", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x46", + "removed": false, + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c18838", + "0x0000000000000000000000003cb693656622fc470f0bb07d3f5813f7889bf82e" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000004563918244f40000", + "logIndex": "0x47", + "removed": false, + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000004563918244f40000", + "logIndex": "0x48", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x0000000000000000000000002354ef4df11afacb85a5c7f98b624072eccddbb1" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x49", + "removed": false, + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0xe9e7cea3dedca5984780bafc599bd69add087d56", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x00000000000000000000000000000000000000000000000045351670c8c8eb16", + "logIndex": "0x4a", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000002354ef4df11afacb85a5c7f98b624072eccddbb1", + "0x00000000000000000000000066fdb2eccfb58cf098eaa419e5efde841368e489" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x2354ef4df11afacb85a5c7f98b624072eccddbb1", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x000000000000000000000000000000000000000000005cf210c436771e7d4016000000000000000000000000000000000000000000005cfaf19326e57b4c5707", + "logIndex": "0x4b", + "removed": false, + "topics": [ + "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x2354ef4df11afacb85a5c7f98b624072eccddbb1", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000004563918244f400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045351670c8c8eb16", + "logIndex": "0x4c", + "removed": false, + "topics": [ + "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff", + "0x00000000000000000000000066fdb2eccfb58cf098eaa419e5efde841368e489" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x000000000000000000000000000000000000000000000000453047e918796cfd", + "logIndex": "0x4d", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000066fdb2eccfb58cf098eaa419e5efde841368e489", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x66fdb2eccfb58cf098eaa419e5efde841368e489", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000020c638a3898eb7869dcf0000000000000000000000000000000000000000000020af974dbd9430b354c8", + "logIndex": "0x4e", + "removed": false, + "topics": [ + "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x66fdb2eccfb58cf098eaa419e5efde841368e489", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045351670c8c8eb16000000000000000000000000000000000000000000000000453047e918796cfd0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x4f", + "removed": false, + "topics": [ + "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x50", + "removed": false, + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x000000000000000000000000000000000000000000000000453047e918796cfd", + "logIndex": "0x51", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c18838" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000045357415000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x52", + "removed": false, + "topics": [ + "0x0c18aae526accb31b01cf9a15bdf435e70632ee31efc4c5c0752c4262ea45d2f" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + } + ], + "logsBloom": "0x006000000040001000000000800004000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000002000c0000000010000012000040008000000240000000000000088000000000000000008000000000000000000000004000040000000000000002008000010000000020000000000000001000000000040008000000000000800084000004000000100020000000000000000004000000000000000000000000000004000000000000000000002000000020000000000001000000040100000001000000020000000000010000000004002000000100000000000800000008000000000000001000000", + "status": "0x1", + "to": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21", + "type": "0x2" + }, + "type": "swapAndSend", + "userEditedGasLimit": false, + "userFeeLevel": "medium", + "v": "0x1", + "verifiedOnBlockchain": true + }, + "primaryTransaction": { + "actionId": 1718133500046.724, + "approvalTxId": "5ce4f880-2827-11ef-9c65-d1738f73c46f", + "baseFeePerGas": "0x0", + "blockTimestamp": "0x6668a2fd", + "chainId": "0x38", + "defaultGasEstimates": { + "estimateType": "medium", + "gas": "0x51fc6", + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00" + }, + "destinationTokenAddress": "0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3", + "destinationTokenAmount": "4990565483715933000", + "destinationTokenDecimals": 18, + "destinationTokenSymbol": "DAI", + "hash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "history": [], + "id": "5cf9b900-2827-11ef-9c65-d1738f73c46f", + "networkClientId": "899c28d9-9f01-43c6-be76-b5e9f3cfe8bc", + "origin": "metamask", + "r": "0x443ec5a1269c18767b078894d177b4067831ea9ddcb33ebf92670d6667940985", + "rawTx": "0x02f903f1380984b2d05e0084b2d05e0083051fc6943cb693656622fc470f0bb07d3f5813f7889bf82e80b90384048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d0000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c188380000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d0000000000000000000000001af3f329e8be154074d8769d1ffa4ee058b1dbc30000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000043df73024b82680400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000148c43c9ef600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000043df73024b826804000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d000000000000000000000000e9e7cea3dedca5984780bafc599bd69add087d560000000000000000000000001af3f329e8be154074d8769d1ffa4ee058b1dbc3869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb0000000000000000000000000000000000000000aca7f7533c2098f78f35db24000000000000000000000000000000000000000000000000c001a0443ec5a1269c18767b078894d177b4067831ea9ddcb33ebf92670d6667940985a0519c27715e9ce0cab31e7738ffad7d454088c3e3c855f54b8a0965a17d999c62", + "s": "0x519c27715e9ce0cab31e7738ffad7d454088c3e3c855f54b8a0965a17d999c62", + "sendFlowHistory": [], + "sourceTokenAddress": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "sourceTokenAmount": "5000000000000000000", + "sourceTokenDecimals": 18, + "sourceTokenSymbol": "USDC", + "status": "confirmed", + "submittedTime": 1718133500335, + "swapAndSendRecipient": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "swapTokenValue": "5", + "time": 1718133500048, + "txParams": { + "data": "0x048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d0000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c188380000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d0000000000000000000000001af3f329e8be154074d8769d1ffa4ee058b1dbc30000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000043df73024b82680400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000148c43c9ef600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000043df73024b826804000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d000000000000000000000000e9e7cea3dedca5984780bafc599bd69add087d560000000000000000000000001af3f329e8be154074d8769d1ffa4ee058b1dbc3869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb0000000000000000000000000000000000000000aca7f7533c2098f78f35db24000000000000000000000000000000000000000000000000", + "from": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "gas": "0x51fc6", + "gasLimit": "0x51fc6", + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00", + "nonce": "0x9", + "to": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "type": "0x2", + "value": "0x0" + }, + "txReceipt": { + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "contractAddress": null, + "cumulativeGasUsed": "0x30fb3e", + "effectiveGasPrice": "0xb2d05e00", + "from": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "gasUsed": "0x401d6", + "logs": [ + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000004563918244f40000", + "logIndex": "0x45", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c18838", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x46", + "removed": false, + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c18838", + "0x0000000000000000000000003cb693656622fc470f0bb07d3f5813f7889bf82e" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000004563918244f40000", + "logIndex": "0x47", + "removed": false, + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000004563918244f40000", + "logIndex": "0x48", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x0000000000000000000000002354ef4df11afacb85a5c7f98b624072eccddbb1" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x49", + "removed": false, + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0xe9e7cea3dedca5984780bafc599bd69add087d56", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x00000000000000000000000000000000000000000000000045351670c8c8eb16", + "logIndex": "0x4a", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000002354ef4df11afacb85a5c7f98b624072eccddbb1", + "0x00000000000000000000000066fdb2eccfb58cf098eaa419e5efde841368e489" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x2354ef4df11afacb85a5c7f98b624072eccddbb1", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x000000000000000000000000000000000000000000005cf210c436771e7d4016000000000000000000000000000000000000000000005cfaf19326e57b4c5707", + "logIndex": "0x4b", + "removed": false, + "topics": [ + "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x2354ef4df11afacb85a5c7f98b624072eccddbb1", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000004563918244f400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045351670c8c8eb16", + "logIndex": "0x4c", + "removed": false, + "topics": [ + "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff", + "0x00000000000000000000000066fdb2eccfb58cf098eaa419e5efde841368e489" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x000000000000000000000000000000000000000000000000453047e918796cfd", + "logIndex": "0x4d", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000066fdb2eccfb58cf098eaa419e5efde841368e489", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x66fdb2eccfb58cf098eaa419e5efde841368e489", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000020c638a3898eb7869dcf0000000000000000000000000000000000000000000020af974dbd9430b354c8", + "logIndex": "0x4e", + "removed": false, + "topics": [ + "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x66fdb2eccfb58cf098eaa419e5efde841368e489", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045351670c8c8eb16000000000000000000000000000000000000000000000000453047e918796cfd0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x4f", + "removed": false, + "topics": [ + "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x50", + "removed": false, + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x000000000000000000000000000000000000000000000000453047e918796cfd", + "logIndex": "0x51", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c18838" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + }, + { + "address": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "blockHash": "0x2ad0174dc123330852694ddeaa1924450b6bba340485f18abe3a6681bc8896f7", + "blockNumber": "0x25b2338", + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000045357415000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x52", + "removed": false, + "topics": [ + "0x0c18aae526accb31b01cf9a15bdf435e70632ee31efc4c5c0752c4262ea45d2f" + ], + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21" + } + ], + "logsBloom": "0x006000000040001000000000800004000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000002000c0000000010000012000040008000000240000000000000088000000000000000008000000000000000000000004000040000000000000002008000010000000020000000000000001000000000040008000000000000800084000004000000100020000000000000000004000000000000000000000000000004000000000000000000002000000020000000000001000000040100000001000000020000000000010000000004002000000100000000000800000008000000000000001000000", + "status": "0x1", + "to": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "transactionHash": "0x5be1ae5ae27c4e2a5542228b4f7967a660881dcbc71521a978ea6d9c3b3971fe", + "transactionIndex": "0x21", + "type": "0x2" + }, + "type": "swapAndSend", + "userEditedGasLimit": false, + "userFeeLevel": "medium", + "v": "0x1", + "verifiedOnBlockchain": true + }, + "hasRetried": false, + "hasCancelled": false + }, + { + "nonce": "0x0", + "transactions": [ + { + "actionId": 1717789986313.557, + "baseFeePerGas": "0x0", + "blockTimestamp": "0x66636524", + "chainId": "0x38", + "defaultGasEstimates": { + "estimateType": "medium", + "gas": "0x397cf", + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00" + }, + "destinationTokenAddress": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "destinationTokenAmount": "33721280446418538542", + "destinationTokenDecimals": 18, + "destinationTokenSymbol": "USDC", + "firstRetryBlockNumber": "0x259650b", + "gasFeeEstimates": { + "high": { + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00" + }, + "low": { + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00" + }, + "medium": { + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00" + }, + "type": "fee-market" + }, + "gasFeeEstimatesLoaded": true, + "hash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "history": [], + "id": "8ed642e0-2507-11ef-99c4-53f3fc2768a2", + "networkClientId": "899c28d9-9f01-43c6-be76-b5e9f3cfe8bc", + "origin": "metamask", + "r": "0x7fbbe0d92a8da53a9bc98ef8144c6677ecb08050ea180548d93b7830cb407a2a", + "rawTx": "0x02f903d8388084b2d05e0084b2d05e00830397cf943cb693656622fc470f0bb07d3f5813f7889bf82e87b1a2bc2ec50000b90364048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c1883800000000000000000000000000000000000000000000000000000000000000000000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d00000000000000000000000000000000000000000000000000b014d4c6ae2800000000000000000000000000000000000000000000000001ca9e03628c802fdb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000018de76816d80000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000128c43c9ef6000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000b014d4c6ae2800000000000000000000000000000000000000000000000001ca9e03628c802fdb00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb000000000000000000000000000000003736a41146b8f4bb97dbe80a5771808c000000000000000000000000000000000000000000000000c001a07fbbe0d92a8da53a9bc98ef8144c6677ecb08050ea180548d93b7830cb407a2aa04d050489b179ec7832166566d3769408ef6c407d0032243cdabeb99bab87d634", + "s": "0x4d050489b179ec7832166566d3769408ef6c407d0032243cdabeb99bab87d634", + "sendFlowHistory": [], + "sourceTokenAddress": "0x0000000000000000000000000000000000000000", + "sourceTokenAmount": "50000000000000000", + "sourceTokenDecimals": 18, + "sourceTokenSymbol": "BNB", + "status": "confirmed", + "submittedTime": 1717789986704, + "swapAndSendRecipient": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "swapTokenValue": "0.05", + "time": 1717789986319, + "txParams": { + "data": "0x048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c1883800000000000000000000000000000000000000000000000000000000000000000000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d00000000000000000000000000000000000000000000000000b014d4c6ae2800000000000000000000000000000000000000000000000001ca9e03628c802fdb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000018de76816d80000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000128c43c9ef6000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000b014d4c6ae2800000000000000000000000000000000000000000000000001ca9e03628c802fdb00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb000000000000000000000000000000003736a41146b8f4bb97dbe80a5771808c000000000000000000000000000000000000000000000000", + "from": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "gas": "0x397cf", + "gasLimit": "0x397cf", + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00", + "nonce": "0x0", + "to": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "type": "0x2", + "value": "0xb1a2bc2ec50000" + }, + "txReceipt": { + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "contractAddress": null, + "cumulativeGasUsed": "0x2644bd", + "effectiveGasPrice": "0xb2d05e00", + "from": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "gasUsed": "0x31a28", + "logs": [ + { + "address": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x00000000000000000000000000000000000000000000000000b014d4c6ae2800", + "logIndex": "0x38", + "removed": false, + "topics": [ + "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x00000000000000000000000000000000000000000000000000b014d4c6ae2800", + "logIndex": "0x39", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff", + "0x000000000000000000000000d99c7f6c65857ac913a8f880a4cb84032ab2fc5b" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x000000000000000000000000000000000000000000000001d3be028ce893dfbe", + "logIndex": "0x3a", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000d99c7f6c65857ac913a8f880a4cb84032ab2fc5b", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0xd99c7f6c65857ac913a8f880a4cb84032ab2fc5b", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x000000000000000000000000000000000000000000003ef046f04c7cafc1e5e20000000000000000000000000000000000000000000000179ff39de2fc5b390a", + "logIndex": "0x3b", + "removed": false, + "topics": [ + "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0xd99c7f6c65857ac913a8f880a4cb84032ab2fc5b", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b014d4c6ae2800000000000000000000000000000000000000000000000001d3be028ce893dfbe0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x3c", + "removed": false, + "topics": [ + "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x000000000000000000000000000000000000000000000001d3be028ce893dfbe", + "logIndex": "0x3d", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c18838" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000045357415000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x3e", + "removed": false, + "topics": [ + "0x0c18aae526accb31b01cf9a15bdf435e70632ee31efc4c5c0752c4262ea45d2f" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + } + ], + "logsBloom": "0x00600000000000000000000080000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000010000012000000008000000200000000000000000000400008000000000400000000000000000000004000040000000000000000008000010000000000000000000000001000000000040008000040001000800080000004000000000000000000000000000004000000000000000000000000004024000000000000000000002000000000000040000000000000000000000001040000000000080000000000000005002000000000000000000000000000000400000000001000000", + "status": "0x1", + "to": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e", + "type": "0x2" + }, + "type": "swapAndSend", + "userEditedGasLimit": false, + "userFeeLevel": "medium", + "v": "0x1", + "verifiedOnBlockchain": true + } + ], + "initialTransaction": { + "actionId": 1717789986313.557, + "baseFeePerGas": "0x0", + "blockTimestamp": "0x66636524", + "chainId": "0x38", + "defaultGasEstimates": { + "estimateType": "medium", + "gas": "0x397cf", + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00" + }, + "destinationTokenAddress": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "destinationTokenAmount": "33721280446418538542", + "destinationTokenDecimals": 18, + "destinationTokenSymbol": "USDC", + "firstRetryBlockNumber": "0x259650b", + "gasFeeEstimates": { + "high": { + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00" + }, + "low": { + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00" + }, + "medium": { + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00" + }, + "type": "fee-market" + }, + "gasFeeEstimatesLoaded": true, + "hash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "history": [], + "id": "8ed642e0-2507-11ef-99c4-53f3fc2768a2", + "networkClientId": "899c28d9-9f01-43c6-be76-b5e9f3cfe8bc", + "origin": "metamask", + "r": "0x7fbbe0d92a8da53a9bc98ef8144c6677ecb08050ea180548d93b7830cb407a2a", + "rawTx": "0x02f903d8388084b2d05e0084b2d05e00830397cf943cb693656622fc470f0bb07d3f5813f7889bf82e87b1a2bc2ec50000b90364048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c1883800000000000000000000000000000000000000000000000000000000000000000000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d00000000000000000000000000000000000000000000000000b014d4c6ae2800000000000000000000000000000000000000000000000001ca9e03628c802fdb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000018de76816d80000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000128c43c9ef6000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000b014d4c6ae2800000000000000000000000000000000000000000000000001ca9e03628c802fdb00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb000000000000000000000000000000003736a41146b8f4bb97dbe80a5771808c000000000000000000000000000000000000000000000000c001a07fbbe0d92a8da53a9bc98ef8144c6677ecb08050ea180548d93b7830cb407a2aa04d050489b179ec7832166566d3769408ef6c407d0032243cdabeb99bab87d634", + "s": "0x4d050489b179ec7832166566d3769408ef6c407d0032243cdabeb99bab87d634", + "sendFlowHistory": [], + "sourceTokenAddress": "0x0000000000000000000000000000000000000000", + "sourceTokenAmount": "50000000000000000", + "sourceTokenDecimals": 18, + "sourceTokenSymbol": "BNB", + "status": "confirmed", + "submittedTime": 1717789986704, + "swapAndSendRecipient": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "swapTokenValue": "0.05", + "time": 1717789986319, + "txParams": { + "data": "0x048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c1883800000000000000000000000000000000000000000000000000000000000000000000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d00000000000000000000000000000000000000000000000000b014d4c6ae2800000000000000000000000000000000000000000000000001ca9e03628c802fdb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000018de76816d80000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000128c43c9ef6000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000b014d4c6ae2800000000000000000000000000000000000000000000000001ca9e03628c802fdb00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb000000000000000000000000000000003736a41146b8f4bb97dbe80a5771808c000000000000000000000000000000000000000000000000", + "from": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "gas": "0x397cf", + "gasLimit": "0x397cf", + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00", + "nonce": "0x0", + "to": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "type": "0x2", + "value": "0xb1a2bc2ec50000" + }, + "txReceipt": { + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "contractAddress": null, + "cumulativeGasUsed": "0x2644bd", + "effectiveGasPrice": "0xb2d05e00", + "from": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "gasUsed": "0x31a28", + "logs": [ + { + "address": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x00000000000000000000000000000000000000000000000000b014d4c6ae2800", + "logIndex": "0x38", + "removed": false, + "topics": [ + "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x00000000000000000000000000000000000000000000000000b014d4c6ae2800", + "logIndex": "0x39", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff", + "0x000000000000000000000000d99c7f6c65857ac913a8f880a4cb84032ab2fc5b" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x000000000000000000000000000000000000000000000001d3be028ce893dfbe", + "logIndex": "0x3a", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000d99c7f6c65857ac913a8f880a4cb84032ab2fc5b", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0xd99c7f6c65857ac913a8f880a4cb84032ab2fc5b", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x000000000000000000000000000000000000000000003ef046f04c7cafc1e5e20000000000000000000000000000000000000000000000179ff39de2fc5b390a", + "logIndex": "0x3b", + "removed": false, + "topics": [ + "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0xd99c7f6c65857ac913a8f880a4cb84032ab2fc5b", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b014d4c6ae2800000000000000000000000000000000000000000000000001d3be028ce893dfbe0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x3c", + "removed": false, + "topics": [ + "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x000000000000000000000000000000000000000000000001d3be028ce893dfbe", + "logIndex": "0x3d", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c18838" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000045357415000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x3e", + "removed": false, + "topics": [ + "0x0c18aae526accb31b01cf9a15bdf435e70632ee31efc4c5c0752c4262ea45d2f" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + } + ], + "logsBloom": "0x00600000000000000000000080000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000010000012000000008000000200000000000000000000400008000000000400000000000000000000004000040000000000000000008000010000000000000000000000001000000000040008000040001000800080000004000000000000000000000000000004000000000000000000000000004024000000000000000000002000000000000040000000000000000000000001040000000000080000000000000005002000000000000000000000000000000400000000001000000", + "status": "0x1", + "to": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e", + "type": "0x2" + }, + "type": "swapAndSend", + "userEditedGasLimit": false, + "userFeeLevel": "medium", + "v": "0x1", + "verifiedOnBlockchain": true + }, + "primaryTransaction": { + "actionId": 1717789986313.557, + "baseFeePerGas": "0x0", + "blockTimestamp": "0x66636524", + "chainId": "0x38", + "defaultGasEstimates": { + "estimateType": "medium", + "gas": "0x397cf", + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00" + }, + "destinationTokenAddress": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "destinationTokenAmount": "33721280446418538542", + "destinationTokenDecimals": 18, + "destinationTokenSymbol": "USDC", + "firstRetryBlockNumber": "0x259650b", + "gasFeeEstimates": { + "high": { + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00" + }, + "low": { + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00" + }, + "medium": { + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00" + }, + "type": "fee-market" + }, + "gasFeeEstimatesLoaded": true, + "hash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "history": [], + "id": "8ed642e0-2507-11ef-99c4-53f3fc2768a2", + "networkClientId": "899c28d9-9f01-43c6-be76-b5e9f3cfe8bc", + "origin": "metamask", + "r": "0x7fbbe0d92a8da53a9bc98ef8144c6677ecb08050ea180548d93b7830cb407a2a", + "rawTx": "0x02f903d8388084b2d05e0084b2d05e00830397cf943cb693656622fc470f0bb07d3f5813f7889bf82e87b1a2bc2ec50000b90364048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c1883800000000000000000000000000000000000000000000000000000000000000000000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d00000000000000000000000000000000000000000000000000b014d4c6ae2800000000000000000000000000000000000000000000000001ca9e03628c802fdb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000018de76816d80000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000128c43c9ef6000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000b014d4c6ae2800000000000000000000000000000000000000000000000001ca9e03628c802fdb00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb000000000000000000000000000000003736a41146b8f4bb97dbe80a5771808c000000000000000000000000000000000000000000000000c001a07fbbe0d92a8da53a9bc98ef8144c6677ecb08050ea180548d93b7830cb407a2aa04d050489b179ec7832166566d3769408ef6c407d0032243cdabeb99bab87d634", + "s": "0x4d050489b179ec7832166566d3769408ef6c407d0032243cdabeb99bab87d634", + "sendFlowHistory": [], + "sourceTokenAddress": "0x0000000000000000000000000000000000000000", + "sourceTokenAmount": "50000000000000000", + "sourceTokenDecimals": 18, + "sourceTokenSymbol": "BNB", + "status": "confirmed", + "submittedTime": 1717789986704, + "swapAndSendRecipient": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "swapTokenValue": "0.05", + "time": 1717789986319, + "txParams": { + "data": "0x048226a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c1883800000000000000000000000000000000000000000000000000000000000000000000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d00000000000000000000000000000000000000000000000000b014d4c6ae2800000000000000000000000000000000000000000000000001ca9e03628c802fdb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000018de76816d80000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000128c43c9ef6000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000b014d4c6ae2800000000000000000000000000000000000000000000000001ca9e03628c802fdb00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000008ac76a51cc950d9822d68b83fe1ad97b32cd580d869584cd00000000000000000000000011ededebf63bef0ea2d2d071bdf88f71543ec6fb000000000000000000000000000000003736a41146b8f4bb97dbe80a5771808c000000000000000000000000000000000000000000000000", + "from": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "gas": "0x397cf", + "gasLimit": "0x397cf", + "maxFeePerGas": "0xb2d05e00", + "maxPriorityFeePerGas": "0xb2d05e00", + "nonce": "0x0", + "to": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "type": "0x2", + "value": "0xb1a2bc2ec50000" + }, + "txReceipt": { + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "contractAddress": null, + "cumulativeGasUsed": "0x2644bd", + "effectiveGasPrice": "0xb2d05e00", + "from": "0x141d32a89a1e0a5ef360034a2f60a4b917c18838", + "gasUsed": "0x31a28", + "logs": [ + { + "address": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x00000000000000000000000000000000000000000000000000b014d4c6ae2800", + "logIndex": "0x38", + "removed": false, + "topics": [ + "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x00000000000000000000000000000000000000000000000000b014d4c6ae2800", + "logIndex": "0x39", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff", + "0x000000000000000000000000d99c7f6c65857ac913a8f880a4cb84032ab2fc5b" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x000000000000000000000000000000000000000000000001d3be028ce893dfbe", + "logIndex": "0x3a", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000d99c7f6c65857ac913a8f880a4cb84032ab2fc5b", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0xd99c7f6c65857ac913a8f880a4cb84032ab2fc5b", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x000000000000000000000000000000000000000000003ef046f04c7cafc1e5e20000000000000000000000000000000000000000000000179ff39de2fc5b390a", + "logIndex": "0x3b", + "removed": false, + "topics": [ + "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0xd99c7f6c65857ac913a8f880a4cb84032ab2fc5b", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b014d4c6ae2800000000000000000000000000000000000000000000000001d3be028ce893dfbe0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x3c", + "removed": false, + "topics": [ + "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822", + "0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x000000000000000000000000000000000000000000000001d3be028ce893dfbe", + "logIndex": "0x3d", + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000bd7607133b9620320e745b3e0b1af717f8ea5889", + "0x000000000000000000000000141d32a89a1e0a5ef360034a2f60a4b917c18838" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + }, + { + "address": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "blockHash": "0xdf447bf7f6018f3b30ddc7004f45d8d55f68434865a05598ce4c1fd774642590", + "blockNumber": "0x259650c", + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000045357415000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x3e", + "removed": false, + "topics": [ + "0x0c18aae526accb31b01cf9a15bdf435e70632ee31efc4c5c0752c4262ea45d2f" + ], + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e" + } + ], + "logsBloom": "0x00600000000000000000000080000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000010000012000000008000000200000000000000000000400008000000000400000000000000000000004000040000000000000000008000010000000000000000000000001000000000040008000040001000800080000004000000000000000000000000000004000000000000000000000000004024000000000000000000002000000000000040000000000000000000000001040000000000080000000000000005002000000000000000000000000000000400000000001000000", + "status": "0x1", + "to": "0x3cb693656622fc470f0bb07d3f5813f7889bf82e", + "transactionHash": "0x5b13c4573b31d93bfb564c4f8506448bba16908b6974a4c0494a40d9aa622de7", + "transactionIndex": "0x2e", + "type": "0x2" + }, + "type": "swapAndSend", + "userEditedGasLimit": false, + "userFeeLevel": "medium", + "v": "0x1", + "verifiedOnBlockchain": true + }, + "hasRetried": false, + "hasCancelled": false } ] diff --git a/test/e2e/.mocharc.js b/test/e2e/.mocharc.js index 3513eaa0efdd..77eccc7deb25 100644 --- a/test/e2e/.mocharc.js +++ b/test/e2e/.mocharc.js @@ -1,5 +1,8 @@ // This file exists to add mocha configuration options specific to our // E2E Test suite. module.exports = { - require: ['test/e2e/e2e-mocha-setup.js'], + // Registers tsx so that we may use the same TypeScript features in + // E2E tests that we use elsewhere in our code. + require: ['tsx/esm'], + 'node-option': ['import=tsx'], }; diff --git a/test/e2e/accounts/account-custom-name.spec.ts b/test/e2e/accounts/account-custom-name.spec.ts new file mode 100644 index 000000000000..cdab01cfe826 --- /dev/null +++ b/test/e2e/accounts/account-custom-name.spec.ts @@ -0,0 +1,89 @@ +import { Suite } from 'mocha'; +import { + unlockWallet, + withFixtures, + locateAccountBalanceDOM, + findAnotherAccountFromAccountList, +} from '../helpers'; +import FixtureBuilder from '../fixture-builder'; +import { Driver } from '../webdriver/driver'; + +const newAccountLabel = 'Custom name'; +const anotherAccountLabel = '2nd custom name'; + +describe('Account Custom Name Persistence', function (this: Suite) { + it('persists custom account label through account change and wallet lock', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + await unlockWallet(driver); + // Change account label for existing account + await driver.clickElement( + '[data-testid="account-options-menu-button"]', + ); + await driver.clickElement('[data-testid="account-list-menu-details"]'); + await driver.clickElement('[data-testid="editable-label-button"]'); + await driver.fill('input[placeholder="Account name"]', newAccountLabel); + await driver.clickElement('[data-testid="save-account-label-input"]'); + await driver.clickElement('button[aria-label="Close"]'); + + // Verify account label + await driver.findElement({ + css: '[data-testid="account-menu-icon"]', + text: newAccountLabel, + }); + + // Add new account with custom label + await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-add-account"]', + ); + await driver.fill('[placeholder="Account 2"]', anotherAccountLabel); + await driver.clickElement({ text: 'Create', tag: 'button' }); + await locateAccountBalanceDOM(driver); + + // Verify initial custom account label after freshly added account was active + const accountOneSelector = await findAnotherAccountFromAccountList( + driver, + 1, + newAccountLabel, + ); + await driver.clickElement(accountOneSelector); + await driver.findElement({ + css: '[data-testid="account-menu-icon"]', + text: newAccountLabel, + }); + + // Lock and unlock wallet + await driver.waitForSelector( + '[data-testid="account-options-menu-button"]', + ); + await driver.clickElement( + '[data-testid="account-options-menu-button"]', + ); + await driver.clickElement({ + text: 'Lock MetaMask', + tag: 'div', + }); + await unlockWallet(driver); + + // Verify both account labels persist after unlock + await driver.findElement({ + css: '[data-testid="account-menu-icon"]', + text: newAccountLabel, + }); + await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.findElement({ + css: `.multichain-account-list-item__account-name__button`, + text: anotherAccountLabel, + }); + }, + ); + }); +}); diff --git a/test/e2e/accounts/common.ts b/test/e2e/accounts/common.ts index c8b448dd1b58..f4039d6b6533 100644 --- a/test/e2e/accounts/common.ts +++ b/test/e2e/accounts/common.ts @@ -10,6 +10,7 @@ import { validateContractDetails, multipleGanacheOptions, regularDelayMs, + openDapp, } from '../helpers'; import { Driver } from '../webdriver/driver'; import { TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL } from '../constants'; @@ -52,6 +53,7 @@ export async function installSnapSimpleKeyring( // navigate to test Snaps page and connect await driver.openNewPage(TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL); + await driver.clickElement('#connectButton'); await driver.delay(500); @@ -65,14 +67,14 @@ export async function installSnapSimpleKeyring( tag: 'button', }); - await driver.findElement({ text: 'Installation request', tag: 'h2' }); + await driver.findElement({ text: 'Add to MetaMask', tag: 'h3' }); await driver.clickElementSafe('[data-testid="snap-install-scroll"]', 200); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -182,7 +184,20 @@ async function switchToAccount2(driver: Driver) { } export async function connectAccountToTestDapp(driver: Driver) { - await switchToOrOpenDapp(driver); + try { + // Do an unusually fast switchToWindowWithTitle, just 1 second + await driver.switchToWindowWithTitle( + WINDOW_TITLES.TestDApp, + null, + 1000, + 1000, + ); + } catch { + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + await openDapp(driver); + } await driver.clickElement('#connectButton'); await driver.delay(regularDelayMs); @@ -193,7 +208,7 @@ export async function connectAccountToTestDapp(driver: Driver) { css: '[data-testid="page-container-footer-next"]', }); await driver.clickElement({ - text: 'Connect', + text: 'Confirm', tag: 'button', css: '[data-testid="page-container-footer-next"]', }); @@ -202,9 +217,18 @@ export async function connectAccountToTestDapp(driver: Driver) { export async function disconnectFromTestDapp(driver: Driver) { await driver.switchToWindowWithTitle(WINDOW_TITLES.ExtensionInFullScreenView); await driver.clickElement('[data-testid="account-options-menu-button"]'); - await driver.clickElement('[data-testid="global-menu-connected-sites"]'); - await driver.clickElement({ text: 'Disconnect', tag: 'a' }); + await driver.clickElement({ text: 'All Permissions', tag: 'div' }); + await driver.clickElementAndWaitToDisappear({ + text: 'Got it', + tag: 'button', + }); + await driver.clickElement({ + text: '127.0.0.1:8080', + tag: 'p', + }); + await driver.clickElement('[data-testid="account-list-item-menu-button"]'); await driver.clickElement({ text: 'Disconnect', tag: 'button' }); + await driver.clickElement('[data-testid ="disconnect-all"]'); } export async function approveOrRejectRequest(driver: Driver, flowType: string) { @@ -223,7 +247,7 @@ export async function approveOrRejectRequest(driver: Driver, flowType: string) { // get the JSON from the screen const requestJSON = await ( await driver.findElement({ - text: '"scope": "",', + text: '"scope":', tag: 'div', }) ).getText(); @@ -293,7 +317,7 @@ export async function signData( await validateContractDetails(driver); } - await clickSignOnSignatureConfirmation(driver, 3, locatorID); + await clickSignOnSignatureConfirmation({ driver, locatorID }); if (isAsyncFlow) { await driver.delay(2000); diff --git a/test/e2e/accounts/create-snap-account.spec.ts b/test/e2e/accounts/create-snap-account.spec.ts index dce3735a226f..ab34ac0046c0 100644 --- a/test/e2e/accounts/create-snap-account.spec.ts +++ b/test/e2e/accounts/create-snap-account.spec.ts @@ -33,12 +33,13 @@ describe('Create Snap Account', function (this: Suite) { }); // scroll to the bottom of the page + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); // click the install button to install the snap - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); await driver.waitForSelector({ text: 'OK' }); @@ -111,12 +112,13 @@ describe('Create Snap Account', function (this: Suite) { }); // scroll to the bottom of the page + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); // click the install button to install the snap - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); await driver.waitForSelector({ text: 'OK' }); @@ -202,12 +204,13 @@ describe('Create Snap Account', function (this: Suite) { }); // scroll to the bottom of the page + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); // click the install button to install the snap - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); await driver.waitForSelector({ text: 'OK' }); diff --git a/test/e2e/accounts/remove-account-snap.spec.ts b/test/e2e/accounts/remove-account-snap.spec.ts index 51039f69d573..f4b8e025c62d 100644 --- a/test/e2e/accounts/remove-account-snap.spec.ts +++ b/test/e2e/accounts/remove-account-snap.spec.ts @@ -1,3 +1,4 @@ +import { strict as assert } from 'assert'; import { Suite } from 'mocha'; import FixtureBuilder from '../fixture-builder'; import { WINDOW_TITLES, defaultGanacheOptions, withFixtures } from '../helpers'; @@ -17,6 +18,13 @@ describe('Remove Account Snap', function (this: Suite) { await makeNewAccountAndSwitch(driver); + // Check accounts after adding the snap account. + await driver.clickElement('[data-testid="account-menu-icon"]'); + const accountMenuItemsWithSnapAdded = await driver.findElements( + '.multichain-account-list-item', + ); + await driver.clickElement('.mm-box button[aria-label="Close"]'); + // Navigate to settings. await driver.switchToWindowWithTitle( WINDOW_TITLES.ExtensionInFullScreenView, @@ -69,6 +77,17 @@ describe('Remove Account Snap', function (this: Suite) { text: "You don't have any snaps installed.", tag: 'p', }); + await driver.clickElement('.mm-box button[aria-label="Close"]'); + + // Assert that an account was removed. + await driver.clickElement('[data-testid="account-menu-icon"]'); + const accountMenuItemsAfterRemoval = await driver.findElements( + '.multichain-account-list-item', + ); + assert.equal( + accountMenuItemsAfterRemoval.length, + accountMenuItemsWithSnapAdded.length - 1, + ); }, ); }); diff --git a/test/e2e/accounts/snap-account-transfers.spec.ts b/test/e2e/accounts/snap-account-transfers.spec.ts index cc5949bf14c4..cb344e188640 100644 --- a/test/e2e/accounts/snap-account-transfers.spec.ts +++ b/test/e2e/accounts/snap-account-transfers.spec.ts @@ -1,5 +1,10 @@ import { Suite } from 'mocha'; -import { sendTransaction, withFixtures, WINDOW_TITLES } from '../helpers'; +import { + sendTransaction, + withFixtures, + WINDOW_TITLES, + clickNestedButton, +} from '../helpers'; import { Driver } from '../webdriver/driver'; import { accountSnapFixtures, @@ -53,11 +58,6 @@ describe('Snap Account Transfers', function (this: Suite) { // send 1 ETH from Account 2 to Account 1 await sendTransaction(driver, PUBLIC_KEY, 1, isAsyncFlow); - // TODO: Update Test when Multichain Send Flow is added - if (process.env.MULTICHAIN) { - return; - } - if (isAsyncFlow) { await driver.assertElementNotPresent({ text: 'Please complete the transaction on the Snap.', @@ -66,7 +66,7 @@ describe('Snap Account Transfers', function (this: Suite) { WINDOW_TITLES.ExtensionInFullScreenView, ); await driver.navigate(); - await driver.delay(1000); + await driver.delay(2000); await driver.clickElement({ text: 'Go to site', tag: 'button', @@ -85,7 +85,7 @@ describe('Snap Account Transfers', function (this: Suite) { await driver.findElement('[title="24 ETH"]'); } else if (flowType === 'reject') { // ensure the transaction was rejected by the Snap - await driver.clickElement({ text: 'Activity', tag: 'button' }); + await clickNestedButton(driver, 'Activity'); await driver.findElement( '[data-original-title="Request rejected by user or snap."]', ); diff --git a/test/e2e/api-specs/ConfirmationRejectionRule.ts b/test/e2e/api-specs/ConfirmationRejectionRule.ts new file mode 100644 index 000000000000..9a8348357a69 --- /dev/null +++ b/test/e2e/api-specs/ConfirmationRejectionRule.ts @@ -0,0 +1,224 @@ +import Rule from '@open-rpc/test-coverage/build/rules/rule'; +import { Call } from '@open-rpc/test-coverage/build/coverage'; +import { + ContentDescriptorObject, + ExampleObject, + ExamplePairingObject, + MethodObject, +} from '@open-rpc/meta-schema'; +import paramsToObj from '@open-rpc/test-coverage/build/utils/params-to-obj'; +import { Driver } from '../webdriver/driver'; +import { WINDOW_TITLES, switchToOrOpenDapp } from '../helpers'; +import { addToQueue } from './helpers'; + +type ConfirmationsRejectRuleOptions = { + driver: Driver; + only: string[]; +}; +// this rule makes sure that all confirmation requests are rejected. +// it also validates that the JSON-RPC response is an error with +// error code 4001 (user rejected request) +export class ConfirmationsRejectRule implements Rule { + private driver: Driver; + + private only: string[]; + + private rejectButtonInsteadOfCancel: string[]; + + private requiresEthAccountsPermission: string[]; + + constructor(options: ConfirmationsRejectRuleOptions) { + this.driver = options.driver; + this.only = options.only; + this.rejectButtonInsteadOfCancel = [ + 'personal_sign', + 'eth_signTypedData_v4', + ]; + this.requiresEthAccountsPermission = [ + 'personal_sign', + 'eth_signTypedData_v4', + 'eth_getEncryptionPublicKey', + ]; + } + + getTitle() { + return 'Confirmations Rejection Rule'; + } + + async beforeRequest(_: unknown, call: Call) { + await new Promise((resolve, reject) => { + addToQueue({ + name: 'beforeRequest', + resolve, + reject, + task: async () => { + try { + if (this.requiresEthAccountsPermission.includes(call.methodName)) { + const requestPermissionsRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'wallet_requestPermissions', + params: [{ eth_accounts: {} }], + }); + + await this.driver.executeScript( + `window.ethereum.request(${requestPermissionsRequest})`, + ); + const screenshot = await this.driver.driver.takeScreenshot(); + call.attachments = call.attachments || []; + call.attachments.push({ + type: 'image', + data: `data:image/png;base64,${screenshot}`, + }); + + await this.driver.waitUntilXWindowHandles(3); + await this.driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + + await this.driver.findClickableElements({ + text: 'Next', + tag: 'button', + }); + + const screenshotTwo = await this.driver.driver.takeScreenshot(); + call.attachments.push({ + type: 'image', + data: `data:image/png;base64,${screenshotTwo}`, + }); + + await this.driver.clickElement({ + text: 'Next', + tag: 'button', + }); + + await this.driver.clickElement({ + text: 'Confirm', + tag: 'button', + }); + + await switchToOrOpenDapp(this.driver); + } + } catch (e) { + console.log(e); + } + }, + }); + }); + } + + async afterRequest(_: unknown, call: Call) { + await new Promise((resolve, reject) => { + addToQueue({ + name: 'afterRequest', + resolve, + reject, + task: async () => { + try { + await this.driver.waitUntilXWindowHandles(3); + await this.driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + + let text = 'Cancel'; + if (this.rejectButtonInsteadOfCancel.includes(call.methodName)) { + await this.driver.findClickableElements({ + text: 'Reject', + tag: 'button', + }); + text = 'Reject'; + } else { + await this.driver.findClickableElements({ + text: 'Cancel', + tag: 'button', + }); + } + const screenshot = await this.driver.driver.takeScreenshot(); + call.attachments = call.attachments || []; + call.attachments.push({ + type: 'image', + data: `data:image/png;base64,${screenshot}`, + }); + await this.driver.clickElement({ text, tag: 'button' }); + // make sure to switch back to the dapp or else the next test will fail on the wrong window + await switchToOrOpenDapp(this.driver); + } catch (e) { + console.log(e); + } + }, + }); + }); + } + + // get all the confirmation calls to make and expect to pass + getCalls(_: unknown, method: MethodObject) { + const calls: Call[] = []; + const isMethodAllowed = this.only ? this.only.includes(method.name) : true; + if (isMethodAllowed) { + if (method.examples) { + // pull the first example + const e = method.examples[0]; + const ex = e as ExamplePairingObject; + + if (!ex.result) { + return calls; + } + const p = ex.params.map((_e) => (_e as ExampleObject).value); + const params = + method.paramStructure === 'by-name' + ? paramsToObj(p, method.params as ContentDescriptorObject[]) + : p; + calls.push({ + title: `${this.getTitle()} - with example ${ex.name}`, + methodName: method.name, + params, + url: '', + resultSchema: (method.result as ContentDescriptorObject).schema, + expectedResult: (ex.result as ExampleObject).value, + }); + } else { + // naively call the method with no params + calls.push({ + title: `${method.name} > confirmation rejection`, + methodName: method.name, + params: [], + url: '', + resultSchema: (method.result as ContentDescriptorObject).schema, + }); + } + } + return calls; + } + + async afterResponse(_: unknown, call: Call) { + await new Promise((resolve, reject) => { + addToQueue({ + name: 'afterResponse', + resolve, + reject, + task: async () => { + try { + if (this.requiresEthAccountsPermission.includes(call.methodName)) { + const revokePermissionsRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'wallet_revokePermissions', + params: [{ eth_accounts: {} }], + }); + + await this.driver.executeScript( + `window.ethereum.request(${revokePermissionsRequest})`, + ); + } + } catch (e) { + console.log(e); + } + }, + }); + }); + } + + validateCall(call: Call) { + if (call.error) { + call.valid = call.error.code === 4001; + if (!call.valid) { + call.reason = `Expected error code 4001, got ${call.error.code}`; + } + } + return call; + } +} diff --git a/test/e2e/api-specs/helpers.ts b/test/e2e/api-specs/helpers.ts new file mode 100644 index 000000000000..d4f4d3be22c5 --- /dev/null +++ b/test/e2e/api-specs/helpers.ts @@ -0,0 +1,135 @@ +import { v4 as uuid } from 'uuid'; +import { ErrorObject } from '@open-rpc/meta-schema'; +import { Driver } from '../webdriver/driver'; + +// eslint-disable-next-line @typescript-eslint/no-shadow, @typescript-eslint/no-explicit-any +declare let window: any; + +type QueueItem = { + task: () => Promise; + resolve: (value: unknown) => void; + reject: (reason?: unknown) => void; + name: string; +}; + +export const taskQueue: QueueItem[] = []; +let isProcessing = false; + +export const processQueue = async () => { + if (isProcessing || taskQueue.length === 0) { + return; + } + + isProcessing = true; + const item = taskQueue.shift(); + if (!item) { + return; + } + const { task, resolve, reject }: QueueItem | undefined = item; + try { + const result = await task(); + resolve(result); + } catch (error) { + reject(error); + } finally { + isProcessing = false; + await processQueue(); + } +}; + +export const addToQueue = ({ task, resolve, reject, name }: QueueItem) => { + taskQueue.push({ task, resolve, reject, name }); + return processQueue(); +}; + +export const pollForResult = async ( + driver: Driver, + generatedKey: string, +): Promise => { + let result; + // eslint-disable-next-line no-loop-func + await new Promise((resolve, reject) => { + addToQueue({ + name: 'pollResult', + resolve, + reject, + task: async () => { + result = await driver.executeScript( + `return window['${generatedKey}'];`, + ); + + while (result === null) { + // Continue polling if result is not set + await driver.delay(500); + result = await driver.executeScript( + `return window['${generatedKey}'];`, + ); + } + + // clear the result + await driver.executeScript(`delete window['${generatedKey}'];`); + + return result; + }, + }); + }); + if (result !== undefined) { + return result; + } + return pollForResult(driver, generatedKey); +}; + +export const createDriverTransport = (driver: Driver) => { + return async ( + _: string, + method: string, + params: unknown[] | Record, + ) => { + const generatedKey = uuid(); + return new Promise((resolve, reject) => { + const execute = async () => { + await addToQueue({ + name: 'transport', + resolve, + reject, + task: async () => { + // don't wait for executeScript to finish window.ethereum promise + // we need this because if we wait for the promise to resolve it + // will hang in selenium since it can only do one thing at a time. + // the workaround is to put the response on window.asyncResult and poll for it. + driver.executeScript( + ([m, p, g]: [ + string, + unknown[] | Record, + string, + ]) => { + window[g] = null; + window.ethereum + .request({ method: m, params: p }) + .then((r: unknown) => { + window[g] = { result: r }; + }) + .catch((e: ErrorObject) => { + window[g] = { + error: { + code: e.code, + message: e.message, + data: e.data, + }, + }; + }); + }, + method, + params, + generatedKey, + ); + }, + }); + }; + return execute(); + }).then(async () => { + const response = await pollForResult(driver, generatedKey); + return response; + }); + }; +}; diff --git a/test/e2e/default-fixture.js b/test/e2e/default-fixture.js new file mode 100644 index 000000000000..1ffe75134970 --- /dev/null +++ b/test/e2e/default-fixture.js @@ -0,0 +1,270 @@ +const { NetworkStatus } = require('@metamask/network-controller'); +const { CHAIN_IDS } = require('../../shared/constants/network'); +const { FirstTimeFlowType } = require('../../shared/constants/onboarding'); + +const FIXTURE_STATE_METADATA_VERSION = 74; + +const E2E_SRP = + 'spread raise short crane omit tent fringe mandate neglect detail suspect cradle'; + +function defaultFixture(inputChainId = CHAIN_IDS.LOCALHOST) { + return { + data: { + AuthenticationController: { + isSignedIn: true, + }, + UserStorageController: { + isProfileSyncingEnabled: true, + }, + MetamaskNotificationsController: { + subscriptionAccountsSeen: [], + isFeatureAnnouncementsEnabled: false, + isMetamaskNotificationsEnabled: false, + isMetamaskNotificationsFeatureSeen: false, + metamaskNotificationsList: [], + metamaskNotificationsReadList: [], + }, + AccountsController: { + internalAccounts: { + selectedAccount: 'd5e45e4a-3b04-4a09-a5e1-39762e5c6be4', + accounts: { + 'd5e45e4a-3b04-4a09-a5e1-39762e5c6be4': { + id: 'd5e45e4a-3b04-4a09-a5e1-39762e5c6be4', + address: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', + metadata: { + name: 'Account 1', + lastSelected: 1665507600000, + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [ + 'personal_sign', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + }, + }, + AlertController: { + alertEnabledness: { + unconnectedAccount: true, + web3ShimUsage: true, + }, + unconnectedAccountAlertShownOrigins: {}, + web3ShimUsageOrigins: {}, + }, + AnnouncementController: { + announcements: { + 8: { + date: '2021-11-01', + id: 8, + isShown: false, + }, + }, + }, + NetworkOrderController: { + orderedNetworkList: [ + { + networkId: '0x1', + networkRpcUrl: + 'https://mainnet.infura.io/v3/00000000000000000000000000000000', + }, + { + networkId: '0xe708', + networkRpcUrl: + 'https://linea-mainnet.infura.io/v3/00000000000000000000000000000000', + }, + { + networkId: '0x539', + networkRpcUrl: 'http://localhost:8545', + }, + ], + }, + AccountOrderController: { + pinnedAccountList: [], + hiddenAccountList: [], + }, + AppStateController: { + browserEnvironment: {}, + nftsDropdownState: {}, + connectedStatusPopoverHasBeenShown: true, + termsOfUseLastAgreed: + '__FIXTURE_SUBSTITUTION__currentDateInMilliseconds', + defaultHomeActiveTabName: null, + fullScreenGasPollTokens: [], + notificationGasPollTokens: [], + popupGasPollTokens: [], + qrHardware: {}, + recoveryPhraseReminderHasBeenShown: true, + recoveryPhraseReminderLastShown: + '__FIXTURE_SUBSTITUTION__currentDateInMilliseconds', + showTestnetMessageInDropdown: true, + trezorModel: null, + newPrivacyPolicyToastClickedOrClosed: true, + newPrivacyPolicyToastShownDate: Date.now(), + usedNetworks: { + [CHAIN_IDS.MAINNET]: true, + [CHAIN_IDS.LINEA_MAINNET]: true, + [CHAIN_IDS.GOERLI]: true, + [CHAIN_IDS.LOCALHOST]: true, + }, + snapsInstallPrivacyWarningShown: true, + }, + CurrencyController: { + currentCurrency: 'usd', + currencyRates: { + ETH: { + conversionDate: 1665507600.0, + conversionRate: 1700.0, + usdConversionRate: 1700.0, + }, + }, + }, + GasFeeController: { + estimatedGasFeeTimeBounds: {}, + gasEstimateType: 'none', + gasFeeEstimates: {}, + }, + KeyringController: { + vault: + '{"data":"WHaP1FrrtV4zUonudIppDifsLHF39g6oPkVksAIdWAHBRzax1uy1asfAJprR7u72t4/HuYz5yPIFQrnNnv+hwQu9GRuty88VKMnvMy+sq8MNtoXI+C54bZpWa8r4iUQfa0Mj/cfJbpFpzOdF1ZYXahTfTcU5WsrHwvJew842CiJR4B2jmCHHXfm/DxLK3WazsVQwXJGx/U71UelGoOOrT8NI28EKrAwgPn+7Xmv0j92gmhau30N7Bo2fr6Zv","iv":"LfD8/tY1EjXzxuemSmDVdA==","keyMetadata":{"algorithm":"PBKDF2","params":{"iterations":600000}},"salt":"nk4xdpmMR+1s5BYe4Vnk++XAQwrISI2bCtbMg7V1wUA="}', + }, + MetaMetricsController: { + eventsBeforeMetricsOptIn: [], + fragments: {}, + metaMetricsId: null, + participateInMetaMetrics: false, + dataCollectionForMarketing: false, + traits: {}, + }, + NetworkController: { + selectedNetworkClientId: 'networkConfigurationId', + networksMetadata: { + networkConfigurationId: { + EIPS: {}, + status: NetworkStatus.Available, + }, + }, + providerConfig: { + chainId: inputChainId, + nickname: 'Localhost 8545', + rpcPrefs: {}, + rpcUrl: 'http://localhost:8545', + ticker: 'ETH', + type: 'rpc', + id: 'networkConfigurationId', + }, + networkConfigurations: { + networkConfigurationId: { + chainId: inputChainId, + nickname: 'Localhost 8545', + rpcPrefs: {}, + rpcUrl: 'http://localhost:8545', + ticker: 'ETH', + networkConfigurationId: 'networkConfigurationId', + }, + }, + }, + OnboardingController: { + completedOnboarding: true, + firstTimeFlowType: FirstTimeFlowType.import, + onboardingTabs: {}, + seedPhraseBackedUp: true, + }, + PermissionController: { + subjects: {}, + }, + PreferencesController: { + advancedGasFee: null, + currentLocale: 'en', + useExternalServices: true, + dismissSeedBackUpReminder: true, + featureFlags: {}, + forgottenPassword: false, + identities: { + '0x5cfe73b6021e818b776b421b1c4db2474086a7e1': { + address: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', + lastSelected: 1665507600000, + name: 'Account 1', + }, + }, + ipfsGateway: 'dweb.link', + knownMethodData: {}, + ledgerTransportType: 'webhid', + lostIdentities: {}, + openSeaEnabled: false, + preferences: { + hideZeroBalanceTokens: false, + showExtensionInFullSizeView: false, + showFiatInTestnets: false, + showTestNetworks: false, + smartTransactionsOptInStatus: false, + useNativeCurrencyAsPrimaryCurrency: true, + petnamesEnabled: true, + showTokenAutodetectModal: false, + }, + selectedAddress: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', + theme: 'light', + useBlockie: false, + useNftDetection: false, + useNonceField: false, + usePhishDetect: true, + useTokenDetection: false, + useCurrencyRateCheck: true, + useMultiAccountBalanceChecker: true, + useRequestQueue: true, + }, + QueuedRequestController: { + queuedRequestCount: 0, + }, + SelectedNetworkController: { + domains: {}, + }, + SmartTransactionsController: { + smartTransactionsState: { + fees: {}, + liveness: true, + smartTransactions: { + [CHAIN_IDS.MAINNET]: [], + }, + }, + }, + SubjectMetadataController: { + subjectMetadata: { + 'https://metamask.github.io': { + extensionId: null, + iconUrl: null, + name: 'MetaMask < = > Ledger Bridge', + origin: 'https://metamask.github.io', + subjectType: 'website', + }, + }, + }, + TokensController: { + allDetectedTokens: {}, + allIgnoredTokens: {}, + allTokens: {}, + detectedTokens: [], + ignoredTokens: [], + tokens: [], + }, + TransactionController: { + transactions: {}, + }, + config: {}, + firstTimeInfo: { + date: 1665507600000, + version: '10.21.0', + }, + }, + }; +} + +module.exports = { defaultFixture, FIXTURE_STATE_METADATA_VERSION, E2E_SRP }; diff --git a/test/e2e/e2e-mocha-setup.js b/test/e2e/e2e-mocha-setup.js deleted file mode 100644 index 26965006ece5..000000000000 --- a/test/e2e/e2e-mocha-setup.js +++ /dev/null @@ -1,5 +0,0 @@ -// This file simply registers babel and ts-node so that we may use the same -// ECMAScript features in E2E tests that we use elsewhere in our code. It also -// allows values to be read from TypeScript files. -require('@babel/register'); -require('ts-node/register'); diff --git a/test/e2e/fixture-builder.js b/test/e2e/fixture-builder.js index c8ef4ed8f162..7bc15af41969 100644 --- a/test/e2e/fixture-builder.js +++ b/test/e2e/fixture-builder.js @@ -5,232 +5,15 @@ const { const { merge } = require('lodash'); const { toHex } = require('@metamask/controller-utils'); const { NetworkStatus } = require('@metamask/network-controller'); + const { CHAIN_IDS, NETWORK_TYPES } = require('../../shared/constants/network'); const { SMART_CONTRACTS } = require('./seeder/smart-contracts'); const { DAPP_URL, DAPP_ONE_URL } = require('./helpers'); const { DEFAULT_FIXTURE_ACCOUNT, ERC_4337_ACCOUNT } = require('./constants'); - -function defaultFixture(inputChainId = CHAIN_IDS.LOCALHOST) { - return { - data: { - AccountsController: { - internalAccounts: { - selectedAccount: 'd5e45e4a-3b04-4a09-a5e1-39762e5c6be4', - accounts: { - 'd5e45e4a-3b04-4a09-a5e1-39762e5c6be4': { - id: 'd5e45e4a-3b04-4a09-a5e1-39762e5c6be4', - address: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', - metadata: { - name: 'Account 1', - lastSelected: 1665507600000, - keyring: { - type: 'HD Key Tree', - }, - }, - options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', - }, - }, - }, - }, - AlertController: { - alertEnabledness: { - unconnectedAccount: true, - web3ShimUsage: true, - }, - unconnectedAccountAlertShownOrigins: {}, - web3ShimUsageOrigins: {}, - }, - AnnouncementController: { - announcements: { - 8: { - date: '2021-11-01', - id: 8, - isShown: false, - }, - }, - }, - NetworkOrderController: { - orderedNetworkList: [], - }, - AccountOrderController: { - pinnedAccountList: [], - hiddenAccountList: [], - }, - AppStateController: { - browserEnvironment: {}, - nftsDropdownState: {}, - connectedStatusPopoverHasBeenShown: true, - termsOfUseLastAgreed: - '__FIXTURE_SUBSTITUTION__currentDateInMilliseconds', - defaultHomeActiveTabName: null, - fullScreenGasPollTokens: [], - notificationGasPollTokens: [], - popupGasPollTokens: [], - qrHardware: {}, - recoveryPhraseReminderHasBeenShown: true, - recoveryPhraseReminderLastShown: - '__FIXTURE_SUBSTITUTION__currentDateInMilliseconds', - showTestnetMessageInDropdown: true, - trezorModel: null, - usedNetworks: { - [CHAIN_IDS.MAINNET]: true, - [CHAIN_IDS.LINEA_MAINNET]: true, - [CHAIN_IDS.GOERLI]: true, - [CHAIN_IDS.LOCALHOST]: true, - }, - snapsInstallPrivacyWarningShown: true, - }, - CurrencyController: { - currentCurrency: 'usd', - currencyRates: { - ETH: { - conversionDate: 1665507600.0, - conversionRate: 1300.0, - usdConversionRate: 1300.0, - }, - }, - }, - GasFeeController: { - estimatedGasFeeTimeBounds: {}, - gasEstimateType: 'none', - gasFeeEstimates: {}, - }, - KeyringController: { - vault: - '{"data":"WHaP1FrrtV4zUonudIppDifsLHF39g6oPkVksAIdWAHBRzax1uy1asfAJprR7u72t4/HuYz5yPIFQrnNnv+hwQu9GRuty88VKMnvMy+sq8MNtoXI+C54bZpWa8r4iUQfa0Mj/cfJbpFpzOdF1ZYXahTfTcU5WsrHwvJew842CiJR4B2jmCHHXfm/DxLK3WazsVQwXJGx/U71UelGoOOrT8NI28EKrAwgPn+7Xmv0j92gmhau30N7Bo2fr6Zv","iv":"LfD8/tY1EjXzxuemSmDVdA==","keyMetadata":{"algorithm":"PBKDF2","params":{"iterations":600000}},"salt":"nk4xdpmMR+1s5BYe4Vnk++XAQwrISI2bCtbMg7V1wUA="}', - }, - MetaMetricsController: { - eventsBeforeMetricsOptIn: [], - fragments: {}, - metaMetricsId: null, - participateInMetaMetrics: false, - traits: {}, - }, - NetworkController: { - selectedNetworkClientId: 'networkConfigurationId', - networksMetadata: { - networkConfigurationId: { - EIPS: {}, - status: NetworkStatus.Available, - }, - }, - providerConfig: { - chainId: inputChainId, - nickname: 'Localhost 8545', - rpcPrefs: {}, - rpcUrl: 'http://localhost:8545', - ticker: 'ETH', - type: 'rpc', - id: 'networkConfigurationId', - }, - networkConfigurations: { - networkConfigurationId: { - chainId: inputChainId, - nickname: 'Localhost 8545', - rpcPrefs: {}, - rpcUrl: 'http://localhost:8545', - ticker: 'ETH', - networkConfigurationId: 'networkConfigurationId', - }, - }, - }, - OnboardingController: { - completedOnboarding: true, - firstTimeFlowType: 'import', - onboardingTabs: {}, - seedPhraseBackedUp: true, - }, - PermissionController: { - subjects: {}, - }, - PreferencesController: { - advancedGasFee: null, - currentLocale: 'en', - dismissSeedBackUpReminder: true, - featureFlags: {}, - forgottenPassword: false, - identities: { - '0x5cfe73b6021e818b776b421b1c4db2474086a7e1': { - address: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', - lastSelected: 1665507600000, - name: 'Account 1', - }, - }, - ipfsGateway: 'dweb.link', - knownMethodData: {}, - ledgerTransportType: 'webhid', - lostIdentities: {}, - openSeaEnabled: false, - preferences: { - hideZeroBalanceTokens: false, - showExtensionInFullSizeView: false, - showFiatInTestnets: false, - showTestNetworks: false, - useNativeCurrencyAsPrimaryCurrency: true, - petnamesEnabled: true, - }, - selectedAddress: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', - theme: 'light', - useBlockie: false, - useNftDetection: false, - useNonceField: false, - usePhishDetect: true, - useTokenDetection: false, - useCurrencyRateCheck: true, - useMultiAccountBalanceChecker: true, - useRequestQueue: false, - }, - SelectedNetworkController: { - domains: {}, - }, - SmartTransactionsController: { - smartTransactionsState: { - fees: {}, - liveness: true, - smartTransactions: { - [CHAIN_IDS.MAINNET]: [], - }, - }, - }, - SubjectMetadataController: { - subjectMetadata: { - 'https://metamask.github.io': { - extensionId: null, - iconUrl: null, - name: 'MetaMask < = > Ledger Bridge', - origin: 'https://metamask.github.io', - subjectType: 'website', - }, - }, - }, - TokensController: { - allDetectedTokens: {}, - allIgnoredTokens: {}, - allTokens: {}, - detectedTokens: [], - ignoredTokens: [], - tokens: [], - }, - TransactionController: { - transactions: {}, - }, - config: {}, - firstTimeInfo: { - date: 1665507600000, - version: '10.21.0', - }, - }, - }; -} +const { + defaultFixture, + FIXTURE_STATE_METADATA_VERSION, +} = require('./default-fixture'); function onboardingFixture() { return { @@ -301,9 +84,12 @@ function onboardingFixture() { showExtensionInFullSizeView: false, showFiatInTestnets: false, showTestNetworks: false, + smartTransactionsOptInStatus: false, useNativeCurrencyAsPrimaryCurrency: true, petnamesEnabled: true, + showTokenAutodetectModal: false, }, + useExternalServices: true, theme: 'light', useBlockie: false, useNftDetection: false, @@ -312,7 +98,10 @@ function onboardingFixture() { useTokenDetection: false, useCurrencyRateCheck: true, useMultiAccountBalanceChecker: true, - useRequestQueue: false, + useRequestQueue: true, + }, + QueuedRequestController: { + queuedRequestCount: 0, }, SelectedNetworkController: { domains: {}, @@ -344,6 +133,13 @@ function onboardingFixture() { } class FixtureBuilder { + /** + * Constructs a new instance of the FixtureBuilder class. + * + * @param {object} [options] - The options for the constructor. + * @param {boolean} [options.onboarding] - Indicates if onboarding is enabled. + * @param {string} [options.inputChainId] - The input chain ID. + */ constructor({ onboarding = false, inputChainId = CHAIN_IDS.LOCALHOST } = {}) { this.fixture = onboarding === true ? onboardingFixture() : defaultFixture(inputChainId); @@ -466,6 +262,23 @@ class FixtureBuilder { }); } + withNetworkControllerTripleGanache() { + this.withNetworkControllerDoubleGanache(); + merge(this.fixture.data.NetworkController, { + networkConfigurations: { + '243ad4c2-10a6-4621-9536-e3a67f4dd4c9': { + id: '243ad4c2-10a6-4621-9536-e3a67f4dd4c9', + rpcUrl: 'http://localhost:7777', + chainId: '0x3e8', + ticker: 'ETH', + nickname: 'Localhost 7777', + rpcPrefs: {}, + }, + }, + }); + return this; + } + withNftController(data) { merge( this.fixture.data.NftController @@ -720,6 +533,12 @@ class FixtureBuilder { }); } + withPreferencesControllerTxSimulationsDisabled() { + return this.withPreferencesController({ + useTransactionSimulations: false, + }); + } + withAccountsController(data) { merge(this.fixture.data.AccountsController, data); return this; @@ -873,9 +692,11 @@ class FixtureBuilder { } withPreferencesControllerUseRequestQueueEnabled() { - return this.withPreferencesController({ - useRequestQueue: true, - }); + return merge( + this.withPreferencesController({ + useRequestQueue: true, + }), + ); } withSmartTransactionsController(data) { @@ -903,6 +724,11 @@ class FixtureBuilder { return this; } + // withTokenRatesController(data) { + // merge(this.fixture.data.TokenRatesController, data); + // return this; + // } + withBadPreferencesControllerState() { merge(this.fixture.data, { PreferencesController: 5, @@ -918,7 +744,7 @@ class FixtureBuilder { symbol: 'TST', decimals: 4, image: - 'https://static.metafi.codefi.network/api/v1/tokenIcons/1337/0x581c3c1a2a4ebde2a0df29b5cf4c116e42945947.png', + 'https://static.cx.metamask.io/api/v1/tokenIcons/1337/0x581c3c1a2a4ebde2a0df29b5cf4c116e42945947.png', isERC721: false, aggregators: [], }, @@ -933,7 +759,7 @@ class FixtureBuilder { symbol: 'TST', decimals: 4, image: - 'https://static.metafi.codefi.network/api/v1/tokenIcons/1337/0x581c3c1a2a4ebde2a0df29b5cf4c116e42945947.png', + 'https://static.cx.metamask.io/api/v1/tokenIcons/1337/0x581c3c1a2a4ebde2a0df29b5cf4c116e42945947.png', isERC721: false, aggregators: [], }, @@ -997,8 +823,28 @@ class FixtureBuilder { timestamp: 1631545992244, value: false, }, + { + op: 'add', + path: '/simulationData', + value: { + error: { + code: 'disabled', + message: 'Simulation disabled', + }, + tokenBalanceChanges: [], + }, + note: 'TransactionController#updateSimulationData - Update simulation data', + timestamp: 1631545992244, + }, ], ], + simulationData: { + error: { + code: 'disabled', + message: 'Simulation disabled', + }, + tokenBalanceChanges: [], + }, id: '7087d1d7-f0e8-4c0f-a903-6d9daa392baf', loadingDefaults: false, origin: 'https://metamask.github.io', @@ -1052,8 +898,28 @@ class FixtureBuilder { timestamp: 1631545994695, value: false, }, + { + op: 'add', + path: '/simulationData', + value: { + error: { + code: 'disabled', + message: 'Simulation disabled', + }, + tokenBalanceChanges: [], + }, + note: 'TransactionController#updateSimulationData - Update simulation data', + timestamp: 1631545992244, + }, ], ], + simulationData: { + error: { + code: 'disabled', + message: 'Simulation disabled', + }, + tokenBalanceChanges: [], + }, id: '6eab4240-3762-4581-abc5-cd91eab6964e', loadingDefaults: false, origin: 'https://metamask.github.io', @@ -1107,8 +973,28 @@ class FixtureBuilder { timestamp: 1631545996678, value: false, }, + { + op: 'add', + path: '/simulationData', + value: { + error: { + code: 'disabled', + message: 'Simulation disabled', + }, + tokenBalanceChanges: [], + }, + note: 'TransactionController#updateSimulationData - Update simulation data', + timestamp: 1631545992244, + }, ], ], + simulationData: { + error: { + code: 'disabled', + message: 'Simulation disabled', + }, + tokenBalanceChanges: [], + }, id: 'c15eee26-11d6-4914-a70e-36ef9a3bcacb', loadingDefaults: false, origin: 'https://metamask.github.io', @@ -1162,8 +1048,28 @@ class FixtureBuilder { timestamp: 1631545998677, value: false, }, + { + op: 'add', + path: '/simulationData', + value: { + error: { + code: 'disabled', + message: 'Simulation disabled', + }, + tokenBalanceChanges: [], + }, + note: 'TransactionController#updateSimulationData - Update simulation data', + timestamp: 1631545992244, + }, ], ], + simulationData: { + error: { + code: 'disabled', + message: 'Simulation disabled', + }, + tokenBalanceChanges: [], + }, id: 'dfa9e5ad-d069-46b1-976e-a23734971d87', loadingDefaults: false, origin: 'https://metamask.github.io', @@ -1739,7 +1645,7 @@ class FixtureBuilder { build() { this.fixture.meta = { - version: 74, + version: FIXTURE_STATE_METADATA_VERSION, }; return this.fixture; } diff --git a/test/e2e/flask/user-operations.spec.ts b/test/e2e/flask/user-operations.spec.ts index 585501d14a2b..d84779ba79b6 100644 --- a/test/e2e/flask/user-operations.spec.ts +++ b/test/e2e/flask/user-operations.spec.ts @@ -1,13 +1,11 @@ -import { TransactionParams } from '@metamask/transaction-controller'; import { withFixtures, unlockWallet, - openDapp, switchToNotificationWindow, - DAPP_URL, WINDOW_TITLES, sendTransaction, convertETHToHexGwei, + createDappTransaction, } from '../helpers'; import FixtureBuilder from '../fixture-builder'; import { @@ -38,10 +36,10 @@ async function installExampleSnap(driver: Driver) { text: 'Connect', tag: 'button', }); - await driver.findElement({ text: 'Installation request', tag: 'h2' }); + await driver.findElement({ text: 'Add to MetaMask', tag: 'h3' }); await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); await driver.clickElement({ @@ -93,19 +91,6 @@ async function setSnapConfig( await driver.clickElement({ text: 'Set Chain Configs', tag: 'button' }); } -async function createDappTransaction( - driver: Driver, - transaction: TransactionParams, -) { - await openDapp( - driver, - null, - `${DAPP_URL}/request?method=eth_sendTransaction¶ms=${JSON.stringify([ - transaction, - ])}`, - ); -} - async function createSwap(driver: Driver) { await driver.switchToWindowWithTitle(WINDOW_TITLES.ExtensionInFullScreenView); await buildQuote(driver, { @@ -128,7 +113,7 @@ async function confirmTransaction(driver: Driver) { async function openConfirmedTransaction(driver: Driver) { await driver.switchToWindowWithTitle(WINDOW_TITLES.ExtensionInFullScreenView); - await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.clickElement('[data-testid="account-overview__activity-tab"]'); await driver.clickElement({ css: '[data-testid="activity-list-item"]', @@ -247,10 +232,6 @@ describe('User Operations', function () { }); it('from send transaction', async function (this: Mocha.Context) { - if (process.env.MULTICHAIN) { - return; - } - await withAccountSnap( { title: this.test?.fullTitle() }, async (driver, bundlerServer) => { diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index 28454c9bad66..41951f973aa9 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -8,7 +8,7 @@ const { difference } = require('lodash'); const createStaticServer = require('../../development/create-static-server'); const { tEn } = require('../lib/i18n-helpers'); const { setupMocking } = require('./mock-e2e'); -const { Ganache } = require('./ganache'); +const { Ganache } = require('./seeder/ganache'); const FixtureServer = require('./fixture-server'); const PhishingWarningPageServer = require('./phishing-warning-page-server'); const { buildWebDriver } = require('./webdriver'); @@ -44,20 +44,25 @@ async function withFixtures(options, testSuite) { title, ignoredConsoleErrors = [], dappPath = undefined, + disableGanache, dappPaths, testSpecificMock = function () { // do nothing. }, useBundler, usePaymaster, + ethConversionInUsd, } = options; const fixtureServer = new FixtureServer(); - const ganacheServer = new Ganache(); + let ganacheServer; + if (!disableGanache) { + ganacheServer = new Ganache(); + } const bundlerServer = new Bundler(); const https = await mockttp.generateCACertificate(); const mockServer = mockttp.getLocal({ https, cors: true }); - let secondaryGanacheServer; + const secondaryGanacheServer = []; let numberOfDapps = dapp ? 1 : 0; const dappServer = []; const phishingPageServer = new PhishingWarningPageServer(); @@ -66,28 +71,39 @@ async function withFixtures(options, testSuite) { let driver; let failed = false; try { - await ganacheServer.start(ganacheOptions); + if (!disableGanache) { + await ganacheServer.start(ganacheOptions); + } let contractRegistry; - if (smartContract) { + if (smartContract && !disableGanache) { const ganacheSeeder = new GanacheSeeder(ganacheServer.getProvider()); - await ganacheSeeder.deploySmartContract(smartContract); + const contracts = + smartContract instanceof Array ? smartContract : [smartContract]; + await Promise.all( + contracts.map((contract) => + ganacheSeeder.deploySmartContract(contract), + ), + ); contractRegistry = ganacheSeeder.getContractRegistry(); } if (ganacheOptions?.concurrent) { - const { port, chainId, ganacheOptions2 } = ganacheOptions.concurrent; - secondaryGanacheServer = new Ganache(); - await secondaryGanacheServer.start({ - blockTime: 2, - chain: { chainId }, - port, - vmErrorsOnRPCResponse: false, - ...ganacheOptions2, + ganacheOptions.concurrent.forEach(async (ganacheSettings) => { + const { port, chainId, ganacheOptions2 } = ganacheSettings; + const server = new Ganache(); + secondaryGanacheServer.push(server); + await server.start({ + blockTime: 2, + chain: { chainId }, + port, + vmErrorsOnRPCResponse: false, + ...ganacheOptions2, + }); }); } - if (useBundler) { + if (!disableGanache && useBundler) { await initBundler(bundlerServer, ganacheServer, usePaymaster); } @@ -126,6 +142,7 @@ async function withFixtures(options, testSuite) { testSpecificMock, { chainId: ganacheOptions?.chainId || 1337, + ethConversionInUsd, }, ); if ((await detectPort(8000)) !== 8000) { @@ -172,6 +189,7 @@ async function withFixtures(options, testSuite) { secondaryGanacheServer, mockedEndpoint, bundlerServer, + mockServer, }); const errorsAndExceptions = driver.summarizeErrorsAndExceptions(); @@ -199,7 +217,7 @@ async function withFixtures(options, testSuite) { ...new Set([...privacyReport, ...privacySnapshot]), ].sort(); - // To determine if a new host was requsted, we use the lodash difference + // To determine if a new host was requested, we use the lodash difference // method to generate an array of the items included in the first argument // but not in the second const newHosts = difference(mergedReport, privacySnapshot); @@ -229,7 +247,10 @@ async function withFixtures(options, testSuite) { } catch (verboseReportError) { console.error(verboseReportError); } - if (driver.errors.length > 0 || driver.exceptions.length > 0) { + if ( + process.env.E2E_LEAVE_RUNNING !== 'true' && + (driver.errors.length > 0 || driver.exceptions.length > 0) + ) { /** * Navigate to the background * forcing background exceptions to be captured @@ -248,10 +269,14 @@ async function withFixtures(options, testSuite) { } finally { if (!failed || process.env.E2E_LEAVE_RUNNING !== 'true') { await fixtureServer.stop(); - await ganacheServer.quit(); + if (ganacheServer) { + await ganacheServer.quit(); + } if (ganacheOptions?.concurrent) { - await secondaryGanacheServer.quit(); + secondaryGanacheServer.forEach(async (server) => { + await server.quit(); + }); } if (useBundler) { @@ -303,12 +328,12 @@ const WINDOW_TITLES = Object.freeze({ }); /** - * @param {*} driver - selinium driver + * @param {*} driver - Selenium driver * @param {*} handlesCount - total count of windows that should be loaded * @returns handles - an object with window handles, properties in object represent windows: - * 1. extension: metamask extension window + * 1. extension: MetaMask extension window * 2. dapp: test-app window - * 3. popup: metsmask extension popup window + * 3. popup: MetaMask extension popup window */ const getWindowHandles = async (driver, handlesCount) => { await driver.waitUntilXWindowHandles(handlesCount); @@ -498,9 +523,17 @@ const onboardingCompleteWalletCreationWithOptOut = async (driver) => { await driver.findElement({ text: 'Wallet creation successful', tag: 'h2' }); // opt-out from third party API await driver.clickElement({ text: 'Advanced configuration', tag: 'a' }); + await driver.clickElement( + '[data-testid="basic-functionality-toggle"] .toggle-button', + ); + await driver.clickElement('[id="basic-configuration-checkbox"]'); + await driver.clickElement({ text: 'Turn off', tag: 'button' }); + await Promise.all( ( - await driver.findClickableElements('.toggle-button.toggle-button--on') + await driver.findClickableElements( + '.toggle-button.toggle-button--on:not([data-testid="basic-functionality-toggle"] .toggle-button)', + ) ).map((toggle) => toggle.click()), ); // complete onboarding @@ -613,7 +646,7 @@ const tapAndHoldToRevealSRP = async (driver) => { text: tEn('holdToRevealSRP'), tag: 'span', }, - 2000, + 3000, ); }; @@ -628,15 +661,26 @@ const closeSRPReveal = async (driver) => { }); }; -const DAPP_URL = 'http://127.0.0.1:8080'; +const DAPP_HOST_ADDRESS = '127.0.0.1:8080'; +const DAPP_URL = `http://${DAPP_HOST_ADDRESS}`; const DAPP_ONE_URL = 'http://127.0.0.1:8081'; const openDapp = async (driver, contract = null, dappURL = DAPP_URL) => { - contract + return contract ? await driver.openNewPage(`${dappURL}/?contract=${contract}`) : await driver.openNewPage(dappURL); }; +const createDappTransaction = async (driver, transaction) => { + await openDapp( + driver, + null, + `${DAPP_URL}/request?method=eth_sendTransaction¶ms=${JSON.stringify([ + transaction, + ])}`, + ); +}; + const switchToOrOpenDapp = async ( driver, contract = null, @@ -669,7 +713,7 @@ const connectToDapp = async (driver) => { tag: 'button', }); await driver.clickElement({ - text: 'Connect', + text: 'Confirm', tag: 'button', }); await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); @@ -681,6 +725,9 @@ const PRIVATE_KEY = const PRIVATE_KEY_TWO = '0xa444f52ea41e3a39586d7069cb8e8233e9f6b9dea9cbb700cce69ae860661cc8'; +const ACCOUNT_1 = '0x5cfe73b6021e818b776b421b1c4db2474086a7e1'; +const ACCOUNT_2 = '0x09781764c08de8ca82e156bbf156a3ca217c7950'; + const defaultGanacheOptions = { accounts: [{ secretKey: PRIVATE_KEY, balance: convertETHToHexGwei(25) }], }; @@ -717,7 +764,7 @@ const generateGanacheOptions = ({ }; // Edit priority gas fee form -const editGasfeeForm = async (driver, gasLimit, gasPrice) => { +const editGasFeeForm = async (driver, gasLimit, gasPrice) => { const inputs = await driver.findElements('input[type="number"]'); const gasLimitInput = inputs[0]; const gasPriceInput = inputs[1]; @@ -727,9 +774,20 @@ const editGasfeeForm = async (driver, gasLimit, gasPrice) => { }; const openActionMenuAndStartSendFlow = async (driver) => { + await driver.delay(500); await driver.clickElement('[data-testid="eth-overview-send"]'); }; +const clickNestedButton = async (driver, tabName) => { + try { + await driver.clickElement({ text: tabName, tag: 'button' }); + } catch (error) { + await driver.clickElement({ + xpath: `//*[contains(text(),"${tabName}")]/parent::button`, + }); + } +}; + const sendScreenToConfirmScreen = async ( driver, recipientAddress, @@ -738,36 +796,26 @@ const sendScreenToConfirmScreen = async ( await openActionMenuAndStartSendFlow(driver); await driver.fill('[data-testid="ens-input"]', recipientAddress); await driver.fill('.unit-input__input', quantity); - if (process.env.MULTICHAIN) { - // check if element exists and click it - await driver - .findElement({ - text: 'I understand', - tag: 'button', - }) - .then( - (_found) => { - driver.clickElement({ - text: 'I understand', - tag: 'button', - }); - }, - (error) => { - console.error('Element not found.', error); - }, - ); - await driver.clickElement({ - text: 'Continue', + // check if element exists and click it + await driver + .findElement({ + text: 'I understand', tag: 'button', - }); - } else { - await driver.clickElement({ - text: 'Next', - tag: 'button', - css: '[data-testid="page-container-footer-next"]', - }); - } + }) + .then( + (_found) => { + driver.clickElement({ + text: 'I understand', + tag: 'button', + }); + }, + (error) => { + console.error('Element not found.', error); + }, + ); + + await driver.clickElement({ text: 'Continue', tag: 'button' }); }; const sendTransaction = async ( @@ -776,31 +824,22 @@ const sendTransaction = async ( quantity, isAsyncFlow = false, ) => { - // TODO: Update Test when Multichain Send Flow is added - if (process.env.MULTICHAIN) { - return; - } await openActionMenuAndStartSendFlow(driver); await driver.fill('[data-testid="ens-input"]', recipientAddress); await driver.fill('.unit-input__input', quantity); - // We need to wait for the text "Max Fee: 0.000xxxx ETH" before continuing - await driver.findElement({ text: '0.000', tag: 'span' }); - await driver.clickElement({ - text: 'Next', + text: 'Continue', tag: 'button', - css: '[data-testid="page-container-footer-next"]', }); await driver.clickElement({ text: 'Confirm', tag: 'button', - css: '[data-testid="page-container-footer-next"]', }); // the default is to do this block, but if we're testing an async flow, it would get stuck here if (!isAsyncFlow) { - await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.clickElement('[data-testid="account-overview__activity-tab"]'); await driver.assertElementNotPresent('.transaction-list-item--unconfirmed'); await driver.findElement('.transaction-list-item'); } @@ -830,27 +869,23 @@ const TEST_SEED_PHRASE_TWO = // Usually happens when onboarded to make sure the state is retrieved from metamaskState properly, or after txn is made const locateAccountBalanceDOM = async (driver, ganacheServer) => { - const balance = (await ganacheServer.getFiatBalance()).toLocaleString( - undefined, - { - minimumFractionDigits: 2, - }, - ); - - await driver.findElement({ - css: '[data-testid="eth-overview__primary-currency"]', - text: `$ ${balance} USD`, - }); + const balanceSelector = '[data-testid="eth-overview__primary-currency"]'; + if (ganacheServer) { + const balance = await ganacheServer.getBalance(); + await driver.waitForSelector({ + css: balanceSelector, + text: `${balance} ETH`, + }); + } else { + await driver.findElement(balanceSelector); + } }; const WALLET_PASSWORD = 'correct horse battery staple'; -async function waitForAccountRendered(driver) { - await driver.findElement('[data-testid="eth-overview__primary-currency"]'); -} - /** * Unlock the wallet with the default password. + * This method is intended to replace driver.navigate and should not be called after driver.navigate. * * @param {WebDriver} driver - The webdriver instance * @param {object} options - Options for unlocking the wallet @@ -879,6 +914,7 @@ async function unlockWallet( const logInWithBalanceValidation = async (driver, ganacheServer) => { await unlockWallet(driver); + // Wait for balance to load await locateAccountBalanceDOM(driver, ganacheServer); }; @@ -906,18 +942,25 @@ function genRandInitBal(minETHBal = 10, maxETHBal = 100, decimalPlaces = 4) { } /** - * This method handles clicking the sign button on signature confrimation + * This method handles clicking the sign button on signature confirmation * screen. * - * @param {WebDriver} driver - * @param {number} numHandles - * @param {string} locatorID + * @param {object} options - Options for the function. + * @param {WebDriver} options.driver - The WebDriver instance controlling the browser. + * @param {string} [options.locatorID] - ID of the signature element (if any). + * @param {boolean} [options.snapSigInsights] - Whether to wait for the insights snap to be ready before clicking the sign button. */ -async function clickSignOnSignatureConfirmation( +async function clickSignOnSignatureConfirmation({ driver, - numHandles = 2, // eslint-disable-line no-unused-vars locatorID = null, -) { + snapSigInsights = false, +}) { + if (snapSigInsights) { + // there is no condition we can wait for to know the snap is ready, + // so we have to add a small delay as the last alternative to avoid flakiness. + await driver.delay(regularDelayMs); + } + await driver.clickElement({ text: 'Sign', tag: 'button' }); // #ethSign has a second Sign confirmation button that says "Your funds may be at risk" @@ -1069,18 +1112,21 @@ async function initBundler(bundlerServer, ganacheServer, usePaymaster) { await bundlerServer.start(); } catch (error) { - console.log('Failed to initialise bundler', error); + console.log('Failed to initialize bundler', error); throw error; } } module.exports = { + DAPP_HOST_ADDRESS, DAPP_URL, DAPP_ONE_URL, TEST_SEED_PHRASE, TEST_SEED_PHRASE_TWO, PRIVATE_KEY, PRIVATE_KEY_TWO, + ACCOUNT_1, + ACCOUNT_2, getWindowHandles, convertToHexValue, tinyDelayMs, @@ -1102,6 +1148,7 @@ module.exports = { importWrongSRPOnboardingFlow, testSRPDropdownIterations, openDapp, + createDappTransaction, switchToOrOpenDapp, connectToDapp, multipleGanacheOptions, @@ -1112,7 +1159,6 @@ module.exports = { unlockWallet, logInWithBalanceValidation, locateAccountBalanceDOM, - waitForAccountRendered, generateGanacheOptions, WALLET_PASSWORD, WINDOW_TITLES, @@ -1133,5 +1179,6 @@ module.exports = { genRandInitBal, openActionMenuAndStartSendFlow, getCleanAppState, - editGasfeeForm, + editGasFeeForm, + clickNestedButton, }; diff --git a/test/e2e/json-rpc/eth_newBlockFilter.spec.js b/test/e2e/json-rpc/eth_newBlockFilter.spec.js index 039045d20e19..1b1091f82efa 100644 --- a/test/e2e/json-rpc/eth_newBlockFilter.spec.js +++ b/test/e2e/json-rpc/eth_newBlockFilter.spec.js @@ -47,25 +47,21 @@ describe('eth_newBlockFilter', function () { await driver.delay(1000); - const filterChanges = await driver.executeScript( - `return window.ethereum.request(${getFilterChangesRequest})`, - ); - const blockByHashRequest = JSON.stringify({ jsonrpc: '2.0', method: 'eth_getBlockByNumber', params: ['latest', false], }); - const blockByHash = await driver.executeScript( `return window.ethereum.request(${blockByHashRequest})`, ); - assert.strictEqual( - filterChanges[filterChanges.length - 1], - blockByHash.hash, + const filterChanges = await driver.executeScript( + `return window.ethereum.request(${getFilterChangesRequest})`, ); + assert.strictEqual(filterChanges.includes(blockByHash.hash), true); + // eth_uninstallFilter const uninstallFilterRequest = JSON.stringify({ jsonrpc: '2.0', diff --git a/test/e2e/json-rpc/switchEthereumChain.spec.js b/test/e2e/json-rpc/switchEthereumChain.spec.js index e255f7b894dd..ef195f4b9a2b 100644 --- a/test/e2e/json-rpc/switchEthereumChain.spec.js +++ b/test/e2e/json-rpc/switchEthereumChain.spec.js @@ -20,23 +20,41 @@ describe('Switch Ethereum Chain for two dapps', function () { .withNetworkControllerDoubleGanache() .build(), dappOptions: { numberOfDapps: 2 }, + ganacheOptions: { ...defaultGanacheOptions, - concurrent: { port: 8546, chainId: 1338 }, + concurrent: [{ port: 8546, chainId: 1338 }], }, title: this.test.fullTitle(), }, async ({ driver }) => { await unlockWallet(driver); - // open two dapps - await openDapp(driver, undefined, DAPP_URL); - await openDapp(driver, undefined, DAPP_ONE_URL); + // Open settings menu button + const accountOptionsMenuSelector = + '[data-testid="account-options-menu-button"]'; + await driver.waitForSelector(accountOptionsMenuSelector); + await driver.clickElement(accountOptionsMenuSelector); - // Window Handling - const windowHandles = await driver.getAllWindowHandles(); - const dappOne = windowHandles[1]; - const dappTwo = windowHandles[2]; + // Click settings from dropdown menu + const globalMenuSettingsSelector = + '[data-testid="global-menu-settings"]'; + await driver.waitForSelector(globalMenuSettingsSelector); + await driver.clickElement(globalMenuSettingsSelector); + + // Click Experimental tab + const experimentalTabRawLocator = { + text: 'Experimental', + tag: 'div', + }; + await driver.clickElement(experimentalTabRawLocator); + + // Toggle off request queue setting (on by default now) + await driver.clickElement('.request-queue-toggle'); + + // open two dapps + const dappOne = await openDapp(driver, undefined, DAPP_URL); + const dappTwo = await openDapp(driver, undefined, DAPP_ONE_URL); // switchEthereumChain request const switchEthereumChainRequest = JSON.stringify({ @@ -50,7 +68,7 @@ describe('Switch Ethereum Chain for two dapps', function () { `window.ethereum.request(${switchEthereumChainRequest})`, ); - // Confirm switchEtheruemChain + // Confirm switchEthereumChain await switchToNotificationWindow(driver, 4); await driver.findClickableElements({ text: 'Switch network', @@ -92,21 +110,39 @@ describe('Switch Ethereum Chain for two dapps', function () { dappOptions: { numberOfDapps: 2 }, ganacheOptions: { ...defaultGanacheOptions, - concurrent: { port: 8546, chainId: 1338 }, + concurrent: [{ port: 8546, chainId: 1338 }], }, title: this.test.fullTitle(), }, async ({ driver }) => { await unlockWallet(driver); + // Open settings menu button + const accountOptionsMenuSelector = + '[data-testid="account-options-menu-button"]'; + await driver.waitForSelector(accountOptionsMenuSelector); + await driver.clickElement(accountOptionsMenuSelector); + + // Click settings from dropdown menu + const globalMenuSettingsSelector = + '[data-testid="global-menu-settings"]'; + await driver.waitForSelector(globalMenuSettingsSelector); + await driver.clickElement(globalMenuSettingsSelector); + + // Click Experimental tab + const experimentalTabRawLocator = { + text: 'Experimental', + tag: 'div', + }; + await driver.clickElement(experimentalTabRawLocator); + + // Toggle off request queue setting (on by default now) + await driver.clickElement('.request-queue-toggle'); + // open two dapps - await openDapp(driver, undefined, DAPP_URL); + const dappOne = await openDapp(driver, undefined, DAPP_URL); await openDapp(driver, undefined, DAPP_ONE_URL); - // Window Handling - const windowHandles = await driver.getAllWindowHandles(); - const dappOne = windowHandles[1]; - // Initiate send transaction on Dapp two await driver.clickElement('#sendButton'); await driver.delay(2000); @@ -164,21 +200,39 @@ describe('Switch Ethereum Chain for two dapps', function () { dappOptions: { numberOfDapps: 2 }, ganacheOptions: { ...defaultGanacheOptions, - concurrent: { port: 8546, chainId: 1338 }, + concurrent: [{ port: 8546, chainId: 1338 }], }, title: this.test.fullTitle(), }, async ({ driver }) => { await unlockWallet(driver); + // Open settings menu button + const accountOptionsMenuSelector = + '[data-testid="account-options-menu-button"]'; + await driver.waitForSelector(accountOptionsMenuSelector); + await driver.clickElement(accountOptionsMenuSelector); + + // Click settings from dropdown menu + const globalMenuSettingsSelector = + '[data-testid="global-menu-settings"]'; + await driver.waitForSelector(globalMenuSettingsSelector); + await driver.clickElement(globalMenuSettingsSelector); + + // Click Experimental tab + const experimentalTabRawLocator = { + text: 'Experimental', + tag: 'div', + }; + await driver.clickElement(experimentalTabRawLocator); + + // Toggle off request queue setting (on by default now) + await driver.clickElement('.request-queue-toggle'); + // open two dapps - await openDapp(driver, undefined, DAPP_URL); + const dappOne = await openDapp(driver, undefined, DAPP_URL); await openDapp(driver, undefined, DAPP_ONE_URL); - // Window Handling - let windowHandles = await driver.getAllWindowHandles(); - const dappOne = windowHandles[1]; - // switchEthereumChain request const switchEthereumChainRequest = JSON.stringify({ jsonrpc: '2.0', @@ -206,7 +260,7 @@ describe('Switch Ethereum Chain for two dapps', function () { await driver.clickElement('#sendButton'); await driver.delay(2000); - // Switch to nofication that should still be switchEthereumChain request but with an warning. + // Switch to notification that should still be switchEthereumChain request but with a warning. await switchToNotificationWindow(driver, 4); await driver.findElement({ @@ -214,13 +268,19 @@ describe('Switch Ethereum Chain for two dapps', function () { text: 'Switching networks will cancel all pending confirmations', }); - // Confirm switchEtheruemChain with queued pending tx + // Confirm switchEthereumChain with queued pending tx await driver.clickElement({ text: 'Switch network', tag: 'button' }); - // Window handles should only be expanded mm, dapp one, dapp 2 (3 total) + // Window handles should only be expanded mm, dapp one, dapp 2, and the offscreen document + // if this is an MV3 build(3 or 4 total) await driver.wait(async () => { - windowHandles = await driver.getAllWindowHandles(); - return windowHandles.length === 3; + const windowHandles = await driver.getAllWindowHandles(); + const numberOfWindowHandlesToExpect = + process.env.ENABLE_MV3 === 'true' || + process.env.ENABLE_MV3 === undefined + ? 4 + : 3; + return windowHandles.length === numberOfWindowHandlesToExpect; }); }, ); @@ -237,21 +297,39 @@ describe('Switch Ethereum Chain for two dapps', function () { dappOptions: { numberOfDapps: 2 }, ganacheOptions: { ...defaultGanacheOptions, - concurrent: { port: 8546, chainId: 1338 }, + concurrent: [{ port: 8546, chainId: 1338 }], }, title: this.test.fullTitle(), }, async ({ driver }) => { await unlockWallet(driver); + // Open settings menu button + const accountOptionsMenuSelector = + '[data-testid="account-options-menu-button"]'; + await driver.waitForSelector(accountOptionsMenuSelector); + await driver.clickElement(accountOptionsMenuSelector); + + // Click settings from dropdown menu + const globalMenuSettingsSelector = + '[data-testid="global-menu-settings"]'; + await driver.waitForSelector(globalMenuSettingsSelector); + await driver.clickElement(globalMenuSettingsSelector); + + // Click Experimental tab + const experimentalTabRawLocator = { + text: 'Experimental', + tag: 'div', + }; + await driver.clickElement(experimentalTabRawLocator); + + // Toggle off request queue setting (on by default now) + await driver.clickElement('.request-queue-toggle'); + // open two dapps - await openDapp(driver, undefined, DAPP_URL); + const dappOne = await openDapp(driver, undefined, DAPP_URL); await openDapp(driver, undefined, DAPP_ONE_URL); - // Window Handling - const windowHandles = await driver.getAllWindowHandles(); - const dappOne = windowHandles[1]; - // switchEthereumChain request const switchEthereumChainRequest = JSON.stringify({ jsonrpc: '2.0', @@ -287,7 +365,7 @@ describe('Switch Ethereum Chain for two dapps', function () { text: 'Switching networks will cancel all pending confirmations', }); - // Cancel switchEtheruemChain with queued pending tx + // Cancel switchEthereumChain with queued pending tx await driver.clickElement({ text: 'Cancel', tag: 'button' }); // Delay for second notification of the pending tx diff --git a/test/e2e/json-rpc/wallet_requestPermissions.spec.js b/test/e2e/json-rpc/wallet_requestPermissions.spec.js index c564295b5d48..917e30ca12fc 100644 --- a/test/e2e/json-rpc/wallet_requestPermissions.spec.js +++ b/test/e2e/json-rpc/wallet_requestPermissions.spec.js @@ -43,7 +43,7 @@ describe('wallet_requestPermissions', function () { }); await driver.clickElement({ - text: 'Connect', + text: 'Confirm', tag: 'button', }); diff --git a/test/e2e/mmi/.env.example b/test/e2e/mmi/.env.example index 1acc6ff92d24..302ea0db2a4a 100644 --- a/test/e2e/mmi/.env.example +++ b/test/e2e/mmi/.env.example @@ -17,4 +17,4 @@ MMI_E2E_JUPITER_BASE_URL= MMI_E2E_MMI_TEST_DAPP_URL= MMI_E2E_MMI_DASHBOARD_URL= # run tests locally in headless mode (true/false) -HEADLESS= \ No newline at end of file +HEADLESS= diff --git a/test/e2e/mmi/Dockerfile b/test/e2e/mmi/Dockerfile index 200dbfb72df4..27bcf32d61fd 100644 --- a/test/e2e/mmi/Dockerfile +++ b/test/e2e/mmi/Dockerfile @@ -1,9 +1,10 @@ -FROM mcr.microsoft.com/playwright:v1.42.1-focal AS build +FROM mcr.microsoft.com/playwright:v1.44.1-focal AS build WORKDIR '/usr/src/app' # Copy test files COPY playwright.config.ts . +COPY env.ts test/helpers/env.ts COPY . ./test/e2e/mmi/ # Copy extension for test COPY ./dist/chrome ./dist/chrome diff --git a/test/e2e/mmi/README.md b/test/e2e/mmi/README.md index d57d1d0ddedb..7c4b37ff6ec0 100644 --- a/test/e2e/mmi/README.md +++ b/test/e2e/mmi/README.md @@ -94,4 +94,4 @@ When tests finish on the pipeline, you can find the same logs that you use local ![CircleCI Job Actifact detail](resources/circleci-artifact-screnshot.png) ## Contact MMI team -If you encounter any problems while working on these e2e tests, you can write into the Consensys Slack channel `metamask-mmi-collab`. \ No newline at end of file +If you encounter any problems while working on these e2e tests, you can write into the Consensys Slack channel `contact-mmi-team`. \ No newline at end of file diff --git a/test/e2e/mmi/custodian-hooks/ICustodianTestClient.ts b/test/e2e/mmi/custodian-hooks/ICustodianTestClient.ts index 2ea67946b525..00565e5d85b5 100644 --- a/test/e2e/mmi/custodian-hooks/ICustodianTestClient.ts +++ b/test/e2e/mmi/custodian-hooks/ICustodianTestClient.ts @@ -1,6 +1,6 @@ import { type BrowserContext } from '@playwright/test'; -export interface ICustodianTestClient { +export type ICustodianTestClient = { /** This method is expected to be used for initial test setup and to keep the context object in order to manage extra screen actions */ setup: (context?: BrowserContext) => Promise; @@ -36,4 +36,4 @@ export interface ICustodianTestClient { /** This method should return the list of account titles to be selected when MMI custodian is connected */ getSelectedAccounts: () => Promise; -} +}; diff --git a/test/e2e/mmi/custodian-hooks/hooks.ts b/test/e2e/mmi/custodian-hooks/hooks.ts index 40aaa3d3be2d..a012f5633224 100644 --- a/test/e2e/mmi/custodian-hooks/hooks.ts +++ b/test/e2e/mmi/custodian-hooks/hooks.ts @@ -134,6 +134,8 @@ export class CustodianTestClient implements ICustodianTestClient { const maxRetries = 3; const retryInterval = 3000; let retries = 0; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any let transaction: any; while (retries < maxRetries) { try { @@ -154,7 +156,7 @@ export class CustodianTestClient implements ICustodianTestClient { console.log(`Retrying in ${retryInterval / 1000} seconds...`); await new Promise((resolve) => setTimeout(resolve, retryInterval)); } else { - throw error( + throw new Error( `👎 Max retries (${maxRetries}) reached. Saturn tx not found.`, ); } @@ -193,6 +195,8 @@ export class CustodianTestClient implements ICustodianTestClient { try { const transactions = await this.getEIP721TransactionStatusCreated(); const { id } = transactions.find( + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any (transaction: any) => transaction?.payload?.message?.contents === signedTransactionTime, ); @@ -295,6 +299,8 @@ export class CustodianTestClient implements ICustodianTestClient { return transactions[index]; } + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any async getPersonalSignatureTransactionStatusCreated(): Promise { const authorization = this.bearerToken; return await axios @@ -317,6 +323,8 @@ export class CustodianTestClient implements ICustodianTestClient { }); } + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any async getEIP721TransactionStatusCreated(): Promise { const authorization = this.bearerToken; return await axios @@ -346,4 +354,27 @@ export class CustodianTestClient implements ICustodianTestClient { async rejectPersonalSignatureId(txId: string): Promise { return txId; } + + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public async postConnectionRequest(data: any) { + return (await axios + .post( + 'https://neptune-custody.dev.metamask-institutional.io/qrcode/connection-request', + data, + { + headers: { + 'Content-Type': 'application/json', + }, + }, + ) + .then(function (response) { + expect(response.status).toBe(200); + return response.data; + }) + .catch(function (error) { + console.log(error.response.data); + throw error; + })) as string; + } } diff --git a/test/e2e/mmi/env.ts b/test/e2e/mmi/env.ts new file mode 100644 index 000000000000..dc21b57b129a --- /dev/null +++ b/test/e2e/mmi/env.ts @@ -0,0 +1,36 @@ +import { env } from 'process'; + +type HeadlessCapableServiceName = 'SELENIUM' | 'PLAYWRIGHT'; + +export function isHeadless(serviceName: HeadlessCapableServiceName): boolean { + if (serviceName) { + const serviceKey = `${serviceName}_HEADLESS`; + if (env[serviceKey]) { + return parseBoolean(env[serviceKey]); + } + } + return Boolean(env.HEADLESS) && parseBoolean(env.HEADLESS); +} + +export function parseBoolean(value: undefined | string): boolean { + if (!value) { + return false; + } + if (typeof value === 'boolean') { + return value; + } + if (typeof value !== 'string') { + throw new Error(`Not-a-Boolean: '${value}'`); + } + switch (value.toLowerCase().trim()) { + case 'false': + case '0': + case '': + return false; + case 'true': + case '1': + return true; + default: + throw new Error(`Not-a-Boolean: '${value}'`); + } +} diff --git a/test/e2e/mmi/helpers/custodian-helper.ts b/test/e2e/mmi/helpers/custodian-helper.ts index eab47957aba2..a45e5a7e84c3 100644 --- a/test/e2e/mmi/helpers/custodian-helper.ts +++ b/test/e2e/mmi/helpers/custodian-helper.ts @@ -6,6 +6,8 @@ export async function getCustodianInfoByName(name: string) { // First get an admin token try { const { custodians } = (await axios.get(`${MMI_E2E_MMI_CONFIG_URL}`)).data; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any return custodians.filter(function (custodian: any) { return custodian.name === name; }); diff --git a/test/e2e/mmi/helpers/dapps-helpers.ts b/test/e2e/mmi/helpers/dapps-helpers.ts index 3990eaeb8efb..0cf01ec3f47d 100644 --- a/test/e2e/mmi/helpers/dapps-helpers.ts +++ b/test/e2e/mmi/helpers/dapps-helpers.ts @@ -32,6 +32,8 @@ export async function callTestDappBtn( // Setup testnetwork in settings const mainMenuPage = new MMIMainMenuPage(page, extensionId as string); await mainMenuPage.goto(); + await mainMenuPage.fillPassword(); + await mainMenuPage.finishOnboarding(); await mainMenuPage.selectMenuOption('settings'); await mainMenuPage.selectSettings('Advance'); await mainMenuPage.switchTestNetwork(); @@ -41,7 +43,9 @@ export async function callTestDappBtn( // Check network const networkPage = new MMINetworkPage(page); await networkPage.open(); - await networkPage.selectNetwork(process.env.MMI_E2E_TEST_NETWORK ?? SEPOLIA_DISPLAY_NAME); + await networkPage.selectNetwork( + process.env.MMI_E2E_TEST_NETWORK ?? SEPOLIA_DISPLAY_NAME, + ); // get token to access saturn // changed to get it from Saturn endpoint to avoid calling Auth0 API @@ -68,5 +72,8 @@ export async function callTestDappBtn( isSign, signedTransactionTime, ); - return signedTransactionTime; + return { + dummyDApp, + signedTransactionTime, + }; } diff --git a/test/e2e/mmi/helpers/extension-loader.ts b/test/e2e/mmi/helpers/extension-loader.ts index b1e4e0a021ba..31834d7fce50 100644 --- a/test/e2e/mmi/helpers/extension-loader.ts +++ b/test/e2e/mmi/helpers/extension-loader.ts @@ -1,6 +1,8 @@ import path from 'path'; import { test as base, chromium } from '@playwright/test'; +import { isHeadless } from '../../../helpers/env'; + const extensionPath = path.join(__dirname, '../../../../dist/chrome'); export const test = base.extend({ @@ -10,7 +12,7 @@ export const test = base.extend({ headless: false, args: [`--disable-extensions-except=${extensionPath}`], }; - if (process.env.HEADLESS === 'true') { + if (isHeadless('PLAYWRIGHT')) { launchOptions.args.push('--headless=new'); } const context = await chromium.launchPersistentContext('', launchOptions); diff --git a/test/e2e/mmi/pageObjects/mmi-accountMenu-page.ts b/test/e2e/mmi/pageObjects/mmi-accountMenu-page.ts index 72c049ac0c6c..7680769bbe6c 100644 --- a/test/e2e/mmi/pageObjects/mmi-accountMenu-page.ts +++ b/test/e2e/mmi/pageObjects/mmi-accountMenu-page.ts @@ -1,5 +1,6 @@ import { type Locator, type Page, test, expect } from '@playwright/test'; import { getCustodianInfoByName } from '../helpers/custodian-helper'; +import { CustodianTestClient } from '../custodian-hooks/hooks'; import { MMISaturnUIPage } from './mmi-saturn-ui-page'; export class MMIAccountMenuPage { @@ -46,7 +47,7 @@ export class MMIAccountMenuPage { .filter({ hasText: 'Select an account' }); } - async connectCustodian(name: string, visual?: boolean) { + async connectCustodian(name: string, visual?: boolean, qrCode?: boolean) { await this.page .getByRole('button', { name: /Add account or hardware wallet/iu }) .click(); @@ -61,6 +62,7 @@ export class MMIAccountMenuPage { } const custodian = await getCustodianInfoByName(name); + await this.page .getByRole('list') .locator('div') @@ -69,29 +71,56 @@ export class MMIAccountMenuPage { .getByTestId('custody-connect-button') .click(); - await expect( - this.page.getByText(/connect saturn custody accounts/iu), - ).toBeVisible(); - if (visual) { - await test.expect - .soft(this.page) - .toHaveScreenshot('custodian_connection_info.png', { fullPage: true }); + if (qrCode) { + const spanElement = await this.page.$('span.hidden'); + + if (spanElement) { + let data = await spanElement.getAttribute('data-value'); + + while (!data) { + await new Promise((resolve) => setTimeout(resolve, 1000)); + data = await spanElement.getAttribute('data-value'); + } + + const client = new CustodianTestClient(); + await client.setup(); + await client.postConnectionRequest(data); + await this.page + .getByTestId('select-all-accounts-selected-false') + .click(); + await this.page.getByRole('button', { name: /connect/iu }).click(); + await this.page + .getByRole('button', { name: /close/iu }) + .first() + .click(); + } + } else { + await expect( + this.page.getByText(/connect saturn custody accounts/iu), + ).toBeVisible(); + if (visual) { + await test.expect + .soft(this.page) + .toHaveScreenshot('custodian_connection_info.png', { + fullPage: true, + }); + } + + const pagePromise = this.page.context().waitForEvent('page'); + await this.page.getByRole('button', { name: /continue/iu }).click(); + const saturnUI = await pagePromise; + await saturnUI.waitForLoadState(); + + const saturnUIPage = new MMISaturnUIPage(saturnUI); + await saturnUIPage.connectMMI(); + await this.page.getByRole('button', { name: /cancel/iu }).click(); + await this.page.getByRole('button', { name: /back/iu }).click(); } - - const pagePromise = this.page.context().waitForEvent('page'); - await this.page.getByRole('button', { name: /continue/iu }).click(); - const saturnUI = await pagePromise; - await saturnUI.waitForLoadState(); - - const saturnUIPage = new MMISaturnUIPage(saturnUI); - await saturnUIPage.connectMMI(); - await this.page.getByRole('button', { name: /cancel/iu }).click(); - await this.page.getByRole('button', { name: /back/iu }).click(); } async selectCustodyAccount(account: string) { await this.accountsMenu(); - await this.dialog.getByText(`${account}`).first().click(); + await this.dialog.getByText(`${account}`).click(); } async accountMenuScreenshot(screenshotName: string) { @@ -105,11 +134,9 @@ export class MMIAccountMenuPage { '.multichain-account-list-item__content', ); - await test.expect - .soft(dialog) - .toHaveScreenshot(screenshotName, { - mask: [accountsFunds, networkBanner], - }); + await test.expect.soft(dialog).toHaveScreenshot(screenshotName, { + mask: [accountsFunds, networkBanner], + }); } async removeTokenScreenshot(accountToRemoveName: string) { @@ -132,7 +159,7 @@ export class MMIAccountMenuPage { .click(); await this.page.getByTestId('account-options-menu__remove-jwt').click(); await expect(this.page.getByText('Remove custodian token')).toBeVisible(); - await this.page.getByRole('button', { name: /remove/iu }).click(); + await this.page.getByTestId('remove-jwt-confirm-btn').click(); } async getAccountNames() { diff --git a/test/e2e/mmi/pageObjects/mmi-dummyApp-page.ts b/test/e2e/mmi/pageObjects/mmi-dummyApp-page.ts index 222a277fe459..3aff49658f53 100644 --- a/test/e2e/mmi/pageObjects/mmi-dummyApp-page.ts +++ b/test/e2e/mmi/pageObjects/mmi-dummyApp-page.ts @@ -1,4 +1,9 @@ -import { type BrowserContext, type Locator, type Page } from '@playwright/test'; +import { + expect, + type BrowserContext, + type Locator, + type Page, +} from '@playwright/test'; // eslint-disable-next-line node/no-unsupported-features/es-syntax export class DummyAppPage { @@ -19,6 +24,10 @@ export class DummyAppPage { await this.page.goto(process.env.MMI_E2E_MMI_TEST_DAPP_URL as string); } + async bringToFront() { + await this.page.bringToFront(); + } + async connectMMI(context: BrowserContext) { const [popup1] = await Promise.all([ context.waitForEvent('page'), @@ -27,9 +36,8 @@ export class DummyAppPage { await popup1.waitForLoadState(); // Check which account is selected and select if required await popup1.locator('.check-box__indeterminate'); - // await popup1.locator('text=Custody Ac... (0x8b2...b3ad)').click() await popup1.locator('button:has-text("Next")').click(); - await popup1.locator('button:has-text("Connect")').click(); + await popup1.locator('button:has-text("Confirm")').click(); await popup1.close(); } @@ -50,7 +58,7 @@ export class DummyAppPage { await popup.waitForLoadState(); if (isSign) { - await popup.click('button:has-text("Sign")'); + await popup.click('button:has-text("Confirm")'); } else { // Confirm await popup.getByTestId('page-container-footer-next').click(); @@ -62,4 +70,11 @@ export class DummyAppPage { } await popup.close(); } + + async checkContractStatus(status: string | RegExp) { + await expect(this.page.locator('#contractStatus')).toHaveText(status, { + timeout: 60000, + ignoreCase: true, + }); + } } diff --git a/test/e2e/mmi/pageObjects/mmi-main-page.ts b/test/e2e/mmi/pageObjects/mmi-main-page.ts index b5ca9ae56b66..591f4aa3428f 100644 --- a/test/e2e/mmi/pageObjects/mmi-main-page.ts +++ b/test/e2e/mmi/pageObjects/mmi-main-page.ts @@ -25,6 +25,13 @@ export class MMIMainPage { await this.activityTab.click(); } + async finishOnboarding() { + await this.page.getByRole('button', { name: /continue/iu }).click(); + await this.page + .getByRole('button', { name: /continue to wallet/iu }) + .click(); + } + async checkLastTransactionStatus(status: string | RegExp) { // NOTE: Assumes that transaction is the first one on the activity list await expect( @@ -48,6 +55,17 @@ export class MMIMainPage { .getAttribute('data-custodiantransactionid')) as string; } + async getSecondCustodianTXId() { + return (await this.page + .locator('.test-transaction-meta') + .nth(1) + .getAttribute('data-custodiantransactionid')) as string; + } + + async closeCustodyConfirmLink() { + return this.page.locator('button[aria-label="Close"]').click(); + } + async selectMainAction(action: string) { await this.page .locator(`.wallet-overview__buttons >> text=${action}`) @@ -55,17 +73,16 @@ export class MMIMainPage { } async sendFunds(account: string, amount: string) { - await this.page - .getByTestId('recipient-group') - .locator(`text="${account}"`) - .click(); + await this.page.locator(`button >> text="${account}"`).click(); await expect( this.page.locator('.ens-input__selected-input__title'), - ).toHaveText(`${account}`); - await this.page.locator('input.unit-input__input').type(`${amount}`); - await this.page.locator('text="Next"').click(); + ).toContainText(`${account}`); + await this.page + .locator('[data-testid="currency-input"]') + .first() + .type(`${amount}`); + await this.page.locator('text="Continue"').click(); await this.page.locator('text="Confirm"').click(); - await this.page.locator('text="Approve"').click(); } async mainPageScreenshot(screenshotName: string, accountName: string) { @@ -81,7 +98,7 @@ export class MMIMainPage { await test.expect.soft(this.page).toHaveScreenshot(screenshotName, { fullPage: true, mask: [accountsFunds, fundsDetails, accountMenu], - maxDiffPixelRatio: 0.02, + maxDiffPixelRatio: 0.06, }); } } diff --git a/test/e2e/mmi/pageObjects/mmi-mainMenu-page.ts b/test/e2e/mmi/pageObjects/mmi-mainMenu-page.ts index 6c7027e02350..7780c2ce8893 100644 --- a/test/e2e/mmi/pageObjects/mmi-mainMenu-page.ts +++ b/test/e2e/mmi/pageObjects/mmi-mainMenu-page.ts @@ -88,6 +88,20 @@ export class MMIMainMenuPage { .click(); } + async fillPassword() { + await this.page + .getByTestId('unlock-password') + .fill(process.env.MMI_E2E_MMI_PASSWORD as string); + await this.page.getByRole('button', { name: /unlock/iu }).click(); + } + + async finishOnboarding() { + await this.page.getByRole('button', { name: /continue/iu }).click(); + await this.page + .getByRole('button', { name: /continue to wallet/iu }) + .click(); + } + async switchTestNetwork() { await this.page .locator( diff --git a/test/e2e/mmi/pageObjects/mmi-network-page.ts b/test/e2e/mmi/pageObjects/mmi-network-page.ts index d71047f04c05..1da268cdeb1f 100644 --- a/test/e2e/mmi/pageObjects/mmi-network-page.ts +++ b/test/e2e/mmi/pageObjects/mmi-network-page.ts @@ -32,6 +32,7 @@ export class MMINetworkPage { } async selectNetwork(network: string) { - await this.page.getByText(network).first().click(); + await this.page.waitForSelector(`text=${network}`, { state: 'visible' }); + await this.page.click(`text=${network}`, { force: true }); } } diff --git a/test/e2e/mmi/pageObjects/mmi-signup-page.ts b/test/e2e/mmi/pageObjects/mmi-signup-page.ts index 812e097a08a8..55c59a153e59 100644 --- a/test/e2e/mmi/pageObjects/mmi-signup-page.ts +++ b/test/e2e/mmi/pageObjects/mmi-signup-page.ts @@ -13,7 +13,7 @@ export class MMISignUpPage { readonly agreeBtn: Locator; - readonly noThanksBtn: Locator; + readonly enableBtn: Locator; readonly passwordTxt: Locator; @@ -44,7 +44,7 @@ export class MMISignUpPage { 'button:has-text("Confirm Secret Recovery Phrase")', ); this.agreeBtn = page.locator('button:has-text("I agree")'); - this.noThanksBtn = page.locator('button:has-text("No thanks")'); + this.enableBtn = page.locator('button:has-text("Enable")'); // It shows in the Smart Transactions Opt-In Modal. this.passwordTxt = page.getByTestId('create-password-new'); this.passwordConfirmTxt = page.getByTestId('create-password-confirm'); this.agreeCheck = page.getByTestId('create-new-vault__terms-checkbox'); @@ -52,7 +52,7 @@ export class MMISignUpPage { this.agreePasswordTermsCheck = page.getByTestId('create-password-terms'); this.importBtn = page.locator('button:has-text("Import my wallet")'); this.doneBtn = page.locator('button:has-text("Done")'); - this.gotItBtn = page.locator('button:has-text("Got it!")'); + this.gotItBtn = page.locator('button:has-text("Got it")'); this.nextBtn = page.locator('button:has-text("Next")'); } @@ -84,12 +84,6 @@ export class MMISignUpPage { async info() { await this.page.getByRole('button', { name: /continue/iu }).click(); - await this.page - .getByRole('button', { - name: /continue metamask institutional onboarding/iu, - }) - .click(); - // After this click its redirect to the dashboard but we don't need to signin } async close() { diff --git a/test/e2e/mmi/scripts/run-visual-test.sh b/test/e2e/mmi/scripts/run-visual-test.sh index 1c63fc598c02..d3249d7bc792 100755 --- a/test/e2e/mmi/scripts/run-visual-test.sh +++ b/test/e2e/mmi/scripts/run-visual-test.sh @@ -13,7 +13,7 @@ mkdir -p test/e2e/mmi/dist cp -r dist/chrome test/e2e/mmi/dist/chrome # copy playwright config to the docker context -cp playwright.config.ts test/e2e/mmi/ +cp playwright.config.ts test/helpers/env.ts test/e2e/mmi/ # Build the Docker image echo "Building the Docker image..." @@ -43,4 +43,4 @@ rm test/e2e/mmi/playwright.config.ts echo "Removing mmi dist/chrome from test dir..." rm -rf test/e2e/mmi/dist -echo "Script completed successfully." \ No newline at end of file +echo "Script completed successfully." diff --git a/test/e2e/mmi/specs/dapp.signature.spec.ts b/test/e2e/mmi/specs/dapp.signature.spec.ts index d5e0624f8d96..79458b2aee4f 100644 --- a/test/e2e/mmi/specs/dapp.signature.spec.ts +++ b/test/e2e/mmi/specs/dapp.signature.spec.ts @@ -11,7 +11,7 @@ const dappsTest = async ( // Connect to Saturn API const client = new CustodianTestClient(); await client.setup(); - const signedTransactionTime = await callTestDappBtn( + const { signedTransactionTime } = await callTestDappBtn( page, context, client, diff --git a/test/e2e/mmi/specs/dapp.spec.ts b/test/e2e/mmi/specs/dapp.spec.ts index 40ae0a6c5b62..39eae6e3e4e6 100644 --- a/test/e2e/mmi/specs/dapp.spec.ts +++ b/test/e2e/mmi/specs/dapp.spec.ts @@ -12,7 +12,7 @@ const dappsTest = async ( // Connect to Saturn API const client = new CustodianTestClient(); await client.setup(); - await callTestDappBtn(page, context, client, buttonId); + const { dummyDApp } = await callTestDappBtn(page, context, client, buttonId); const mainPage = new MMIMainPage(page); // Rest of the test dapp buttons await mainPage.bringToFront(); @@ -24,6 +24,16 @@ const dappsTest = async ( const statusName = await client.submitTransactionById(custodianTxId); await mainPage.checkLastTransactionStatus(statusName); // Mined status not check as it makes tests flaky and it is blockchain performance dependent + + // check contract status in test dapp + await dummyDApp.bringToFront(); + + if ( + buttonId === 'showMeTheMoneyButton_sepolia' || + buttonId === 'useSuperPowers_sepolia' + ) { + await dummyDApp.checkContractStatus(/Called contract/iu); + } }; // Important note: @@ -31,7 +41,7 @@ const dappsTest = async ( test.describe('MMI dapps', () => { test.describe.configure({ mode: 'serial' }); - test('MMI connects to dapp, clicks "Show me the money" button and confirm from custody', async ({ + test.skip('MMI connects to dapp, clicks "Show me the money" button and confirm from custody', async ({ page, context, }) => { @@ -45,7 +55,7 @@ test.describe('MMI dapps', () => { await dappsTest(page, context, 'approveTokens'); }); - test('MMI connects to dapp, clicks "Use Super Powers" button, and confirm from custody', async ({ + test.skip('MMI connects to dapp, clicks "Use Super Powers" button, and confirm from custody', async ({ page, context, }) => { diff --git a/test/e2e/mmi/specs/extension.visual.spec.ts b/test/e2e/mmi/specs/extension.visual.spec.ts index 0314877e89bd..240f3dce75b2 100644 --- a/test/e2e/mmi/specs/extension.visual.spec.ts +++ b/test/e2e/mmi/specs/extension.visual.spec.ts @@ -32,6 +32,8 @@ test.describe('MMI extension', () => { // Setup testnetwork in settings const mainMenuPage = new MMIMainMenuPage(page, extensionId as string); await mainMenuPage.goto(); + await mainMenuPage.fillPassword(); + await mainMenuPage.finishOnboarding(); await mainMenuPage.selectMenuOption('settings'); await mainMenuPage.selectSettings('Advance'); await mainMenuPage.switchTestNetwork(); @@ -124,6 +126,8 @@ test.describe('MMI extension', () => { // Setup testnetwork in settings const mainMenuPage = new MMIMainMenuPage(page, extensionId as string); await mainMenuPage.goto(); + await mainMenuPage.fillPassword(); + await mainMenuPage.finishOnboarding(); await mainMenuPage.selectMenuOption('settings'); await mainMenuPage.selectSettings('Advance'); await mainMenuPage.switchTestNetwork(); diff --git a/test/e2e/mmi/specs/extension.visual.spec.ts-snapshots/token-replacement-notification-mmi-visual-linux.png b/test/e2e/mmi/specs/extension.visual.spec.ts-snapshots/token-replacement-notification-mmi-visual-linux.png index 37eced1cdcf2..36dd9b1cf85a 100644 Binary files a/test/e2e/mmi/specs/extension.visual.spec.ts-snapshots/token-replacement-notification-mmi-visual-linux.png and b/test/e2e/mmi/specs/extension.visual.spec.ts-snapshots/token-replacement-notification-mmi-visual-linux.png differ diff --git a/test/e2e/mmi/specs/navigation.spec.ts b/test/e2e/mmi/specs/navigation.spec.ts index 3760fedf56f1..1dd919856ede 100644 --- a/test/e2e/mmi/specs/navigation.spec.ts +++ b/test/e2e/mmi/specs/navigation.spec.ts @@ -11,18 +11,17 @@ import { Auth0Page } from '../pageObjects/mmi-auth0-page'; import { MMIMainPage } from '../pageObjects/mmi-main-page'; const portfolio = `${process.env.MMI_E2E_MMI_DASHBOARD_URL}/portfolio`; -const swap = `${process.env.MMI_E2E_MMI_DASHBOARD_URL}/swap`; const stake = `${process.env.MMI_E2E_MMI_DASHBOARD_URL}/stake`; -const support = 'https://mmi-support.zendesk.com/hc/en-us'; +const support = 'https://mmi-support.metamask.io/hc/en-us'; const supportContactUs = - 'https://mmi-support.zendesk.com/hc/en-us/requests/new'; + 'https://mmi-support.metamask.io/hc/en-us/requests/new'; const mmiHomePage = 'https://metamask.io/institutions/'; -const privacyAndPolicy = 'https://consensys.io/privacy-policy'; -const hwWalletPrivacyAndSecurity = - 'https://support.metamask.io/hc/en-us/articles/4408552261275'; +const privacyAndNotice = 'https://consensys.io/privacy-notice'; const openSeaTermsOfUse = 'https://opensea.io/securityproviderterms'; -const metamaskAttributions = 'https://metamask.io/attributions/'; +const metamaskAttributions = + 'https://raw.githubusercontent.com/MetaMask/metamask-extension/develop/attribution.txt'; const termsOfUse = 'https://consensys.io/terms-of-use'; +const learnMoreArticles = 'https://support.metamask.io/hc/en-us/articles'; test.describe('MMI Navigation', () => { test('MMI full navigation links', async ({ context }) => { @@ -56,6 +55,8 @@ test.describe('MMI Navigation', () => { await getPageAndCloseRepeated(context, 'home.html'), ); + await mainPage.finishOnboarding(); + // Check main page links await checkLinkURL( context, @@ -67,8 +68,6 @@ test.describe('MMI Navigation', () => { await checkLinkURL(context, mainPage.page, 'Stake', stake, 'button'); - await checkLinkURL(context, mainPage.page, 'Swap', swap, 'button'); - await checkLinkURL( context, mainPage.page, @@ -123,7 +122,7 @@ test.describe('MMI Navigation', () => { context, mainMenuPage.page, 'learn more', - hwWalletPrivacyAndSecurity, + 'https://support.metamask.io', ); await mainMenuPage.selectSettings('Security & privacy'); @@ -131,13 +130,13 @@ test.describe('MMI Navigation', () => { context, mainMenuPage.page, 'Privacy policy', - privacyAndPolicy, + privacyAndNotice, ); await checkLinkURL( context, mainMenuPage.page, - 'Learn More', - privacyAndPolicy, + 'requests. Learn more', + learnMoreArticles, ); await mainMenuPage.selectSettings('Experimental'); @@ -153,7 +152,7 @@ test.describe('MMI Navigation', () => { context, mainMenuPage.page, 'Privacy policy', - privacyAndPolicy, + privacyAndNotice, ); await checkLinkURL(context, mainMenuPage.page, 'Terms of use', termsOfUse); await checkLinkURL( diff --git a/test/e2e/mmi/specs/qrCode.spec.ts b/test/e2e/mmi/specs/qrCode.spec.ts new file mode 100644 index 000000000000..23ad4c88e1b4 --- /dev/null +++ b/test/e2e/mmi/specs/qrCode.spec.ts @@ -0,0 +1,65 @@ +import { test } from '../helpers/extension-loader'; +import { ChromeExtensionPage } from '../pageObjects/mmi-extension-page'; +import { MMIMainMenuPage } from '../pageObjects/mmi-mainMenu-page'; +import { MMINetworkPage } from '../pageObjects/mmi-network-page'; +import { MMISignUpPage } from '../pageObjects/mmi-signup-page'; +import { MMIMainPage } from '../pageObjects/mmi-main-page'; +import { MMIAccountMenuPage } from '../pageObjects/mmi-accountMenu-page'; +import { CustodianTestClient } from '../custodian-hooks/hooks'; +import { SEPOLIA_DISPLAY_NAME } from '../helpers/utils'; + +test.describe('QR Code Connection Request', () => { + // @TODO Follow up task to understand why this test fails more times than it passes + test.skip('run the extension and add custodian accounts using the QR Code feature', async ({ + page, + context, + }) => { + const client = new CustodianTestClient(); + await client.setup(); + + // Getting extension id of MMI + const extensions = new ChromeExtensionPage(await context.newPage()); + await extensions.goto(); + await extensions.setDevMode(); + const extensionId = await extensions.getExtensionId(); + await extensions.close(); + + const signUp = new MMISignUpPage( + await context.newPage(), + extensionId as string, + ); + await signUp.goto(); + await signUp.start(); + await signUp.authentication(); + await signUp.info(); + await signUp.close(); + + // Setup testnetwork in settings + const mainMenuPage = new MMIMainMenuPage(page, extensionId as string); + await mainMenuPage.goto(); + await mainMenuPage.fillPassword(); + await mainMenuPage.finishOnboarding(); + await mainMenuPage.selectMenuOption('settings'); + await mainMenuPage.selectSettings('Advance'); + await mainMenuPage.switchTestNetwork(); + await mainMenuPage.closeSettings(); + + // Check network + const networkPage = new MMINetworkPage(page); + await networkPage.open(); + await networkPage.selectNetwork( + process.env.MMI_E2E_TEST_NETWORK || SEPOLIA_DISPLAY_NAME, + ); + + // Get account from and to name + const accountFrom = await client.getAccountFrom(); + + const accountsPopup = new MMIAccountMenuPage(page); + await accountsPopup.accountsMenu(); + await accountsPopup.connectCustodian('Neptune Custody', false, true); + await accountsPopup.selectCustodyAccount(accountFrom); + + const mainPage = new MMIMainPage(page); + await mainPage.bringToFront(); + }); +}); diff --git a/test/e2e/mmi/specs/transactions.spec.ts b/test/e2e/mmi/specs/transactions.spec.ts index 7ada08005851..27583283417b 100644 --- a/test/e2e/mmi/specs/transactions.spec.ts +++ b/test/e2e/mmi/specs/transactions.spec.ts @@ -13,6 +13,7 @@ const sendTransaction = async ( page: Page, context: BrowserContext, client: CustodianTestClient, + repeatTx?: boolean, ) => { // Getting extension id of MMI const extensions = new ChromeExtensionPage(await context.newPage()); @@ -34,6 +35,8 @@ const sendTransaction = async ( // Setup testnetwork in settings const mainMenuPage = new MMIMainMenuPage(page, extensionId as string); await mainMenuPage.goto(); + await mainMenuPage.fillPassword(); + await mainMenuPage.finishOnboarding(); await mainMenuPage.selectMenuOption('settings'); await mainMenuPage.selectSettings('Advance'); await mainMenuPage.switchTestNetwork(); @@ -63,13 +66,28 @@ const sendTransaction = async ( await mainPage.selectMainAction('Send'); await mainPage.sendFunds(accounTo, '0'); + if (repeatTx) { + await mainPage.bringToFront(); + await mainPage.closeCustodyConfirmLink(); + await mainPage.selectMainAction('Send'); + await mainPage.sendFunds(accounTo, '0'); + } + // Check that action took place await mainPage.bringToFront(); + await mainPage.closeCustodyConfirmLink(); await mainPage.openActivityTab(); await mainPage.checkLastTransactionStatus(/created/iu); // Get custodianTxId to mine the transaction const custodianTxId = await mainPage.getCustodianTXId(); - return { mainPage, custodianTxId }; + + // Get the 2nd txId of the 2nd sent transaction + let secondCustodianTxId = ''; + if (repeatTx) { + secondCustodianTxId = await mainPage.getSecondCustodianTXId(); + } + + return { mainPage, custodianTxId, secondCustodianTxId }; }; test.describe('MMI send', () => { @@ -91,6 +109,26 @@ test.describe('MMI send', () => { await mainPage.checkLastTransactionStatus(statusName); }); + test('Send a 2nd transaction while a there is already a pending transaction', async ({ + page, + context, + }) => { + // Setup custodian and auth + const client = new CustodianTestClient(); + await client.setup(); + const repeatTx = true; + const { mainPage, custodianTxId, secondCustodianTxId } = + await sendTransaction(page, context, client, repeatTx); + + // Sign and submit + const statusName = await client.submitTransactionById(custodianTxId); + await mainPage.checkLastTransactionStatus(statusName); + + if (secondCustodianTxId && secondCustodianTxId.length > 0) { + await client.submitTransactionById(secondCustodianTxId); + } + }); + test('Send a transaction from one account to another and abort it from custody', async ({ page, context, diff --git a/test/e2e/mmi/specs/visual.spec.ts b/test/e2e/mmi/specs/visual.spec.ts index 5eb66affec92..9e7b2a424fc4 100644 --- a/test/e2e/mmi/specs/visual.spec.ts +++ b/test/e2e/mmi/specs/visual.spec.ts @@ -5,7 +5,6 @@ import { MMINetworkPage } from '../pageObjects/mmi-network-page'; import { MMISignUpPage } from '../pageObjects/mmi-signup-page'; import { CustodianTestClient } from '../custodian-hooks/hooks'; import { MMIAccountMenuPage } from '../pageObjects/mmi-accountMenu-page'; -import { MMIMainPage } from '../pageObjects/mmi-main-page'; import { SEPOLIA_DISPLAY_NAME } from '../helpers/utils'; test.describe('MMI visual', () => { @@ -30,6 +29,8 @@ test.describe('MMI visual', () => { // Setup testnetwork in settings const mainMenuPage = new MMIMainMenuPage(page, extensionId as string); await mainMenuPage.goto(); + await mainMenuPage.fillPassword(); + await mainMenuPage.finishOnboarding(); await mainMenuPage.selectMenuOption('settings'); await mainMenuPage.selectSettings('Advance'); await mainMenuPage.switchTestNetwork(); @@ -44,14 +45,9 @@ test.describe('MMI visual', () => { const client = new CustodianTestClient(); await client.setup(); - // It will use account A by default - const accounts = await client.getSelectedAccounts(); - const accountA = accounts[0]; - const accountsPopup = new MMIAccountMenuPage(page); await accountsPopup.accountsMenu(); - // await accountsPopup.accountMenuScreenshot('connect_custodian.png'); await accountsPopup.connectCustodian( process.env.MMI_E2E_CUSTODIAN_NAME as string, true, @@ -59,20 +55,8 @@ test.describe('MMI visual', () => { // Check accounts added from Custodian await accountsPopup.accountsMenu(); - // await accountsPopup.accountMenuScreenshot('custody_accounts_selection.png'); // Check remove custodian token screen (aborted before removed) await accountsPopup.removeTokenScreenshot('Custody Account A'); - - // Select custodian accounts - await accountsPopup.selectCustodyAccount(accountA); - - // Check that custodian logo is loaded and account is selected - const mainPage = new MMIMainPage(page); - - await mainPage.mainPageScreenshot( - 'mainWindow_custodian_selected.png', - accountA, - ); }); }); diff --git a/test/e2e/mmi/specs/visual.spec.ts-snapshots/custodian-connection-info-mmi-visual-linux.png b/test/e2e/mmi/specs/visual.spec.ts-snapshots/custodian-connection-info-mmi-visual-linux.png index bc7cc8867ee3..8b628e6b61cc 100644 Binary files a/test/e2e/mmi/specs/visual.spec.ts-snapshots/custodian-connection-info-mmi-visual-linux.png and b/test/e2e/mmi/specs/visual.spec.ts-snapshots/custodian-connection-info-mmi-visual-linux.png differ diff --git a/test/e2e/mmi/specs/visual.spec.ts-snapshots/custodian-list-mmi-visual-linux.png b/test/e2e/mmi/specs/visual.spec.ts-snapshots/custodian-list-mmi-visual-linux.png index fa3f4b7ab9c5..d4a4c717a303 100644 Binary files a/test/e2e/mmi/specs/visual.spec.ts-snapshots/custodian-list-mmi-visual-linux.png and b/test/e2e/mmi/specs/visual.spec.ts-snapshots/custodian-list-mmi-visual-linux.png differ diff --git a/test/e2e/mmi/specs/visual.spec.ts-snapshots/mainWindow-custodian-selected-mmi-visual-linux.png b/test/e2e/mmi/specs/visual.spec.ts-snapshots/mainWindow-custodian-selected-mmi-visual-linux.png index 507e6f1e8971..4254768bc46b 100644 Binary files a/test/e2e/mmi/specs/visual.spec.ts-snapshots/mainWindow-custodian-selected-mmi-visual-linux.png and b/test/e2e/mmi/specs/visual.spec.ts-snapshots/mainWindow-custodian-selected-mmi-visual-linux.png differ diff --git a/test/e2e/mock-cdn/cdn-config-res-headers.json b/test/e2e/mock-cdn/cdn-config-res-headers.json new file mode 100644 index 000000000000..7b0e37a92449 --- /dev/null +++ b/test/e2e/mock-cdn/cdn-config-res-headers.json @@ -0,0 +1,3 @@ +{ + "Etag": "bb28e40153ff052671b8ad835d368d89" +} diff --git a/test/e2e/mock-cdn/cdn-config.txt b/test/e2e/mock-cdn/cdn-config.txt new file mode 100644 index 000000000000..b05273585ff5 Binary files /dev/null and b/test/e2e/mock-cdn/cdn-config.txt differ diff --git a/test/e2e/mock-cdn/cdn-stale-diff-res-headers.json b/test/e2e/mock-cdn/cdn-stale-diff-res-headers.json new file mode 100644 index 000000000000..b3c558ff1cdd --- /dev/null +++ b/test/e2e/mock-cdn/cdn-stale-diff-res-headers.json @@ -0,0 +1,3 @@ +{ + "Etag": "W/\"ece7f5f533b8978063633ea5b1f8a0fc\"" +} diff --git a/test/e2e/mock-cdn/cdn-stale-diff.txt b/test/e2e/mock-cdn/cdn-stale-diff.txt new file mode 100644 index 000000000000..02e2bae35ce5 Binary files /dev/null and b/test/e2e/mock-cdn/cdn-stale-diff.txt differ diff --git a/test/e2e/mock-cdn/cdn-stale-res-headers.json b/test/e2e/mock-cdn/cdn-stale-res-headers.json new file mode 100644 index 000000000000..bb2df028661c --- /dev/null +++ b/test/e2e/mock-cdn/cdn-stale-res-headers.json @@ -0,0 +1,3 @@ +{ + "Etag": "W/\"b89ab99b0801b5d64acb27893a2b31ca\"" +} diff --git a/test/e2e/mock-cdn/cdn-stale.txt b/test/e2e/mock-cdn/cdn-stale.txt new file mode 100644 index 000000000000..39e3f2b9ea1b Binary files /dev/null and b/test/e2e/mock-cdn/cdn-stale.txt differ diff --git a/test/e2e/mock-cdn/ppom-version-headers.json b/test/e2e/mock-cdn/ppom-version-headers.json new file mode 100644 index 000000000000..a29a05e8c360 --- /dev/null +++ b/test/e2e/mock-cdn/ppom-version-headers.json @@ -0,0 +1,3 @@ +{ + "Etag": "W/\"9f5df4118b061a89ac013422f809de72\"" +} diff --git a/test/e2e/mock-cdn/ppom-version.json b/test/e2e/mock-cdn/ppom-version.json new file mode 100644 index 000000000000..e06e6705218b --- /dev/null +++ b/test/e2e/mock-cdn/ppom-version.json @@ -0,0 +1,302 @@ +[ + { + "name": "stale", + "chainId": "0x144", + "version": "0.0.11", + "checksum": "b4731bb258fec747bf9394d4c21096dd27d498e6ada6c1a871d0407f63f9c2d3", + "signature": "49fa6b11db8114a4520343544d829753c0eedd156f15c168dd8e31a8ddc25c10c16d9203bdd5d0872610a805d7e37a26b79bf399d1c2d5037f6ebd02ac6d0306", + "hashSignature": "7a7d72a4214317738b3b91c3245a8ef8ac0f5bac247c369212c79db763ef78b1a5001f892edf41c2b619f28c326541ecd76e9bbe7db444a6d2898ab408832507", + "filePath": "stale/0x144/0.0.11", + "timestamp": "2024-03-06T11:05:22.120889" + }, + { + "name": "stale_diff", + "chainId": "0x144", + "version": "0.0.77", + "checksum": "69b726f5ae8567cd566c6bf30dea3692ffb159d1d61dcdf081298c7023635be9", + "signature": "5a5110480d0d63e35900a1e5e09d253f644a1b481c3461e0ffc8dc614dca67838cc7051e304e23ad8cf9e2b74b9e129724253da4f1239140d8474d59400b7502", + "hashSignature": "846d71a01cc094b1940cdedba0cf1e5b2d324eaca41a55d9825f759f67572f43fcc2d29bd894f66d906eebae0fe49922db5d02948748880e9ecb7a884a17b901", + "filePath": "stale_diff/0x144/0.0.77", + "timestamp": "2024-03-10T11:34:07.732508" + }, + { + "name": "config", + "chainId": "0x144", + "version": "0.0.77", + "checksum": "3e1772693c4e2fa91ae00c4b79d546f36e97525daa60baab372c145e979e19f4", + "signature": "f56c9387e07892aceb1018db6dc7e32cce0528c131b6ac1822e12e87dd43d40fdb9f3e17a9c6d7fd25a095e000db19acaf3f93c42142c48f35b06f07998f0f0e", + "hashSignature": "ae3fbbe3f87e48e537e9c1c9601fa5706ed72145250e5f4a2d7a4902d59e2c770c7c1ef88bde15505fa6bcbf24f85ef1b5ad48b76447a3479f7f7a462f082302", + "filePath": "config/0x144/0.0.77", + "timestamp": "2024-03-10T11:34:07.732733" + }, + { + "name": "stale", + "chainId": "0x38", + "version": "0.0.38", + "checksum": "99776fbf3527ad357f0772a48585750aa9dfe3ff006a4eb8788ca5cde3dfa6e9", + "signature": "e592080cca99f769f602d94b774fe7905c9e53e9be3f2bc172c0bfd9d0a641083fb735add7cfe5734d3252e217ca63a0b4fbcde6b4376c0ee6a21ce9d07ee700", + "hashSignature": "def291f8e687284afec51cfe8e4ebd9f260078f4ac0804742c31f7444a6d7ba055ab485d227707826761d8c97cba1f6bc08cb5e8fb7e9fb5fdcf1aa8190cc901", + "filePath": "stale/0x38/0.0.38", + "timestamp": "2024-03-20T21:00:30.533909" + }, + { + "name": "stale", + "chainId": "0x1", + "version": "0.0.52", + "checksum": "20c1449b660f32d7c8e03b0170c79878879cd9ba40fd84374bb7d86cd82a8e6b", + "signature": "9d5f4e433156ddaec3d34361b3bef4c0147c464e6810c6d5c45a0b179227f97d8ed03bc847330eb7d529cc4b5320a8a3602522820d2b44ec2928c227ed7cb700", + "hashSignature": "fd98b80b18a774c64f8bc3a48cbbd1fdd948af320dd14e229c1c2587c5ca6199cb7782989f3edc783e1534b8db2bd758b83898c12899aaf43cf319f112a07e05", + "filePath": "stale/0x1/0.0.52", + "timestamp": "2024-03-20T21:00:43.282213" + }, + { + "name": "stale", + "chainId": "0x89", + "version": "0.0.38", + "checksum": "b484bd673cd5eec0724fb22c36ba39c9ccc9721401be07fb273f27ec020bfb4a", + "signature": "7392aeb07bba7034fffe308e316f424c48bf868051b655114b63cb36038d4495d190c8daadf33b815bee9bced838aadcf2eb49cbf177d6ab38ae97b6475f7f03", + "hashSignature": "48b8e01132ffdbdd01439dd0e1d8c443bb4c2b88c29d1b9132bb107b0890d246ea73fd55ac2be3bdd0b4922400f5930d3335aafadd2141b6049f1caa1ec59d00", + "filePath": "stale/0x89/0.0.38", + "timestamp": "2024-03-20T21:00:56.806406" + }, + { + "name": "stale", + "chainId": "0xa", + "version": "0.0.38", + "checksum": "7408b4f44e86e19025549c3e165f7d528f856ed3473a6efddf3d2577251d3544", + "signature": "fd0e9a82564802155a6bc13f34363dddc99ca2a3468e3f0e7b00360ee5008f6f2a30dd47771b69352fa1c4323deae756c46fc03508dc39ccccda3fb8678d7f09", + "hashSignature": "9aab8ca37a8cf0797d55c0b655e280e527751a9739766e8d2edd6c45b18dabe09f0ee66518f59a4112b45e74d5c047af7b39380a0e3f700a41d1680f24b6ad06", + "filePath": "stale/0xa/0.0.38", + "timestamp": "2024-03-20T21:01:06.639827" + }, + { + "name": "stale", + "chainId": "0xa4b1", + "version": "0.0.38", + "checksum": "642573df1c81669619be1bda27c1659bb730a201824f0470495d38c08acabd70", + "signature": "4d8b6c51d8f9205ce173cde3dab150ad6653f48dc2ca59c3f1beb5e574430404f8b9c03f701dc9160a56f93a35560cd57b49edef6e3f65ea71ea6bfbf21c2b0b", + "hashSignature": "4e07a1c1b15353e2a5f2c7bd35525f47cd9405f740a89a2faa5ea7096edc7278a272aed383341eaee413673a45cd8d6e042fd784493cafee2699fe01229a0b04", + "filePath": "stale/0xa4b1/0.0.38", + "timestamp": "2024-03-20T21:01:16.670454" + }, + { + "name": "stale", + "chainId": "0xa86a", + "version": "0.0.38", + "checksum": "94982df19575b44a03f3f620bb75fb673b35535e6fede1e542dfbc2166984e5c", + "signature": "d59c6d65721e7003b83870af71152559c5170fff2c81b073faf3618c344063079d2551d5d2dcd310af58a840120aa6dc1e8eba2d83c7a6eb1fd61e58999b900f", + "hashSignature": "22c6d339c1957909b68922c31c015852175e494b6db191b2d1e52612c492ec22d25dfe111eb8cd99131ae245b36aa9f9dfa989cc4d437940893c0c8d2157580a", + "filePath": "stale/0xa86a/0.0.38", + "timestamp": "2024-03-20T21:01:28.762015" + }, + { + "name": "stale", + "chainId": "0xe708", + "version": "0.0.28", + "checksum": "a05a57016325ea3fd2663ec61e2d2a28fff07c7cc1fd653fb0d38867b4a40b6c", + "signature": "079268869c98b0552129a9aaadb08dd4ff2cc828344365eab8bdb579f6f204cc51515d4eacc034f18fab2df64c82f7d84bec668e80a10e5b4e389eabbf8b3e03", + "hashSignature": "175b783790515ccd4446cd17c44c4877fd48a54b51d0da44fc7f861eedad275f87c425f6dcf9a1e6061c0d56eafe118e6332ce3dedf9ed4ae6951a016a392600", + "filePath": "stale/0xe708/0.0.28", + "timestamp": "2024-03-20T21:01:38.871229" + }, + { + "name": "stale", + "chainId": "0x2105", + "version": "0.0.16", + "checksum": "d92e7360c8504e6be5b124ba6f53030b286d64ccb050252589324ea49060ef60", + "signature": "85c7c0ad4a293e64738c722e3fe52d7d59c35c7d6cb306c54797767664aa7e47fbc9f52b4dfdf25495fe4e22acf399feacabbc8a2b9dd4eb0a0e8855ee9af607", + "hashSignature": "c93d06cea4f28a602c7871e0b946b528835900aac603187c877153dbc31aceb7fe6cdb17e03558718e62b7a001cc71aef4508098a808bc83b889e91d0fda0501", + "filePath": "stale/0x2105/0.0.16", + "timestamp": "2024-03-20T21:01:47.120043" + }, + { + "name": "stale", + "chainId": "0xaa36a7", + "version": "0.0.5", + "checksum": "fa8f9b03fb688da8dc98c0e38f49f05ca1a644609742d7e2b37373d4fa56b961", + "signature": "a9473d0b8659be8332f7b2e04c530bdef5f52a24c5aeb8cdbbe8ed83daa50e97878cebd4db0280b715d8c9a4c23390e30edf2bda990a699b52dbb3514ac2e805", + "hashSignature": "a8ef8f5ccff133430cf2a660c6a9522c674cc62aade0326d71063b5d43480d05c31780cbc027e2eda281e29cf0f3b94188c9584e5e92ba21d91b9ae27056040d", + "filePath": "stale/0xaa36a7/0.0.5", + "timestamp": "2024-03-20T21:01:55.297706" + }, + { + "name": "stale_diff", + "chainId": "0x38", + "version": "0.0.217", + "checksum": "5a73bfc69701257e3e56a8d4b47d0f17888aaa5a615ce383ad5119d6766d9133", + "signature": "59f489f4680ce4782f68e3c00a011346a366d6bd1b2e5d3de5147680317fe40d05160ffd4976b021ad89c20bc3ef4b4212a0ce70d3859dd281bdeded42204a05", + "hashSignature": "85a82f9d2adf7dd9c9a186ab936c84a71d79818f4612d8410c04670396d62118b313f9914da17bc8299c8617dcd301a38e2dafe086943f1d5eca4622a466e50c", + "filePath": "stale_diff/0x38/0.0.217", + "timestamp": "2024-03-21T12:13:14.798558" + }, + { + "name": "config", + "chainId": "0x38", + "version": "0.0.217", + "checksum": "3e1772693c4e2fa91ae00c4b79d546f36e97525daa60baab372c145e979e19f4", + "signature": "f56c9387e07892aceb1018db6dc7e32cce0528c131b6ac1822e12e87dd43d40fdb9f3e17a9c6d7fd25a095e000db19acaf3f93c42142c48f35b06f07998f0f0e", + "hashSignature": "ae3fbbe3f87e48e537e9c1c9601fa5706ed72145250e5f4a2d7a4902d59e2c770c7c1ef88bde15505fa6bcbf24f85ef1b5ad48b76447a3479f7f7a462f082302", + "filePath": "config/0x38/0.0.217", + "timestamp": "2024-03-21T12:13:14.798803" + }, + { + "name": "stale_diff", + "chainId": "0x1", + "version": "0.0.260", + "checksum": "fdfde4e2d19c7cbfc307924ee49b277888bfe644dadcf2dc646e4828739adda0", + "signature": "e54483a98adf96e5f16134400a2bb7dc23693de2509a878c50e6fd0ff531f1c13e2f8fdeb58e63f5e47c2497ae5dd8c904c7456456e05bad37758a40d356710f", + "hashSignature": "7f047374e55203d2e0e52257fa9b8fa2c455e27a01f131956063156335476bd0c925a8f60506820861b4a18335835bdddf1be99486aa45df331514d72b22aa0c", + "filePath": "stale_diff/0x1/0.0.260", + "timestamp": "2024-03-21T12:13:18.827919" + }, + { + "name": "config", + "chainId": "0x1", + "version": "0.0.260", + "checksum": "29771bc6544e0d66898eb727ed1b4db478b33e8e45be560de84880c2433ebca2", + "signature": "1a501372b5bd9ac95accd6bf8caeec08425f3e826f100e3ca9df1dff8a861d713207e387676ed64df920ac4682888da76bde534157d71ec270e28e66b033290e", + "hashSignature": "a1cb93bea92cfbe79dd2d9023e0f7b748f0f370c97f2eabdb00a215b39dcac7a32614aa2729dcefe2a7c57a6bce78c934187a3ea443944b13b4da2fa7ee5ac0a", + "filePath": "config/0x1/0.0.260", + "timestamp": "2024-03-21T12:13:18.828225" + }, + { + "name": "stale_diff", + "chainId": "0x89", + "version": "0.0.216", + "checksum": "d38399d82b0615fbada643872c7dfc7debf183cc1634d643ce608f8c8ffc5d20", + "signature": "89506ef81561309831f4a27cac0d330c8d14607fd646906391c73fccecb4b399931b81e29c2358747414fccee9cb774d936c8d32d8b55f3f3f0adca750f8e805", + "hashSignature": "72cdb5e05f4b1da1ed80140457e7d130beaf8eb6be864847e01befecc6bd619db5ff924578d4b127f82548766ee4b7ac49256026b2012f923fceb0bef0e6300e", + "filePath": "stale_diff/0x89/0.0.216", + "timestamp": "2024-03-21T12:13:22.608506" + }, + { + "name": "config", + "chainId": "0x89", + "version": "0.0.216", + "checksum": "d75160f71081e7fe387344f51fb48251b8e7a91e7690be97ee845967494dfd86", + "signature": "78a82de98e2ac84c47d392296625679504f327263b3ace3b96686be3a443b76a0ae4e5cfb38962d3024e73250fe8479b423af21cc28b09defbc20f0285d60e04", + "hashSignature": "16840dddb6f35de35dd57159056217d947d7bc242cedc60eff3ccad664ed952f2287f19ee6a0413c929299afcd04447c217494c9bb2c433879f6c2ea66e69c03", + "filePath": "config/0x89/0.0.216", + "timestamp": "2024-03-21T12:13:22.608797" + }, + { + "name": "stale_diff", + "chainId": "0xa", + "version": "0.0.216", + "checksum": "4d44ce4c9c9e8b12ee5cc696b21f6409429d9f55cdc703c5acf799836c80ad8a", + "signature": "679813ccd33b254e88c19421e95a93e16c1db4fa473b8f9a510df7fe9ca56c7c0f21b303660d2e1175b1dc47c40aaa4fa989e710cfc2a432ad65cb7d0a522c0a", + "hashSignature": "ab86ad1046968599d8d85e0417e504c05f8bd87051ab4edee46a7946699f21e827bce2093dc94aee7f6746bb25413f819b4ca19950022fa0f8ed80efde0d2902", + "filePath": "stale_diff/0xa/0.0.216", + "timestamp": "2024-03-21T12:13:26.693599" + }, + { + "name": "config", + "chainId": "0xa", + "version": "0.0.216", + "checksum": "3e1772693c4e2fa91ae00c4b79d546f36e97525daa60baab372c145e979e19f4", + "signature": "f56c9387e07892aceb1018db6dc7e32cce0528c131b6ac1822e12e87dd43d40fdb9f3e17a9c6d7fd25a095e000db19acaf3f93c42142c48f35b06f07998f0f0e", + "hashSignature": "ae3fbbe3f87e48e537e9c1c9601fa5706ed72145250e5f4a2d7a4902d59e2c770c7c1ef88bde15505fa6bcbf24f85ef1b5ad48b76447a3479f7f7a462f082302", + "filePath": "config/0xa/0.0.216", + "timestamp": "2024-03-21T12:13:26.693846" + }, + { + "name": "stale_diff", + "chainId": "0xa4b1", + "version": "0.0.216", + "checksum": "837ea3eef03c7a5a9975e5435581d6d051c5b4bd9a60e726ab044c8f7d911c7c", + "signature": "1c8252591e29761981ca792e2fb5e8c611906a7a136f8ac09e5fe0290ac3106cf425f0d38bc579739f09dba6ea4b9de50a77202f6d11e6b24e1f4d242af83603", + "hashSignature": "ffb5d7f443682e36b2928bccfe8919ecfb591b2cbf8cda82440332aec5927d39a3521c93fb7a39db20516a70a5dc101fddbc4548dabd1ee221fc754ca4c5040c", + "filePath": "stale_diff/0xa4b1/0.0.216", + "timestamp": "2024-03-21T12:13:31.844985" + }, + { + "name": "config", + "chainId": "0xa4b1", + "version": "0.0.216", + "checksum": "3e1772693c4e2fa91ae00c4b79d546f36e97525daa60baab372c145e979e19f4", + "signature": "f56c9387e07892aceb1018db6dc7e32cce0528c131b6ac1822e12e87dd43d40fdb9f3e17a9c6d7fd25a095e000db19acaf3f93c42142c48f35b06f07998f0f0e", + "hashSignature": "ae3fbbe3f87e48e537e9c1c9601fa5706ed72145250e5f4a2d7a4902d59e2c770c7c1ef88bde15505fa6bcbf24f85ef1b5ad48b76447a3479f7f7a462f082302", + "filePath": "config/0xa4b1/0.0.216", + "timestamp": "2024-03-21T12:13:31.845230" + }, + { + "name": "stale_diff", + "chainId": "0xa86a", + "version": "0.0.216", + "checksum": "a4b8a87b84c93d03c1e51e83046edcda608be70d32924bad82aa3f93a0633f0c", + "signature": "be4cf087a3491184a4702cb9d4368775df68651735e050e2f2b16845376b87986ed24b00cde91a0d1a5739ddde513d9c9e97949b26ce96cb71b657c7e4d24a04", + "hashSignature": "0a74a14fa27289d347db514bfd11d2edb281cc6cf1bd7917705430dd7b4d97b245daa78bdcc07b74bd519619518432c7658d9c3e17b7def5e948655c9222f606", + "filePath": "stale_diff/0xa86a/0.0.216", + "timestamp": "2024-03-21T12:13:36.520723" + }, + { + "name": "config", + "chainId": "0xa86a", + "version": "0.0.216", + "checksum": "3e1772693c4e2fa91ae00c4b79d546f36e97525daa60baab372c145e979e19f4", + "signature": "f56c9387e07892aceb1018db6dc7e32cce0528c131b6ac1822e12e87dd43d40fdb9f3e17a9c6d7fd25a095e000db19acaf3f93c42142c48f35b06f07998f0f0e", + "hashSignature": "ae3fbbe3f87e48e537e9c1c9601fa5706ed72145250e5f4a2d7a4902d59e2c770c7c1ef88bde15505fa6bcbf24f85ef1b5ad48b76447a3479f7f7a462f082302", + "filePath": "config/0xa86a/0.0.216", + "timestamp": "2024-03-21T12:13:36.520972" + }, + { + "name": "stale_diff", + "chainId": "0xe708", + "version": "0.0.170", + "checksum": "79ed396331e95cfb34b5e14fce09b23c2059d78ada026cc38dc8f1119b793cee", + "signature": "8ae4be3b31e45eab20c4c0a177cd68ccba4293f790702392da02f840398e8da3525e69fb129c3c600c28c6dd773abfbe368a9b02c37076e82a67a906fc712e09", + "hashSignature": "9b3bacc5d3e9c50e711b8b0fd9e50dde38cc93c0fcde468efe8cac03e3b3b3fe818cfa105029b0fcac8ecc9c03c4c4833ad5da0fce9ed2b80e9d762640a2410b", + "filePath": "stale_diff/0xe708/0.0.170", + "timestamp": "2024-03-21T12:13:41.925924" + }, + { + "name": "config", + "chainId": "0xe708", + "version": "0.0.170", + "checksum": "3e1772693c4e2fa91ae00c4b79d546f36e97525daa60baab372c145e979e19f4", + "signature": "f56c9387e07892aceb1018db6dc7e32cce0528c131b6ac1822e12e87dd43d40fdb9f3e17a9c6d7fd25a095e000db19acaf3f93c42142c48f35b06f07998f0f0e", + "hashSignature": "ae3fbbe3f87e48e537e9c1c9601fa5706ed72145250e5f4a2d7a4902d59e2c770c7c1ef88bde15505fa6bcbf24f85ef1b5ad48b76447a3479f7f7a462f082302", + "filePath": "config/0xe708/0.0.170", + "timestamp": "2024-03-21T12:13:41.926309" + }, + { + "name": "stale_diff", + "chainId": "0x2105", + "version": "0.0.105", + "checksum": "e9135ad2c08b3b0349db7e2decb871598251680d81c320718ac59de91b0cfcc8", + "signature": "e47d5f9afdd1c0557cdc020692d80bc844477c8407392ab860ce8b1efb95e2c303695699d6a464dfe071685d87990bbfceb1ab166bffff795c883444543b9404", + "hashSignature": "58224a7946eea888848a9305189c080f4eab04aca4be0bd69b08a799c7cb3c8595dcd354e021fccfd4c304465d94819dd1978e8dd898938d1391dfb508735e08", + "filePath": "stale_diff/0x2105/0.0.105", + "timestamp": "2024-03-21T12:13:47.580538" + }, + { + "name": "config", + "chainId": "0x2105", + "version": "0.0.105", + "checksum": "3e1772693c4e2fa91ae00c4b79d546f36e97525daa60baab372c145e979e19f4", + "signature": "f56c9387e07892aceb1018db6dc7e32cce0528c131b6ac1822e12e87dd43d40fdb9f3e17a9c6d7fd25a095e000db19acaf3f93c42142c48f35b06f07998f0f0e", + "hashSignature": "ae3fbbe3f87e48e537e9c1c9601fa5706ed72145250e5f4a2d7a4902d59e2c770c7c1ef88bde15505fa6bcbf24f85ef1b5ad48b76447a3479f7f7a462f082302", + "filePath": "config/0x2105/0.0.105", + "timestamp": "2024-03-21T12:13:47.580833" + }, + { + "name": "stale_diff", + "chainId": "0xaa36a7", + "version": "0.0.24", + "checksum": "501048a17060b390dd5f6d3556dfae356299f2e1761170c5e77f71ae304b38a5", + "signature": "453422760071953f014675c10e7b540474847a7901d078aa892c1ea6cde2f669209772042b73573943cb3b123ae4ea4c48b3bda285a13262ec93e4acffe51e07", + "hashSignature": "4e1a3c0e259dfa4ee5bdfc9580a3d53c817229bb076b2ff90ad63cf7db5444073e1257a27f8be0cce7825f8824fe6a3f698c77f4f24d156b52d019bec155460c", + "filePath": "stale_diff/0xaa36a7/0.0.24", + "timestamp": "2024-03-21T12:13:51.767514" + }, + { + "name": "config", + "chainId": "0xaa36a7", + "version": "0.0.24", + "checksum": "3e1772693c4e2fa91ae00c4b79d546f36e97525daa60baab372c145e979e19f4", + "signature": "f56c9387e07892aceb1018db6dc7e32cce0528c131b6ac1822e12e87dd43d40fdb9f3e17a9c6d7fd25a095e000db19acaf3f93c42142c48f35b06f07998f0f0e", + "hashSignature": "ae3fbbe3f87e48e537e9c1c9601fa5706ed72145250e5f4a2d7a4902d59e2c770c7c1ef88bde15505fa6bcbf24f85ef1b5ad48b76447a3479f7f7a462f082302", + "filePath": "config/0xaa36a7/0.0.24", + "timestamp": "2024-03-21T12:13:51.767758" + } +] diff --git a/test/e2e/mock-cdn/update-mock-cdn-files.js b/test/e2e/mock-cdn/update-mock-cdn-files.js new file mode 100644 index 000000000000..5fa2d7cc51a5 --- /dev/null +++ b/test/e2e/mock-cdn/update-mock-cdn-files.js @@ -0,0 +1,127 @@ +const util = require('util'); +const { writeFileSync } = require('fs'); + +const exec = util.promisify(require('node:child_process').exec); + +const PPOM_VERSION_URL = + 'https://static.cx.metamask.io/api/v1/confirmations/ppom/ppom_version.json'; +const PPOM_CONFIG_URL = + 'https://static.cx.metamask.io/api/v1/confirmations/ppom/config/0x1/'; +const PPOM_STALE_URL = + 'https://static.cx.metamask.io/api/v1/confirmations/ppom/stale/0x1/'; +const PPOM_STALE_DIFF_URL = + 'https://static.cx.metamask.io/api/v1/confirmations/ppom/stale_diff/0x1/'; +const MOCK_CDN_FOLDER_URL = 'test/e2e/mock-cdn/'; + +const CDN_CONFIG_PATH = 'test/e2e/mock-cdn/cdn-config.txt'; +const CDN_STALE_DIFF_PATH = 'test/e2e/mock-cdn/cdn-stale-diff.txt'; +const CDN_STALE_PATH = 'test/e2e/mock-cdn/cdn-stale.txt'; + +async function getFileVersions() { + let ppomVersionData; + + ppomVersionData = await fetch(PPOM_VERSION_URL, { + method: 'GET', + }); + + const ppomVersionDataHeaders = ppomVersionData.headers; + ppomVersionData = await ppomVersionData.json(); + + const etagVersion = ppomVersionDataHeaders.get('etag'); + const etagVersionObject = { Etag: etagVersion }; + + // updating ppom-version-headers.json file + writeFileSync( + `${MOCK_CDN_FOLDER_URL}ppom-version-headers.json`, + JSON.stringify(etagVersionObject, null, 2), + ); + + // updating ppom-version.json file + writeFileSync( + `${MOCK_CDN_FOLDER_URL}ppom-version.json`, + JSON.stringify(ppomVersionData, null, 2), + ); + + const mainnetConfigVersion = ppomVersionData.find( + (item) => item.name === 'config' && item.chainId === '0x1', + ).version; + + const mainnetStaleVersion = ppomVersionData.find( + (item) => item.name === 'stale' && item.chainId === '0x1', + ).version; + + const mainnetStaleDiffVersion = ppomVersionData.find( + (item) => item.name === 'stale_diff' && item.chainId === '0x1', + ).version; + + return { + mainnetConfigVersion, + mainnetStaleVersion, + mainnetStaleDiffVersion, + }; +} + +async function updateMockCdnFiles() { + const { mainnetConfigVersion, mainnetStaleVersion, mainnetStaleDiffVersion } = + await getFileVersions(); + + // updating cdn-config-res-headers.json file + const configResponse = await fetch( + `${PPOM_CONFIG_URL}${mainnetConfigVersion}`, + { + method: 'GET', + }, + ); + + const configHeaders = configResponse.headers; + + const etagConfig = configHeaders.get('etag'); + const etagConfigObject = { Etag: etagConfig }; + + writeFileSync( + `${MOCK_CDN_FOLDER_URL}cdn-config-res-headers.json`, + JSON.stringify(etagConfigObject, null, 2), + ); + + // updating cdn-stale-res-headers.json file + const staleResponse = await fetch(`${PPOM_STALE_URL}${mainnetStaleVersion}`, { + method: 'GET', + }); + + const staleHeaders = staleResponse.headers; + + const etagStale = staleHeaders.get('etag'); + const etagStaleObject = { Etag: etagStale }; + + writeFileSync( + `${MOCK_CDN_FOLDER_URL}cdn-stale-res-headers.json`, + JSON.stringify(etagStaleObject, null, 2), + ); + + // updating cdn-stale-diff-res-headers.json file + const staleDiffResponse = await fetch( + `${PPOM_STALE_DIFF_URL}${mainnetStaleDiffVersion}`, + { + method: 'GET', + }, + ); + + const staleDiffHeaders = staleDiffResponse.headers; + + const etagStaleDiff = staleDiffHeaders.get('etag'); + const etagStaleDiffObject = { Etag: etagStaleDiff }; + + writeFileSync( + `${MOCK_CDN_FOLDER_URL}cdn-stale-diff-res-headers.json`, + JSON.stringify(etagStaleDiffObject, null, 2), + ); + + // exporting the brotli data to files + exec(`curl ${PPOM_CONFIG_URL}${mainnetConfigVersion} -o ${CDN_CONFIG_PATH}`); + exec(`curl ${PPOM_STALE_URL}${mainnetStaleVersion} -o ${CDN_STALE_PATH}`); + exec( + `curl ${PPOM_STALE_DIFF_URL}${mainnetStaleDiffVersion} -o ${CDN_STALE_DIFF_PATH}`, + ); +} + +updateMockCdnFiles(); diff --git a/test/e2e/mock-e2e.js b/test/e2e/mock-e2e.js index fd00bd914bbf..f3279377114d 100644 --- a/test/e2e/mock-e2e.js +++ b/test/e2e/mock-e2e.js @@ -1,4 +1,27 @@ -const { GAS_API_BASE_URL } = require('../../shared/constants/swaps'); +const fs = require('fs'); + +const { + GAS_API_BASE_URL, + SWAPS_API_V2_BASE_URL, + TOKEN_API_BASE_URL, +} = require('../../shared/constants/swaps'); + +const CDN_CONFIG_PATH = 'test/e2e/mock-cdn/cdn-config.txt'; +const CDN_STALE_DIFF_PATH = 'test/e2e/mock-cdn/cdn-stale-diff.txt'; +const CDN_STALE_PATH = 'test/e2e/mock-cdn/cdn-stale.txt'; +const PPOM_VERSION_PATH = 'test/e2e/mock-cdn/ppom-version.json'; +const PPOM_VERSION_HEADERS_PATH = 'test/e2e/mock-cdn/ppom-version-headers.json'; + +const CDN_CONFIG_RES_HEADERS_PATH = + 'test/e2e/mock-cdn/cdn-config-res-headers.json'; +const CDN_STALE_DIFF_RES_HEADERS_PATH = + 'test/e2e/mock-cdn/cdn-stale-diff-res-headers.json'; +const CDN_STALE_RES_HEADERS_PATH = + 'test/e2e/mock-cdn/cdn-stale-res-headers.json'; + +const AGGREGATOR_METADATA_PATH = + 'test/e2e/mock-response-data/aggregator-metadata.json'; +const TOKEN_BLOCKLIST_PATH = 'test/e2e/mock-response-data/token-blocklist.json'; const blacklistedHosts = [ 'arbitrum-mainnet.infura.io', @@ -9,6 +32,7 @@ const blacklistedHosts = [ const { mockEmptyStalelistAndHotlist, } = require('./tests/phishing-controller/mocks'); +const { mockNotificationServices } = require('./tests/notifications/mocks'); const emptyHtmlPage = () => ` @@ -49,9 +73,14 @@ const browserAPIRequestDomains = * @param {(server: Mockttp) => MockedEndpoint} testSpecificMock - A function for setting up test-specific network mocks * @param {object} options - Network mock options. * @param {string} options.chainId - The chain ID used by the default configured network. + * @param {string} options.ethConversionInUsd - The USD conversion rate for ETH. * @returns {SetupMockReturn} */ -async function setupMocking(server, testSpecificMock, { chainId }) { +async function setupMocking( + server, + testSpecificMock, + { chainId, ethConversionInUsd = '1700' }, +) { const privacyReport = new Set(); await server.forAnyRequest().thenPassThrough({ beforeRequest: (req) => { @@ -176,7 +205,7 @@ async function setupMocking(server, testSpecificMock, { chainId }) { }); await server - .forGet('https://swap.metaswap.codefi.network/networks/1/token') + .forGet(`${SWAPS_API_V2_BASE_URL}/networks/1/token`) .withQuery({ address: '0x72c9Fb7ED19D3ce51cea5C56B3e023cd918baaDf' }) .thenCallback(() => { return { @@ -228,7 +257,7 @@ async function setupMocking(server, testSpecificMock, { chainId }) { }); await server - .forGet('https://swap.metaswap.codefi.network/featureFlags') + .forGet(`${SWAPS_API_V2_BASE_URL}/featureFlags`) .thenCallback(() => { return { statusCode: 200, @@ -265,7 +294,7 @@ async function setupMocking(server, testSpecificMock, { chainId }) { }); await server - .forGet(`https://token-api.metaswap.codefi.network/tokens/${chainId}`) + .forGet(`https://token.api.cx.metamask.io/tokens/${chainId}`) .thenCallback(() => { return { statusCode: 200, @@ -290,12 +319,65 @@ async function setupMocking(server, testSpecificMock, { chainId }) { ], occurrences: 9, }, + { + address: '0x6b175474e89094c44da98b954eedeac495271d0f', + symbol: 'DAI', + decimals: 18, + name: 'Dai Stablecoin', + iconUrl: + 'https://raw.githubusercontent.com/MetaMask/contract-metadata/master/images/dai.svg', + type: 'erc20', + aggregators: [ + 'metamask', + 'aave', + 'bancor', + 'cmc', + 'cryptocom', + 'coinGecko', + 'oneInch', + 'pmm', + 'sushiswap', + 'zerion', + 'lifi', + 'socket', + 'squid', + 'openswap', + 'sonarwatch', + 'uniswapLabs', + 'coinmarketcap', + ], + occurrences: 17, + erc20Permit: true, + fees: { '0xb0da5965d43369968574d399dbe6374683773a65': 0 }, + storage: { balance: 2 }, + }, ], }; }); + const TOKEN_BLOCKLIST = fs.readFileSync(TOKEN_BLOCKLIST_PATH); await server - .forGet('https://swap.metaswap.codefi.network/networks/1/tokens') + .forGet(`${TOKEN_API_BASE_URL}/blocklist`) + .withQuery({ chainId: '1', region: 'global' }) + .thenCallback(() => { + return { + statusCode: 200, + json: JSON.parse(TOKEN_BLOCKLIST), + }; + }); + + const AGGREGATOR_METADATA = fs.readFileSync(AGGREGATOR_METADATA_PATH); + await server + .forGet(`${SWAPS_API_V2_BASE_URL}/networks/1/aggregatorMetadata`) + .thenCallback(() => { + return { + statusCode: 200, + json: JSON.parse(AGGREGATOR_METADATA), + }; + }); + + await server + .forGet(`${SWAPS_API_V2_BASE_URL}/networks/1/tokens`) .thenCallback(() => { return { statusCode: 200, @@ -306,7 +388,7 @@ async function setupMocking(server, testSpecificMock, { chainId }) { decimals: 18, type: 'native', iconUrl: - 'https://token.metaswap.codefi.network/assets/nativeCurrencyLogos/ethereum.svg', + 'https://token.api.cx.metamask.io/assets/nativeCurrencyLogos/ethereum.svg', coingeckoId: 'ethereum', address: '0x0000000000000000000000000000000000000000', occurrences: 100, @@ -379,7 +461,7 @@ async function setupMocking(server, testSpecificMock, { chainId }) { }); await server - .forGet('https://swap.metaswap.codefi.network/networks/1/topAssets') + .forGet(`${SWAPS_API_V2_BASE_URL}/networks/1/topAssets`) .thenCallback(() => { return { statusCode: 200, @@ -405,7 +487,7 @@ async function setupMocking(server, testSpecificMock, { chainId }) { }); await server - .forGet(`https://token-api.metaswap.codefi.network/token/${chainId}`) + .forGet(`https://token.api.cx.metamask.io/token/${chainId}`) .thenCallback(() => { return { statusCode: 200, @@ -413,9 +495,9 @@ async function setupMocking(server, testSpecificMock, { chainId }) { }; }); - // It disables loading of token icons, e.g. this URL: https://static.metafi.codefi.network/api/v1/tokenIcons/1337/0x0000000000000000000000000000000000000000.png + // It disables loading of token icons, e.g. this URL: https://static.cx.metamask.io/api/v1/tokenIcons/1337/0x0000000000000000000000000000000000000000.png const tokenIconRegex = new RegExp( - `^https:\\/\\/static\\.metafi\\.codefi\\.network\\/api\\/vi\\/tokenIcons\\/${chainId}\\/.*\\.png`, + `^https:\\/\\/static\\.cx\\.metamask\\.io\\/api\\/vi\\/tokenIcons\\/${chainId}\\/.*\\.png`, 'u', ); await server.forGet(tokenIconRegex).thenCallback(() => { @@ -431,15 +513,84 @@ async function setupMocking(server, testSpecificMock, { chainId }) { return { statusCode: 200, json: { - USD: '1700', + USD: ethConversionInUsd, }, }; }); + const PPOM_VERSION = fs.readFileSync(PPOM_VERSION_PATH); + const PPOM_VERSION_HEADERS = fs.readFileSync(PPOM_VERSION_HEADERS_PATH); + const CDN_CONFIG = fs.readFileSync(CDN_CONFIG_PATH); + const CDN_STALE = fs.readFileSync(CDN_STALE_PATH); + const CDN_STALE_DIFF = fs.readFileSync(CDN_STALE_DIFF_PATH); + const CDN_CONFIG_RES_HEADERS = fs.readFileSync(CDN_CONFIG_RES_HEADERS_PATH); + const CDN_STALE_RES_HEADERS = fs.readFileSync(CDN_STALE_RES_HEADERS_PATH); + const CDN_STALE_DIFF_RES_HEADERS = fs.readFileSync( + CDN_STALE_DIFF_RES_HEADERS_PATH, + ); + + await server + .forHead( + 'https://static.cx.metamask.io/api/v1/confirmations/ppom/ppom_version.json', + ) + .thenCallback(() => { + return { + statusCode: 200, + }; + }); + + await server + .forGet( + 'https://static.cx.metamask.io/api/v1/confirmations/ppom/ppom_version.json', + ) + .thenCallback(() => { + return { + statusCode: 200, + json: JSON.parse(PPOM_VERSION), + headers: JSON.parse(PPOM_VERSION_HEADERS), + }; + }); + + await server + .forGet( + /^https:\/\/static.cx.metamask.io\/api\/v1\/confirmations\/ppom\/config\/0x1\/(.*)/u, + ) + .thenCallback(() => { + return { + statusCode: 200, + rawBody: CDN_CONFIG, + headers: JSON.parse(CDN_CONFIG_RES_HEADERS), + }; + }); + + await server + .forGet( + /^https:\/\/static.cx.metamask.io\/api\/v1\/confirmations\/ppom\/stale_diff\/0x1\/(.*)/u, + ) + .thenCallback(() => { + return { + statusCode: 200, + rawBody: CDN_STALE_DIFF, + headers: JSON.parse(CDN_STALE_DIFF_RES_HEADERS), + }; + }); + + await server + .forGet( + /^https:\/\/static.cx.metamask.io\/api\/v1\/confirmations\/ppom\/stale\/0x1\/(.*)/u, + ) + .thenCallback(() => { + return { + statusCode: 200, + rawBody: CDN_STALE, + headers: JSON.parse(CDN_STALE_RES_HEADERS), + }; + }); + await mockEmptyStalelistAndHotlist(server); await server - .forPost('https://customnetwork.com/api/customRPC') + .forPost('https://customnetwork.test/api/customRPC') .thenCallback(() => { return { statusCode: 200, @@ -454,6 +605,20 @@ async function setupMocking(server, testSpecificMock, { chainId }) { await mockLensNameProvider(server); await mockTokenNameProvider(server, chainId); + // IPFS endpoint for NFT metadata + await server + .forGet( + 'https://bafybeidxfmwycgzcp4v2togflpqh2gnibuexjy4m4qqwxp7nh3jx5zlh4y.ipfs.dweb.link/1.json', + ) + .thenCallback(() => { + return { + statusCode: 200, + }; + }); + + // Notification APIs + mockNotificationServices(server); + /** * Returns an array of alphanumerically sorted hostnames that were requested * during the current test suite. @@ -521,7 +686,7 @@ async function mockTokenNameProvider(server) { const name = namesByAddress[address]; await server - .forGet(/https:\/\/token-api\.metaswap\.codefi\.network\/token\/.*/gu) + .forGet(/https:\/\/token\.api\.cx\.metamask\.io\/token\/.*/gu) .withQuery({ address }) .thenCallback(() => { return { diff --git a/test/e2e/mock-response-data/aggregator-metadata.json b/test/e2e/mock-response-data/aggregator-metadata.json new file mode 100644 index 000000000000..67511003e8ab --- /dev/null +++ b/test/e2e/mock-response-data/aggregator-metadata.json @@ -0,0 +1,44 @@ +{ + "airswapLight": { + "color": "#2B71FF", + "title": "AirSwap", + "icon": "data:image/svg+xml,%3csvg width='75' height='31' viewBox='0 0 75 31' fill='none' xmlns='http://www.w3.org/2000/svg'%3e %3cpath fill-rule='evenodd' clip-rule='evenodd' d='M31.4038 12.231H30.1152V19.3099H31.4038V12.231Z' fill='%23FDFDFD'/%3e %3cpath fill-rule='evenodd' clip-rule='evenodd' d='M42.8265 15.1959C44.1549 15.5074 44.9217 15.9477 45.1053 16.8178C45.1368 16.9625 45.1513 17.1103 45.1485 17.2582C45.1485 18.5793 44.2197 19.4171 42.7077 19.4171C41.5541 19.4075 40.4409 18.9929 39.5649 18.2463L40.3317 17.3548C41.0229 17.9456 41.8437 18.3215 42.7401 18.3215C43.6365 18.3215 43.8849 17.9241 43.8849 17.3763C43.8849 16.8285 43.5933 16.5922 42.2541 16.2915C40.7205 15.937 39.8349 15.4322 39.8349 14.1218C39.8349 12.8114 40.7529 12.1239 42.1785 12.1239C43.1717 12.1129 44.1403 12.4303 44.9325 13.0262L44.2521 13.9607C43.6041 13.488 42.8697 13.1658 42.2109 13.1658C41.5521 13.1658 41.0985 13.5418 41.0985 14.0144C41.0985 14.487 41.4549 14.8736 42.8265 15.1959Z' fill='%23FDFDFD'/%3e %3cpath fill-rule='evenodd' clip-rule='evenodd' d='M54.8897 12.231L53.1626 17.4487L51.3925 12.231H50.3305L48.5605 17.4487L46.8333 12.231H45.4709L47.9812 19.3099H49.0754L50.8454 14.2643L52.6155 19.3099H53.699L56.2092 12.231H54.8897Z' fill='%23FDFDFD'/%3e %3cpath d='M66.2502 13.3606H64.4545V15.8457H66.2502C67.2129 15.8457 67.8078 15.48 67.8078 14.5655C67.8078 13.651 67.202 13.3606 66.2502 13.3606ZM66.2069 16.9538H64.4545V19.3099H63.189V12.231H66.3583C68.0349 12.231 69.095 13.0809 69.095 14.5117C69.095 16.1039 67.916 16.9538 66.2069 16.9538Z' fill='%23FDFDFD'/%3e %3cpath d='M36.1129 13.3606H34.2841V15.835H36.1237C37.0273 15.835 37.6082 15.3078 37.6082 14.587C37.6082 13.8662 37.0488 13.3606 36.1129 13.3606ZM37.4253 19.3099L35.8547 16.9323H34.2841V19.3099H33.0146V12.231H36.2205C37.8664 12.231 38.8884 13.21 38.8884 14.587C38.8884 15.7489 38.1784 16.4482 37.1672 16.7279L38.9207 19.3099H37.4253Z' fill='%23FDFDFD'/%3e %3cpath d='M25.3908 13.7048L26.4171 16.3944C25.6372 16.3931 24.8666 16.562 24.1593 16.8893L25.3908 13.7048ZM21.7395 19.3099H23.0682C23.0682 19.3099 24.0297 17.2766 26.8492 17.5025L27.6054 19.3099H28.9341L25.9958 12.231H24.7535L21.7395 19.3099Z' fill='%23FDFDFD'/%3e %3cpath d='M60.0214 16.8893C59.315 16.5627 58.5456 16.3938 57.767 16.3944L58.7917 13.7048L60.0214 16.8893ZM59.4281 12.231H58.1877L55.2429 19.3099H56.5697L57.3355 17.5025C60.14 17.2766 61.1 19.3099 61.1 19.3099H62.4376L59.4281 12.231Z' fill='%23FDFDFD'/%3e %3cpath fill-rule='evenodd' clip-rule='evenodd' d='M16.021 18.988L12.332 22.6348L10.5039 20.8275C12.4754 20.7086 14.3794 20.0738 16.021 18.988Z' fill='%23FDFDFD'/%3e %3cpath d='M19.4724 15.2831L19.0194 14.8302L12.3431 8.15515L5.66685 14.8302L5.09521 15.4017L5.30014 15.585C5.53742 15.7791 5.77471 15.9624 6.02278 16.135C7.83476 17.4034 9.98616 18.0982 12.198 18.1289C14.4098 18.1597 16.5797 17.5251 18.4262 16.3075C18.6851 16.135 18.9439 15.9409 19.192 15.7468C19.4401 15.5527 19.4616 15.5203 19.5911 15.4017L19.4724 15.2831ZM14.1012 16.9545C12.1094 15.732 9.81597 15.0897 7.47883 15.0997C10.5312 13.7734 14.263 13.5901 17.6928 15.5634C16.597 16.2552 15.3771 16.7277 14.1012 16.9545Z' fill='%23FDFDFD'/%3e %3c/svg%3e", + "iconPng": "data:image/png;base64,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" + }, + "bancor": { + "color": "#c9c9c9", + "title": "Bancor", + "icon": "data:image/svg+xml,%3csvg width='117' height='29' viewBox='0 0 117 29' fill='none' xmlns='http://www.w3.org/2000/svg'%3e %3cpath fill-rule='evenodd' clip-rule='evenodd' d='M9.15211 0.0550469L16.2358 3.98013C16.5117 4.1333 16.5117 4.51305 16.2358 4.66622L9.15211 8.5913C9.02579 8.66151 8.86623 8.66151 8.73992 8.5913L1.65627 4.66622C1.38037 4.51305 1.38037 4.1333 1.65627 3.98013L8.73992 0.0550469C8.86956 -0.018349 9.02579 -0.018349 9.15211 0.0550469Z' fill='%230A2540'/%3e %3cpath fill-rule='evenodd' clip-rule='evenodd' d='M17.8737 6.17705V14.0304C17.8737 14.1708 17.7939 14.3017 17.6676 14.3751L10.4244 18.3799C10.1485 18.5331 9.80615 18.3416 9.80615 18.0353V10.1851C9.80615 10.0447 9.88593 9.91386 10.0122 9.84046L17.2521 5.82922C17.528 5.67924 17.8737 5.8707 17.8737 6.17705Z' fill='%230A2540'/%3e %3cpath fill-rule='evenodd' clip-rule='evenodd' d='M19.8715 14.9575L10.0122 20.4048C9.88593 20.475 9.80615 20.6058 9.80615 20.7494V28.6028C9.80615 28.9091 10.1485 29.0974 10.4244 28.9474L20.2804 23.497C20.4067 23.4268 20.4865 23.2959 20.4865 23.1523V15.299C20.4898 14.9958 20.1441 14.8043 19.8715 14.9575Z' fill='%230A2540'/%3e %3cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 14.0244V6.1742C0 5.86785 0.342382 5.67958 0.618281 5.82956L7.85483 9.8408C7.98115 9.91101 8.06093 10.0418 8.06093 10.1854V18.0356C8.06093 18.342 7.71855 18.5302 7.44265 18.3802L0.206094 14.3658C0.0797783 14.2956 0 14.1648 0 14.0244Z' fill='%230A2540'/%3e %3cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 16.7387V24.592C0 24.7324 0.0797783 24.8633 0.206094 24.9366L7.44265 28.9447C7.71855 29.0979 8.06093 28.9064 8.06093 28.6001V20.7499C8.06093 20.6095 7.98115 20.4786 7.85483 20.4053L0.618281 16.394C0.342382 16.244 0 16.4323 0 16.7387Z' fill='%230A2540'/%3e %3cpath d='M40.0036 16.4058C40.6736 17.2194 41.0086 18.1524 41.0086 19.2049C41.0086 20.1573 40.7674 20.9903 40.2817 21.7135C39.7959 22.4334 39.0958 22.9984 38.1813 23.4052C37.2634 23.812 36.1813 24.0154 34.9318 24.0154H26.9823V6.24902H34.5901C35.8396 6.24902 36.9183 6.44596 37.8262 6.83338C38.734 7.22403 39.4207 7.76641 39.8864 8.46376C40.352 9.16112 40.5865 9.94887 40.5865 10.8302C40.5865 11.8666 40.2984 12.7318 39.7289 13.4259C39.1561 14.1233 38.3957 14.614 37.4443 14.9014C38.4828 15.0918 39.337 15.5923 40.0036 16.4058ZM30.6807 13.5809H34.0608C34.9418 13.5809 35.6185 13.3904 36.0942 13.0095C36.5699 12.6285 36.8078 12.0797 36.8078 11.3662C36.8078 10.6527 36.5699 10.1038 36.0942 9.71319C35.6185 9.32254 34.9418 9.12883 34.0608 9.12883H30.6807V13.5809ZM36.5063 20.506C37.0088 20.0992 37.26 19.5213 37.26 18.7755C37.26 18.0136 36.9954 17.4131 36.4661 16.9805C35.9368 16.5479 35.2232 16.3316 34.3254 16.3316H30.6807V21.1162H34.4058C35.3036 21.1162 36.0038 20.9128 36.5063 20.506Z' fill='%230A2540'/%3e %3cpath d='M43.2303 13.1217C43.8199 12.0175 44.6206 11.1717 45.6323 10.5744C46.644 9.98037 47.7763 9.68335 49.0258 9.68335C50.1179 9.68335 51.0726 9.89643 51.8934 10.3194C52.7108 10.7423 53.3674 11.2782 53.8598 11.9239V9.9158H57.585V24.0178H53.8631V21.9548C53.3875 22.6167 52.7309 23.1655 51.8967 23.5981C51.0592 24.0307 50.0944 24.247 49.0057 24.247C47.7729 24.247 46.6507 23.9403 45.639 23.3301C44.6273 22.72 43.8266 21.858 43.237 20.7474C42.6474 19.6368 42.3527 18.3583 42.3527 16.9152C42.346 15.4882 42.6408 14.2258 43.2303 13.1217ZM53.3339 14.7392C52.9821 14.1193 52.5064 13.6447 51.9068 13.3122C51.3071 12.9796 50.6639 12.815 49.9772 12.815C49.2904 12.815 48.6573 12.9764 48.0744 13.2993C47.4949 13.6221 47.0225 14.0935 46.6607 14.7133C46.2989 15.3332 46.118 16.0661 46.118 16.9152C46.118 17.7642 46.2989 18.5068 46.6607 19.1428C47.0225 19.7788 47.4982 20.2663 48.0878 20.6053C48.6774 20.9443 49.3072 21.1154 49.9772 21.1154C50.6639 21.1154 51.3071 20.9508 51.9068 20.6182C52.5064 20.2857 52.9821 19.8111 53.3339 19.1912C53.6856 18.5714 53.8631 17.8288 53.8631 16.9636C53.8631 16.1016 53.6856 15.359 53.3339 14.7392Z' fill='%230A2540'/%3e %3cpath d='M72.8699 11.3028C73.9452 12.3618 74.4812 13.8436 74.4812 15.7452V24.0166H70.7829V16.2295C70.7829 15.1092 70.4914 14.2472 69.9119 13.6467C69.3323 13.043 68.5384 12.7427 67.5334 12.7427C66.5116 12.7427 65.7076 13.043 65.118 13.6467C64.5285 14.2504 64.2337 15.1092 64.2337 16.2295V24.0198H60.5353V9.9178H64.2337V11.6741C64.7261 11.0639 65.3559 10.5829 66.123 10.2342C66.8902 9.88552 67.731 9.71118 68.6456 9.71118C70.3876 9.71441 71.7945 10.2439 72.8699 11.3028Z' fill='%230A2540'/%3e %3cpath d='M77.2995 13.1346C77.9159 12.0401 78.7701 11.1911 79.8622 10.5873C80.9543 9.9836 82.2039 9.68335 83.6142 9.68335C85.4265 9.68335 86.9307 10.1192 88.1166 10.9941C89.3058 11.869 90.1031 13.0926 90.5084 14.6714H86.5186C86.3076 14.0612 85.9525 13.5801 85.45 13.2347C84.9475 12.886 84.3277 12.7117 83.5874 12.7117C82.5322 12.7117 81.6947 13.0797 81.0783 13.819C80.4619 14.5584 80.1537 15.6044 80.1537 16.9636C80.1537 18.3034 80.4619 19.343 81.0783 20.0823C81.6947 20.8216 82.5322 21.1897 83.5874 21.1897C85.0848 21.1897 86.0597 20.544 86.5186 19.2558H90.5084C90.1031 20.7829 89.3025 21.9968 88.1065 22.8943C86.9072 23.7951 85.4131 24.2438 83.6176 24.2438C82.2072 24.2438 80.9577 23.9436 79.8656 23.3398C78.7735 22.7361 77.9192 21.8902 77.3029 20.7926C76.6865 19.6981 76.3783 18.4229 76.3783 16.9604C76.3749 15.5075 76.6798 14.2291 77.2995 13.1346Z' fill='%230A2540'/%3e %3cpath d='M95.2474 23.3451C94.1185 22.7414 93.2341 21.889 92.5909 20.7881C91.9477 19.684 91.6261 18.412 91.6261 16.9688C91.6261 15.5257 91.9578 14.2537 92.6177 13.1495C93.2776 12.0454 94.1788 11.1931 95.3245 10.5926C96.4702 9.98885 97.7465 9.6886 99.1535 9.6886C100.564 9.6886 101.837 9.98885 102.983 10.5926C104.128 11.1963 105.029 12.0486 105.689 13.1495C106.349 14.2537 106.681 15.5257 106.681 16.9688C106.681 18.412 106.343 19.684 105.662 20.7881C104.986 21.8923 104.068 22.7446 102.916 23.3451C101.763 23.9488 100.473 24.2491 99.0463 24.2491C97.6426 24.2491 96.373 23.9456 95.2474 23.3451ZM100.939 20.6719C101.529 20.3587 102.001 19.8874 102.353 19.2611C102.704 18.6347 102.882 17.8696 102.882 16.9688C102.882 15.629 102.517 14.5991 101.787 13.8759C101.056 13.156 100.162 12.7944 99.1066 12.7944C98.0514 12.7944 97.1636 13.156 96.4534 13.8759C95.7399 14.5959 95.3848 15.629 95.3848 16.9688C95.3848 18.3087 95.7332 19.3418 96.4266 20.0617C97.1234 20.7817 97.9978 21.1433 99.053 21.1433C99.7196 21.1433 100.349 20.9851 100.939 20.6719Z' fill='%230A2540'/%3e %3cpath d='M114.297 10.3484C115.064 9.92548 115.938 9.7124 116.923 9.7124V13.4542H115.945C114.783 13.4542 113.908 13.719 113.319 14.242C112.729 14.7682 112.434 15.6851 112.434 16.9926V24.0178H108.736V9.9158H112.434V12.1047C112.91 11.3557 113.53 10.7713 114.297 10.3484Z' fill='%230A2540'/%3e %3c/svg%3e", + "iconPng": "data:image/png;base64,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" + }, + "curve": { + "color": "#24292E", + "title": "Curve", + "icon": "data:image/svg+xml,%3csvg width='74' height='30' viewBox='0 0 74 30' fill='none' xmlns='http://www.w3.org/2000/svg'%3e %3cpath d='M38.1738 15.9546C38.0552 16.9697 37.6794 17.7542 37.0466 18.3079C36.4182 18.8572 35.5811 19.1318 34.5352 19.1318C33.4014 19.1318 32.4917 18.7253 31.8062 17.9124C31.125 17.0994 30.7844 16.0117 30.7844 14.6494V13.7266C30.7844 12.8345 30.9426 12.05 31.259 11.3733C31.5798 10.6965 32.0325 10.178 32.6169 9.81763C33.2014 9.45288 33.8782 9.27051 34.6472 9.27051C35.6667 9.27051 36.4841 9.55615 37.0994 10.1274C37.7146 10.6943 38.0728 11.481 38.1738 12.4873H36.9016C36.7917 11.7227 36.5522 11.1689 36.1831 10.8262C35.8184 10.4834 35.3064 10.312 34.6472 10.312C33.8386 10.312 33.2036 10.6108 32.7422 11.2085C32.2852 11.8062 32.0566 12.6565 32.0566 13.7595V14.689C32.0566 15.7305 32.2742 16.5588 32.7092 17.1741C33.1443 17.7893 33.7529 18.0969 34.5352 18.0969C35.2383 18.0969 35.7766 17.9387 36.1501 17.6223C36.5281 17.3015 36.7786 16.7456 36.9016 15.9546H38.1738ZM44.1196 18.2947C43.645 18.8528 42.9485 19.1318 42.03 19.1318C41.2698 19.1318 40.6897 18.9121 40.2898 18.4727C39.8943 18.0288 39.6943 17.374 39.6899 16.5083V11.8677H40.9094V16.4753C40.9094 17.5564 41.3489 18.0969 42.2278 18.0969C43.1594 18.0969 43.7791 17.7498 44.0867 17.0554V11.8677H45.3062V19H44.146L44.1196 18.2947ZM50.6125 12.9619C50.428 12.9312 50.228 12.9158 50.0127 12.9158C49.2129 12.9158 48.6702 13.2563 48.3845 13.9375V19H47.165V11.8677H48.3516L48.3713 12.6917C48.7712 12.0544 49.3381 11.7358 50.072 11.7358C50.3093 11.7358 50.4895 11.7666 50.6125 11.8281V12.9619ZM54.2117 17.3455L55.9783 11.8677H57.2241L54.6665 19H53.7371L51.1531 11.8677H52.3989L54.2117 17.3455ZM61.2649 19.1318C60.2981 19.1318 59.5115 18.8154 58.905 18.1826C58.2986 17.5454 57.9954 16.6951 57.9954 15.6316V15.4075C57.9954 14.7 58.1294 14.0693 58.3975 13.5156C58.6699 12.9575 59.0479 12.5225 59.5312 12.2104C60.019 11.894 60.5464 11.7358 61.1133 11.7358C62.0405 11.7358 62.7612 12.0413 63.2754 12.6521C63.7896 13.2629 64.0466 14.1375 64.0466 15.2756V15.7832H59.2148C59.2324 16.4863 59.4368 17.0554 59.8279 17.4905C60.2234 17.9211 60.7244 18.1365 61.3308 18.1365C61.7615 18.1365 62.1262 18.0486 62.425 17.8728C62.7239 17.697 62.9854 17.4641 63.2095 17.1741L63.9543 17.7542C63.3567 18.6726 62.4602 19.1318 61.2649 19.1318ZM61.1133 12.7378C60.6211 12.7378 60.208 12.918 59.874 13.2783C59.54 13.6343 59.3335 14.1353 59.2544 14.7812H62.8271V14.689C62.792 14.0693 62.625 13.5903 62.3262 13.252C62.0273 12.9092 61.623 12.7378 61.1133 12.7378Z' fill='%23E6E6E6'/%3e %3cpath d='M16.2311 16.396L14.9332 16.6817L14.7722 16.0747L16.1506 15.8225L16.2311 16.396Z' fill='blue'/%3e %3cpath d='M14.9332 16.6814L13.8055 17.0642L13.5618 16.4305L14.7722 16.0743L14.9332 16.6814Z' fill='blue'/%3e %3cpath d='M16.1501 15.8226L14.7717 16.0747L14.6267 15.3663L16.0781 15.1522L16.1501 15.8226Z' fill='%230028FF'/%3e %3cpath d='M14.772 16.0744L13.5616 16.4305L13.3418 15.691L14.6271 15.366L14.772 16.0744Z' fill='%230018FF'/%3e %3cpath d='M16.3176 16.8586L15.106 17.1726L14.9329 16.6816L16.2308 16.3959L16.3176 16.8586Z' fill='%230000F1'/%3e %3cpath d='M15.1063 17.1724L14.0672 17.577L13.8054 17.0642L14.9332 16.6814L15.1063 17.1724Z' fill='%230000DA'/%3e %3cpath d='M16.0785 15.1524L14.6271 15.3664L14.5017 14.5736L16.0166 14.4012L16.0785 15.1524Z' fill='%230058FF'/%3e %3cpath d='M14.627 15.3659L13.3417 15.6909L13.1511 14.8631L14.5016 14.573L14.627 15.3659Z' fill='%230048FF'/%3e %3cpath d='M17.6493 16.2077L16.2308 16.3961L16.1504 15.8226L17.6439 15.6733L17.6493 16.2077Z' fill='%230014FF'/%3e %3cpath d='M16.4089 17.1991L15.2871 17.5354L15.106 17.1724L16.3176 16.8584L16.4089 17.1991Z' fill='%230000DA'/%3e %3cpath d='M13.8051 17.0646L12.8805 17.5388L12.5557 16.8863L13.5614 16.4309L13.8051 17.0646Z' fill='%230000E8'/%3e %3cpath d='M15.2872 17.5355L14.3404 17.9562L14.0669 17.577L15.106 17.1725L15.2872 17.5355Z' fill='%230000C4'/%3e %3cpath d='M17.6442 15.6732L16.1507 15.8225L16.0786 15.1521L17.6402 15.0465L17.6442 15.6732Z' fill='%23003CFF'/%3e %3cpath d='M13.5614 16.4308L12.5557 16.8863L12.2625 16.1237L13.3416 15.6913L13.5614 16.4308Z' fill='%230008FF'/%3e %3cpath d='M17.656 16.6367L16.3179 16.8586L16.231 16.3958L17.6494 16.2075L17.656 16.6367Z' fill='blue'/%3e %3cpath d='M14.0669 17.5773L13.2293 18.0654L12.8806 17.5387L13.8052 17.0646L14.0669 17.5773Z' fill='%230000C8'/%3e %3cpath d='M16.0164 14.4008L14.5015 14.5731L14.3987 13.7146L15.9662 13.5868L16.0164 14.4008Z' fill='%230090FF'/%3e %3cpath d='M14.5016 14.5736L13.1511 14.8637L12.9944 13.9673L14.3988 13.7151L14.5016 14.5736Z' fill='%230084FF'/%3e %3cpath d='M17.6399 15.0464L16.0782 15.1521L16.0164 14.4009L17.6373 14.3425L17.6399 15.0464Z' fill='%230068FF'/%3e %3cpath d='M13.3417 15.6913L12.2626 16.1237L12.0081 15.2691L13.1511 14.8635L13.3417 15.6913Z' fill='%23003CFF'/%3e %3cpath d='M17.6634 16.9501L16.4089 17.1993L16.3176 16.8586L17.6558 16.6367L17.6634 16.9501Z' fill='%230000F6'/%3e %3cpath d='M16.5024 17.4092L15.4719 17.7614L15.2871 17.5357L16.4089 17.1993L16.5024 17.4092Z' fill='%230000D1'/%3e %3cpath d='M14.3404 17.9563L13.5935 18.4533L13.2292 18.0652L14.0668 17.5771L14.3404 17.9563Z' fill='%230000AD'/%3e %3cpath d='M15.4721 17.7614L14.6194 18.1924L14.3406 17.9565L15.2873 17.5358L15.4721 17.7614Z' fill='%230000BB'/%3e %3cpath d='M17.6374 14.3424L16.0165 14.4008L15.9663 13.5869L17.6364 13.5782L17.6374 14.3424Z' fill='%23009CFF'/%3e %3cpath d='M13.1514 14.8634L12.0084 15.269L11.7988 14.3425L12.9946 13.967L13.1514 14.8634Z' fill='%230078FF'/%3e %3cpath d='M17.6719 17.1396L16.5024 17.4091L16.4089 17.1992L17.6634 16.9501L17.6719 17.1396Z' fill='%230000ED'/%3e %3cpath d='M15.9664 13.5869L14.3989 13.7148L14.3213 12.8112L15.9291 12.7296L15.9664 13.5869Z' fill='%2300CCFF'/%3e %3cpath d='M19.1245 16.1121L17.6492 16.2077L17.6438 15.6733L19.1861 15.6207L19.1245 16.1121Z' fill='%23002CFF'/%3e %3cpath d='M14.3985 13.7149L12.9941 13.9671L12.8752 13.0234L14.3209 12.8113L14.3985 13.7149Z' fill='%2300C4FF'/%3e %3cpath d='M19.0598 16.5039L17.656 16.6368L17.6494 16.2076L19.1248 16.1121L19.0598 16.5039Z' fill='%230014FF'/%3e %3cpath d='M19.1865 15.6206L17.6442 15.6732L17.6401 15.0465L19.2431 15.0416L19.1865 15.6206Z' fill='%230050FF'/%3e %3cpath d='M12.8805 17.5384L12.1747 18.0922L11.7742 17.43L12.5556 16.886L12.8805 17.5384Z' fill='%230000DA'/%3e %3cpath d='M12.5557 16.8862L11.7742 17.4302L11.4126 16.6537L12.2625 16.1237L12.5557 16.8862Z' fill='blue'/%3e %3cpath d='M14.6194 18.1922L13.9649 18.6929L13.5938 18.4533L14.3406 17.9563L14.6194 18.1922Z' fill='%230000A4'/%3e %3cpath d='M13.2291 18.0655L12.6044 18.6247L12.1746 18.0926L12.8804 17.5388L13.2291 18.0655Z' fill='%230000B6'/%3e %3cpath d='M16.5957 17.4821L15.6559 17.8432L15.4719 17.7611L16.5024 17.4089L16.5957 17.4821Z' fill='%230000D6'/%3e %3cpath d='M18.9927 16.7865L17.6634 16.9502L17.6558 16.6369L19.0596 16.5039L18.9927 16.7865Z' fill='%230004FF'/%3e %3cpath d='M19.243 15.0416L17.64 15.0464L17.6375 14.3425L19.2934 14.3889L19.243 15.0416Z' fill='%230078FF'/%3e %3cpath d='M15.6559 17.8435L14.8965 18.2784L14.6191 18.1924L15.4719 17.7615L15.6559 17.8435Z' fill='%230000BF'/%3e %3cpath d='M17.6362 13.5783L15.9662 13.587L15.929 12.7296L17.6367 12.7723L17.6362 13.5783Z' fill='%2300D8FF'/%3e %3cpath d='M12.2628 16.1236L11.4129 16.6537L11.0989 15.7812L12.0083 15.2689L12.2628 16.1236Z' fill='%230034FF'/%3e %3cpath d='M17.6811 17.2004L16.5958 17.4825L16.5024 17.4093L17.672 17.1399L17.6811 17.2004Z' fill='%230000F1'/%3e %3cpath d='M13.5935 18.4534L13.0534 19.0136L12.6045 18.6245L13.2292 18.0653L13.5935 18.4534Z' fill='%2300009F'/%3e %3cpath d='M12.994 13.9668L11.7982 14.3422L11.6389 13.3657L12.8751 13.0231L12.994 13.9668Z' fill='%2300BCFF'/%3e %3cpath d='M18.9259 16.9526L17.6721 17.1398L17.6636 16.9503L18.9929 16.7865L18.9259 16.9526Z' fill='blue'/%3e %3cpath d='M15.9291 12.7295L14.3213 12.8111L14.271 11.8841L15.9059 11.8496L15.9291 12.7295Z' fill='%2323FFD4'/%3e %3cpath d='M19.2932 14.3888L17.6373 14.3424L17.6362 13.5782L19.336 13.6783L19.2932 14.3888Z' fill='%2300ACFF'/%3e %3cpath d='M14.3211 12.8112L12.8755 13.0233L12.7976 12.055L14.2709 11.8843L14.3211 12.8112Z' fill='%231CFFDB'/%3e %3cpath d='M14.8966 18.2783L14.334 18.7774L13.9648 18.693L14.6193 18.1923L14.8966 18.2783Z' fill='%230000AD'/%3e %3cpath d='M12.0081 15.2687L11.0987 15.781L10.8401 14.833L11.7986 14.3422L12.0081 15.2687Z' fill='%230070FF'/%3e %3cpath d='M16.6868 17.416L15.8347 17.7786L15.656 17.8432L16.5958 17.4822L16.6868 17.416Z' fill='%230000E8'/%3e %3cpath d='M13.9648 18.6931L13.5108 19.2498L13.0535 19.0137L13.5936 18.4535L13.9648 18.6931Z' fill='%23000096'/%3e %3cpath d='M17.6365 12.7723L15.9288 12.7297L15.9055 11.8497L17.6385 11.9439L17.6365 12.7723Z' fill='%2326FFD1'/%3e %3cpath d='M18.8603 16.9972L17.6813 17.1999L17.6721 17.1394L18.926 16.9521L18.8603 16.9972Z' fill='blue'/%3e %3cpath d='M20.5826 16.1006L19.1245 16.1121L19.1861 15.6207L20.701 15.6547L20.5826 16.1006Z' fill='%230044FF'/%3e %3cpath d='M20.4573 16.4525L19.0598 16.5036L19.1248 16.1118L20.5829 16.1003L20.4573 16.4525Z' fill='%23002CFF'/%3e %3cpath d='M15.8348 17.7787L15.1658 18.2112L14.8967 18.2782L15.6561 17.8433L15.8348 17.7787Z' fill='%230000D1'/%3e %3cpath d='M19.336 13.6785L17.6362 13.5785L17.6367 12.7725L19.3701 12.9273L19.336 13.6785Z' fill='%2300E0FB'/%3e %3cpath d='M17.6909 17.1294L16.6869 17.4162L16.5959 17.4824L17.6813 17.2002L17.6909 17.1294Z' fill='blue'/%3e %3cpath d='M20.7014 15.6543L19.1865 15.6204L19.2432 15.0414L20.8095 15.1254L20.7014 15.6543Z' fill='%230064FF'/%3e %3cpath d='M12.8755 13.0234L11.6394 13.3661L11.5347 12.3631L12.7977 12.0551L12.8755 13.0234Z' fill='%2319FFDE'/%3e %3cpath d='M20.327 16.7024L18.9927 16.7865L19.0595 16.5039L20.4569 16.4528L20.327 16.7024Z' fill='%23001CFF'/%3e %3cpath d='M12.175 18.0925L11.6864 18.7086L11.2197 18.0462L11.7745 17.4303L12.175 18.0925Z' fill='%230000D1'/%3e %3cpath d='M12.6045 18.6246L12.1868 19.2371L11.686 18.7086L12.1747 18.0925L12.6045 18.6246Z' fill='%230000A8'/%3e %3cpath d='M15.9056 11.8497L14.2708 11.8842L14.2493 10.9565L15.8971 10.9688L15.9056 11.8497Z' fill='%235AFF9D'/%3e %3cpath d='M20.809 15.1256L19.2427 15.0416L19.293 14.3889L20.9043 14.5266L20.809 15.1256Z' fill='%23008CFF'/%3e %3cpath d='M11.7741 17.4301L11.2193 18.0459L10.7979 17.2652L11.4125 16.6536L11.7741 17.4301Z' fill='blue'/%3e %3cpath d='M11.7985 14.3425L10.84 14.8333L10.6433 13.8323L11.6393 13.366L11.7985 14.3425Z' fill='%2300B8FF'/%3e %3cpath d='M14.271 11.8842L12.7977 12.0549L12.7632 11.0855L14.2495 10.9565L14.271 11.8842Z' fill='%235AFF9D'/%3e %3cpath d='M20.1962 16.843L18.9258 16.9525L18.9928 16.7864L20.3272 16.7023L20.1962 16.843Z' fill='%230018FF'/%3e %3cpath d='M15.1657 18.2109L14.6921 18.703L14.334 18.7771L14.8966 18.278L15.1657 18.2109Z' fill='%230000BF'/%3e %3cpath d='M14.3338 18.7775L13.9655 19.3264L13.5107 19.2498L13.9647 18.6931L14.3338 18.7775Z' fill='%2300009B'/%3e %3cpath d='M13.0536 19.0134L12.7099 19.6185L12.187 19.2368L12.6047 18.6244L13.0536 19.0134Z' fill='%23000092'/%3e %3cpath d='M18.7975 16.9198L17.6905 17.1293L17.6809 17.2002L18.86 16.9975L18.7975 16.9198Z' fill='%23000CFF'/%3e %3cpath d='M11.4129 16.6536L10.7982 17.2653L10.4321 16.3846L11.0989 15.7811L11.4129 16.6536Z' fill='%23002CFF'/%3e %3cpath d='M17.6388 11.9436L15.9058 11.8494L15.8972 10.9685L17.6424 11.1134L17.6388 11.9436Z' fill='%235DFF9A'/%3e %3cpath d='M19.3703 12.9269L17.637 12.7721L17.639 11.9437L19.3949 12.1534L19.3703 12.9269Z' fill='%232CFFCA'/%3e %3cpath d='M20.9042 14.5269L19.293 14.3892L19.3357 13.6786L20.9841 13.8722L20.9042 14.5269Z' fill='%2300B8FF'/%3e %3cpath d='M16.7734 17.2111L16.0038 17.5677L15.835 17.7787L16.6871 17.4161L16.7734 17.2111Z' fill='blue'/%3e %3cpath d='M17.7008 16.928L16.7733 17.2111L16.687 17.4162L17.691 17.1294L17.7008 16.928Z' fill='%23000CFF'/%3e %3cpath d='M20.0676 16.871L18.8604 16.9974L18.9259 16.9523L20.1964 16.8429L20.0676 16.871Z' fill='%230018FF'/%3e %3cpath d='M16.0038 17.5679L15.4201 17.9915L15.166 18.2114L15.835 17.7789L16.0038 17.5679Z' fill='%230000F1'/%3e %3cpath d='M12.7976 12.0548L11.5346 12.3628L11.4875 11.3577L12.7631 11.0854L12.7976 12.0548Z' fill='%2356FFA0'/%3e %3cpath d='M13.5109 19.2497L13.2426 19.8438L12.71 19.6186L13.0536 19.0135L13.5109 19.2497Z' fill='%23000089'/%3e %3cpath d='M11.0987 15.781L10.4319 16.3845L10.1304 15.4246L10.84 14.833L11.0987 15.781Z' fill='%23006CFF'/%3e %3cpath d='M11.6394 13.366L10.6434 13.8323L10.5139 12.8023L11.5347 12.3629L11.6394 13.366Z' fill='%2316FFE1'/%3e %3cpath d='M20.9843 13.872L19.3359 13.6784L19.37 12.9271L21.0469 13.1778L20.9843 13.872Z' fill='%2306ECF1'/%3e %3cpath d='M15.8971 10.9687L14.2493 10.9564L14.2574 10.0511L15.9035 10.1087L15.8971 10.9687Z' fill='%2394FF63'/%3e %3cpath d='M18.7397 16.7205L17.7005 16.928L17.6907 17.1294L18.7976 16.9198L18.7397 16.7205Z' fill='%230024FF'/%3e %3cpath d='M14.6918 18.7034L14.4064 19.2403L13.9653 19.3263L14.3337 18.7774L14.6918 18.7034Z' fill='%230000AD'/%3e %3cpath d='M21.7696 16.4731L20.457 16.4525L20.5827 16.1003L21.9438 16.1614L21.7696 16.4731Z' fill='%230044FF'/%3e %3cpath d='M21.9436 16.1613L20.5825 16.1003L20.7009 15.6543L22.1073 15.7615L21.9436 16.1613Z' fill='%23005CFF'/%3e %3cpath d='M19.3948 12.1537L17.6389 11.944L17.6424 11.1138L19.4091 11.377L19.3948 12.1537Z' fill='%235DFF9A'/%3e %3cpath d='M14.2492 10.9564L12.7629 11.0854L12.773 10.1391L14.2573 10.0511L14.2492 10.9564Z' fill='%2394FF63'/%3e %3cpath d='M19.944 16.7853L18.7976 16.9198L18.8601 16.9975L20.0674 16.8711L19.944 16.7853Z' fill='%230028FF'/%3e %3cpath d='M15.4202 17.9912L15.0305 18.4711L14.6924 18.7032L15.1661 18.2111L15.4202 17.9912Z' fill='%230000DF'/%3e %3cpath d='M21.5893 16.6891L20.3271 16.7021L20.4571 16.4525L21.7696 16.4731L21.5893 16.6891Z' fill='%230038FF'/%3e %3cpath d='M22.1074 15.7619L20.7009 15.6546L20.8091 15.1257L22.2567 15.2839L22.1074 15.7619Z' fill='%230078FF'/%3e %3cpath d='M17.6424 11.1135L15.8972 10.9686L15.9036 10.1086L17.6473 10.3022L17.6424 11.1135Z' fill='%2390FF66'/%3e %3cpath d='M13.9655 19.3263L13.7719 19.9063L13.2424 19.8438L13.5108 19.2498L13.9655 19.3263Z' fill='%2300008D'/%3e %3cpath d='M16.8524 16.8708L16.1582 17.214L16.0034 17.5676L16.7729 17.211L16.8524 16.8708Z' fill='%23001CFF'/%3e %3cpath d='M21.4072 16.804L20.196 16.843L20.327 16.7022L21.5892 16.6892L21.4072 16.804Z' fill='%230034FF'/%3e %3cpath d='M17.7105 16.5997L16.8526 16.8708L16.7732 17.2109L17.7007 16.9278L17.7105 16.5997Z' fill='%230030FF'/%3e %3cpath d='M22.2567 15.2839L20.8091 15.1257L20.9043 14.5267L22.3878 14.7393L22.2567 15.2839Z' fill='%2300A0FF'/%3e %3cpath d='M21.047 13.1775L19.3701 12.9269L19.3947 12.1533L21.0906 12.4607L21.047 13.1775Z' fill='%2333FFC4'/%3e %3cpath d='M10.8404 14.8331L10.1307 15.4247L9.90137 14.4083L10.6437 13.8322L10.8404 14.8331Z' fill='%2300B0FF'/%3e %3cpath d='M11.6861 18.7086L11.3977 19.3644L10.8779 18.7114L11.2194 18.0461L11.6861 18.7086Z' fill='%230000C8'/%3e %3cpath d='M12.1869 19.2369L11.9553 19.8799L11.3977 19.3643L11.6861 18.7085L12.1869 19.2369Z' fill='%230000A4'/%3e %3cpath d='M16.1584 17.2144L15.6526 17.6227L15.4199 17.9916L16.0036 17.5679L16.1584 17.2144Z' fill='%230008FF'/%3e %3cpath d='M11.2196 18.0461L10.8782 18.7114L10.4087 17.9365L10.7982 17.2654L11.2196 18.0461Z' fill='blue'/%3e %3cpath d='M12.7633 11.0856L11.4878 11.3579L11.5001 10.3756L12.7734 10.1393L12.7633 11.0856Z' fill='%2394FF63'/%3e %3cpath d='M21.2284 16.8148L20.0676 16.8712L20.1964 16.8431L21.4075 16.8042L21.2284 16.8148Z' fill='%230034FF'/%3e %3cpath d='M19.8293 16.5872L18.74 16.7206L18.7979 16.92L19.9442 16.7854L19.8293 16.5872Z' fill='%23003CFF'/%3e %3cpath d='M11.5345 12.3629L10.5138 12.8023L10.4553 11.7683L11.4874 11.3578L11.5345 12.3629Z' fill='%2356FFA0'/%3e %3cpath d='M12.7098 19.6184L12.5374 20.2456L11.9553 19.8797L12.1869 19.2367L12.7098 19.6184Z' fill='%23000089'/%3e %3cpath d='M18.6882 16.4033L17.7105 16.5997L17.7007 16.9278L18.7399 16.7203L18.6882 16.4033Z' fill='%230044FF'/%3e %3cpath d='M22.388 14.7392L20.9045 14.5267L20.9845 13.8721L22.4976 14.1413L22.388 14.7392Z' fill='%2300C8FF'/%3e %3cpath d='M19.409 11.3768L17.6423 11.1135L17.6473 10.3022L19.4127 10.6165L19.409 11.3768Z' fill='%2390FF66'/%3e %3cpath d='M15.9037 10.1088L14.2576 10.0513L14.2954 9.19141L15.925 9.29178L15.9037 10.1088Z' fill='%23CAFF2C'/%3e %3cpath d='M15.0299 18.4711L14.823 18.9922L14.4065 19.2401L14.6918 18.7032L15.0299 18.4711Z' fill='%230000CD'/%3e %3cpath d='M10.798 17.2652L10.4085 17.9362L10.0007 17.0576L10.4319 16.3845L10.798 17.2652Z' fill='%230028FF'/%3e %3cpath d='M14.2575 10.0511L12.7732 10.139L12.8281 9.2398L14.2953 9.19128L14.2575 10.0511Z' fill='%23CEFF29'/%3e %3cpath d='M17.6473 10.3026L15.9036 10.109L15.925 9.29199L17.6535 9.53097L17.6473 10.3026Z' fill='%23C7FF30'/%3e %3cpath d='M14.4069 19.2402L14.2858 19.8033L13.7722 19.9062L13.9658 19.3262L14.4069 19.2402Z' fill='%2300009F'/%3e %3cpath d='M21.0904 12.4609L19.3945 12.1535L19.4088 11.3768L21.1138 11.7395L21.0904 12.4609Z' fill='%2360FF97'/%3e %3cpath d='M21.0566 16.7205L19.9443 16.7854L20.0677 16.8713L21.2285 16.8148L21.0566 16.7205Z' fill='%230040FF'/%3e %3cpath d='M15.6527 17.6224L15.3398 18.085L15.0303 18.4711L15.42 17.9912L15.6527 17.6224Z' fill='blue'/%3e %3cpath d='M13.2424 19.8436L13.1301 20.4526L12.5374 20.2456L12.7098 19.6184L13.2424 19.8436Z' fill='navy'/%3e %3cpath d='M10.6432 13.8322L9.90096 14.4083L9.75 13.3597L10.5137 12.8021L10.6432 13.8322Z' fill='%2316FFE1'/%3e %3cpath d='M22.4975 14.1412L20.9844 13.8719L21.047 13.1777L22.5827 13.5047L22.4975 14.1412Z' fill='%230FF8E7'/%3e %3cpath d='M17.7199 16.1522L16.923 16.403L16.8525 16.8709L17.7104 16.5998L17.7199 16.1522Z' fill='%230058FF'/%3e %3cpath d='M16.9229 16.4028L16.2948 16.7251L16.1582 17.2139L16.8524 16.8708L16.9229 16.4028Z' fill='%230048FF'/%3e %3cpath d='M19.7258 16.2806L18.6882 16.4036L18.74 16.7206L19.8293 16.5871L19.7258 16.2806Z' fill='%230058FF'/%3e %3cpath d='M10.4319 16.3849L10.0007 17.058L9.66479 16.0962L10.1304 15.425L10.4319 16.3849Z' fill='%230068FF'/%3e %3cpath d='M22.9183 16.5539L21.7695 16.4732L21.9437 16.1615L23.1284 16.2819L22.9183 16.5539Z' fill='%230060FF'/%3e %3cpath d='M22.701 16.7369L21.5896 16.6892L21.7699 16.4731L22.9186 16.5538L22.701 16.7369Z' fill='%230054FF'/%3e %3cpath d='M23.1283 16.2818L21.9436 16.1615L22.1074 15.7617L23.3257 15.9276L23.1283 16.2818Z' fill='%230074FF'/%3e %3cpath d='M18.6436 15.9758L17.7197 16.1522L17.7102 16.5998L18.6879 16.4034L18.6436 15.9758Z' fill='%23006CFF'/%3e %3cpath d='M16.295 16.7253L15.8577 17.1123L15.6526 17.6225L16.1584 17.2141L16.295 16.7253Z' fill='%230038FF'/%3e %3cpath d='M20.896 16.5228L19.8291 16.587L19.944 16.7853L21.0563 16.7203L20.896 16.5228Z' fill='%230054FF'/%3e %3cpath d='M19.4124 10.6168L17.647 10.3025L17.6532 9.53088L19.4051 9.89236L19.4124 10.6168Z' fill='%23C1FF36'/%3e %3cpath d='M13.772 19.9065L13.7193 20.4952L13.1301 20.453L13.2424 19.844L13.772 19.9065Z' fill='%23000084'/%3e %3cpath d='M11.4875 11.3575L10.4553 11.768L10.4701 10.7557L11.4998 10.3752L11.4875 11.3575Z' fill='%2397FF60'/%3e %3cpath d='M22.4812 16.8263L21.4075 16.8039L21.5894 16.6891L22.7009 16.7368L22.4812 16.8263Z' fill='%23004CFF'/%3e %3cpath d='M12.773 10.1393L11.4998 10.3756L11.5718 9.44116L12.8279 9.24011L12.773 10.1393Z' fill='%23D1FF26'/%3e %3cpath d='M23.326 15.9275L22.1077 15.7617L22.2569 15.2837L23.5057 15.4996L23.326 15.9275Z' fill='%230090FF'/%3e %3cpath d='M22.5828 13.5045L21.0471 13.1776L21.0907 12.4608L22.6415 12.845L22.5828 13.5045Z' fill='%2336FFC1'/%3e %3cpath d='M21.1139 11.7395L19.4089 11.3768L19.4126 10.6166L21.1162 11.0315L21.1139 11.7395Z' fill='%238DFF6A'/%3e %3cpath d='M15.9249 9.29178L14.2952 9.19141L14.362 8.39941L15.9609 8.53893L15.9249 9.29178Z' fill='%23FFEA00'/%3e %3cpath d='M15.3394 18.0851L15.2042 18.5868L14.823 18.9923L15.03 18.4712L15.3394 18.0851Z' fill='blue'/%3e %3cpath d='M22.2647 16.8201L21.2283 16.8149L21.4074 16.8043L22.4811 16.8266L22.2647 16.8201Z' fill='%230050FF'/%3e %3cpath d='M14.8232 18.9924L14.7705 19.5361L14.2856 19.8034L14.4067 19.2403L14.8232 18.9924Z' fill='%230000C4'/%3e %3cpath d='M23.5058 15.4997L22.2571 15.2837L22.3882 14.7391L23.6634 15.0087L23.5058 15.4997Z' fill='%2300B0FF'/%3e %3cpath d='M17.6536 9.53087L15.925 9.29189L15.9611 8.53906L17.6611 8.81903L17.6536 9.53087Z' fill='%23FBF100'/%3e %3cpath d='M19.6365 15.8729L18.644 15.976L18.6883 16.4036L19.7258 16.2807L19.6365 15.8729Z' fill='%230080FF'/%3e %3cpath d='M14.2953 9.19128L12.8281 9.23979L12.927 8.41112L14.3622 8.39929L14.2953 9.19128Z' fill='%23FFE200'/%3e %3cpath d='M10.5137 12.8022L9.74995 13.3598L9.68188 12.3046L10.4553 11.7682L10.5137 12.8022Z' fill='%2353FFA4'/%3e %3cpath d='M10.1304 15.4247L9.66486 16.0958L9.40942 15.0737L9.90108 14.4083L10.1304 15.4247Z' fill='%2300B0FF'/%3e %3cpath d='M15.8576 17.1122L15.6123 17.5528L15.3396 18.085L15.6525 17.6224L15.8576 17.1122Z' fill='%23002CFF'/%3e %3cpath d='M20.7512 16.2266L19.7253 16.2804L19.8288 16.5869L20.8958 16.5227L20.7512 16.2266Z' fill='%230070FF'/%3e %3cpath d='M11.9556 19.8803L11.9063 20.503L11.3254 19.996L11.398 19.3646L11.9556 19.8803Z' fill='%2300009F'/%3e %3cpath d='M11.3976 19.3641L11.325 19.9955L10.7834 19.3496L10.8778 18.7112L11.3976 19.3641Z' fill='%230000C8'/%3e %3cpath d='M17.729 15.5952L16.9827 15.8177L16.9231 16.4028L17.72 16.1521L17.729 15.5952Z' fill='%23008CFF'/%3e %3cpath d='M22.057 16.7172L21.0564 16.7201L21.2283 16.8145L22.2647 16.8198L22.057 16.7172Z' fill='%23005CFF'/%3e %3cpath d='M16.9827 15.818L16.4096 16.1125L16.2949 16.7255L16.9231 16.4032L16.9827 15.818Z' fill='%23007CFF'/%3e %3cpath d='M23.6634 15.0087L22.3882 14.7391L22.4977 14.1412L23.7947 14.4666L23.6634 15.0087Z' fill='%2300D8FF'/%3e %3cpath d='M12.5374 20.2456L12.5123 20.8585L11.906 20.5025L11.9553 19.8798L12.5374 20.2456Z' fill='%23000089'/%3e %3cpath d='M14.2854 19.8035L14.2906 20.3706L13.7192 20.4951L13.7719 19.9064L14.2854 19.8035Z' fill='%2300009B'/%3e %3cpath d='M22.6413 12.8453L21.0906 12.4611L21.1139 11.7396L22.6717 12.1794L22.6413 12.8453Z' fill='%2363FF94'/%3e %3cpath d='M10.878 18.7115L10.7836 19.3498L10.2944 18.5803L10.4085 17.9365L10.878 18.7115Z' fill='%230000FA'/%3e %3cpath d='M18.6083 15.4476L17.729 15.5954L17.72 16.1523L18.6439 15.9759L18.6083 15.4476Z' fill='%23009CFF'/%3e %3cpath d='M19.4055 9.89242L17.6536 9.53094L17.661 8.81909L19.3874 9.22278L19.4055 9.89242Z' fill='%23F1FC06'/%3e %3cpath d='M21.1164 11.0314L19.4128 10.6165L19.4055 9.89209L21.0976 10.3552L21.1164 11.0314Z' fill='%23BEFF39'/%3e %3cpath d='M16.4099 16.1125L16.0298 16.4723L15.8579 17.1125L16.2952 16.7256L16.4099 16.1125Z' fill='%230070FF'/%3e %3cpath d='M13.1303 20.4528L13.1297 21.0547L12.5125 20.8587L12.5376 20.2458L13.1303 20.4528Z' fill='navy'/%3e %3cpath d='M21.8634 16.5206L20.8962 16.5226L21.0565 16.7201L22.0571 16.7171L21.8634 16.5206Z' fill='%23006CFF'/%3e %3cpath d='M11.4998 10.3755L10.4702 10.756L10.5588 9.79116L11.5719 9.44104L11.4998 10.3755Z' fill='%23D4FF23'/%3e %3cpath d='M23.7945 14.4668L22.4976 14.1415L22.5828 13.5049L23.8963 13.887L23.7945 14.4668Z' fill='%2319FFDE'/%3e %3cpath d='M12.8279 9.23967L11.5718 9.44072L11.7025 8.57845L12.9267 8.41101L12.8279 9.23967Z' fill='%23FFDB00'/%3e %3cpath d='M10.4086 17.9363L10.2945 18.58L9.86963 17.7048L10.0008 17.0576L10.4086 17.9363Z' fill='%230024FF'/%3e %3cpath d='M20.6261 15.8385L19.636 15.8727L19.7254 16.2804L20.7512 16.2266L20.6261 15.8385Z' fill='%230094FF'/%3e %3cpath d='M19.5633 15.3733L18.6082 15.4476L18.6437 15.9758L19.6361 15.8727L19.5633 15.3733Z' fill='%2300ACFF'/%3e %3cpath d='M15.9612 8.53908L14.3623 8.39956L14.4569 7.69666L16.011 7.87059L15.9612 8.53908Z' fill='%23FFB200'/%3e %3cpath d='M9.90084 14.4086L9.40918 15.074L9.24121 14.016L9.74989 13.3601L9.90084 14.4086Z' fill='%2313FCE4'/%3e %3cpath d='M15.2044 18.5868L15.2144 19.1093L14.7705 19.5359L14.8232 18.9923L15.2044 18.5868Z' fill='%230000F1'/%3e %3cpath d='M17.6609 8.81882L15.9609 8.53885L16.0108 7.87036L17.6693 8.18577L17.6609 8.81882Z' fill='%23FFBD00'/%3e %3cpath d='M15.6123 17.5527L15.5404 18.032L15.2043 18.5867L15.3396 18.0849L15.6123 17.5527Z' fill='%230020FF'/%3e %3cpath d='M22.6718 12.1791L21.114 11.7393L21.1164 11.0314L22.6729 11.5237L22.6718 12.1791Z' fill='%238DFF6A'/%3e %3cpath d='M23.5883 16.8344L22.7009 16.737L22.9185 16.554L23.8307 16.6826L23.5883 16.8344Z' fill='%23006CFF'/%3e %3cpath d='M23.8306 16.6828L22.9185 16.5541L23.1286 16.2821L24.0644 16.4485L23.8306 16.6828Z' fill='%230078FF'/%3e %3cpath d='M10.4555 11.7682L9.68213 12.3046L9.69959 11.269L10.4703 10.7559L10.4555 11.7682Z' fill='%2397FF60'/%3e %3cpath d='M23.3433 16.9001L22.481 16.8265L22.7007 16.7371L23.588 16.8345L23.3433 16.9001Z' fill='%230068FF'/%3e %3cpath d='M24.0643 16.448L23.1284 16.2816L23.3258 15.9274L24.2839 16.137L24.0643 16.448Z' fill='%23008CFF'/%3e %3cpath d='M14.3622 8.39923L12.927 8.41106L13.0678 7.67517L14.4568 7.69631L14.3622 8.39923Z' fill='%23FFA700'/%3e %3cpath d='M17.7371 14.9423L17.0298 15.129L16.9827 15.8177L17.7289 15.5952L17.7371 14.9423Z' fill='%2300C4FF'/%3e %3cpath d='M13.7194 20.495L13.7431 21.0854L13.1296 21.0547L13.1302 20.4528L13.7194 20.495Z' fill='%23000084'/%3e %3cpath d='M14.7703 19.536L14.8299 20.0807L14.2905 20.3704L14.2854 19.8033L14.7703 19.536Z' fill='%230000BB'/%3e %3cpath d='M21.6881 16.2348L20.7512 16.2266L20.8958 16.5227L21.8629 16.5207L21.6881 16.2348Z' fill='%230084FF'/%3e %3cpath d='M16.0295 16.4723L15.8409 16.8865L15.6123 17.553L15.8576 17.1124L16.0295 16.4723Z' fill='%230068FF'/%3e %3cpath d='M23.8963 13.8867L22.5828 13.5046L22.6414 12.8451L23.9658 13.2836L23.8963 13.8867Z' fill='%233CFFBA'/%3e %3cpath d='M18.5823 14.8315L17.737 14.9426L17.7288 15.5956L18.6081 15.4478L18.5823 14.8315Z' fill='%2300D0FF'/%3e %3cpath d='M10.001 17.0576L9.86982 17.7048L9.51978 16.7445L9.66509 16.0958L10.001 17.0576Z' fill='%230064FF'/%3e %3cpath d='M23.1022 16.8775L22.2646 16.8198L22.4811 16.8263L23.3434 16.8999L23.1022 16.8775Z' fill='%230068FF'/%3e %3cpath d='M17.0296 15.1293L16.499 15.3895L16.4094 16.1124L16.9825 15.8179L17.0296 15.1293Z' fill='%2300B8FF'/%3e %3cpath d='M24.2838 16.1372L23.3257 15.9275L23.5054 15.4996L24.4836 15.7571L24.2838 16.1372Z' fill='%2300A4FF'/%3e %3cpath d='M21.0975 10.3554L19.4055 9.8923L19.3875 9.22266L21.0578 9.72855L21.0975 10.3554Z' fill='%23EBFF0C'/%3e %3cpath d='M19.3873 9.22253L17.6609 8.81884L17.6693 8.18579L19.3589 8.62552L19.3873 9.22253Z' fill='%23FFC800'/%3e %3cpath d='M20.5241 15.368L19.5635 15.3735L19.6363 15.873L20.6264 15.8388L20.5241 15.368Z' fill='%2300BCFF'/%3e %3cpath d='M22.8707 16.7676L22.0569 16.7173L22.2646 16.8199L23.1022 16.8776L22.8707 16.7676Z' fill='%230074FF'/%3e %3cpath d='M24.4836 15.7573L23.5054 15.4998L23.6629 15.0088L24.6585 15.3175L24.4836 15.7573Z' fill='%2300C4FF'/%3e %3cpath d='M19.5092 14.7942L18.5825 14.8313L18.6084 15.4476L19.5635 15.3733L19.5092 14.7942Z' fill='%2300DCFE'/%3e %3cpath d='M16.4993 15.3893L16.1635 15.7167L16.0295 16.472L16.4096 16.1122L16.4993 15.3893Z' fill='%2300B0FF'/%3e %3cpath d='M22.6727 11.524L21.1162 11.0317L21.0974 10.3555L22.6443 10.896L22.6727 11.524Z' fill='%23B7FF40'/%3e %3cpath d='M21.5367 15.8665L20.6262 15.8387L20.7514 16.2268L21.6882 16.2351L21.5367 15.8665Z' fill='%2300A4FF'/%3e %3cpath d='M23.9655 13.2838L22.6411 12.8453L22.6714 12.1794L24.0007 12.6726L23.9655 13.2838Z' fill='%2363FF94'/%3e %3cpath d='M14.2908 20.3704L14.3381 20.949L13.7432 21.0854L13.7195 20.4949L14.2908 20.3704Z' fill='%23000096'/%3e %3cpath d='M9.74991 13.3597L9.24123 14.0156L9.16577 12.9476L9.68184 12.3046L9.74991 13.3597Z' fill='%2353FFA4'/%3e %3cpath d='M11.572 9.44114L10.5588 9.79126L10.7199 8.8991L11.7027 8.57886L11.572 9.44114Z' fill='gold'/%3e %3cpath d='M16.0107 7.87056L14.4565 7.69662L14.5767 7.10217L16.0733 7.3048L16.0107 7.87056Z' fill='%23FF7A00'/%3e %3cpath d='M12.9269 8.41107L11.7026 8.57851L11.8894 7.81158L13.0677 7.67517L12.9269 8.41107Z' fill='%23FF9C00'/%3e %3cpath d='M17.6695 8.18608L16.011 7.87067L16.0735 7.30493L17.6788 7.64922L17.6695 8.18608Z' fill='%23FF8900'/%3e %3cpath d='M22.655 16.5723L21.8633 16.5206L22.057 16.7171L22.8709 16.7674L22.655 16.5723Z' fill='%230084FF'/%3e %3cpath d='M11.9058 20.5028L11.9763 21.0714L11.3966 20.5653L11.325 19.9957L11.9058 20.5028Z' fill='%2300009F'/%3e %3cpath d='M24.6587 15.3175L23.6631 15.0088L23.7945 14.4667L24.8043 14.8288L24.6587 15.3175Z' fill='%2300E4F8'/%3e %3cpath d='M11.3252 19.9959L11.3968 20.5654L10.8564 19.9211L10.7837 19.35L11.3252 19.9959Z' fill='%230000C8'/%3e %3cpath d='M15.5406 18.0323L15.606 18.5322L15.2146 19.1095L15.2046 18.587L15.5406 18.0323Z' fill='%230018FF'/%3e %3cpath d='M9.66508 16.0961L9.51977 16.7447L9.25366 15.722L9.40964 15.0739L9.66508 16.0961Z' fill='%2300ACFF'/%3e %3cpath d='M12.5123 20.8584L12.5817 21.4268L11.9765 21.0711L11.906 20.5024L12.5123 20.8584Z' fill='%23000089'/%3e %3cpath d='M15.8408 16.8866L15.822 17.3408L15.5403 18.0324L15.6122 17.5531L15.8408 16.8866Z' fill='%23005CFF'/%3e %3cpath d='M17.7441 14.2092L17.0628 14.3537L17.0295 15.129L17.7368 14.9422L17.7441 14.2092Z' fill='%2316FFE1'/%3e %3cpath d='M15.2144 19.1094L15.3238 19.6315L14.8301 20.0808L14.7705 19.5361L15.2144 19.1094Z' fill='%230000ED'/%3e %3cpath d='M21.0577 9.72862L19.3873 9.22273L19.3589 8.62573L20.9979 9.16784L21.0577 9.72862Z' fill='gold'/%3e %3cpath d='M18.5669 14.1423L17.7443 14.2095L17.7371 14.9426L18.5823 14.8315L18.5669 14.1423Z' fill='%231CFFDB'/%3e %3cpath d='M10.4702 10.7558L9.69946 11.269L9.80303 10.2794L10.5588 9.79102L10.4702 10.7558Z' fill='%23D7FF1F'/%3e %3cpath d='M10.7836 19.3498L10.8563 19.9209L10.3682 19.1535L10.2944 18.5802L10.7836 19.3498Z' fill='%230000FA'/%3e %3cpath d='M20.4474 14.8258L19.5093 14.7941L19.5636 15.3732L20.5242 15.3677L20.4474 14.8258Z' fill='%2302E8F4'/%3e %3cpath d='M14.4563 7.69659L13.0674 7.67545L13.2471 7.05273L14.5764 7.10215L14.4563 7.69659Z' fill='%23FF6F00'/%3e %3cpath d='M19.359 8.62564L17.6694 8.18591L17.6786 7.64905L19.3208 8.11761L19.359 8.62564Z' fill='%23FF9800'/%3e %3cpath d='M17.0634 14.354L16.5614 14.5744L16.4995 15.3895L17.0301 15.1293L17.0634 14.354Z' fill='%2313FCE4'/%3e %3cpath d='M22.4596 16.2967L21.688 16.2347L21.8629 16.5207L22.6545 16.5724L22.4596 16.2967Z' fill='%23009CFF'/%3e %3cpath d='M16.1633 15.7167L16.0188 16.1009L15.8408 16.8862L16.0294 16.472L16.1633 15.7167Z' fill='%2300A8FF'/%3e %3cpath d='M21.413 15.4238L20.5242 15.3678L20.6265 15.8385L21.537 15.8662L21.413 15.4238Z' fill='%2300CCFF'/%3e %3cpath d='M24.8045 14.8286L23.7947 14.4665L23.8964 13.8867L24.9169 14.3031L24.8045 14.8286Z' fill='%231FFFD7'/%3e %3cpath d='M13.1295 21.0545L13.1978 21.6233L12.5816 21.4268L12.5122 20.8584L13.1295 21.0545Z' fill='navy'/%3e %3cpath d='M24.0009 12.6726L22.6716 12.1795L22.6727 11.524L24.0006 12.0687L24.0009 12.6726Z' fill='%238DFF6A'/%3e %3cpath d='M22.6443 10.8962L21.0974 10.3556L21.0576 9.72876L22.5869 10.3119L22.6443 10.8962Z' fill='%23E1FF16'/%3e %3cpath d='M19.4748 14.1497L18.5669 14.1421L18.5823 14.8312L19.509 14.7941L19.4748 14.1497Z' fill='%2323FFD4'/%3e %3cpath d='M10.2946 18.5802L10.3683 19.1535L9.94431 18.281L9.86963 17.705L10.2946 18.5802Z' fill='%230024FF'/%3e %3cpath d='M24.19 16.9715L23.5881 16.8346L23.8305 16.6827L24.4458 16.8482L24.19 16.9715Z' fill='%230084FF'/%3e %3cpath d='M14.8301 20.0807L14.8996 20.6475L14.338 20.949L14.2908 20.3704L14.8301 20.0807Z' fill='%230000BB'/%3e %3cpath d='M23.9314 17.0153L23.3433 16.9001L23.5881 16.8345L24.1899 16.9714L23.9314 17.0153Z' fill='%230080FF'/%3e %3cpath d='M24.4459 16.848L23.8306 16.6825L24.0645 16.4482L24.6927 16.6483L24.4459 16.848Z' fill='%230090FF'/%3e %3cpath d='M23.6767 16.9788L23.1021 16.8778L23.3432 16.9002L23.9314 17.0154L23.6767 16.9788Z' fill='%230084FF'/%3e %3cpath d='M24.6924 16.6482L24.0642 16.4481L24.2838 16.1371L24.924 16.3771L24.6924 16.6482Z' fill='%2300A0FF'/%3e %3cpath d='M16.5612 14.5743L16.2555 14.8649L16.1636 15.7169L16.4994 15.3895L16.5612 14.5743Z' fill='%230CF4EB'/%3e %3cpath d='M9.40948 15.0739L9.25349 15.7221L9.07861 14.6616L9.2415 14.0159L9.40948 15.0739Z' fill='%2313FCE4'/%3e %3cpath d='M22.2911 15.9473L21.5369 15.8663L21.6883 16.2349L22.46 16.2969L22.2911 15.9473Z' fill='%2300B8FF'/%3e %3cpath d='M17.6784 7.64898L16.0732 7.30469L16.147 6.85779L17.6882 7.22345L17.6784 7.64898Z' fill='%23FF6000'/%3e %3cpath d='M24.9167 14.3031L23.8962 13.8867L23.9657 13.2836L24.993 13.754L24.9167 14.3031Z' fill='%2343FFB4'/%3e %3cpath d='M9.68183 12.3047L9.16577 12.9478L9.18577 11.8964L9.69929 11.2692L9.68183 12.3047Z' fill='%2397FF60'/%3e %3cpath d='M13.7431 21.0852L13.8104 21.6552L13.1979 21.6233L13.1296 21.0544L13.7431 21.0852Z' fill='%23000084'/%3e %3cpath d='M16.0733 7.3049L14.5767 7.10227L14.7195 6.6333L16.147 6.858L16.0733 7.3049Z' fill='%23FF4E00'/%3e %3cpath d='M20.9977 9.16757L19.3588 8.62545L19.3206 8.11743L20.9193 8.68813L20.9977 9.16757Z' fill='%23FFAB00'/%3e %3cpath d='M23.4323 16.8623L22.8706 16.7676L23.102 16.8776L23.6767 16.9786L23.4323 16.8623Z' fill='%23008CFF'/%3e %3cpath d='M20.3982 14.2265L19.4749 14.15L19.5091 14.7944L20.4472 14.8261L20.3982 14.2265Z' fill='%232CFFCA'/%3e %3cpath d='M24.9241 16.3772L24.2839 16.1371L24.4837 15.7571L25.1347 16.0413L24.9241 16.3772Z' fill='%2300B8FF'/%3e %3cpath d='M11.7028 8.57856L10.72 8.8988L10.9502 8.10331L11.8896 7.81165L11.7028 8.57856Z' fill='%23FF9400'/%3e %3cpath d='M13.0676 7.67522L11.8894 7.81162L12.1281 7.16134L13.2473 7.05249L13.0676 7.67522Z' fill='%23FF6400'/%3e %3cpath d='M21.3194 14.9185L20.447 14.8259L20.5238 15.3678L21.4126 15.4239L21.3194 14.9185Z' fill='%230CF4EB'/%3e %3cpath d='M18.5626 13.3975L17.7504 13.4147L17.7444 14.2093L18.567 14.1421L18.5626 13.3975Z' fill='%2350FFA7'/%3e %3cpath d='M17.7503 13.4147L17.0813 13.5114L17.063 14.3538L17.7443 14.2092L17.7503 13.4147Z' fill='%234DFFAA'/%3e %3cpath d='M24.0008 12.0689L22.6729 11.5242L22.6445 10.8961L23.965 11.4881L24.0008 12.0689Z' fill='%23B4FF43'/%3e %3cpath d='M15.822 17.3406L15.9338 17.817L15.6056 18.5321L15.5403 18.0322L15.822 17.3406Z' fill='%230058FF'/%3e %3cpath d='M19.3206 8.11749L17.6785 7.64892L17.6882 7.22339L19.2735 7.71267L19.3206 8.11749Z' fill='%23FF6F00'/%3e %3cpath d='M9.86958 17.7049L9.94427 18.2809L9.59508 17.3239L9.51953 16.7445L9.86958 17.7049Z' fill='%230068FF'/%3e %3cpath d='M22.5869 10.3115L21.0576 9.72838L20.9978 9.1676L22.5018 9.78666L22.5869 10.3115Z' fill='%23FFE200'/%3e %3cpath d='M15.6059 18.5322L15.7593 19.0323L15.324 19.6317L15.2146 19.1095L15.6059 18.5322Z' fill='%230014FF'/%3e %3cpath d='M16.019 16.1011L16.0417 16.528L15.8223 17.3406L15.8411 16.8864L16.019 16.1011Z' fill='%2300A0FF'/%3e %3cpath d='M23.2042 16.6691L22.6545 16.5725L22.8705 16.7676L23.4322 16.8624L23.2042 16.6691Z' fill='%23009CFF'/%3e %3cpath d='M19.4621 13.4565L18.5627 13.3977L18.5672 14.1423L19.4751 14.1499L19.4621 13.4565Z' fill='%2353FFA4'/%3e %3cpath d='M25.1346 16.0415L24.4836 15.7573L24.6586 15.3175L25.3187 15.6492L25.1346 16.0415Z' fill='%2300D4FF'/%3e %3cpath d='M14.5767 7.10215L13.2473 7.05273L13.4616 6.56104L14.7195 6.63316L14.5767 7.10215Z' fill='%23FF3F00'/%3e %3cpath d='M10.559 9.79097L9.80322 10.2794L9.99136 9.36175L10.72 8.8988L10.559 9.79097Z' fill='%23FFD300'/%3e %3cpath d='M17.0813 13.5115L16.5932 13.6872L16.561 14.5742L17.063 14.3538L17.0813 13.5115Z' fill='%2349FFAD'/%3e %3cpath d='M22.1525 15.5321L21.4126 15.4238L21.5366 15.8663L22.2908 15.9472L22.1525 15.5321Z' fill='%2300DCFE'/%3e %3cpath d='M24.9931 13.7544L23.9658 13.284L24.001 12.6727L25.031 13.1955L24.9931 13.7544Z' fill='%2366FF90'/%3e %3cpath d='M16.2553 14.8647L16.1408 15.2159L16.0188 16.101L16.1634 15.7168L16.2553 14.8647Z' fill='%2309F0EE'/%3e %3cpath d='M14.338 20.9491L14.4043 21.5209L13.8104 21.6555L13.7432 21.0855L14.338 20.9491Z' fill='%2300009B'/%3e %3cpath d='M15.3236 19.6316L15.4133 20.1869L14.8992 20.6476L14.8298 20.0808L15.3236 19.6316Z' fill='%230000E8'/%3e %3cpath d='M22.9988 16.4034L22.4602 16.2968L22.6551 16.5724L23.2047 16.669L22.9988 16.4034Z' fill='%2300B0FF'/%3e %3cpath d='M25.3189 15.649L24.6587 15.3173L24.8043 14.8286L25.4718 15.2099L25.3189 15.649Z' fill='%230CF4EB'/%3e %3cpath d='M21.2594 14.3627L20.3979 14.2263L20.4469 14.826L21.3193 14.9185L21.2594 14.3627Z' fill='%2333FFC4'/%3e %3cpath d='M20.3783 13.5842L19.4617 13.4565L19.4747 14.15L20.3981 14.2264L20.3783 13.5842Z' fill='%2356FFA0'/%3e %3cpath d='M17.6884 7.22365L16.1472 6.85799L16.2303 6.54309L17.6984 6.92188L17.6884 7.22365Z' fill='%23FF3B00'/%3e %3cpath d='M11.9765 21.0714L12.0853 21.5817L11.5116 21.0808L11.3967 20.5653L11.9765 21.0714Z' fill='%230000A8'/%3e %3cpath d='M23.9648 11.488L22.6443 10.896L22.5869 10.3118L23.8939 10.9454L23.9648 11.488Z' fill='%23D7FF1F'/%3e %3cpath d='M20.9195 8.68842L19.3208 8.11772L19.2737 7.71289L20.8242 8.30369L20.9195 8.68842Z' fill='%23FF8600'/%3e %3cpath d='M11.3969 20.5651L11.5118 21.0806L10.9771 20.4433L10.8564 19.9208L11.3969 20.5651Z' fill='%230000CD'/%3e %3cpath d='M9.24126 14.0156L9.07837 14.6613L9 13.5888L9.16581 12.9475L9.24126 14.0156Z' fill='%2353FFA4'/%3e %3cpath d='M16.5932 13.6875L16.3023 13.9376L16.2554 14.865L16.5611 14.5744L16.5932 13.6875Z' fill='%2346FFB1'/%3e %3cpath d='M16.1473 6.85773L14.7197 6.63304L14.8817 6.30347L16.2304 6.54283L16.1473 6.85773Z' fill='%23FF2900'/%3e %3cpath d='M9.51953 16.7446L9.59507 17.3239L9.32971 16.305L9.25342 15.7219L9.51953 16.7446Z' fill='%2300B0FF'/%3e %3cpath d='M18.5694 12.6169L17.7552 12.5793L17.7505 13.4149L18.5626 13.3977L18.5694 12.6169Z' fill='%2380FF77'/%3e %3cpath d='M12.5815 21.4269L12.6842 21.9339L12.0852 21.5815L11.9763 21.0712L12.5815 21.4269Z' fill='%23000092'/%3e %3cpath d='M22.5021 9.78697L20.9982 9.16791L20.9197 8.68848L22.3913 9.33564L22.5021 9.78697Z' fill='%23FFB900'/%3e %3cpath d='M17.7552 12.5791L17.0843 12.6237L17.0815 13.5114L17.7505 13.4147L17.7552 12.5791Z' fill='%2380FF77'/%3e %3cpath d='M22.0482 15.062L21.3193 14.9186L21.4126 15.424L22.1525 15.5323L22.0482 15.062Z' fill='%2316FFE1'/%3e %3cpath d='M19.2738 7.71268L17.6885 7.2234L17.6985 6.92163L19.219 7.42276L19.2738 7.71268Z' fill='%23FF4E00'/%3e %3cpath d='M25.0308 13.1953L24.0007 12.6725L24.0005 12.0687L25.0292 12.6409L25.0308 13.1953Z' fill='%238AFF6D'/%3e %3cpath d='M9.69956 11.269L9.18604 11.8962L9.30216 10.8882L9.80312 10.2794L9.69956 11.269Z' fill='%23D7FF1F'/%3e %3cpath d='M10.8563 19.9207L10.9769 20.4433L10.494 19.6845L10.3682 19.1533L10.8563 19.9207Z' fill='blue'/%3e %3cpath d='M22.8203 16.072L22.2913 15.9473L22.4601 16.2969L22.9987 16.4035L22.8203 16.072Z' fill='%2300C8FF'/%3e %3cpath d='M19.4705 12.7317L18.5692 12.6167L18.5625 13.3975L19.4618 13.4563L19.4705 12.7317Z' fill='%2380FF77'/%3e %3cpath d='M25.4717 15.2101L24.8042 14.8288L24.9166 14.3033L25.5895 14.7351L25.4717 15.2101Z' fill='%2329FFCE'/%3e %3cpath d='M13.2471 7.0526L12.1279 7.16145L12.4129 6.64654L13.4614 6.56091L13.2471 7.0526Z' fill='%23FF3000'/%3e %3cpath d='M11.8896 7.81189L10.9502 8.10356L11.2446 7.42686L12.1283 7.16162L11.8896 7.81189Z' fill='%23FF5900'/%3e %3cpath d='M24.2003 17.1639L23.9316 17.0151L24.1901 16.9712L24.4629 17.139L24.2003 17.1639Z' fill='%230098FF'/%3e %3cpath d='M24.4628 17.1393L24.1899 16.9715L24.4458 16.8481L24.7227 17.0413L24.4628 17.1393Z' fill='%23009CFF'/%3e %3cpath d='M13.198 21.6235L13.2944 22.1292L12.6844 21.934L12.5818 21.427L13.198 21.6235Z' fill='%23000084'/%3e %3cpath d='M23.9414 17.1151L23.677 16.9786L23.9316 17.0152L24.2002 17.164L23.9414 17.1151Z' fill='%230098FF'/%3e %3cpath d='M17.0842 12.6238L16.5945 12.7514L16.5933 13.6872L17.0814 13.5114L17.0842 12.6238Z' fill='%2380FF77'/%3e %3cpath d='M24.7227 17.0412L24.4458 16.8481L24.6926 16.6484L24.9734 16.8724L24.7227 17.0412Z' fill='%2300A4FF'/%3e %3cpath d='M16.0414 16.5281L16.1897 16.9808L15.9339 17.817L15.822 17.3406L16.0414 16.5281Z' fill='%23009CFF'/%3e %3cpath d='M14.8996 20.6477L14.965 21.2219L14.4044 21.521L14.3381 20.9492L14.8996 20.6477Z' fill='%230000BB'/%3e %3cpath d='M15.9342 17.8169L16.1246 18.2958L15.7594 19.032L15.606 18.5319L15.9342 17.8169Z' fill='%230054FF'/%3e %3cpath d='M14.7194 6.63293L13.4614 6.5608L13.7049 6.21484L14.8813 6.30336L14.7194 6.63293Z' fill='%23FF1600'/%3e %3cpath d='M21.2349 13.7707L20.3784 13.5842L20.3981 14.2265L21.2596 14.3629L21.2349 13.7707Z' fill='%235AFF9D'/%3e %3cpath d='M23.6927 16.9936L23.4324 16.8624L23.6768 16.9787L23.9412 17.1151L23.6927 16.9936Z' fill='%2300A0FF'/%3e %3cpath d='M10.3683 19.1532L10.4942 19.6844L10.0749 18.8221L9.94434 18.2808L10.3683 19.1532Z' fill='%230028FF'/%3e %3cpath d='M16.1408 15.2158L16.192 15.6142L16.0414 16.5279L16.0188 16.1009L16.1408 15.2158Z' fill='%2306ECF1'/%3e %3cpath d='M23.8938 10.9454L22.5868 10.3117L22.5017 9.78687L23.7896 10.4555L23.8938 10.9454Z' fill='%23FBF100'/%3e %3cpath d='M20.3887 12.9159L19.4704 12.7319L19.4617 13.4565L20.3783 13.5841L20.3887 12.9159Z' fill='%2380FF77'/%3e %3cpath d='M24.9734 16.8722L24.6926 16.6482L24.9242 16.3772L25.2084 16.6368L24.9734 16.8722Z' fill='%2300B4FF'/%3e %3cpath d='M22.674 15.6827L22.1528 15.5322L22.2912 15.9473L22.8203 16.072L22.674 15.6827Z' fill='%2302E8F4'/%3e %3cpath d='M20.8243 8.30368L19.2738 7.71288L19.219 7.42297L20.7148 8.02465L20.8243 8.30368Z' fill='%23FF6400'/%3e %3cpath d='M10.7199 8.89888L9.99121 9.36182L10.2601 8.54082L10.9501 8.10339L10.7199 8.89888Z' fill='%23FF9100'/%3e %3cpath d='M25.5896 14.735L24.9167 14.3033L24.993 13.7542L25.6691 14.2361L25.5896 14.735Z' fill='%2346FFB1'/%3e %3cpath d='M21.9814 14.5481L21.2598 14.3627L21.3196 14.9185L22.0485 15.0619L21.9814 14.5481Z' fill='%2339FFBE'/%3e %3cpath d='M17.6981 6.92174L16.23 6.54295L16.3203 6.36987L17.7082 6.75301L17.6981 6.92174Z' fill='%23FF2200'/%3e %3cpath d='M25.0292 12.6407L24.0005 12.0686L23.9646 11.4878L24.9878 12.1052L25.0292 12.6407Z' fill='%23ADFF49'/%3e %3cpath d='M16.3023 13.9373L16.203 14.253L16.1409 15.2158L16.2553 14.8646L16.3023 13.9373Z' fill='%2343FFB4'/%3e %3cpath d='M23.4611 16.8024L23.2046 16.6692L23.4326 16.8624L23.693 16.9936L23.4611 16.8024Z' fill='%2300B0FF'/%3e %3cpath d='M22.3913 9.33524L20.9197 8.68808L20.8245 8.30334L22.2575 8.96999L22.3913 9.33524Z' fill='%23FF9800'/%3e %3cpath d='M15.7593 19.0319L15.8669 19.5764L15.4137 20.1866L15.324 19.6313L15.7593 19.0319Z' fill='%230014FF'/%3e %3cpath d='M18.5872 11.8202L17.7583 11.7245L17.7551 12.579L18.5694 12.6166L18.5872 11.8202Z' fill='%23B4FF43'/%3e %3cpath d='M25.2085 16.6368L24.9243 16.3772L25.1349 16.0414L25.4221 16.3405L25.2085 16.6368Z' fill='%2300C8FF'/%3e %3cpath d='M13.8104 21.6555L13.9006 22.1619L13.2944 22.1293L13.198 21.6237L13.8104 21.6555Z' fill='%2300008D'/%3e %3cpath d='M19.2189 7.42292L17.6985 6.92179L17.7085 6.75305L19.1579 7.25669L19.2189 7.42292Z' fill='%23FF3800'/%3e %3cpath d='M9.25349 15.722L9.32978 16.3051L9.15551 15.2486L9.07861 14.6615L9.25349 15.722Z' fill='%2313FCE4'/%3e %3cpath d='M19.5009 11.9949L18.5872 11.8202L18.5693 12.6166L19.4706 12.7316L19.5009 11.9949Z' fill='%23ADFF49'/%3e %3cpath d='M17.7582 11.7247L17.071 11.7144L17.0841 12.6238L17.755 12.5792L17.7582 11.7247Z' fill='%23B7FF40'/%3e %3cpath d='M16.2301 6.54267L14.8813 6.30331L15.0583 6.12354L16.3204 6.3696L16.2301 6.54267Z' fill='%23F60B00'/%3e %3cpath d='M16.5944 12.7513L16.3025 12.9585L16.3022 13.9373L16.5932 13.6871L16.5944 12.7513Z' fill='%2380FF77'/%3e %3cpath d='M9.16581 12.9479L9 13.5892L9.02121 12.5317L9.18581 11.8965L9.16581 12.9479Z' fill='%2397FF60'/%3e %3cpath d='M23.2516 16.5461L22.9985 16.4034L23.2044 16.6691L23.461 16.8023L23.2516 16.5461Z' fill='%2300C0FF'/%3e %3cpath d='M9.9444 18.2808L10.0749 18.8221L9.72973 17.8764L9.59521 17.3237L9.9444 18.2808Z' fill='%230068FF'/%3e %3cpath d='M22.5636 15.2453L22.0486 15.062L22.1528 15.5323L22.6739 15.6828L22.5636 15.2453Z' fill='%231FFFD7'/%3e %3cpath d='M25.4217 16.3406L25.1345 16.0415L25.3187 15.6492L25.6082 15.9908L25.4217 16.3406Z' fill='%2300E0FB'/%3e %3cpath d='M21.2463 13.1575L20.3887 12.9159L20.3784 13.5842L21.2349 13.7707L21.2463 13.1575Z' fill='%2380FF77'/%3e %3cpath d='M25.669 14.2359L24.9929 13.754L25.0309 13.1951L25.7078 13.7257L25.669 14.2359Z' fill='%2366FF90'/%3e %3cpath d='M23.7896 10.4556L22.5017 9.78691L22.3909 9.33557L23.6545 10.0315L23.7896 10.4556Z' fill='%23FFCC00'/%3e %3cpath d='M20.4293 12.2391L19.501 11.9952L19.4707 12.7319L20.389 12.9158L20.4293 12.2391Z' fill='%23AAFF4D'/%3e %3cpath d='M17.071 11.7145L16.5642 11.7918L16.5943 12.7516L17.084 12.624L17.071 11.7145Z' fill='%23BAFF3C'/%3e %3cpath d='M21.9531 14.0038L21.2349 13.7705L21.2595 14.3626L21.9812 14.548L21.9531 14.0038Z' fill='%235AFF9D'/%3e %3cpath d='M20.7148 8.02439L19.219 7.42272L19.158 7.25647L20.5937 7.85933L20.7148 8.02439Z' fill='%23FF4E00'/%3e %3cpath d='M9.80273 10.2796L9.30176 10.8884L9.51225 9.9504L9.99086 9.36194L9.80273 10.2796Z' fill='%23FFD000'/%3e %3cpath d='M24.9881 12.1054L23.9649 11.488L23.894 10.9454L24.9079 11.6027L24.9881 12.1054Z' fill='%23D1FF26'/%3e %3cpath d='M13.4616 6.5608L12.4131 6.64642L12.7372 6.2823L13.7051 6.21484L13.4616 6.5608Z' fill='%23F10800'/%3e %3cpath d='M23.07 16.2311L22.8201 16.0719L22.9985 16.4034L23.2515 16.5461L23.07 16.2311Z' fill='%2300D8FF'/%3e %3cpath d='M15.4135 20.187L15.4781 20.7642L14.9648 21.2219L14.8994 20.6477L15.4135 20.187Z' fill='%230000ED'/%3e %3cpath d='M22.257 8.97021L20.8239 8.30357L20.7144 8.02454L22.1036 8.70135L22.257 8.97021Z' fill='%23FF7A00'/%3e %3cpath d='M14.8815 6.30363L13.7051 6.21511L13.9716 6.02588L15.0584 6.12386L14.8815 6.30363Z' fill='%23DF0000'/%3e %3cpath d='M18.616 11.0297L17.7601 10.8743L17.7585 11.7248L18.5874 11.8204L18.616 11.0297Z' fill='%23E4FF13'/%3e %3cpath d='M17.7084 6.75312L16.3206 6.36999L16.4157 6.34473L17.7183 6.72309L17.7084 6.75312Z' fill='%23FA0F00'/%3e %3cpath d='M12.1283 7.16165L11.2446 7.4269L11.5961 6.88848L12.4133 6.64673L12.1283 7.16165Z' fill='%23FF2500'/%3e %3cpath d='M25.6084 15.9906L25.3188 15.649L25.4718 15.2098L25.7631 15.5959L25.6084 15.9906Z' fill='%2316FFE1'/%3e %3cpath d='M14.4044 21.5208L14.4885 22.0299L13.9007 22.1617L13.8105 21.6554L14.4044 21.5208Z' fill='%2300009F'/%3e %3cpath d='M19.1576 7.25644L17.7083 6.7528L17.7181 6.72278L19.0919 7.21923L19.1576 7.25644Z' fill='%23FF2500'/%3e %3cpath d='M19.5523 11.2661L18.6157 11.0298L18.5872 11.8205L19.5009 11.9952L19.5523 11.2661Z' fill='%23DBFF1C'/%3e %3cpath d='M17.7598 10.8744L17.0425 10.8079L17.0711 11.7146L17.7582 11.7249L17.7598 10.8744Z' fill='%23EBFF0C'/%3e %3cpath d='M16.1918 15.6141L16.3653 16.0433L16.1895 16.9806L16.0413 16.5279L16.1918 15.6141Z' fill='%2302E8F4'/%3e %3cpath d='M22.4921 14.7704L21.9812 14.548L22.0483 15.0618L22.5634 15.2451L22.4921 14.7704Z' fill='%233CFFBA'/%3e %3cpath d='M16.1899 16.981L16.4093 17.4402L16.1245 18.2961L15.9341 17.8172L16.1899 16.981Z' fill='%230098FF'/%3e %3cpath d='M16.203 14.2531L16.2688 14.622L16.192 15.6141L16.1409 15.2158L16.203 14.2531Z' fill='%2343FFB4'/%3e %3cpath d='M16.3204 6.36966L15.0583 6.1236L15.2456 6.09998L16.4156 6.34441L16.3204 6.36966Z' fill='%23DF0000'/%3e %3cpath d='M12.0854 21.5816L12.192 22.0092L11.6293 21.5178L11.5117 21.0807L12.0854 21.5816Z' fill='%230000B2'/%3e %3cpath d='M25.7081 13.7256L25.0311 13.195L25.0295 12.6406L25.7052 13.2172L25.7081 13.7256Z' fill='%238AFF6D'/%3e %3cpath d='M11.5118 21.0808L11.6294 21.5179L11.1049 20.893L10.9771 20.4435L11.5118 21.0808Z' fill='%230000DA'/%3e %3cpath d='M21.294 12.5389L20.4292 12.2388L20.3889 12.9155L21.2465 13.1571L21.294 12.5389Z' fill='%23A7FF50'/%3e %3cpath d='M16.3023 12.9585L16.2026 13.2375L16.2028 14.253L16.3021 13.9372L16.3023 12.9585Z' fill='%2380FF77'/%3e %3cpath d='M22.9213 15.8651L22.6741 15.6825L22.8204 16.0718L23.0703 16.231L22.9213 15.8651Z' fill='%230CF4EB'/%3e %3cpath d='M24.126 17.3402L24.2001 17.1638L24.4627 17.1389L24.3857 17.3318L24.126 17.3402Z' fill='%2300A8FF'/%3e %3cpath d='M23.6545 10.0313L22.3909 9.33535L22.2571 8.97009L23.492 9.68489L23.6545 10.0313Z' fill='%23FFAB00'/%3e %3cpath d='M9.59496 17.3238L9.72947 17.8764L9.4673 16.8698L9.32959 16.3048L9.59496 17.3238Z' fill='%2300B0FF'/%3e %3cpath d='M20.4988 11.5716L19.5526 11.266L19.5012 11.9951L20.4294 12.2389L20.4988 11.5716Z' fill='%23D4FF23'/%3e %3cpath d='M23.8701 17.2808L23.9414 17.115L24.2002 17.1639L24.1261 17.3403L23.8701 17.2808Z' fill='%2300ACFF'/%3e %3cpath d='M10.9502 8.10345L10.2603 8.54088L10.604 7.83941L11.2446 7.42676L10.9502 8.10345Z' fill='%23FF5500'/%3e %3cpath d='M9.07837 14.6613L9.15527 15.2484L9.07734 14.1804L9 13.5889L9.07837 14.6613Z' fill='%2353FFA4'/%3e %3cpath d='M12.6844 21.934L12.7796 22.3552L12.1921 22.0091L12.0854 21.5815L12.6844 21.934Z' fill='%2300009B'/%3e %3cpath d='M20.5933 7.8594L19.1575 7.25654L19.0918 7.21936L20.4638 7.81348L20.5933 7.8594Z' fill='%23FF3F00'/%3e %3cpath d='M24.3855 17.332L24.4626 17.1392L24.7225 17.0411L24.6424 17.2557L24.3855 17.332Z' fill='%2300ACFF'/%3e %3cpath d='M16.5645 11.7915L16.2556 11.9543L16.3027 12.9585L16.5946 12.7513L16.5645 11.7915Z' fill='%23BEFF39'/%3e %3cpath d='M16.1242 18.2959L16.2469 18.8305L15.8666 19.5766L15.759 19.0321L16.1242 18.2959Z' fill='%230050FF'/%3e %3cpath d='M21.9651 13.4429L21.2463 13.1571L21.2349 13.7703L21.9531 14.0036L21.9651 13.4429Z' fill='%2380FF77'/%3e %3cpath d='M25.763 15.5961L25.4717 15.21L25.5895 14.735L25.8817 15.1663L25.763 15.5961Z' fill='%2330FFC7'/%3e %3cpath d='M24.9078 11.6025L23.894 10.9452L23.7898 10.4553L24.7905 11.1461L24.9078 11.6025Z' fill='%23F1FC06'/%3e %3cpath d='M23.6243 17.1548L23.6929 16.9934L23.9413 17.1149L23.8701 17.2808L23.6243 17.1548Z' fill='%2300B4FF'/%3e %3cpath d='M10.9768 20.4434L11.1047 20.893L10.6312 20.1493L10.4939 19.6847L10.9768 20.4434Z' fill='blue'/%3e %3cpath d='M22.1036 8.70114L20.7144 8.02432L20.5933 7.85925L21.9347 8.53648L22.1036 8.70114Z' fill='%23FF6400'/%3e %3cpath d='M24.6428 17.2557L24.7229 17.0411L24.9736 16.8723L24.8904 17.1135L24.6428 17.2557Z' fill='%2300B8FF'/%3e %3cpath d='M18.6545 10.2661L17.76 10.051L17.7601 10.8742L18.6159 11.0297L18.6545 10.2661Z' fill='gold'/%3e %3cpath d='M17.0424 10.8079L16.5034 10.834L16.5642 11.7919L17.071 11.7146L17.0424 10.8079Z' fill='%23F1FC06'/%3e %3cpath d='M17.7183 6.72273L16.4158 6.34436L16.5131 6.46876L17.7276 6.83321L17.7183 6.72273Z' fill='%23ED0400'/%3e %3cpath d='M19.0921 7.2196L17.7183 6.72314L17.7276 6.83363L19.0234 7.3133L19.0921 7.2196Z' fill='%23FF1E00'/%3e %3cpath d='M19.6234 10.5642L18.6543 10.2662L18.6157 11.0298L19.5523 11.2661L19.6234 10.5642Z' fill='%23FFE200'/%3e %3cpath d='M23.395 16.9656L23.4612 16.8025L23.6931 16.9937L23.6245 17.155L23.395 16.9656Z' fill='%2300C0FF'/%3e %3cpath d='M9.18584 11.8961L9.02124 12.5314L9.14272 11.5159L9.30196 10.8882L9.18584 11.8961Z' fill='%23D7FF1F'/%3e %3cpath d='M13.2945 22.1293L13.3782 22.5473L12.7798 22.3552L12.6846 21.9341L13.2945 22.1293Z' fill='%23000092'/%3e %3cpath d='M17.7598 10.0511L16.999 9.92871L17.0426 10.8078L17.7599 10.8744L17.7598 10.0511Z' fill='%23FFCC00'/%3e %3cpath d='M24.8901 17.1134L24.9733 16.8722L25.2083 16.6368L25.1222 16.9087L24.8901 17.1134Z' fill='%2300C4FF'/%3e %3cpath d='M22.4621 14.2707L21.9534 14.0038L21.9814 14.548L22.4923 14.7705L22.4621 14.2707Z' fill='%235DFF9A'/%3e %3cpath d='M22.8088 15.4576L22.5637 15.2454L22.674 15.6828L22.9213 15.8654L22.8088 15.4576Z' fill='%2326FFD1'/%3e %3cpath d='M25.705 13.2173L25.0294 12.6408L24.988 12.1052L25.6601 12.7239L25.705 13.2173Z' fill='%23AAFF4D'/%3e %3cpath d='M15.0585 6.12399L13.9717 6.02601L14.2541 6.00024L15.2457 6.10036L15.0585 6.12399Z' fill='%23C80000'/%3e %3cpath d='M14.9647 21.2219L15.0432 21.7358L14.4882 22.0302L14.4041 21.521L14.9647 21.2219Z' fill='%230000C4'/%3e %3cpath d='M23.1875 16.7176L23.2516 16.5464L23.461 16.8026L23.3948 16.9658L23.1875 16.7176Z' fill='%2300D0FF'/%3e %3cpath d='M13.705 6.215L12.7371 6.28245L13.092 6.08072L13.9715 6.02576L13.705 6.215Z' fill='%23CD0000'/%3e %3cpath d='M21.3765 11.9322L20.4986 11.5718L20.4292 12.2391L21.294 12.5392L21.3765 11.9322Z' fill='%23CEFF29'/%3e %3cpath d='M20.4642 7.81348L19.0921 7.21936L19.0234 7.31306L20.3299 7.88856L20.4642 7.81348Z' fill='%23FF3800'/%3e %3cpath d='M20.5953 10.9318L19.6233 10.5642L19.5522 11.2661L20.4985 11.5717L20.5953 10.9318Z' fill='%23FBF100'/%3e %3cpath d='M25.8819 15.1662L25.5896 14.7348L25.669 14.2358L25.9615 14.7123L25.8819 15.1662Z' fill='%234DFFAA'/%3e %3cpath d='M10.494 19.6845L10.6313 20.1491L10.2203 19.3041L10.0747 18.8221L10.494 19.6845Z' fill='%230030FF'/%3e %3cpath d='M16.4156 6.34453L15.2456 6.1001L15.4381 6.23457L16.5129 6.46893L16.4156 6.34453Z' fill='%23D10000'/%3e %3cpath d='M23.4923 9.6852L22.2574 8.9704L22.104 8.70154L23.3064 9.42602L23.4923 9.6852Z' fill='%23FF9100'/%3e %3cpath d='M15.8668 19.5765L15.9307 20.1572L15.4782 20.7639L15.4136 20.1868L15.8668 19.5765Z' fill='%230014FF'/%3e %3cpath d='M18.702 9.55075L17.7583 9.27783L17.76 10.051L18.6545 10.2661L18.702 9.55075Z' fill='%23FFA700'/%3e %3cpath d='M25.1223 16.9087L25.2084 16.6368L25.422 16.3406L25.3329 16.6465L25.1223 16.9087Z' fill='%2300D8FF'/%3e %3cpath d='M22.017 12.8807L21.2938 12.5392L21.2463 13.1575L21.9651 13.4433L22.017 12.8807Z' fill='%23A4FF53'/%3e %3cpath d='M21.9352 8.53663L20.5938 7.8594L20.4644 7.81348L21.7551 8.48119L21.9352 8.53663Z' fill='%23FF5500'/%3e %3cpath d='M24.7903 11.1464L23.7896 10.4556L23.6545 10.0316L24.6388 10.7485L24.7903 11.1464Z' fill='%23FFDB00'/%3e %3cpath d='M19.0236 7.31305L17.7278 6.83337L17.7363 7.08213L18.9539 7.53573L19.0236 7.31305Z' fill='%23FF1E00'/%3e %3cpath d='M9.99106 9.36198L9.51245 9.95044L9.81307 9.10774L10.26 8.54102L9.99106 9.36198Z' fill='%23FF8D00'/%3e %3cpath d='M19.7124 9.90874L18.7019 9.55078L18.6543 10.2662L19.6234 10.5642L19.7124 9.90874Z' fill='%23FFB600'/%3e %3cpath d='M17.7274 6.83356L16.5129 6.46912L16.6099 6.7407L17.7359 7.08233L17.7274 6.83356Z' fill='%23F10800'/%3e %3cpath d='M12.4133 6.64659L11.5962 6.88834L11.9961 6.50436L12.7375 6.28247L12.4133 6.64659Z' fill='%23E40000'/%3e %3cpath d='M23.0078 16.4166L23.0702 16.2311L23.2517 16.5461L23.1876 16.7173L23.0078 16.4166Z' fill='%2302E8F4'/%3e %3cpath d='M16.9989 9.9284L16.4133 9.90417L16.5034 10.8337L17.0424 10.8075L16.9989 9.9284Z' fill='%23FFC100'/%3e %3cpath d='M17.7581 9.27788L16.9417 9.10156L16.999 9.92864L17.7598 10.0511L17.7581 9.27788Z' fill='%23FF9800'/%3e %3cpath d='M13.9007 22.1616L13.9729 22.5798L13.3781 22.5471L13.2944 22.129L13.9007 22.1616Z' fill='%23000096'/%3e %3cpath d='M16.5037 10.8337L16.1621 10.9521L16.2556 11.9544L16.5645 11.7916L16.5037 10.8337Z' fill='%23F8F500'/%3e %3cpath d='M22.7359 15.0182L22.4924 14.7708L22.5637 15.2454L22.8088 15.4576L22.7359 15.0182Z' fill='%2343FFB4'/%3e %3cpath d='M9.33004 16.3049L9.46774 16.8699L9.29578 15.8266L9.15576 15.2485L9.33004 16.3049Z' fill='%2313FCE4'/%3e %3cpath d='M20.3295 7.88861L19.0231 7.31311L18.9534 7.53578L20.194 8.08319L20.3295 7.88861Z' fill='%23FF3800'/%3e %3cpath d='M16.2556 11.9545L16.1399 12.1964L16.203 13.2377L16.3027 12.9586L16.2556 11.9545Z' fill='%23C1FF36'/%3e %3cpath d='M22.474 13.7589L21.9653 13.4434L21.9534 14.0041L22.4621 14.271L22.474 13.7589Z' fill='%2380FF77'/%3e %3cpath d='M18.757 8.90348L17.7546 8.57629L17.758 9.27797L18.7017 9.55088L18.757 8.90348Z' fill='%23FF7E00'/%3e %3cpath d='M25.3328 16.6466L25.4218 16.3407L25.6083 15.9908L25.5165 16.3334L25.3328 16.6466Z' fill='%2309F0EE'/%3e %3cpath d='M16.2026 13.2379L16.2687 13.5773L16.2687 14.6223L16.2028 14.2534L16.2026 13.2379Z' fill='%2383FF73'/%3e %3cpath d='M20.7167 10.3366L19.7121 9.90881L19.623 10.5643L20.595 10.9318L20.7167 10.3366Z' fill='%23FFC400'/%3e %3cpath d='M18.9537 7.53587L17.7361 7.08228L17.7436 7.46304L18.8848 7.88188L18.9537 7.53587Z' fill='%23FF2900'/%3e %3cpath d='M16.2687 14.6222L16.4554 15.0286L16.3654 16.0435L16.1919 15.6144L16.2687 14.6222Z' fill='%2340FFB7'/%3e %3cpath d='M19.817 9.31762L18.7572 8.9032L18.7019 9.5506L19.7124 9.90856L19.817 9.31762Z' fill='%23FF9100'/%3e %3cpath d='M25.66 12.724L24.988 12.1053L24.9077 11.6027L25.574 12.2585L25.66 12.724Z' fill='%23CAFF2C'/%3e %3cpath d='M25.9614 14.7124L25.6689 14.2359L25.7078 13.7257L25.9997 14.2459L25.9614 14.7124Z' fill='%236AFF8D'/%3e %3cpath d='M21.4916 11.3525L20.5951 10.9316L20.4983 11.5716L21.3762 11.932L21.4916 11.3525Z' fill='%23F1FC06'/%3e %3cpath d='M16.3655 16.0436L16.6051 16.4851L16.4091 17.44L16.1897 16.9808L16.3655 16.0436Z' fill='%2300E4F8'/%3e %3cpath d='M23.3064 9.42601L22.104 8.70153L21.9351 8.53687L23.1021 9.26143L23.3064 9.42601Z' fill='%23FF7A00'/%3e %3cpath d='M21.7549 8.48131L20.4641 7.8136L20.3298 7.8887L21.5685 8.53701L21.7549 8.48131Z' fill='%23FF4E00'/%3e %3cpath d='M17.7359 7.08211L16.6099 6.74048L16.7037 7.15244L17.7434 7.46288L17.7359 7.08211Z' fill='%23FF1300'/%3e %3cpath d='M16.5131 6.46886L15.4382 6.2345L15.6307 6.52443L16.6101 6.74044L16.5131 6.46886Z' fill='%23D60000'/%3e %3cpath d='M18.8186 8.34187L17.7498 7.96558L17.7546 8.57619L18.757 8.90337L18.8186 8.34187Z' fill='%23FF5900'/%3e %3cpath d='M9 13.5891L9.07734 14.1806L9.09883 13.1276L9.02121 12.5316L9 13.5891Z' fill='%2397FF60'/%3e %3cpath d='M18.8849 7.88149L17.7437 7.46265L17.7499 7.96522L18.8188 8.34151L18.8849 7.88149Z' fill='%23FF3B00'/%3e %3cpath d='M10.0749 18.8223L10.2205 19.3043L9.8823 18.3779L9.72974 17.8766L10.0749 18.8223Z' fill='%230070FF'/%3e %3cpath d='M22.8601 16.0707L22.9212 15.8651L23.0702 16.2311L23.0078 16.4165L22.8601 16.0707Z' fill='%2316FFE1'/%3e %3cpath d='M20.1942 8.08292L18.9536 7.53552L18.8848 7.88151L20.0612 8.39204L20.1942 8.08292Z' fill='%23FF4300'/%3e %3cpath d='M17.755 8.57607L16.8723 8.34949L16.9419 9.10145L17.7583 9.27776L17.755 8.57607Z' fill='%23FF6C00'/%3e %3cpath d='M19.9342 8.80745L18.8186 8.34167L18.7571 8.90319L19.8169 9.31761L19.9342 8.80745Z' fill='%23FF6F00'/%3e %3cpath d='M22.1077 12.3309L21.3762 11.9321L21.2937 12.5391L22.017 12.8806L22.1077 12.3309Z' fill='%23C7FF30'/%3e %3cpath d='M11.2441 7.42672L10.6035 7.83938L11.0139 7.27762L11.5956 6.88831L11.2441 7.42672Z' fill='%23FF1E00'/%3e %3cpath d='M15.2458 6.10012L14.2542 6L14.5449 6.13984L15.4383 6.23458L15.2458 6.10012Z' fill='%23BB0000'/%3e %3cpath d='M24.6392 10.7484L23.655 10.0315L23.4924 9.68506L24.4573 10.4199L24.6392 10.7484Z' fill='%23FFBD00'/%3e %3cpath d='M20.0614 8.39236L18.885 7.88184L18.8188 8.34187L19.9344 8.80764L20.0614 8.39236Z' fill='%23FF5500'/%3e %3cpath d='M16.4089 17.4399L16.5433 17.9659L16.2466 18.8305L16.124 18.2958L16.4089 17.4399Z' fill='%230098FF'/%3e %3cpath d='M17.7435 7.46267L16.7039 7.15222L16.792 7.69351L17.7498 7.96524L17.7435 7.46267Z' fill='%23FF2900'/%3e %3cpath d='M17.75 7.9657L16.7922 7.69397L16.8722 8.34974L17.7549 8.57633L17.75 7.9657Z' fill='%23FF4700'/%3e %3cpath d='M20.8603 9.8026L19.8167 9.31787L19.7122 9.90884L20.7168 10.3367L20.8603 9.8026Z' fill='%23FFA300'/%3e %3cpath d='M16.9417 9.10147L16.2964 9.02905L16.4135 9.90432L16.9991 9.92854L16.9417 9.10147Z' fill='%23FF8900'/%3e %3cpath d='M25.5166 16.3332L25.6084 15.9907L25.7631 15.5959L25.6687 15.9768L25.5166 16.3332Z' fill='%231CFFDB'/%3e %3cpath d='M21.5685 8.5371L20.3299 7.88879L20.1943 8.08338L21.3809 8.70285L21.5685 8.5371Z' fill='%23FF5200'/%3e %3cpath d='M22.7042 14.5579L22.4619 14.2706L22.4921 14.7704L22.7356 15.0178L22.7042 14.5579Z' fill='%2360FF97'/%3e %3cpath d='M23.4626 17.4728L23.87 17.281L24.126 17.3405L23.7111 17.5415L23.4626 17.4728Z' fill='%2300BCFF'/%3e %3cpath d='M13.9717 6.02588L13.0923 6.08085L13.4687 6.04871L14.2542 6.00012L13.9717 6.02588Z' fill='%23B20000'/%3e %3cpath d='M23.7112 17.5413L24.1261 17.3403L24.3858 17.3318L23.9631 17.5467L23.7112 17.5413Z' fill='%2300B8FF'/%3e %3cpath d='M15.4783 20.764L15.5517 21.2846L15.0436 21.7357L14.9651 21.2218L15.4783 20.764Z' fill='%230000F1'/%3e %3cpath d='M23.2239 17.3423L23.6241 17.1548L23.8699 17.2808L23.4625 17.4725L23.2239 17.3423Z' fill='%2300C4FF'/%3e %3cpath d='M21.6373 10.8162L20.717 10.3364L20.5952 10.9316L21.4918 11.3525L21.6373 10.8162Z' fill='gold'/%3e %3cpath d='M22.5277 13.2474L22.017 12.8804L21.9651 13.443L22.4738 13.7585L22.5277 13.2474Z' fill='%23A0FF56'/%3e %3cpath d='M23.102 9.26099L21.935 8.53642L21.7549 8.48096L22.8845 9.19592L23.102 9.26099Z' fill='%23FF6F00'/%3e %3cpath d='M16.61 6.74042L15.6306 6.52441L15.8177 6.96254L16.7038 7.15235L16.61 6.74042Z' fill='%23E40000'/%3e %3cpath d='M21.0219 9.34431L19.9343 8.80774L19.8169 9.3179L20.8605 9.80262L21.0219 9.34431Z' fill='%23FF8200'/%3e %3cpath d='M9.30182 10.8883L9.14258 11.516L9.36249 10.5691L9.5123 9.95032L9.30182 10.8883Z' fill='%23FFD000'/%3e %3cpath d='M14.4885 22.0299L14.5496 22.4518L13.9728 22.58L13.9006 22.1618L14.4885 22.0299Z' fill='%230000A8'/%3e %3cpath d='M16.4134 9.9043L16.0242 9.97929L16.1619 10.9521L16.5035 10.8338L16.4134 9.9043Z' fill='%23FFB900'/%3e %3cpath d='M22.748 15.6884L22.8084 15.4574L22.9209 15.8652L22.8598 16.0708L22.748 15.6884Z' fill='%2330FFC7'/%3e %3cpath d='M23.9631 17.5469L24.3858 17.332L24.6427 17.2557L24.2122 17.489L23.9631 17.5469Z' fill='%2300BCFF'/%3e %3cpath d='M25.9997 14.2461L25.7078 13.726L25.7048 13.2175L25.9954 13.779L25.9997 14.2461Z' fill='%2387FF70'/%3e %3cpath d='M21.3811 8.70285L20.1946 8.08337L20.0615 8.39246L21.1973 8.97436L21.3811 8.70285Z' fill='%23FF5900'/%3e %3cpath d='M25.5739 12.2584L24.9076 11.6025L24.7903 11.1461L25.4488 11.8331L25.5739 12.2584Z' fill='%23E7FF0F'/%3e %3cpath d='M23.0012 17.154L23.3949 16.9657L23.6243 17.1551L23.2241 17.3426L23.0012 17.154Z' fill='%2300D0FF'/%3e %3cpath d='M21.1968 8.97436L20.061 8.39246L19.9341 8.80778L21.0217 9.34435L21.1968 8.97436Z' fill='%23FF6C00'/%3e %3cpath d='M16.8722 8.34961L16.1555 8.23267L16.2965 9.02914L16.9418 9.10155L16.8722 8.34961Z' fill='%23FF5D00'/%3e %3cpath d='M12.1924 22.009L12.2662 22.3335L11.7192 21.8558L11.6296 21.5176L12.1924 22.009Z' fill='%230000C4'/%3e %3cpath d='M22.2354 11.8088L21.4919 11.3525L21.3765 11.932L22.108 12.3308L22.2354 11.8088Z' fill='%23E7FF0F'/%3e %3cpath d='M24.2122 17.4887L24.6426 17.2555L24.8902 17.1133L24.4521 17.3686L24.2122 17.4887Z' fill='%2300C4FF'/%3e %3cpath d='M24.4569 10.4198L23.492 9.68497L23.3062 9.42578L24.2494 10.1699L24.4569 10.4198Z' fill='%23FFA700'/%3e %3cpath d='M16.7039 7.15257L15.8179 6.96277L15.9944 7.53741L16.7921 7.69387L16.7039 7.15257Z' fill='%23FF1300'/%3e %3cpath d='M11.6294 21.5175L11.719 21.8557L11.2093 21.2485L11.105 20.8926L11.6294 21.5175Z' fill='%230000E8'/%3e %3cpath d='M25.6687 15.9767L25.7631 15.5959L25.8818 15.1661L25.7851 15.5859L25.6687 15.9767Z' fill='%2336FFC1'/%3e %3cpath d='M22.7998 16.9116L23.1876 16.7173L23.3949 16.9654L23.0013 17.1537L22.7998 16.9116Z' fill='%2300E0FB'/%3e %3cpath d='M16.7921 7.69382L15.9944 7.53735L16.1554 8.23263L16.8721 8.34957L16.7921 7.69382Z' fill='%23FF3400'/%3e %3cpath d='M16.1622 10.9523L16.0149 11.1577L16.1399 12.1965L16.2557 11.9546L16.1622 10.9523Z' fill='%23FBF100'/%3e %3cpath d='M16.247 18.8304L16.3105 19.415L15.9307 20.1571L15.8667 19.5765L16.247 18.8304Z' fill='%230054FF'/%3e %3cpath d='M12.7372 6.28266L11.9958 6.50456L12.4339 6.28722L13.0922 6.08093L12.7372 6.28266Z' fill='%23BB0000'/%3e %3cpath d='M15.438 6.23463L14.5447 6.13989L14.8358 6.44265L15.6305 6.52457L15.438 6.23463Z' fill='%23BF0000'/%3e %3cpath d='M21.8092 10.3378L20.8605 9.80249L20.717 10.3366L21.6374 10.8163L21.8092 10.3378Z' fill='%23FFB600'/%3e %3cpath d='M22.8844 9.19629L21.7547 8.48132L21.5684 8.53703L22.6597 9.2328L22.8844 9.19629Z' fill='%23FF6800'/%3e %3cpath d='M12.7797 22.3552L12.8371 22.6703L12.266 22.3337L12.1921 22.0092L12.7797 22.3552Z' fill='%230000AD'/%3e %3cpath d='M9.72946 17.8769L9.88202 18.3782L9.62534 17.3925L9.46729 16.8702L9.72946 17.8769Z' fill='%2300B4FF'/%3e %3cpath d='M9.15556 15.2487L9.29558 15.8268L9.21901 14.7723L9.07764 14.1807L9.15556 15.2487Z' fill='%2353FFA4'/%3e %3cpath d='M22.7156 14.0896L22.4738 13.7588L22.4619 14.2709L22.7042 14.5582L22.7156 14.0896Z' fill='%237DFF7A'/%3e %3cpath d='M10.2602 8.54074L9.81323 9.10747L10.1972 8.38348L10.6039 7.83923L10.2602 8.54074Z' fill='%23FF4E00'/%3e %3cpath d='M24.4521 17.369L24.8903 17.1136L25.1223 16.9089L24.6769 17.1897L24.4521 17.369Z' fill='%2300D4FF'/%3e %3cpath d='M11.1048 20.8928L11.2091 21.2488L10.749 20.5263L10.6313 20.1492L11.1048 20.8928Z' fill='%230004FF'/%3e %3cpath d='M22.6755 15.279L22.7357 15.0178L22.8086 15.4573L22.7483 15.6882L22.6755 15.279Z' fill='%2349FFAD'/%3e %3cpath d='M16.1399 12.1964L16.1916 12.507L16.2691 13.5771L16.203 13.2377L16.1399 12.1964Z' fill='%23C1FF36'/%3e %3cpath d='M22.6245 16.6219L23.0074 16.4166L23.1872 16.7174L22.7994 16.9117L22.6245 16.6219Z' fill='%230CF4EB'/%3e %3cpath d='M22.6226 12.7506L22.1078 12.3307L22.0171 12.8803L22.5278 13.2473L22.6226 12.7506Z' fill='%23C1FF36'/%3e %3cpath d='M22.0028 9.93016L21.022 9.34412L20.8606 9.80242L21.8093 10.3378L22.0028 9.93016Z' fill='%23FF9800'/%3e %3cpath d='M16.2963 9.02881L15.8457 9.06293L16.0241 9.9791L16.4134 9.9041L16.2963 9.02881Z' fill='%23FF7E00'/%3e %3cpath d='M22.6598 9.23276L21.5685 8.53699L21.3809 8.70273L22.4339 9.37008L22.6598 9.23276Z' fill='%23FF6C00'/%3e %3cpath d='M25.9957 13.7789L25.7051 13.2175L25.6602 12.724L25.9487 13.3233L25.9957 13.7789Z' fill='%23A7FF50'/%3e %3cpath d='M25.4487 11.8334L24.7902 11.1464L24.6387 10.7485L25.2878 11.4599L25.4487 11.8334Z' fill='%23FFEA00'/%3e %3cpath d='M22.3963 11.3284L21.6375 10.8163L21.4919 11.3526L22.2354 11.8088L22.3963 11.3284Z' fill='%23FFE600'/%3e %3cpath d='M24.2494 10.17L23.3062 9.42591L23.1018 9.26135L24.0215 10.0056L24.2494 10.17Z' fill='%23FF9400'/%3e %3cpath d='M16.2691 13.5771L16.4566 13.9622L16.4557 15.0286L16.269 14.6221L16.2691 13.5771Z' fill='%2383FF73'/%3e %3cpath d='M22.2129 9.60483L21.197 8.97437L21.022 9.34433L22.0028 9.93037L22.2129 9.60483Z' fill='%23FF8200'/%3e %3cpath d='M22.434 9.37022L21.3809 8.70288L21.197 8.97438L22.2129 9.60485L22.434 9.37022Z' fill='%23FF7300'/%3e %3cpath d='M13.3781 22.5472L13.4189 22.8573L12.8372 22.6702L12.7798 22.3551L13.3781 22.5472Z' fill='%230000A4'/%3e %3cpath d='M14.2542 6L13.4688 6.04859L13.8565 6.18843L14.545 6.13984L14.2542 6Z' fill='%23A40000'/%3e %3cpath d='M25.7852 15.5862L25.8818 15.1664L25.9615 14.7125L25.8628 15.1711L25.7852 15.5862Z' fill='%2350FFA7'/%3e %3cpath d='M24.6768 17.1897L25.1222 16.9089L25.3328 16.6467L24.8805 16.9556L24.6768 17.1897Z' fill='%2300E4F8'/%3e %3cpath d='M15.6309 6.52467L14.8362 6.44275L15.1195 6.90085L15.818 6.96281L15.6309 6.52467Z' fill='%23CD0000'/%3e %3cpath d='M16.4558 15.0283L16.7063 15.4545L16.6054 16.4847L16.3657 16.0432L16.4558 15.0283Z' fill='%2340FFB7'/%3e %3cpath d='M22.4812 16.2918L22.8603 16.0707L23.008 16.4166L22.625 16.6219L22.4812 16.2918Z' fill='%231FFFD7'/%3e %3cpath d='M9.02148 12.5316L9.0991 13.1276L9.22068 12.1167L9.14297 11.5161L9.02148 12.5316Z' fill='%23D7FF1F'/%3e %3cpath d='M11.5957 6.88849L11.0139 7.2778L11.4807 6.87257L11.9955 6.50452L11.5957 6.88849Z' fill='%23DA0000'/%3e %3cpath d='M15.0435 21.7354L15.094 22.1642L14.5496 22.4515L14.4885 22.0297L15.0435 21.7354Z' fill='%230000CD'/%3e %3cpath d='M10.6312 20.1493L10.7489 20.5264L10.3496 19.7058L10.2202 19.3043L10.6312 20.1493Z' fill='%23003CFF'/%3e %3cpath d='M16.1555 8.23267L15.6316 8.22961L15.846 9.06329L16.2965 9.02917L16.1555 8.23267Z' fill='%23FF4E00'/%3e %3cpath d='M22.7693 13.6243L22.5276 13.2476L22.4736 13.7587L22.7154 14.0895L22.7693 13.6243Z' fill='%239DFF5A'/%3e %3cpath d='M22.6438 14.8533L22.7043 14.558L22.7357 15.0179L22.6755 15.2791L22.6438 14.8533Z' fill='%2363FF94'/%3e %3cpath d='M15.8179 6.96284L15.1194 6.90088L15.387 7.50206L15.9944 7.53747L15.8179 6.96284Z' fill='%23E80000'/%3e %3cpath d='M22.5861 10.9027L21.809 10.3379L21.6372 10.8164L22.396 11.3285L22.5861 10.9027Z' fill='%23FFC400'/%3e %3cpath d='M16.0242 9.97937L15.8306 10.15L16.0146 11.1577L16.1619 10.9522L16.0242 9.97937Z' fill='%23FFAE00'/%3e %3cpath d='M24.0216 10.0055L23.102 9.26125L22.8845 9.19617L23.7795 9.93127L24.0216 10.0055Z' fill='%23FF8600'/%3e %3cpath d='M22.7558 12.2817L22.2351 11.809L22.1077 12.331L22.6224 12.7509L22.7558 12.2817Z' fill='%23DEFF19'/%3e %3cpath d='M16.6052 16.485L16.748 17.0037L16.5436 17.9659L16.4092 17.44L16.6052 16.485Z' fill='%2300E4F8'/%3e %3cpath d='M15.9943 7.53749L15.387 7.50208L15.6314 8.22972L16.1553 8.23277L15.9943 7.53749Z' fill='%23FF2200'/%3e %3cpath d='M15.9306 20.1571L15.9994 20.6861L15.5514 21.2844L15.478 20.7638L15.9306 20.1571Z' fill='%230018FF'/%3e %3cpath d='M25.288 11.4596L24.6389 10.7482L24.457 10.4198L25.0952 11.148L25.288 11.4596Z' fill='%23FFD000'/%3e %3cpath d='M24.8809 16.9555L25.3331 16.6466L25.5169 16.3334L25.0584 16.6723L24.8809 16.9555Z' fill='%230FF8E7'/%3e %3cpath d='M25.9485 13.3232L25.66 12.724L25.574 12.2584L25.8598 12.8911L25.9485 13.3232Z' fill='%23C1FF36'/%3e %3cpath d='M22.3718 15.9296L22.7482 15.6884L22.8599 16.0707L22.4809 16.2918L22.3718 15.9296Z' fill='%2333FFC4'/%3e %3cpath d='M13.9727 22.58L13.9968 22.8899L13.4187 22.8574L13.3779 22.5472L13.9727 22.58Z' fill='%230000A8'/%3e %3cpath d='M25.8628 15.1712L25.9615 14.7126L25.9998 14.2461L25.8994 14.7422L25.8628 15.1712Z' fill='%236AFF8D'/%3e %3cpath d='M13.0922 6.08084L12.4338 6.28713L12.8983 6.24412L13.4686 6.04871L13.0922 6.08084Z' fill='%239F0000'/%3e %3cpath d='M22.7444 17.6893L23.4626 17.4725L23.7111 17.5413L22.9826 17.7665L22.7444 17.6893Z' fill='%2300C8FF'/%3e %3cpath d='M22.8007 10.5429L22.0029 9.93005L21.8093 10.3377L22.5864 10.9025L22.8007 10.5429Z' fill='%23FFAB00'/%3e %3cpath d='M22.5156 17.5544L23.2242 17.3424L23.4629 17.4727L22.7446 17.6894L22.5156 17.5544Z' fill='%2300D0FF'/%3e %3cpath d='M23.7794 9.93127L22.8844 9.19617L22.6597 9.23267L23.5295 9.94956L23.7794 9.93127Z' fill='%23FF8200'/%3e %3cpath d='M9.46738 16.8702L9.62544 17.3924L9.45733 16.3711L9.29541 15.8269L9.46738 16.8702Z' fill='%2316FFE1'/%3e %3cpath d='M9.51236 9.9502L9.36255 10.569L9.67644 9.71643L9.81298 9.10754L9.51236 9.9502Z' fill='%23FF8D00'/%3e %3cpath d='M22.9827 17.7669L23.7111 17.5416L23.963 17.5471L23.2241 17.7843L22.9827 17.7669Z' fill='%2300C8FF'/%3e %3cpath d='M22.3013 17.3649L23.0009 17.1538L23.2238 17.3424L22.5153 17.5543L22.3013 17.3649Z' fill='%2300D8FF'/%3e %3cpath d='M14.545 6.13989L13.8564 6.18848L14.2447 6.49765L14.8361 6.44265L14.545 6.13989Z' fill='%23A80000'/%3e %3cpath d='M16.0149 11.1578L16.0378 11.4411L16.1917 12.5073L16.1399 12.1967L16.0149 11.1578Z' fill='%23FEED00'/%3e %3cpath d='M23.0336 10.2594L22.2131 9.60449L22.0029 9.93005L22.8008 10.5429L23.0336 10.2594Z' fill='%23FF9800'/%3e %3cpath d='M23.5296 9.94932L22.6597 9.23242L22.4338 9.36977L23.2787 10.0597L23.5296 9.94932Z' fill='%23FF8200'/%3e %3cpath d='M22.6541 14.4221L22.7157 14.0896L22.7043 14.5582L22.6438 14.8535L22.6541 14.4221Z' fill='%237DFF7A'/%3e %3cpath d='M22.8651 13.1747L22.6229 12.7507L22.5281 13.2475L22.7698 13.6242L22.8651 13.1747Z' fill='%23BAFF3C'/%3e %3cpath d='M22.9246 11.8527L22.3962 11.3285L22.2354 11.8089L22.756 12.2817L22.9246 11.8527Z' fill='%23FBF100'/%3e %3cpath d='M23.2244 17.784L23.9632 17.5469L24.2123 17.4889L23.463 17.7411L23.2244 17.784Z' fill='%2300C8FF'/%3e %3cpath d='M25.0583 16.6724L25.5169 16.3335L25.669 15.9771L25.205 16.3473L25.0583 16.6724Z' fill='%2326FFD1'/%3e %3cpath d='M22.1077 17.1258L22.7994 16.9117L23.0009 17.1539L22.3012 17.365L22.1077 17.1258Z' fill='%2302E8F4'/%3e %3cpath d='M10.2205 19.3043L10.3499 19.7058L10.0215 18.8065L9.88232 18.3779L10.2205 19.3043Z' fill='%230078FF'/%3e %3cpath d='M23.2785 10.0602L22.4337 9.37024L22.2126 9.60485L23.0332 10.2598L23.2785 10.0602Z' fill='%23FF8900'/%3e %3cpath d='M25.0953 11.148L24.4571 10.4199L24.2495 10.1699L24.8756 10.9068L25.0953 11.148Z' fill='%23FFB900'/%3e %3cpath d='M16.5435 17.9657L16.6067 18.5544L16.3103 19.4148L16.2468 18.8303L16.5435 17.9657Z' fill='%230098FF'/%3e %3cpath d='M9.07764 14.1805L9.21901 14.7721L9.24085 13.7328L9.09912 13.1276L9.07764 14.1805Z' fill='%2397FF60'/%3e %3cpath d='M15.8458 9.06335L15.5923 9.20185L15.8306 10.1501L16.0242 9.97953L15.8458 9.06335Z' fill='%23FF7300'/%3e %3cpath d='M22.3005 15.5444L22.6755 15.2791L22.7482 15.6883L22.3719 15.9296L22.3005 15.5444Z' fill='%234DFFAA'/%3e %3cpath d='M25.8599 12.8913L25.574 12.2586L25.449 11.8334L25.7316 12.4941L25.8599 12.8913Z' fill='%23DEFF19'/%3e %3cpath d='M10.604 7.83935L10.1973 8.38359L10.6555 7.79919L11.0143 7.27759L10.604 7.83935Z' fill='%23FF1A00'/%3e %3cpath d='M23.4626 17.741L24.212 17.4887L24.452 17.3687L23.6924 17.6387L23.4626 17.741Z' fill='%2300D0FF'/%3e %3cpath d='M21.9395 16.8427L22.6245 16.6218L22.7994 16.9116L22.1077 17.1256L21.9395 16.8427Z' fill='%2313FCE4'/%3e %3cpath d='M25.8996 14.7421L26 14.2459L25.9957 13.7788L25.894 14.3104L25.8996 14.7421Z' fill='%2387FF70'/%3e %3cpath d='M16.1917 12.5068L16.3672 12.8723L16.4566 13.962L16.2692 13.5769L16.1917 12.5068Z' fill='%23C4FF33'/%3e %3cpath d='M14.836 6.44263L14.2446 6.49763L14.6227 6.9684L15.1193 6.90073L14.836 6.44263Z' fill='%23B60000'/%3e %3cpath d='M23.1239 11.4753L22.5861 10.9026L22.396 11.3284L22.9244 11.8526L23.1239 11.4753Z' fill='gold'/%3e %3cpath d='M24.8752 10.9068L24.2491 10.1699L24.0212 10.0055L24.6344 10.7427L24.8752 10.9068Z' fill='%23FFA700'/%3e %3cpath d='M15.5513 21.2847L15.5922 21.7237L15.0937 22.1646L15.0432 21.7358L15.5513 21.2847Z' fill='%230000FA'/%3e %3cpath d='M14.5496 22.4517L14.5576 22.7659L13.997 22.8897L13.9729 22.5799L14.5496 22.4517Z' fill='%230000BB'/%3e %3cpath d='M25.2048 16.3472L25.6688 15.9769L25.7852 15.5862L25.3168 15.9882L25.2048 16.3472Z' fill='%233CFFBA'/%3e %3cpath d='M23.6924 17.6389L24.452 17.3689L24.6767 17.1896L23.9073 17.4798L23.6924 17.6389Z' fill='%2300DCFE'/%3e %3cpath d='M22.9992 12.7526L22.7559 12.2815L22.6226 12.7507L22.8648 13.1746L22.9992 12.7526Z' fill='%23D4FF23'/%3e %3cpath d='M15.6312 8.22937L15.3059 8.33945L15.5921 9.20155L15.8456 9.06305L15.6312 8.22937Z' fill='%23FF3F00'/%3e %3cpath d='M22.7066 13.9959L22.7697 13.624L22.7158 14.0892L22.6543 14.4217L22.7066 13.9959Z' fill='%239AFF5D'/%3e %3cpath d='M11.9958 6.50408L11.481 6.87212L11.9921 6.63622L12.4338 6.28674L11.9958 6.50408Z' fill='%23B20000'/%3e %3cpath d='M12.2655 22.3339L12.2903 22.541L11.7635 22.0809L11.7185 21.8562L12.2655 22.3339Z' fill='%230000D6'/%3e %3cpath d='M21.801 16.5231L22.4808 16.2917L22.6246 16.6219L21.9396 16.8427L21.801 16.5231Z' fill='%2326FFD1'/%3e %3cpath d='M11.7189 21.856L11.7639 22.0807L11.273 21.496L11.2092 21.2488L11.7189 21.856Z' fill='%230000FA'/%3e %3cpath d='M22.269 15.1462L22.6439 14.8534L22.6756 15.2792L22.3007 15.5445L22.269 15.1462Z' fill='%2363FF94'/%3e %3cpath d='M16.4566 13.9622L16.7082 14.3757L16.7063 15.4547L16.4558 15.0285L16.4566 13.9622Z' fill='%2383FF73'/%3e %3cpath d='M15.1195 6.90088L14.6228 6.96855L14.98 7.58827L15.3871 7.50205L15.1195 6.90088Z' fill='%23D60000'/%3e %3cpath d='M13.4687 6.04846L12.8984 6.24387L13.3768 6.37789L13.8564 6.1883L13.4687 6.04846Z' fill='%23960000'/%3e %3cpath d='M25.7317 12.4938L25.4491 11.8331L25.2881 11.4596L25.5671 12.1422L25.7317 12.4938Z' fill='%23F4F802'/%3e %3cpath d='M15.3869 7.50183L14.9797 7.58805L15.306 8.33956L15.6313 8.22949L15.3869 7.50183Z' fill='%23FF1300'/%3e %3cpath d='M12.837 22.6702L12.8408 22.865L12.2907 22.5407L12.2659 22.3336L12.837 22.6702Z' fill='%230000BF'/%3e %3cpath d='M23.349 11.1598L22.8005 10.543L22.5862 10.9025L23.1239 11.4752L23.349 11.1598Z' fill='%23FFC100'/%3e %3cpath d='M9.14282 11.5159L9.22053 12.1164L9.44035 11.174L9.36274 10.569L9.14282 11.5159Z' fill='%23FFD000'/%3e %3cpath d='M24.6351 10.7427L24.0219 10.0055L23.7798 9.93127L24.3797 10.6602L24.6351 10.7427Z' fill='%23FF9C00'/%3e %3cpath d='M25.894 14.3106L25.9956 13.779L25.9486 13.3234L25.8462 13.8874L25.894 14.3106Z' fill='%23A0FF56'/%3e %3cpath d='M15.8306 10.15L15.811 10.4082L16.0376 11.441L16.0147 11.1577L15.8306 10.15Z' fill='%23FFAB00'/%3e %3cpath d='M11.2091 21.249L11.2729 21.4962L10.8299 20.8008L10.749 20.5266L11.2091 21.249Z' fill='%230014FF'/%3e %3cpath d='M23.9072 17.4796L24.6766 17.1894L24.8804 16.9553L24.1019 17.2674L23.9072 17.4796Z' fill='%2306ECF1'/%3e %3cpath d='M9.88192 18.3781L10.0211 18.8066L9.77209 17.8499L9.62524 17.3923L9.88192 18.3781Z' fill='%2300BCFF'/%3e %3cpath d='M16.3105 19.415L16.3755 19.9542L15.9995 20.6862L15.9307 20.1572L16.3105 19.415Z' fill='%230054FF'/%3e %3cpath d='M21.696 16.1749L22.3721 15.9296L22.4811 16.2918L21.8013 16.5231L21.696 16.1749Z' fill='%2339FFBE'/%3e %3cpath d='M23.5941 10.9149L23.0337 10.2594L22.8008 10.5428L23.3493 11.1597L23.5941 10.9149Z' fill='%23FFAE00'/%3e %3cpath d='M16.7059 15.4545L16.8532 15.9675L16.7478 17.0034L16.605 16.4847L16.7059 15.4545Z' fill='%2340FFB7'/%3e %3cpath d='M24.3795 10.6602L23.7797 9.93127L23.5298 9.94954L24.1162 10.6618L24.3795 10.6602Z' fill='%23FF9800'/%3e %3cpath d='M9.29532 15.8266L9.45724 16.3708L9.38276 15.3388L9.21875 14.7721L9.29532 15.8266Z' fill='%2356FFA0'/%3e %3cpath d='M25.3167 15.9882L25.7851 15.5862L25.8627 15.171L25.3908 15.6045L25.3167 15.9882Z' fill='%2353FFA4'/%3e %3cpath d='M23.1692 12.3696L22.9244 11.8528L22.7559 12.2818L22.9991 12.7529L23.1692 12.3696Z' fill='%23EEFF09'/%3e %3cpath d='M23.852 10.7477L23.2789 10.0601L23.0337 10.2597L23.5941 10.9152L23.852 10.7477Z' fill='%23FF9F00'/%3e %3cpath d='M24.1161 10.6619L23.5297 9.94958L23.2788 10.06L23.8519 10.7476L24.1161 10.6619Z' fill='%23FF9800'/%3e %3cpath d='M22.7997 13.587L22.8649 13.1747L22.7696 13.6242L22.7065 13.9961L22.7997 13.587Z' fill='%23B4FF43'/%3e %3cpath d='M13.4188 22.8574L13.401 23.0456L12.8409 22.8651L12.8372 22.6703L13.4188 22.8574Z' fill='%230000B6'/%3e %3cpath d='M21.5459 17.7914L22.5153 17.5543L22.7443 17.6894L21.7641 17.9325L21.5459 17.7914Z' fill='%2300D8FF'/%3e %3cpath d='M25.5671 12.1423L25.288 11.4597L25.0952 11.1481L25.3704 11.8458L25.5671 12.1423Z' fill='%23FFDE00'/%3e %3cpath d='M22.2779 14.7445L22.654 14.4218L22.6437 14.8531L22.2688 15.1459L22.2779 14.7445Z' fill='%237DFF7A'/%3e %3cpath d='M21.7639 17.9325L22.7442 17.6893L22.9824 17.7666L21.9908 18.0181L21.7639 17.9325Z' fill='%2300D0FF'/%3e %3cpath d='M21.342 17.5983L22.3016 17.3647L22.5156 17.5542L21.5461 17.7913L21.342 17.5983Z' fill='%2300E0FB'/%3e %3cpath d='M21.9915 18.0183L22.983 17.7667L23.2245 17.7841L22.2213 18.0462L21.9915 18.0183Z' fill='%2300D0FF'/%3e %3cpath d='M9.81306 9.10766L9.67651 9.71655L10.0773 8.98197L10.1971 8.38367L9.81306 9.10766Z' fill='%23FF4E00'/%3e %3cpath d='M21.157 17.3582L22.1078 17.1256L22.3013 17.3648L21.3418 17.5983L21.157 17.3582Z' fill='%2309F0EE'/%3e %3cpath d='M24.1021 17.2676L24.8805 16.9555L25.0581 16.6724L24.2715 17.0076L24.1021 17.2676Z' fill='%2319FFDE'/%3e %3cpath d='M10.7491 20.5261L10.83 20.8003L10.4456 20.0106L10.3499 19.7056L10.7491 20.5261Z' fill='%230048FF'/%3e %3cpath d='M21.6267 15.8069L22.3007 15.5446L22.372 15.9297L21.696 16.1751L21.6267 15.8069Z' fill='%2350FFA7'/%3e %3cpath d='M25.8463 13.8871L25.9487 13.3231L25.86 12.891L25.7573 13.4836L25.8463 13.8871Z' fill='%23BEFF39'/%3e %3cpath d='M13.8563 6.18835L13.3767 6.37794L13.8557 6.6865L14.2446 6.49753L13.8563 6.18835Z' fill='%23960000'/%3e %3cpath d='M23.3708 12.0353L23.124 11.4753L22.9246 11.8527L23.1693 12.3695L23.3708 12.0353Z' fill='%23FFE600'/%3e %3cpath d='M15.0938 22.1644L15.0864 22.4877L14.5573 22.766L14.5493 22.4518L15.0938 22.1644Z' fill='%230000DA'/%3e %3cpath d='M22.2209 18.0461L23.2242 17.784L23.4628 17.7411L22.4479 18.0155L22.2209 18.0461Z' fill='%2300D0FF'/%3e %3cpath d='M16.0378 11.4408L16.1889 11.789L16.3672 12.8724L16.1917 12.507L16.0378 11.4408Z' fill='%23FFEA00'/%3e %3cpath d='M20.9961 17.0772L21.9395 16.8429L22.1077 17.1258L21.1569 17.3584L20.9961 17.0772Z' fill='%2316FFE1'/%3e %3cpath d='M15.5925 9.20154L15.5176 9.43755L15.8112 10.408L15.8308 10.1498L15.5925 9.20154Z' fill='%23FF6C00'/%3e %3cpath d='M9.09888 13.1275L9.2406 13.7328L9.36147 12.7352L9.22045 12.1166L9.09888 13.1275Z' fill='%23D7FF1F'/%3e %3cpath d='M25.3911 15.6047L25.863 15.1712L25.8996 14.7423L25.4254 15.2062L25.3911 15.6047Z' fill='%236DFF8A'/%3e %3cpath d='M11.0142 7.27779L10.6553 7.79939L11.1761 7.37197L11.481 6.87256L11.0142 7.27779Z' fill='%23D10000'/%3e %3cpath d='M25.3706 11.8457L25.0954 11.148L24.8757 10.9067L25.1468 11.6124L25.3706 11.8457Z' fill='%23FFCC00'/%3e %3cpath d='M16.7478 17.0038L16.8109 17.597L16.6066 18.5548L16.5435 17.966L16.7478 17.0038Z' fill='%2300E4F8'/%3e %3cpath d='M22.9315 13.2049L22.9994 12.7523L22.8651 13.1744L22.7998 13.5867L22.9315 13.2049Z' fill='%23CEFF29'/%3e %3cpath d='M12.4337 6.28716L11.9919 6.63664L12.5338 6.57823L12.8982 6.24414L12.4337 6.28716Z' fill='%23960000'/%3e %3cpath d='M22.3275 14.3506L22.7063 13.9961L22.654 14.4219L22.2778 14.7447L22.3275 14.3506Z' fill='%2397FF60'/%3e %3cpath d='M13.9968 22.8897L13.9576 23.077L13.4009 23.0454L13.4187 22.8572L13.9968 22.8897Z' fill='%230000BB'/%3e %3cpath d='M22.448 18.0153L23.4629 17.7409L23.6926 17.6387L22.6664 17.9269L22.448 18.0153Z' fill='%2300D8FF'/%3e %3cpath d='M15.9996 20.6862L16.0319 21.1386L15.5924 21.7235L15.5515 21.2844L15.9996 20.6862Z' fill='%230020FF'/%3e %3cpath d='M24.2715 17.0075L25.0581 16.6723L25.2048 16.3472L24.4112 16.7062L24.2715 17.0075Z' fill='%2329FFCE'/%3e %3cpath d='M20.8638 16.7618L21.8013 16.5231L21.9398 16.8427L20.9965 17.077L20.8638 16.7618Z' fill='%2329FFCE'/%3e %3cpath d='M23.5984 11.7591L23.3491 11.1599L23.124 11.4753L23.3708 12.0352L23.5984 11.7591Z' fill='%23FFD000'/%3e %3cpath d='M21.5955 15.4282L22.2691 15.1461L22.3007 15.5445L21.6267 15.8069L21.5955 15.4282Z' fill='%2366FF90'/%3e %3cpath d='M25.7573 13.4836L25.86 12.8909L25.7318 12.4938L25.6294 13.1103L25.7573 13.4836Z' fill='%23D4FF23'/%3e %3cpath d='M25.1466 11.6124L24.8755 10.9067L24.6348 10.7426L24.9018 11.4486L25.1466 11.6124Z' fill='%23FFB900'/%3e %3cpath d='M14.2449 6.49768L13.856 6.68666L14.3223 7.16203L14.6229 6.96846L14.2449 6.49768Z' fill='%23A80000'/%3e %3cpath d='M9.62562 17.3922L9.77247 17.8498L9.6096 16.8588L9.45752 16.3708L9.62562 17.3922Z' fill='%2319FFDE'/%3e %3cpath d='M16.3672 12.8724L16.6098 13.2763L16.7082 14.3756L16.4566 13.9621L16.3672 12.8724Z' fill='%23C4FF33'/%3e %3cpath d='M15.306 8.33984L15.1646 8.55733L15.5173 9.43793L15.5922 9.20193L15.306 8.33984Z' fill='%23FF3400'/%3e %3cpath d='M10.3496 19.7059L10.4454 20.0109L10.1294 19.1456L10.0212 18.8065L10.3496 19.7059Z' fill='%230080FF'/%3e %3cpath d='M23.8463 11.5486L23.5941 10.915L23.3494 11.1598L23.5986 11.759L23.8463 11.5486Z' fill='%23FFC100'/%3e %3cpath d='M22.6665 17.9271L23.6927 17.6389L23.9077 17.4797L22.8706 17.7829L22.6665 17.9271Z' fill='%2300E4F8'/%3e %3cpath d='M25.4249 15.206L25.8992 14.7421L25.8936 14.3104L25.4182 14.8029L25.4249 15.206Z' fill='%2387FF70'/%3e %3cpath d='M20.7622 16.4206L21.6955 16.175L21.8008 16.5233L20.8633 16.762L20.7622 16.4206Z' fill='%233CFFBA'/%3e %3cpath d='M23.0984 12.8613L23.1694 12.3695L22.9993 12.7528L22.9314 13.2054L23.0984 12.8613Z' fill='%23E4FF13'/%3e %3cpath d='M24.9016 11.4486L24.6346 10.7426L24.3792 10.6602L24.6421 11.3589L24.9016 11.4486Z' fill='%23FFB200'/%3e %3cpath d='M14.6227 6.96851L14.322 7.16207L14.7624 7.79143L14.9798 7.58825L14.6227 6.96851Z' fill='%23C80000'/%3e %3cpath d='M14.9798 7.58826L14.7625 7.79144L15.1646 8.55723L15.3061 8.33974L14.9798 7.58826Z' fill='%23F10800'/%3e %3cpath d='M22.4171 13.9742L22.7998 13.5869L22.7066 13.9961L22.3279 14.3506L22.4171 13.9742Z' fill='%23B1FF46'/%3e %3cpath d='M24.1069 11.4097L23.8514 10.7476L23.5935 10.9151L23.8457 11.5487L24.1069 11.4097Z' fill='%23FFB200'/%3e %3cpath d='M9.36279 10.5691L9.44041 11.1742L9.754 10.3259L9.67668 9.71655L9.36279 10.5691Z' fill='%23FF8D00'/%3e %3cpath d='M24.4114 16.7062L25.205 16.3471L25.3169 15.9882L24.5176 16.3711L24.4114 16.7062Z' fill='%2340FFB7'/%3e %3cpath d='M24.6423 11.3588L24.3793 10.66L24.116 10.6616L24.3751 11.3456L24.6423 11.3588Z' fill='%23FFAB00'/%3e %3cpath d='M24.3748 11.3456L24.1158 10.6616L23.8516 10.7473L24.107 11.4094L24.3748 11.3456Z' fill='%23FFAE00'/%3e %3cpath d='M21.6028 15.0489L22.2779 14.7449L22.2689 15.1463L21.5952 15.4284L21.6028 15.0489Z' fill='%237DFF7A'/%3e %3cpath d='M20.3831 18.0561L21.5462 17.7916L21.7644 17.9327L20.5902 18.2053L20.3831 18.0561Z' fill='%2300DCFE'/%3e %3cpath d='M20.1887 17.8558L21.3416 17.5983L21.5457 17.7913L20.3826 18.0558L20.1887 17.8558Z' fill='%2300E4F8'/%3e %3cpath d='M9.21875 14.7719L9.38276 15.3386L9.40482 14.3217L9.24058 13.7325L9.21875 14.7719Z' fill='%2397FF60'/%3e %3cpath d='M25.6293 13.1103L25.7317 12.4938L25.5671 12.1422L25.4656 12.7774L25.6293 13.1103Z' fill='%23EBFF0C'/%3e %3cpath d='M12.2908 22.5406L12.267 22.623L11.7642 22.184L11.7639 22.0806L12.2908 22.5406Z' fill='%230000ED'/%3e %3cpath d='M16.6067 18.5548L16.6689 19.1055L16.3754 19.9543L16.3103 19.4151L16.6067 18.5548Z' fill='%23009CFF'/%3e %3cpath d='M16.7079 14.3759L16.8559 14.8847L16.8534 15.9679L16.7061 15.4549L16.7079 14.3759Z' fill='%2383FF73'/%3e %3cpath d='M20.5901 18.2053L21.7643 17.9327L21.9912 18.0184L20.8052 18.2999L20.5901 18.2053Z' fill='%2300D4FF'/%3e %3cpath d='M11.7641 22.0808L11.7644 22.1842L11.296 21.6263L11.2732 21.4961L11.7641 22.0808Z' fill='blue'/%3e %3cpath d='M15.8108 10.4081L15.9254 10.7418L16.1884 11.789L16.0374 11.4408L15.8108 10.4081Z' fill='%23FFA300'/%3e %3cpath d='M20.0134 17.6101L21.1572 17.3582L21.342 17.5983L20.1891 17.8558L20.0134 17.6101Z' fill='%230CF4EB'/%3e %3cpath d='M22.8704 17.7827L23.9074 17.4795L24.1021 17.2673L23.0551 17.5863L22.8704 17.7827Z' fill='%230CF4EB'/%3e %3cpath d='M14.5573 22.7659L14.4972 22.9583L13.9575 23.0771L13.9967 22.8897L14.5573 22.7659Z' fill='%230000CD'/%3e %3cpath d='M20.6956 16.0617L21.6266 15.8069L21.6958 16.175L20.7625 16.4206L20.6956 16.0617Z' fill='%2350FFA7'/%3e %3cpath d='M12.8407 22.8651L12.7917 22.9326L12.2668 22.6231L12.2906 22.5408L12.8407 22.8651Z' fill='%230000D6'/%3e %3cpath d='M23.2961 12.5639L23.3706 12.0352L23.1692 12.3694L23.0981 12.8612L23.2961 12.5639Z' fill='%23F8F500'/%3e %3cpath d='M20.8052 18.2996L21.9912 18.0181L22.221 18.046L21.023 18.3373L20.8052 18.2996Z' fill='%2300D4FF'/%3e %3cpath d='M12.8986 6.24402L12.5342 6.57811L13.092 6.70032L13.377 6.37804L12.8986 6.24402Z' fill='%23890000'/%3e %3cpath d='M19.8604 17.325L20.9965 17.0771L21.1572 17.3583L20.0135 17.6103L19.8604 17.325Z' fill='%2319FFDE'/%3e %3cpath d='M15.5923 21.7235L15.5707 22.0604L15.0864 22.4876L15.0938 22.1644L15.5923 21.7235Z' fill='blue'/%3e %3cpath d='M25.4185 14.8028L25.8939 14.3104L25.8461 13.8872L25.3708 14.4056L25.4185 14.8028Z' fill='%23A0FF56'/%3e %3cpath d='M11.2729 21.4959L11.2957 21.6261L10.873 20.9626L10.8298 20.8004L11.2729 21.4959Z' fill='%230024FF'/%3e %3cpath d='M10.1969 8.3836L10.0771 8.9819L10.5552 8.38643L10.6551 7.79919L10.1969 8.3836Z' fill='%23FF1600'/%3e %3cpath d='M22.5433 13.6251L22.9311 13.2051L22.7994 13.5868L22.4167 13.974L22.5433 13.6251Z' fill='%23C7FF30'/%3e %3cpath d='M25.4655 12.7777L25.5671 12.1426L25.3704 11.8461L25.2703 12.494L25.4655 12.7777Z' fill='%23FEED00'/%3e %3cpath d='M24.5176 16.3714L25.3169 15.9884L25.391 15.6047L24.5875 16.0111L24.5176 16.3714Z' fill='%2356FFA0'/%3e %3cpath d='M11.4811 6.87252L11.1763 7.37193L11.7463 7.11488L11.9922 6.6366L11.4811 6.87252Z' fill='%23A80000'/%3e %3cpath d='M21.0229 18.3374L22.221 18.0461L22.448 18.0155L21.2379 18.3169L21.0229 18.3374Z' fill='%2300D4FF'/%3e %3cpath d='M21.6498 14.6781L22.3281 14.3506L22.2784 14.7446L21.6033 15.0486L21.6498 14.6781Z' fill='%2397FF60'/%3e %3cpath d='M19.7336 17.0072L20.8637 16.7618L20.9964 17.0771L19.8602 17.3249L19.7336 17.0072Z' fill='%2329FFCE'/%3e %3cpath d='M10.0215 18.8063L10.1297 19.1454L9.89017 18.2252L9.77246 17.8496L10.0215 18.8063Z' fill='%2300C4FF'/%3e %3cpath d='M23.0552 17.5863L24.1022 17.2673L24.2717 17.0073L23.2157 17.3424L23.0552 17.5863Z' fill='%231CFFDB'/%3e %3cpath d='M13.4012 23.0457L13.3264 23.105L12.792 22.9328L12.841 22.8652L13.4012 23.0457Z' fill='%230000CD'/%3e %3cpath d='M20.6648 15.6945L21.5954 15.4283L21.6267 15.807L20.6957 16.0618L20.6648 15.6945Z' fill='%2366FF90'/%3e %3cpath d='M23.52 12.3215L23.5982 11.759L23.3706 12.0351L23.2961 12.5638L23.52 12.3215Z' fill='%23FFDE00'/%3e %3cpath d='M9.22046 12.1164L9.36148 12.735L9.57955 11.8054L9.44027 11.1741L9.22046 12.1164Z' fill='%23FFD300'/%3e %3cpath d='M16.8537 15.9677L16.9168 16.5655L16.8113 17.5969L16.7483 17.0036L16.8537 15.9677Z' fill='%2340FFB7'/%3e %3cpath d='M21.2378 18.317L22.4479 18.0155L22.6662 17.9271L21.4443 18.2388L21.2378 18.317Z' fill='%2300DCFE'/%3e %3cpath d='M25.2706 12.4937L25.3707 11.8458L25.1469 11.6124L25.0488 12.267L25.2706 12.4937Z' fill='%23FFDB00'/%3e %3cpath d='M25.371 14.4057L25.8463 13.8873L25.7574 13.4838L25.2834 14.0248L25.371 14.4057Z' fill='%23B7FF40'/%3e %3cpath d='M16.1887 11.7891L16.4125 12.1863L16.6096 13.2763L16.367 12.8725L16.1887 11.7891Z' fill='%23FFE600'/%3e %3cpath d='M10.8299 20.8006L10.873 20.9629L10.5064 20.2096L10.4456 20.0109L10.8299 20.8006Z' fill='%230054FF'/%3e %3cpath d='M9.45753 16.3709L9.60962 16.8588L9.53781 15.8579L9.38306 15.3389L9.45753 16.3709Z' fill='%2356FFA0'/%3e %3cpath d='M19.6367 16.6651L20.7625 16.4207L20.8636 16.762L19.7335 17.0073L19.6367 16.6651Z' fill='%233CFFBA'/%3e %3cpath d='M16.3753 19.954L16.4004 20.4225L16.0316 21.1384L15.9993 20.686L16.3753 19.954Z' fill='%23005CFF'/%3e %3cpath d='M15.5173 9.43787L15.5843 9.76023L15.9255 10.742L15.8109 10.4083L15.5173 9.43787Z' fill='%23FF6400'/%3e %3cpath d='M23.7642 12.1407L23.8461 11.5487L23.5984 11.7591L23.5203 12.3216L23.7642 12.1407Z' fill='%23FFD000'/%3e %3cpath d='M22.7043 13.3133L23.0982 12.8613L22.9312 13.2054L22.5435 13.6255L22.7043 13.3133Z' fill='%23DEFF19'/%3e %3cpath d='M13.3768 6.37781L13.0918 6.70009L13.6501 7.0007L13.8558 6.68637L13.3768 6.37781Z' fill='%23890000'/%3e %3cpath d='M24.5874 16.0109L25.3909 15.6045L25.4252 15.2059L24.6189 15.6346L24.5874 16.0109Z' fill='%236DFF8A'/%3e %3cpath d='M25.0485 12.2669L25.1466 11.6124L24.9018 11.4486L24.8062 12.1032L25.0485 12.2669Z' fill='%23FFCC00'/%3e %3cpath d='M21.7338 14.3262L22.4169 13.9742L22.3277 14.3507L21.6494 14.6782L21.7338 14.3262Z' fill='%23ADFF49'/%3e %3cpath d='M23.2158 17.3427L24.2718 17.0076L24.4115 16.7063L23.3478 17.0574L23.2158 17.3427Z' fill='%232CFFCA'/%3e %3cpath d='M20.6709 15.3282L21.603 15.0488L21.5954 15.4283L20.6648 15.6945L20.6709 15.3282Z' fill='%237DFF7A'/%3e %3cpath d='M19.1769 18.4522L20.4852 18.137L20.2841 17.9619L18.9727 18.2743L19.1769 18.4522Z' fill='%2300DCFE'/%3e %3cpath d='M18.9727 18.2742L20.2842 17.9618L20.0988 17.7383L18.7842 18.0471L18.9727 18.2742Z' fill='%2302E8F4'/%3e %3cpath d='M24.0219 12.0261L24.1076 11.4097L23.8463 11.5487L23.7644 12.1406L24.0219 12.0261Z' fill='%23FFC400'/%3e %3cpath d='M15.0865 22.4878L15.0065 22.6911L14.4973 22.9585L14.5574 22.7661L15.0865 22.4878Z' fill='%230000ED'/%3e %3cpath d='M21.4446 18.2389L22.6665 17.9273L22.8707 17.7831L21.6375 18.1049L21.4446 18.2389Z' fill='%2302E8F4'/%3e %3cpath d='M19.3916 18.5765L20.6968 18.2593L20.485 18.137L19.1768 18.4522L19.3916 18.5765Z' fill='%2300D4FF'/%3e %3cpath d='M13.9576 23.0772L13.8572 23.1352L13.3262 23.1049L13.4009 23.0455L13.9576 23.0772Z' fill='%230000D1'/%3e %3cpath d='M24.8061 12.1032L24.9017 11.4486L24.6422 11.3589L24.5496 12.0071L24.8061 12.1032Z' fill='%23FFC400'/%3e %3cpath d='M19.5725 16.3069L20.6959 16.0616L20.7628 16.4205L19.6371 16.665L19.5725 16.3069Z' fill='%2353FFA4'/%3e %3cpath d='M18.7841 18.0474L20.0987 17.7385L19.9338 17.4722L18.616 17.7769L18.7841 18.0474Z' fill='%230FF8E7'/%3e %3cpath d='M24.2859 11.9815L24.3752 11.3461L24.1074 11.4099L24.0217 12.0264L24.2859 11.9815Z' fill='%23FFC100'/%3e %3cpath d='M25.2832 14.0246L25.7572 13.4836L25.6292 13.1104L25.158 13.6703L25.2832 14.0246Z' fill='%23CEFF29'/%3e %3cpath d='M24.5498 12.0073L24.6424 11.3591L24.3752 11.3459L24.2859 11.9814L24.5498 12.0073Z' fill='%23FFBD00'/%3e %3cpath d='M19.6118 18.6442L20.9142 18.3257L20.6971 18.2594L19.3918 18.5766L19.6118 18.6442Z' fill='%2300D4FF'/%3e %3cpath d='M22.8953 13.0463L23.2963 12.5641L23.0983 12.8613L22.7043 13.3133L22.8953 13.0463Z' fill='%23F1FC06'/%3e %3cpath d='M15.1648 8.55713L15.1743 8.87166L15.5845 9.7601L15.5175 9.43774L15.1648 8.55713Z' fill='%23FF2D00'/%3e %3cpath d='M18.6158 17.777L19.9337 17.4723L19.7934 17.1698L18.4724 17.4699L18.6158 17.777Z' fill='%231CFFDB'/%3e %3cpath d='M9.67651 9.7163L9.75384 10.3257L10.1541 9.59509L10.0773 8.98169L9.67651 9.7163Z' fill='%23FF4E00'/%3e %3cpath d='M16.6096 13.2764L16.7542 13.7829L16.856 14.8846L16.708 14.3757L16.6096 13.2764Z' fill='%23C4FF33'/%3e %3cpath d='M13.8561 6.68665L13.6504 7.00098L14.1936 7.47242L14.3224 7.16203L13.8561 6.68665Z' fill='%239B0000'/%3e %3cpath d='M9.24072 13.7326L9.40496 14.3218L9.52415 13.3462L9.3616 12.735L9.24072 13.7326Z' fill='%23D4FF23'/%3e %3cpath d='M10.4457 20.0111L10.5065 20.2098L10.2051 19.3847L10.1296 19.1458L10.4457 20.0111Z' fill='%23008CFF'/%3e %3cpath d='M24.6191 15.6346L25.4253 15.2059L25.4186 14.8027L24.6113 15.2521L24.6191 15.6346Z' fill='%2387FF70'/%3e %3cpath d='M19.8311 18.6533L21.131 18.3344L20.914 18.3258L19.6116 18.6443L19.8311 18.6533Z' fill='%2300D4FF'/%3e %3cpath d='M11.992 6.63665L11.7461 7.11493L12.35 7.03692L12.5338 6.57825L11.992 6.63665Z' fill='%238D0000'/%3e %3cpath d='M21.8538 14.0021L22.5434 13.6255L22.4168 13.9744L21.7336 14.3263L21.8538 14.0021Z' fill='%23C4FF33'/%3e %3cpath d='M23.3479 17.0571L24.4116 16.706L24.5178 16.371L23.4479 16.7377L23.3479 17.0571Z' fill='%2343FFB4'/%3e %3cpath d='M21.6372 18.1047L22.8703 17.7829L23.055 17.5864L21.8116 17.918L21.6372 18.1047Z' fill='%230FF8E7'/%3e %3cpath d='M16.0316 21.1387L15.9975 21.4934L15.5706 22.0605L15.5921 21.7236L16.0316 21.1387Z' fill='%230028FF'/%3e %3cpath d='M16.8111 17.597L16.8714 18.1604L16.6691 19.1054L16.6069 18.5548L16.8111 17.597Z' fill='%2302E8F4'/%3e %3cpath d='M20.714 14.9721L21.6495 14.6781L21.603 15.0487L20.6709 15.328L20.714 14.9721Z' fill='%2394FF63'/%3e %3cpath d='M9.77249 17.8496L9.8902 18.2252L9.73378 17.2723L9.60962 16.8586L9.77249 17.8496Z' fill='%231CFFDB'/%3e %3cpath d='M12.2668 22.6231L12.2119 22.581L11.7366 22.1659L11.7641 22.1841L12.2668 22.6231Z' fill='blue'/%3e %3cpath d='M19.5417 15.9423L20.6647 15.6946L20.6956 16.0619L19.5722 16.3071L19.5417 15.9423Z' fill='%2366FF90'/%3e %3cpath d='M11.7641 22.1842L11.7366 22.1661L11.2937 21.6386L11.2957 21.6263L11.7641 22.1842Z' fill='%230010FF'/%3e %3cpath d='M18.4722 17.4699L19.7932 17.1698L19.6811 16.8387L18.3572 17.1338L18.4722 17.4699Z' fill='%2330FFC7'/%3e %3cpath d='M25.1581 13.6702L25.6294 13.1103L25.4657 12.7773L24.9983 13.3517L25.1581 13.6702Z' fill='%23E4FF13'/%3e %3cpath d='M14.7624 7.79126L14.7061 8.10174L15.1741 8.87159L15.1646 8.55706L14.7624 7.79126Z' fill='%23E80000'/%3e %3cpath d='M14.3219 7.16211L14.1931 7.4725L14.706 8.10194L14.7623 7.79146L14.3219 7.16211Z' fill='%23BB0000'/%3e %3cpath d='M10.6551 7.79913L10.5552 8.38636L11.0984 7.94774L11.1759 7.3717L10.6551 7.79913Z' fill='%23D10000'/%3e %3cpath d='M23.1117 12.8314L23.5203 12.3214L23.2965 12.5638L22.8955 13.046L23.1117 12.8314Z' fill='%23FEED00'/%3e %3cpath d='M12.7918 22.9328L12.7082 22.8738L12.2119 22.5812L12.2668 22.6233L12.7918 22.9328Z' fill='%230000F1'/%3e %3cpath d='M15.9258 10.7418L16.1212 11.1358L16.4126 12.1864L16.1888 11.7891L15.9258 10.7418Z' fill='%23FF9F00'/%3e %3cpath d='M20.0446 18.6031L21.3424 18.2848L21.131 18.3342L19.8311 18.6531L20.0446 18.6031Z' fill='%2300D8FF'/%3e %3cpath d='M11.2955 21.6263L11.2935 21.6386L10.8938 21.0113L10.8728 20.9629L11.2955 21.6263Z' fill='%230038FF'/%3e %3cpath d='M14.4971 22.9581L14.3715 23.0218L13.8569 23.1349L13.9574 23.0769L14.4971 22.9581Z' fill='%230000E3'/%3e %3cpath d='M24.6113 15.2522L25.4185 14.8029L25.3709 14.4056L24.5642 14.8735L24.6113 15.2522Z' fill='%239DFF5A'/%3e %3cpath d='M18.3573 17.134L19.6812 16.8389L19.6002 16.4877L18.2737 16.7774L18.3573 17.134Z' fill='%2343FFB4'/%3e %3cpath d='M24.9981 13.3518L25.4655 12.7775L25.2702 12.4938L24.8079 13.0778L24.9981 13.3518Z' fill='%23F4F802'/%3e %3cpath d='M21.8115 17.9181L23.055 17.5865L23.2154 17.3427L21.9628 17.6834L21.8115 17.9181Z' fill='%231FFFD7'/%3e %3cpath d='M22.0068 13.7142L22.7042 13.3132L22.5434 13.6254L21.8538 14.002L22.0068 13.7142Z' fill='%23D7FF1F'/%3e %3cpath d='M17.8295 18.8008L19.1769 18.4524L18.9726 18.2744L17.6169 18.6156L17.8295 18.8008Z' fill='%2300D8FF'/%3e %3cpath d='M23.4475 16.738L24.5174 16.3712L24.5873 16.011L23.5128 16.3925L23.4475 16.738Z' fill='%2356FFA0'/%3e %3cpath d='M17.6169 18.6156L18.9726 18.2744L18.7841 18.0474L17.4204 18.3794L17.6169 18.6156Z' fill='%2300E4F8'/%3e %3cpath d='M23.3473 12.6751L23.7642 12.1407L23.5203 12.3217L23.1116 12.8316L23.3473 12.6751Z' fill='%23FFDE00'/%3e %3cpath d='M19.5462 15.5796L20.6708 15.3279L20.6647 15.6942L19.5417 15.9419L19.5462 15.5796Z' fill='%237DFF7A'/%3e %3cpath d='M20.7929 14.6357L21.7338 14.326L21.6494 14.6781L20.7139 14.972L20.7929 14.6357Z' fill='%23AAFF4D'/%3e %3cpath d='M13.326 23.105L13.2132 23.0366L12.708 22.8738L12.7916 22.9328L13.326 23.105Z' fill='%230000E8'/%3e %3cpath d='M18.0527 18.9301L19.3918 18.5765L19.177 18.4521L17.8296 18.8006L18.0527 18.9301Z' fill='%2300D0FF'/%3e %3cpath d='M9.38281 15.3388L9.53756 15.8578L9.5596 14.872L9.40487 14.322L9.38281 15.3388Z' fill='%2394FF63'/%3e %3cpath d='M17.4207 18.3792L18.7843 18.0472L18.6162 17.7767L17.2451 18.0979L17.4207 18.3792Z' fill='%230CF4EB'/%3e %3cpath d='M20.2468 18.4958L21.5428 18.1788L21.3424 18.2852L20.0447 18.6036L20.2468 18.4958Z' fill='%2300E4F8'/%3e %3cpath d='M16.856 14.8848L16.9194 15.4872L16.9166 16.5657L16.8535 15.9679L16.856 14.8848Z' fill='%2383FF73'/%3e %3cpath d='M9.44019 11.1742L9.57946 11.8056L9.89026 10.9692L9.75378 10.3259L9.44019 11.1742Z' fill='%23FF9100'/%3e %3cpath d='M15.5706 22.0603L15.4723 22.2802L15.0063 22.6909L15.0863 22.4876L15.5706 22.0603Z' fill='%230008FF'/%3e %3cpath d='M24.808 13.0778L25.2704 12.4939L25.0486 12.2671L24.5923 12.8557L24.808 13.0778Z' fill='%23FFE600'/%3e %3cpath d='M18.2807 19.0008L19.6116 18.6442L19.3916 18.5767L18.0525 18.9303L18.2807 19.0008Z' fill='%2300CCFF'/%3e %3cpath d='M16.669 19.1052L16.6884 19.5924L16.4006 20.4226L16.3755 19.954L16.669 19.1052Z' fill='%2300A0FF'/%3e %3cpath d='M10.1294 19.1456L10.2049 19.3845L9.97664 18.5074L9.88989 18.2253L10.1294 19.1456Z' fill='%2300CCFF'/%3e %3cpath d='M23.5962 12.5811L24.0215 12.0262L23.764 12.1407L23.3472 12.6751L23.5962 12.5811Z' fill='%23FFD300'/%3e %3cpath d='M10.873 20.9626L10.894 21.011L10.5474 20.299L10.5063 20.2094L10.873 20.9626Z' fill='%230064FF'/%3e %3cpath d='M17.2449 18.0983L18.616 17.7771L18.4726 17.47L17.0947 17.7789L17.2449 18.0983Z' fill='%231CFFDB'/%3e %3cpath d='M18.2737 16.777L19.6002 16.4872L19.5526 16.1246L18.2236 16.4089L18.2737 16.777Z' fill='%235AFF9D'/%3e %3cpath d='M12.5339 6.57788L12.3501 7.03656L12.9714 7.14115L13.0917 6.70011L12.5339 6.57788Z' fill='maroon'/%3e %3cpath d='M24.5642 14.8733L25.3708 14.4054L25.2833 14.0245L24.479 14.5082L24.5642 14.8733Z' fill='%23B4FF43'/%3e %3cpath d='M24.5924 12.8557L25.0487 12.2671L24.8063 12.1034L24.3569 12.6913L24.5924 12.8557Z' fill='%23FFDB00'/%3e %3cpath d='M22.1891 13.4705L22.8955 13.0463L22.7045 13.3133L22.0071 13.7142L22.1891 13.4705Z' fill='%23E7FF0F'/%3e %3cpath d='M23.852 12.5521L24.2857 11.9812L24.0215 12.0261L23.5962 12.581L23.852 12.5521Z' fill='%23FFD000'/%3e %3cpath d='M18.5085 19.0106L19.8314 18.6534L19.6119 18.6444L18.281 19.001L18.5085 19.0106Z' fill='%2300D0FF'/%3e %3cpath d='M21.9631 17.6831L23.2158 17.3424L23.3478 17.0571L22.0873 17.4061L21.9631 17.6831Z' fill='%2330FFC7'/%3e %3cpath d='M24.3568 12.6911L24.8062 12.1032L24.5497 12.0071L24.1079 12.589L24.3568 12.6911Z' fill='%23FFD000'/%3e %3cpath d='M24.1078 12.5893L24.5496 12.0074L24.2857 11.9814L23.8521 12.5523L24.1078 12.5893Z' fill='%23FFCC00'/%3e %3cpath d='M23.5132 16.3927L24.5876 16.0111L24.6192 15.6349L23.542 16.0301L23.5132 16.3927Z' fill='%236DFF8A'/%3e %3cpath d='M19.5859 15.2294L20.714 14.9722L20.6709 15.3281L19.5464 15.5799L19.5859 15.2294Z' fill='%2394FF63'/%3e %3cpath d='M20.9059 14.3277L21.8538 14.0017L21.7336 14.3259L20.7927 14.6356L20.9059 14.3277Z' fill='%23C1FF36'/%3e %3cpath d='M20.4326 18.3325L21.7273 18.0177L21.543 18.1785L20.2471 18.4955L20.4326 18.3325Z' fill='%230CF4EB'/%3e %3cpath d='M17.0944 17.7787L18.4722 17.4699L18.3572 17.1338L16.9734 17.4293L17.0944 17.7787Z' fill='%232CFFCA'/%3e %3cpath d='M15.5845 9.76025L15.7427 10.1541L16.1211 11.1359L15.9256 10.742L15.5845 9.76025Z' fill='%23FF6000'/%3e %3cpath d='M16.4124 12.1865L16.5495 12.6924L16.754 13.783L16.6095 13.2765L16.4124 12.1865Z' fill='%23FFE600'/%3e %3cpath d='M13.8572 23.1355L13.7151 23.0653L13.2134 23.0367L13.3262 23.1052L13.8572 23.1355Z' fill='%230000ED'/%3e %3cpath d='M9.60917 16.8586L9.73332 17.2723L9.66463 16.3103L9.53735 15.8577L9.60917 16.8586Z' fill='%2356FFA0'/%3e %3cpath d='M18.2238 16.409L19.5527 16.1248L19.5397 15.76L18.2087 16.0388L18.2238 16.409Z' fill='%236DFF8A'/%3e %3cpath d='M18.7291 18.9589L20.0446 18.6034L19.831 18.6533L18.5081 19.0105L18.7291 18.9589Z' fill='%2300D4FF'/%3e %3cpath d='M10.0771 8.9822L10.154 9.5956L10.6314 9.00369L10.5552 8.38672L10.0771 8.9822Z' fill='%23FF1A00'/%3e %3cpath d='M24.4792 14.5083L25.2834 14.0246L25.1582 13.6702L24.3579 14.1667L24.4792 14.5083Z' fill='%23CAFF2C'/%3e %3cpath d='M12.2119 22.5812L12.1583 22.4225L11.7129 22.0334L11.7366 22.1661L12.2119 22.5812Z' fill='%23000CFF'/%3e %3cpath d='M15.0066 22.6912L14.8572 22.7673L14.3718 23.0222L14.4974 22.9586L15.0066 22.6912Z' fill='blue'/%3e %3cpath d='M16.5238 19.184L17.8295 18.8008L17.617 18.6156L16.2981 18.9872L16.5238 19.184Z' fill='%2300D0FF'/%3e %3cpath d='M16.2979 18.9871L17.6168 18.6155L17.4203 18.3793L16.0889 18.7363L16.2979 18.9871Z' fill='%2300DCFE'/%3e %3cpath d='M11.7366 22.1661L11.7128 22.0335L11.2978 21.5391L11.2937 21.6386L11.7366 22.1661Z' fill='%230028FF'/%3e %3cpath d='M22.3949 13.2773L23.1113 12.8314L22.8952 13.0461L22.1887 13.4703L22.3949 13.2773Z' fill='%23F8F500'/%3e %3cpath d='M11.1761 7.37181L11.0986 7.94784L11.6929 7.6797L11.7461 7.11475L11.1761 7.37181Z' fill='%23A40000'/%3e %3cpath d='M16.7606 19.3218L18.0528 18.9304L17.8297 18.8009L16.5239 19.1841L16.7606 19.3218Z' fill='%2300C8FF'/%3e %3cpath d='M16.4007 20.4229L16.3559 20.7995L15.9978 21.4935L16.0319 21.1388L16.4007 20.4229Z' fill='%230064FF'/%3e %3cpath d='M9.36157 12.735L9.52412 13.3462L9.73858 12.4375L9.57963 11.8054L9.36157 12.735Z' fill='gold'/%3e %3cpath d='M10.5064 20.2095L10.5475 20.2992L10.2628 19.5194L10.2051 19.3844L10.5064 20.2095Z' fill='%230098FF'/%3e %3cpath d='M16.9738 17.4293L18.3576 17.1338L18.274 16.7772L16.8853 17.0585L16.9738 17.4293Z' fill='%2343FFB4'/%3e %3cpath d='M16.089 18.7365L17.4204 18.3795L17.2449 18.0981L15.9019 18.4378L16.089 18.7365Z' fill='%2306ECF1'/%3e %3cpath d='M12.7083 22.8736L12.6234 22.6964L12.1584 22.4222L12.2121 22.581L12.7083 22.8736Z' fill='blue'/%3e %3cpath d='M22.0869 17.4063L23.3475 17.0573L23.4475 16.7379L22.1806 17.0941L22.0869 17.4063Z' fill='%2343FFB4'/%3e %3cpath d='M23.5419 16.0297L24.6191 15.6346L24.6114 15.2521L23.5332 15.6593L23.5419 16.0297Z' fill='%2383FF73'/%3e %3cpath d='M13.0917 6.70032L12.9714 7.14136L13.593 7.42673L13.65 7.00091L13.0917 6.70032Z' fill='%23840000'/%3e %3cpath d='M20.5966 18.1183L21.8904 17.8065L21.727 18.0179L20.4324 18.3327L20.5966 18.1183Z' fill='%2319FFDE'/%3e %3cpath d='M16.9165 16.5658L16.9759 17.1426L16.8713 18.1605L16.811 17.5972L16.9165 16.5658Z' fill='%2340FFB7'/%3e %3cpath d='M17.0022 19.3969L18.2809 19.0009L18.0527 18.9304L16.7605 19.3218L17.0022 19.3969Z' fill='%2300C4FF'/%3e %3cpath d='M21.0507 14.0566L22.0071 13.714L21.8541 14.0018L20.9062 14.3278L21.0507 14.0566Z' fill='%23D4FF23'/%3e %3cpath d='M19.6593 14.9L20.7929 14.636L20.7138 14.9723L19.5857 15.2295L19.6593 14.9Z' fill='%23AAFF4D'/%3e %3cpath d='M11.2935 21.6386L11.2976 21.539L10.9231 20.9512L10.8938 21.0114L11.2935 21.6386Z' fill='%23004CFF'/%3e %3cpath d='M18.9381 18.8472L20.2469 18.4957L20.0447 18.6035L18.7292 18.959L18.9381 18.8472Z' fill='%2300E0FB'/%3e %3cpath d='M15.9022 18.4379L17.2452 18.0982L17.095 17.7788L15.7417 18.0988L15.9022 18.4379Z' fill='%2316FFE1'/%3e %3cpath d='M24.3576 14.1669L25.1579 13.6704L24.998 13.3519L24.2034 13.8578L24.3576 14.1669Z' fill='%23DEFF19'/%3e %3cpath d='M15.1743 8.8717L15.2875 9.26886L15.7428 10.1541L15.5846 9.76017L15.1743 8.8717Z' fill='%23FF2900'/%3e %3cpath d='M22.6201 13.1401L23.3471 12.6749L23.1114 12.8314L22.395 13.2772L22.6201 13.1401Z' fill='%23FFEA00'/%3e %3cpath d='M18.209 16.0387L19.5399 15.7599L19.5619 15.4023L18.2295 15.6758L18.209 16.0387Z' fill='%2383FF73'/%3e %3cpath d='M9.89031 18.2254L9.97705 18.5075L9.82812 17.5996L9.73389 17.2726L9.89031 18.2254Z' fill='%231FFFD7'/%3e %3cpath d='M13.2133 23.0366L13.0965 22.8489L12.6233 22.6965L12.7081 22.8738L13.2133 23.0366Z' fill='blue'/%3e %3cpath d='M17.2425 19.4073L18.5082 19.0104L18.2807 19.0007L17.002 19.3967L17.2425 19.4073Z' fill='%2300C4FF'/%3e %3cpath d='M16.8851 17.0584L18.2738 16.7771L18.2238 16.4091L16.8313 16.6756L16.8851 17.0584Z' fill='%2356FFA0'/%3e %3cpath d='M14.3715 23.0222L14.2009 22.958L13.7148 23.0652L13.8569 23.1354L14.3715 23.0222Z' fill='blue'/%3e %3cpath d='M15.7411 18.0987L17.0944 17.7787L16.9735 17.4292L15.6113 17.7277L15.7411 18.0987Z' fill='%2329FFCE'/%3e %3cpath d='M24.2035 13.8578L24.9981 13.3519L24.8079 13.0779L24.0203 13.5894L24.2035 13.8578Z' fill='%23EEFF09'/%3e %3cpath d='M13.6501 7.00085L13.593 7.42668L14.1973 7.88556L14.1933 7.47229L13.6501 7.00085Z' fill='%23920000'/%3e %3cpath d='M15.9977 21.4934L15.883 21.7354L15.4724 22.2804L15.5708 22.0605L15.9977 21.4934Z' fill='%230038FF'/%3e %3cpath d='M22.8585 13.0626L23.5964 12.5808L23.3473 12.6748L22.6204 13.14L22.8585 13.0626Z' fill='%23FFDE00'/%3e %3cpath d='M23.5331 15.6591L24.6113 15.2519L24.5643 14.8732L23.4871 15.2907L23.5331 15.6591Z' fill='%239AFF5D'/%3e %3cpath d='M10.8939 21.0111L10.9232 20.9509L10.5985 20.2837L10.5474 20.2991L10.8939 21.0111Z' fill='%230074FF'/%3e %3cpath d='M22.1809 17.0941L23.4478 16.7379L23.5132 16.3925L22.2416 16.7545L22.1809 17.0941Z' fill='%235AFF9D'/%3e %3cpath d='M15.3302 19.5999L16.5237 19.1838L16.2981 18.9871L15.0867 19.3876L15.3302 19.5999Z' fill='%2300C4FF'/%3e %3cpath d='M15.0865 19.3879L16.2978 18.9873L16.0888 18.7365L14.8606 19.1173L15.0865 19.3879Z' fill='%2300D0FF'/%3e %3cpath d='M9.40479 14.3222L9.55951 14.8721L9.67591 13.9267L9.52397 13.3466L9.40479 14.3222Z' fill='%23D1FF26'/%3e %3cpath d='M21.2227 13.8293L22.1889 13.4705L22.0069 13.7142L21.0505 14.0567L21.2227 13.8293Z' fill='%23E4FF13'/%3e %3cpath d='M14.7063 8.10181L14.7676 8.50546L15.2875 9.26883L15.1744 8.87167L14.7063 8.10181Z' fill='%23DF0000'/%3e %3cpath d='M20.7354 17.8578L22.0289 17.5497L21.8907 17.8064L20.5969 18.1182L20.7354 17.8578Z' fill='%2329FFCE'/%3e %3cpath d='M16.7539 13.783L16.8177 14.3899L16.9191 15.4871L16.8557 14.8847L16.7539 13.783Z' fill='%23C4FF33'/%3e %3cpath d='M15.585 19.749L16.7603 19.3218L16.5237 19.1841L15.3301 19.6002L15.585 19.749Z' fill='%2300BCFF'/%3e %3cpath d='M19.1294 18.6778L20.4323 18.3325L20.2467 18.4955L18.938 18.8471L19.1294 18.6778Z' fill='%2309F0EE'/%3e %3cpath d='M19.7651 14.5996L20.9059 14.3278L20.7927 14.6356L19.6592 14.8996L19.7651 14.5996Z' fill='%23BEFF39'/%3e %3cpath d='M14.1931 7.47229L14.1971 7.88556L14.7672 8.5054L14.706 8.10175L14.1931 7.47229Z' fill='%23B20000'/%3e %3cpath d='M17.4762 19.3531L18.7293 18.959L18.5083 19.0106L17.2427 19.4075L17.4762 19.3531Z' fill='%2300CCFF'/%3e %3cpath d='M14.8608 19.1173L16.089 18.7364L15.9018 18.4377L14.6582 18.7951L14.8608 19.1173Z' fill='%2300E0FB'/%3e %3cpath d='M24.0201 13.5895L24.8078 13.078L24.5921 12.8558L23.8127 13.3691L24.0201 13.5895Z' fill='%23FBF100'/%3e %3cpath d='M9.75391 10.3259L9.89039 10.9692L10.2869 10.2491L10.1542 9.59534L9.75391 10.3259Z' fill='%23FF5200'/%3e %3cpath d='M23.1032 13.0471L23.8522 12.5519L23.5963 12.5808L22.8584 13.0626L23.1032 13.0471Z' fill='%23FFDB00'/%3e %3cpath d='M16.1211 11.1356L16.247 11.6425L16.5497 12.6921L16.4125 12.1862L16.1211 11.1356Z' fill='%23FF9F00'/%3e %3cpath d='M10.2048 19.3847L10.2625 19.5197L10.0469 18.6911L9.97656 18.5076L10.2048 19.3847Z' fill='%2300D4FF'/%3e %3cpath d='M12.1581 22.4222L12.1492 22.1609L11.7352 21.7994L11.7126 22.0332L12.1581 22.4222Z' fill='%230028FF'/%3e %3cpath d='M15.8451 19.8301L17.0019 19.3967L16.7602 19.3215L15.585 19.7487L15.8451 19.8301Z' fill='%2300B8FF'/%3e %3cpath d='M18.229 15.676L19.5615 15.4026L19.6182 15.0615L18.2847 15.3298L18.229 15.676Z' fill='%239AFF5D'/%3e %3cpath d='M16.8712 18.1602L16.8868 18.668L16.6884 19.5924L16.6689 19.1052L16.8712 18.1602Z' fill='%2302E8F4'/%3e %3cpath d='M11.7127 22.0333L11.7352 21.7995L11.3495 21.34L11.2976 21.5389L11.7127 22.0333Z' fill='%230040FF'/%3e %3cpath d='M16.8311 16.6757L18.2235 16.4092L18.2085 16.0389L16.8135 16.2907L16.8311 16.6757Z' fill='%236DFF8A'/%3e %3cpath d='M15.6115 17.7275L16.9737 17.429L16.8851 17.0582L15.5159 17.3339L15.6115 17.7275Z' fill='%2340FFB7'/%3e %3cpath d='M23.8129 13.3688L24.5923 12.8555L24.3568 12.6912L23.5869 13.2023L23.8129 13.3688Z' fill='%23FFE600'/%3e %3cpath d='M23.3483 13.0944L24.108 12.5893L23.8522 12.5522L23.1033 13.0474L23.3483 13.0944Z' fill='gold'/%3e %3cpath d='M13.7149 23.0649L13.5664 22.875L13.0964 22.8486L13.2132 23.0364L13.7149 23.0649Z' fill='blue'/%3e %3cpath d='M23.5871 13.2023L24.357 12.6912L24.1081 12.5891L23.3484 13.0942L23.5871 13.2023Z' fill='%23FFDB00'/%3e %3cpath d='M14.6584 18.7952L15.902 18.4378L15.7415 18.0988L14.4841 18.4296L14.6584 18.7952Z' fill='%230FF8E7'/%3e %3cpath d='M12.6233 22.6965L12.5815 22.4157L12.1494 22.1611L12.1583 22.4224L12.6233 22.6965Z' fill='%230018FF'/%3e %3cpath d='M11.7463 7.11499L11.6931 7.67995L12.3226 7.59124L12.3502 7.03699L11.7463 7.11499Z' fill='%23890000'/%3e %3cpath d='M15.4725 22.2805L15.3011 22.3759L14.8572 22.7673L15.0066 22.6912L15.4725 22.2805Z' fill='%230018FF'/%3e %3cpath d='M23.4869 15.2909L24.5642 14.8735L24.479 14.5084L23.4045 14.934L23.4869 15.2909Z' fill='%23B1FF46'/%3e %3cpath d='M21.4178 13.6518L22.3948 13.2773L22.1886 13.4704L21.2224 13.8293L21.4178 13.6518Z' fill='%23F1FC06'/%3e %3cpath d='M11.2981 21.539L11.35 21.3401L11.0021 20.7937L10.9236 20.9512L11.2981 21.539Z' fill='%230060FF'/%3e %3cpath d='M22.2415 16.7545L23.513 16.3924L23.5417 16.0298L22.2674 16.3963L22.2415 16.7545Z' fill='%236DFF8A'/%3e %3cpath d='M16.1039 19.842L17.2427 19.4074L17.0021 19.3969L15.8452 19.8303L16.1039 19.842Z' fill='%2300B8FF'/%3e %3cpath d='M9.53735 15.8578L9.66463 16.3104L9.68631 15.3633L9.55939 14.8719L9.53735 15.8578Z' fill='%2394FF63'/%3e %3cpath d='M17.6965 19.2345L18.9381 18.8469L18.7292 18.9587L17.4761 19.3528L17.6965 19.2345Z' fill='%2300D8FF'/%3e %3cpath d='M14.303 20.0434L15.3301 19.6001L15.0867 19.3878L14.0376 19.8119L14.303 20.0434Z' fill='%2300B4FF'/%3e %3cpath d='M20.8444 17.558L22.1381 17.2542L22.0288 17.5497L20.7354 17.8579L20.8444 17.558Z' fill='%233CFFBA'/%3e %3cpath d='M19.2987 18.4552L20.5967 18.1182L20.4325 18.3325L19.1296 18.6778L19.2987 18.4552Z' fill='%2316FFE1'/%3e %3cpath d='M14.0378 19.8121L15.0869 19.388L14.861 19.1174L13.7913 19.5171L14.0378 19.8121Z' fill='%2300C0FF'/%3e %3cpath d='M10.5472 20.2993L10.5984 20.2839L10.3317 19.5533L10.2625 19.5195L10.5472 20.2993Z' fill='%2300A8FF'/%3e %3cpath d='M19.9009 14.3372L21.0504 14.0565L20.9059 14.3278L19.7651 14.5997L19.9009 14.3372Z' fill='%23D1FF26'/%3e %3cpath d='M10.5557 8.38649L10.6318 9.00347L11.1743 8.56788L11.0989 7.94788L10.5557 8.38649Z' fill='%23D10000'/%3e %3cpath d='M14.5806 20.2059L15.5851 19.7489L15.3301 19.6002L14.303 20.0435L14.5806 20.2059Z' fill='%2300A8FF'/%3e %3cpath d='M14.4839 18.4292L15.7412 18.0984L15.6114 17.7274L14.3425 18.0292L14.4839 18.4292Z' fill='%2323FFD4'/%3e %3cpath d='M13.0968 22.8487L13.0215 22.5568L12.5818 22.4155L12.6236 22.6963L13.0968 22.8487Z' fill='%230010FF'/%3e %3cpath d='M13.7911 19.5171L14.8609 19.1174L14.6583 18.7953L13.5696 19.1661L13.7911 19.5171Z' fill='%2300D4FF'/%3e %3cpath d='M15.5161 17.3341L16.8853 17.0584L16.8315 16.6757L15.457 16.9277L15.5161 17.3341Z' fill='%2356FFA0'/%3e %3cpath d='M14.8571 22.7671L14.6594 22.7168L14.2012 22.9578L14.3718 23.022L14.8571 22.7671Z' fill='%230008FF'/%3e %3cpath d='M16.8137 16.2905L18.2087 16.0387L18.2292 15.6758L16.833 15.9131L16.8137 16.2905Z' fill='%2383FF73'/%3e %3cpath d='M18.2849 15.3298L19.6184 15.0615L19.7085 14.7457L18.3744 15.0094L18.2849 15.3298Z' fill='%23B1FF46'/%3e %3cpath d='M23.4045 14.934L24.4789 14.5084L24.3576 14.1667L23.2878 14.5982L23.4045 14.934Z' fill='%23C4FF33'/%3e %3cpath d='M14.8638 20.2948L15.8453 19.8302L15.5852 19.7489L14.5808 20.2058L14.8638 20.2948Z' fill='%2300A8FF'/%3e %3cpath d='M21.6315 13.5291L22.6202 13.14L22.395 13.2771L21.418 13.6516L21.6315 13.5291Z' fill='%23FEED00'/%3e %3cpath d='M16.6883 19.5927L16.6351 19.9946L16.3557 20.7995L16.4005 20.4229L16.6883 19.5927Z' fill='%2300A8FF'/%3e %3cpath d='M16.3545 19.7837L17.4761 19.3529L17.2426 19.4073L16.1038 19.8419L16.3545 19.7837Z' fill='%2300C0FF'/%3e %3cpath d='M12.1496 22.1613L12.2341 21.8166L11.8522 21.4832L11.7356 21.7998L12.1496 22.1613Z' fill='%230040FF'/%3e %3cpath d='M10.9236 20.9511L11.002 20.7936L10.7005 20.1735L10.5989 20.2839L10.9236 20.9511Z' fill='%230088FF'/%3e %3cpath d='M9.73349 17.2726L9.82773 17.5995L9.76254 16.6833L9.66479 16.3105L9.73349 17.2726Z' fill='%235AFF9D'/%3e %3cpath d='M11.7353 21.7994L11.8519 21.4828L11.4962 21.0588L11.3496 21.3399L11.7353 21.7994Z' fill='%230058FF'/%3e %3cpath d='M9.57959 11.8054L9.73854 12.4375L10.0439 11.6202L9.8904 10.969L9.57959 11.8054Z' fill='%23FF9400'/%3e %3cpath d='M13.5696 19.1659L14.6583 18.7951L14.484 18.4294L13.3787 18.7674L13.5696 19.1659Z' fill='%2306ECF1'/%3e %3cpath d='M13.477 20.5037L14.3031 20.0437L14.0377 19.8121L13.186 20.2498L13.477 20.5037Z' fill='%2300A0FF'/%3e %3cpath d='M17.8982 19.0553L19.1296 18.6777L18.9381 18.847L17.6965 19.2345L17.8982 19.0553Z' fill='%2302E8F4'/%3e %3cpath d='M13.1861 20.2497L14.0378 19.8121L13.7912 19.5171L12.9155 19.9264L13.1861 20.2497Z' fill='%2300B0FF'/%3e %3cpath d='M16.9195 15.4869L16.979 16.0778L16.9761 17.1423L16.9167 16.5654L16.9195 15.4869Z' fill='%2383FF73'/%3e %3cpath d='M12.5815 22.4156L12.6325 22.0509L12.2339 21.8163L12.1494 22.161L12.5815 22.4156Z' fill='%230034FF'/%3e %3cpath d='M22.2674 16.3964L23.5417 16.0298L23.533 15.6594L22.2578 16.0289L22.2674 16.3964Z' fill='%2383FF73'/%3e %3cpath d='M14.2008 22.9577L14.0212 22.7743L13.5662 22.8751L13.7147 23.0649L14.2008 22.9577Z' fill='%230008FF'/%3e %3cpath d='M14.3424 18.0292L15.6113 17.7275L15.5156 17.3339L14.2375 17.6047L14.3424 18.0292Z' fill='%2339FFBE'/%3e %3cpath d='M15.7429 10.1542L15.854 10.6638L16.2472 11.6429L16.1213 11.136L15.7429 10.1542Z' fill='%23FF6000'/%3e %3cpath d='M13.7809 20.6816L14.5805 20.2057L14.3029 20.0433L13.4768 20.5034L13.7809 20.6816Z' fill='%230094FF'/%3e %3cpath d='M20.063 14.1195L21.2225 13.8293L21.0504 14.0568L19.9009 14.3375L20.063 14.1195Z' fill='%23E1FF16'/%3e %3cpath d='M19.4408 18.1849L20.7351 17.858L20.5966 18.1184L19.2986 18.4554L19.4408 18.1849Z' fill='%2329FFCE'/%3e %3cpath d='M20.9211 17.2261L22.2153 16.9271L22.1379 17.2541L20.8442 17.5579L20.9211 17.2261Z' fill='%2353FFA4'/%3e %3cpath d='M11.3497 21.3399L11.4963 21.0589L11.1755 20.5547L11.0017 20.7935L11.3497 21.3399Z' fill='%230074FF'/%3e %3cpath d='M15.1447 20.3079L16.1037 19.8418L15.8451 19.8301L14.8635 20.2947L15.1447 20.3079Z' fill='%2300A8FF'/%3e %3cpath d='M23.288 14.5981L24.3578 14.1667L24.2036 13.8575L23.1401 14.2923L23.288 14.5981Z' fill='%23D7FF1F'/%3e %3cpath d='M12.9153 19.926L13.791 19.5167L13.5695 19.1656L12.6719 19.5413L12.9153 19.926Z' fill='%2300C4FF'/%3e %3cpath d='M21.8575 13.4651L22.8581 13.063L22.62 13.1404L21.6313 13.5294L21.8575 13.4651Z' fill='%23FFE600'/%3e %3cpath d='M9.97681 18.5073L10.0472 18.6908L9.90663 17.8334L9.82788 17.5994L9.97681 18.5073Z' fill='%2326FFD1'/%3e %3cpath d='M13.5663 22.8753L13.4575 22.5811L13.021 22.557L13.0963 22.8489L13.5663 22.8753Z' fill='%230014FF'/%3e %3cpath d='M15.457 16.9276L16.8315 16.6755L16.8139 16.2905L15.4363 16.5188L15.457 16.9276Z' fill='%236DFF8A'/%3e %3cpath d='M12.3502 7.03662L12.3225 7.59087L12.9699 7.68538L12.9715 7.14122L12.3502 7.03662Z' fill='maroon'/%3e %3cpath d='M12.2341 21.8162L12.4594 21.4101L12.1094 21.1045L11.8523 21.4828L12.2341 21.8162Z' fill='%23005CFF'/%3e %3cpath d='M12.8649 20.9655L13.4769 20.5037L13.1859 20.2498L12.5454 20.6867L12.8649 20.9655Z' fill='%23008CFF'/%3e %3cpath d='M11.8523 21.4828L12.1094 21.1044L11.7834 20.7157L11.4966 21.0588L11.8523 21.4828Z' fill='%230070FF'/%3e %3cpath d='M13.3786 18.7672L14.484 18.4292L14.3426 18.0292L13.2231 18.3313L13.3786 18.7672Z' fill='%231CFFDB'/%3e %3cpath d='M12.5453 20.6865L13.1858 20.2496L12.9152 19.9263L12.248 20.3317L12.5453 20.6865Z' fill='%23009CFF'/%3e %3cpath d='M14.0905 20.7797L14.8633 20.2948L14.5804 20.2058L13.7808 20.6817L14.0905 20.7797Z' fill='%230094FF'/%3e %3cpath d='M13.0212 22.5571L13.0381 22.1811L12.6325 22.0511L12.5815 22.4158L13.0212 22.5571Z' fill='%23002CFF'/%3e %3cpath d='M16.5496 12.6923L16.614 13.3034L16.8179 14.3898L16.7541 13.7829L16.5496 12.6923Z' fill='%23FFE600'/%3e %3cpath d='M16.5912 19.6566L17.6967 19.2346L17.4763 19.3529L16.3547 19.7836L16.5912 19.6566Z' fill='%2300CCFF'/%3e %3cpath d='M16.3556 20.7993L16.227 21.0683L15.8828 21.7354L15.9975 21.4934L16.3556 20.7993Z' fill='%230070FF'/%3e %3cpath d='M16.8333 15.9132L18.2295 15.6759L18.2852 15.3297L16.889 15.5532L16.8333 15.9132Z' fill='%239AFF5D'/%3e %3cpath d='M18.3743 15.009L19.7083 14.7454L19.8296 14.4633L18.4955 14.7227L18.3743 15.009Z' fill='%23C4FF33'/%3e %3cpath d='M12.4592 21.4102L12.8649 20.9653L12.5454 20.6865L12.1091 21.1046L12.4592 21.4102Z' fill='%230074FF'/%3e %3cpath d='M13.1984 21.1611L13.7809 20.6816L13.4768 20.5034L12.8647 20.9653L13.1984 21.1611Z' fill='%230080FF'/%3e %3cpath d='M12.6325 22.0508L12.8246 21.6249L12.4592 21.41L12.2339 21.8162L12.6325 22.0508Z' fill='%23004CFF'/%3e %3cpath d='M10.2627 19.5196L10.3319 19.5534L10.1302 18.7773L10.0471 18.6909L10.2627 19.5196Z' fill='%2300E0FB'/%3e %3cpath d='M23.1401 14.2925L24.2036 13.8577L24.0204 13.5894L22.9648 14.0249L23.1401 14.2925Z' fill='%23E7FF0F'/%3e %3cpath d='M12.1094 21.1046L12.5457 20.6865L12.2484 20.3317L11.7834 20.7159L12.1094 21.1046Z' fill='%230084FF'/%3e %3cpath d='M22.0906 13.4606L23.1033 13.0472L22.8585 13.0627L21.8579 13.4649L22.0906 13.4606Z' fill='%23FFE200'/%3e %3cpath d='M12.6716 19.5417L13.5692 19.166L13.3783 18.7676L12.4614 19.1051L12.6716 19.5417Z' fill='%2300E0FB'/%3e %3cpath d='M12.248 20.3319L12.9152 19.9265L12.6717 19.5417L11.9802 19.9097L12.248 20.3319Z' fill='%2300B4FF'/%3e %3cpath d='M11.4966 21.059L11.7834 20.7159L11.4896 20.2535L11.1758 20.5548L11.4966 21.059Z' fill='%23008CFF'/%3e %3cpath d='M10.5987 20.2838L10.7003 20.1734L10.4527 19.4945L10.332 19.5533L10.5987 20.2838Z' fill='%2300B4FF'/%3e %3cpath d='M12.8247 21.625L13.1986 21.1612L12.8649 20.9653L12.4592 21.4101L12.8247 21.625Z' fill='%230068FF'/%3e %3cpath d='M22.2579 16.0289L23.5331 15.6594L23.487 15.2909L22.2129 15.6618L22.2579 16.0289Z' fill='%239AFF5D'/%3e %3cpath d='M11.0018 20.7937L11.1756 20.5548L10.8977 19.9827L10.7002 20.1735L11.0018 20.7937Z' fill='%23009CFF'/%3e %3cpath d='M18.076 18.8193L19.2986 18.4552L19.1295 18.6778L17.8982 19.0553L18.076 18.8193Z' fill='%2313FCE4'/%3e %3cpath d='M15.4171 20.2452L16.3546 19.7838L16.1038 19.8421L15.1448 20.3082L15.4171 20.2452Z' fill='%2300B0FF'/%3e %3cpath d='M9.52441 13.3462L9.67635 13.9263L9.88527 13.0461L9.73888 12.4375L9.52441 13.3462Z' fill='%23FFDB00'/%3e %3cpath d='M14.2379 17.6048L15.516 17.334L15.457 16.9276L14.1724 17.1666L14.2379 17.6048Z' fill='%2353FFA4'/%3e %3cpath d='M20.2475 13.952L21.4181 13.652L21.2228 13.8294L20.0632 14.1196L20.2475 13.952Z' fill='%23EEFF09'/%3e %3cpath d='M22.9647 14.025L24.0202 13.5894L23.8128 13.369L22.7666 13.8028L22.9647 14.025Z' fill='%23F4F802'/%3e %3cpath d='M11.7833 20.7157L12.2482 20.3315L11.9804 19.9093L11.4895 20.2533L11.7833 20.7157Z' fill='%2300A0FF'/%3e %3cpath d='M22.3235 13.5168L23.3481 13.0943L23.1031 13.0474L22.0903 13.4608L22.3235 13.5168Z' fill='%23FFE200'/%3e %3cpath d='M13.5381 21.2691L14.0907 20.7796L13.781 20.6816L13.1985 21.1612L13.5381 21.2691Z' fill='%23007CFF'/%3e %3cpath d='M14.3981 20.7948L15.1446 20.3082L14.8635 20.2949L14.0906 20.7798L14.3981 20.7948Z' fill='%230094FF'/%3e %3cpath d='M15.8831 21.7354L15.6919 21.8564L15.301 22.3758L15.4725 22.2804L15.8831 21.7354Z' fill='%230044FF'/%3e %3cpath d='M10.1545 9.59528L10.2873 10.2491L10.76 9.66613L10.6319 9.00342L10.1545 9.59528Z' fill='%23FF1E00'/%3e %3cpath d='M20.9634 16.8709L22.2589 16.5771L22.2154 16.9271L20.9211 17.2262L20.9634 16.8709Z' fill='%2366FF90'/%3e %3cpath d='M13.0379 22.181L13.1963 21.7438L12.8245 21.6251L12.6323 22.0511L13.0379 22.181Z' fill='%230048FF'/%3e %3cpath d='M22.7666 13.8028L23.8129 13.369L23.5868 13.2025L22.551 13.6319L22.7666 13.8028Z' fill='%23FEED00'/%3e %3cpath d='M19.5523 17.873L20.8441 17.558L20.735 17.8578L19.4407 18.1847L19.5523 17.873Z' fill='%233CFFBA'/%3e %3cpath d='M22.5512 13.6316L23.587 13.2021L23.3483 13.094L22.3237 13.5165L22.5512 13.6316Z' fill='%23FFE200'/%3e %3cpath d='M13.2231 18.3316L14.3425 18.0295L14.2377 17.605L13.1072 17.8689L13.2231 18.3316Z' fill='%2336FFC1'/%3e %3cpath d='M13.1963 21.7435L13.538 21.2689L13.1984 21.161L12.8245 21.6248L13.1963 21.7435Z' fill='%230064FF'/%3e %3cpath d='M11.9801 19.9097L12.6716 19.5417L12.4614 19.1051L11.7485 19.4306L11.9801 19.9097Z' fill='%2300D0FF'/%3e %3cpath d='M15.2876 9.2688L15.3806 9.78269L15.8541 10.6636L15.7429 10.154L15.2876 9.2688Z' fill='%23FF2900'/%3e %3cpath d='M15.436 16.519L16.8136 16.2907L16.8329 15.9133L15.4543 16.1183L15.436 16.519Z' fill='%2387FF70'/%3e %3cpath d='M13.4577 22.5808L13.4406 22.2024L13.0381 22.1807L13.0212 22.5567L13.4577 22.5808Z' fill='%230030FF'/%3e %3cpath d='M12.4616 19.1048L13.3785 18.7673L13.2231 18.3313L12.29 18.6271L12.4616 19.1048Z' fill='%2313FCE4'/%3e %3cpath d='M16.9757 17.1426L16.9892 17.6727L16.8866 18.6683L16.8711 18.1605L16.9757 17.1426Z' fill='%2343FFB4'/%3e %3cpath d='M11.1754 20.555L11.4892 20.2537L11.2349 19.729L10.8975 19.9828L11.1754 20.555Z' fill='%2300ACFF'/%3e %3cpath d='M15.301 22.3757L15.0783 22.3468L14.6594 22.7168L14.8571 22.7671L15.301 22.3757Z' fill='%23002CFF'/%3e %3cpath d='M11.0986 7.94806L11.174 8.56807L11.7673 8.30236L11.6929 7.67993L11.0986 7.94806Z' fill='%23A80000'/%3e %3cpath d='M16.8072 19.4637L17.8983 19.0554L17.6966 19.2347L16.5911 19.6567L16.8072 19.4637Z' fill='%2300DCFE'/%3e %3cpath d='M12.9714 7.14111L12.9697 7.68527L13.6171 7.96139L13.5929 7.4265L12.9714 7.14111Z' fill='maroon'/%3e %3cpath d='M14.0215 22.7744L13.8803 22.4868L13.4578 22.581L13.5665 22.8752L14.0215 22.7744Z' fill='%230020FF'/%3e %3cpath d='M18.4956 14.7228L19.8297 14.4633L19.979 14.2223L18.6455 14.4782L18.4956 14.7228Z' fill='%23D7FF1F'/%3e %3cpath d='M11.4897 20.2534L11.9806 19.9094L11.7491 19.4303L11.2354 19.7287L11.4897 20.2534Z' fill='%2300C0FF'/%3e %3cpath d='M14.6594 22.7166L14.4503 22.548L14.0215 22.7742L14.2011 22.9576L14.6594 22.7166Z' fill='%230020FF'/%3e %3cpath d='M16.8889 15.553L18.285 15.3295L18.3746 15.009L16.9799 15.2197L16.8889 15.553Z' fill='%23B1FF46'/%3e %3cpath d='M22.2127 15.6617L23.4868 15.2908L23.4044 14.934L22.1333 15.3046L22.2127 15.6617Z' fill='%23B1FF46'/%3e %3cpath d='M9.55957 14.8721L9.6865 15.3634L9.799 14.4555L9.67597 13.9266L9.55957 14.8721Z' fill='%23CEFF29'/%3e %3cpath d='M13.8752 21.2863L14.3982 20.7947L14.0907 20.7797L13.5381 21.2692L13.8752 21.2863Z' fill='%23007CFF'/%3e %3cpath d='M20.449 13.8393L21.6315 13.5292L21.418 13.6518L20.2473 13.9518L20.449 13.8393Z' fill='%23FBF100'/%3e %3cpath d='M15.6735 20.107L16.5909 19.6565L16.3544 19.7836L15.417 20.2449L15.6735 20.107Z' fill='%2300BCFF'/%3e %3cpath d='M10.7002 20.1734L10.8977 19.9826L10.6697 19.3563L10.4526 19.4946L10.7002 20.1734Z' fill='%2300C4FF'/%3e %3cpath d='M14.6959 20.7263L15.417 20.2451L15.1447 20.3081L14.3982 20.7947L14.6959 20.7263Z' fill='%23009CFF'/%3e %3cpath d='M14.1723 17.1666L15.4569 16.9277L15.4362 16.5189L14.1479 16.7257L14.1723 17.1666Z' fill='%236DFF8A'/%3e %3cpath d='M13.4404 22.2026L13.5654 21.7631L13.1963 21.7438L13.0378 22.1809L13.4404 22.2026Z' fill='%23004CFF'/%3e %3cpath d='M18.2254 18.5326L19.441 18.1848L19.2988 18.4553L18.0762 18.8195L18.2254 18.5326Z' fill='%2323FFD4'/%3e %3cpath d='M13.5654 21.763L13.875 21.2862L13.5379 21.269L13.1963 21.7436L13.5654 21.763Z' fill='%230064FF'/%3e %3cpath d='M11.7488 19.4305L12.4616 19.1051L12.29 18.6273L11.5593 18.9063L11.7488 19.4305Z' fill='%2309F0EE'/%3e %3cpath d='M14.7673 8.50549L14.8395 9.02508L15.3803 9.78271L15.2873 9.26882L14.7673 8.50549Z' fill='%23DF0000'/%3e %3cpath d='M20.97 16.5014L22.2671 16.2131L22.2589 16.5771L20.9634 16.8709L20.97 16.5014Z' fill='%237DFF7A'/%3e %3cpath d='M10.3319 19.5532L10.4526 19.4944L10.2654 18.7733L10.1301 18.777L10.3319 19.5532Z' fill='%2302E8F4'/%3e %3cpath d='M9.66504 16.3102L9.76278 16.683L9.7838 15.7813L9.68672 15.3632L9.66504 16.3102Z' fill='%2394FF63'/%3e %3cpath d='M13.593 7.42664L13.6171 7.96153L14.2463 8.41216L14.1974 7.88552L13.593 7.42664Z' fill='%23920000'/%3e %3cpath d='M19.6302 17.5281L20.9209 17.2262L20.8441 17.558L19.5522 17.873L19.6302 17.5281Z' fill='%2350FFA7'/%3e %3cpath d='M13.1072 17.869L14.2377 17.605L14.1722 17.1667L13.0339 17.3913L13.1072 17.869Z' fill='%2350FFA7'/%3e %3cpath d='M12.2902 18.6274L13.2232 18.3316L13.1073 17.869L12.1616 18.1204L12.2902 18.6274Z' fill='%2330FFC7'/%3e %3cpath d='M22.1337 15.3049L23.4048 14.9342L23.2882 14.5984L22.022 14.9672L22.1337 15.3049Z' fill='%23C4FF33'/%3e %3cpath d='M10.0468 18.6909L10.1298 18.7773L9.99842 17.9745L9.90625 17.8335L10.0468 18.6909Z' fill='%232CFFCA'/%3e %3cpath d='M10.8976 19.9827L11.2351 19.7289L11.0267 19.1547L10.6697 19.3564L10.8976 19.9827Z' fill='%2300D4FF'/%3e %3cpath d='M9.82789 17.5995L9.90664 17.8335L9.84529 16.9685L9.7627 16.6832L9.82789 17.5995Z' fill='%235AFF9D'/%3e %3cpath d='M14.1973 7.88574L14.2462 8.41239L14.8395 9.02518L14.7674 8.50558L14.1973 7.88574Z' fill='%23B20000'/%3e %3cpath d='M11.2353 19.7287L11.749 19.4304L11.5596 18.9061L11.0269 19.1545L11.2353 19.7287Z' fill='%2300E4F8'/%3e %3cpath d='M20.6626 13.785L21.8574 13.4648L21.6313 13.5292L20.4487 13.8393L20.6626 13.785Z' fill='%23FFEA00'/%3e %3cpath d='M15.4543 16.1182L16.8329 15.9133L16.8887 15.5532L15.5114 15.7359L15.4543 16.1182Z' fill='%239DFF5A'/%3e %3cpath d='M18.6453 14.4784L19.9788 14.2224L20.1526 14.0291L18.82 14.2822L18.6453 14.4784Z' fill='%23E7FF0F'/%3e %3cpath d='M16.9973 19.2095L18.0761 18.8193L17.8983 19.0553L16.8071 19.4637L16.9973 19.2095Z' fill='%2309F0EE'/%3e %3cpath d='M16.8869 18.668L16.8277 19.0982L16.6353 19.9943L16.6885 19.5924L16.8869 18.668Z' fill='%2306ECF1'/%3e %3cpath d='M13.8801 22.4869L13.83 22.1152L13.4404 22.2027L13.4576 22.5811L13.8801 22.4869Z' fill='%23003CFF'/%3e %3cpath d='M14.2012 21.2116L14.6957 20.7261L14.398 20.7945L13.875 21.2861L14.2012 21.2116Z' fill='%230088FF'/%3e %3cpath d='M16.8179 14.3896L16.8788 14.9946L16.9788 16.0778L16.9192 15.4869L16.8179 14.3896Z' fill='%23C4FF33'/%3e %3cpath d='M16.2471 11.6427L16.3123 12.2577L16.6141 13.3034L16.5497 12.6923L16.2471 11.6427Z' fill='%23FF9F00'/%3e %3cpath d='M16.9795 15.22L18.3741 15.0093L18.4954 14.723L17.1035 14.9222L16.9795 15.22Z' fill='%23C7FF30'/%3e %3cpath d='M9.89062 10.9691L10.0441 11.6203L10.4334 10.9171L10.2872 10.249L9.89062 10.9691Z' fill='%23FF5900'/%3e %3cpath d='M15.9081 19.8973L16.8073 19.4636L16.5912 19.6565L15.6738 20.1071L15.9081 19.8973Z' fill='%2300D0FF'/%3e %3cpath d='M22.0216 14.9673L23.2878 14.5985L23.1399 14.2927L21.8804 14.6582L22.0216 14.9673Z' fill='%23D7FF1F'/%3e %3cpath d='M14.9761 20.5759L15.6735 20.1073L15.417 20.2452L14.6958 20.7264L14.9761 20.5759Z' fill='%2300ACFF'/%3e %3cpath d='M20.8834 13.7905L22.0906 13.4607L21.8579 13.4649L20.6631 13.7851L20.8834 13.7905Z' fill='%23FFE600'/%3e %3cpath d='M13.9228 21.6821L14.2016 21.2117L13.8753 21.2861L13.5657 21.7629L13.9228 21.6821Z' fill='%230070FF'/%3e %3cpath d='M13.8302 22.1152L13.9228 21.6824L13.5657 21.7632L13.4407 22.2028L13.8302 22.1152Z' fill='%230054FF'/%3e %3cpath d='M14.1477 16.7258L15.436 16.519L15.4543 16.1183L14.1653 16.2935L14.1477 16.7258Z' fill='%2387FF70'/%3e %3cpath d='M20.9404 16.1273L22.2397 15.8446L22.2671 16.2131L20.9699 16.5014L20.9404 16.1273Z' fill='%2394FF63'/%3e %3cpath d='M11.5594 18.9063L12.2901 18.6274L12.1615 18.1204L11.417 18.3499L11.5594 18.9063Z' fill='%2326FFD1'/%3e %3cpath d='M18.3419 18.2016L19.5525 17.8729L19.4409 18.1846L18.2253 18.5323L18.3419 18.2016Z' fill='%2339FFBE'/%3e %3cpath d='M14.4502 22.548L14.2781 22.2759L13.8801 22.4866L14.0214 22.7742L14.4502 22.548Z' fill='%230038FF'/%3e %3cpath d='M10.4525 19.4946L10.6696 19.3563L10.4975 18.6913L10.2654 18.7735L10.4525 19.4946Z' fill='%230CF4EB'/%3e %3cpath d='M19.6727 17.159L20.9636 16.8712L20.9213 17.2264L19.6306 17.5283L19.6727 17.159Z' fill='%2366FF90'/%3e %3cpath d='M16.635 19.9946L16.4954 20.2951L16.2271 21.0685L16.3557 20.7995L16.635 19.9946Z' fill='%2300B0FF'/%3e %3cpath d='M21.8805 14.658L23.1401 14.2925L22.9648 14.0249L21.7134 14.3856L21.8805 14.658Z' fill='%23E4FF13'/%3e %3cpath d='M13.034 17.391L14.1722 17.1665L14.1478 16.7256L13.0054 16.9103L13.034 17.391Z' fill='%236AFF8D'/%3e %3cpath d='M21.1041 13.8557L22.3235 13.5168L22.0903 13.4607L20.8831 13.7905L21.1041 13.8557Z' fill='%23FFE600'/%3e %3cpath d='M12.1614 18.1199L13.1071 17.8686L13.0338 17.3909L12.0793 17.5963L12.1614 18.1199Z' fill='%2349FFAD'/%3e %3cpath d='M18.8201 14.2823L20.1526 14.0292L20.3462 13.8887L19.0152 14.1398L18.8201 14.2823Z' fill='%23F4F802'/%3e %3cpath d='M11.6929 7.67969L11.7672 8.30211L12.3956 8.21513L12.3223 7.59094L11.6929 7.67969Z' fill='%238D0000'/%3e %3cpath d='M15.0784 22.347L14.8421 22.2014L14.4504 22.5483L14.6595 22.717L15.0784 22.347Z' fill='%230040FF'/%3e %3cpath d='M11.0269 19.1545L11.5596 18.9061L11.4172 18.3496L10.8699 18.5448L11.0269 19.1545Z' fill='%231FFFD7'/%3e %3cpath d='M10.6697 19.3563L11.0267 19.1546L10.8696 18.5449L10.4976 18.6913L10.6697 19.3563Z' fill='%2316FFE1'/%3e %3cpath d='M21.7132 14.3856L22.9645 14.0249L22.7664 13.8027L21.5247 14.1573L21.7132 14.3856Z' fill='%23F1FC06'/%3e %3cpath d='M15.5115 15.7358L16.8888 15.5532L16.9798 15.2198L15.6059 15.3819L15.5115 15.7358Z' fill='%23B4FF43'/%3e %3cpath d='M21.3198 13.9791L22.5509 13.6318L22.3234 13.5168L21.104 13.8558L21.3198 13.9791Z' fill='%23FFE600'/%3e %3cpath d='M16.2273 21.0685L16.0194 21.2211L15.6919 21.8566L15.883 21.7355L16.2273 21.0685Z' fill='%23007CFF'/%3e %3cpath d='M21.5249 14.1571L22.7667 13.8026L22.5511 13.6317L21.3201 13.9789L21.5249 14.1571Z' fill='%23FEED00'/%3e %3cpath d='M17.1563 18.9006L18.225 18.5326L18.0758 18.8195L16.9971 19.2097L17.1563 18.9006Z' fill='%231CFFDB'/%3e %3cpath d='M15.692 21.8564L15.4469 21.8561L15.0784 22.3468L15.3011 22.3758L15.692 21.8564Z' fill='%230054FF'/%3e %3cpath d='M10.6313 9.00358L10.7594 9.66628L11.2963 9.23776L11.1738 8.56799L10.6313 9.00358Z' fill='%23D60000'/%3e %3cpath d='M14.5085 21.0471L14.9762 20.5756L14.6959 20.7261L14.2014 21.2117L14.5085 21.0471Z' fill='%230098FF'/%3e %3cpath d='M17.104 14.9221L18.4958 14.7229L18.6457 14.4784L17.258 14.6678L17.104 14.9221Z' fill='%23D7FF1F'/%3e %3cpath d='M9.73853 12.4377L9.88492 13.0463L10.182 12.2551L10.0439 11.6204L9.73853 12.4377Z' fill='%23FF9C00'/%3e %3cpath d='M10.1302 18.777L10.2655 18.7733L10.1438 18.0278L9.99878 17.9742L10.1302 18.777Z' fill='%2330FFC7'/%3e %3cpath d='M20.8757 15.7584L22.1775 15.4813L22.2399 15.8446L20.9406 16.1273L20.8757 15.7584Z' fill='%23AAFF4D'/%3e %3cpath d='M14.2779 22.276L14.1966 21.92L13.8298 22.1151L13.8799 22.4868L14.2779 22.276Z' fill='%230050FF'/%3e %3cpath d='M16.1136 19.6209L16.9971 19.2096L16.8069 19.4637L15.9077 19.8974L16.1136 19.6209Z' fill='%2300E4F8'/%3e %3cpath d='M15.2321 20.3465L15.908 19.8975L15.6737 20.1072L14.9763 20.5758L15.2321 20.3465Z' fill='%2300C0FF'/%3e %3cpath d='M19.0154 14.1394L20.3464 13.8883L20.5548 13.8046L19.2258 14.0546L19.0154 14.1394Z' fill='%23FEED00'/%3e %3cpath d='M14.165 16.2934L15.4541 16.1182L15.5111 15.7358L14.2243 15.8808L14.165 16.2934Z' fill='%23A0FF56'/%3e %3cpath d='M18.4226 17.8357L19.6303 17.5282L19.5524 17.8731L18.3418 18.2019L18.4226 17.8357Z' fill='%2350FFA7'/%3e %3cpath d='M14.2588 21.5028L14.5085 21.0474L14.2014 21.2119L13.9226 21.6823L14.2588 21.5028Z' fill='%230080FF'/%3e %3cpath d='M11.4169 18.3497L12.1615 18.1202L12.0795 17.5966L11.3254 17.7748L11.4169 18.3497Z' fill='%2346FFB1'/%3e %3cpath d='M16.9785 16.0781L16.992 16.6314L16.9891 17.6727L16.9756 17.1426L16.9785 16.0781Z' fill='%2383FF73'/%3e %3cpath d='M19.6773 16.7745L20.9699 16.5016L20.9633 16.8711L19.6724 17.1588L19.6773 16.7745Z' fill='%237DFF7A'/%3e %3cpath d='M14.1968 21.9201L14.2588 21.5027L13.9227 21.6822L13.8301 22.1151L14.1968 21.9201Z' fill='%230068FF'/%3e %3cpath d='M9.90656 17.8332L9.99874 17.9742L9.94157 17.1647L9.84521 16.9683L9.90656 17.8332Z' fill='%235DFF9A'/%3e %3cpath d='M15.854 10.6635L15.9202 11.2819L16.3124 12.2576L16.2472 11.6425L15.854 10.6635Z' fill='%23FF6000'/%3e %3cpath d='M9.67603 13.9266L9.79905 14.4555L10.0005 13.6107L9.88494 13.0464L9.67603 13.9266Z' fill='%23FFE200'/%3e %3cpath d='M13.0051 16.9103L14.1476 16.7256L14.1651 16.2932L13.0222 16.4388L13.0051 16.9103Z' fill='%2387FF70'/%3e %3cpath d='M12.0793 17.5965L13.0338 17.3911L13.0052 16.9104L12.0461 17.0695L12.0793 17.5965Z' fill='%236AFF8D'/%3e %3cpath d='M20.7769 15.4045L22.0815 15.1328L22.1774 15.4813L20.8756 15.7585L20.7769 15.4045Z' fill='%23BEFF39'/%3e %3cpath d='M10.2655 18.7735L10.4976 18.6913L10.386 18.0039L10.1438 18.0279L10.2655 18.7735Z' fill='%2336FFC1'/%3e %3cpath d='M15.606 15.382L16.9799 15.22L17.1039 14.9222L15.7356 15.0657L15.606 15.382Z' fill='%23CAFF2C'/%3e %3cpath d='M17.2576 14.6679L18.6453 14.4785L18.82 14.2823L17.4376 14.4639L17.2576 14.6679Z' fill='%23E7FF0F'/%3e %3cpath d='M9.7627 16.6831L9.84529 16.9685L9.86542 16.1177L9.78372 15.7815L9.7627 16.6831Z' fill='%2390FF66'/%3e %3cpath d='M9.68677 15.3632L9.78384 15.7814L9.89145 14.9175L9.79928 14.4553L9.68677 15.3632Z' fill='%23CAFF2C'/%3e %3cpath d='M10.8698 18.5449L11.4172 18.3497L11.3257 17.7749L10.7683 17.915L10.8698 18.5449Z' fill='%2340FFB7'/%3e %3cpath d='M19.2258 14.055L20.5548 13.8049L20.7726 13.7804L19.446 14.0303L19.2258 14.055Z' fill='%23FFE600'/%3e %3cpath d='M14.8421 22.2015L14.6416 21.9534L14.2783 22.2762L14.4504 22.5484L14.8421 22.2015Z' fill='%230054FF'/%3e %3cpath d='M17.2807 18.5441L18.3421 18.2019L18.2255 18.5326L17.1567 18.9006L17.2807 18.5441Z' fill='%2333FFC4'/%3e %3cpath d='M10.4976 18.6915L10.8697 18.5451L10.7682 17.9152L10.386 18.0041L10.4976 18.6915Z' fill='%233CFFBA'/%3e %3cpath d='M14.7886 20.7961L15.232 20.3462L14.9762 20.5755L14.5085 21.047L14.7886 20.7961Z' fill='%2300ACFF'/%3e %3cpath d='M12.3223 7.59119L12.3956 8.21538L13.0417 8.31086L12.9696 7.68573L12.3223 7.59119Z' fill='maroon'/%3e %3cpath d='M16.614 13.3036L16.6773 13.9224L16.8788 14.995L16.8179 14.39L16.614 13.3036Z' fill='%23FFEA00'/%3e %3cpath d='M20.6467 15.0751L21.9544 14.8085L22.0813 15.1329L20.7767 15.4047L20.6467 15.0751Z' fill='%23D1FF26'/%3e %3cpath d='M19.645 16.3852L20.9405 16.1273L20.97 16.5014L19.6774 16.7743L19.645 16.3852Z' fill='%2394FF63'/%3e %3cpath d='M16.2858 19.2842L17.1564 18.9004L16.9972 19.2095L16.1138 19.6208L16.2858 19.2842Z' fill='%2316FFE1'/%3e %3cpath d='M15.4566 20.0437L16.1137 19.6207L15.9078 19.8973L15.2319 20.3463L15.4566 20.0437Z' fill='%2300D8FF'/%3e %3cpath d='M18.4654 17.4435L19.6724 17.1588L19.6303 17.5282L18.4226 17.8357L18.4654 17.4435Z' fill='%2366FF90'/%3e %3cpath d='M19.446 14.03L20.7726 13.7802L20.994 13.8156L19.6702 14.0662L19.446 14.03Z' fill='%23FFE200'/%3e %3cpath d='M14.2246 15.8807L15.5114 15.7357L15.6058 15.3817L14.3243 15.4986L14.2246 15.8807Z' fill='%23B7FF40'/%3e %3cpath d='M16.9894 17.6725L16.927 18.1332L16.8276 19.0983L16.8868 18.6681L16.9894 17.6725Z' fill='%2343FFB4'/%3e %3cpath d='M10.2869 10.2492L10.4331 10.9173L10.8969 10.3485L10.7596 9.66626L10.2869 10.2492Z' fill='%23FF2500'/%3e %3cpath d='M11.3254 17.7749L12.0795 17.5966L12.0463 17.0696L11.2874 17.1961L11.3254 17.7749Z' fill='%2366FF90'/%3e %3cpath d='M14.5657 21.2284L14.7888 20.7963L14.5087 21.0472L14.259 21.5027L14.5657 21.2284Z' fill='%230098FF'/%3e %3cpath d='M15.4466 21.8561L15.1862 21.7413L14.8418 22.2012L15.0781 22.3468L15.4466 21.8561Z' fill='%230068FF'/%3e %3cpath d='M20.4888 14.7785L21.7997 14.5165L21.9543 14.8082L20.6467 15.0749L20.4888 14.7785Z' fill='%23E1FF16'/%3e %3cpath d='M17.4377 14.4636L18.8201 14.282L19.0153 14.1395L17.6392 14.3154L17.4377 14.4636Z' fill='%23F8F500'/%3e %3cpath d='M14.6416 21.9533L14.5316 21.6217L14.197 21.9201L14.2783 22.2761L14.6416 21.9533Z' fill='%23006CFF'/%3e %3cpath d='M15.3804 9.78271L15.4476 10.4039L15.92 11.282L15.8538 10.6636L15.3804 9.78271Z' fill='%23FF2900'/%3e %3cpath d='M9.99882 17.9744L10.1438 18.028L10.0911 17.2764L9.94165 17.1649L9.99882 17.9744Z' fill='%2360FF97'/%3e %3cpath d='M19.6699 14.0665L20.9937 13.8159L21.2129 13.9105L19.8921 14.1627L19.6699 14.0665Z' fill='%23FFE600'/%3e %3cpath d='M15.7356 15.0657L17.1039 14.9222L17.2579 14.6678L15.8972 14.7955L15.7356 15.0657Z' fill='%23DEFF19'/%3e %3cpath d='M13.0225 16.4391L14.1654 16.2934L14.2247 15.8809L13.0849 15.989L13.0225 16.4391Z' fill='%23A4FF53'/%3e %3cpath d='M14.5316 21.6218L14.5656 21.2286L14.259 21.5029L14.197 21.9202L14.5316 21.6218Z' fill='%230080FF'/%3e %3cpath d='M12.0461 17.0695L13.0052 16.9104L13.0222 16.439L12.0628 16.5524L12.0461 17.0695Z' fill='%2387FF70'/%3e %3cpath d='M20.3074 14.5234L21.6216 14.2654L21.8 14.5166L20.4891 14.7786L20.3074 14.5234Z' fill='%23EEFF09'/%3e %3cpath d='M19.8923 14.1625L21.2131 13.9103L21.4242 14.0615L20.1066 14.3163L19.8923 14.1625Z' fill='%23FFEA00'/%3e %3cpath d='M11.1741 8.56783L11.2966 9.23759L11.8838 8.97681L11.7674 8.30212L11.1741 8.56783Z' fill='%23AD0000'/%3e %3cpath d='M20.1064 14.3163L21.424 14.0615L21.6213 14.2655L20.3071 14.5235L20.1064 14.3163Z' fill='%23FBF100'/%3e %3cpath d='M16.8277 19.0983L16.6802 19.4339L16.4956 20.2949L16.6353 19.9944L16.8277 19.0983Z' fill='%230CF4EB'/%3e %3cpath d='M19.5757 16.0014L20.8754 15.7585L20.9403 16.1274L19.6448 16.3853L19.5757 16.0014Z' fill='%23AAFF4D'/%3e %3cpath d='M17.3661 18.1492L18.4229 17.8357L18.3421 18.2018L17.2808 18.544L17.3661 18.1492Z' fill='%234DFFAA'/%3e %3cpath d='M16.0193 21.2211L15.7553 21.256L15.4468 21.8562L15.6918 21.8566L16.0193 21.2211Z' fill='%230088FF'/%3e %3cpath d='M12.97 7.68555L13.0421 8.31068L13.6882 8.58698L13.6173 7.96164L12.97 7.68555Z' fill='maroon'/%3e %3cpath d='M10.7681 17.9149L11.3255 17.7748L11.2874 17.196L10.7251 17.2805L10.7681 17.9149Z' fill='%2366FF90'/%3e %3cpath d='M16.4955 20.2949L16.2743 20.4843L16.0193 21.2209L16.2272 21.0683L16.4955 20.2949Z' fill='%2300B8FF'/%3e %3cpath d='M15.0344 20.4647L15.4565 20.0438L15.232 20.3464L14.7886 20.7962L15.0344 20.4647Z' fill='%2300C8FF'/%3e %3cpath d='M18.469 17.0354L19.6776 16.7745L19.6726 17.1588L18.4656 17.4435L18.469 17.0354Z' fill='%237DFF7A'/%3e %3cpath d='M10.1438 18.0277L10.3859 18.0037L10.338 17.3111L10.0911 17.2762L10.1438 18.0277Z' fill='%2360FF97'/%3e %3cpath d='M17.6392 14.3155L19.0152 14.1396L19.2257 14.0548L17.8568 14.2274L17.6392 14.3155Z' fill='%23FFEA00'/%3e %3cpath d='M14.8396 9.02527L14.908 9.6486L15.4477 10.4041L15.3805 9.78289L14.8396 9.02527Z' fill='%23DF0000'/%3e %3cpath d='M10.3858 18.0039L10.7681 17.915L10.725 17.2805L10.3379 17.3113L10.3858 18.0039Z' fill='%2363FF94'/%3e %3cpath d='M9.84497 16.9685L9.94132 17.165L9.96047 16.3692L9.8651 16.1178L9.84497 16.9685Z' fill='%2390FF66'/%3e %3cpath d='M16.4198 18.896L17.2807 18.5441L17.1567 18.9005L16.2861 19.2844L16.4198 18.896Z' fill='%232CFFCA'/%3e %3cpath d='M14.3245 15.4988L15.606 15.382L15.7356 15.0657L14.4622 15.1574L14.3245 15.4988Z' fill='%23D1FF26'/%3e %3cpath d='M10.0442 11.6205L10.1824 12.2552L10.5609 11.5749L10.4335 10.9174L10.0442 11.6205Z' fill='%23FF6000'/%3e %3cpath d='M15.644 19.6755L16.2858 19.2844L16.1137 19.621L15.4565 20.044L15.644 19.6755Z' fill='%230CF4EB'/%3e %3cpath d='M13.6172 7.96155L13.6881 8.58689L14.3159 9.03691L14.2463 8.41219L13.6172 7.96155Z' fill='%23920000'/%3e %3cpath d='M15.8972 14.7953L17.2579 14.6676L17.438 14.4636L16.0866 14.5786L15.8972 14.7953Z' fill='%23EEFF09'/%3e %3cpath d='M19.4719 15.6329L20.7771 15.4044L20.8758 15.7583L19.576 16.0012L19.4719 15.6329Z' fill='%23C1FF36'/%3e %3cpath d='M15.1862 21.7411L14.9605 21.5253L14.6414 21.953L14.8418 22.2011L15.1862 21.7411Z' fill='%23007CFF'/%3e %3cpath d='M14.2461 8.41235L14.3157 9.03708L14.9078 9.64847L14.8394 9.02514L14.2461 8.41235Z' fill='%23B20000'/%3e %3cpath d='M16.8787 14.9948L16.8942 15.5716L16.9922 16.6312L16.9787 16.0779L16.8787 14.9948Z' fill='%23C1FF36'/%3e %3cpath d='M11.2874 17.1962L12.0463 17.0697L12.063 16.5526L11.304 16.6282L11.2874 17.1962Z' fill='%238AFF6D'/%3e %3cpath d='M17.8569 14.2273L19.2258 14.0548L19.446 14.03L18.0851 14.2017L17.8569 14.2273Z' fill='%23FFE200'/%3e %3cpath d='M13.0847 15.989L14.2245 15.8808L14.3242 15.4988L13.1913 15.5722L13.0847 15.989Z' fill='%23BEFF39'/%3e %3cpath d='M14.8348 20.8658L15.0347 20.4647L14.7888 20.7962L14.5657 21.2284L14.8348 20.8658Z' fill='%2300B4FF'/%3e %3cpath d='M16.3123 12.2574L16.3791 12.8895L16.6774 13.922L16.6141 13.3031L16.3123 12.2574Z' fill='%23FFA300'/%3e %3cpath d='M9.78345 15.7815L9.86515 16.1177L9.96707 15.303L9.89105 14.9176L9.78345 15.7815Z' fill='%23C7FF30'/%3e %3cpath d='M12.063 16.5522L13.0223 16.4388L13.0848 15.9888L12.1296 16.0585L12.063 16.5522Z' fill='%23A7FF50'/%3e %3cpath d='M9.88477 13.0462L10.0004 13.6105L10.2866 12.8516L10.1819 12.255L9.88477 13.0462Z' fill='%23FFA300'/%3e %3cpath d='M17.4103 17.7262L18.4655 17.4436L18.4227 17.8358L17.366 18.1493L17.4103 17.7262Z' fill='%2363FF94'/%3e %3cpath d='M18.4324 16.6219L19.6447 16.3853L19.6772 16.7744L18.4686 17.0353L18.4324 16.6219Z' fill='%2397FF60'/%3e %3cpath d='M9.79907 14.4553L9.89125 14.9174L10.0836 14.114L10.0006 13.6105L9.79907 14.4553Z' fill='%23FFEA00'/%3e %3cpath d='M19.3352 15.2901L20.6468 15.0751L20.7768 15.4046L19.4716 15.6331L19.3352 15.2901Z' fill='%23D4FF23'/%3e %3cpath d='M14.9606 21.5255L14.8253 21.2267L14.5315 21.6216L14.6415 21.9532L14.9606 21.5255Z' fill='%230090FF'/%3e %3cpath d='M14.8253 21.2268L14.8346 20.866L14.5655 21.2286L14.5315 21.6217L14.8253 21.2268Z' fill='%2300A0FF'/%3e %3cpath d='M18.0852 14.2018L19.4461 14.0302L19.6703 14.0663L18.3177 14.2396L18.0852 14.2018Z' fill='%23FFDE00'/%3e %3cpath d='M9.94141 17.1646L10.0909 17.2761L10.1091 16.5377L9.96055 16.3688L9.94141 17.1646Z' fill='%238DFF6A'/%3e %3cpath d='M14.4622 15.1572L15.7356 15.0655L15.8971 14.7953L14.6345 14.8655L14.4622 15.1572Z' fill='%23E4FF13'/%3e %3cpath d='M16.0867 14.5787L17.4381 14.4638L17.6395 14.3157L16.2991 14.4214L16.0867 14.5787Z' fill='%23FEED00'/%3e %3cpath d='M10.7249 17.2803L11.2872 17.1959L11.3039 16.6279L10.7418 16.6575L10.7249 17.2803Z' fill='%238AFF6D'/%3e %3cpath d='M15.2395 20.0606L15.644 19.6753L15.4566 20.0438L15.0344 20.4647L15.2395 20.0606Z' fill='%2302E8F4'/%3e %3cpath d='M15.755 21.256L15.474 21.1792L15.186 21.7415L15.4465 21.8562L15.755 21.256Z' fill='%230098FF'/%3e %3cpath d='M16.511 18.4657L17.3658 18.1493L17.2804 18.5441L16.4194 18.8961L16.511 18.4657Z' fill='%2346FFB1'/%3e %3cpath d='M19.1699 14.9816L20.4888 14.7787L20.6467 15.075L19.3352 15.2901L19.1699 14.9816Z' fill='%23E4FF13'/%3e %3cpath d='M11.7673 8.30208L11.8838 8.97677L12.5055 8.8924L12.3957 8.21509L11.7673 8.30208Z' fill='%23920000'/%3e %3cpath d='M10.7598 9.66628L10.8971 10.3486L11.4238 9.93094L11.2967 9.23779L10.7598 9.66628Z' fill='%23DF0000'/%3e %3cpath d='M18.3176 14.2396L19.6702 14.0663L19.8924 14.1625L18.5485 14.3399L18.3176 14.2396Z' fill='%23FFDE00'/%3e %3cpath d='M15.7896 19.2497L16.4197 18.8958L16.286 19.2841L15.6443 19.6751L15.7896 19.2497Z' fill='%2326FFD1'/%3e %3cpath d='M16.9923 16.6315L16.9296 17.1242L16.927 18.1334L16.9894 17.6727L16.9923 16.6315Z' fill='%2383FF73'/%3e %3cpath d='M18.9805 14.7158L20.3073 14.5234L20.489 14.7787L19.1702 14.9815L18.9805 14.7158Z' fill='%23F1FC06'/%3e %3cpath d='M18.5486 14.3401L19.8925 14.1627L20.1068 14.3165L18.7715 14.5003L18.5486 14.3401Z' fill='%23FFE600'/%3e %3cpath d='M10.0911 17.2763L10.338 17.3111L10.3554 16.6309L10.1093 16.5378L10.0911 17.2763Z' fill='%238DFF6A'/%3e %3cpath d='M10.3381 17.3111L10.7253 17.2803L10.7422 16.6574L10.3556 16.6309L10.3381 17.3111Z' fill='%238DFF6A'/%3e %3cpath d='M18.3574 16.2139L19.5757 16.0013L19.6448 16.3852L18.4324 16.6218L18.3574 16.2139Z' fill='%23ADFF49'/%3e %3cpath d='M18.7712 14.5001L20.1065 14.3163L20.3071 14.5235L18.9803 14.7159L18.7712 14.5001Z' fill='%23FEED00'/%3e %3cpath d='M13.1914 15.5723L14.3243 15.4989L14.462 15.1575L13.3396 15.1997L13.1914 15.5723Z' fill='%23D7FF1F'/%3e %3cpath d='M17.4124 17.2858L18.469 17.0355L18.4656 17.4437L17.4104 17.7262L17.4124 17.2858Z' fill='%237DFF7A'/%3e %3cpath d='M11.3042 16.6282L12.0631 16.5526L12.1297 16.0588L11.3756 16.0856L11.3042 16.6282Z' fill='%23AAFF4D'/%3e %3cpath d='M16.2744 20.4844L15.9952 20.5604L15.7554 21.2559L16.0194 21.221L16.2744 20.4844Z' fill='%2300C4FF'/%3e %3cpath d='M16.2991 14.4214L17.6395 14.3157L17.8571 14.2275L16.529 14.3278L16.2991 14.4214Z' fill='%23FFE200'/%3e %3cpath d='M12.1294 16.0588L13.0847 15.9891L13.1912 15.5723L12.2444 15.6013L12.1294 16.0588Z' fill='%23C4FF33'/%3e %3cpath d='M15.059 20.4237L15.2395 20.0608L15.0344 20.4649L14.8345 20.866L15.059 20.4237Z' fill='%2300D8FF'/%3e %3cpath d='M16.9271 18.1332L16.7752 18.5068L16.6802 19.4339L16.8277 19.0983L16.9271 18.1332Z' fill='%2346FFB1'/%3e %3cpath d='M9.86523 16.1179L9.9606 16.3692L10.0563 15.6076L9.96715 15.3032L9.86523 16.1179Z' fill='%23C1FF36'/%3e %3cpath d='M15.9202 11.2821L15.9914 11.9263L16.3792 12.8899L16.3124 12.2578L15.9202 11.2821Z' fill='%23FF6400'/%3e %3cpath d='M14.6345 14.8655L15.8971 14.7954L16.0866 14.5786L14.8372 14.6315L14.6345 14.8655Z' fill='%23F8F500'/%3e %3cpath d='M15.4743 21.1792L15.2273 21.0031L14.9607 21.5256L15.1864 21.7415L15.4743 21.1792Z' fill='%2300A8FF'/%3e %3cpath d='M16.68 19.4338L16.4493 19.6644L16.2742 20.4842L16.4954 20.2948L16.68 19.4338Z' fill='%230FF8E7'/%3e %3cpath d='M18.2454 15.8225L19.4716 15.6331L19.5757 16.0014L18.3574 16.214L18.2454 15.8225Z' fill='%23C4FF33'/%3e %3cpath d='M16.558 18.0043L17.4104 17.7261L17.366 18.1492L16.5112 18.4656L16.558 18.0043Z' fill='%2363FF94'/%3e %3cpath d='M16.6772 13.9221L16.6969 14.5224L16.8943 15.5716L16.8787 14.9947L16.6772 13.9221Z' fill='%23FFEA00'/%3e %3cpath d='M10.4333 10.9174L10.5608 11.575L11.0116 11.0252L10.8972 10.3486L10.4333 10.9174Z' fill='%23FF3000'/%3e %3cpath d='M15.0707 20.7444L15.0593 20.4235L14.8347 20.8658L14.8254 21.2266L15.0707 20.7444Z' fill='%2300C8FF'/%3e %3cpath d='M16.5288 14.3277L17.8569 14.2275L18.0851 14.2019L16.7701 14.3006L16.5288 14.3277Z' fill='%23FFDB00'/%3e %3cpath d='M15.2273 21.0029L15.0707 20.7444L14.8254 21.2266L14.9608 21.5254L15.2273 21.0029Z' fill='%2300B8FF'/%3e %3cpath d='M15.3983 19.5938L15.7893 19.2499L15.644 19.6753L15.2395 20.0606L15.3983 19.5938Z' fill='%231CFFDB'/%3e %3cpath d='M10.7422 16.6576L11.3043 16.6281L11.3757 16.0856L10.8191 16.0624L10.7422 16.6576Z' fill='%23ADFF49'/%3e %3cpath d='M12.3958 8.21509L12.5056 8.8924L13.1449 8.98808L13.0419 8.31057L12.3958 8.21509Z' fill='%23840000'/%3e %3cpath d='M17.3713 16.8393L18.4325 16.6219L18.4687 17.0354L17.4121 17.2856L17.3713 16.8393Z' fill='%2397FF60'/%3e %3cpath d='M15.8885 18.7779L16.5109 18.4653L16.4194 18.8957L15.7893 19.2496L15.8885 18.7779Z' fill='%2343FFB4'/%3e %3cpath d='M9.89136 14.9177L9.96737 15.3031L10.1493 14.5459L10.0837 14.1143L9.89136 14.9177Z' fill='%23FBF100'/%3e %3cpath d='M18.0994 15.4579L19.3352 15.29L19.4717 15.633L18.2455 15.8225L18.0994 15.4579Z' fill='%23D7FF1F'/%3e %3cpath d='M13.3394 15.1995L14.4618 15.1573L14.6341 14.8656L13.5255 14.881L13.3394 15.1995Z' fill='%23EEFF09'/%3e %3cpath d='M9.96069 16.3689L10.1092 16.5378L10.1985 15.8314L10.0564 15.6072L9.96069 16.3689Z' fill='%23BEFF39'/%3e %3cpath d='M14.8372 14.6312L16.0865 14.5784L16.299 14.421L15.0649 14.4613L14.8372 14.6312Z' fill='%23FFE600'/%3e %3cpath d='M16.7703 14.3007L18.0852 14.202L18.3177 14.2398L17.0167 14.341L16.7703 14.3007Z' fill='gold'/%3e %3cpath d='M10.1821 12.2551L10.2869 12.8517L10.6514 12.1996L10.5607 11.5748L10.1821 12.2551Z' fill='%23FF6C00'/%3e %3cpath d='M11.3755 16.0854L12.1296 16.0586L12.2446 15.6011L11.5001 15.5824L11.3755 16.0854Z' fill='%23CAFF2C'/%3e %3cpath d='M10.3555 16.631L10.7421 16.6575L10.819 16.0622L10.4384 15.9806L10.3555 16.631Z' fill='%23B4FF43'/%3e %3cpath d='M10.0005 13.6109L10.0836 14.1144L10.3567 13.3931L10.2868 12.8519L10.0005 13.6109Z' fill='%23FFAE00'/%3e %3cpath d='M12.2446 15.601L13.1915 15.572L13.3397 15.1993L12.4053 15.1919L12.2446 15.601Z' fill='%23DEFF19'/%3e %3cpath d='M15.4475 10.4039L15.5241 11.0588L15.9911 11.9262L15.9199 11.282L15.4475 10.4039Z' fill='%23FF2D00'/%3e %3cpath d='M17.9231 15.1301L19.1702 14.9818L19.3355 15.2903L18.0996 15.4581L17.9231 15.1301Z' fill='%23EBFF0C'/%3e %3cpath d='M15.9952 20.5602L15.6979 20.5278L15.4744 21.179L15.7554 21.2557L15.9952 20.5602Z' fill='%2300CCFF'/%3e %3cpath d='M11.2969 9.2377L11.424 9.93085L11.9998 9.67733L11.8841 8.97693L11.2969 9.2377Z' fill='%23BB0000'/%3e %3cpath d='M10.1094 16.5379L10.3555 16.631L10.4384 15.9806L10.1986 15.8315L10.1094 16.5379Z' fill='%23B7FF40'/%3e %3cpath d='M17.0166 14.3408L18.3177 14.2396L18.5485 14.3399L17.2615 14.4475L17.0166 14.3408Z' fill='gold'/%3e %3cpath d='M16.5584 17.5236L17.4121 17.2854L17.4102 17.7259L16.5579 18.0041L16.5584 17.5236Z' fill='%237DFF7A'/%3e %3cpath d='M17.2888 16.3988L18.3575 16.214L18.4326 16.6219L17.3714 16.8392L17.2888 16.3988Z' fill='%23B1FF46'/%3e %3cpath d='M15.2329 19.9121L15.3984 19.5938L15.2395 20.0606L15.0591 20.4235L15.2329 19.9121Z' fill='%2316FFE1'/%3e %3cpath d='M17.7207 14.8476L18.9803 14.7161L19.17 14.9818L17.9228 15.1301L17.7207 14.8476Z' fill='%23F8F500'/%3e %3cpath d='M17.2612 14.4476L18.5482 14.34L18.7711 14.5001L17.4981 14.6179L17.2612 14.4476Z' fill='%23FFDB00'/%3e %3cpath d='M13.0417 8.31067L13.1447 8.98818L13.7838 9.26225L13.6878 8.58699L13.0417 8.31067Z' fill='%23890000'/%3e %3cpath d='M17.4985 14.6178L18.7716 14.5L18.9806 14.7158L17.721 14.8473L17.4985 14.6178Z' fill='%23FFE600'/%3e %3cpath d='M16.8943 15.5719L16.8342 16.0972L16.9296 17.1241L16.9923 16.6314L16.8943 15.5719Z' fill='%23C1FF36'/%3e %3cpath d='M15.0647 14.4615L16.2988 14.4212L16.5287 14.3276L15.3116 14.3604L15.0647 14.4615Z' fill='gold'/%3e %3cpath d='M13.5259 14.8811L14.6345 14.8656L14.8372 14.6316L13.7453 14.6255L13.5259 14.8811Z' fill='%23FFEA00'/%3e %3cpath d='M15.9385 18.2722L16.5577 18.0043L16.5109 18.4657L15.8884 18.7782L15.9385 18.2722Z' fill='%2360FF97'/%3e %3cpath d='M15.5065 19.0757L15.8886 18.778L15.7895 19.2497L15.3984 19.5936L15.5065 19.0757Z' fill='%233CFFBA'/%3e %3cpath d='M14.9082 9.64832L14.9908 10.3121L15.5244 11.0587L15.4479 10.4038L14.9082 9.64832Z' fill='%23E40000'/%3e %3cpath d='M15.6976 20.5279L15.4337 20.3981L15.2271 21.0029L15.4741 21.179L15.6976 20.5279Z' fill='%2300D8FF'/%3e %3cpath d='M16.4497 19.6643L16.1597 19.7864L15.9954 20.5602L16.2746 20.4841L16.4497 19.6643Z' fill='%2316FFE1'/%3e %3cpath d='M15.2604 20.1865L15.2329 19.912L15.0591 20.4233L15.0705 20.7443L15.2604 20.1865Z' fill='%230CF4EB'/%3e %3cpath d='M10.8188 16.0623L11.3754 16.0855L11.5001 15.5825L10.9542 15.5103L10.8188 16.0623Z' fill='%23D1FF26'/%3e %3cpath d='M13.6877 8.58716L13.7837 9.26242L14.4047 9.70781L14.3156 9.03718L13.6877 8.58716Z' fill='%239B0000'/%3e %3cpath d='M9.96729 15.3027L10.0564 15.6071L10.227 14.8996L10.1492 14.5455L9.96729 15.3027Z' fill='%23F4F802'/%3e %3cpath d='M17.1665 15.9759L18.2455 15.8225L18.3575 16.214L17.2888 16.3987L17.1665 15.9759Z' fill='%23C7FF30'/%3e %3cpath d='M16.3792 12.8896L16.4048 13.5122L16.6971 14.5224L16.6775 13.9221L16.3792 12.8896Z' fill='%23FFA700'/%3e %3cpath d='M14.3159 9.03711L14.405 9.70773L14.9906 10.3122L14.908 9.64846L14.3159 9.03711Z' fill='%23BB0000'/%3e %3cpath d='M15.4339 20.3982L15.2605 20.1868L15.0706 20.7445L15.2272 21.003L15.4339 20.3982Z' fill='%2302E8F4'/%3e %3cpath d='M16.9296 17.124L16.7771 17.5376L16.7751 18.5069L16.927 18.1333L16.9296 17.124Z' fill='%2380FF77'/%3e %3cpath d='M12.4053 15.1921L13.3397 15.1995L13.5258 14.881L12.6078 14.8423L12.4053 15.1921Z' fill='%23F8F500'/%3e %3cpath d='M16.5122 17.0367L17.3711 16.8392L17.4118 17.2856L16.5581 17.5237L16.5122 17.0367Z' fill='%239AFF5D'/%3e %3cpath d='M16.7755 18.5068L16.5394 18.782L16.4497 19.6645L16.6804 19.4339L16.7755 18.5068Z' fill='%2349FFAD'/%3e %3cpath d='M15.3118 14.3606L16.5288 14.3278L16.7702 14.3007L15.5714 14.3313L15.3118 14.3606Z' fill='%23FFD000'/%3e %3cpath d='M11.5002 15.5826L12.2447 15.6013L12.4054 15.1921L11.6753 15.1326L11.5002 15.5826Z' fill='%23E7FF0F'/%3e %3cpath d='M10.8967 10.3485L11.0111 11.0251L11.5229 10.6218L11.4234 9.93091L10.8967 10.3485Z' fill='%23F10800'/%3e %3cpath d='M10.4382 15.9803L10.8188 16.062L10.9542 15.5099L10.585 15.3768L10.4382 15.9803Z' fill='%23DBFF1C'/%3e %3cpath d='M17.0076 15.5821L18.0993 15.458L18.2455 15.8226L17.1665 15.976L17.0076 15.5821Z' fill='%23DEFF19'/%3e %3cpath d='M13.7451 14.6256L14.837 14.6317L15.0648 14.4617L13.9922 14.4399L13.7451 14.6256Z' fill='gold'/%3e %3cpath d='M10.0562 15.6077L10.1983 15.8319L10.3569 15.1761L10.2267 14.9001L10.0562 15.6077Z' fill='%23EBFF0C'/%3e %3cpath d='M11.8838 8.9768L11.9995 9.67721L12.6091 9.59622L12.5055 8.89246L11.8838 8.9768Z' fill='%239F0000'/%3e %3cpath d='M15.3511 19.3444L15.5065 19.0758L15.3984 19.5937L15.2329 19.9121L15.3511 19.3444Z' fill='%2336FFC1'/%3e %3cpath d='M10.084 14.114L10.1495 14.5456L10.4076 13.8662L10.3571 13.3927L10.084 14.114Z' fill='%23FFB900'/%3e %3cpath d='M15.5715 14.331L16.7703 14.3004L17.0167 14.3407L15.8369 14.3745L15.5715 14.331Z' fill='%23FFCC00'/%3e %3cpath d='M15.938 17.7451L16.5584 17.5239L16.5578 18.0044L15.9386 18.2723L15.938 17.7451Z' fill='%2380FF77'/%3e %3cpath d='M10.1987 15.8316L10.4385 15.9806L10.5853 15.3771L10.3574 15.1758L10.1987 15.8316Z' fill='%23E1FF16'/%3e %3cpath d='M16.8164 15.2277L17.9232 15.13L18.0997 15.458L17.0079 15.5821L16.8164 15.2277Z' fill='%23F1FC06'/%3e %3cpath d='M15.5608 18.5199L15.9387 18.272L15.8887 18.778L15.5066 19.0757L15.5608 18.5199Z' fill='%235DFF9A'/%3e %3cpath d='M10.5605 11.575L10.6513 12.1998L11.0851 11.6732L11.0114 11.0251L10.5605 11.575Z' fill='%23FF3B00'/%3e %3cpath d='M16.1596 19.7866L15.8508 19.8039L15.698 20.528L15.9953 20.5604L16.1596 19.7866Z' fill='%231CFFDB'/%3e %3cpath d='M16.4209 16.5559L17.2887 16.3988L17.3712 16.8392L16.5123 17.0366L16.4209 16.5559Z' fill='%23B7FF40'/%3e %3cpath d='M15.8367 14.3744L17.0165 14.3406L17.2614 14.4473L16.1008 14.4898L15.8367 14.3744Z' fill='%23FFCC00'/%3e %3cpath d='M10.2869 12.8515L10.3568 13.3927L10.7043 12.7734L10.6514 12.1995L10.2869 12.8515Z' fill='%23FF7A00'/%3e %3cpath d='M16.5972 14.9221L17.7207 14.8473L17.9229 15.1299L16.8161 15.2275L16.5972 14.9221Z' fill='%23FFEA00'/%3e %3cpath d='M12.6077 14.8421L13.5257 14.8809L13.7451 14.6253L12.8469 14.5613L12.6077 14.8421Z' fill='%23FFDB00'/%3e %3cpath d='M16.1008 14.4898L17.2614 14.4473L17.4982 14.6176L16.3566 14.6739L16.1008 14.4898Z' fill='%23FFD000'/%3e %3cpath d='M10.9543 15.5103L11.5002 15.5826L11.6752 15.1326L11.145 15.0161L10.9543 15.5103Z' fill='%23F4F802'/%3e %3cpath d='M16.3564 14.674L17.4981 14.6177L17.7206 14.8472L16.597 14.9221L16.3564 14.674Z' fill='%23FFDB00'/%3e %3cpath d='M13.9922 14.4397L15.0648 14.4615L15.3117 14.3604L14.2604 14.3292L13.9922 14.4397Z' fill='%23FFC800'/%3e %3cpath d='M15.9915 11.9261L16.025 12.5695L16.4049 13.5124L16.3792 12.8898L15.9915 11.9261Z' fill='%23FF6C00'/%3e %3cpath d='M16.6968 14.5226L16.6423 15.0802L16.8341 16.0971L16.8942 15.5718L16.6968 14.5226Z' fill='%23FBF100'/%3e %3cpath d='M15.3897 19.5671L15.3511 19.3445L15.2329 19.9121L15.2604 20.1867L15.3897 19.5671Z' fill='%2330FFC7'/%3e %3cpath d='M11.6748 15.1326L12.4049 15.1922L12.6075 14.8424L11.8959 14.7477L11.6748 15.1326Z' fill='%23FFE600'/%3e %3cpath d='M15.8507 19.8037L15.575 19.7258L15.4341 20.398L15.698 20.5278L15.8507 19.8037Z' fill='%2323FFD4'/%3e %3cpath d='M15.5746 19.7259L15.3895 19.5671L15.2603 20.1867L15.4337 20.3981L15.5746 19.7259Z' fill='%2329FFCE'/%3e %3cpath d='M16.2864 16.094L17.1666 15.9758L17.2889 16.3987L16.4211 16.5557L16.2864 16.094Z' fill='%23D1FF26'/%3e %3cpath d='M15.8862 17.2102L16.5123 17.0366L16.5582 17.5237L15.9378 17.7449L15.8862 17.2102Z' fill='%239DFF5A'/%3e %3cpath d='M10.1489 14.5455L10.2267 14.8996L10.4683 14.2651L10.407 13.8661L10.1489 14.5455Z' fill='%23FFC400'/%3e %3cpath d='M16.5391 18.7821L16.2431 18.9541L16.1594 19.7867L16.4494 19.6646L16.5391 18.7821Z' fill='%234DFFAA'/%3e %3cpath d='M12.5056 8.89233L12.6091 9.5961L13.2357 9.69114L13.1449 8.98799L12.5056 8.89233Z' fill='%23920000'/%3e %3cpath d='M14.2605 14.3294L15.3117 14.3606L15.5713 14.3313L14.543 14.2974L14.2605 14.3294Z' fill='%23FFC100'/%3e %3cpath d='M10.585 15.3771L10.9541 15.5101L11.1448 15.0159L10.7923 14.8365L10.585 15.3771Z' fill='%23FEED00'/%3e %3cpath d='M15.4102 18.7349L15.5606 18.52L15.5064 19.0759L15.3511 19.3445L15.4102 18.7349Z' fill='%235AFF9D'/%3e %3cpath d='M11.4236 9.93101L11.523 10.6219L12.0823 10.3778L11.9994 9.67749L11.4236 9.93101Z' fill='%23C80000'/%3e %3cpath d='M16.8344 16.0969L16.6851 16.5513L16.7773 17.5374L16.9298 17.1238L16.8344 16.0969Z' fill='%23BEFF39'/%3e %3cpath d='M15.5591 17.9408L15.9379 17.7451L15.9385 18.2723L15.5606 18.5203L15.5591 17.9408Z' fill='%2380FF77'/%3e %3cpath d='M12.8469 14.5616L13.7451 14.6256L13.9921 14.4399L13.1168 14.3575L12.8469 14.5616Z' fill='%23FFC800'/%3e %3cpath d='M16.7773 17.5376L16.5403 17.8596L16.5393 18.7821L16.7754 18.5069L16.7773 17.5376Z' fill='%2380FF77'/%3e %3cpath d='M16.1118 15.6639L17.0076 15.582L17.1666 15.976L16.2864 16.0941L16.1118 15.6639Z' fill='%23E7FF0F'/%3e %3cpath d='M10.2271 14.8999L10.3573 15.1759L10.5819 14.5882L10.4687 14.2655L10.2271 14.8999Z' fill='%23FFD300'/%3e %3cpath d='M15.5242 11.0585L15.5672 11.7203L16.0248 12.5692L15.9912 11.9259L15.5242 11.0585Z' fill='%23FF3400'/%3e %3cpath d='M10.3572 15.1756L10.5851 15.377L10.7925 14.8365L10.5817 14.5879L10.3572 15.1756Z' fill='%23FFDE00'/%3e %3cpath d='M14.543 14.2974L15.5714 14.3313L15.8368 14.3748L14.8321 14.3449L14.543 14.2974Z' fill='%23FFB900'/%3e %3cpath d='M11.145 15.016L11.6752 15.1325L11.8963 14.7476L11.3865 14.5931L11.145 15.016Z' fill='gold'/%3e %3cpath d='M11.896 14.7473L12.6076 14.842L12.8468 14.5611L12.1577 14.4381L11.896 14.7473Z' fill='%23FFCC00'/%3e %3cpath d='M10.3564 13.393L10.4069 13.8665L10.7351 13.2836L10.704 12.7737L10.3564 13.393Z' fill='%23FF8600'/%3e %3cpath d='M15.7852 16.6822L16.4212 16.5558L16.5127 17.0366L15.8866 17.2102L15.7852 16.6822Z' fill='%23BAFF3C'/%3e %3cpath d='M13.1448 8.98828L13.2356 9.69143L13.8619 9.96079L13.7839 9.26236L13.1448 8.98828Z' fill='%23960000'/%3e %3cpath d='M15.9021 15.2765L16.8163 15.2274L17.0078 15.5818L16.1119 15.6637L15.9021 15.2765Z' fill='%23FBF100'/%3e %3cpath d='M15.4546 18.9014L15.4104 18.7349L15.3513 19.3444L15.3899 19.5671L15.4546 18.9014Z' fill='%2356FFA0'/%3e %3cpath d='M16.2434 18.9539L15.9281 19.0249L15.8508 19.8037L16.1597 19.7865L16.2434 18.9539Z' fill='%234DFFAA'/%3e %3cpath d='M11.0112 11.0249L11.085 11.673L11.5773 11.2873L11.5229 10.6217L11.0112 11.0249Z' fill='%23FF1300'/%3e %3cpath d='M14.8323 14.3446L15.8369 14.3745L16.101 14.4898L15.1203 14.4706L14.8323 14.3446Z' fill='%23FFBD00'/%3e %3cpath d='M16.4047 13.5123L16.3586 14.101L16.6425 15.08L16.697 14.5225L16.4047 13.5123Z' fill='%23FFAE00'/%3e %3cpath d='M14.9905 10.3119L15.0443 10.9894L15.5671 11.7203L15.5241 11.0585L14.9905 10.3119Z' fill='%23F10800'/%3e %3cpath d='M13.1167 14.3572L13.992 14.4396L14.2603 14.3292L13.4102 14.2357L13.1167 14.3572Z' fill='%23FFB900'/%3e %3cpath d='M15.6626 14.9432L16.5975 14.9224L16.8164 15.2277L15.9022 15.2768L15.6626 14.9432Z' fill='%23FFDB00'/%3e %3cpath d='M10.6516 12.1997L10.7045 12.7736L11.118 12.2739L11.0855 11.6731L10.6516 12.1997Z' fill='%23FF4A00'/%3e %3cpath d='M15.1201 14.4709L16.1008 14.4902L16.3566 14.6743L15.3994 14.6722L15.1201 14.4709Z' fill='%23FFC100'/%3e %3cpath d='M15.3994 14.6719L16.3567 14.6741L16.5973 14.9221L15.6624 14.9429L15.3994 14.6719Z' fill='%23FFCC00'/%3e %3cpath d='M13.7837 9.26233L13.8618 9.96076L14.4703 10.3975L14.4047 9.70776L13.7837 9.26233Z' fill='%23A40000'/%3e %3cpath d='M15.5017 17.3524L15.8865 17.21L15.9381 17.7446L15.5592 17.9404L15.5017 17.3524Z' fill='%23A0FF56'/%3e %3cpath d='M14.4048 9.70776L14.4704 10.3975L15.0441 10.9897L14.9903 10.3122L14.4048 9.70776Z' fill='%23C40000'/%3e %3cpath d='M15.6456 19.0031L15.4544 18.9012L15.3896 19.5669L15.5747 19.7257L15.6456 19.0031Z' fill='%2353FFA4'/%3e %3cpath d='M15.4082 18.099L15.5592 17.9404L15.5607 18.5199L15.4102 18.7348L15.4082 18.099Z' fill='%2380FF77'/%3e %3cpath d='M15.9277 19.0249L15.6456 19.0032L15.5747 19.7258L15.8504 19.8037L15.9277 19.0249Z' fill='%2350FFA7'/%3e %3cpath d='M15.6362 16.1749L16.2865 16.094L16.4212 16.5557L15.7851 16.6821L15.6362 16.1749Z' fill='%23D7FF1F'/%3e %3cpath d='M10.7927 14.8367L11.1452 15.0161L11.3867 14.5932L11.0558 14.3739L10.7927 14.8367Z' fill='%23FFC800'/%3e %3cpath d='M11.9995 9.67742L12.0824 10.3777L12.6742 10.3008L12.6091 9.59644L11.9995 9.67742Z' fill='%23AD0000'/%3e %3cpath d='M10.407 13.8664L10.4684 14.2654L10.7755 13.7215L10.7351 13.2834L10.407 13.8664Z' fill='%23FF9800'/%3e %3cpath d='M12.1582 14.4386L12.8473 14.5616L13.1172 14.3575L12.4539 14.2137L12.1582 14.4386Z' fill='%23FFB600'/%3e %3cpath d='M16.5402 17.8595L16.2432 18.084L16.2432 18.954L16.5392 18.782L16.5402 17.8595Z' fill='%2380FF77'/%3e %3cpath d='M13.4104 14.2359L14.2605 14.3293L14.543 14.2973L13.7198 14.2006L13.4104 14.2359Z' fill='%23FFAE00'/%3e %3cpath d='M11.3865 14.5932L11.8963 14.7477L12.158 14.4385L11.6728 14.2533L11.3865 14.5932Z' fill='%23FFB900'/%3e %3cpath d='M16.6422 15.0801L16.4998 15.5749L16.6846 16.5514L16.834 16.097L16.6422 15.0801Z' fill='%23F8F500'/%3e %3cpath d='M10.5818 14.5881L10.7925 14.8367L11.0556 14.3739L10.867 14.0846L10.5818 14.5881Z' fill='%23FFB600'/%3e %3cpath d='M10.4685 14.2654L10.5817 14.5881L10.8668 14.0845L10.7756 13.7214L10.4685 14.2654Z' fill='%23FFA700'/%3e %3cpath d='M16.685 16.5514L16.4517 16.9212L16.5403 17.8595L16.7773 17.5375L16.685 16.5514Z' fill='%23BAFF3C'/%3e %3cpath d='M15.4434 15.7023L16.1116 15.6638L16.2862 16.0941L15.6359 16.175L15.4434 15.7023Z' fill='%23F1FC06'/%3e %3cpath d='M15.3892 16.7721L15.7848 16.6824L15.8863 17.2104L15.5015 17.3529L15.3892 16.7721Z' fill='%23C1FF36'/%3e %3cpath d='M15.4523 18.2069L15.4082 18.0992L15.4102 18.735L15.4544 18.9015L15.4523 18.2069Z' fill='%2380FF77'/%3e %3cpath d='M16.0245 12.5697L15.9895 13.1873L16.3584 14.1012L16.4045 13.5125L16.0245 12.5697Z' fill='%23FF7300'/%3e %3cpath d='M13.7197 14.2007L14.5429 14.2974L14.8321 14.3449L14.0367 14.2528L13.7197 14.2007Z' fill='%23FFA700'/%3e %3cpath d='M10.7043 12.7735L10.7355 13.2835L11.1257 12.8135L11.1178 12.2738L10.7043 12.7735Z' fill='%23FF5D00'/%3e %3cpath d='M15.3445 17.4538L15.5014 17.3527L15.559 17.9405L15.408 18.0991L15.3445 17.4538Z' fill='%23A4FF53'/%3e %3cpath d='M11.5232 10.6218L11.5775 11.2874L12.1154 11.0545L12.0824 10.3777L11.5232 10.6218Z' fill='%23DA0000'/%3e %3cpath d='M15.2124 15.277L15.902 15.2769L16.1119 15.664L15.4436 15.7025L15.2124 15.277Z' fill='%23FFE200'/%3e %3cpath d='M12.4536 14.2138L13.1169 14.3576L13.4104 14.236L12.7755 14.0798L12.4536 14.2138Z' fill='%23FFA300'/%3e %3cpath d='M16.2433 18.0839L15.927 18.2115L15.928 19.025L16.2433 18.9539L16.2433 18.0839Z' fill='%2380FF77'/%3e %3cpath d='M12.6089 9.59619L12.6741 10.3005L13.2824 10.394L13.2355 9.69123L12.6089 9.59619Z' fill='%23A40000'/%3e %3cpath d='M14.0369 14.2527L14.8322 14.3448L15.1202 14.4708L14.353 14.3911L14.0369 14.2527Z' fill='%23FFAB00'/%3e %3cpath d='M11.0554 14.3738L11.3863 14.5931L11.6726 14.2532L11.3676 14.0016L11.0554 14.3738Z' fill='%23FFA700'/%3e %3cpath d='M15.644 18.2487L15.4524 18.2067L15.4545 18.9013L15.6457 19.0032L15.644 18.2487Z' fill='%2380FF77'/%3e %3cpath d='M11.0852 11.6729L11.1177 12.2737L11.5867 11.9082L11.5775 11.2872L11.0852 11.6729Z' fill='%23FF2500'/%3e %3cpath d='M14.9487 14.9103L15.6624 14.9432L15.902 15.2768L15.2124 15.277L14.9487 14.9103Z' fill='%23FFCC00'/%3e %3cpath d='M14.353 14.391L15.1203 14.4707L15.3995 14.6719L14.6598 14.6121L14.353 14.391Z' fill='%23FFAE00'/%3e %3cpath d='M15.9269 18.2114L15.644 18.2487L15.6458 19.0032L15.9279 19.0249L15.9269 18.2114Z' fill='%2380FF77'/%3e %3cpath d='M11.6729 14.2531L12.1581 14.4383L12.4538 14.2134L11.9966 14.0057L11.6729 14.2531Z' fill='%23FF9F00'/%3e %3cpath d='M14.6594 14.6121L15.3992 14.6718L15.6622 14.9429L14.9485 14.91L14.6594 14.6121Z' fill='%23FFBD00'/%3e %3cpath d='M15.2249 16.2139L15.6361 16.175L15.785 16.6823L15.3893 16.772L15.2249 16.2139Z' fill='%23E1FF16'/%3e %3cpath d='M15.5673 11.7206L15.5457 12.364L15.9899 13.1871L16.0249 12.5695L15.5673 11.7206Z' fill='%23FF3F00'/%3e %3cpath d='M10.7351 13.2834L10.7754 13.7214L11.1405 13.2832L11.1254 12.8135L10.7351 13.2834Z' fill='%23FF6F00'/%3e %3cpath d='M16.3585 14.101L16.2266 14.6348L16.4999 15.5749L16.6423 15.08L16.3585 14.101Z' fill='%23FFB600'/%3e %3cpath d='M12.7754 14.0796L13.4102 14.2358L13.7196 14.2005L13.1151 14.0405L12.7754 14.0796Z' fill='%23FF9800'/%3e %3cpath d='M10.8669 14.0845L11.0556 14.3738L11.3678 14.0015L11.2057 13.6792L10.8669 14.0845Z' fill='%23FF9400'/%3e %3cpath d='M16.4516 16.9214L16.1587 17.1995L16.2432 18.0841L16.5403 17.8597L16.4516 16.9214Z' fill='%23B7FF40'/%3e %3cpath d='M13.2358 9.69141L13.2827 10.3942L13.8907 10.6564L13.8622 9.96077L13.2358 9.69141Z' fill='%23A40000'/%3e %3cpath d='M15.383 17.5015L15.3447 17.454L15.4083 18.0993L15.4523 18.2069L15.383 17.5015Z' fill='%23A7FF50'/%3e %3cpath d='M15.2212 16.816L15.3895 16.7719L15.5019 17.3526L15.3449 17.4538L15.2212 16.816Z' fill='%23C7FF30'/%3e %3cpath d='M10.7756 13.7215L10.8668 14.0846L11.2056 13.6793L11.1407 13.2833L10.7756 13.7215Z' fill='%23FF8200'/%3e %3cpath d='M16.5001 15.5747L16.2749 15.9921L16.4516 16.921L16.685 16.5511L16.5001 15.5747Z' fill='%23F1FC06'/%3e %3cpath d='M15.0122 15.6936L15.4434 15.7024L15.6359 16.1751L15.2246 16.2139L15.0122 15.6936Z' fill='%23FBF100'/%3e %3cpath d='M15.0443 10.9896L15.0381 11.6552L15.5456 12.364L15.5672 11.7205L15.0443 10.9896Z' fill='%23FF1300'/%3e %3cpath d='M12.0823 10.3776L12.1152 11.0545L12.6843 10.982L12.6741 10.3007L12.0823 10.3776Z' fill='%23C40000'/%3e %3cpath d='M13.8623 9.96082L13.8908 10.6565L14.4815 11.0807L14.4708 10.3975L13.8623 9.96082Z' fill='%23B60000'/%3e %3cpath d='M13.1152 14.0405L13.7198 14.2005L14.0368 14.2526L13.4636 14.0977L13.1152 14.0405Z' fill='%23FF9400'/%3e %3cpath d='M11.9966 14.0058L12.4537 14.2135L12.7757 14.0796L12.3494 13.8583L11.9966 14.0058Z' fill='%23FF8D00'/%3e %3cpath d='M11.3677 14.0017L11.6726 14.2533L11.9964 14.006L11.7211 13.7306L11.3677 14.0017Z' fill='%23FF8D00'/%3e %3cpath d='M14.4702 10.3973L14.4808 11.0805L15.0377 11.6551L15.0439 10.9895L14.4702 10.3973Z' fill='%23D10000'/%3e %3cpath d='M11.1179 12.2739L11.1259 12.8136L11.5683 12.4703L11.5869 11.9084L11.1179 12.2739Z' fill='%23FF3800'/%3e %3cpath d='M15.5689 17.4825L15.3828 17.5016L15.4522 18.207L15.6438 18.2491L15.5689 17.4825Z' fill='%23ADFF49'/%3e %3cpath d='M16.1588 17.1991L15.8472 17.3845L15.9271 18.2114L16.2434 18.0837L16.1588 17.1991Z' fill='%23B4FF43'/%3e %3cpath d='M14.7576 15.2253L15.2124 15.277L15.4436 15.7025L15.0124 15.6937L14.7576 15.2253Z' fill='%23FFD300'/%3e %3cpath d='M11.5774 11.2873L11.5866 11.9083L12.0988 11.6882L12.1153 11.0544L11.5774 11.2873Z' fill='%23F10800'/%3e %3cpath d='M13.4634 14.0977L14.0366 14.2525L14.3527 14.3909L13.811 14.2499L13.4634 14.0977Z' fill='%23FF9400'/%3e %3cpath d='M15.8469 17.3849L15.5691 17.4825L15.644 18.249L15.9269 18.2117L15.8469 17.3849Z' fill='%23B1FF46'/%3e %3cpath d='M15.0403 16.2031L15.2251 16.214L15.3896 16.772L15.2213 16.8162L15.0403 16.2031Z' fill='%23EBFF0C'/%3e %3cpath d='M15.9897 13.187L15.8718 13.7573L16.2267 14.6348L16.3586 14.101L15.9897 13.187Z' fill='%23FF7E00'/%3e %3cpath d='M14.4673 14.8213L14.9489 14.91L15.2126 15.2767L14.7577 15.225L14.4673 14.8213Z' fill='%23FFB900'/%3e %3cpath d='M13.8113 14.2499L14.353 14.3909L14.6597 14.612L14.1488 14.4933L13.8113 14.2499Z' fill='%23FF9C00'/%3e %3cpath d='M15.2477 16.8041L15.2209 16.8162L15.3447 17.454L15.383 17.5015L15.2477 16.8041Z' fill='%23CEFF29'/%3e %3cpath d='M14.1489 14.4934L14.6598 14.6122L14.9489 14.9101L14.4673 14.8214L14.1489 14.4934Z' fill='%23FFA700'/%3e %3cpath d='M11.2058 13.6792L11.3679 14.0016L11.7213 13.7305L11.5895 13.3838L11.2058 13.6792Z' fill='%23FF7700'/%3e %3cpath d='M12.3494 13.8586L12.7756 14.0799L13.1153 14.0408L12.722 13.8153L12.3494 13.8586Z' fill='%23FF8200'/%3e %3cpath d='M11.1257 12.8134L11.1409 13.2832L11.5546 12.9634L11.5682 12.4701L11.1257 12.8134Z' fill='%23FF4A00'/%3e %3cpath d='M12.6743 10.3005L12.6845 10.9819L13.2693 11.0729L13.2826 10.394L12.6743 10.3005Z' fill='%23B60000'/%3e %3cpath d='M16.275 15.9924L15.9912 16.3238L16.1587 17.1994L16.4517 16.9213L16.275 15.9924Z' fill='%23EBFF0C'/%3e %3cpath d='M11.1409 13.2833L11.2058 13.6793L11.5895 13.3839L11.5546 12.9636L11.1409 13.2833Z' fill='%23FF6000'/%3e %3cpath d='M11.7212 13.7305L11.9965 14.0059L12.3494 13.8584L12.1066 13.5686L11.7212 13.7305Z' fill='%23FF7700'/%3e %3cpath d='M16.2269 14.635L16.0142 15.0983L16.275 15.9925L16.5002 15.575L16.2269 14.635Z' fill='%23FFC100'/%3e %3cpath d='M14.8064 15.6313L15.0125 15.6936L15.2249 16.2139L15.0401 16.2031L14.8064 15.6313Z' fill='%23FFE200'/%3e %3cpath d='M15.4226 16.7241L15.2478 16.8038L15.3831 17.5013L15.5692 17.4823L15.4226 16.7241Z' fill='%23D7FF1F'/%3e %3cpath d='M15.5457 12.3641L15.4448 12.9671L15.872 13.7575L15.9899 13.1872L15.5457 12.3641Z' fill='%23FF4A00'/%3e %3cpath d='M12.7219 13.8149L13.1153 14.0404L13.4636 14.0976L13.1043 13.8776L12.7219 13.8149Z' fill='%23FF7A00'/%3e %3cpath d='M11.5869 11.9085L11.5684 12.4704L12.0515 12.2641L12.0991 11.6884L11.5869 11.9085Z' fill='%23FF1A00'/%3e %3cpath d='M12.1156 11.0545L12.0991 11.6883L12.6409 11.6206L12.6846 10.9821L12.1156 11.0545Z' fill='%23DA0000'/%3e %3cpath d='M15.0496 16.1335L15.0398 16.2033L15.2208 16.8164L15.2475 16.8042L15.0496 16.1335Z' fill='%23F4F802'/%3e %3cpath d='M15.991 16.3237L15.6895 16.5666L15.8469 17.3847L16.1585 17.1993L15.991 16.3237Z' fill='%23E4FF13'/%3e %3cpath d='M13.2824 10.394L13.269 11.0729L13.8534 11.3257L13.8903 10.6563L13.2824 10.394Z' fill='%23BB0000'/%3e %3cpath d='M14.5261 15.1166L14.7576 15.2252L15.0124 15.6936L14.8064 15.6314L14.5261 15.1166Z' fill='%23FFC100'/%3e %3cpath d='M15.6896 16.5665L15.4226 16.7241L15.5692 17.4823L15.847 17.3846L15.6896 16.5665Z' fill='%23DEFF19'/%3e %3cpath d='M11.5891 13.3839L11.7209 13.7306L12.1063 13.5687L12.0078 13.2072L11.5891 13.3839Z' fill='%23FF6000'/%3e %3cpath d='M13.104 13.8778L13.4633 14.0979L13.811 14.2502L13.4858 14.045L13.104 13.8778Z' fill='%23FF7E00'/%3e %3cpath d='M12.1064 13.5684L12.3492 13.8582L12.7218 13.8149L12.5137 13.5206L12.1064 13.5684Z' fill='%23FF6C00'/%3e %3cpath d='M15.0381 11.6553L14.9568 12.2862L15.4448 12.9671L15.5456 12.3641L15.0381 11.6553Z' fill='%23FF1E00'/%3e %3cpath d='M14.2065 14.6727L14.4669 14.8214L14.7574 15.2251L14.5259 15.1164L14.2065 14.6727Z' fill='%23FFA700'/%3e %3cpath d='M13.8904 10.6561L13.8535 11.3256L14.4213 11.7337L14.481 11.0803L13.8904 10.6561Z' fill='%23C80000'/%3e %3cpath d='M13.4858 14.0447L13.811 14.2498L14.1486 14.4932L13.8567 14.3121L13.4858 14.0447Z' fill='%23FF8600'/%3e %3cpath d='M11.5683 12.47L11.5547 12.9633L12.0063 12.7716L12.0514 12.2637L11.5683 12.47Z' fill='%23FF3000'/%3e %3cpath d='M15.872 13.7572L15.6758 14.2634L16.0141 15.098L16.2269 14.6347L15.872 13.7572Z' fill='%23FF8900'/%3e %3cpath d='M13.8567 14.3123L14.1486 14.4934L14.4669 14.8214L14.2065 14.6727L13.8567 14.3123Z' fill='%23FF9400'/%3e %3cpath d='M14.4809 11.0807L14.4211 11.734L14.9564 12.2862L15.0378 11.6553L14.4809 11.0807Z' fill='%23E40000'/%3e %3cpath d='M16.014 15.098L15.7444 15.4809L15.9911 16.3235L16.2748 15.9921L16.014 15.098Z' fill='%23FFC800'/%3e %3cpath d='M11.5544 12.9634L11.5893 13.3837L12.008 13.2069L12.0061 12.7717L11.5544 12.9634Z' fill='%23FF4A00'/%3e %3cpath d='M14.7939 15.5076L14.8061 15.6312L15.0398 16.2029L15.0496 16.1332L14.7939 15.5076Z' fill='%23FFD300'/%3e %3cpath d='M15.2077 15.9948L15.0498 16.1331L15.2478 16.8037L15.4225 16.724L15.2077 15.9948Z' fill='%23FEED00'/%3e %3cpath d='M12.6843 10.9818L12.6406 11.6204L13.1974 11.708L13.2691 11.0728L12.6843 10.9818Z' fill='%23CD0000'/%3e %3cpath d='M12.5139 13.5209L12.722 13.8152L13.1044 13.8778L12.932 13.589L12.5139 13.5209Z' fill='%23FF6400'/%3e %3cpath d='M12.0991 11.6883L12.0515 12.264L12.5625 12.2014L12.641 11.6206L12.0991 11.6883Z' fill='%23F10800'/%3e %3cpath d='M15.7444 15.4812L15.4583 15.7796L15.6895 16.5668L15.991 16.3239L15.7444 15.4812Z' fill='%23FFD300'/%3e %3cpath d='M12.0081 13.2072L12.1066 13.5687L12.5138 13.5209L12.4506 13.1545L12.0081 13.2072Z' fill='%23FF5200'/%3e %3cpath d='M15.4581 15.7794L15.2075 15.9949L15.4224 16.7242L15.6894 16.5666L15.4581 15.7794Z' fill='%23FFE200'/%3e %3cpath d='M14.4878 14.9443L14.5264 15.1165L14.8066 15.6313L14.7944 15.5077L14.4878 14.9443Z' fill='%23FFB200'/%3e %3cpath d='M15.4445 12.9672L15.2686 13.5119L15.6756 14.2637L15.8717 13.7575L15.4445 12.9672Z' fill='%23FF5900'/%3e %3cpath d='M12.9319 13.589L13.1043 13.8777L13.486 14.0449L13.3495 13.7717L12.9319 13.589Z' fill='%23FF6400'/%3e %3cpath d='M12.051 12.2642L12.0059 12.7721L12.4834 12.7145L12.562 12.2015L12.051 12.2642Z' fill='%23FF2200'/%3e %3cpath d='M14.9298 15.3147L14.7939 15.5078L15.0496 16.1335L15.2075 15.9951L14.9298 15.3147Z' fill='%23FFC400'/%3e %3cpath d='M12.0059 12.7719L12.0078 13.2071L12.4503 13.1545L12.4834 12.7144L12.0059 12.7719Z' fill='%23FF3800'/%3e %3cpath d='M15.6757 14.2638L15.4248 14.6947L15.7444 15.4812L16.0141 15.0984L15.6757 14.2638Z' fill='%23FF9400'/%3e %3cpath d='M13.2693 11.0729L13.1975 11.7081L13.7539 11.9494L13.8537 11.3257L13.2693 11.0729Z' fill='%23D10000'/%3e %3cpath d='M14.1382 14.4586L14.2069 14.6727L14.5262 15.1164L14.4876 14.9442L14.1382 14.4586Z' fill='%23FF9400'/%3e %3cpath d='M13.3494 13.7716L13.4859 14.0448L13.8568 14.3123L13.7551 14.0641L13.3494 13.7716Z' fill='%23FF6C00'/%3e %3cpath d='M13.7551 14.064L13.8568 14.3121L14.2066 14.6726L14.1379 14.4584L13.7551 14.064Z' fill='%23FF7E00'/%3e %3cpath d='M14.9565 12.2863L14.8037 12.8641L15.2684 13.512L15.4444 12.9672L14.9565 12.2863Z' fill='%23FF3000'/%3e %3cpath d='M12.4507 13.1545L12.5138 13.5209L12.9319 13.589L12.9052 13.2282L12.4507 13.1545Z' fill='%23FF4A00'/%3e %3cpath d='M12.6405 11.6205L12.562 12.2012L13.087 12.2848L13.1972 11.7082L12.6405 11.6205Z' fill='%23E80000'/%3e %3cpath d='M13.8535 11.3259L13.7537 11.9497L14.2942 12.3385L14.4213 11.734L13.8535 11.3259Z' fill='%23DF0000'/%3e %3cpath d='M15.1593 15.0447L14.9302 15.3143L15.2079 15.9948L15.4585 15.7793L15.1593 15.0447Z' fill='%23FFB200'/%3e %3cpath d='M14.421 11.7336L14.2939 12.3381L14.8036 12.8637L14.9564 12.2858L14.421 11.7336Z' fill='%23FA0F00'/%3e %3cpath d='M15.4249 14.6946L15.1592 15.0449L15.4584 15.7795L15.7445 15.4811L15.4249 14.6946Z' fill='%23FFA300'/%3e %3cpath d='M14.5967 14.7019L14.4875 14.9445L14.7942 15.5079L14.93 15.3147L14.5967 14.7019Z' fill='%23FF9F00'/%3e %3cpath d='M15.2686 13.5118L15.0405 13.9861L15.4247 14.6946L15.6756 14.2637L15.2686 13.5118Z' fill='%23FF6800'/%3e %3cpath d='M12.4837 12.7141L12.4507 13.1543L12.9052 13.2279L12.9742 12.793L12.4837 12.7141Z' fill='%23FF3000'/%3e %3cpath d='M12.905 13.228L12.9317 13.5889L13.3494 13.7716L13.3591 13.4264L12.905 13.228Z' fill='%23FF4A00'/%3e %3cpath d='M12.5622 12.2013L12.4836 12.7143L12.9742 12.7931L13.0872 12.2849L12.5622 12.2013Z' fill='%23FF1A00'/%3e %3cpath d='M14.2169 14.1736L14.1382 14.4588L14.4876 14.9444L14.5968 14.7018L14.2169 14.1736Z' fill='%23FF7E00'/%3e %3cpath d='M13.1976 11.7083L13.0874 12.2849L13.612 12.5131L13.754 11.9496L13.1976 11.7083Z' fill='%23ED0400'/%3e %3cpath d='M13.3591 13.4266L13.3494 13.7718L13.7551 14.0644L13.8004 13.7446L13.3591 13.4266Z' fill='%23FF5500'/%3e %3cpath d='M14.7997 14.3832L14.5967 14.7017L14.93 15.3145L15.159 15.0449L14.7997 14.3832Z' fill='%23FF8D00'/%3e %3cpath d='M13.8006 13.7444L13.7554 14.0641L14.1382 14.4586L14.2169 14.1734L13.8006 13.7444Z' fill='%23FF6800'/%3e %3cpath d='M15.0405 13.9861L14.7996 14.3832L15.1589 15.0449L15.4247 14.6946L15.0405 13.9861Z' fill='%23FF7A00'/%3e %3cpath d='M14.8039 12.8638L14.6021 13.3753L15.0405 13.9859L15.2685 13.5115L14.8039 12.8638Z' fill='%23FF4300'/%3e %3cpath d='M12.9738 12.7932L12.9048 13.2282L13.3589 13.4266L13.4639 13.0069L12.9738 12.7932Z' fill='%23FF3400'/%3e %3cpath d='M13.7538 11.9495L13.6118 12.5129L14.1215 12.8798L14.2943 12.3382L13.7538 11.9495Z' fill='%23FA0F00'/%3e %3cpath d='M13.0872 12.285L12.9741 12.7933L13.4642 13.007L13.6117 12.5132L13.0872 12.285Z' fill='%23FF1A00'/%3e %3cpath d='M14.2944 12.3384L14.1216 12.8799L14.6022 13.3755L14.8041 12.864L14.2944 12.3384Z' fill='%23FF2200'/%3e %3cpath d='M14.3896 13.813L14.2166 14.1736L14.5965 14.7018L14.7995 14.3833L14.3896 13.813Z' fill='%23FF6800'/%3e %3cpath d='M14.602 13.3752L14.3896 13.8126L14.7995 14.383L15.0404 13.9858L14.602 13.3752Z' fill='%23FF5500'/%3e %3cpath d='M13.4642 13.007L13.3591 13.4266L13.8004 13.7446L13.9405 13.35L13.4642 13.007Z' fill='%23FF3B00'/%3e %3cpath d='M13.9406 13.3499L13.8005 13.7445L14.2168 14.1735L14.3898 13.8129L13.9406 13.3499Z' fill='%23FF4E00'/%3e %3cpath d='M13.6118 12.5131L13.4644 13.0069L13.9406 13.3499L14.1215 12.88L13.6118 12.5131Z' fill='%23FF2500'/%3e %3cpath d='M14.1214 12.8798L13.9404 13.3497L14.3897 13.8127L14.602 13.3754L14.1214 12.8798Z' fill='%23FF3800'/%3e %3c/svg%3e", + "iconPng": "data:image/png;base64,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" + }, + "oneInch": { + "color": "#323232", + "title": "1inch", + "icon": "data:image/svg+xml,%3csvg width='1070' height='420' viewBox='0 0 1070 420' fill='none' xmlns='http://www.w3.org/2000/svg'%3e %3cpath d='M470 116H510V276H550V76H510C488 76 470 94 470 116Z' fill='white'/%3e %3cpath d='M590 276H630V196C630 174 612 156 590 156V276Z' fill='white'/%3e %3cpath d='M670 156V276H710V196H750V236C750 258 768 276 790 276V196C790 174 772 156 750 156H670Z' fill='white'/%3e %3cpath d='M1030 156H990V116C990 94 972 76 950 76V236H870V196H910V156H870C848 156 830 174 830 196V236C830 258 848 276 870 276H990V196H1030V236C1030 258 1048 276 1070 276V196C1070 174 1052 156 1030 156Z' fill='white'/%3e %3cpath d='M590 116H630C630 94 612 76 590 76V116Z' fill='white'/%3e %3cpath fill-rule='evenodd' clip-rule='evenodd' d='M532.363 316V342.177H528.698L514.301 324.04V342.177H510V316H513.665L528.062 334.212V316H532.363ZM613.729 342.177H598.21V316H613.356V320.301H602.81V326.807H612.234V331.108H602.81V337.877H613.729V342.177ZM679.577 320.301H688.066V342.177H692.665V320.301H701.154V316H679.577V320.301ZM799.05 316H803.463L795.983 342.177H791.683L785.363 323.255L779.155 342.177H774.817L767.001 316H772.162L777.435 334.661L783.269 316H787.831L793.814 334.698L799.05 316ZM873.124 319.889C870.581 322.482 869.31 325.686 869.31 329.5C869.31 333.514 870.594 336.767 873.162 339.26C875.729 341.753 878.983 343 882.922 343C886.836 343 890.09 341.729 892.682 339.186C895.275 336.643 896.572 333.414 896.572 329.5C896.572 325.511 895.275 322.258 892.682 319.74C890.115 317.247 886.861 316 882.922 316C878.983 316 875.717 317.296 873.124 319.889ZM876.677 336.082C875.007 334.337 874.171 332.143 874.171 329.5C874.171 326.807 874.994 324.601 876.639 322.881C878.31 321.161 880.404 320.301 882.922 320.301C885.39 320.301 887.472 321.161 889.167 322.881C890.862 324.626 891.71 326.832 891.71 329.5C891.71 332.143 890.912 334.337 889.317 336.082C887.746 337.827 885.615 338.699 882.922 338.699C880.429 338.699 878.347 337.827 876.677 336.082ZM967.018 332.454V342.252H962.419V316.075C963.715 316.075 965.124 316.062 966.644 316.037C968.165 316.012 969.412 316 970.384 316C976.716 316 979.883 318.693 979.883 324.078C979.883 326.072 979.372 327.717 978.349 329.014C977.327 330.26 976.156 331.108 974.834 331.557L983.024 342.252H977.452L970.234 332.454H967.018ZM970.16 320.301C970.035 320.301 969.836 320.313 969.561 320.338C969.287 320.338 968.901 320.35 968.402 320.375H967.018V328.154H970.01C971.481 328.154 972.678 327.792 973.6 327.069C974.548 326.346 975.021 325.361 975.021 324.115C975.021 321.572 973.401 320.301 970.16 320.301ZM1048.87 342.177H1053.47V328.677L1064.17 342.177H1070L1058.56 328.191L1069.33 316H1063.79L1053.47 328.416V316H1048.87V342.177Z' fill='%232F7AEA'/%3e %3cpath d='M104.449 229.147L114.949 150.069L23.73 86.7412L107.074 114.96L126.761 84.7725L198.621 40.1475L357.105 127.429L365.308 260.647L294.761 358.757L238.98 367.288L267.855 314.46V263.601L246.855 223.897L225.527 209.788L192.714 243.585V279.351L167.121 303.304L134.636 307.241L120.199 315.444L96.5737 307.897L86.73 272.46L104.449 247.522V229.147Z' fill='white'/%3e %3cpath d='M250.136 86.0848C232.746 82.4754 213.715 83.4598 213.715 83.4598C213.715 83.4598 207.48 112.335 168.761 119.882C169.09 119.882 219.949 137.272 250.136 86.0848Z' fill='%2394A6C3'/%3e %3cpath d='M265.886 347.929C286.886 331.523 302.636 308.882 309.855 283.288C310.183 282.304 313.136 280.663 315.105 279.351C318.386 277.382 321.667 275.741 322.324 273.116C323.636 265.569 324.292 257.694 324.292 249.819C324.292 246.866 321.339 243.913 318.386 240.96C316.089 238.991 313.792 236.694 313.792 235.054C310.511 205.194 296.73 177.304 274.746 156.96L272.449 159.257C293.777 179.273 307.558 206.507 310.511 235.382C310.839 238.007 313.464 240.632 316.089 243.257C318.386 245.226 321.011 248.179 321.011 249.491C321.011 257.038 320.355 264.585 319.042 272.132C318.714 273.444 315.761 274.757 313.464 276.069C310.183 277.71 307.23 279.351 306.574 281.976C298.699 309.866 280.652 334.148 256.699 349.898C260.964 340.71 274.417 310.851 281.636 295.757L280.324 247.194L238.652 206.835L215.027 210.116L189.105 252.116C189.105 252.116 201.246 267.538 184.183 285.585C167.449 303.304 154.324 307.241 154.324 307.241L142.183 300.679C145.792 296.085 153.011 289.194 158.589 284.601C168.105 276.726 177.621 276.069 177.621 267.538C177.949 249.819 158.917 254.741 158.917 254.741L152.027 261.304L149.074 285.585L134.636 303.632L132.996 303.304L109.371 298.054C109.371 298.054 123.808 290.507 126.105 281.976C128.402 273.773 121.511 246.538 121.183 244.898C121.511 245.226 128.074 250.804 131.027 259.991C136.277 245.554 143.167 231.773 145.136 230.46C147.105 229.148 173.683 215.038 173.683 215.038L164.824 238.335L171.386 234.726L187.136 196.007C187.136 196.007 202.558 188.46 214.042 188.46C234.714 188.132 265.23 162.866 251.449 117.585C255.386 119.226 323.636 153.351 335.449 220.288C344.308 271.804 315.105 320.038 265.886 347.929Z' fill='%2394A6C3'/%3e %3cpath d='M187.793 93.3039C195.34 84.4445 192.386 71.3195 192.386 71.3195L170.402 103.804C170.074 103.804 178.277 104.132 187.793 93.3039Z' fill='%231B314F'/%3e %3cpath d='M113.964 270.82L116.589 257.695C116.589 257.695 105.761 276.726 104.777 279.351C103.793 282.305 105.433 287.555 109.699 287.226C113.964 286.898 119.214 280.664 119.214 276.07C119.214 270.164 113.964 270.82 113.964 270.82Z' fill='%231B314F'/%3e %3cpath d='M308.871 62.1324C308.871 62.1324 325.277 62.7886 342.339 64.7574C303.949 34.5699 267.527 25.7105 237.996 25.7105C197.308 25.7105 169.746 42.4449 168.105 43.4292L180.902 23.0855C180.902 23.0855 129.714 18.1636 111.667 72.3042C107.074 60.8199 102.808 44.0855 102.808 44.0855C102.808 44.0855 76.23 67.3824 88.6987 106.101C58.1831 94.9449 14.5425 79.523 12.9019 79.1949C10.605 78.8667 9.94875 79.8511 9.94875 79.8511C9.94875 79.8511 9.2925 80.8355 11.2613 82.4761C14.8706 85.4292 83.7769 136.289 98.8706 146.132C95.5894 157.945 95.5894 163.523 98.8706 169.101C103.464 176.648 103.792 180.585 103.136 186.164C102.48 191.742 96.5737 239.976 95.2612 245.882C93.9487 251.789 80.1675 272.789 80.8238 279.023C81.48 285.257 90.0113 311.835 97.5581 314.789C103.136 316.757 116.918 321.023 126.105 321.023C129.386 321.023 132.339 320.367 133.652 319.054C139.23 314.132 140.871 313.148 144.808 313.148C145.136 313.148 145.464 313.148 145.793 313.148C147.433 313.148 149.402 313.476 151.699 313.476C156.949 313.476 163.839 312.492 168.761 307.898C175.98 300.679 188.449 290.835 192.386 286.242C197.308 280.007 199.933 271.476 198.621 262.945C197.636 255.07 201.902 248.179 206.824 241.289C213.058 233.085 224.542 218.32 224.542 218.32C247.183 235.382 261.292 261.304 261.292 290.179C261.292 341.367 216.668 382.71 161.543 382.71C153.011 382.71 144.808 381.726 136.605 379.757C161.871 388.617 183.199 391.57 200.589 391.57C237.667 391.57 257.355 378.117 257.355 378.117C257.355 378.117 250.464 386.976 239.308 397.148C239.636 397.148 239.636 397.148 239.636 397.148C300.996 388.617 330.855 338.085 330.855 338.085C330.855 338.085 328.558 354.492 325.605 365.648C407.308 304.289 393.527 227.507 393.199 224.882C393.855 225.867 402.058 235.71 406.324 240.96C419.449 105.773 308.871 62.1324 308.871 62.1324ZM183.199 278.039C181.886 279.679 176.308 284.601 172.371 288.21C168.433 291.82 164.168 295.429 160.886 298.71C159.574 300.023 156.949 300.679 153.011 300.679C151.699 300.679 150.386 300.679 149.402 300.679C148.746 300.679 148.089 300.679 147.433 300.679C146.777 300.679 146.449 300.679 146.121 300.679C145.136 300.679 144.152 300.679 143.167 300.679C148.089 294.117 162.527 279.023 167.449 275.742C173.355 271.804 176.308 267.867 172.699 260.976C169.089 254.085 159.574 255.726 159.574 255.726C159.574 255.726 165.152 253.429 170.074 253.429C163.839 251.789 155.964 253.429 152.355 257.039C148.418 260.648 149.074 273.445 147.433 281.648C145.793 290.179 140.214 294.445 131.683 302.32C127.089 306.585 123.808 307.898 121.183 307.898C115.605 306.914 109.042 305.273 104.449 303.632C101.167 299.367 96.2456 285.257 94.9331 279.351C95.9175 276.07 99.855 269.179 101.824 265.242C105.761 257.695 108.058 253.429 108.714 249.492C110.027 243.914 114.293 209.46 115.933 195.023C120.199 200.601 126.105 209.789 124.793 215.695C134.308 202.242 127.418 189.117 124.136 183.867C121.183 178.617 117.246 168.117 120.527 156.96C123.808 145.804 135.621 114.96 135.621 114.96C135.621 114.96 139.558 121.851 145.136 120.539C150.714 119.226 195.667 51.6324 195.667 51.6324C195.667 51.6324 207.808 78.2105 195.011 97.5699C181.886 116.929 169.089 120.539 169.089 120.539C169.089 120.539 187.136 123.82 203.871 111.679C210.761 127.757 217.324 144.492 217.652 146.789C216.667 149.085 203.542 180.585 202.23 182.554C201.574 183.21 196.98 184.523 193.699 185.179C188.121 186.82 184.839 187.804 183.527 188.789C181.23 190.757 170.73 219.632 165.808 233.742C159.902 235.382 153.996 238.664 149.73 245.226C152.027 243.585 159.246 242.601 164.496 241.945C169.089 241.617 183.199 249.164 186.808 263.273C186.808 263.601 186.808 263.601 186.808 263.929C187.464 269.179 185.824 274.101 183.199 278.039ZM152.355 281.976C155.308 277.71 154.98 270.492 155.308 268.195C155.636 265.898 156.293 261.632 158.918 260.976C161.543 260.32 167.777 261.304 167.777 265.898C167.777 270.164 163.183 271.148 159.902 274.101C157.605 276.398 153.011 281.32 152.355 281.976ZM283.277 219.304C286.558 202.57 286.886 188.132 285.902 176.32C298.699 193.382 306.574 214.054 308.871 235.382C309.199 238.007 311.824 240.632 314.449 243.257C316.746 245.226 319.371 247.851 319.371 249.492C319.371 257.039 318.714 264.585 317.402 272.132C317.074 273.117 314.121 274.757 311.824 276.07C308.542 277.71 305.589 279.351 304.933 281.976C297.714 307.242 282.292 329.554 261.621 345.304C292.136 313.476 306.902 260.976 283.277 219.304ZM262.605 348.257C283.933 331.851 300.339 308.882 307.558 282.96C307.886 281.976 310.839 280.335 312.808 279.023C316.089 277.382 319.371 275.414 320.027 272.789C321.339 265.242 321.996 257.367 321.996 249.492C321.996 246.539 319.043 243.585 316.089 240.632C314.449 238.664 311.824 236.367 311.824 234.726C309.199 210.773 299.683 188.132 284.918 169.429C278.355 130.054 252.105 117.914 251.449 117.585C252.105 118.57 269.168 143.179 257.355 172.054C245.214 201.257 214.043 196.664 211.418 196.992C208.793 196.992 198.621 210.117 185.824 234.398C184.183 233.742 177.292 232.101 169.417 233.414C175.324 217.007 184.183 193.71 185.824 191.742C186.48 191.085 191.402 189.773 194.683 188.789C200.917 187.148 203.871 186.164 204.855 184.851C205.511 183.867 208.792 176.32 212.074 168.445C215.027 168.445 222.574 167.789 223.23 167.46C223.886 166.804 230.121 150.726 230.121 148.757C230.121 147.117 217.324 115.289 212.402 103.148C214.699 100.523 216.996 97.2417 219.292 93.6324C286.558 100.851 339.058 157.945 339.058 227.179C339.058 280.335 307.886 326.601 262.605 348.257Z' fill='%231B314F'/%3e %3cpath d='M175.324 171.07C181.558 163.851 178.277 150.398 166.793 148.101C169.746 141.21 174.011 127.429 174.011 127.429C174.011 127.429 140.543 179.929 137.589 180.913C134.636 181.898 131.683 170.413 131.683 170.413C125.449 194.367 142.183 197.648 144.152 190.101C153.339 187.804 169.089 177.96 175.324 171.07Z' fill='%231B314F'/%3e %3cpath d='M146.777 183.867L163.839 154.664C163.839 154.664 173.683 159.586 168.761 167.461C162.527 176.648 146.777 183.867 146.777 183.867Z' fill='%23FFD923'/%3e %3cpath d='M357.761 319.054C352.839 325.617 347.261 332.507 340.699 339.07C383.027 257.695 342.668 183.211 341.027 180.257C343.98 183.211 346.933 186.492 349.558 189.445C382.043 225.539 385.98 279.679 357.761 319.054Z' fill='%23D82122'/%3e %3cpath d='M397.136 214.382C382.371 174.679 361.371 140.882 315.105 110.367C270.48 80.8355 222.574 83.1323 219.949 83.4605C219.621 83.4605 219.293 83.4605 219.293 83.4605C220.933 82.8042 222.574 82.4761 224.214 82.148C234.386 78.8667 247.511 76.2417 260.636 74.6011C295.418 69.6792 330.527 81.4917 354.48 106.757C354.808 107.085 354.808 107.085 355.136 107.414C382.371 136.289 396.48 172.382 397.136 214.382Z' fill='%23D82122'/%3e %3cpath d='M304.605 51.9613C255.714 42.7738 224.214 47.3675 201.574 55.8988C200.918 53.2738 198.621 48.0238 196.652 43.7582C189.761 51.9613 182.543 61.805 177.949 68.0394C165.48 76.5707 160.23 84.7738 160.23 84.7738C167.449 60.1644 188.449 41.7894 214.043 37.1957C221.261 35.8832 229.136 35.2269 237.668 35.2269C260.308 35.555 282.949 41.1332 304.605 51.9613Z' fill='%23D82122'/%3e %3cpath d='M123.808 114.961C85.4177 113.649 98.2145 69.0238 98.8708 66.3988C98.8708 66.7269 101.496 101.508 123.808 114.961Z' fill='%23D82122'/%3e %3cpath d='M161.543 34.5702C132.011 52.2889 137.918 94.6171 137.918 94.6171C109.699 51.6327 159.246 35.5546 161.543 34.5702Z' fill='%23D82122'/%3e %3cpath d='M112.98 126.773C114.949 128.414 116.918 131.367 114.621 135.632C113.308 137.929 111.34 137.601 108.386 136.289C104.449 134.32 80.824 120.539 59.4958 106.429C83.7771 114.96 108.386 124.148 112.324 126.117C112.324 126.117 112.652 126.445 112.98 126.773Z' fill='white'/%3e %3c/svg%3e", + "iconPng": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAItUAAA2sCAYAAABTSr5cAAAACXBIWXMAAFxGAABcRgEUlENBAAAgAElEQVR42uzBAQEAAACAkP6v7ggKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA2bvjGMmrg4DjVzgKSKmhQI55b3bRc/HMXXfnvZ2TYnPN2PRIT/fmvdnVSWtLwNB4pIZINMJZSwupNgG8kKBN0yOKqRit2BZ00T+kbbShaWtJG9Fao72IUqSNhZIWPBvgxjfnYQzRNlAOdm8/n+Sb95vfzN3uzrz3+739awEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAID15+xt5czZ+aWzZneubI1p6YLO4qgf8ujHQiq7Qy4lpjJu4+VxcbSvk+s1Mdf9zxRSfVd73Q3P6jdbB59dTPW3/o/XHq0996vT/6+Th1dOv05Iw8umXzfm4cr0++gs1teFhZKn3+N5aXxu96Lx6T45AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgBfIudvHr4jzy93uwvKrO/3RrrA42hvz8JJOHl4Zcrk25nKg9dshlQ/HVD7Wuq8dH2rPPRJy/c+Y62TdlspT7Wf7Wkz1S+3xve3xn3Z7owvNCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBmdn7prJnecEenP9oVUxm3roq5Xh9SOdiOV9vxve34UMjl2+14ov8upPq5TePxyWYQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcEKb7S93Yr+8JqYyDrn8Ukj15pDK7THXv2jj/e3xwzGXp9vjiZ5jqT7Z6e9dNMsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAdW379vHLZ3eubO30R7tiKuOY6/6QysF2vNq6L+byrXZuouNVOWAWAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGve+YPBaTO94Y5OGtaYylUh1ZtDKh8Ouf51O3445jrRS1QqD2xZuPgMsxQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYEzr9vd8X83ChtdLJ9ZqQ662tT8RU/yXmeqQ10RqsV5bMXgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOBFNzu/dFZncdSPqVwaUrmhjattPBRzeTrmOtE6KpU/MqMBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA4yrOL3e7ebgn9MrVMdXbQqqfDrl8I+Y60fpv+lnO9pc7ZjoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwgtjaH39/Z3HUj6lcGnK9JeZ6T8zla22c6ITuCrMfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeF5md65sjan8dEz110Muf9Z6MOY60UarfGrTputOsiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA72ww2DzTG+6IqYxjrte3cTWm+u/teKINXqpPxrTcs0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAZ7nupPNS2R7S8LKY6vtCLp8NqR6OuU6kZ9fmx3utGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGDTTC4h5DqMuV4fU1kNuTzSjifSdyuk+k/di8anW0UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwwWxZuPiM2Ks/HnK5NqayGnP9amsiPY+OhFzfYFUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADABjCTSwi5DkMqN8Rc7w25fLuNE+l7rc2rD1phAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcCIaj0+eyWVnTOWq1odCLg/GXCfSC14qX+/0955j0QEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMCJYDw+ubM46sdUroq53hFyfbSNE+l4F9LwMgsQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1qvBYHNncdSPue6PqayGVB5rxxPpxSzk8pdtNr7MggQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAID1YjDYHFJ9bUjl3W38eEz1iZjrRHqpavPwcFgY/ckRkJoAACAASURBVLDFCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGvc7M6VrXFxtC/mekfI9dE2TqS1UsjlWqsUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1qDz0vjcmMo4pHKwjQ/EXCfSGu0f5ub2nGrVAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwBowN7fn1JDK7pjLgZDq38Rcj7Qm0hrvSKc/2mUFAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwEuo0987G3O9onVXzOVbbZxI66mQykErGYANZzDYPDu/dFbby50zu3Nl60x/9EOdxVF/Wsj1De3+uDvm4UpMZdztlbfGxdG+Zwq9cnW7h+6fFlJ9V3vtDc/U9oPvn95bp8VUb2uvueM71f79R9p4z3Or3Pn//n+5fvCZr//s2vfzvv/9vR77ft8z/Tk6uV7zzM/XTfUt05+7k4Z1+j5M+5/3Zr5sm75fcX65O33/pplMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA89fv7Tom98vqY600h179r40Rar4VUH56dXzrLygZgLdqycPEZs/3lTpgv2zqLo/7RPViqPxlTGXdSfVsnD69s97P9IZf3tnvazSGVg+35P2zn7mrd085/tp27v3WoPf9Q27s92s4/bg9w3Hr82Hv81el73j6LL7XP6r7Wx9rxn0w/m6OfUS4HWu+ZfnZxcbQv5uElrZX23O7YL6/pLiy/enbnytbpHmVubs+pVgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ5TZ/nIn9srPhVQ/GlP9Zsx1Ip0IhVzfZIUDcDycPxicNt1DzfSGOzr90a6QS4mpXNrJwytjGr4jpHJD6wMxlz9o96O723OfbMdfaOcOtcePtsdPuVfraKk+eWxOPND6+9Z97fw9x/bmv9PmzYE2v97ZHv98G9/cXaxv7PZGF8a0dEGnv/ecTZuuO8mKBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAldV4q22MqvxJS/UzM5emY60Q6kQq5/LmVDsB3Mze359RubynGtNzrpOHFIdc3hTR6e7uPvLPtkQ7EVG9r451tz/RXIZX72/NfaeeecK/Vmtr3pPJYm6f/3I4/3+bqx9s8/ePWrW2/f+N0z9/OX9HGcXvd7s7iqD+7c2Xr2dvKma4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxP153U6Y92xVxvCrn+Yxsn0gnc41t69Qese4CNZ8vCxWd083AuLg4vCoujvaFXfzb0ytUxl99o/W5MZTWk+umQypdjqt90z9RGrq2Fw21N/GsbP9d+R7j72Bq5sY2/GPPwku5ifWMbF2b7y51Ng8FmVxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACADez8weC0kMrukOstbfy3mOtE2giFVH/ZFQDgxLF9+/jlM7mEmd5wx3RvE1O5tF3v9x/b4/xeO76n9cWQyzfcB6Xjusc63NbcoXZ8b1uHq+34YDu+vh1fNV2X0/U5XafT9dqW7stcvQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADWuXO3j18RcnlzSPUjMdUnYq4TaWNVvrBpMNjsagCw9vX7+04JO+tM27e8tl3Dfyqm8gutG0Mqt4dcP9HOfbHtax5xb5PWX20d/0fry21Nf7Kt599v5246usbzcCUuDi/q9paiPRsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAGnT2tnJmJ41+JqT60ekfr3++f/heWvel8lQ37f1RVwWAl96rLtzzypnecEdMo58IuVze9ijvbn2gXatX2zX7823f8nAbj7h/SRt779auBQ+1PnP0d5lcb+nkek3Mw0u6aTSIaemC7kXj011RAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI6zs7eVM7upviXmcmdI9fCL9ofvpTVcyPUWVweA46/f33fKeXnl/M5ifV3Mw0tiGr6j7UneH1NZDbn8bUjlMfclSS9YqXy9XVfub3u9u1u3tuPrOqm+rZuHe8J82TY3t+dUV2YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA5+hVF+55ZbdX3hpzvSukenhN/+F76UUu5PLg2dvKma4UAN+78weD0zr9vT/SzcM9IY3e3q6zN8VUPhRz+VTI9SttfNq9R9Ia6kj7/eihNt4bUrk9pvprbW94eeyV129ZGP7gpsFgsys7AAAAAAAAAAAAAAAAAAAAAAAA/Bd79x6t11kXeDxN71CK9ELy7n2SNOec5Jzznsv77POe9JImnKRN2qQ577NPgq84FYuMEh0YjFoGdBQTF8uxCAUDKHYJo2aojlFAWkccq3SKVWCoimBsvIAVBS9cy6X0ljzznMioYFvSNJdz+XzW+q6dsmDR7nfv336e/vMAAAAAAAAAAAAAAABA1t+/5eyy6uwoQv323Ffm0cH30nGtETq1iQFwdNrtnWcun9jRW453rmqE+jvLUL+qqOq35Xl6d15vfMJ3RdK8KtSPlFX86zzn3pP//NY8516Z91jPb7Q6Vy6rYpHH4mm+DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMA8tntx2ao3lFV8S1HFzy3Ig++lJ1ER6neYGwBf6+Jm97yiVYc8J5+be0VeU/xcUdXvKUO8rwz1I74fkvTVtWRVP5ivB/Oa8t15Pr65UdUvL8anv6UnTK1ptKcu8kUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5qRlrc5wWdV7ch9zuL10lIX6/nJ0e48JAixEy0e3PasxPt0uQ+zmmfiKIsRb8vWOfP1ovh72nZCkp15Rxc/lOXtP/vP+PF9vyn++YWb2XjgQn+FLBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMwqS6sdK8rQ+aGiih9xYL305GtUnf9skgDzWc/l3XPLsL1VhtjN64UfLkLcl68fyH3Gd0CSTnEhfjz3O2Wo31xW8fvz9bqeqtO/aHLyDF8wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4KS4uNk9r6jiC4tQ31VW9WGH0UvHVn6H3r9o0e7Fpgow9+1evKRVX9JoTV/TU9UvLUP9pjznfrsM8T5rBUmai+vU+HC+Hszz/F1lFV9TtuKLyla9YXl7e8M3DwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgeTmuM1+vLKv587osOmpeeYqF+pAzbW0YLMJf09285u6w6Y0VVPy/Psh/L7S9C/HD+6wfNdklaMOvYL5Qh3pOvvzzzLegJ9fWN9tR4z+Xdc30pAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgCe0rIpFWdWvKKr6LxwgLx2/ihBvMmGA2arZ7J61rNUZLkPs5pm1J7c/dyD/9aNmuCTpCda4n8zfittn1rr5ekNjfLrdc3n3XF9WAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWMBWTE6eU1TxW4sQf6us4iGHw0vHt/xufbTRnnqaaQOcav39W87O82i8CJ0X5G/+a498+0O8L8+qw+a1JOk4rX0fztcDuf35zz+ar88tRuPAosnJM3yJAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYB5rjE+3y1C/qajqzzr8XTpx9YzX15o4wMm2tNqxohifnipD54fKEP9nnkcH8nf/EXNZknQqyvvOB8sq/nFRxVtnvk35Gpe1p/sWLdq92FcbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5qgVk5PnlCF2y6q+w8Hu0omvqOKtJg9wIjWb3bOWtTrD+ft+Q1HVe//5Gx//yQyWJM2R9fJD+Xogtz+3Z2a/OvNdW7Ro92JfeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJilZg4lL0P9xiLEzzu4XTo5FVX8zLNHOktMIOD42L24DNtW5fny3NyPFaF+R/6u/1X+82EzV5I079bSee+av3V3FVX9U0Wr/o4ybG+12zvPtB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAU6TZ7J5Vhtgtq/qO3GEHs0snt0aov9MkAo5Fb7v7zEZ7el05Pr2zqOq9eabcXVbxi2arJGkhV4T4cL4eyNd9ea+7a+ZbuWRs89OtHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAEKsO2VWUVX1OG+lMOXpdOTUWo78qv42kmEvCNrFhz3dKyFbcVIe4uQ7ytqOLfmqOSJB1lIT6a97735j3wLxWt+F/y93RTsWb6QisMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeCq63dPLqrOjrOo7cocdri6duoqqfnBpNT1kMAFf79kjnSVlqK8rQvzRfH1Xnhd/Z25KknQCCvXf5Ouv5/Y0QqdutKeWW4kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAN3DBpVvOL0PcVVbxrx2cLs2a9phOwIpW/U2N9vS6me90EeK+PBsOmI+SJJ268vf48/l6d1HVe/P3+YZlrc7wom73dKsWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFryl1fRQGeo3l1X9JYejS7Oqg/39W842pWCBfZdD9+KeqrOlqOKPlFV8Zxnix81DSZLmRF8qQn1X/n6/Jv/5ucVEvczKBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgIXitCLETWWIt5dVfdjh59Ks63A53rnKqIL5rbfdfWajPb0uf4935e/yvvzuH/BdliRp/pS/75/86r57T1HVnZ5m9wIrIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOaNCwfiM3qq+qVFVf+FA86lWVyo32piwfyyYnLynEarc2UR6huLEH+tDPE+806SpIVWPJSvB/L154sqfk8xFqtFk5NnWCkBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwpyyf2NFbhPj6MtT3O8Rcmu3FfyzWTF9ocsHc1mhPLS+q+nm5nypC/f78HX7YfJMkSV9fXiM8kK935/36zTNrhyWt+hIrKQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGalMmxvFSHuK0P9iMPKpblRTyt+m+kFc8zk5BmN8el2GeKuI9/dqv6YeSZJko61vJ74fL7ekdtTVHWn0Z66yIILAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAU6bRmr6mDPF3HEYuzbl+2wSD2a+YqJcV49PfUoT4+iLU7yuq+JD5JUmSTmCHy1DfW1T1Lxbj8SVFqw6Lut3TrcoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4gXYvLqq6U1TxAw4cl+ZeRYgPLGtP95llMMtMTp7RGJ9ulyHuyu/pvvy+fszMkiRJp774xXy9I7cnr1E29VzePdfCDQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgKdsydjmp/dU9UvLKv61Q8WlOVyIP2iiwanX09pW5vexW4T6dbn3FVV8yIySJEmzvX9es8Tfz+uYVxdV3elpdi+wsgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOCoNdpTF5VVvacM9accIC7N7YoqfqTd3nmmyQYn37IqFmWI3SLEW/L7eMBMkiRJ82afEeJHc/vK8emdy1qdYSs/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/p1ydHtPEeIbylB/2SHh0nwoHirHO5ebbnByLK2mh/K7991FVb+tqOLfmkGSJGmhNLP2yd1ahPrFPe16dNGi3YutDgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABaoRntqeVHVe4tQf8Vh4NJ8Kv60CQcnzvKJHb3l+PTOIsR9ZYgfN3MkSZK+Wqi/kK935PbktdKmFZOT51g9AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzHPL2tN9ZRXfUoT4sEO/pflVEepP9La7zzTp4DiZnDyjJ0ytye/WjWWItxVV/VmzRpIk6Sj3J1X9YF5D/V6+/reyFbfZqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMwjS8Y6K4sQbylD/YjDvaV523NNO3gKJifPaIxPt8sQd+X3aX9Rxc+ZK5IkScepEB/N3VNU9d587V5w6ZbzLUABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADmmKUhNosq3nrk8GqHeEvz+YD620w8eHL6+7ecXbbixvwO7cnfyjuLEB8wTyRJkk5Oef31UBHqu/IabHdjvF7fbHbPskIFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACYpXrGto8UIe4rQ3zUYd3SPC/UX14y1llp8sE3tnxiR285Pr0zvzv787tzvxkiSZI0e/Y1+XpHbk8R4qZ2e+eZVq8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACn2LJWZ7gI9TvKqj7sUG5pgTRef5/pB4/zXWxP95Xj0zvzu7K/DPWnzAxJkqS5UVHFz+Xrr5chfm/P2PaRvLQ7zeoWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgJFla7VhRhHhLGeKjDt+WFtBB86H+4KJu93RTEP5Zoz11Uf4Wdo98E6v6Y+aEJEnSfCn+U77uz2u9XY3x6baVLwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAnQ09pWFlW9N/egA7alBVaIjzbaU+MmIQtZfgeeVoS4KXdTfifuKat4yHyQJEma/xWh/vt83V+OT+9cWu1YYWUMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwFDTaUxeVob65CPEBh2lLC7Q8A0xDFpzJyTOKavqKItSvLKr4f3IPmQeSJEnKHcx7pDeXIXaLNdMXWjgDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAchd5295llVf9YGeovODBbWsCFeN+Ssc1PNxVZCJZW00P5mf/e/O17V+5+M0CSJEnfYL/0aFHFD+S146sa4/X6RZOTZ1hVAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/BuN9tTTyhB3lVX8RwdkSyqqumMyMp+/eUWIm/Jzvjd/++7zzkuSJOkp9qXcHblXLA2xacUNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsWO32zjOLUL+4CPGTDsGW9NX2m47MN8taneH8vXtZ7neLKj7kPZckSdKJqgjxr8oq/nQjdOoLB+IzrMYBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAFodGqp8uqPujAa0n/cvh7FT+3vL29YUIy1104EJ/RMx63FyHeUob4ce+3JEmSTskeK8SHi1DflfdaP9xoT43npeppVusAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMC8sqyKE0UV73S4taTH6LtNSeaq5RM7essQd+Xn+I6iqh/0PkuSJGn2Ff8pX/fndesNy0e3PcsqHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmLPK0e09RYi3lFU85BBrSV9fEer3L1q0e7FpyVyxZGzz0/N3bVNR1XvLUP+N91iSJElzqhAfzd2T/7ynMT7dzkvc06zyAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWe/iZve8mQOai1B/xaHVkh77MPf6kTJsb5mYzHbLJ3b0liHuys/tHUUVH/L+SpIkaf4U/zFf9+f17g0rWvU3Wf0DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACzSru988yeqn5pGepPOZha0hNVVPHHTU1moxWTk+fk79h1RYg/W1T133lfJUmStCD2aCE+nPdpdxahflkxGgfsDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgFOqCHFTUdV/6iBqSd/4sPb6L3su755rcjJrvmFrpi8sQ+zmb9m+MtT3e08lSZKk+mN5fXxLUdWdZrN7ll0DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwUhRjsSpDfK/DpiUdZYeLqr7a9ORUa7SnBhtV/fL8TN6dv2OPejclSZKkx64I8fN5zfwr+c/fntfRF9lNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx93y0W3PKqp6bxniow6YlnTUh7FX9S+aoJwS3e7pjfHpdn4O9+QOeB8lSZKkYykeKkO8Z2ZdPbO+zivt02w2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAY9ftnl6E6f9UVPEzDpKW9KQK8dON9tRFBikny4UD8Rn5ufvmoqp/ceb58x5KkiRJx72P5fX23tzViyYnz7ALAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjlpPmFpTVPEDDoyWdCwVofMCk5QTbcnY9meXId6Qu72o6ge9e5IkSdJJ2vNV9Wfzdf/MevyCS7ecb3cCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8pmVVLIqqfltZ1YcdEi3pGA9Xf08eJ6eZqJwIZdjeKkLcXYb6D32rJEmSpFmwBwz1V/I+8DfKVnzRijXXLbVrAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFrXbO88sQ9xVhvp+B0JLOubD1Kv6wUZ7atBU5Xha1uoM5+drT/5G3es9kyRJkmZz8VAZ4j0z6/elITbtZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAEqw/TWsop/7uBnSU+1ooo/Yqry1O1e3GhPrytCfH0Z6r/xbkmSJElztFDfm9f1N5XteFle6J9mrwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPPYklZ9SRnqdznkWdJx6kCz2T3LdOWYdLunF1V9dVnFnylC/KT3SZIkSZpfFVX827zWf0PZqjfMrP9tggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYL6YnDyjDHFXWcUvOtRZ0nHqcKM9vc6A5Unpdk+feW6Kqt5bhPrvvUeSJEnSAinETxch7st7gU6z2T3L5ggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOaoRntqvAj1Bx3gLOl4VoR4iwnL0VgxOXlOUdWd/MzsK6r4Oe+PJEmStOD7Uhni7bkbLm52z7NrAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAOaC33X1mUdV7yxAfdVizpOPcPywf3fYsk5bH03N599z8DeoUIe4rQ32/d0aSJEnSY5X3DA+UId6eu2Hm32XZTQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwCxUhtgtQv0JhzNLOiGHnlf180xavt6Ssc1PL6r4rWUV35m/QV/xrkiSJEl6knvNB8sQbyurzvMvuHTL+XZZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwivW0tpVFqN/uIGZJJ+yQ81C/27Tl/+vv33J2UdWdIsR9Zai/4B2RJEmSdFz2nlX9YBni7bkbLrh0y/l2XwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcDJNTp5RhrirrOIXHbws6YQV6i8vn9jRa+gucN3u6Y329LqiqvfmZ+JT3g1JkiRJJ7K893iwDPH23A0XXLrlfJsyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4gRrtqfEi1B90yLKkE36QeahfZuouVLsXN9rT64qq3pufhX/wPkiSJEk6RfvSr5Qh3p674YJLt5xvrwYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMdJoz31tCLE15dVPORQZUknvvjHiyYnzzB9F5ae1vSlRahfV1T133kHJEmSJM2mihAfyPuVt+f9yvNm/j2ZHRwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAByjItRry6o+6ABlSSeneKiopq8wfReGZa3OcP7d9xRV/ReefUmSJElzoSLEB8oQb891+/u3nG1nBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR6Hn8u65RYg3lVU85MBkSSftcPKq3msCz29LWvUlZYi7ylD/oWdekiRJ0tzew8bPFSHuy3vZTru980w7PgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAyNVufKsop/7nBkSSf1MPJQf6K33X2mKTz/9DS7F5Tj0zvz73x37rDnXZIkSdK8K8RPFyHuy23K26DT7AQBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFjwGu2ppxUh3lRW8ZDDkCWd7BqhU5vE88eKyclziqru5N92f/62POwZlyRJkrRgCvHjeT+0t9GeXmd3CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAglS24sayqj/m4GNJp6Ii1O8wieeD3YvLVr2hDPV/z93v2ZYkSZK04Av1vUWIP7qsPd1nzwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwLzXaE89rQjxprKKhxx0rPncsiqmraNXpyvHtqQe92O2HTB+fzm6vcdEnruWerHjwwAAIABJREFUVtND+bfck78nH/VMS5IkSdLj7X/jPbldzx7pLLGTBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABg3mmM1+uLUP+lQ401nwvhunTj0Nr0hoHxtLa1xT2ZhRXj8SUm8tzT0+xeUI5P78y/4d2eY0mSJEl6EoX4aL7eka83XNzsnmeHCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAnNZzeffcMtRvLKv6sIOMNR9bGWK6fmRDunXVWPpg7+r00ua6tKyK7s0srAj1+xct2r3YZJ4bGu2pp/WE+vqiir+ZvyOPeIYlSZIk6SkW6i/k6y8UIW5a1O2ebucJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMCcUozFqqzqAw4t1nxs49g16TWDE+kPe1ele1f2pjcOtNNw2ObezN6Dwx8pw/aWyTzb7V5cVPXVM4e8f/Wwd8+uJEmSJJ2AilB/Iu+7bp7593f2ogAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzHK7Fzeq+uVFFR9ySLHmU6vDVNrZXJ9uX9VMB1f2Huk9fYOpHr3K/Znthfhqs3n2WtKqL8m/0578O93neZUkSZKkk96B3Ct6WttKO1QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGaVRntqeVHFOx1GrPnUxrFr0s2DE+lDvf3p4MreIx1Y2Zf2DF2WVoboHs32Qrxvydjmp5vQs0t//5az82/Tzd2ee9SzKkl6si2rYhoIU0dqt7amibGtad3YtUfWbv+2a8Y2pzh69WO2Y/SqdP3IhsfshpHJtLO5/jF7SXNdunFo7df8Z88f/tf/7fTIv/5/bB7d/C9/L2tbW478fc4UwnX/8ve/3JpSkjQriofy9e5yfHrnxc3ueXauAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACcUmWI3aKKn3EAseZDA2Eq7WyuT7/V10wHV/Z+TftXjaYrx7a4T3OlVtxmQs8ejfHpdlHVe/M349OeT0maX11SxTQYtqWJsa1p/di16ZqxzSmOXp2uH9mQvmv4OenFw+vSjUNrj7Rn6LIjvXpgTbp5cCK9caCdblldpbesDunWVWPpl3K39Q8f6Xf7BtOd/YPpfX2r0z29q9KHevv/3fpsvjTzz/eB3Mw/72/3Dx355//VvPacuScz92bmHr1uYCK9Nt+zmfv3yqHLj9zPXc0rj6xdv214Mu0YvSptHd2UNo5dc+S3GMm/SV/oeEYlSU+qIsQH8nV/vm7KW7nT7GYBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADhpLrh0y/lFiPscOKy53vIQ0/aRq9JbVod0YGVfOriy92v6o5X9aefw+tTjXs2dQ8CreKspfeotH932rHJ8emdZxT/2XErS7Ko3dFLVui5d2bo2bRrdnOLo1ek/jGxI/3H4OeklzXXpxqG1ac/QZemmwTVp70A73bK6SreuGkvvXDWS3t3fTHf2DaZ7elc95tpJs6t7czO/1Xv7BtL/zr/dbf3DR37LtwyE9KaB8fSawYkjv/XLmmvT9zTXp+cPb0j16FXp6rHN6dLW1tQMU0fWy94bSVqAhfjxIsSbeqpOvx0uAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnVFFNX1GE+FEHDGsu12ptSzcOrU139g2mgyt7H7NfXTWa1rS2ul9zqKKKn3n2SGeJSX2KdLun5+/Dpvxb7M/Xhz2TknRiu6SKabR1XbqydW3aOropPW9kY3rR8Pr0A80r056hy9LrBibSW1aHtH/VWHp3fzP9ft9A+nBv3+OufaTH649W9qf35ufnf/UPH3meZp6rnxpop1cNXpp+cOiK9JLmunTDyGSqR65KG8auTVV+LntDx3sqSfOlEO/J7SrWTF9o4wsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwHHTbHbPKkN8dVnFQw4U1lxsWRXTN49sTP9j9Vj6s5V96eDK3sfsQ7396SXNdanHPZtz9YT6u0zrk29pNT2U7/9PFqH+e8+hJB1by3NjrevShtFr03NHr0ovHJ5M39e8Mr1y6PL0kwNr0s8OjKdfXjWafqN/OL23b+DIeuXx1jLSbGnmOZ15Xm/Lz+2+1a30pvwc//jQpenlQ1eknc316XnDG9PW0U1p7di1aSRsO7JeNw8kafZWhPhAUcVbG6GzedGi3YvthgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOGaN9tRgWdV/5ABhzcUGwlR6aXNdurNvMB1c2fuEvWPVSLqstcV9m5OHe9d35XF1mol9clzc7J7XCPV3liH+gedPkp54HbJ27Nq0dfTq9O0jk+l7h65Me4YuS28YGE9vW91K7+5vpvf1rk73foM1irQQmnkPZt6Hmfdi5v2YeU9m3peZ92bm/Zl5j2bep5n3ynyRpFNciPfl654lrfoSO2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ6Usuo8v6ziFx0YrLnWxrFr0s2DE+lPevvTwZW9T9iHe/vSjUNr0/IQ3bs5WFHFh5aG2DSxT7yZ+1yEeFO+55/x7ElaqF1SxVS1rkubRjen7sjG9N3N9em/Dl2RfnJgTXrr6lZ6x6qRdFff4JH1xTdag0g6tmber5n3bOZ9m3nvZt6/mfdw5n2ceS9n9gKj+T3tMbMk6QQXD+Xr3eX49M4lY5ufbtcMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDjWjE5eU5R1XsdDqy51CVVTNePbEhv7x9JB1f2HlW/nv+7V4xtcf/mdntM7RP7PShD7Ob7fIdnTdJCqDd00sTY1hRHr047m+vTnqHL0hsH2unWVWPpzv7BdKC376jXGZJObQdW9qU/6BtIt/UPp19YHdLNgxPpxqG16YXDk0fe8Zl3fXneQ5h9kvTUK0L8fO6WRnt6nZ00AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABfoxiNA0Wo/8SBwJorTbS2plcNXpbu6V2VDq7sPao+srIvvay5Ni13/+Z48c9XTE6eY3Iff0tDbBYh3lRU8TOeM0nzpeVVTON53bB1dFP6juHnpJcPXZFeOziR9q1upd/qH0of6u0/6rWEpPnRgd6+9Pt9A+mdq0bSWwZC+onBNekHmlembx+ZTNeMbU5jretSj/kpSU+uEP8sX1+xZGz7s+2uAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWuCJ0XlBW9ZccAKy50JbRTennVlfpQG9fOriy96j7zf5mWjd2rXs49ztctuoNJvfxc3Gze17Zii8qqvr/er4kzcVWhpjWtrak545sTC8eXpf2DF2Wfmb1ePq1/pH0e70DT3rNIEkzfWRlX/qdvqF066qxdPPARHr50BXpBcPPSdeObU6t1ra0rIpmsCQ9RkUVH8r7y18tw/TWRd3u6XbdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALSM/l3XOLqt7rwF/N9pZXMV0/siG9Y9XIEx58/3i9caCdekPHvZwPhfqtpvfxsTTEZhHiTfk78FnPlqTZ3soQ05Wta9PzRjam72+uTa8dnEi/vGo0vbdvIN17DGsDSXqq/enKvvSevsH0S6vG0uvzfuMHh65I3zH8nLR1dFMK4brUY3ZLUipC/YmZfeeSsc5Ku3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHmu0Z4aLEL8sAN+NZtbHabSS5vr0nv7Bo7poPsP9K5K3ZGN7uV8KdSfyrPrIhP82K2YnDynDLGb7+cdnilJs60VVUwTY1tTHL067WyuTz8xuCbdumos3dk/mA709h3TWkCSTlV/urLvyPyamWM3D06kG4fWputHNqSNY9ek3tAx9yUtsOKhI/vQvB9tt3eeaXcOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDPFFV8YRnqLzvQV7O1S1tb008Mrkkf6u0/5kPsf2XVaGq1trmf86rO803wY7M0xGZZxZ/Os/8LniNJp7IVVUwTY1tTHL067WyuP/K9v3XVWLqzfzAd6O075u++JM217uldlX6tfyTdPDiRbhxam64f2ZA2jl2TVoeO74WkeV0R4ieLKv748okdvXbrAAAAAAAAAAAAAAAAAAAAwP9j786j9Drvwo5LdhaSAk0IiT33HY0y7zbv+8673KsZRbIWj8baRhq990q2BwdI0jrtUUupSagoRmGxmpLaLVWK8YEekwXjYJbUrYtDix2TxDhOnDh26gVZaekS6JoFKDgJhGA/vTM0bRYvWmZ5l8/nnO+Zk5NjaeY+o+e5975//AAAAAAAAAAAAAAAAADoc6NbF14SJdnPG+CrXi1t7Q7vqbbD6fMYTn8q79r6tjAWp67pIA3dTrIP5tvYejv52bjugvy6dfPrd0/e036PJK1m5aQbLmvvC39z8tLw1tqW8EvVTrivNHFeZ7wkDUsPFKvh9nIz/LOJqXAsf7a5qjkbLmnPhY2JZxxJg1T6VP71/sKmw0cX31l6hgcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6DMXx2mjEGenDexVr7UhScOVzdlwR6V53sPn7ytNhAOtPa7rgBXF6Zc2TB0u2cnPzMbNBy+O4uzHoyT7b35/JK10G/NzfFtnLnxPc1c4Xt8abq4m4a5yPTwxXjrvc12S9PWdyvtQuRZuq7TDydp0uKaxI6St3WG6fSCMOpMk9XXpZ/N+KmqlE57qAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6QCFOrywk6ZMG9KqX2pik4erJmXBPqb4sA+bfORGHWjzv2g5icfojdvLnN7Ip21mIs1+JkvTLfm8kLXevzs/tmfa+8PrmTLiutiW8q9oJHyzVwhPjpWU5xyVJ59dDxUq4o9IMPzOxKfxQY1t4bXNX2N7Zv7R/O8ck9VFP58+0947Eh7+7XJ57sSd9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBes7BwYSHJTiwOpDWUV71SJe6Gaxo7wv2l6rIMj3+sWFr681zbwSxK0senpo6+0Ib+zDbOzHxLIU7fkF+nR/y+SFqOxpI0bO/sD6+b3BV+tL41vKOahN8q1cOpZTizJUmr3+L+vbiPv7Mahx+rbwmvz/f3ne39YWO+3zv3JPX4+4A/ipLsxrHpy4ue/gEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAekC0+fArCkl6tyG86pXanYPhrbUt4ZPj5WUbEL84HH5bZ871HdjSp6I422ZH/2ajSbccxekNUZL+gd8TSedaNe6GudaecLSxM1xf2xxuLzfDo8XlO6clSb3bqbwPlWvhlmocTtS3hKsnZ8Jse18o5meDM1JSr70byL/eU4jThXUzMy/wRgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYA2MTB3aVEjS/2LornqhzZ0D4fra5vBYsbSsQ+AXh79PxIdc48EenP2zdvSvdd0FUZKm+bV5f97Tfj8knU1J52D4ruZl4Xj9kvDOiTh8qFRb1nNZkjQYncp7f7ke3lFNwo/Wt4bvnZwJ2zv7w1iSOk8lrX1x+vtRnP342NSREe8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABWyWgn/d5CnH3RoF2tdbPtfeGd1Tg8MV5a3iHvxVL4+41LwqhrPNBFcfY/N3ayl9nV1617xUT6bYVNh4/me/tpvxuSzqSJ+FCYa+0Jx+rbwi35WfxAqbqsZ7Ekafg6lXdXuR5uribheH1ruLI5G5qdeeeupLUpTv8i/3pPlGTd/LF5vTcHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArYWbmBVGc3mCwrta6S9v7lgatn16BQe4Plioha17mOg9HVwz7tj42fXlxcV+PkuwP/T5IeraqcTccau0Jx+rbwjvy8/e3S7VlP38lSXq2PlKaCO+ptsOJ+pbw+uZM2NaZC2POZ0mrWBRnv5t/vXZk6tB3ekEMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALBMNm4+eHEhTj9skK7Wspn2vnBzNQmnV2hY+/vKjTDdOeBaD0Nxeucw7+lRku1evAaFJH3K74Okb6zdORi+p7krXF/bHO4sT4Ynxksrcu5KknSuncrPprvK9XDTxFQ4Vt8WrmzOhmY87xyXtKJFcfanhTh798imw1PeFgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnIcNSTpdiLPfMzxXa9We1t5wSzUOp1dwKPviMPZi3HW9h6E4++JF7e74sO3l5fLciwtx+oYozh71eyDpq5WTbphv7Qk/XL8k3FLphAdLlRU7ayVJWuk+XJwI786fHd+Sn2tXNmdDu3PQeS9phd4tpA8VNh0+Orp14SXeHgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnIUoSf923pcNy9VatLe1N9xSjVd06Prj46VwTWOH6z1MbcrePEz7+GhnvpDv428rxNnnrL+keudQuKo5G95Wf024szwZTq3gGStJUi/0QKkafrHSCT9W3xKumpwNSeegewJJy1j6mfx5+ycLrSOj3iQDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADyXmZkXFJL05wzG1Vq0r7033FKNV3y4+oeLE2FPa69rPkRFcfaJdQsLFw7DNl6YSrcU4uxXojj9c2svDW/NeD5c2ZwNJ+pbwp3lyfDEeGnFz1dJknq9h4uVcHu5Ga6vbQ5XT86EbZ25sCFJ3TtIOvfi7Cv58/fthU4668UyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMA3eMVE+m1Rkv2Ggbha7Q609oRfqbRWZYj6v6o0QzOed92HasB1+hcjU4c2DfYOft0F+f7dzX/ee6y5NJy1OgfDX5u8NLx9Yjp8oFRblTNVkqRB6KFiZel59K21LeF1k7vCVOeAewtJ51j67/Ov127sZC/zphkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGHobpg6XCnH6hOG3Ws32tfeGX620Vm1Y+s9VN4XxOHXth2+o9T8d1L27XJ57cb53v8H+LQ1f5aQb0tbucKK+JdxZngynV+kslSRpGHq4WAm3VdrheH1ruLI5Gybjefcfks68OPuTKE5v3tDpTnrrDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMpZFOd3shST9r6K1Wq+3tuXBzNQmnV2kg+uLfc6K+JYy69sM4yPr3XtlY+NZB27cvjhdemf9810Zx+j+sszQcFeNuSFu7l86z28vNcGq8tCpnqCRJ+ss+WpoIt1TjcKy+Lcy19iydze5RJJ1B9xfidGHdwsKF3kIDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEMhStI35n3ZgFutRknnYDhZmw6niqVVG3z++HgpvKE54/oPaVGSdQdpz94wdbiU/0w3FuLsi9ZXGvym2wfC0cbOcEs1XjrPVuvslCRJz9+pvLvK9XDTxFS4prEjzLb3hQ1J6h5G0jO/n4iz382/Xruxk73MG2kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYFCtLyTZCUNttRo14kPhRH1LeKxYWtUh5x8tTYTd7b3WYFiL018blA17ZNPhqShOb81/pr+wttLgVovnw+smd4WfnpgKH8nPsNU8MyVJ0vn3cLEcfrnSDj9a3xqONC8LE/mzsHscSV//riL74/z5/uaolU54PQ0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADIxXNha+tZCkdxhkq5WunHTDsfq2pcHiqz3M/N+WG2FT54B1GOIh1aOd+UJ/79bXXRAlWTffrz9iTaXBbEOShj2tveF4fWu4o9IMp4qlVT8vJUnSyvXEeCncXaqHt09MhzdOXhq2dubcA0n6v6VPFeL0fVGc7lm3bt16b6wBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgL412pkvFOL0IYNrtZJtTNJwtLEzPFCsrsng8lurnVCNu9ZiuPtb/bpPNxoLL8r36TfkP8OnrKM0eBXz8+nK5mw4WZsOHylNrMk5KUmS1q6Hi+VwW6Udjte3hrS1e+newD2SNNxFSfpIYdPhoyNTh17q7TUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0FcKU+mWKM7+p2G1WqnG8q6enAn3lmprNqD8+trmsCFJrccwD6OOs4+tW3fdBf22R79iIv22Qpy+KUqy/2YdpcFqqnMgHG3sDLdU4/D4eGnNzkhJktR7ncq7q1wPJ2vTS8/T0+0D7p+koS39bBSnN0TT2QZvsgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAnhcl6WujOPtTw2m1Eo3mvW5yV/hAqbZ2g8iLpXC0sdN6DHn5Xvfl0faRZj/tz69qdi+KkuwfRXH6v62hNBhtSNKwr703nKhvCXeV62t2NkqSpP7svtJE+LnqpvB9kzvCts7c0jO3eyxpuN5tRHH6nqidJt5qAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9qRCnbyok6VOG0molmmvtCXeWJ9d04PijxXK4qjlrPRQKcfaT/bI3X9TJXh0l2Y359/xFayf1f2NxunQmXl/bHO4vVdf0XJQkSYPVw/kz722VdjhW37Z0v7ExSd1/ScPT/YU4XVi3sHCht9wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQC9YX0iyf2L4rFaipHMw3DQxFU6v8XDxh4qVcKC1x5ooRHH2u6NbF17S6xvz6FTWiuL01kKcfcW6Sf1dMe6GK5uzS+fh4nn0qTU+EyVJ0nD0SLEcbqu0w/H61pC2dofxOHVvJg38O4/0Pxbi9E0jU4de6pU3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAmNs7MfEuUZP/C0Fktd6W4uzS4+7Fiac0HiX+0NBEube+zLlrs6XzP293L+/LIpmxnlKT/ZvF7tV5S/zYRHwpXT86Ed1U74dFiec3PQkmSpMV7kl+rtMJb8mf1bmv30nO7+zZpQIuzz+X9w42bD17sDTgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsGo2drKXRUl6r0GzWs42JGm4enImPFCq9sTQ8PeX6yHpHLQ2WipKsl/s1T15ZOrwjvx7vMc6Sf1bNT60dAbeUo3D4+OlnjgHJUmSnq1T+f3Kv6o0w4n6lnC4uTuUk657Omng3oOkX47i9NbRqazlbTgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsKI2JGkUJekjhstqOZtv7Qm/UZ7smQHh/7rcDJPxvLXRXxann7+ofeRVvbYfR3G6J4qzB6yR1J8V4264sjkbbpqYCo8Wyz1zBkqSJJ1tp4qlcGf+TH+iviWkrd1L9znu96SB6v4oybrr1q1b7+04AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALCsRttHmlGS/leDZLVcbe4cCDdXk54aBn5bpR0qBoDra4o62V/vnZ34ugsKSffy/Pv6pLWR+q/F8+UNzZnw7mocHh8v9dT5J0mStFw9ViyFX620wo/ULwn723vDWJK6F5QG4f1Ikv1OlKRvbDQWXuRNOQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABw3gqdbFeUpH9kgKyWo3LSDcfrW8Pj46WeGvx908SUYd/6hoHR6b35Frh+7Xfh6y6IkqxbiLOHrYvUX43FaUhbu5fOmH83Xu6pc0+SJGk1erRYDrdV2kvvARbvizx3S33f/8o7Mdaaf7m35gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAOSkk3cujOPtTA2N1vo3lfd/kjvCxYrXnhnyfqG8Jo9ZIX1OUZH82MnWotrY78HUXFOJ0oRBnp62J1D8tnidzrT3hp2rT4cFSpefOPEmSpLXs4WIl/EI1Dj9Q3x4ube/zLC71a3H2J1GS3RhNZxu8QQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzlhhU/bmQpI+ZVCszre0tTvcXar35EDv4/VLrJG+qShJf2yt9t6pqaMvHImzv5F/H//ZWkj90/b2XH6mbA0fLNV68ryTJEnqxT5erISbq0k42tgZks5B95VS/70/+XIhSX9hQ6c76W06AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPBc1heS7ITBsDrf2p2D4aaJqZ4d3n1tfZt10jP1qXJ57sWrv/Ved0EhTheiJPsP1kDqj5rxfPiB+vbwb8qTPXvWSZIk9VN3l+rhbfXXhMtbl4VS3HXPKfVX90dJ1vVqHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4ejMzL4ji9FZDYHU+jSVpuKaxI3xyvNyTQ7pP5/1Afbu10jP19MjU4R2ru/Fed8FIfPi787/7U66/1AdnXJyGtLU73FxNwqnxUk+ec5IkSYPQqbw7y5PhRH1LmGvtCRuS1P2o1AdFcfax/OsVi+87vGwHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgCHXaCy8KIrT2w1/1fk039oT7i7Ve3Yo9+m872/ssFZ6lsHP6c2ruO2uj5KsW0jSf+faS73fts5cOFHfEh4oVnv2jJMkSRrkHixVws3VJBxt7AybOgfco0q9/47lPxXi9E0jU4de6s07AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyhxeGmUZzeZeCrzrUJ4EfRAAAgAElEQVR252C4aWKqpwdwnyqWwhsnL7Veerb+11hr/uWrsefm++2eQpw+5JpLvd1kPB/e3NgefrPc6OnzTZIkaRh7f7kebqhtDlc0Z0Mp7rp/lXq29LP51xOr9c4FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOgBr2wsfGsUZx8w4FXn0ljeDza2hUeK5Z4etn1qvBReN7nLmulZi5LsqpXeb6M43ZP/PQ+63lLvtiFJw1xrTzhZmw6P9vjZJkmSpK8+8xfD7eVmOFbfFmbb+9zXSr1YnP1JlGQ35s9ckTfyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDAxlrzL4/i7GMGu+pc2tXaH+4sT/b8cO3fGS+Fq5qz1kzPWr4P/uZK7rUjU4d3REl6r2st9W6tzsFwrL4tfLBU6/lzTZIkSc/dh/J7upO16fA9zV2hEnfd70q99A4myf4sitNbC/F8xdt5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgwGzcfvDiK08cMc9XZVo0Phetrm8OpYqnnB2k/Pl4KC81Z66ZnL86+ODZ9eXEl9tmRTnd7FGcfcJ2l3mxDkoa0tTvcXE3CqfHeP9MkSZJ09j1WLIXbKu1wrL4tzLb3uQ+Weqb0qfzrezd0upPe1AMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAALg4uXxjlGT/wfBWnW2vbe4KHylN9MXg7MfHSyFrXWbd9JxFcfZDy73HFjZ1txbi9H2ur9SbtTsHw1vql4T7S9W+OM8kSZK0fH2wVAs31DaHI83LQjHuuj+W1r6nF9+hRMnhS7y1BwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIA+FbXSiUKc/r6BrTqbOp358I5q0jdDsk+Nl8JCc9ba6TmL4uzRqamjL1yu/bWQdNv5n/te11bqvUbzDrX2hJ/Pz7LFM6JfzjNJkiStXI8Wy+E91Xb4/saOMN0+4L5ZWvvuj5Ksu27duvXe4gMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAnyjERzqFJP2MAa060zYkafi7jR3hkWK5b4Zin8r77uYu66fnLk7/YjQ+tHk59taL47SR/5n/2nWVeq9q3A1HGzvDXaVG35xjkiRJWps+VK6F62ubQ9raHcbcS0tr+c7mofzrFevWXXeBN/oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0MM2JOl0IU4/bzCrzrTNnQPh1yqtvhqA/cR4Kfy1yUutn563KMluPN99dbQzX4ji9OZCnH3FNZV6q12t/eFkbTo8Uiz31TkmSZKk3ujBUiXcXE3C1ZMzoRp33WNLa/HuJk7/Y2HT4aPrZmZe4O0+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPSY0fjwTCHO/sQwVp1JY3nH6tvC4+Olvhp4fTrvbzV2WkOdwVDm7L8Xpxb+6rnuqa9sLHxr/udca1+VeqsNSRqubM6G2yrtvjq/JEmS1Ns9Viwt3WNe09gRks5B997S6vefC3H6pnJ57sXe9AMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABADxjpHN4XxemXDF/VmXRpe1+4szzZl0Ou39zYZg11Ro3E3exc9tPF4c2FJP3BQpx+3nWUeqdqfChc09gR7itN9OX5JUmSpP7qrnI9nKhvCXOtPWHU/bi0esXpp6P48Pctvp/x1h8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1shI3N0bxemXDF3V8zUep+F4fWs4NV7qy4HWP9TYZh11RkVx9i/PYTtdX4jThXw//U+uodQ7be/sDycnpsOjxXJfnl2SJEnq/z5Smggna9PhiuZsKMZd9+nSqpR+Jv967cjUoZf6BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVtFI3N0bxemXDFnV87W3tTfcU6r37QDr4/VLrKPOrDj740LryOjZ7KX5Pron/+8edv2k3mhDkoaF5mz45Uq7b88tSZIkDWaPFMvhHdUkvKE5EybiQ+7fpZV/z/O5/OuJjZ3sZT4NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAVNhJ390Zx+iXDVfVcjSVpOF7fGk4VS307sPona6+xljrjok3p95/pPjraPtKMkuw3XDepN3p1fmZdPTkT7i43+vbMkiRJ0vC0+K7l9nIzXNPYETqdeff00koWZ38cxekNo42F7/DJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsgCjJdkdx+iUDVfVc7WjvD+8rN/p6QPXJ2rS11BkXxdnH1q277oLn20PHpi8vFpL0l/P/5mnXTVr7JuP5cKy+LXy0NNHXZ5YkSZKGtyfGS+HO8mQ4Xt8aLmnPuc+XVqo4++MoSd82MnXoO31KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADLpLCpe1khzr5oiKqerbG8Y/Vt4XfGS309kPrd1XjpZ7GmOsOhyl8pxEc6z7V/buxkL4vi7O1Rkn7ZNZPWvs2dA+H62ubwaLHc1+eVJEmS9I3dVa6HE/UtYa61J4y695dWoPTJKMmuH5k69J0+MQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA8zCyKdu5ODDU0FQ9W9va+8Ovlyf7fvj0eyutMB6n1lRnXBSnNzz77nndBYU4fUO+f37GtZLWvtn2vnDTxFQ4VSz1/XklSZIkPV+/XaqF62ubQ9raHcY8D0jL3ReiJLtx4+aDF/v0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADO0simbGchSZ80KFXP1IYkDW9ubA+PFUt9P2z635YbYSI+ZF115sXppy9q7/0rz7R3Rkm2O4qzR10naW0bzbuidVm4vdzs+3NKkiRJOtceKFbDydp0SFu7w5jnBGk5+0KUZDdu3HzwYp8kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAZGNmU7Swk6ZOGo+qZasbz4dZqZyCGS3+4OBGSzkHrqrOrk85/474ZtQ9X8//vva6PtLZtSNJwZXM23FmeHIhzSpIkSVquHipWwk0TU0v3y2P5fbPnB2lZ+kKUZDdu3HzwYp8qAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMCzGJk6vKOQpE8aiKpn6qrmbHiwVBmIYdIfL1bCJe0566qzKkrS2752zxxrzb88itMboiT7M9dHWrs2Jmm4enIm3FOqD8QZJUmSJK1kDxUr4aaJqXBlc3bpXtozhXTefSFKshs3bj54sU8YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOBrFDrZrsUBoIag6hurxN1wsjY9MMOjHy2Ww772XmursypK0j94VbN70dKGOTPzgtEku6YQp593baS1q5SfT9c0doT7ShMDc0ZJkiRJq9lDxUq4aWIqXNmcDRuT1HOGdF6lT0ZxesPI1KHv9GkDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENvZFO2s5BkXzD4VN/Y7vbe8IFSbWCGRZ8aL4Ujzcusrc660Tj7m4v7ZaGT7YqS9HHXRFq7qnE3/HD9kvDxYmVgzidJkiRprXuwVAlvn5gOWfOyMJaknj2kcy59MorTGy6OF17pkwcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhlIhPtKJkvSPDDvV1zaWd6y+LZwaLw3McOjTeW+cvNT66uyL0/tGO/OFKE5vzf/3066JtDZV4u7S2fSJYnVgziZJkiSpF3uoWAk3TUyFK5uzYWOSeh6Rzq0vRHF6w1hr/uU+hQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgaFycHK4XkvSzBpzqa0s6B8Pt5ebADYS+tr7N+uocSp8qxNm7869PuhbS2jQRHwrH61vDQ8XKwJ1NkiRJUq/3iWI1vH1iOhxq7QljceoZRTrLojj933k/8R2vmft2n0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMNCi6WxDIU4/bbCpvraF5uzSsORBGwD9zyeSMGp9JamvqsbdcKy+LTxUrAzcuSRJkiT1Yw+WKuFkbTrMtfZ4zyKdZVGS/kH+9cR3vGbu2306AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAuah95FWFJPuUYab6amNJGk7Ut4TTAzjw+fZyM7w6//mssyT1R7V4PvxEbWv45Hh54M4kSZIkaVD6ULkWfry+NWzv7PccI51Ncfa5/Ou1o1sXXuKTCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQnFq4a8WkuyTBpjqq23qHAh3VJoDOeD53lItNON56yxJfVA17oa31C8JDxcr57X3f/w8/3tJkiRJZ9dvlhvh7zcuCdOdA55tpDMu/Uz+9dqNMzPf4lMLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPrWyNShlxbi9MMGluqrXdWcDQ8VKwM50PnhYjls7+y3zpLU4xXjbrimsSM8UKye997/ifzP2NKZC3eXGwN5tkmSJEm93l3lejhW3xZanYOed6QzKU5/P+9N5fLci32CAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBfaTQWXhTF6V0GlWqxYtwNJ2vTAzvA+VRe1rrMWktSD7cxScPRxs7w0dLEsu393dbupT978c8d1DNOkiRJ6oeeGC+F28vNcE1jR5iM5z0DSc9XnH66sOnw0XUzMy/waQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACskijJdrsKcI5mZl5QSNI7DCfVYknnYPj18uRAD27+O5M7rLUk9WhjSRqONnaG+0oTK7b3j8dpeKBYHeizTpIkSeqXHh8vhXdVO+G1zV3h1fnzgOci6TmK0yfyrly3bt16H2wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADACiok2bVRnP75d7xm7ttdDThr6wtx9i4DSbXYFc3Z8FCxMtCDmt9Wf421lqQebDTv9ZO7wgdLtWXf+//JxOZv+vt+pH7JQJ93kiRJUj+2+F7qn9amw/723qVnBM9K0jMXxeljhThd8PEGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALL/1UZz+zP8bJNhJ510SODuFOLvJEFKNxWk4Xt8anhgvDfRg5vdU22HMektSz5W2doc7y5Mrsve/t9IKG5P0m/7OWjwfHimWB/rckyRJkvq5+0oT4UR9S9jSmfPcJD1LUZJ+KEoOX+KTDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFge6wtJ+rNfNzwwzt7ussCZK8TZPzR4VM14PvxypT3wg5jvLjdCJe5ac0nqobZ39odbqvGK7f33lmphMj/nnu3v/8cTmwf+/JMkSZIGoTvLk+Gaxo6l91iepaRn7J6onSY+9QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBztbBwYSFJf+EbhwZGcfqYiwNnJv839IMGjWq2vS/cW6oN/ODlT46Xw/b2nDWXpB5pU+dAOFmbDk+Ml1Z27+/sf87vY7p9IJwqlgb+HJQkSZIGpcX799sq7XD15Ewoxl3PV9LXlT4Vxel7xqYvL/oEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM7GwsKFUZL94rMMDXx64+aDF7tI8NyiTYe/a3HApiGjw93Rxs7wO+OlgR+2fDrvtc1d1lySeqBmPB9uqG0Op1b4/Hki//OvaF12Rt/TO6vxwJ+FkiRJ0iD2iWI1/FRtOuxv7w2jnrek/1cUp3+ed/OGJI18GgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADPZ2HhwihO3/NcwwJH4sPf7ULBsxtN0kujOPtTw0WHt1cnafjpiamhGbD8lvpW6y5Ja9x4nIYfamwLDxfLq7L3/73G9jP+3va19w7NmShJkiQNah8s1cLx+tYw3TngGUz6anH2xSjJbryofeRVPhkBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAZzA1dfSFUZzefgZDAt/lasEzuzhOG1GS/aGBosNbu3Mw3FFpDs1A5V+qdMJYnFp7SVqjRvO+p7krfKhUW7W9/6aJqbP+Pv9leXjORkmSJGnQu7M8GY42doZy0vVcJuVFSfpHhTh7y0XtvX/FpyQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwfzUaCy8qJOkdZzQgMM5+zxWDbzY2dWSkEKefNkR0eNvV2h/uK00MzQDle0u1UO8csvaStEbtbu8Nt5ebq7r331meDMW4e9bf61XN2aE5HyVJkqRh6eFiOdw0MRXS1u4w6hlNWvz87HP512sXP3PziQkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDbXG4XyFO33d2gwHnK64c/H+vmEi/Lf+38UmDQ4e31zdnwqPF8tAMTX4k/1m3d/Zbe0lag5LOwaXB9adXee//SGkidDrz5/Q9b0jS8IFSbWjOSUmSJGnY+q1SPRyvbw1TnQOe26Qk/ff51yvWrVu33qcnAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADJ+FhQsLcfqrZzsQMErSv+3iwV+amjr6wihO7zIodDgbi9Nwor5l6AYlv25yl/WXpFWuGh8Kb61tCY+Pl1Z933+0WA67WvvP6/v/O5M7hu68lCRJkoatU8VSuLXaCd87ORNenaSe5TTURUn2YKGTzvoUBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgOGxsHBhlGS/dI6DAP+FCwhL1hfi7N0GhA5n1bgbfqEaD91w5LfWtlh/SVrFRvOunpwJDxSra7Lvn857/eSu8/45ivm5+fFiZejOTUmSJGlYeyi//z9Zmw5zrT2e7TTs3RN1stjHKQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAy69VGS/fw5DwCM08+vW3fdBS4jwy7/9/APDAQdzrZ05sIHSrWhG4b8q5VWGLP+krRqXdbeF+6oNNd07z9e37psP89b8j9r2M5OSZIkScVwd7kRjtW3hWY871lPQ1r6VP71vRe1u+M+WQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAQrS8k6c+e7wDAkalDm1xKhtlInP0Ng0CHs/3tveFjxerQDT9+IP+Z252DfgckaRXqdObDz1Y3hdNrvPe/o5qE0WX8uZrxfHisWBq6M1SSJEnSX3ZqvLT0nJE1LwsbktTzn4auKEm/HMXpzRe1j7zKpywAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjEKcnVyOwX8jSfbDribDajTpzuX/lr5iCOjw9brJXeGxYmnoBh4/MV4KWesyvwOStMJtTNJwTWNH+OR4ec33/t8oT4ZS3F32n/FkbXrozlFJkiRJ39z9pWo4Ud8SNnUOeB7U0BUl2R8ufs42unXhJT5xAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoK8V4uwtyzj07/2uKMNoZOrQpkKSPmnw53A1mne8vjWcHtIhxz9R+z/s3XuYZWdd4PsG5AF1BmdwNPTelerUvt/32lXVt0p1qu9d1V21dhPTCQRFo6YVQzsywaPhKGkICAdPIhDITDRIjIaBiEQ6gIkIragJkAuGpLtzjuc5owcVx8vMqOAV8ju7ysATY25935fP53m+D/9p117vet+1sv74bbAOJOk0d3FjaxwuVPpi378nV4pOe/dp+Ts3tubj6ER+JM9TSZIkSf+6I7l8vLeUxEWNLTGepN4PNVJlOukXen3vqlVXP9fXFwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZOttP9gVM66C/p/t2aubkX+mUZJee0u+f11v4XDfscrc7rpPHu0uTIDja+vdiI8Y6BxpJ0uppuLcTNpaR/BtpP5GOhue20/s3v7aO/V5IkSVL/dHe+HAer61fek7wvaqRK0qOZyb2LvsIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDKTey/OJulXTvmQv3a6xa/LqHjxuvkXZTrdhw34HK2q7cW4rdgc2UHG9+WKMdk2xFiSTkfjnTQO1Gbj93KFvtr799c3nfa/faG5bWTPVkmSJEnP3NGJfNxabMWljc2xpvfu5B1So1ImSe/MdpZavsgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQ1zKd7rZef39aBvwl3Tf5hRkNVz83m6SHDPUcrTa25uNwoTKyw4uP9fqOxhZrQZJOQ4vN7XFXodZ3e/81lfVn7De4vdgY2TNWkiRJ0rPvvlwxrq1Mx/ntXd4nNSKlX+39720v6Vy4xrcZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+s5Ye++6bCf9m9M12C+TdO/xKzMKevfRTxvkOVpta+2Iz+SKIz2w+JrKemtBkk5xnfbu+LlSpy/3/VtK7RhP0jP2W7yiPjfS56wkSZKk4+tYr/cXm/Fdjbk4r5N6x9Twl3S/nEnSt7543fyLfKUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgL7wkSWuZTvqXp3egX/qVNe3uv/NrM8wyydJ3G+A5Wn1HY0s8mCuM9JDiDxfqscZwYkk6ZY33+k+18+P3+vR8uatQi1KyeMZ/k8P5ykift5IkSZJOrM/kinGwuj7Wthe8c2royyTdL2Yn9+5ftW/f83yxAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4KwZn3rp6myS/sGZGOa3Olnq+sUZVpmkO5PpdP/e4M7R6bL6XByZyI/0UOL7csWYNpBYkk5Zm5u74lCh3tf7/rqztO8fqM2O9JkrSZIk6eQ6OpGPW4utuLSxOca9f2rYS7rHskm6z5cbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzrhvLaf/NtvpPnCmhvhlkvSdfnWG0eqpxfHeGv9TwzpHpx+tbYxjhhHHd9Y3Ww+SdArKJ0txsLo+juTyfbvnH+m11Nx2Vn+jz+aLI3/2SpIkSTr57s6XV97BOu3d3kk11GWS7icyrbTjKw4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnxNTU/udnO91fP6MD/JLuMb88w+ac1o5vznbSzxnQORqN9bqmst7w4V7vKk9aE5J0CrqkviV+J1/q+33/itrsWf+trnYGS5IkSTqFHZnIx42lTuxpbl/5737eUTWcpV/t/e/N2eZLx3zRAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4HR6zsoAvbMwvG/11OK4n5+hupeS9AOGco5Gazpp3FDuGDjc67dz5Sgni9aFJJ1EnfbueE+pPRD7/nXl6b74zZq93+yhibyzWJJ0VjvSO4vuyxXj7nw5Dhcq8WuFWhwq1OP9xWbcWmzFjaXOyrvjtZXpla6prIuD1fUr/WR1Q1xZnfl6r6rPxv7appW+t35BXNrY/PW6za2RNretNN/cHltaO7/edGvh6y2fj8vvZ8fbqTyjx3vvy0/8v7/8rPP4f+fa9sK/+BuWW/67vvY3fq2XP+43WO6Vjbmv/0bL/UCvr/1+V1f++Xd9W3ntym99Q2ly5fe/udheuRa/3Lsmy9dm+RotX6tP9a7Z8rW7v5e1LOmJ/XqhGgdqs/6bl4a3pPvlTJK+9VvL6b/1aQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBTLtPp/tTZGtq3Oul+nyvAsMgm3WsM4xyNislS/Ndi04DhXkcn8rGnud26kKQTbDxJVwa1PzBRGIh9//ZiI87rpH3z+72jPOU8liQ9bUdy+bgvV4zD+Up8tFCPX+69y91Sasd/KU/GtZXpeFNlXRysro8frW2MK6szsb+2KS6vb4pLG5vj4sbWSJvbYldrR2xp7YwN7fmYbi1Etb0YpWTRs8wQVu5d1+Wm2gsr13qud92Xr/1Cbx0sr4V9jS0ra+N76hesrJXlNfO66oZ4Y2X9ynq6odyJny8lcWuxFYd66+2uQi1+q7f2ltfgEfejNJA9mCvEdeXplb3APqlhLJN0/zg7uXf/qlVXP9dXHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE6JbDu9/KwO7EvS97sKDMW9lKQX9db0o4ZwjsaA7Q8VG4YKP9by4HDrQpJOrPNb83H7AJ0p9+RL0W7v6avfcK6103ksSUPa53P5uCdXik/mK3GoUI/3F5vx86Uk3lWejLeV18bB6vp4bW0mrqjNxvfUL4hLGltiqbkttvTOhnXthWgkeyKXLHnmUF91Xidd+e8K062FOL+9K7a1dkTaW7eX1LfEKxtzsb+2Ka6szsTrqhtW3revrUzHDaXJeE+pHbcWWyv3wl2FWtydL8eDuYK9QjrDfbh3D35/78xxvmgoS9L7Vk92N/naAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwEnJdLpL2ST9ytkc0pfppH+5at++57kaDLKxZHFtJkn/1uDN4W95KPtHC3VDhB/rzkI1JpLU2pCk42y8k8b/Vt0YD03kB2bPf7j3b51vbu/L3/MDxaZzWZL6uM9NFOJT+XJ8pPcu9b5iK/5LeTLeVl4bP1ndED9SOz8uq8/FRY0tsau1I2Zau1beu5bPSs8M0jO3/E7eaO+Jja352N7cEXsb2+K7GnPxqvpsvLY2Ewer6+Pa8nTcWOrErb3771DvPvxkvhKfzRfjSC5vj5JOsHtzpXhDZV1MtRfsRRq2Hs0m6ftf0rlwjS8/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHLdz20v1bChxaxIAACAASURBVNL9q34Y0jfW3rvOFWFQjU+9dHWmk37BsM3hr9neHXflqwYHP9ZDE/m4oLXT2pCk42xza1d8pFAfuH3/VfXZvv1NL25sdTZL0hl6B/idfCk+VqjFB4rNuKmUxLXl6bi6sj5eU5uJ769fEJc0tsRCc3vMtOdX3qHO66TOf6mPKyZL0endq5t6z6jL9+6+3j18WX0uDtRm43XVjfHm6rp4R3kq3lNqx23FVny09xz727lyfD6Xty9KvY707oXl83Cxd//YUzRMZTrpP2Q63Xe8eN38i3wFAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4FlZs3b3S7JJ9w/7aDjfT7gqDOS9NDf3wt76/Ywhm8PfVHshPpmvGBb8uF5Tm7E2JOk4Gu+kcWV1Jh6eyA/cnv/O8mRf/7bn9n5b57QknVgP9c6lu/PluLNQjVuLrbi+PBVvqaxdObMuq8/FRY0tsaW1M1rt3Sv7rTNd0tfKJUsre8NMez7mm9vj0sbmOFCbjauqG1b2keX9ZHlfWd5flveZI/ZcDXm/ka+u3AP53r1hj9DQlHT/PJuk/3HVvn3P80UIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACApzS2Yd83ZjrpZ/prKF/6KVeGQZRJ0l80WHP429iaj9/OlQ0Hfly3FZsxnqTWhyQ9y7Y3d8SdhepA7vm3FxtxXqf/9/zl4fXOaEn65x6ayMfd+fLK2XNrsRXXl6fiLZW1cWV1Ji6rz0Xa3BYz7flotXfHuR3P9ZLOXLlkaWXv2dLaGRc1tqzsScvPcVdVN8S1lem4uZTEBwuNlf1reR87Zk/XAHZ/rrCynpf/m6L7XkPUA9l2d7OvQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADyZ52Q66a19N4wv6f5Tbmrft7g8DJLVnaVXG6Q5/M21dsY9uZKBwP9iMHAxJtsL1ockPYsmkjSuqayPI7n8QO759+RL0W7vGYjfupQsrQyvd1ZLGuaOTuTj7nw5Plyox02lJN5aWRtXVmfiu+sXxEJze2xsza/sh85gScP0PL38PHpBa2ekzW3xXY25OFCbjat7z9jvLE/GLaV2fLS3Jy4/ty7vkc4K9du5/d7eeb28dsfczxqWkvSOc6f25n0hAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4OuynfSN/TqIb3Wy1HWFGJh7aSpdn+mk/2CI5nC3vbkj7ssVDQF+Qvvrm6wPSXoWbWvtiLsKtYHd749M5GOhuX2gfvM3VdY5qyUNdMvvH4cK9bi5lMS1lem4sjoTl9XnIm1ui+nWQox3UmesJD1N5WQxZtrzMd97jr20sTkO1GbjYHV9XF+eiluLrbizUI2782Vnjs54n8hXVs715TXqXtWgl0nSf8x0uu948br5F/laBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMOKySbov2+k+2r+D+NJ3u0oMgnNaL/32TCf9guGZw93m5q6VgfaG/v7L3l9sxpj1IUlP25pOGq+vbIgjA77nv6o+O3C//XRrIY7k8s5sSX3XwxP5OFyoxG295+l3lybjDZV18erabFxS3xLbmzui1d4d5/bOD+eoJJ2ZcslSrG0vxK7WjnhZY3Nc0duTf6K6Pn6mPBU3F9txqFCP382XB/6ZXv3X/blivLm6bmX9uRc16GWS9E+yk3v3r1p19XN9OQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABhB53bS6WzS/XJ/D9/r/r4rRd/bt+952U56l4GZw93m1q64N1cy6PcJPZgrGPgrSc/QXGtnfKxQG/g9/7ry9MBeg5tKiXNb0hnvSC4fn8qX47ZiM95ZnozXVTfGZfW5WGhuj057d5zbSZ2TkjSAjfVqJHtitrUruo2tK3v7ldWZ+KnK2pXnztuLjfjd3v6/fA44D3U8HZ3Ix83Fdiw1t7nXNPBlku69vWZ8QAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABghL+lcuCbbSf/7IAzeO3dqb94Vo59lkvSthmQOd3OtnXFvrmS475N0oDZrjUjSUzTe68rqTDw8kR/4/f72YiPO66QDey0Wmtuc25JOS/flinGoUI8bS504WF0f+2ub4qLGltjSe4fIJUvOQ0ka8crJ4sqZsHw2LJ8Ry2fF9eWpuLXYisOFShwZgncFnZ4+VqitrBnPExrs0q/2eu+atbtf4ksSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAkBvbsO8bs0l636AM3cske1/lqtGvMp007a3TRw3HHN4uaO2Mz+aLhvk+SbcXGzGepNaJJD1J57fm41ChPhT7/T35UrTbewb+mtxRqDm/JR139+WKK/vHTaUkrqmsjytqs/Edza0r+3wuWXLmSZJOqnM7abTau2N7c0dc0tgSr+6dM2/snTc3lCbjl4vN+M18JR6eyDuTR7jl97Efr26MerLHPaNB7ku9DhYK8y/wVQkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGBIZTvp+wZp2F4m6X7IVaMv76VkTzGTpP/LQMzhbVNrV3wmVzTA90l6aCIf57fmrRNJekJjvfbXNsWDucJQ7PdHevv9QnP7UFyby+pzznBJT/lse2ehGjeWOnGwun5lH0+b26LZ3u1skyT1ReVkMWba8yvn0/I5dVV1Q1xbmY5bi62VM+yBiYIzfQSeV64vT8X57V3uCQ1smaT7+9kk3efrEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwJDJtNMfHbhBe0n3r6am9j/f1aOfnNPa8c2ZTvqQQZjD28bWfNyTKxna+xS9tjZjnUjSE2q2d8cvldpDtd//YG3T0Fyf8zpp3JN3tkuj2kMT+bizUI2bSkkcrK6Py+ubYqG5bWXvdoZJkoaherIn5lo74+LG1jhQm42fqqxdOfc+UqjHfbmi54Eh6Viv5ffObu86j1n3Gtw+fm57qe5LEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwBDIJOn2bNL9p0EcsLd6au+sK0hf3U+d7i8YfDm8bWzNxz35kkG9T9FHC/UY76TWiiQ9rksaW+Kz+eEaVH9deXrortPrqhud5dIQd6TXJ/OV+MVSK95SWRtX1Gaj29wa0+2FONfzqyRpxCsli3FBa2fs6727HOidkW+uroubSkncUajFfbmiZ4kB7K58NS6vb4qJxHOOBq9Mkv5jptN9R25q37f44gQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCgxqcvzGU66V8O7oC99I2uIv1irNM9YOjl8La2vRB358sG8z5FR3ptae20ViTpsYrJUvxMeWro9vvbi404rzN8g9mb7d3x8ETemS4NePfnCiv71HXl6XhNbSYuamyJDe35WDOE+5YkSWeqUrIYm1q7Yl/vXH11bTbeVFkXN5WTuKNQi3tzJc8gfdyne9fnddUN0WjvsZY1iP1pppNetmrVquf4+gQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBAzmnt+OZMkn5+kIfqZZLup11J+kF2cmlDppP+g0GXw1m7vSd+M18xjPdpen1lg7UiSY+1o7kjDheG79y4O1+OVnv30F63G0qTznRpQLo/V4jbi424rjwdP1KbiW5ja3SGeH+SJKmfKyVLsam1Ky5qbIlX12bjTZV1cVMpiTuKtbg3V/Ls0gc9NJGPd5SnVq6TNasB/A54b3YqXe8rFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwGB4TjZJ3z/wA/WS9CtjtX0vdjk5m769sXROptP9IwMuh7Nashh3FqoG8D5Nv5WvRD5Zsl4kjXzjSRpXVTfEkSHc6x+eyMeu1o6hvn47e3+fc13qr+7PFeP2YiOuK0/Hj9TOj25ja3Tau505kiQNUMVkKWZbu+KixpZ4dW023lRZFz9fSlb+e9vnc3nPPGewY71+sdSKxeZ2a1MDVvrVTJLe8pJk37f5IgUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANDHskn648MyTC8zufdiV5SzZm7uGzKd9LChlsM79PdQoW7o7jP0HY0t1oukka/T3h23FZtDu9f/QG3TSFxH5750dro/V1i5/64vT8WV1Zm4qPd8Od1aiDHniyRJQ185WYwtrZ1xaWNzXFXdEDeWOivPBffnip6TTmMf6f3Gl9XnYtwa1CCVdP88204vX7Xq6uf6OAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANBnVidLO7JJ+pVhGaKX6aQ/56pytmQ76RsNsxzO1nTS+KVi25DdZ+jnSh3rRdLId0l9S9ybKw3tXn9deXpkruX31S9wvkunsSO97ixU44bSZFxZnYluY2t02rudJZIk6UlrJHtiR3NHfE/vOf111Q3x7t4zxO3FRnwmV/RsdYo6nK/EFbXZyCVL1pwGp6R7f6azd6MvVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH1i9dTieDZJ/2KYhudlOukXXFnOhrFOekHvfvqKIZbD13iSxs+VOgbrPkMP5gox2V6wZiSNbBO98+ItlbVDvdcvD6w/r5OOzDVd/lvvyZWc89Ip6IGJQhwq1OP68lQcqM3GfHN75JIl54ckSTpl72Mz7fm4tLE5rqzOxLWV6bi12IrDhUocnch7HjvO7s8VV95vW+3d1pcGpUczSXrLOa2XfruvVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGfR1NT+52eT9O5hHJ63emqx4gpzJo039/z7bNL9Q4Mrh6+xXj9TnjJM91n0I7XzrRlJI9tMa1d8rFAb6n3+nnwp2u09I3dtr66sd85Lx9nd+XLcXEriYHV9XFafi5n2fJzbSZ0XkiTprLSm9xwy3VqItLkt9tc2rTyjLD+rHC5U4ohnt6ftoYl8XF+eio2teWtJA1Gm0/0f2ST9j6v27XueL1cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnQTbpXj+0g/OWB+bBmfOc3rr7VQMrh7O3VtYaoPss+lihFuPWi6QR7Qdrm+LBXGGo9/mHJ/Kxs7VjJK/vZHshjuTyznvpKfaGO4q1eHt5Kg7UZmN3c3uUk0VngyRJGpjWdNJY356Plza2xhW955n/o7w2bi224lP5sue9x7X8TvSzpU5sbe20bjQgpZ9b3V463+crAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAMygzuffiYR6Wl+l0P+Iqc6Zkk/SHDagczv5T7XxDc59Fx3rtbO2wZiSNXKVkKW4sdUZir/+B2qaRvtY3lRJnvka+B3OF+GChEW+urovvqV8Qm1q7YryTOg8kSdLQlu+9821u7orvqm+Oq6ob4j+XO3FHoRa/13suGuXnwg8Um3Fhc2uMWSPq/x7NJOkt395YOseXLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgNMs09pbyibdvx7yQXlfKhTmX+Bqc9rvp3Y3yXS6f2845fB1aWNzHJ3Ij/SA3GfbdeVpa0bSyLW5tSs+ma+MxD5/rX0+lprbnPkaqR7uPQcfKtTjbeW18f31C2JTb88bt/dLkiStNNar094dae894YrabLy1sjZuLbbiU/lyHBuhZ8Y787W4rD7Xe05MrQv1dZlO+j8zk+kVq/bte56vWgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKfBmrm5F2Y73QdGYkhekm53xTmdzmnt+OZs0j1mKOXwNd/cHp/P5UdmAO7J9Nl8MWrJonUjaaT6gdqmkTknPlRsxHkGpMdYrzsLVWe/hrIjvf3sznwt3l6eih+qz8bW1s5Y476XJEk6oXLJUmxu7YrvrG+O11U3xg2lybijWIvPTRSG9nnyt/KVuKI2u/K3WwPq8x7ITi5t8HULAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgFMsm3Z8fmeF4SfdaV5zTej910vcaQjl8bWjPx2fzxaEdcnuqu7y+ybqRNDIVOksrA9FHZY+/J1eKdnuPa/9YP1SfdfZrKLo7X46bS0lcVd0QFzW2RDlZdI9LkiSdgZafu+ab22N/bVMcrK5feSY7XKjE0Yn8UDxnfrr3Drn8jOn5Uv1d+tVMkt6SWbv3W33lAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAXG2ukrRmowXpIeddU5XTKTey82fHL4qiWL8Yl8ZSiG2J6J7ijU4txOau1IGolmW7vi4/nqyOzxR3rtbm537R9XobMU9+eKngE0UH0qX46bSkm8tjYTaXNblHvPu+5nSZKk/iqXLMVca2e8oj4XP17dGDeUJuNQoR4PTBQG8hl0+b3p9ZUN0Uj2uL7q2zKd9C+zk3v3r1q16jm+eAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJygsdZLG9mk++VRG4o3Pn1hztXnVFteV7376a8Mnhy+4bUfKjYGclDt2Wqhud3akTQSfX/9gngwVxipPf41tRnX/kl6a2WtZwD1bQ9P5FeeZ6+prIuXNTZHq73bfStJkjTgTbYXYm9j28o72tvLU/HhQj0+NzEY76fL79HL71Adz6Xq4zJJ97fObS/VffkCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4Tt9W2/dvskl6dDSH4e19lRXAqTQ1tf/5maR7j2GTw9W5nTRuKicDMYy2X7qh3LF2JA195/XOh2vL0yO3x99USmLM9X/SZlq74pjnAPVJ9+RLcXPvfr2quiHS5rbIJUvuU0mSpBGp1d698gx4oDYb11am44OFRnxuotCXz61HJvJxfXlq5X3KtVN/fktM/zHT6b5j+Xuqr2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADPUqaT3jqyw/CS9JAVwKnUW1dvM2Ry+HpLZW1fDpzt1x7MFWKyvWDtSBrqOu3d8auFxsjt8b+Rr0YpWbIGnqbbik3PAzrjHcnl485CNa6tTMdl9bmYac/HmPtRkiRJT6jVe5dNm9viQG125dnxg7332s9NFPrimfboRD5uLiWxrbXDtVK/flP8g0wnTX0JAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAbZJH3liA/B+1KhMP8CK4FTYWyyuyvbSb9quORw9b31C/piqOwg9brqBmtH0lC3p7k97smVRm5/Xx60PtOetwaeoVc25jwP6LR3f64QtxZbcVXvueuixpYoJ4vuP0mSJJ1wrfbuSJvb4kBtNq6tTMcHC434vd4z59l63l3+/7/8nOvaqC9L0jvOaS1N+CoGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwJManL8xlk+5fjfrwu0ySbrcaOFnntF767Zmk+0UDJYerna0d8dBE/qwNjx3EfidfinyyZP1IGsrO7aRxVXVjHB3Bs+FYr0sbm62DZ9F5vXXymVzRc4FOaXcVanFdeTq+r35BbGzNx5h7TZIkSWfgHXhteyH2NbbEa2sz8e7SZNzRey79fO7MvRN/sNCI72hudT3Uj98W/7b3vwcLhfkX+EIGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwmKmp/c/PJN1PG3y3PPiue50VwUl6TqaTftT9NFx12rvjnlzpjA2IHZZe2ZizfiQNZaVkKW4qJyO7v7+xst46OI6Wfy/PBTqZDhcqcW1lOi6rz608l7qvJEmS1E+1es+oaXNbHKjNrjy3frDQiAdzhdP2fPyxQi0ubWyOMb+9+q0kPTrWSS/wmQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAn00nfbNjd1wbedY9ZEZyM7OTe/e6l4SqXLMWHC/XTNgR2WLu92DDYVtJQNtfaGYcLlZHd328rtmLcOjiu1rUX4phnAz3LjuTycUexFm+urouLG1uj2l50H0mSJGngGk/SlXehlzc2x/9e3RDvKbXjcP7Uvkt/tFCPl/X+75/bSf3m6qcezSTpLaunFv+DL2YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDIWj3Z3ZRN0q8Ycve4YY/TF+asDE7EOa2liWzS/Wv30fA01uuG0uQpHfY6Ch3rtb25wxqSNHR9Z31zPJgrjOz+fk++FK32bmvhBHpfseUZQU/akVw+DhXq8ZbK2ri0sTkqyR73jCRJkoa2UrIUW1o747L63Moz8AcLjfjcxMm9Z9+Vr6783xtPUr+x+qZMJ/3L7OTe/atWrXqOr2cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBIWdPu/rts0v1Dw+2eMOgu2fsqq4Pjd/VzM530N91Dw9WP1jae1EDXUe1d5UnrR9JQtTyY+2B1fRwb4b39yEQ+FprbrYcT7NLGZs8IeuxeysWhQn1lT7mosSXKyaJ7RJIkSSNfq7175fn4yupMXF+eijsL1Tjaew89nmftw4VK7K9tinG/p/rpm2Mn/c3VU4sV39AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICRkU3S9xto9yQl6SGrg+OVSbqvdf8MV3sb2+JI7vgGtyoXD0/kY7q1YA1JGprKyWL8Yqk18vv7FbVZ6+EkGu+kcU++5FlhBPt873nyA8VmXFXdEHua2yOXLLknJEmSpGdRsffsvLO1I36wtil+ujIdv1JoxAMThWd8Bv+NfDUuq8/13sP8huqPMkn373r/e7BQmH+Br2kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBQy7bTyw2ye8q+ZLAdx+Pc9lL9saGI7p8haWNrPu7PPfOAVv3rrqmss4YkDU3r2/NxV6E28nv7DaXJgbt2r/zha/ru3/T6ygbPCiPS4UIlrq1Mx6WNzVFMluynkiRJ0ims1d4dFzW2xJXVmbi+PBV3FqpxdCL/r57LfzNfiQO12Tivk/rd1C8dWT3Z3eSrGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMJTGOkuFbCf9G8PrnrrVydIOK4VnZW7uGzKd7mfdN8NTLlmKjxbq/2oIq565+3LFqLYXrSNJQ9GFza1xf29fG/W9/dcKtcj3zsZBunYX7//J+Kd/+kqsW/j+vvp3ddq740gu75lhCDtcqMS1lem4tLHZs5AkSZJ0FlrTSWOmPR+X1efiLZW1cWuxFZ957J3+U/lyHKjNxkSS+q3UDz2aSdJbVk8t/gcf2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgKFRKMy/INvpPmBo3dOXSbrXWS08G7318gb3zHD1zvLkyrBVHX+vrc1YQ5IGvrFeP17dGEcn8iO/r9+XK8ba9sJAXb/K7MvjC3/yZ7Hs3e/9lb779/1Cse2ZYQj6dK4U/7ncicvrm2J6wO4RSZIkaZRafl6/uLF15T3/TZV10W1ujfFO6rdRH5T+97F2+gpf2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgKGQ7aQ/bVDdsyjpHrNaeCZjyeLa3lr5J/fM8HR5fVM8MpHTCfS7+XLkkiXrSNJAt7yP3Vjq2Nd7Heu1r7Fl4K7hL/3KXfE1/+N//XXk1u/rq3/f8m9qfQ1eD+YK8YulVrymNhNzrZ0xZr+UJEmSJJ2afv3cqb15X9wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICBtXpq72y2k37VgLpn1zmtpQmrhqcytmHfN2aT9Kh7ZXiabe2KB3OFeGQipxPo8vom60jSQNds744PF+r29Mf6ier6gbuGL3/V1fHoo4/G4/3I69/RV//G8V5358vWWJ93JJePQ7394GDvPkib22IiSe2TkiRJkqTTUiZJ/zabLF01NbX/+b6+AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2X11OI3ZTrd/9twuuMZYrf3VVYOT6V3P73dfTI8FTpL8euFajwykdMJ9PF8NcatI0kD3JbWzvidfMme/li3FlsxnqQDdQ0rsy+PP/rin8UTPfDQ/9V3/9Y3VNZZZ33Yb+fKcW15Oi6pb4lSsmhvlCRJkiSd4e+S6eezU+l6X+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICBkU267zKQ7jhL0kNWDk9m9dTe2Wwn/ar7ZHj62VInHpnI6QS7uLHVOpI0sL2ssTkezBXs54/1qXw5asniwF3H993+8XgqC6+4sq/+rRva89ZaH3Qkl49DhXpcVd0QW1o7Y8x+KEmSJEk666VfzSTpjd9W2/dvfI0DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6WnZyaWu2033UILrj7ktr5uZeaAXxeC9eN/+ibJL+gftjeDpQm41HJnI6wW4vNmLMOpI0gC3vXVdWZ+LoRN5+/lgP9X6Lra2dA3ctX/aDr49HH300nsr7bv943/2bl89Pa+7Md0+uFNeXp+LSxuYoJ4v2QkmSJElSn5b+t7HJ7i5f5QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgL50TmvHN2eS9P8xfO7EWp0s7bCKeLxs0v1598bwtL25Ix6eyMcjEzmdYLtaO6wlSQPXeZ003lmetI8/ocvrmwbuWlZmXx5/9MU/i6fzd3//D1Hf/Iq++nfvr22y5s5AR3L5OFSox1XVDbGltTPG7H+SJEmSpMHqtpck+77N1zkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKCvZDrdnzVw7sTLJN3rrCIedz8tuS+Gp3yyFJ/IV+KRiZxOsFtKbWtJ0sBVT/bEh4oN+/gTuq48PZDX8323fzyejYP/53v66t9dShbjwVzB2jsN/U6+tLKeX9bY3Pudl+x7kiRJkqQBL/2zsXb6Cl/pAAAAAAAAAAAAAAAAAAAAAAAAAAAALuZpSQAAIABJREFUAAAAAACAvjA22d2V7XQfNWzuJEq6x6wkluWm9n1LJun+sftieHp7eSoemcjpJNre3GEtSRqoNrTn45P5ij38CR0q1GMiSQfuer7iijfEo48+Gs/G7/+3L/Tdv/9d5Unr7xR0pNdtxVZcWZ2JC1o77XWSJEmSpKEs00k/9pLOhWt8sQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM6a3NS+b8km6f9nyNzJNz59Yc6KIpOkN7ofhqdL6lvikYmcTqKbS4m1JGmg2tHcEZ/OlezhT+je3m8y3V4YuOtZ2fTy+OM//fM4Ht3v+bG++hsWm9utwRPswVxh5Vlkf21TNJI99jhJkiRJ0miUdL/c+98fW7Vv3/N8uQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM64TKf7C4bLnZoySfeHrKjRNtZJL+ithUfdD8NRq707PpsvxiMTOZ1EW1s7rSdJA9PLG5vjwVzB/v2Ejk7k46WNrQN5Td//4d+I4/Vff/XjffU3jPX6ZL5iLT7LPpUvx7WV6biosSXO66T2NkmSJEnSKPfA6qnFSV/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAMybT6S4ZJncKS9I7rKrRtWZu7oW9dfCIe2E4Gut1S6kdj0zkdBK9p/cbWk+SBqUDtdk4OpG3fz9JP1adGchr+p2vfkOciC99+e+idP4lffW3vK660Vp8mu4sVONgdX3MN7evPMfZ0yRJkiRJ+ucySfqP2aR7TaEw/wJf8wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgNMqs3bvt2aS7hcNkzulfWnN3NwLra7RlE26b3IPDE8/XD0/HpnI6SQ61mtLa6f1JKnvG0/SeFt5rb37Kbq5lMS5nXTgrmtl08vjj//0z+NEXXnw+r76eybbC3F0Im9NPtaRXh8sNOJAbTY67d32MkmSJEmSnqFM0v39sWTvnC96AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAaZPtpO8zQO7Ut7q9d6fVNYr301Irk6T/6B4Yjs5vzceDuUI8MpHTSXRTKbGeJPV9xWQpfqnUtm8/RYfzlSgniwN5bT/w4U/Eybj394713d90a7E10uvx3lwp3lWejEsbm1fuXXuYJEmSJEnHWZJ+JZN0r1s9tfhNvu4BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACnVDbZu2Bw3OlpeRCdFTZqrn5uNknvtv6Ho/M6aXy0UI9HJnI6iY71uqC105qS1Nc1kj1xR7Fm336KPp/Lx+bmroG8tq/84WviVNh84RV99Xd9X/2CkVuHh/OVeFNlXexubo9x+5YkSZIkSaeq/zfT6W7zjQ8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADglVk8tftPyoDTD4k5TSfeYVTZasp30Ndb+8PTGyvp4ZCKnk+zGUsd6ktTXTbcW4hP5ij37adpf2zSQ17ay6eXxJ3/6F3EqvPvmD/XV31ZKluLzufzQr73DvXvzLZW1Md/cHmP2K0mSJEmSTlePZpL0xhevm3+Rr30AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBJySTpzxgSd3o7d2pv3kobDS/pXLgm20n/xrofjra1dsSRXD4emcjpJDo6kY+Z9rw1Jalv29raGffkSvbsp+mG0uTAXt9fvuOTcar82V/8z1iz9sK++vveU2oP5Zq7s1CNg9X1Md/cbp+SJEmSJOkMlknSP1mdLHV99QMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE7IWLK4NpukXzEg7vS2urP0aqttNGSS7q9Z88PReK+PFOrxyEROJ9nPljrWlKS+LW1uiwcmCvbrp+nOfC3yydJAXt/v/uFr4lT73tf8VF/9jd9V3zw8a61QjauqG2Kmtcv+JEmSJEnS2e/m8eaef+/rHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8OzNzX1DNunebyDc6S+TpHdacMMv21n6Tut9eLqquuH/Z+9OoCSr60OPt5gY15y4IPStnhnrVvW+1L3dDDMDM9MzwOzd9zbEDiJCUHCUuKBiQsDEIZoQnsYFTUw0KBGNCtEYBIOoGZUQcQFxxIFSYzQ+RVDEJSDLDPN/BXnPPBOFWaq6q25/Pud8Tw24cLru7/6Gc/5zzj/Uy7Ga0Nqx9WZKUlv27OHJsLNcsasfohvK1XDE2IaOfL4Dq04It9x6e2i2qz752bb6OeNk+sHn1Kkz9pHq4IP/3rW8ttFekiRJkiSp/bq10W86BQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPZKVMt+10Vwc1OU5vccPDT7eFNXXN0TU08pJfn3zXsxWjG2MdxYroR6OdYB9u6+mpmS1Ja9aGhluNmefth+e3h1xz7jv7t8e2iFXbt3h3TdKW31s76lP+2Ymbqp8e9YH6oOh7MHl4eltU32kSRJkiRJnVCSXXLI2LFPdSIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8Uoemxy0ppfmdLoGby6aPM3nFFSXZu8x4MVqUZuED1ZFQL8dqQptGjzZXktpuz58/sNSO3ose+J469Tn/9otfHVrp3D97e1v9vL81clRbz9LOuBLe2zsafmd4ZRitbbaLJEmSJEnqwKI0v6M0PrPVqSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPALldLsKpe/zXFJ/g6TV0w94/kGM16cXjJ0ZKiXYzWhD/aOmClJbdXiJAtv6J+wo/eif6iOhCVp1pHPeXjNieG2798RWmnHzq+11c/8wLP6fNzXdnP0oepweNHQyjBa22wHSZIkSZJUmDPP7EOLJ47tdkIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8TE8tO9GFb/NRdltX17aDTGCxHDK27nGNZ/sN812MJmqbwg3laqiXYzWh3xxZa64ktU1PS7NwYV9iP+9Fn4/7Hvw9sVOf9Qc+/IkwF1bNnN5WP/cb+yfaYn4+Uh0MZw8uD0s7eIYkSZIkSdJDF6XZD0rp9LOcFAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF3R0pknl9Lsey57m6fGp5ebwmIpJfnrzHYx6mn0t71joV6O1YT+sTr04HdqtiS1Q9V02o7fy24qV8LMyNEd+6yf89Lzwlx53V+9t61+9nzkqHmbm09WBsK5g8vCEWMb7BxJkiRJkhZW/7Bk6eZDnRgCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMACVkqzi1zuNo8l+R+bwuI4NMmGoiS7z2wXo+cMrw71cqwmddLIpLmS1BaNJFvC5b1DdvNe9orB5Z37rNc8K3zv9jvCXPnGt25pq59/caPPxH1zNitXV/rDqwaWhbVj6+0aSZIkSZIWcFGa/bA0PrPVySEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACxAPcnMZCnN97jcbR4vlUvyHSaxOKI0326ui1FfMh0+XekP9XKsJvSJ6kBYbK4ktUFpbXP4WGXQbt7L3ts7GhYnWcc+7w999Jow1zadeGZbfQdv7J9o6Yx8Pu4Lb278M7LRo8OiNLNnJEmSJEnSf52DpvkVi9IscoIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALRLW68ddKSX6zC93mv0Nq+dNMZOfrSfJnmufi9KcDS0O9HKtJbR1eZa4kzXsrxjaGqyv99vJedk2lL4wkWzr2eZ/6svPCfHjbuy9rq+/ht0aOavpsXB/3hgv6J0Le+P9ebLdIkiRJkqSHKEqzH5bGZ7Y6SQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAWglObnusitTS6TS/LfMZGd7cn92RMaz/E75rkYrRzbEHaW41BXU7q20heelmZmS9K8tnpsfbg27rOX97Kd5UrYMLauY5937eiTw+13/DjMh1u/94OweOLYtvku4mQ67IirBzwTX27MxNv7auH4kbWhnPh9XZIkSZIk7eN5aJr/3SFjxz7VqSIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABRU98TU4lKS3+UCtza5RC7JrzSVna3xPr3OLBenS3pHQ70cq0mdNXiEuZI0r60dWx8+V+m1k/ehM4aO7Ohn/uGPfzrMp+Of94dt9X1c1Jfs9yx8pDoYzmz8Xj6SbLFPJEmSJEnSgZ2Jpvkdjc+TnCwCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEABRUn+9y5ua6sL5O55cn/2BJPZmQ5NsqEoye4zy8XopJHJUC/HalI74moYSqbMlqR5a+PoMeH6xi6yk/e+C/uS0NPBz/yFr3h9mG/v+eDH2uo72Tq8ap9m4OpKf3jlwPKwYmyjPSJJkiRJklrRpYcmswc7ZQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgIKI0vxoF7W1Xz3j2bGms2Pfqe1muBhV0+lwTaUv1MuxmtSfDRxmtiTNW5tGjw5fKFft431oe2Ug9CVTHfvM03WnhB/+6D/CfPvJnXeFyvLZtvlexmubHvbZ74ir4a19aXj6yNqwOMnsEEmSJEmS1OKy20pJ9nQnjQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0OEmJrb+ainNd7qkrQ1L8reb0M7TncycYH6L07mDy0K9HKtJ3dzoiLENZkvSvHTc6FFhR1y1j/ehL8WVsKbD9/ZHP/W50C5OO/P8tvpuPl4Z/B/P/KZyJby/OhK2Dq0K1XTa7pAkSZIkSfNQ9p6eodknOXUEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAOFaXZy1zM1rYXxt3W1bXtIFPaOZ7cnz0hSvNvm91idHhtU7ixXAn1cqwm9c7emtmSNC89fWStnb4fnTq8uqOf+0u3XRDayRUf+5e2+n7OH1j6s2d9VXUonD24PEw0/v3HzpAkSZIkSW3QrVGaTzt9BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACADnPI2LFPjdLshy5la+MmsmUmtXOU0uzPzG1xelffWKiXYzWxbPRosyVpzjt5ZDLstIP3uTf0T3T0cx9f/+zwox//R2gn99x7bxhc/cy2+Y6mRo8JfzJ4eFgzusGukCRJkiRJbVmUZBc/uT97glNIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADoEKU0u8hlbG1ekr/apHaGQ5NsKEqy+8xtMdo8ekyol2M1sY9UhkKP2ZI0x500vCbstIP3uSurQyFOpjv62W+/5vrQjl627U3eTUmSJEmSpH0q+0aplq9xGgkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG2uNJEtK6XZ/S5ha/tL4m4wrZ0hSvPt5rUY9TT6UHU41Muxmtipw6vNl6Q57aThNWGn/bvPfaFcDSvGNnb0s3/5q/48tKtPfvoG76ckSZIkSdK+n5k+cK79miWTk492KgkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1p20FRkn/G5Wud0aHpcUvMbHvrTmZOMKvF6aThNaFejtXEro37QjnJzJekudvlI5NhZ1yxg/exmxs9Y2RNRz/7ZZtPCz+5867Qrnbt3h1G157kPZUkSZIkSdq/dnaPz0w4nQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgDbTneSnunCtc4qSmdNNbft6cn/2hCjNv21Wi9HiNAvbKwOhXo7VxM4ZXGG+JM1Zpw6vDjeVK/bvfvTqgWUd/ex7xmfCJz/9hdDuzjz3zd5VSZIkSZKk/S3Jd0VJdv7ExNZfdVIJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABt4EmHb/z1KMm/68K1zilKs380ue2rlGavNafF6QVDK0O9HKuJ7SxXwlhts/mSNCedNrw63NTYO/bvvvfB3pGwJM06+vm/4k/fGjrBP/3zdd5XSZIkSZKkAz9D/Wz3xNSA00oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJhnUZK9wSVrHXYhXJLffcjYuseZ3vbzwEV9jXfqPnNajKrpdLi20hfq5VhN7C/7U/MlaU46bXh1uKlcsXv3o2vjvlCrbeno579iamu48667Qye4775dYWDVCd5bSZIkSZKkAz5HzX5aSrIXd3V1PcLJJQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzINDk2woSrL7XLDWeXUn07kJbj9Rml9hPovTOYMrQr0cq8ltGj3GfElqec8dXhVuKlfs3f3oge8tGz26o5//oomZcO11Xw6d5EWveL13V5IkSZIkqXlds2hipuL0EgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5lgpzT/mQrVOLbvQBLfZ+zQ+fZS5LE5DyVS4Pq6GejlWE/tIdTD0mC9JLe7E4cmwM67Yu/vZOYPLO34G/vA1fx06zZXbP+P9lSRJkiRJamZJ/uOolp/iFBMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOZIqZZtcZlaJ5fd1tW17SCT3C62HVRKsuvMZXE6b2BpqJdjNbnTh1eaL0kt7Rkja8JO+3a/u6R3NCxOso6egRVTW8Odd90dOs09994b+o98hvdYkiRJkiSpyUVJ/oHuiamnOM8EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBWmp19ZJRmN7pErbPrSaaWGub2ENXyU8xkcRqtbQ474mqol2M1sS+Uq6EvmTZjklrW8cNrw85yxc7dz66N+8JY4/fATp6BRRMz4TNf2Bk61elnvda7LEmSJEmS1JpujcZnppxqAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAi5TGZ7a6OK0IZa8yzfOve2LqsVGaf9s8Fqc/GTw81Muxmtz5A0vNl6SWNTNydLixXLFv97ObGt9dNnp0x8/Bq99wUehkH/roNd5nSZIkSZKk1rWnlORv7lk++xgnnAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0EQHD80+Pkry77o0rRB9wUTPvyjJXmkWi9NQMhVuKFdDvRyryR1Z22DGJLWkbPTo8KW4YtceQGcNHtHxczB57AvC3ffcGzrZnXfdHeJls95rSZIkSZKkVpbkN3ePz0w45QQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgCYpJfkfuyytMO0pjR7bY6rnz1NHpg9pvFM/MYvF6dzBZaFejtXk3tc7ar4ktaSNo8eEL8ZVu/YAem9jRy9Oso6egyWHHRduuPGroQhOfMEfebclSZIkSZJaXZLvanye2zU7+0gnngAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAB6altKpSS/y0VpxSlKs+eb7PlTSrMLzWFxGki2hC+Uq6FejtXkThhZY8YkNb0NY+vCF2N7+0C6ptIXRhq//3X6LJz/5+8KRfHOS6/0fkuSJEmSJM3VWWuSX9uTTledegIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwH4qpdlFLkcr2EVvaX6FyZ4fPRP5aCnJdpvD4nT24PJQL8dqctfGfWFxmpkxSU1t1diGcF3ca88eQDsbbRo9puNn4ajZF4V7770vFMV3b7s99IzPeM8lSZIkSZLmqiT/cVTLT3H6CQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+6hnIh8tpdn9LkYrVlGS/fSQsXWPM+Fzr/E+XWUGi1NfMh2ui3tDvRyryZ07uMyMSWpqh9c2hWsrfXbsAfbyoSM6fhaWHHZc2LHza6FoNp14pnddkiRJkiRpzs9d8w90T0w9xSkoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADspVKSXe4ytIJe8JZmmQmf6/dpZpPZK1a/O7Qi1MuxWtARYxvMmKSmldY2h09VBuzXA+zivlpYlGYdPw+v+6v3hiJ6419f4n2XJEmSJEman26NxmemnIYCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDD6K5NH+kCtOIWpfnbTPkcmp19ZJRmN5q94lRJpsO1cV+ol2M1uUt7R82YpKY1kmwJH60O2q8H2D/H/WEomer4eVj/jJeEXbt2hyK6+Wvf9M5LkiRJkiTNX3uiJHtTz/LZxzgYBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAXyJKs0+4/Ky4RUl2S+MxP8Kkz43Gd/48c1eszhg6MtTLsVrQs4cnzZikptSXTIXLq0N26wG2s9GGsXUdPw9Llh4XvnTzv4YiWzG11bsvSZIkSZI0nyXZTdFYljodBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA/yZK82mXnhW/RWl2mGlvvYOHZh8fJfl3zVxxWpxk4ROVgVAvx2py18fVUEmmzZmkAy5u7JK/6x21W5vQS4aOKMRMXHDhpaHoXvnaC73/kiRJkiRJ81yU5vc0Ps/q6tp2kJNSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB40LaDoiTf4cKzhVD2KvPeeqUk/2OzVqyOH14b6uVYLejPBg4zY5IOuKelWXhP75i92oTe0ZeEngLMxKYTzwy7du8ORXfN53bYAZIkSZIkSW1SlORXLlm6+VCnpQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALHilND/JJWcL5iK3HSa+tXpqW0qlJL/LvBWrS3pHQ70cqwUdNbbejEk6oBalWXhrX2qnNqGrK/1hsDbV8TNRXvb0UP/av4eFYNeu3WFg1Ql2gSRJkiRJUtuUfS9K82mnpgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALFhDQ7OPKqX5v7ncbOG0+LDjYpPfOqUkf4c5K1ZH1jaEm8txqKvpXVkdMmOSDrjzBpbaqU1oZ7kS1o+tK8RM/MVFHwgLyWlnnm8XSJIkSZIktVd7Skn+5iWTk492egoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwIITpdnzXWq2sGo885eZ/Ba9T2MzfaUk32XOitXr+w8L9XKsFvTCoZVmTNIBdc7gCvvUTv65pk/+vbD7/vvDQvKev/+ofSBJkiRJktSOJdlNUS1PnKICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALBgVKsbf62UZN9yodnCKkryT5n+1mi8T5eYsWI1WJsKO+JqqJdjNbkby5UwkGwxZ5L2u61Dq+zTJnVRXxJ6CjAT8bLZ8JWvfyssNLd+7wehZ3zGXpAkSZIkSWrPs9m7G59ndXVtO8hpKgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhVdKshe7yGwhlt3/1JHpQ7wBzdUzkY8+8N2ar2L18qEjQr0cqwVd2JeYMUn73ezI2rDTLm1Kn6oMhIFkSyHm4m3vviwsVOuOP8NukCRJkiRJau8+unji2G6nqgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFNaSyclHR2n+bZeXLcyiNHuOt6C5Skl2udkqVosbXV3pD/VyrBZ0/MhacyZpv9o0enT4UlyxS5vQjeVKWDu2vhBzkZ9yVth9//1hoTrvTRfbD5IkSZIkSW1f9r1ofGbKySoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIUUJfmZLi1bwCX5Zd6C5ulJppY2vtc9ZqtYPXNkTaiXY7Wgz8d94WlpZs4k7XOrxjaE6+Neu7RJ/c7wykLMRXXFb4V/+/fvhIXsM9d/2Y6QJEmSJEnqjPZESfbW7ompxzplBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgMA4emn18Kc1uc2HZwi1Ksp8eMrbucd6G5oiS/J/MVfG6tHc01MuxWtBr+peaMUn73Fhtc7i60m+PNqm39qWFmY13vO+KsNDt2r07DK5+pl0hSZIkSZLUOee1X1pUmx520goAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQCGUkumzXVSmUjp9nLfhwPWk2WqzVLwOr20KN5fjUFdLWje6zpxJ2qf6kunw4eqwHdqktlcGGt/pVCFmY3brH4Q9e/YEQnje773GvpAkSZIkSeqgoiS/u5RkZzhxBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgoz25P3tCKclud0mZoiS72Btx4Brv06fNU/F65cDyUC/HakHbKwOhx4xJ2ocWp1n4294xO7RJfSmuhDVjGwoxG/1HPiN86zu3Bf7TJZf9k50hSZIkSZLUmV26pJb/hpNXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6UinJft+lZHqgKM1+0DU5+Sveiv0Xpfm0WSpei9IsXF3pD/VyrBZ0zuAKcyZpr+tpdEH/hP3ZxLYOryrMfLzr/R8J/Jfbvn9H6BmfsTskSZIkSZI6suwbUTqzwgksAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdpXti6rGlNLvNhWT6WePTR3kz9tsjGu/TDeaoeOUjR4V6OVaLWlbbaM4k7XXnDC63O5vYW/rGCzMbxz/vD8OePXsCP++o2RfZHZIkSZIkSZ1aku9qfJ7bNTv7SEexAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0hCjNXuYyMv3/RWl+gTdjf9+n/HgzVMze0p+GejlWC3p/dcSMSdrrThtebXc2se2VgdCXTBdiNgZWnhC+/d3vBf6nba+90P6QJEmSJEnq/DPc7YvSLHIiCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAW1syOfnoKMm/4xIy/fyFbNn/bozHI7wh+2h29pGlJLvJDBWv/mQqfCmuhHo5Vgt6/tAqcyZpr8pHjwo7y/Zxs3rg97bJsfWFmY/3XfbxwC/28as/b4dIkiRJkiQVoST/fjQ+M+VgFgAAAADD6hgGAAAgAElEQVQAAAAAAAAAAAAAAAAAAAAAAAAAAACAttWdTr/Q5WP6RXVPTI17Q/ZNlGbPNjvF7PThlaFejtWCdjYaTraYM0kP25FjG8N1ca/d2cSeP7SqMPNxwunbwp49ewK/2F0/vTuUlz3dLpEkSZIkSSpGe6I0v6Ba3fhrTmgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGgrExNbf7WUZN906Zh+SX/kLdm39ylKsq+bm2J2WXU41MuxWtC7+sbMmKSHbSiZCtsrA/ZmE3tbX1qY+Rhc/cxwy623Bx7acaeeY59IkiRJkiQVqSS/vpRs6XVSCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA2yjVsue6bEy/rCjJd3hL9l53Ov1Cc1PMjqhtDPVyrBZ16vBqcybpISsnWfj73hE7s4ltrwyEvmSqMDPygQ9/IvDw3vC2S+wUSZIkSZKkopXkP2l8nuS0FgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA+Tc5+StRkn3dRWN6qBYfdlzsZXl43RNTj228T7eYmWL2qoFloV6O1YK+XK6E/mTKnEn6pfU0ekvfuJ3ZxHY2du8xo+sKMyPPeel5gb1z3Y66vSJJkiRJklTQojR/58FDs493cgsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwLzpqWUnulxMD3/5WvYyb8vDi5L85ealmPU0urrSH+rlWC3ob/oScybpIfuDwWX2ZZN7wdDKwszHyJpnhe/dfkdg7+zavTsMrDrBbpEkSZIkSSps2VeisSx1egsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwLwopdkNLhXTXnSNt+WhLZmcfHSUZLeYlWJ2zOi6UC/HalGnDK82Z5J+ac8aXhNutiub2t/0JaGnQDNy2VX/HNg3z3npefaLJEmSJElSgYvS/J5Skp3hFBcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgDlVqmVbXCimvSu7f1GaRd6ah3ifkuzF5qS4/dHA4aFejtWCbixXQl8yZc4k/cI2jh7z4J6wL5vX1ZX+MJBsKcyMnPqy8wL77h3vu8KOkSRJkiRJWgBFSf73i0e3PNFpLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcyJKs0+6SEz7cOHa73hrfrGhodlHlZLsW+akuG2vDIR6OVYLurAvMWOSfmGH1TaFz8a9dmUT21muhGNG1xVmRmpHnxxuv+PHgX33r9/4tj0jSZIkSZK0YM55s3/tHp+ZcKoLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBLlSayZS4Q0z6VZB/35vyS96mWPdeMFLfJsfWhXo7Vok4aXmPOJP2Pqul0uLI6ZE82uZcMHVmoObniY/8S2H/j659t30iSJEmSJC2QoiS7r/F5VldX1yOc7gIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0BKlJL/M5WHap5Js96HJ7MHenv9mdvaRUZp/1YwUtz8YXBbq5VgtaEdcDdV02pxJ+rl6Gv1V/7g92eTe2Vt78Lstypy84JzXBQ7M6We91s6RJEmSJElaeP3D4tEtT3TICwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAU3VPTA2U0ux+F4ZpX4vS7DneoJ9XSqefZTaK3VXVoVAvx2pBF/YlZkzS/+gVg8vtyCb3z3F/GEqmCjMj6bpTwg9/9B+BA/POS6+0cyRJkiRJkhZiSf7vUTqzwkkvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABNU0qzi1wWpv0pSvMrvEE/5xFRmt1oNorbkWMbQ70cq0WdPDJpziT9XMcPrw03249NbWejDWPrCjUnV26/NnDgvvL1b9k7kiRJkiRJC7Uk39X4POuB805HvgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHJBFaRZFaXavi8K0P0Vpfs+TDt/4696k/1RKp48zF8Xu9wdXhHo5VgvaWa6E/mTKnEn6WavH1ocvxlU7ssmdOXhEoebkjD98Y6A59uzZE8aOOsn+kSRJkiRJWtj9w+LRLU908gsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwH6L0vxPXQymA6knyZ/pTfq/71OSf95MFLsPV4dDvRyrBb27t2bGJP2swdpU+ER1wH5scu/qGwuL0qwwczK+/tnhRz/+j0DznHbm+XaQJEmSJEnSQi/JvtVdmz7S6S8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPuse2LqsaUku93FYDqQoiR7v7epq6uU5JvNQ7E7rLYp1MuxWtTpwyvNmaQHW5xm4dLeMbuxyV1T6QvDyZZCzcr2a64PNNfb33O5PSRJkiRJkqRQSvJdjc9zu7q2HeQkGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAvRYlM6e7EExN6M7uianHLvT3qfE9XGMWit3zh1aFejlWC7qpXAljtc3mTNKDnT+w1G5swZ6dGj2mUHPy8j96c6D5dn7lG/aQJEmSJEmS/qsku7xnaPZJ/nQFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB7YdtBpTSvuwhMzahnPDt2Ib9NpVq+xhwUvwv7klAvx2pBH6iOmDFJD3byyKS92IJ+b3BFoebk8E2nhZ/ceVeg+e6/f08YmjzRPpIkSZIk7Wv1B0uyb0Vpfkcpze73nUgFKsm+2VObOdyfsQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4CGVatkWF4CpWUVp/u4F/T6l+cfMQbFbnGThurg31MuxWtBLh44wZ5LC6rH1YUdctReb3Pt6Rx/8fawoc9IzPhOu/swXA63z7Jf8iZ0kSZIkSdq3c6Ik+1GU5m+Mxmb6/t/ZyZLJyUf3DM0+afFhx8U9E/loaSJb1vjvHVNKp49r9KzS+MzW7jT/vcb//txGr2n8Z2+N0uxvS2n2wQfOXRr/f59r9OXGX3+j8XlH4/N+37U0n+fB2b3d6fQL/UkLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+qSjJ/8nlX2paSf6TBy5HXIjv0gOXQJqB4rd+bF2ol2O1qGW1jeZMWuD1J1PhE9UBO7HJXRv3hdHa5kLNyh+c/7ZAa/3lOz9oL0mSJEmS9rc9jT5WSrLZrsnJX2n2mUzP8tnHLB7d8sRFaRYtqk0Pd0/MrIzSfPqBf16jkxud0fjnn9v4exdESXZx49eXNv7e5Y3PaxrtbPy9Wxr/2R2ek3QgZR9cUst/w5+4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg55TS6TGXfanpJTObFuT79J+XMXr+Be/sweWhXo7Vgq6sDpkxaYG3KM3CxX01O7HJ3VSuhGz06ELNyhHTzwt3/fTuQGt98ctftZskSZIkSQdclGRfj5L85T1Ds09qt7OdoaHZR3VPTD1l8WHHxY3P8Z5kZjIan5nqSfJnRsnM6aVk+uxSkv2vxs/w1sbnJaU0uypKs882Pr/S+NlujdL8Hs9YC7x6z0Q+6k9eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwM6U0u8hFX2p+2YUL7l1Kjq01fvY9nn3x+0B1JNTLsVrQKwaXmzFpgffKgeX2YQs6u2D7ddHETPjsDTcFWm/X7t2h94jj7SdJkiRJUlOKkuynD5whRbU8KdIZUc/y2ccsWbr50O6JqYHS+PTynnR6Y5Tmxzd+5uc1Oqvxc59fSvK/bPTeKMmvLCXZpxvd1Pj7t/znd2I21OEl+V2N9/oUf/oCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICuQ5PZg6Mkv9tFX2rBxWnf75qc/JWF9D41fu5LPfvi15dMh53lSqiXY7Wgo8bWmzNpAfdbI0eFm+3Cpndp71hYnGSFmpVXv+GiwNx5+nNfYUdJkiRJkppelOSf6k6m866ubQct9DPboaHZRx0yduxTo7GZvp5kamnje1lXSrLZ0vjM1qiW/W6UZn9SSrO/KCX5exufVzW+u89HSfb1xt//oVlSm50Rv71n+exj/EkMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAFrJRMn+1yL7WsWrZ2obxL0WjWX0qz+z334nf8yNpQL8dqQdfGfWFRmpkzaYG2vLYxXB9X7cMW7NbR2uZCzcra33xhuOfeewNz57w3XWxPSZIkSZJaVpTmX43S7PndE1OPdXq7P7Yd1PjunhKNzfSVxqeXl5J8cymdflYpyV4cJdm2xvd7QePzXY3v+MNRkl9bSrOvNP4732/857vNn1rzTmdfLCVber2bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL0ezsI0tp9g0Xe6llJfmfL5TXKUqyt3rmC6PXDhwW6uVYLeiN/RNmTFqglZMsXFEdtgub3M2Nnj6ytlCzsuSw48IXv/zVwNy66pOftaskSZIkSS0vSrIfRWl+QU9tS8lB7tzoWT77mEVpFi2qTQ93T8ysbHz/06UkO7nRGY1ncu4Dz6PxXC5u/PXlja5r/PqWxt+7x7xqL86Jf9KYleO9ZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0x3LZ9xoZdae/lh/p2urm0HFf1dOjSZPThKsp965gujT1QHQr0cqwU9Y2SNGZMWaBf0T9iDLejcwWWFm5XXvuVvA3Pv+z/4kV0lSZIkSZq786U0v6eUZhcuqk0PO9FtT4eMrXtcdFi+qJQcWyvVsrWN5/abjc/nNj7Pajy71za6qJRkl0dJfm2jr5WS/Cdme8G+z28cGpp9lLcGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGCBKCXZx13kpVbXPZ6vKvq7FCXZNs96YZTWNod6OVYL2lmuhL5k2pxJC7DThlfbgy3osupwWJJmhZqV9c94Sbjvvl2B+XHE9PPsLEmSJEnSfHRNlObTXV1dj3C62/kWj2554qLa9HD3xMzKB55rKclObjzjsxq/viBKsosbf315o+sav76l0X3mvxhFSf75Q8amy94AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICC656YGiil+R6XeKn1l6Rlbyryu7RkcvLRjZ/zVs96YXTS8JpQL8dqQe/pHTNj0gJs5diGsCOu2oNN7rq4NxxW21SoWSkve3q4+WvfDMyfF73i9faWJEmSJGn+zpvS7IuNz5MmJrb+qpPehaNnaPZJ0WjW312bPrI7mc67k/zUUpKfEyX566Mku7gxFx+O0vxzpST7ZmM+7vSutHFJdnspmdlkqgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACqyU5G92eZfm5JLDJP9u1+zsI4v6LvUk+Wme88LpvIGloV6O1YLOGDrSjEkLrGo6HT5aHbQDW9BJw2sKNy9//o73B+bX31zyj3aXJEmSJGn+S7JvNjqje2LqsU58+e+WTE4+elGaRYtq08PdEzMrozSfLo3PbG3MzrmNX18QJdnFjV9/rNHOxq9vKSX5Lu/VnLan8b2fX+SzYwAAAAAAAAAAAAAAAAAAgP/D3r1A2V3Vhx6fUHu1176uXg35n0niOWfer/P/zyQEQsJAQshz/v8JMkVrAVHEKio+qkgrN6hV0SottYIUil4qVlGqhWpBKiCiqIWigZBja0uhYq1PRHxAHvueUOoNkMc8zpk5j89nre9K7FpFsv97/5quPWttAAAAAAAAAAAAAICW9czu9NdycfYjj3ZptmpP0qOa9DjNi5LsLt+4dfpkx0Ao5wuqQctK6+wxqcV6X9ew+VeD3tm9tOn2ytjJbwg7d+0KzK2t279hdkmSJEmS6qj0P3Px2NmFkYnfcPvL9G05ZP7Q5mcfGqd9e+4zc8nY8dFwekZlj51b2WMXVvpE5fe3REn2T5Xf/9i5q05RnP1dtHT8mfYfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEATieLs5R7r0qwWZ+9txrPUnoyt831bp+ckabgzXwzlfEFV7oZijz0mtVhn9K0w/2rQtcW+UIjHmmqvFA+fCN+455uBubdj587QufxEM0ySJEmSVFdFcfpAlGRvnz+0+dlugan53eDhE78yv5Q9Jzc8dnhl3421x9lpUZK+qfL7C3Jx+pHK72+q/Hp3pe85nwcrvWfB8PiIXQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0CSiOPuaR7o0yw8afqutbcshzXaWKn+2z/i+rdPaoTWhnC+oBr2t9zB7TGqhVg0dF+7KF82/KndHviMcMbSu6fbLpVdcHagfJ7zkD8wxSZIkSVK93kX9NBdn7z00OX6x22DqwcjI6b/cXtqYi4bSJBePr4/isVOiUvr6KM7Oj5LsQ1GS3ljZu9sqv/6wdc9t9rP2ODvNbgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaHC5kXSZh/U0F7XH46PNdJbaR7LByp9rt2/bOr2678hQzhdUg7KBVfaY1CJ1JGPh74u9Zl8NOrV/tOn2y+ZT3xh27dodqB9v/9PLzTJJkiRJUp2X7qr8euWhcdrnZphG0dGx7qkLkzRaMDw+EiXZWC5OT67s47Mqv79gz36udEsUp/9S6ZFmPLeVP9flC0Y2/U87AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgQeWS9FKP6WlOirM/a66zlH3Qd22tLulKQjlfUJXbWiiGQjxmj0kt0vu6hs2+GnRhd9J0e6X7yOeFe7/57UB9ue6mL5tlkiRJkqQGKd0Vxdlft8eblrohppnMH9r87PaRbLB9OFubi9OTFyTZG6I4/ePKnv9wZc9/Lhdn2ys92IB3ybfPHxrL+8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3mWX0Tv9qQD2ipKYri7D/aJiZ+qRnO0sIkjaIkfdh3ba1uKXaFcr6gKvehzpL9JbVIL+lfae7VoBuKPaEzHmu6/XLFVdcF6s93vvcD80ySJEmS1IjdEiXZmNtiWsni0dGn7bnTXDA8PpKL04lKZ0Zxel6lyytn4vpK23Jx9qO6OquVf58FpWzc1wMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaCC5JHupR/M0l7XH46PNcJaiJH2b79laJaUNoZwvqAa9pm+5PSa1QEcOrQtfK3SYe1XuznwxHD20tun2ywvOeHPYvXt3oD4la15orkmSJEmSGrIozr4UJWna1tY2z80x/Jf2volntA9tHmgfztZGpeyFlTPyplyc/Vmlv6n8/suVc3N/5fc7Zu+sprsqv57b1rblEF8HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAB5OL0Ng/maW5L39fo52jByKb/WTlL3/MtW6sX9I+Gcr6gGrRyaK09JjV5+TgNn+roN/Nq0Mv7VzTdfukbfUH4j//8XqB+nfyqt5ptkiRJkqTGLs5uj5I0bWtrm+cGGSZjyyGLRjYvWJikS6IkG4vi8ZdVztKbK2fpsijO/q7yP7sritMHqnlOK2f00+19E8+w9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdSwXby55JE910LfbJiZ+qZHPUjScnuE7tl5v7jkslPMFVblbi12h3f6Smr4/6lli5tWgD3bFTTlDr/rUjYH69u6LPmy2SZIkSZKaoihOt+bidKKtrW2e22SYucWjo09btOT4woKR8RV7zlblnJ0VJdkFlV+vrPzn2ypn7ltTOqdxel97afwwKwsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUKdycXaRx/FUF5Wyoxv3JG05pPJnKPuOrdflXaVQzhdU5f60e9j+kpq85w0cbd7VoJuL3aEn3th0++VFr3l7oP5de+OXzDdJkiRJUlMVxenWXJxOtLW1zXOrDLW1eHT0aYuWHF9YMDK+Ys+5q5zBs6Iku6Dy65WV/3xb5Tx+63HnM8l+nhseP93KAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADUmflDa56ei7MfeRRP9VF6YaOepQXxWOb7tWY3F7tDOV9QlTul/yj7S2riktKGcFuh07yrctvyxbBmcE3T7ZehVSeF737/gUD9u//b3zXjJEmSJEnNWZzdHiVp2tbWNs8NM8ydZ3anv3ZonPa1D2drK2fyRVGcbonibLmVAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACoI1Epe6GH8FQ/pd9pGx19SiOepVycft73a7264rGwPV8IZVW1PWs6WNpgj0lN2sIkDR/pHDTvatDrepc35Z752+u/EGgc8bGnmHWSJEmSpKYtitOtuTidaGtrm+emGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYB+iJL3RA3iqq0rpMY12jhYm6RLfrjVbM7gmlPMFVbm/7ei3v6Qm7nW9y826GvShrlKo/J2k6fbLK/7g/EBjecEZbzbrJEmSJElNXxSnW3NxOtHW1jbPjTMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBj5pey5+SSdJeH71RXxdlFjXaWoiS9wrdrzV7SvzKU8wVVubf0LLO/pCbt6KG14a580ayrcrcWusJAaWPT7Zfh404NP3zgx4HGct6f/aV5J0mSJElqpXut26MkTdva2ua5fQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFpeFKdbPHan+iv9Ttvo6FMa5RwtXrrh0ChJH/bdWrO39R4WyvmCqtzmgVX2l9SE5eM0XFvsM+eq3N35YkgHVzflnvns528LNJ5Pf/aLZp4kSZIkqeWK4nRrLk4n2tra5rmFBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWtW8KE6/4ZE71WXDY6sa5SBVztEW36x1u6JzKJTzBVWxbZW64jH7S2rC3tW91JyrQW/qXdaU++X1b31foDHdd/9/mnmSJEmSpJYtitOtuTid2HMX6zoaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoKe1JepSH7VTHDw5e3AjnaGTk9F+O4ux+36x1+2KxO5TzBVWxT3QO2FtSEzY+sDpsN+Oq3pWdg2FRE+6XZRtOCw8+9JNA4xo4+nfMPkmSJElSaxdnty+Ix7K2trZ5bqYBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICWkIuzv/Cgneq1KMl+0Nc38T/q/RxV/j1P9L1at+54UyjnC6pyW3qW2V9Sk9Ufbwy3FrvMuCp3W6EzDJfWN91+aR8eDzd98Y5AY3v+y7aYf5IkSZIk7bnzitOtuTidcDsNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0tflDa56ei7MHPWSnun5kcHh8U72fpSjOPudbtW7rB48N5XxBVS4bXGV/SU3WZV2x+Vbltlc6YeCYptwvb3rnnwca3x/+yQfNP0mSJEmS9r73irPPLRgZX+GmGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaEq5OD3Z43Wq+8cFk/SKej5H7UObB3yn1u53+1aGcr6gKrYtXwzFeMz+kpqo0/qPMt9q0Nt6D2vK/XLEptPDQz/5WaDxfeyaG8xASZIkSZL23fULk3SJG2sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKCp7HmszYN1qv/SH88fWvP0ej1HUZL9uW/U2p3buyyU8wVVsY93DNhbUhMVxxvCbYVO863KXd3RH56TpE23XxaNbA7/8NXtgeawdfs3zEFJkiRJkvbf7ihOP35onPa5uQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABreopHNC3JxutNjdWqEoiR9Xj2eo8Wl7Dcr/34P+Uat3YXdSSjnC6pi5/Qebm9JTVJ7pQ91lcy2KndHviMcXlrXlHvm7X96eaB5/Pzhh0Pl//c0DyVJkiRJOmDprsqvV7YnYx1usQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgIaVi9MzPVCnhinO/qYez1GUpK/1ffTXnQOhnC+oio0Nrra3pCbpFX0rzLUadPLAaFPul1UTrwwPP/xIoLmsHH+ZeShJkiRJ0iSK4vSRXJJe2F7amHObDQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANJwoSb/scTo1zCOCSfpwtHT8mXV2jOblkvTrvo9uKXaFcr6gKnVXvhgK8Zi9JTVBS0vrwx35DrOtyp3fvaQp98viJceHr971T4Hmc9rrzjMTJUmSJEma6r1YnF58aDzxLLfaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQ1g4Ml7MJdluj9JVr754k3Woce1xdlo9naMoyVb7LlqcpOHufDGU8wVVqY93DNhbUhO0sDIfP9Y5aK5VuWs7ekMhHmvKPfOe9/9VoDm9+6IPm4uSJEmSJE2nOHuw8uu57YdP/IobbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoK5FcXaOh+iq24v7jwqLktRa1LDKvv1sPZ2jyr/Tlb6LlgytD+V8QVXs3N5l9pbUBP1e33IzrcptLRTDUUPHNeV+Wfv814QdO3YGmtPVn7nFXJQkSZIkaSZ3ZEn2zdzw+Olto6NPcdMNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADUpSjJ7vIAXXV7X9dwGIg3Woualu5qL23M1cMZevbA2PwoTh/xTbRh8NhQzhdUxU4YOMbekhq85aV14c580Uyrcqf3r2zK/ZJfdkLY/s//FmheX/+X+8xGSZIkSZKqUzkXpxNtbW3z3HgDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1IyplsQfnqt8txa6wfGittah56Wvq4Rzl4uz3fQvt6dT+0VDOF1SltlfqLW2yt6QGbmGShqs6Bsy0KndxV9K0e+bCD5Rf7+oAACAASURBVP51oLnt2Lkz5JedYEZKkiRJklSloiT7Sm54bJWbbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoC7k4vSdHpurbkcOrQvlfCFsGDzWeszCI4Fzf4q2HFL5d/lX30N7emPvEY+ef1Wn64q99pXU4L2270jzrMrdUOwJXfGmptwv6SlvCDt37Qo0v2N/60wzUpIkSZKk6nf9gpFNw27AAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAuTQvF2f3emCuup3RtyKU84Vw0sCo9ZiF2pOxjrk8RJX//nW+g/6787uXPHr+VZ3e3bPEvpIauGWldeFrhQ7zrIptyxfDsYNrmnK/dBzxW+Ff770/0BrO+P33mJOSJEmSJNWkdFeUpFfMHxrLuwoHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmXRRnyz0sV/0u7YpDOV8Ir+070nrMQpV9fM5cnqPKv8MnfQf9d1d0Dj16/lWdXth/lH0lNWgLkzRc2TlollW5V/U2798vL/vI3wZax59e+jGzUpIkSZKkmt6fpY9UuvjQeOJZbsUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBZk4uz93hUrrotitNwW6EzlPOF8Lbew6zJbBRn2+fqDC0a2bxgz6OEvoP+u2s7eh89/6pOS0rr7SupQTujb4U5VuX+b2cptDfpfvmt088Ju3fvDrSO6276slkpSZIkSdIsFCXZDyq/nrV4dPRpbscBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBam5dL0ns8Jlfdjhk6LpTzhUd7f/ewNZmtBwFLWTwXhyiK0/9j/bV3txa6fjEDNLO+UOy2p6QGbbi0PvxjvsMsq2K3FLtCX7ypKfdLz4rnh3//1ncCreWe+75lXkqSJEmSNKul97TH2W/vuSN2TQ4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANREe7xpqcfjqt+r+44M5Xzh0T7eMWBNZqs4fefsn6Ith1T+e//N+mvv7soXfzEDNLMu6k7sKakBa6/0oa6SOVbF7q7835ZNg8c27Z75yN/8faD17Ni5Myxeery5KUmSJEnS7N+p3ZYrpce4LQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKouitPzPBxX/S7tikM5X3i0G4s91mT2HgC8r61tyyGzeYbah7O11l57V4zHfnH+NfNe0bfCvpIasBf3H2WGVbk39h7RtPvlhWf+YaB1rcheZm5KkiRJkjR3XZ9LxobcmgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFUTJdk/eSyuurVX+lKhK5TzhUe7M1989H9mbWanBcPZytk8Q7k4/ah1194lpQ2/OP+aeauH1thXUoPVF28KXy50mmFV7MrOobAoTptyvwwec1L4zvd+EGhdJ73yLWanJEmSJElzWZztiOL0/YuXbjjU7TkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAjUSmLPRRX/Y4srQ3lfOFx9cWbrM3sPfx30aydoaXjz4yS7OfWXXs3OnTck2aApted+WJ4TpLaV1KDdWHXsBlWxb5U6ApDpQ1Nu1+u/swtgdZ2zrsuMTslSZIkSaqPHori9LxnHLbu192kAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA05JL0rd4HK76vax/RSjnC49r5dBaazNLRUn2g46OdU+dpTP0GmuuJ7Zx8NgnzQBNr090DthTUoOVDawyv6rY9konDBzTtPvljLPfHeADH/2U+SlJkiRJUj3dtcXZ/VGSntrWtuUQN+oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMCU5OL0bg/DVb8Lu5NQzhce13MHjrE2s1mcnjAbZyiKs69Zbz2x5w0c/aQZoOn1jp6l9pTUQBXisXBjR4/5VaVuLXSFE5r475DDx50afvjAjwPc9MV/NEMlSZIkSarL+7bs9vZ4fNStOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMCmHxmmfx+Bq0xeK3aGcLzyuM/pWWJvZfeTvb2p9hnLDY4dba+2r0/tXPmkGaHqdNDBqT0kN1Ft6lpldVeqSriT0xZuadq+0D4+HG265PcAe937z22aoJEmSJEl1XBRnVy0cGS+6YQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4oF2e/7xG46re0tD6U84Un9daew6zPbBZnO549MDa/lmcoStJLrLX21et6l+9zDmjqLRlab09JDdLKobVhW75ods2w2wsd4fS+lU2/X876wwsD/Ledu3aF5xz2XLNUkiRJkqQ6LorTR6Iku2BxKftNN+0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMA+RXF2qwfgqt9p/UeFcr7wpC7tjq3PLNeeZK+s1fmZP7Tm6bk4e9A6a19t6Vm2zzmgqfWVYueec2xPSQ3QojgNV3f0m10z7KqOgbC0tL7p98sRm04PP37opwH2dtTml5unkiRJkiQ1QFGSfj8Xp2e2jY4+xY07AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwC/OHNj87l6S7PPxW/S7oHgnlfOFJXdPRZ31m+1G/OPuHWp2hKElfZI21v97Ts2Sfc0BT64OdJftJapBe1XukuTWDthaK4dV9y8PCJG36vbJwZDx86fa7AjzRKa96q3kqSZIkSVIj3cMl6Z0LSuPHuXkHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAetSDOXuyxt9p0Y0dPKOcLT+r2Qqf1mYPahzYP1OIM5eL0Zuur/XVRd7LPOaCpdXbvEfaT1AANlDY++vccc2t6XVvsC6NDx7XMfnnL+ZcF2Jctf3SpmSpJkiRJUmN2fa3u4wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAaSS7JPeuCt+pVKG0M5X9hv3fEm6zTLRUn29mqfn/lDY/nKP3u39dX++ouu0gFngSbX+MBq+0lqgC7qTsysaXR3vhjO7V0WFidpy+yVo48/I/zs5w8H2JcPfvTTZqokSZIkSY1anO2I4vTi+UObn+0mHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWtDi0dGn5ZLsIQ+8Vb+TBkZDOV/Yb0cPrbVOs/6IX3pfW9uWQ6p5hir/3HOtrQ7UhzpLB5wFmlz98Ub7Sarz0sHV5tU0urXQFcYHVrfUXlm85PjwtW3/HGB/PnfrHeaqJEmSJEkNXpRkP2hPsle2jY4+xa08AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0kFycbfCoW236o54loZwv7LcT+4+xTnPR8NiqKh6heZV/5r9aVx2oKzsHDzgLdPBuLnbbS1KdtzhJw2c6es2sKXZpVxx6S5tabr+85/1/FeBA7v3mt81WSZIkSZKapChJ76zy/RwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFDPojh9v8fcatN1xd5Qzhf226v7jrROc1L6gWqdn/Z4fNR66mB9smPggLNAB+/S7thekuq8s3qXm1dTaGuhGF7ZtyK0t+BeWfv814QdO3YGOJA9e2TRyGbzVZIkSZKkZipOr5k/NJZ3Qw8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM1tXpSk/+4Rt+rXHW8Kd+eLoZwv7LfzepZaq7npoWf1TfxqNQ5QLs4us546WJ/u6DvgLNDBO6t3ub0k1XFJaUP4aqHDvJpk1xV7w8qhtS25V/LLTgjlf743wGSMrH2RGStJkiRJUpMVJenDUZJd8Mzu9Ndc1QMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQBNaMDw+4vG22jQ+sDqU84UD9sGu2FrNWWO/M9PzM39ozdNzcfagtdTBur7Ye9B5oAN3/OAqe0mq4z5Q+TuNWXXwtld6T8+SUIjHWnavXPR/PxFgstJT3mDGSpIkSZLUrMXpfVGSnejGHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmkwUZ+d4tK02nd17eCjnCwfsumKvtZqjoji9dqbnp/LPOclaajJ9tthz0HmgAzdQ2mgvSXXaxMAx5tQk+lKhKzy3slatvFfGT31j2LlrV4DJ+t03vMuclSRJkiSp6e/sss/l4s0lN/cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANAkckl2i8faatOHOkuhnC8csK8WOqzVnJXuyg1ubp/R+YnTv7eOmkw3FHsOOg+0/z5f6LaPpDotH6fhxg4z7mBd0TkUBuKNLb1XOpefGO6571sBpuKtf/wBs1aSJEmSpBa5t4vi9PL5Q5uf7QYfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa2OJS9pu5ONvhkbbq117ptkJnKOcLB60/3mjN5qiolL5+uucnWpIt3PPAn3XUZLqx2DOpeaB9d1lXbB9JddpZvcvNqQO0rVAMZ/ceHhYmacvvlb/8+LUBpuovPnyNWStJkiRJUivd3SXp96Ph9Iy20dGnuM0HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAGlEuy53qcrTYtH1obyvnCpFozuMaazd3DfHfO4PycZQ012W4q9kx6JujJnd17hH0k1WFxvCF8tdBhTu2nzxe6w/rBY+2VSi84481h9+7dAabq72641RmSJEmSJKkV7/DidGuulB7jRh8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABpMlKSXeJStNr2kf2Uo5wuT6tT+UWs2l4/yDaXJtM7Pnsf8rJ8m2c3F7knPBD25EwaOsY+kOuzC7sSM2k9XdA6FgXijfVKp96jfDvd/+7sBpuNrd3/DOZIkSZIkqZWL02sWjGxa5GYfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaRC5O7/MYW206v3tJKOcLk+pNvcus2RwWJdmfTPnsJGND1k5T6eZi96Rngp5cUtpgH0l11tqhNWG7+fSktlU6u/fwsDBJ7ZPH+sSnPxdgur77/QecI0mSJEmSWr04ezCKs9eNjJz+y274AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgji0sjfV7hK12XVfsDeV8YVK9v3vYms3pQ3zp9zo61j11Kuen8r/zTmunqXRTsWfSM0GP77ZCZ2i3h6S6amGShqs7+s2oJ3RzsTscN7TGHtmrF7/27QFmYvfu3aF4+ITzJEmSJEmSKqVfXxCPrXHTDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdSqKs9d5eK02dcVj4e58MZTzhUn1qY5+6zbHRUl24uRPz5ZDcnF6n3XTVPpssWfSM0GP78rOIXtIqrNe2rfSfHpCl3QloTveZH/s1dCqk8J3v/9AgJlakb3MmZIkSZIkSf+/OL0mWpItdOMPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1Jpdkn/HoWm3aOHhsKOcLk+6rhY7Qbt3mus9M+uyUsqOtl6badR19U5oL+v+d17PUHpLqqO54U/hyodN8eqxtlV7Xu9zf5fbRpz/7xQDVcOJLz3GmJEmSJEnSE3uo0rl9fRP/w80/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADUgfbDJ34litOfemytNr2278hQzhemVKm00drNbbsXLTm+MJnzEyXpJdZLU+3THX1Tngv6r17Sv9Iekuqot/csNZse6/OF7nDc0Br7Yh+97tz3BqiW12y5wLmSJEmSJEn7qxzF6bF+AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOZY+3C21gNrteui7iSU84UptXHwWGs39735YGeno2PdU6Mk/aG10lS7prNvynNB/9XqoTX2kFQnLS2tD3fli2ZTpY90DoaB0kb7Yh8dtv608OCPfxKgWt590YedLUmSJEmSdKB2R3F6+eKlGw71kwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBHojg9z+NqteuGYk8o5wtT6qV9K63dXBdn97a1bTnkQGcnl4wdb600nT7ROTDluaBCuDtfDMV4zB6S6qS/6Cq1/FzaXunc3mVhUZzaE/uofXg83PKVrwWopiuuus75kiRJkiRJBy2K0wdycfqqttHRp/iJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmGVRkn3Fw2q1qTveFLbnC6E8xd7ac5j1q4Pah7O1Bzw7cXaVddJ0+mjn4JTnggrh74u99o9UJ60fXN3yM+krxc4wPrDafjhA57zrkgDVdu2NX3K+JEmSJEnSpIuS9KsLRsZX+KkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACYJYWRid/IxelOD6rVpnRwdSjnC1Pu8q6S9auPrtzf2XnGYet+PYqzn1kjTacPdpamNRtavYu7EvtHqoMWJmm4uqO/pefRnj//ktJ6++EArRx/Wfjpz34eoNr+4avbnTFJkiRJkjTVdufi7LIFI5v+t58QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAGouSbMwjarXr9/qWh3K+MOVuKvZYvzooStKHD40nnrWvs5OL05Otkabb+7uHpzUbWr2ze4+wf6Q66IX9R7X0LDqvZ2lYnKT2wgFavOT48I93fj1ALdxz37ecM0mSJEmSNM27v+wHuTg9s61tyyF+UgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGokirPzPaBWuy7tikM5X5hy2yt1JGPWsC5KX7PPs5Okn7I2mm4XdI9Maza0eicOHGP/SHNcIR4LNxe7W3IGbS0Uw2n9R9kHk+idf/ahQHX85Kc/C9+455sWYi8P/vgnzpkkSZIkSZpZcfr5haWxfj8tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANZBL0js8nFa7bi52h3K+MK2OHlxrDeugKMnueuK5WTS48X9FSfqw9dF0O69n6bRnQyt3xNA6+0ea497Ye0RLzp89f6dbNXScPTCJ1px4ZnjkkR2B6viDd1wcLrniagvxBIVlE86bJEmSJEma2R1gnD4SJdkFz+qb+FU/NQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFXS3jfxjFyS7vJoWm3qjzeGcr4w7U7pP8o61ksj6bLHnZ04O826aCad27tsRvOhFbsrXwyL7B1pThuo/N3m9kJHy82fj3YOPvpntwcOXn7ZCeHuf7onUB23fOVroX14PJx5zp9YjCdYsu5FzpwkSZIkSapKUZz+Sy4eX++nBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoApyydjxHkqrXeMDq0M5X5h2W3qWWcd6eUwvyf788Wcnu966aCa9ofeIGc2HVuzaYp+9I81x7+5Z0lJzZ3ulc3uXhUVx6vtPsvd94KpAdTz40E/Csg2nPbquqydeZUGeYN3zX+vMSZIkSZKk6han10RLsoV+igAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYgF2fv9UBa7Xp93xGhnC9Mu0u7Y+tYN6U/fmZ3+mt7zs2h8cSzKmdnhzXRTHp5/4oZzYdW7KLuxN6R5rBlpXVhW77YMjPnjnxHeP7A0b79FEpPeUPYuWtXoDp+783v/cXaLl5yfPjZzx+2KHv57Zef69xJkiRJkqSqF8XpA7k4PbNtYuKX/DQBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMQ5Rkd3kcrXa9v3s4lPOFaXd9sdc61tMjekl66n+dm/R3rYdm2kkDozOaD63Y2b1H2DvSHHZxV9Iy8+YzHb1h+dBa330KdRzxW+Ff770/UB033HJ7aB8ef9wab93+DQuzl1e96Y+dPUmSJEmSVMN7wewrC0Y2DfuJAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmIL2voln5JJst0fRatf1xd5Qzhem3bZKz0lSa1k/3bLn7ERJepO10EwbH1g9o/nQij1v4Gh7R5qjVg0dF7a3yKz5y66h0B1v8t2n2Ac++qlAdfzowYfCknUvetIa//WnbrI4e3nL+Zc5e5IkSZIkqcalu6I4vfgZh637dT9dAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkxAl2ZiH0GpXIR4L2wrFUM4XZtTy0jrrWU8Nj63KxelOa6GZduzgmhnPh1Zr+dBae0eaoz7cOdQSc+YdPUvDojj1zafYiS89J+zevTtQHa/4g/P3uc7vet8VFmcv7/vAVc6fJEmSJEmalaI4/VYuTk/2EwYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAQUZK9wyNotWv10JpQzhdm3O/0H2096+nRvCT7pnVQNVpWWleVGdEqbcsXw6IktXekOWh8YHXTz5ithWI4tX/U955GPSufH+7/9ncD1XHdTV/e71q/5PfOs0B7+atPXu8MSpIkSZKk2S1Or46WZAv9pAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOxHLk4/7/Gz2nV6/8pQzhdm3Dm9h1tPqQnrizdVZUa0StcVe+0baQ5amKThms6+pp4vtxS7wqqh43zvafaxa24IVMf3f/ijEB97yn7X+pjnvsIi7eX6m//BGZQkSZIkSbNfnP2k8utZbRMTv+QnDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYC8dHeueGsXZzzx8VrvO61kayvnCjLusK7aeUhPWXmlbvliVOdEKXWoWSnPSyQOjTT1bruoYCAOljb71NDv11W8LVM/pr3/nAdd78dLjw44dOy3UY/7xzq87h5IkSZIkae6K0y8uLI31+8kDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4TJSMH+Gxs9r2sc7BUM4XZtyNxR7rKTVpXyh2V2VOtEJbepbZM9IstzhJw40dPU07V97TveTRP6NvPb2GVp0UvvO9Hwaq4xN/d/Ok1v3f/v0/LNZj7v3mt51FSZIkSZI0p0VJ+nDl1zd3dKx7qp9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACg5UWl9PUeOqtd7ZVuL3SGcr4w47ZX6orHrKvUhF3T2VeVOdEKvbj/KHtGmuV+t29lU86TbYViOKNvhW88w/72+i8EquM/v/uDMHD070xq3T936x0W7DHf/+GPnEVJkiRJklQXRXH2z7lSeoyfQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoKXlkuyTHjirXUtK60M5X6haawbXWFepCbu8q1TVWdHMrR0yB6XZLB+n4eZid9PNkjvyHeGEgWN84xn2qjf9caB6Xvzad0x67f/y49dasMc88sgO51GSJEmSJNVT/4+9ew+Ts64P/g/a1tanvz4++vRXmQ2JO6fdmd2duSfZkDPJJkvIaWfDYUU5WPEQRVRQFAzYEn8q4AEqoLSpWCM2HvCAQq2gLXgOKIgcQqhni1VLLSKoiEA+z7175bHWH+AmmdmdnXm9rut95br8A+H+3vc99z18mc/uTFK/bFZ57Kl2IwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0IkO7KrV7zbYrHkd0zcUd3ZnG9am8jLHVWrD3tYzr6H3inaunGxwzkhT2MvKS9vuPvKFXDFWDBxuffezuatPjJ/ce3/QGB/4+D/t1fF/44XvcdB+wzMOOcp1KUmSJEmSWqpMUv9B+udRtiQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANBRMgP1HgPNmtvm0sK4szvbsM7rne+4Sm3Y2b0LGnqvaNduzBacL9IUlk1G4ou5nra6j/xDvi+SZJ313c9mzd0Yn/nSzUFj/PDffxzl5cft1Rq86PQ3O3C/YWDoBNemJEmSJElqyTK10Q/Nmb/u6XYnAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQETLV0ecaZNbcLi0mcWd3tmFdXqg4rlIbdnJ5aUPvFe3aFYV+54s0hZ1WWtxW95Dx57JsMmJtG9CZ5/5N0Bi7d++O405+3V6vwdpjX+ng/YZFGza5NiVJkiRJUsuWqY3eMysZfcEBBxxwoF0KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0ta5k9K8NMWtun8qX4s7ubMO6MVtwXKU27Jn9Kxt6r2jXLuqZ63yRpqh8bSR2ZIttc/84t3d+HFyrW9sGtHjkRfGznz8QNMZ7Lv/kPq1D34rjHLzfMPzMU1yfkiRJkiSp9Uvqnzto3oZeOxUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhbmdrolw0va16za/XY2Z2LO7uzDa1aXe/4Sm3WisrhDb9XtGOnlxY5X6Qp6jXp9dYO942daSf1LbWmDWrO4JFx0613Bo3xve//KIpLjtnn9fjpfT9zEPc44sTXuEYlSZIaXE+yYaIkWReDlbWxuHJ4DFVWT1QfWPXfOqZvKI7tX/HrTuxbHpvKy37dyeWlcVpp8T71ivLi//bXGm/8r/+b/3/jHTWw8r/9Pa2qHDbx97qksmbi779WXffrf6ZZ1leSNI1lktEHupKRzfPmbfp9OxYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGgr+fyaJ2Vqo780uKx5jQ/rvLM72/COHFjp+EptVjnZ0JT7Rbt1XN9y54s0RYPTb8wWZvw9Y/yfYcPAsDVtYG+5ZHvQGI88sjuOesGZ+7Ue//Ktf3Ug9zju5Ne5RiVJUseVTUZioLouFlXWxMrK6qgPrIpn9q+ME/pWxKbysjilvCReXV4UW0oL4rze+fFXPfNia7EWlxWr8cHCQFyZ74tP5UtxXb43vpArTrxD3ZTNd9R3TV9L/3nH/7l3ZIsTx+Hq9HiMH5f3FSrxnkJ14nhd0DMYb+qZP3EczygtjleUF08c3z/vOzSe3b9iOY1kMQAAIABJREFU4riPH/+F1TXRX10/sS7OT0nSZMok9VsPrtUH7VwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKBtzKpuPMSwsuY2PlCzGYM+Ty8tcnylNuyWDhtavC+NDyh2rkjN76zSwhl/v7g21zsxWN56Nq7Dn/2K+NWvHgoa453br9zvNfn8Dbc4kHu86PQ3u04lSdKM6+BaPfqS9RPvLodXDoux/qF4ft+hcWp5SZyZvped0zs/LuyZF5f2JPH+wkBcme+beNe5IVuInd053xW1cOPr8+VcIa7L906s2wfS9bu0mMRFPXPjvHRdX1taEKek63xi3/I4Kl331en6L6yumTgfZid114ckdVLJ6EOZpH5ePr/mSXYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw42WS0ZcYVNbcNpcWNWUg5zuLNcdXasM+nSsZOvw7KicbnCtSkyum19mN2cKMvld8tNAf/cl669nAuhccHbu+8d2gMb75ne9HbuHYfq/LRz5xnYO5x6ted7FrVZIkTXuFZCQWVNfE4ZXD4pi+oTipb2mcUVocbywdEhf1zI1thWpckb6v/HOuN76SLfquR4/Z+Hv5tel58rF8f7y3WIl3FOfGeb3zJ/6dw4vLy+KY/qGJ82z8fBs/71x/kjTzy9RGb59V3XiIXQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMxoXbX6uw0oa26X9NSaMlDzunyv4yu1YdsLFUODH6ebu/POE2kKOrO0aEbfK/6mZ25kDRRveFvf+7GgMR55ZHccceJrGrIu79j2UQd0j7PfcqlrVZIkNaVi+n6xpLIm1g6sihP6VsRLy0vjtaUF8Vc98+LdxSSuKPTH53I9cUs27/sbTVu3ZnMT5+HH8v2xLT0v35aen2f3LoiXl5bEc/qXT5y/C6trIud9WZJau2T0oUxt9MKD5m14st0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMSJna6O2GkzW3T+T7mjIgc1daT7LBMZbarLf2DhoC/Dh9Ml92nkhTMCz+K9nijLxHjD8fbSktiFnWseEdceJr4uFHHgka4+1/9+GGrc3Zb7nUAd3jLZdsd71KkqS9ak6tHpXquhiqrI6j+4diU3lZbC4tjPN7B2NbMYkr831xY7bgOxm1Xbdmc3Fdvjc+nO+PrcVanNs7P04rLY4T+5ZHfWBVLK6uiUIy4j4hSdNYJql/c1aycbkdDQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzCh/Wh77466k/rChZM3r4Fo9bsnmmzb4ct3AsOMstVmvLC8x2PdxencxcZ5ITe7V5UUz8v5wW3cuTuhfbg2bUHHJMfHdu34YNMbXv31XZBeMNWx9TjrjLQ7qHpds+6hrVpIk/bpZaQPVdTE8cFgc17c8XlFeHOf1zp/4buGqfDl25Iqxy3ct0uO2I1uMK/N9cWl63ZyTXj+nlpfEsf0rJq6r8etrlnuNJDW73ZmkvnX83+vb3QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwIwwq1Y/1CCy5ja/urapAy3HB1g6zlJ7dUzfkIG9j9O5vfOdJ1ITyyUjcX22OOPuDTd352N0YKU1bFIf+Pg/BY3x0MMPx7rjX9XQ9Tny+Wc6sHtc9qFPumYlSeqg5tTqcUh1bdQHVsUL+g6NzaWFcVHP3Hh/YSCuzfXGbd0536VITe729Dq7Lt8bH0yvu/Hr77WlBfHCvmWxYWA4BtPrc7Z7lSQ1qm93zR1ZaYcDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtL5OMnmYAWXM7un+oqQMr394z13GW2qyllcMN5H2cTikvcZ5ITey00uIZd1/YkSvGivTeaf2a04mnvjFonPP/5v2Nf3YYPcmB3eOKf/ys61aSpDarJ9kQQ5XVcWz/ion3lfN7B2N7oRLX5Xtjp+9JpJZv/Dr9Uq4nrsz3xdZiLbaUFsSm8rKoD6yKwcramOU+J0l70+5MUt/6tJ76/2OnAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALaurVn+f4WPNbXzQazMHUl6TKznOUpuVTUZil4G7j9kx/UPOE6mJ958d2eKMuidcm+uN+dW11q9JVVaeEHf/+CdBY9y261sxZ/6RDV+n4pJjHNw9PnntDteuJEkzrNm1egxW1sbIwKrY1Lcszu5dEFuLtbgy3xc3Zgu+C5HavJuy+fhEer1fWkxiS2lBvDC9D6wdGI7+ZL17pCQ9ZvXvZJL6sN0OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0pK6kfoehY83twp55TR04uTObi2wy4lhLbdYXcz2G6j5Gh1ZWO0ekJnVqefGMuh98PN8XfYZsN7V/+PQXg8Z48MFfxaqxlzdtrX754IMOcupTn/2ya1eSpBasJ9kQQ+n7/LH9K+K00uI4v3cwthcqcV2+N3b6rkPSY3Rbdy6uzpdia7EWW0oLYlN5WdQHVkV/1XcBkpS2O5PUL5tVHnuqXQ8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALSMWQvH/qgrGX3IwLHm9rF8f9MHSw4PHOZYS23WBwoDBuc+RsVkg3NEakLPqNXjS7meGXMveE+hGrlkxNo1sVecfWHQOOdcdFlT1+vuH9/jIKeu/cJNrl9JkqahnvRdfUXl8DimfyhOLS+O83rnTzyzX5Mvx63ZnO8zJDW8G7KF+HC+Py7oGZy47xzRvzIGq2tjlnuypA4rk9R/cFAyMmr3AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALeHgWn3QoLHmd1O20PThkSf1LXWspTZrfPi04bj//25M76nOD6k5vai8bMbcCy7umReza3Xr1sQOWfuCuO/+nweNcdOtd8bseUc0dc2+8Z27HOjU567/mmtYkqQmdHD6/F2rrov1A8OxqW9ZbCktiL8t1uKqQnniXd13FpJapVuy+Yl70zuKc+PV5UVxTP9QLKqs8T2CpA6o/u7svLH/aRcEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADT6qBk9PmGizW3vmT9lAyJPL9n0PGW2qyTy0sNwX2UxgfiOj+kxjc7qcc/53pnxH3g3N75McuaNbWD522ML3751qAxfvnggzF01Eubvm433Xqng50aP3ddx5Ik7eN7Qa0e86trY2P/qonvJd5YOiTeXUzimnw5buvO+V5C0oxuZ3ofuzpfir8t1mJzaWE8q39FHJLe88a/E/EZIKldyiT1H3RV6+vthAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYNpkkvpFhos1t8MGDpuSYZD/kO9zvKU2a/3AsGG3j9I7izXnh9SEju9b0fLX/660V5QXW68paMtb3xU0ztlvuXRK1u26L97kYKeu/+pO17EkSY/TnFo9Bitroz6wKjaVl8WW0oLYmr5rX50vxU7fO0jqwG7vzk3cAy/umRenlRbH0f1DE/dJnxmSZnC7M0l965+Wx/7YjggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKZcJhn9rKFize25fYdOydDH8YG3uWTEMZfaqP7qekNtH6XX9y5wfkhN6Mp8X8sPuD6hb4W1moJWHHlyPPDLB4PG+PLNd8TseUdMydp97OrPOeCpm26907UsSer4ZtfqsbC6Jo7uH4pTy4vj/N7B+EBhID6f7YldvluQpEm1I1uM7YVKvKH3kHhB36ExVFkdc9L7q88ZSTOob89KNi63KwIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgKl0YKY2eo9hYs1tc2nhlA14PLxymGMutVlfzhUMsP2tTi4vdW5IDW60f2VLX/c3d+djdGCltZqC5gweGV+7/etBY/z8Fw/EkvqLp2z9LvvQJx301C07v+F6liR1TD3JhlgzMBybystiS2lBbC3W4sp8X9yazfkOQZKa0M60q/OluLhnXpxWWhxH9w9FqbrBZ5KkVm53JqlvPWjehifbHgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQNM9vXbkHEPEmt87inOnbJjjKeUljrnUZl1eGDCs9rc6amClc0NqcB9o4XvNjlwxVlQOt05T1AVbPxA0zmve+NdTun5v/7sPO+ip2+/8tutZktRW9SQbYqiyOo7tXxGnlRbHxT3z4sp8X9zcnfc9gSS1SF/K9cS2YhKbSwvj6P6hGKiu8xkmqdXaeXCtPmiXBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATZWp1euGhzW/Kwr9Uza08ZLiXMdcarPO651vKO1vtaSyxrkhNbBVlcNa9nr/51xvDFbXWqcpau2xr4yHHno4aIzP33BLzJq7cUrX8I0XvseBT935je+5piVJM67ZST3mp8++R/cPxWmlxfFXPfMmvlf8cq7guwBJmqF9MdcT7y4msbm0KI7oXxnlZIPPPEnTWzL6UCapn1cuj/2B3RIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADRFJhn9C8PDmt8N2akbfHttrtcxl9qsTX3LDKD9rXLJiHNDamCX9iQtea1fnS9FpbrOGk1R2QVj8S/f/F7QGPfd//M4ZO0Lpnwdz3jDJQ5+6hvfuct1LUlq2ebU6rG4uiaO7V8Rp5UWx8U98+LKfF/cks1755ekDuhLuZ7YVkxic2lhHN0/FL3Jep+Pkqa8TFK/NVMdTeyYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACg4bpqo5cbGtbcepINUzqMcVdaqbrBsZfaqKHKasNmf6Md2aLzQmpgC6pr4o7uXMtd6x/P9xkqPcW9631XBY1z2paLp2UdTzrjLQ5+6rt3/dB1LUma9srJhlg7MBybysviDb2HxHuLlfhMrnfi+zvv95Kk/9v49zJX50txUc/cOLm8NIYHDotn1Oo+SyU1vUxt9JcH1UZPP2Bs7Il2TgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0DCZ2ujtBoY1t6HK6ikfwLixf5VjL7VR4wNUd3bnDJjd01WFsvNCamBv7R1suev88sJAFJMR6zOFHfOiv4jdu3cHjfHpz31l2tbyxFPfaAFSd/3gbte2JGnKqlbXR31gVZxSXhLn9wzGh9Ln2S/nCt7hJUn73O3dubii0B9vLB0Sx/Utj1p1nc9cSU0rk4zuyAzUe+yeAAAAAABgOkTE76X977RC2vy04bT1aWNpz03blHZ62plp56W9NW3ro/T+tMslSXvdQp9GAJN+dl34G/fP9zzKM+lf73lmHf+Pe85IO3XP8+yxe55vD0tbkZakPSPtfzqqAAAAAAAAAAAAAADsLfvbAQAAAAAAmBmWL/+9TG30lwaFNbcT+lZM+bDF15QWOfZSm3V1rmyY7J62FRPnhNSgepP18bVsvqWu8Q8UBiJfG7E+U3keLHt2fP+HdweN8dP7fhaDa543bet5/EtfZxFSP/z3H7u+JUkNryfZEGsGhmNTeVmc2zs/thcqsSNb9K4uSZqSvpTrmfhudHNpYdQHVkU28f2JpMaVSeq/SP8844ADzn6CjRQAAAAAAOyPiHhaWjltedqz0l6e9vq0d6Vdmfa5tNvS7kq7345HgGk35tMLYNLPumNNuA/vTrsn7VtpN6X9U9qH0i5O+8s9P1peT1uU1p32ZCsBAAAAAAAAAAAAANDZ7G8HAAAAAABgRshUNhYNCGt+p5cWTflgxXcXE8dearPe3jPX4Ng9nd8z6JyQGtTmaXhOebzGB0N3J3VrM8V95BPX+RnwBjp581undT2PedFfWITU3T/+ietbkrTP9SfrY8PAcJxcXhpv7R2MywsD8ZVs0Tu5JKmlur07Fx8t9Mcbeg+J4/qWR7W63ue4pP0vqX/+4Hkbc3ZTAAAAAADwaCLif6fV0kbSXpr2prTtaZ9P+17ar+xgBJhxxnzCAUz6eXisRe7d96ftTLsm7dK0s9Oemzac1pP2R1YLAAAAAAAAAAAAAKB92d8OAAAAAADAjJCp1esGgzW/t/XMm/JBijuyRcdearNOLS8xKHZPZ5UWOiekBvSMWj125Iotc21f0lOL2enfk7WZ2l74qvP8BHgDXX3d9dO+pkc+b7OFSP3k3vtd45Kk31mpuiHWDwzHS/qWxpt75sflhUp8OVfw7i1JmrFdl+uNi3rmxqa+ZbG4crjPe0n7VCap35tJRv7cjgoAAAAAgM4UEf8rbd6eH1TcknZ52o1p99mdCNCWxnz6AUz6WXlsBt3f79nzHD/+PD/+H5BtSlua9hQrCQAAAAAAAAAAAAAws9nfDgAAAAAAwIzQVRs9w1Cw5nd5YWBaBifOra51/KU2au3AsKGwe3pReZlzQmpAL+xb1jLX9cU982K2NZnyqqueE//xn/f6CfAG+c+f/DSS4T+f9nXdcMKrLcb4zsh773OdS5J+3exaPRZX18Sx/Stic2lhbCsmcV2+N3Z5x5YktXk3ZfOxvVCJ00qLY83AcMxJPxM9G0iabJlk9COZ+RufZmcFAAAAAED7iYjfTyvv+dHEs/f8EOGtaQ/YgQjQccZ8MgJM+jl6rE3u/f+R9sW0v007Ne2wtC4rDAAAAAAAAAAAAAAwM9jfDgAAAAAAwIzQVau/2zCw5velXM+0DEocHxLs+EvtUzYZiZ2GwE401j/knJD2s1lp1+RKLXFNv6lnfhxsoPO09OnPfcXPfzfQple/qSXWdc2zX2kxxnc//ue9rnNJ6tBq1XVx5MDKeFV5cVxSnBtX58rp+3TO+7QkSWk3d+dje6ESZ5YWxYaB4YnvnT0/SPod/airWl9vdwUAAAAAwMwVEXPSNqadnXZ52u1pv7LTEIA9xnxaAkz62XqszT8TfvIbP0Z+StrytD+x8gAAAAAAAAAAAAAArcX+dgAAAAAAAGaETDK6wxCw5tad1GPXNA1GfH3vAmsgtVn/mC8b/Jo2VFntfJD2syP6V7bE9byl5Hllunr169/hp78b6KOf+EzLrO3KsZdZkNS//8c9rnVJavPm1OqxuLomTuxbPvFcua2YxI5s0XuzJEl70c60K/N9E5+l9YFVkU1GPGdIerR2Z5L61oPmbXiyXRYAAAAAAK0tIjJpI2lb0q4a305nRyEAv8OYT1CAST9vj3XoZ8UP9rxfbNnzvvF0ZwMAAAAAAAAAAAAAwPSxv93+dgAAAAAAgBkhUxu9xwCw5nZIde20DUK8otBvDaQ264KeQYNe0yrVdc4HaT97X6Ey7dfymaVF1mKaWrRhU9z/s1/46e8G+dHd/xl9K45rmfVdtvEkizK+m/FHP3a9S1IbNbe6Np7Zv3LiGfLSniSuzfXGLu/HkiQ1vFuzubi8UJn4zF07MBzPqNU9i0j6r5L6HZlKvWanBQAAAABAaxj/ob+0jWnnpX0m7T67BwHYB2M+VQEm/Qw+5mPj1+5K+0jaq9KWpj3ZGQIAAAAAAAAAAAAAMDXsb7e/HQAAAAAAoOXNnnfEQQZ/Nb8NA8PTNvhwZ3cussmIdZDaqE3lZR0/1PWO9N4227kg7VdLK4dP63W8K+3k8lJrMU0dPG9j7LjxdtvaGuiEl/1/LbXGC9e/0KKM71z8wd2ueUmagY2/7y2urolj+1fE5tLC2FZMYke22PHvwpIkTVe3ZPPx4Xx/bCktiPrAqnhGre6ZRerwMkn9V+mfWw4YG3uiXRcAAAAAAFMnIp6Utijt1LT3p33XTkEAGmTMJy3ApJ/L/ej4Y3so7ca0t4//51ZpBWcMAAAAAAAAAAAAAEBz2N9ufzsAAAAAAEDL66rWhwz9an4n9i2f1mGHawaGrYPURh1aWd3xQ1x35IrOBWk/O793cNqu4Tu6c/HCvmXWYRp749u22cLWQO+74tMtt8bzDn+ehUl97/s/cs1LUotXSEYmvrs6ubw0LugZjCvzfXFb+rzY6e+9kiS1cl/L5uO9xUqcWl4cyyqHxyzPNFIHV//i7MEjs3ZeAAAAAAA0R0T8ftq8tDPSPp32CzsDAWiSMZ+8AJN+Tvej43vnR2lX7XmvGX+/eYKzCAAAAAAAAAAAAABg/9nfbn87AAAAAABAy8skG08y6Kv5nVFaPK3DDU9L//+tg9Q+zU4bH1rayUNbr8qXnQvSftSTbJi2+8iutJP6llqHaWzV2MvjwQd/Zbtag/zw338cpUOPbbl1rqw8weKkvvOvP3DdS1KLPYeuGRiOl5WXxsU98+LqfCnu6M519PutJEnt0PXZYmwt1mJTeVnUqus890gdVqZW/8msZPRYuy8AAAAAAPZfRDw57bC016d9Pu2XdgICMEXGfBIDTPq53Y+O75+70z6c9vK0StqBzioAAAAAAAAAAAAAgL1nf7v97QAAAAAAAC2vKxk936Cv5nd+7+C0DjP8u2JiHaQ2632FSkcPad3mvibtV68oL56Wa3dX2kv6llqDaewZhxwVt9/5bVvTGmT37t1x7Eu2tORa9y57tgVKffM733ftS9I0Vauui2P6h+K1pQVxWbEaO7LFjn6PlSSpk7omX45ze+fHUemzQL424tlI6pjq75tTHX2KXRgAAAAAAHsnIvrSzkj7dNoDdv4BME3GfCoDTPoZ3o+ON/5HyC9P25Q22xkGAAAAAAAAAAAAADA59rfb3w4AAAAAANDyumqjHzPcq/mNDw6ezuGFN2QLMcs6SG3V5tLCjh7Ken7PoPNA2scOrtXjunzvlF+3u9Je0rfUGkxzF7/rQ7ahNdC7P/iJll3r3qXPtkCpO77+Hde+JE1Bteq6OKZ/KF5bWjDxPdiObLGj31klSdJ/tbM7F5cXBmJzaVEMDxw28d2U5yepjUvq/9pVrQ/ZiQEAAAAA8Ngi4s/2/Ejh1rR/s9MPgBYx5lMaYNLP9H50vLm+ted9afw4/4kzDgAAAAAAAAAAAADg0dnfbn87AAAAAABAy8sk9VsN92p+V+fK0z60cGF1jbWQ2qj6wKqOHsS6ubTQeSDtY2P9Q1N+ze5Ke0nfUsd/uj87/vz0ePiRR2w7a5Dvff9HUVxyTMuud+nQYy1S6ubbvu76l6QGV6mui6PTZ8rx97JtxSR25Iod/X4qSZL2ri/nCrG1WItN5WUTzxWer6S2bHemNnphPr/mSXZkAAAAAABM/CDhE9LmpW1JuzFtt919ALSgMZ/aAJN+xvej41PnobQvpJ2RVnT2AQAAAAAAAAAAAAD8F/vb7W8HAAAAAABoeV21+v2GejW/m7KFaR9S+IK+Q62F1EblkpHY2Z3r2MGrLyovcx5I+9j2QmVKr9ddaSeXlzr201xh8THx7e/9m21mDfLII7vjqBec2dJr3r/ieAuVuv6rO90DJGk/qlTXxdH9Q7G5tDC2FZPYkSt27HuoJElqTlfnS7GltCDqA6tidq3uGUxqozK10du7kiOqdmUAAAAAAJ0oIp6cNpK2Ne0HdvMBMAOM+QQHmPTzvh8dnz7fSrswbTjt95yNAAAAAAAAAAAAAEAns7/d/nYAAAAAAICW9v/2j/yZYV7Nr5CMtMRQwgt6Bq2H1GZ9PN/XsYNWx/qHnAPSPrSguiZ2TeG1Ov7/dXJ5qWPfAl32oU/aUtZAf3PZx1p+zSsrT7BQqc/uuNk9QJImWTEZiTUDw/Gy9Plta7EWO3LFjn3nlCRJ09NXssWJ55BN5WVRra73jCa1QZlk9IH0zzMOOODsJ9ihAQAAAAC0u4h4etqL065J+6UdfADMMGM+zQEm/ezvR8dbw7+nvSttfdqTnJkAAAAAAAAAAAAAQKexv93+dgAAAAAAgJaWqW1cZJBX81tSWdMSgwg/lS9ZD6nNekPvIR07XHWosto5IO1Db+qZP2XX6a60k8tLHfcW6LiTXxe7d++2jaxBvvGduyK3cKzl1z0Zfq7FSn36c19xH5CkR6k7qcdhA4fFS9PntXcU58Y/5UoTz293SpIktUjjzyZXFcpxVmlhrKysjlme4aQZXv2aOfPXPd0uDQAAAACg3UTErLRNaVelPWTXHgAz2JhPdoBJvwf40fHW8/M972XPSftjZykAAAAAAAAAAAAA0Ansb7e/HQAAAAAAoKV11UaON7yr+Y32r2yZ4YPlZIM1kdqoY/qHOnagarW63jkg7WWFZCS+2p2fsueOl/QtddxboNKhx8YPfvRj28Ya5KGHH44NJ7x6Rqz9vMOfZ8HGdwt+6gvuBZKUNlhZGyf2LY9ze+fHh/P9cWs217Hvk5IkaWZ2fbYYF/fMi2P7V0x8z+UZT5qJ1e/OzN24wU4NAAAAAGCmi4jutFel7UjbbaceAG1izKc8wKTfCfzoeGv7Wdrlacf4AXIAAAAAAAAAAAAAoJ3Z325/OwAAAAAAQEvLJPW/NLir+b2wb1nLDBw8qn/ImkhtVE+yIXZ24CD0XWmza3XngLSXvbi8bMqu0ZPLSx3zFunj13zeNrEGuvhdH5oxa3/I2hdYsNRHPnGde4GkjqtSXRdH9w/F5tLC2FZM4ivZYse9N0qSpPbu1mwuthcq8bLy0qilzz6eAaUZ1e5MbfTCfH7Nk+zYAAAAAABmkoh4atqmtC+k7bY7D4A2NOYTH2DS7wd+dHzmeCDtqj1r9gfOXgAAAAAAAAAAAACgndjfbn87AAAAAABAS+uq1d9taFfzO7O0sGWGDJ7du8CaSG3Wlfm+jhuYemO2YO2lfeiqQrnp1+eutJPLSx3vFuklr3mrbWEN9C/f+tfILhibMeu/bONJFi31vis+7X4gqa3rTupxeOWwOLW8OC4tJvGlXE/HvSNKkqTObvz7qPHvvTaXFsZQZXXM8owozYyS0ZsylY1FuzYAAAAAgFYWEX+054fpxn+g7ld25AHQ5sZ8+gNM+l3Bj47PTPekXZY2nHagMxkAAAAAAAAAAAAAmOnsb7e/HQAAAAAAoKV1JfXPGdjV/N7WM69lBgsqw0toAAAgAElEQVR+qDBgTaQ2a0tpQccNSb0212vtpb1seOCwKbk+TykvcbxbpLmrT4yf3Hu/rWAN8tDDD8faY185s677Z55i4VKXbr/SPUFSW1Wrrovj+1bEOb3z44pCf9zeneu4d0JJkqTH64u5nnhzz/yoD6yK2bW6Z0iphcsk9V90JfVT7NwAAAAAAFpJRDwxbV3a+9J+bhceAB1kzJMAwKTfG/zo+Mz33bRz0krOaAAAAAAAAAAAAABgprK/3f52AAAAAACAlpapjX7fsK7mt71QaZlBguODlrPJiHWR2qiN/as6bijqx/L91l7ayy7smdf0a/PM0iLHukWaNXdjXPuFm2z9aqC3XLJ9xp0HG054tYVLve2dH3RfkDRjm502VFkdLysvjYvT57nrcr0d9/4nSZK0P92YLcTWYi1O7FseBf9+TGrZMkn9w7MH1v8vOzgAAAAAgOkUEcW0LXt+eA4AOtGYJwKASb8/+NHx9nJj2ilpT3V2AwAAAAAAAAAAAAAzif3t9rcDAAAAAAC0rHx+zZO6avVHDOlqfp/Ml1tqgODIwCrrIrVR2WQkbuvOddQg1MuKVWsv7UU9yYa4JZtv6nV5bu98x7qF2nzOX9vq1UC37fpWzJl/5Iw7D45+4VkWL/XGt21zX5A0Yxqorouj+4dic2lhbC9U4tZsZ73rSZIkNbPxZ6ttxSQ2lZdFf7Le86fUen27a+7IQjs5AAAAAICpFBF/tOfHAj+dttuOOwA63JinA4BJv0v40fH29EDa5WnDaQc60wEAAAAAAAAAAACAVmd/u/3tAAAAAAAALevgeRtzBnNNTTuyxZYaGnhWaaF1kdqsywsDHTX89O09c627tBe9vLSkqdfkRek1OctxbpkWbdgUP/v5A7Z4NciDD/4qVo29fEaeC8ed/DoLmNp8zl+7N0hqyWYn9Ti0sjpOLi+NS3pq8blcT0e910mSJE1nO9PeV6hMPIslyTrPp1KrlIw+lP655YCxsSfa0QEAAAAANFNELEh7V9r9dtkBwK+NeUoAmPQ7hR8db3/fTDsr7enOeAAAAAAAAAAAAACgVdnfbn87AAAAAABAy5qVbFxuMFfzO7hWnxjM10qDAi8vDFgbqc06s7Soowaents737pLe9E1uVLTrsdLi0nMTuqOc6s8e87bGNd/dactXQ30hrdtm7Hnw/Nfea4FTL3srAvcHyS1RNlkJNYODMfp6fvbZcVq3JTNd9R7nCRJUqu2K+2KQn+cWl4cc6trPbtKLVCmNnrtrOr6Lrs6AAAAAIBGiog/THtO2lftrAOARzXmiQFg0u8XfnS8czycdlXacNqBzn4AAAAAAAAAAAAAoJXY325/OwAAAAAAQMuaVa0fZyBX8+tL1rfccMDbu3MTg5ytj9Q+DQ8c1lFDTl9TWmTdpUm2bmC4adfi3xeq8Yxa3XFuod709r+3jauBbrzlzpg974gZez689KwLLGLqea84x/1B0rRUSEaiPrAqNpcWxvZCJW7N5jrqvU2SJGmmdnW+NPEMN7+61nOtNJ0lo/+RqY2O2NkBAAAAAOyviCimnZf2n3bUAcDjGvPkADDp9ww/Ot6Z/iXtjLSnuQoAAAAAAAAAAAAAgFZgf7v97a4CAAAAOtac5cv/sKs2Ukk78qDayEu7aqOv60pGz88k9a17uihTGz0n/d/POCgZff5B1Y2rn17bWDpo3oYnO3oAAFMjU62/2jCu5re4uqYlBwJuGBi2PlIbdXCtHtdnix0z1PQlfUutuzTJLinObcp1+IHCQGSTEce4hVr9rFPjV796yNatBvnFA7+MZRtPmtHnxFnnbrWQqWdu+gv3CElTUqW6Lo7tXxHn9s6PK/N9cUd3rmPe0SRJktq1q/Ol2FxaGPOraz3zStPT7vG9puP7Ue3wAAAAAAD2RkT83p4fAbzOLjoAmLQxTxEAk37n8KPjne3nae9MS1wNAAAAAAAAAAAAAMB0sr/d/nb72wEAAOgkB2aS0cVpF3Qlozd1JfWH92kIQjL6UKZWvy7967zqoHkbeh1WAIDmydRGLzSEq/mtHxhuySGAZ5YWWh+pzbqkOLdjBpke37fCmkuTqJhsiFuy+YZfgx/L90chGXGMW6jsgrG48xvfs12rgf7ize+c8efFm97+9xYyte74V7lPSGp4s9IWV9fEyeWlE+9in8/2dMz7mCRJUie2K+2KQn+cWl4cc6trPRNLU1ymVv/a02sbS3Z5AAAAAAC/S0T8Sdopad+1ew4A9tqYpwmASb97+NFx/q8v7DkfnujKAAAAAAAAAAAAAACmmv3t2N8OAABA25szf93Tu2qjr8sk9W82ZRhC+tfN1Ebflv45XC6P/YEjDgDQOJlk9CMGcDW/4/tWtOTwv8sLFesjtVkn9i3vmAGm9YFV1lyaRCeXlzb8+vtkvhy9yXrHt8Xa+t6P2Z7VQDfcfEccPG/jjD8vLtn2UYuZWjp6kvuEpP1uVtqS6uETz1d/W6zF9dlix7x/SZIk6b+3K+2KQn+cUl4Sleo6z8vSVJWM/nxWMvoCOz0AAAAAgEcTEbm0C9N+ZtccAOyzMU8VAJN+B/Gj4/y2b6WdkfYUVwgAAAAAAAAAAAAAMFXsb8f+dgAAANrWn5bH/jiT1M/uqtXvn6qhCJna6D3pn9u6qvX1+fyaJ1kFAID9k0lGrzd8q/mND1tuxYF/t3XnIpuMWCOpjepL1scd6bXdCUNLV1QOt+bSJLqqUG7otXdtrjcGDApuucY2vTYeeWS3bVkN8vNfPBCLR17UFufG33/kGgua6l9xvHuFpH1qsLI2NpWXxdZiLW7IFjriXUuSJEl71/h38h/O98fLykujP1nvOVqami6fUx31H2cCAAAAABMiYjjtH9IesVsOAPbbmKcLgEm/i/jRcR7LvWnnpz3DlQIAAAAAAAAAAAAANJv97djfDgAAQFvKVEeTTDL6jekcjJCp1X8yPhyhK6k/588qh/0PqwIAsA/Pdcnovxm41fzOKi1s2UF/6waGrZHUZl1VKHfEoNJadZ31ln5Hh1ZWN/S6+3y2x7XXgvUue3Z8/4d324rVQKe//h1tc35c+akvdPx6PvLI7jh43kb3C0mTarCyNjaVl8XWYi1uyBY64t1KkiRJjWtnNhfbC5U4sW95FJIRz9hSM0tGv5epbVxk1wcAAAAAdKaIeELaSNoNdj0CQEONedIAmPR7iR8d53f+Z01pV6UNumIAAAAAAAAAAAAAgGaxvx372wEAAGg7s2ojazJJ/RctNiDhp+nf03sPSkZG5yxf/odWCQBgEpYv/72upP6wgVvN7629gy073G9zaaE1ktqs15YWdMRwUgNJpd/dub3zG3bN3ZQtxKGV1Y5rC/aRT1xn+1UDfe76r8WsuRvb5vz4zJe+2vFreu9P73evkPSYDVbWxqbystharMUN6fNOJ7xLSZIkaWq6NZuLbcUkju1fEXNqdc/fUhPK1OoPdiX1Uw444IADbQABAAAAgM4QEX+Q9py0O+14BICmGPPEATDp9xM/Os7e+ELaiCsHAAAAAAAAAAAAAGg0+9uxvx0AAIC20pWsL2SS+i9aelhCMnpfplbfPmtu/YhZC8f+yKoBADy6zODowQZtTU2X9iQtO9Dvg4UBayS1Wasqh7X9MNLbunPWWvodjQ/qvSFbaNgA4LUDw45rC/ai099su1UD/fS+n8Xgmue11Tly821f7/h1/e5dP3S/kPTrFlbXxEv6lsalxSS+ki22/buTJEmSWqPxZ88LegZj3cBwHFyrezaXGlwmGf3onOroU+wCAQAAAID2FRF/nHZK2vftdgSAphrz5AEw6fcUPzrOvrhxz7lzoKsIAAAAAAAAAAAAAGgE+9uxvx0AAIC20lWrv2VmDUyo39+VjL6/qzZy5Jzly//QCgIA/Maz3dyRhQZsTU0fzve37BC/27pz0Z0Y3ie1U7PSvpBr7+HwX8z1WGvpd3R834qGXG93pM8Kz+pf4Zi2YHNXnxj33HufbVYNdMpfvK3tzpO7fnB3x6/r127/unuG1MH1J+vj2PRZ5vzewfhsrret35MkSZI0Mxr//v7c3vlxaGW1Z3apsX17VrJhvp0gAAAAANBeIuKpaa9Pu9cuRwCYEmOeQAAm/b7iR8fZH7elPSvtCa4mAAAAAAAAAAAAAGB/2N+O/e0AAAC0lUwyumPGDk1IRn+aSeqXpX+umzdv0+9bTQCg06XPSEcZrDU1/VOu1NLD+9YNDFsnqc0aHxjfzkNHP5kvW2fpd/T3xWpDrreTy0sdzxZs1tyN8ZkvfdXWqgb61Ge/3JbnygO/fLDj1/a6L97kviF1UPnaSNQHVsWW0oK4Mt8Xu9r4vUiSJEkzv6vzpTittDj6k/We56UGlKnVH+xK6i8/4IADDrQjBAAAAABmtoh4atqWtJ/Y4QgAU2rMkwjApN9b/Og4jbAz7TlpT3RVAQAAAAAAAAAAAAD7wv527G8HAACgrXQlo//RFgMUkvqPM7XRv+2aO7LygLExL9wAQEfKJBtPMlhraropW2jpgX2vLS2wTlKbddTAyrYeNPrBwoB1lh6nWnVd3NGd2+9r7azSQsezRTvr3K22UzXQPffeF8nwc9vuPOlZ8iyLm7riHz/rviG1cbPThiqr47TS4theqMTOBjwDSZIkSVPdzmxu4nn2xL7lkU1GPOtL+1kmGf3onOroU+wKAQAAAICZJyKelrYl7Sd2vwHAtBjzRAIw6fcXPzpOI93hx8cBAAAAAAAAAAAAgH1hfzv2twMAANBWumr1+9twgMIPM0n9ooOqI0vSf8QDrTIA0CnSZ6C/NFCr+T2jVo9dLT6o74pCv7WS2qzupB5fy+bbdsDou4pV6yw9Tq8qL97v6+yCnkHHskU79IiXxC8e+KVtVA304tPf3JbnypL6iy1u6tLtV7p3SG3UwbV6DFVWTzzvbC9U4pY2fu+RJElSZ3ZjthBv7R2MwyuHxSzvANL+9O30HXLQzhAAAAAAmBki4mlp56TdZ9cbAEyrMU8mAJN+j/Gj4zTrx8ePTXuCqwwAAAAAAAAAAAAAmAz727G/HQAAgLbSVat/p50HKWRq9bsytdELD5q3cWn6j3ugFQcA2vzZ7h0GaTW/JFnX8sP5dmZz0Zust15Sm3VpT9K2Q0Xf3jPXGkuP09W58n5dY9uKScx2HFuyOYNHxs23fd3WqQb65LXXt+35MvrcMyzw+JSViy5z/5BmeP3V9XFi3/K4pDg3bsgW2vY9R5IkSfrtrs31xmtKi6JWXefdQNqXktGH0j/PsBcUAAAAAFpXRPyPtPHNbvfa7QYALWHMEwrApN9n/Og4zf7x8fFzzL4XAAAAAAAAAAAAAOBx2d+O/e0AAAC0lUyt/o+dMlAhUxv9elcy+vqDqyN9Vh4AaEddSf2DBmk1v2WVw2fEUL5n9a+wXlKbNT50vl0Hib65Z741lh6jocrq/bq+rij0Ry4ZcSxbtAu2fsB2qQb68T0/jeqq57Tt+fL8V55jkVOvPPsi9w9phjV7zzPN5tLCuDLfF7va9L1GkiRJmmx3dOdie6Ey8b1/1nd30t7vBU1GPzKnOvoUu0QAAAAAoHVExB+kbUr7oV1uANBSxjypAEz6vcaPjjMVrk9b6YoDAAAAAAAAAAAAAB6L/e3Y3w4AAEBb6Urqr+nIoQq1+m1pZ82qjeSdBQBAu0ifb64zQKv5rR0YnhHD+N7SO2i9pDarJ9kQt3fn2nKA6JbSAmssPUbn9M7f52vrmnw5epP1jmOLtuGEV8dDDz9sm1QDPf+V57T1OXP6699hkVPHv/R17iHSDGiwsjY2lZfF1mItbsoW2vI9RpIkSWpE48/L5/cOxpr/w969x8lV14f/T7zVttraWoXMJoHdmb3M7OzsOdmEhM1lE8g9u2cSYIqiIKjEC1IUsDRefsSqgN8KFahU1FpE8QJ4A6qgFRRRFEHkEqK23uqlioooyj35/E7S2Ib7JpmdnTnzfD4er0f+a3XO55z9nOm78xlY6l1C2pUZ0Cj57ow4mW1SBAAAAAAmVwjhSTt+mO+7ptsAoCnV7FgAxv1+40fHaaTPpQ258wAAAAAAAAAAAACAhzPfjvl2AAAAMmV6PFboiKtb2/yAhU1pG2cMrc1bEQBAK+uIktscnjXxHTxwQEscwHdVvs/1kjLYB3oqmTw09KTisOsrPUoz067N9+zWffW1ru4wZ3CVz7FJ6x4+NHz3Bz8xGlVHF116ZebXzZnvvdCFTq14/ms8R6QmrCsaC8nAgWFjcW64vFDM5HuLJEmSNNFt20ufUBwO/dEa7xnSOMpFyf3pvydNmTJlqokRAAAAAGi8EMLatE2m2gCgqdXsWgDG/Y7jR8dptK1pH03rdgcCAAAAAAAAAAAAAH9gvh3z7QAAAGROR5Rc7YCF7W1NP4svTYvHXvXc8theVgYA0HL7uji53Z5u4ju8PNIyB+/NrqxyzaSMdXT/wkweFHpsaYHrKz1KBw8csFv31M1d+bC8ssxn2MSdf9FnjETV0c9u/1Uojbwg8+vm4suucrFTs5Yf5TkiNUmLKsvDiaXhcGF3JWzqzGfyXUWSJEmajG5J99fn9sRhXfmAMDNKvH9IT1AuSi7uGqr9uakRAAAAAGiMEMJQ2hdMswFAS6jZvQCM+13Hj44zWe5POzftOe5EAAAAAAAAAAAAAMB8O+bbAQAAyJyOqLrawQoPL9mS/ntNR5Qct1dl3XOtEgCg6dVqT96xh7GXm+BeVlrYMgfubfvP6ppJ2ao4OBo2ZfCA0Jf2L3J9pUfpn3vjXb6fNqcdUR7x+TVxh71yY9i6datRqDp64ave1BZr59rrb237a71ly9awz+yDPEukSaorGgvJwIHh1L454ep8b+beSyRJkqRm7Mvp3ntjcW4YGlzlvUR6vKLqDztmjc0zPAIAAAAAEyeEMH3Hj6BtMbkIAC2jZhcDMO53Hj86zmS7I+2ktD9yRwIAAAAAAAAAAABA+zLfjvl2AAAAsmhqR5Rc7WCFRy8XJ/fl4uplHfHYC5/dmzzTcgEAmtFzy2N72bs1puNL81vmkL339MSumZTBLuiuZO5Q0MPKi11b6WH1RGPhpq7CLt9PJ5aGfX5N3MCSw8Ptv7zD+FMdffBjV7TN+vnhj3/W9tf7F7+607NEanDlaE04qn8knNsThxs7C5l7F5EkSZJapds689v/7wPbvk+f6V1FeoxZz+q90+PqsSZIAAAAAKC+Qgh/mrYx7W5TiwDQcmp2MwDjfvfxo+M0ix+mHZE21Z0JAAAAAAAAAAAAAO3HfDvm2wEAAMik6UPVgY6o+oCDFZ7g0IUouTvt4o4oOWT6vNofWzkAQNPs5yrryvZrjen1xXktc7je9V3dYWaUuG5SxnpZaWHmDgNdWz7QtZUe1kv7F+3yvfSO3iGfXZP36c9/xchTHf3XT34eeuc/ry3WzoyhteH++x9o+2t+67e+51kiTXDbvkdYUlkeNhTnhUsK/WFzxt49JEmSpCz05Xxv2FicG4YGV3mPkR69C5/dmzzTJAkAAAAA7JkQwpPS1qf9zMQiALSsml0NwLjfgfzoOM3m6rQhdycAAAAAAAAAAAAAtBfz7ZhvBwAAILM64uqbHKawC0XV3+bi6gfTxkql2tOsIABgUvdys8YOsEdrTKf0zWmpQ/UOrCxz3aSMVY7WhE1d+UwdALrCs0p6RB/qruzSfXRh90DYN058dk3ca04+05hTHW3dujUc9sqT22b9zFp+lIue+uwXr/M8kSagvvQd47Dy4nB63+xwbb4nU+8akiRJUpa7rTMfLuiubN/Pz/RuIz18vnPz3lFSMk0CAAAAALsnhDA77VpTawDQ8mp2NgDjfg/yo+M05f8bXdr5ac91lwIAAAAAAAAAAABAezDfjvl2AAAAsqtWe3JHlFztQIVdLxdX7+iIqv8yLRpbtu1ztJgAgEbLzVr71/ZljekdvUMtdZje3xb3d92kDLbtkMwsHfy5sLLCdZV2qjy4Jmzqyo/7HvpsoRh6o1GfXRM3b83R4be/+70Rpzp630cua6s1tObwE1301Hkf/bRnilSn5g6uDCcUh8OF3QO7tO+QJEmS1Jxdne8NryvuH6JotXce6X9L7srFyfNMlAAAAADA+IUQnp12ZtoWE2sAkAk1OxyAcb8P+dFxmtkdacel+W0zAAAAAAAAAAAAAMg48+2YbwcAACDTpg+u6cjF1R87TGGPDmL4edo7p82qLpwy5eQnWVUAQCN0zFq73j6sMb2nJ26pA/Qu7K64blIGe3H/okwd9jl7cJXrKu3UMaUF475/rst3hznuoaZuxtDa8NUbbjXWVEc//PHPQs/8Q9tqHb3q9We48KlTzjrfc0Xag4YHV4YNxXnhkkJ/pt4nJEmSJP1ft3XmwwXdlXBIeUmY7j1I2l4urp45NLT+qSZLAAAAAOCxhRCesuPHy+40qQYAmVKz0wEY93uRHx2nFdyYtsAdCwAAAAAAAAAAAADZZb4d8+0AAABk3vTKunIuSu50mEJdDmP48bYDGaYNrd32oj7V6gIAJkpuMHmt/Vdj2nYIXSsdnHdrZz4U4jHXTspYPdFYuKmrkJlDPkvRqOsq7dRF3QPj/ju/cmCpz6zJe+uZ7zfKVEdbtmwNB714Q9uto9Pf9WEXP3XMhrd7rki70Mwo2b5XOLVvTvhSV29m3h8kSZIkja/P5/vCCcXh0Bet8Y4ks5xR9et7xwftY7oEAAAAAB4phDCSdosJNQDIpJrdDsC434386DitYmva+Wl7u3MBAAAAAAAAAAAAIHvMt2O+HQAAgLYwPR5bmYur9zpMoZ6HMiTfzcXJWzvisYoVBgDUW0dUfbM9V2P6RHe55Q7MO3jgANdOymDv7okzc7DnvnHimko7igdXh83jvHfWlxb6zJq8pX99XLjvvvuNMdXROed9vD3fQz79RRc/ddCLN3i2SE9QVzQWDikvCaf3zQ7XdvVk5p1BkiRJ0u53c1c+nN07FEYqy703qd37WcdgssSECQAAAAD8jxDCX6Sdu+PHygCAbKrZ9QCM+x3Jj47Tau5MOy7tye5gAAAAAAAAAAAAAMgO8+2YbwcAAKBt5OLqWC5O7nOQwoS0Kf1s3zBjaG3eSgMA6rJ3i5Kz7LEa0xWFUssdlHda3xzXTspgh5aXZOIwz02deddT2qnjS/P9fc9InXMPCZv/4wdGl+roP77/o5CfV2vL9fTNW79jAaTmrTna80V6lIqDo+Go/pFwbk8cvtlVyMR7giRJkqSJ6ZJCf1hfWhi6ojHvU2rPouoD0+Lq306ZMmWqSRMAAAAA2tmOH9O73VQaAGRezc4HYJfek6AVXZ825C4GAAAAAAAAAAAAgGww3475dgAAANpKLk6SXFy912EKE1cuqn61I0qOmzm0bpoVBwDs/r6t+n57q8Z0Tb6n5Q7Huyrf59pJGWyfOAlf7+pp+QM8t/13cD2l/2vbobZPdN9c2D2w/Rng82ru3nX+J40r1dEDDz4Y1hx+Ytuupzt/c1fbr4EtW7aGfeYc5PkipRXisbBqYGk4vjR/+75gU1e+5d8LJEmSJDW2a7t6whuL80I8uNp7ltp1bvPjf7nfyj8zbQIAAABAuwkhFNI+ayoRANpGzQ4IYNzvS350nJb+f79LOzPtGe5mAAAAAAAAAAAAAGht5tsx3w4AAEDb6RhMluTi5NcOUpjgouTBtH9PP+sX7zNYfZaVBwDs0p4trn7SnqoxfaOz0JIH4w1XVrh+UgY7o3d2yx/c+cV8n2sp7WjO4KonvGe+kN4z/dEan1eTd8jRrw9btmw1qlRH//juj7bteqoccLgFkPrJz37h+aK2rCsaC0sHloVjSgvCWb2zwhX5YtjUlW/59wBJkiRJzdGmtHf3xGHVwFLvYGrDkm9PH6oOmDgBAAAAoB2EEJ6adlLaPabRAKCt1OyEAMb93uRHx8mC76WtdEcDAAAAAAAAAAAAQOsy3475dgAAANrSjMGx/o6o+kOHKDSmXFy9tyNKLk074jml2jOsQADgieSi6hftoya+GXESNrfogXivKQ27hlIGWz2wtOUP7Ly8UHQtpR2dVBx+3Pvlxs5CWFBZ4bNq8voWPj/86Ke3G0+qo03f/n7Yd7+D23ZNVY88ySJIffm6mz1jlPlmRklYmP6tf3lpYTijd3b4t0L/9gPuvyVJkiRJDejS7lI4qn8k7Bsn3tHUPrOaUfWeXJy82NQJAAAAAFkWQpiXdpspNABoSzW7IYBxvzv50XGy5MK0v3JnAwAAAAAAAAAAAEDrMd+O+XYAAADa1vTBNR25qPpVByk0uKj621yUfCD9d/XQ0PqnWokAwKPpiJMb7Z0mvp5otGUPwfto94BrKGWw6WlX5vta+5DOQsm1lHb0mfR+eKx7ZXPaoeUlPqcW6KJLrzSSVEf33/9AWHbocW29pk5809kWQupDH/+sZ4wyVz4aCysHloYTisPhvJ4ofL2rp6X39pIkSZKy0bXpu8nG4twQRau9u6md5jT/qVSqPc30CQAAAABZEkJ4etppaQ+aQAOAtlWzKwIY9zuUHx0na36WdrC7GwAAAAAAAAAAAABai/l2zLcDAADQ3kZGnpKLktMcojA55eLqHennf37a0ilTTn6SBQkA/EFHnHzffmniqwyubtnD7zZ15kNvNOo6ShlsQ3FeSx/O+Ynususope03uOpx75XXpfe6z6n5e8nxpxpFqrO3/dMH235d/cuHLrUQUqecdb7njDLxvcIh5SXbD6e/uFAOt6bv6q28l5ckSZKU7ba9s5zbE4dlA8u806k9ipLr9xqs7msCBQAAAIAsCCHsn7bZ5BkAtL2anRHAuN+j/Og4WXVh2nPc5QAAAAAAAAAAAADQGsy3Y74dAAAAUtOj6mEdcfV3DlKYvHJx8qNcXD1z2tDaBVYkAJDuC+6wR5r4ZldWtfTBd4eVF+WKdyQAACAASURBVLuOUgYbGlwVbuvMt+yz6aPdA66jlHZiafgx75MLuithZpT4nJq8eNmR4Y47f2sEqY5u3vyfYZ85B7X92vrK12+xGFLrX/s2zxq1XP3Rmu3v4qf3zQ5X5fta+jsFSZIkSe3dJYX+cFT/SJjpXU9ZL6r+Ytrg2uWmUAAAAABoVSGEP047Le1BU2cAwLYf0LVDAhj3+5QfHSfLfp52hDsdAAAAAAAAAAAAAJqf+XbMtwMAAMAO04ZG+zri6iYHKTTDQQ7Jbem/G3OVtT1WJgC0pakdUfUB+6KJb35lZUsfdndW7yzXUcpoH+0eaNln0wd7Bl1DKW3bobSPdo98Md8XStGoz6jJmz5rbfj8l643elRH9913f1hyyLHWV9odd/7Wgkgtf96rrQc1fTPjJIwOLA1v7psbLs+XwuYW/g5BkiRJkh6tq/O94TWl4dDjO0tlex7zwW3zmFOmnPwk4ygAAAAAtJIQwoK0/zBtBgDspGaXBDDudyo/Ok47uCjtr9zxAAAAAAAAAAAAANC8zLdjvh0AAAB28pf7rfyzXJRc7CCF5ikXJ1/rmFV99Yw4yVmhANAe9qos+1P7oMa0eGBFSx9y99WunpDuE11LKYMd1T/Sss+m9/VErqHavnhwddj8KPfHzV35sKSy3GfUAr3u1HcZN6qzvz/jfdZW2uyVL7YYduid/zxrQk1Zf7Rm+3783J443NDV3dLfG0iSJEnSeLuhqxDe3Dd3+3eb3g2V2aLqp/YZrD7LVAoAAAAAzS6E8NS0jWkPmjQDAB6mZrcEMO53Kz86Trv4eVrirgcAAAAAAAAAAACA5mS+HfPtAAAA8EhTc1H1hI6o+oCDFJqpZEsurl45Paq+dObAmr+wTAEgu/aOas+x92lMyyvLWv6AuwPT/w6upZS98tFY+EZnoSWfS+f2xK6h2r7jSvMf9f44un+hz6cFWrj2FeHue+41alRHX//m5jBzaJ31lXbE37zZgkj94ld3Wg9qqvqiNeGo/pFwXk8UNnXmW/67AkmSJEna3W5L34m2vRstHfB/g1Q2y0XV/5heWVc2mQIAAABAswohlNJuMGUGADyGmh0TwLjfr/zoOO3m/LRnuPsBAAAAAAAAAAAAoLmYb8d8OwAAADyG6XGyKBclP3WQQhMe7BAn93VE1U+l/z5v2tDon1itAJAt6d/3mfY8jWl0YGnLH2z3uuI811LKaP/YO9SSz6V/6p3l+qntu6h74BH3xum9s302LdA+sw8KN97yHeNFdXT3PfeGBdVXWF87OvXsD1gUqetuvM160KTXG42G9aWF4cPp3+1NXfmW/35AkiRJkurdtvelgwYOCNO9QypzJXd1RMkhplMAAAAAaCYhhKlp69N+b8IMAHgcNTsngHG/Z/nRcdrR99IWegIAAAAAAAAAAAAAQPMw3475dgAAAHgce0e153REyb87RKF5y0XJ3ek1ujStVirVnmbVAkDryw0kvfY5jWld+YCWP8zukkK/aylltGUDy1ryuXRG72zXT21deXBNuK0z/4i/151R4vNpgU5/14eNFdXZG057t7W1U5/4zNUWReqCj11hPWhSmhEnoTpwQDinZ1a4uSv/hHvbr3V1h6sKfeGy9G/5tr/nF3RXwgd7BsO5PXF4Z/o/4/S+2eHUvjlhY3Fu+Lvi/uGE4nB4Rf+CsL60MBxWXhwOLS8JycCB21s1sDQsqSx/SHMGV4XZlf9rMN1H9Eaju1UUrX7I/6xtLa6seMT/zj/85/lDtfQ/47b/rIeXR7b/597Wtv8e23p9cd72/25v6dtv+3/X09O9/rb/7tv6QE9l++dxUffA9s/mynxf+FJXb7g+/cw2tfh3LZIkSZIe2uWFYji6f2HYN/YdpzLV1lyUnDalVnuyKRUAAAAAJlsIYWbalSbLAIBxqNk9AYz7XcuPjtOuHkw7Lc1vkQEAAAAAAAAAAABAEzDfjvl28+0AAAA8kZGRp3TE1Y3bDhFwkEJzl4urd+Si5Pz03zGHPQBA68oNViN7m8Z0aP+Slj/EbnNaZXC16ylltMsK/S33XHpb7xzXTm3dK/oXPOSeuLGzEOYNrvTZtECrDjs+PPDAg0aK6uia624K02ettb526gc/+m8LI7Xx7f9iPajhFQdHwzGlBWFjce7/dnLf3PCa0nB4Sf+iUCsvCSsqy8L+lZWhP1oTZjgsfo+amdYbjYZ4cHXYb3BVWFJZHlYNLA3JwIHhsPLicFT/SFhfWhhOKA6H1xX333493t43O5zTG4fzewbDxwrlcHm+FK7O94Ybugot//2NJEmSlIWuzfeEv033733pO5P3HmVm5jKqfmbmwJq/MKkCAAAAwGQJIRyUdoepMgBgnGp2UADjft/yo+O0u+vTCp4GAAAAAAAAAAAAADC5zLeD+XYAAADGafqsZF0uSu50kEKLHPYQJz/qiJO3TxsanWX1AkBr6Zg1Ns9+pjEd3r84EwfYHd2/0PWUMtoxpQUt90x6c99+rp3augu6Kw+5J44oj/hcWqDC/n8dvvuDnxgjqqPf/f6eMDz2Mutrp8qLXxi2bt1qcaRecMybrAlJu9T0tN5oNAwNrgqLKsvDqoGl4ZDyku17rVf2LwgnlobDxuLccHrf7HBObxzO7xkMn+guh8/n+8L1Xd2Z+P5HkiRJapZu7CyEt/TtF6JotfcVZaTk23tHScm0CgAAAACNFEJ4etqZpskAgF1Us5MCGPd7lx8dhxB+m/ZCTwQAAAAAAAAAAAAAmDzm28F8OwAAALtg7/igfXJR9VqHKLTcoQ/fz0XJabmBpNcqBoDm1zFr7AD7l8Z0ZP+iTBxc996eyPWUMlpPNBpu6iq01DPp5L65rp3a+p7d1Jn/3/vhzN4hn0uL9P4LP2N8qM5OfNPZ1tbDOvzYv7cwdthv1UutCUkNrysaC5XB1WFJZXk4pLwkHNU/Eo4tLQgbivPCqX1zwtnp3u28nihcXCiHqwp94Zad9nWSJEmSHtm270K37aOHKyu8cygLM5Z3pf8ebGIFAAAAgEYIIZTSbjZJBgDshprdFMC437386Dj8n/PTnuHJAAAAAAAAAAAAAACNZ74dzLcDAACwiwqFlX+Ui6tnOkShZduUtnGvylin1QwAzakjqq62Z2lML+5flIkD677RWQj7xolrKmW0s3pntdQz6XXF/V03tW2Hl0f+9164Mt8XuqMxn0sLdNgrTw5bt241NlRHX7z2xjB91lrr62Gdce5HLI7U735/j/UhqWXatp8bGlwVllSWh2r5gHBk/6Lw6tL88Oa+ueHs3qHwwZ7B8OlCKVyb7wm3deYz8T2TJEmStKtt2wu/pyfevm/2HqEWb2suSk6bMuXkJ5lcAQAAAGCihBCOSPu9STIAYDfV7KgAxv3+5UfH4aG+lRZ7OgAAAAAAAAAAAABAY5lvB/PtAAAA7KZpg9W1uTj5tYMUWrVkS/rvNR1RctxelXXPtaIBoHmkf6MPtldpTEf3L8zMYXUHDRzgmkoZbeXA0pZ6Hp1YGnbd1Lad0zNr+31wS2c+LK6s8Jm0QANLDg8//8UdxoXq6Ld3/T7MWfkS6+tR+sJXvmGBpL5563esB0mZrTcaDcODK7e/xx1WXhyOLS0IG4rzwul9s8N5PVG4uFAOVxX6wqaMfB8lSZIkPbxte95Dyku8H6ily8XJv+0zWH2W6RUAAAAA6imE8BdpHzdBBgDsoZqdFcC438P86Dg80r1px3pCAAAAAAAAAAAAAEDjmG8H8+0AAADsgb0Gq/vm4uRrDlJo8aLkwfTfz6X/HvHs3uSZVjYATK6OeOyF9iiNaX1pYWYOqDujd7ZrKmW4K/LFlnkeHVea75qpLZuZdn1X9/b74FWlBT6TFumSz15jTKjOjn39GdbWozR91tpwx52/tUBSF116pTUhqe2bESehPLgmLKisCNWBA8KR/YvCiaXhcFrfnPC+nihcUugPX8n3hs0Z+d5KkiRJ7den0j3toeUl2/e+3gHUiuXi6nf2jpKSCRYAAAAA6iGEEKf9p+kxAKAOanZXAON+F/Oj4/DYPpn2LE8KAAAAAAAAAAAAAJh45tvBfDsAAAB7aJ+RkafnouRdDlLITL/riJMP5eLqWKlUe5oVDgCNNz2qvtSepDG9on9BZg6m+1pXd5gZOZROymrHlFrnefXK9NnqmqkdWzOwdPs98P7uwTDd59ESHffGdxgNqrMrvvA1a+sxWrTulRbIDm898/3WhCSNs5lxEuLB1WFFZVk4rLw4/E1xfnhz337hnN44XNQ9EL6Q7wu3duYz8/2WJEmSstdnC8Xw4v5F2/e29vhqtXJRcmdu1tpRUywAAAAA7IkQwhFpd5scAwDqpGaHBTDu9zE/Og6P7ztpFU8LAAAAAAAAAAAAAJhY5tvBfDsAAAB10hGPHbTtEAGHKWToUIg4+XV6Tc/PxdWxKSMjT7HKAaBB+6oo+Rt7kcZ0TGlBpg6lWzWw1HWVMlpPNBa+0VloiWfR+v6Frpnasrf07ReuyfeEUjTq82iBZq98cbjzN3cZC6qjX/36NyFa+iLr6zF69f93pkWywwuOeZM1IUl1rjy4JiyurAiHlJeEV/QvCG8ozg1n9c4KF3RXwhWFUvhmVyFT34FJkiSp9boq3xfWlxaGfeLEHl6t1tZclJw2ZcrJTzLNAgAAAMCuCCE8Pe29JsYAgDqr2WkBjPu9zI+OwxO7J+2lnhgAAAAAAAAAAAAAMHHMt4P5dgAAAOooV1nbk4uTbzpIIXvl4uqP086cNrR2QXqpp1rtADBx0r+9J9l/NKa/Kc7P1GF0by3u57pKGe60vjkt8Sw6un+h66W27N/zxbBmYKnPogWaMbQ2fPm6m40D1dnL/vb/WV+P04WXfN4i2SFaeqQ1IUmTUG80GoYHV4Zk4MCwvrQwbCzODef2xOGSQn+4oas7U9+RSZIkqXm7tqsnnFAcDl3RmH26WqsoubRrqPbnJloAAAAAGI8QQk/aTabFAIAJULPbAhj3u5kfHYfxOz/tjz05AAAAAAAAAAAAAKD+zLeD+XYAAADqbJ+Rkafn4uqZDlLI9AERP8hFyWnThkb7rHgAqL9cnLzBnqMxvbo0nKlD6L6Y7wvTXVcpsw1XVoTNLfAsekn/ItdLbdf8yspwSt8cn0WL9JZ3nGcEqM4+efnV1tYT9KOf3m6hpH7+izusB0lq0nqj0bCksjwcUl4S1pcWho3FueHcnjhcUugPN3QVMvUdmiRJkia/a7t6wobivNATjdmPq5X61t7x2qKpFgAAAAAeTwjhkLTfmhYDACZIzY4LYNzvZ350HHbN9Wn7enoAAAAAAAAAAAAAQH2Zbwfz7QAAAEyQjnjshR1xcpeDFDLfprSNM2cf1GXVA0B95KLkZHuMxnR8aX7mDqBbPLDCtZUy3AXdlaZ/Dh3VP+Jaqe06rLw4FGKHv7ZCSw5+Vbj3vvuM/9TRL351Zxg88Ajr63Haf3S9hbLDldfcYE1IUovWG42GJZXl4ZDykrC+tDBsLM4N5/bE4ZJCf7ihq5C579gkSZLUmL7W1R02FOdt32/ad6sliqq/mRaNVU22AAAAAPBwIYSpaSelbTUpBgBMoJqdF8C439P86Djsul+mLfUEAQAAAAAAAAAAAID6Md8O5tsBAACYQLmBpDcXVW9ymEI7lGxJ/72mI0qO26uy7rlWPwDsvvRv6kZ7i8Z0fGl+5g6ee0NxrmsrZbhDy0ua/jl0ZP8i10ptV1c05nNogTrnHhI2ffv7xn7q7CXHn2p9PUEnbDzbQtnh7H+5yJqQpIxWjtaE5ZVl4aj+kfDG4rzwz71xuKTQH27oKmTu+zdJkiTVv6939YQNxf1DbzRqf61WaGsuSk6bMmXKVBMuAAAAAGwTQnhm2idNiAEADVCz+wIY97uaHx2H3fNg2kmeIgAAAAAAAAAAAABQH+bbwXw7AAAAE2za0OifdMTJvzpIoX3KRcn9ubh62fTB5AV7VZb9qbsAAHZNunf6e3uKxvTq0nDmDpy7Il90baUMNzNKwlX5vqZ+Dh1RHnGtJDVl55z3ceM+dfbRT33e2hpHH/u3qyyWHV5x0j9YE5LUhpWjNWFFZVl4cf+i8MbivPCu3lnh0u5S+EZnIXPfzUmSJGnPuqGrEN5QnBt6o1F7abVCF5qPBAAAACCE0JN2m+kwAKBBanZgAON+X/Oj47BnPpT2J54mAAAAAAAAAAAAALBnzLeD+XYAAAAapCNKjuiIq79zkEJ7lYuq96TX/tK0WqlUe5o7AQDGs2+qvsU+ojG9ujQ/k4fNzRtc6fpKGe6E4nBTP4MOL4+4TpKarnVH/V14cMsWYz519N8//2UojbzA+hpHP/7v2y2YHRate6U1IUl6SL3RaFhSWR4OKy/e/r57du9QuKTQH27oKmTyeztJkiSNrxs7C2Fjce72/aJ9s5p7PjK5ea/B6r4mXQAAAADaUwhhddqvTYYBAA1UswsDGPc7mx8dhz33jbR9PFEAAAAAAAAAAAAAYPeZbwfz7QAAADTQjMGx/o4ouc1hCm1alPyyI07OmTa0dkG6HKa6IwDg0eXi6in2Do3pb4rzM3nI3LYDiF1fKdsHjm87TLJZn0GH9y92nSQ1VX0Lnh/+6yc/N95TR1u3bg0vfNWbrK9xND95uQWzw+/vvifMHFpnXUiSxl15cE1YNbA0vLR/UTi5b254d08cLiv0h5u6Cpn8Tk+SJEmP7Pqu7nBScTh0R2P2yGrmfpaLqsOmXQAAAADaRwhhatob07aYDAMAGqxmNwYw7nc3PzoO9fGztPmeKgAAAAAAAAAAAACwe8y3g/l2AAAAGmz6vNof5+LkPQ5SaO/SNfCjXFw9c9rQ2gXuCgB4qFyUnGa/0JiOLS3I5OFyn+guu75Sxjutb07TPoNe0D/iGklqqi669EpjPXV2/kWfsbbG2etPPdeC2eHa62+1JiRJdasyuDokAwdu/37v9L7Z4YLuSvhqV08mv+uTJElSV/h6utfbUJwXeqIx+2E16Txk9d5cNPYiEy8AAAAA2RdC+KO0D5gIAwAmSc2ODGDc729+dBzq5960IzxZAAAAAAAAAAAAAGDXmW8H8+0AAABMko4oOaIjqv7egQpK25S2ccbQ2rw7AwDSfVKc/IP9QWM6prQgk4fKbU6LB1e7xlKG229wVbitM9+Uz6Dnlxe7RpKappccf4pxnjr7r5/8PPTOf571Nc6uvOYGi2aHd573cWtCkjTh9UajYeXA0rC+tDCc2jcnXNBdCV/J92byO0BJkqR27Gtd3WFDcV7oicbsf9WU5eLqmVOmnPwkky8AAAAA2RRC+Ku0q02DAQCTqGZXBjDudzg/Og71d2aa2RgAAAAAAAAAAAAA2AXm28F8OwAAAJNo73htMRdXb3WYgv63KLk+7bjnlsf2cocA0K46ourp9gWN6ZjSgsweKLftv5trLGW79/VETfn8ObS8xPWR1BQNHnhE+MWv7jTGU0dbtmwNhxz9eutrnOXn1cLd99xr4exw9ImnWReSpEmrNxoNSyrLw1H9I2FjcW44L32nvqrQFzZn9LtBSZKkrPe1ru5wQnE4dEVj9rtqunJx8um/3G/ln5l+AQAAAMiWEEI57fsmwQCASVazMwMY93ucHx2HiXFR2p94ygAAAAAAAAAAAADA+JhvB/PtAAAATLJn9ybP7IiTDzlMQQ85WCJK7s/F1cumR9XD9qos+1N3CgDtJP07+I/2A43plf0LMnuQ3Ie6K66xlPFWDyxtyufPoeUlro+kSW/6rLXhymtuML5TZ++54BLraxc68ri3WDQ72W/VS60LSVLT1RONhqUDy8LR/QvD3/fNDe/vHgxX5fvC5ox+ZyhJkpS1vpzvDceUFoR94sT+Vk02/1i9ae/4oH1MwAAAAABkQwhhedqdpsAAgCZQszsDGPe7nB8dh4nz1bS9PWkAAAAAAAAAAAAA4ImZbwfz7QAAADSJjig5oiOq/t6BCnrkARPJ3en6uDStVirVnuZuASDrcnH1THuAxvSy0sLMHiC3Ka04OOo6SxnvU4X+pnv+1MpLXBtJk94bTnu3sZ06+8GP/jt0Dx9qfe1CH7j4cgtnh5//4g5rQpLUUnVFY2HxwIpwZP+i8Pd9c8MF3ZVwbVdPZr9LlCRJavWuyveFo/pHwow4sZ9V8xRVfzE9WjtiCgYAAACgtYUQjk170BQYANAkanZoAON+n/Oj4zCxfpg24GkDAAAAAAAAAAAAAI/PfDuYbwcAAKCJ7B2vLebi5BYHKuixysXVO3JRcn7a0nTJTHXXAJBFHVH1bH/3G9NL+hdl+vC49f0LXWcp472oCZ9jh5SXuDaSJrXFBx0T7r7nXiM7dbRly9aw7qi/s752sR/99HaLZ4fPXHmtNSFJykS90WhYObA0HFtaEE7vmx0uLpTDzV35TH/HKEmS1EpdUSiFw8qLw3R7VzXPvOO9ucHqkSZhAAAAAFpPCGFq2kbTXwBAk6nZqQGM+73Oj47DxLsrbaUnDgAAAAAAAAAAAAA8NvPtYL4dAACAJrNXZdmf5uLq+x2ooCcsSn6QrpVTplfWld05AGRJR5y809/6xnR4eSTTh8Z9qLviOksZb584CVfne5vq2XPwwAGujaRJa9/9Dg43b/5Pozp19s5//Zj1tYstO/Q4C2cnp579AetCkpTZZqYND64Mh5UXhw3FeeG8nih8pcne1SVJktqtTxbK4ZDyEvtVNdOs49umTDn5SSZiAAAAAFpDCOFpaR8y+QUANKGa3RrAuN/t/Og4NMZ9aS/w1AEAAAAAAAAAAACAR2e+Hcy3AwAA0KRy0diLOuLq7xyooPGUi5Kb039PmjY0OtPdA0Dr74OSs/x9b0zPLy/O9GFxt3XmQ2VwtWstZbzjSvOb6tlz8MABroukSeud//oxIzp19u3//GHonHuI9bWLnfZPH7B4dvLX699oXUiS2q7eaDSsHFgaji0tCGf3DoVLCv3h5q58pr+PlCRJarYuLpTDqnRPZn+qpiiqfurZvckzTcUAAAAANLcQwrPSvmDqCwBoUjU7NoBxv9/50XFonK1pGz15AAAAAAAAAAAAAOCRzLeD+XYAAACaWG4g6c1F1ZscqKBdO3wiuT7tuL0q657rLgKgJfdAUfUMf9Mb0yHlJZk/KO6Y0gLXWsp4+WgsfK2ru2meO9uera6LpMlo3VF/Fx7cssV4Th098OCDYfULT7S+dqNbNn/XAtppHfXOf551IUlS2sw4CcODK8Nh5cVhQ3FeOK8nCtfmezL/HaUkSdJkd0F3JYxUltuTatLLRcnNe1XGOk3GAAAAADSnEEIu7UZTXwBAE6vZtQGM+x3Pj45D470n7SmeQAAAAAAAAAAAAADwf8y3g/l2AAAAmtw+IyNPz8XVMx2ooF0uSh5M//1c+u8RzynVnuFuAqBVpH+73uZveWOqDhyQ+QPiPlYou9ZSG/S64rymee4c2r/ENZHU8PoWPj/86Ke3G8mps9Pf9WHrazcaHnuZxbOTb9zybetCkqQnaGBwdaiWDwgnFIfDP/fG4fP5vrA5499bSpIkNbrbOvPh7N6hMDS4yh5Ukz3X+Mvp0doR0zEAAAAAzSWE0J/2QxNfAECTq9m5AYz7Pc+PjsPk+GTaH3sKAQAAAAAAAAAAAMD/MN8O5tsBAABoER1x9eBcnPzaoQranXJRcnf674W5uDo2NLT+qe4oAJpZuud5q7/fjWnVwIGZPxxu2+G7DoaTsl9xcDTc2FloiufO88uLXRNJDe8Tn/6iUZw6u/Vb3wv77new9bUb/cM5F1hAOznnvI9bF5Ik7Ubd0VhYObA0HFtaEM7uHQqXF4phU1c+899nSpIkTXSbOvPh9L7ZoRytse/U5M0zxsl9aUeZkAEAAABoDiGEBWm/Nu0FALSAmt0bwLjf9fzoOEyeL6X9uScRAAAAAAAAAAAAAJhvB/PtAAAAtJSOaE13R1z9hkMVtGcHUlTvyEXJ+WlL02U11Z0FQNPteeLqm/zNbkxLB5a1xcFwJxSHXW+pDTq1b05TPHNe2L/Y9ZDU0Na/9m1GcOrsvvvuD0v/+jjrazf79n/+0CLayZHHvcW6kCSpThXisbByYGlYX1q4/XuAiwvlcGtnvi2+45QkSap3N3YWwobivNAVjdlrajJnGc+cUqs92aQMAAAAwOQJIRyYdpdJLwCgRdTs4ADG/b7nR8dhct2SlvM0AgAAAAAAAAAAAKDdmW8H8+0AAAC0mEJh5R9tO0jAgQqqS1HyX9vW07Sh0VnuLgCaRS6qvtHf6ca0eGBFWxwId2l3yfWW2qB4cHVTHKR9eHnE9ZDUsGavfHH49Z3Osqi3U8463/razUbWHWMB7WTLlq2hf/ELrA1JkiawrmgsLBtYFo4pLQhn9c4KVxRK4bYm+H5AkiSpVbo63xuO6h8JM+LE/lKTUi6qfqZrqPbnpmUAAAAAGi+EsDbtXpNeAEALqdnFAYz7nc+PjsPk+25a3hMJAAAAAAAAAAAAgHZmvh3MtwMAANCipg1W1+bi6h0OVVAd25S2ccbQWl9UADCpOqKxDf4uN6b5lZVtcxjc3MGVrrnUBp3dOzTpz5ttB0+6FpIa0YyhteHL191s7KbOvnHLt8PMoXXW2G72j+/+qEW0k03f/r51IUnSJFSIx8LKgaXh2NKC7d8VXF4ohs1t8j2oJEnS7rZtz3RYebH9pCalXJzcsldlrNPEDAAAAEDjhBBelPaAKS8AoMXU7OQAxv3e50fHoTn8NK3sqQQAAAAAAAAAAABAuzLfDubbAQAAaGEzZx/UlYur1zlUQfUt2dIRJVfn4uTluTlrn+1OA6DRclH1RH+PG9OswVVtcwjchuL+rrnUBg1XVoTbOvOT+rx5Sf8i10JSQ3rrO84zblNn9913f1hyyLHW1x70ne/9yELayfs+cpl1IUlSk9QbjYZk4MCwoTgvdWv/1AAAIABJREFUnNcThWu7etrmu1FJkqRd6UPdlbB4YIU9pCZjbvH2aYNj803NAAAAAEy8EMJJaVtNeAEALahmNwcw7nc/PzoOzeNXaXM9mQAAAAAAAAAAAABoR+bbwXw7AAAArW5k5CkdcXVjR5xscaiC6l6UPJj++7n03yOeU6o9ww0HQCOk+5rX+DvcmIqDo21z+NtnC0XXXGqTzu2JJ/V5c3T/QtdB0oS34vmvCfff/4BRmzp70+nvs772cF3yUC//2/9nbUiS1MQNDa4KL+gfCW/u2y9cXCiHm7oKbfN9qSRJ0uN1W2c+nNMza/t+yb5RjSwXV++dPpi8wOQMAAAAwMQJIbzNZBcA0MJqdnQA437/86Pj0Fx+k7bI0wkAAAAAAAAAAACAdmO+Hcy3AwAAkBG5uDqWi5NfOVhBE3ZgRZTcnf574ba1NjS0/qnuOgAmyrR47FX+9jamfeOkrQ5/W1hZ4bpLbdDw4Mrthz1O1rPmZaWFroOkCa1rbi1s/o8fGLGps+tuvC3MHFpnje1B7/vIZRbSTrZu3RqipUdaG5IktVAzd3yvsD59tz+7dyhcXiiGzW30/akkSdLDu7UzH07tmxN6olH7RTWyrWkbTc8AAAAA1FcIYWraP5rsAgBaXM3ODmDc74F+dByaz+/TlnlCAQAAAAAAAAAAANBOzLeD+XYAAAAyJDe7OqMjrl7jUAVNdLk4+VUuSs5PW5ouvanuPgDquqeJk5f7e9u4NnXm2+bQt5P75rrmUpv03p5o0p41x5QWuAaSJrT3feQyozX1ntS5+54wP3m59bUHdc2thTt/c5fFtJNbv/U9a0OSpAzUE42GZODAsKE4L5zXE4Wvd/W0zfepkiRJf+i6fHc4trQgzLQ/VENL/nVoaP1TTdEAAAAA7LkQwtS0s0x1AQAZULO7Axj3u6AfHYfmdG/amKcUAAAAAAAAAAAAAO3CfDuYbwcAACBrRkae0hFXN3bEyRaHKqghRcl/5eLqmdOGRme5AQGoh+lR9aX+xjau67u62+awt6vyfWG6ay61RYsrK8LmSXrWvKq0wDWQNGEd9sqTw9atW43V1NmGU/7Z+trDXvX6MyykhznnvI9bG5IkZbAZcRLmD64IR/cvDGf0zg6XF4qT9h2EJElSo7siXwzV8gH2hWrkbOK/7zNYfZZJGgAAAIDdF0KYmvZOE10AQEbU7PAAxv0+6EfHoXndl7bWkwoAAAAAAAAAAACAdmC+Hcy3AwAAkFEd0dpVHXFyu4MV1MhycfLN3GDy2tzs6gx3IQC7v49JjvB3tXFdne9tq4Pelg4sc92lNum87sFJec4cV5rv85c0IQ0sOTzc/ss7jNPU2Ze+dlOYPmutNbaHffm6my2mhznslSdbG5IktUnd0VhIBg4MG4rzwgXdlXBTV6GtvnOVJEnt17Y9z4LKCntBNWgmsXrr3vFB+5imAQAAANh1IYQnp/2raS4AIENqdnkA434n9KPj0Pw/PH6QpxUAAAAAAAAAAAAAWWe+Hcy3AwAAkGHPLY/t1RFXP+tgBTW+ZEv67zUdUXLcXpV1z3U3ArAr0r8fh/hb2riuKJTa6oC3t/Tt57pLbdLSgWWT8px5TWnY5y9pQrrsc182RlNnv/3d78N+q15qfe1h+4+uD1u2bLWgdnLvffeF/Lya9SFJUps2M214cGVYX1oYzu4dCl/M97XVd7CSJKk92pR2et/sUI7W2ANqwstF1f+eHo3OMVEDAAAAMH4hhCenvd80FwCQMTU7PYBxvxf60XFofg+mvdATCwAAAAAAAAAAAIAsM98O5tsBAADIulrtyR1xdWNHlDzocAVNSv+z9j6X/nvEc0q1Z7gpAXgiHdHaVf6GNq5PFfrb6nC3r+R7tx9q69pL7dEHewYb/px5bWl/n72kuvfaN7/T+MwEOP7ks6yvOnTmey+0mB7m6q9+09qQJEkPqTK4OhxWXhxO7ZsTLin0h9s68231vawkScpuN3YWwobivNAZJfZ9mtByUfWeXFw91FQNAAAAwBMLITw57cMmuQCADKrZ7QGM+93Qj45D6/zwuJkYAAAAAAAAAAAAADLLfDuYbwcAAKBNdAwmS3JR8lOHK2hyD7ZI7k7/vTAXV8eGhtY/1Z0JwKOZHieL/N1sXB/uHmi7g90OGjjAtZfapAMqy8PmBj9jXlec57OXVNeGx14W7vrd3UZn6uzfr/669VWHZg6tCz/52S8sqId56zvOsz4kSdLj1hONbv+e8uS+ueHiQjnc2plvu+9pJUlStroy3xcO7V9ir6eJbmvaRpM1AAAAAI8thPCktPNNcQEAGVWz4wMY9/uhHx2H1vrh8ed5cgEAAAAAAAAAAACQRebbwXw7AAAAbWTvqPacXJRc7mAFNUO5OPlVuh7PT1uaLs+p7lAA/mDarLVD/lY2rvf0xG13oNu7eme59lIbdV73YEOfMRuLc33ukurWPrMPCjfc/C0jM3X26zvvCrOWH2WN1aGXHH+KBfUoVjz/NdaHJEnapWbGSVhSWR5OKA6H83qicH1Xd9t9bytJkrLRR7oHwoLKCns8TfDsYfXdU0ZGnmLCBgAAAOChQghT095lggsAyLCaXR/AuN8R/eg4tJb70xJPLwAAAAAAAAAAAACyxnw7mG8HAACg7Zz8pFxUfWNHlDzocAU1zSEXUfLdjqj6lr2jpOQeBWDa0Gifv4+N6/Te2W13kNutnflQHBx1/aU2afHAirC5gc+YU/rm+Nwl1a0zzv2IUZkJcMyGt1tfdeqrN9xqQT3M7b+8I8wYWmt9SJKkPWpmlIQlleXh2NKCcG5PHK7Ld7fd97iSJKl125R2et/sUIr832Q1gUXJpc8p1Z5hygYAAADgf4QQpqadY4ILAMi4mp0fwLjfE/3oOLSe+9JGPcEAAAAAAAAAAAAAyBLz7WC+HQAAgDY1PU4W5eLqjx2uoCZsU9rGmbMP6nKnArSnaUOjM/09bFwbi3Pb8iC3V/QvcP2lNuq9vVHDni9v75vtM5dUl1a/8MTwwAMPGpOps8uv+qr1VadWPv94C+pRfOgTn7M+JElS3ZsRJ2FBZUU4prQg/HNvHL6S723L73UlSVJr9dWunrC+f+H2vYw9nSaiXFS9KTe7OsOkDQAAANDuQghT0842vQUAtIGa3R/AuN8V/eg4tO4Pj6/2FAMAAAAAAAAAAAAgK8y3g/l2AAAA2ti0odG/ysXJvzlcQc1ZsiX995qOKDlu76j2HHcsQPvIzVn7bH8HG9cJxeG2PMDtE91l119qo4YHV4bbOvMNeb6c1TvLZy5pj+sePjR874c/MR5TZ7/69W9CtPRF1lid+vi/fcGiehQvOf4U6+P/Z+/Oo+Qsy4T/B7d5dcaZ9x0XSFUSSO/d6eWpdBZIAklIgIR0P9UsJYsmAkpQAQFBEZAhisqiIEsGQVEjQtwYUVF03BDCuDAggkZ0XBBEQQYF2SEh1+9JxvGHmJDqTlX1Up/POd+T+W/OKe66667qy+eWJEk1aVr34jh0ytw4p21aXN/YWpe/80qSpNHR1U0dsahroTOcqlIuKf42150WTNsAAAAA9SwizjK5BQDUiZLTH0DZ3xU9dBxGr8ey5tvJAAAAAAAAAAAAABgLzLeD+XYAAADYLp+kx+SS9CkXLGjElqTrs3+/nv277BUdpX/wtgUY23acO/f/+PyrXcun7Fq3l7fN6t7LGpDqqItaCzXZWz6Y/f/xekva1j71hW8Yi6mC5W89y/qqUFP3PDSeemqdRfUsTz75VLTOPtAakSRJw9K07sWxvGPXuLC1N25obKnb330lSdLIbVVLEoWevZ3dVIXSh/M96RITNwAAAEA9ioh3m9wCAOpIyQkQoOzvix46DqPbo1mz7WYAAAAAAAAAAAAAjHbm28F8OwAAAGySS4qz8knxTpcraMSXFB/KFYofnzC1uNe4Uun53r0AY1M+Sdf73KtNB3XOq9tL205rm2kNSHXUjJ7FsbYGe8ulLYnXW9I2dfgJZxqHqYLPffnb1lcFW/nRKy2qzbj2P262PiRJ0ohpWvfiWN6xa1zSUogbG5vr9ndgSZI0srq1oSlOat85JiepM5sqPVe4Lj91YLmJGwAAAKCeRMTRprYAgDpTcgoEKPs7o4eOw+j3QFZiRwMAAAAAAAAAAABgNDPfDubbAQAA4C8aekv/lCsUP+uCBY2WcoX0D7kkvWR878CcbAlv510MMHbkk+JDPutqU1/Xwrq9sO0/GltjksvapLrqgtapVd9bLm/p8VpLGnJT9zw0/vjgQ0ZhKuz3//3HmDLv1dZYhWra5VXW6RacfMbF1ogkSRqRTSykMa97rzimY3Z8rCWJmxua6/Z3YUmSNDL6VmNb7NO5u7OaqjBTWDx/3LjTnmfyBgAAABjrImJZ1gZTWwBAnSk5CQKU/b3RQ8dhjPzPI7Na7GoAAAAAAAAAAAAAjFbm28F8OwAAADzbdvkkPSZXSJ90wYJGVUn661ySnpnrHvAjCcAYkEuK9/h8q01zu/es68vaBjoXWAdSHTW1Z3H8aHJjVfeVTzd3ea0lDakJUwfiWzfcbASmCpa9+XRrrIKd9N4PWlRbsPOSw60RSZI0KpqUpDG/e884vn1WXNHcHbc1NNb178SSJGn4WtWSRG/PYmc0VbRcUvy38b19LzF9AwAAAIxVEVHMWmdiCwCoQyWnQYCyvzt66DiMHb/MGm9nAwAAAAAAAAAAAGA0Mt8O5tsBAABgsyYkfdPzheKvXLCgUXopxvfySfrmV3b2b+/dDDA6ZXv5z32m1aZCz951fUnbRa0F60Cqs97TPqOq+8pVzZ1eZ0lD6rT3XWr0pQpWX/V166uC7Th937jz7nstrM34yX/dYY1IkqRRW0PSH2nXgljRPjO+2DQlfjK5sa5/N5YkSbXt1oamOKl959ipkDqbqXIl6Xd2SEqvMIEDAAAAjDURsXvW4ya2AIA6VXIiBCj7+6OHjsPY8qOsf7a7AQAAAAAAAAAAADDamG8H8+0AAACwRTv2FP9vLkmvdMGCRvHFGOtzSfEr2f+99BUdpX/wrgYYPXKF9Ic+y2rTxovJbq/jC9pua2iM1qTPWpDqqI7sPX9zQ1PV9pUvNU3xOksadLuXjo4nnnzS2EuF3fP7+6N9t4OtsQp2wrtWWlhbcN6HP22NSJKkMfX7ycGd8+KMtunxxaYpdfv7sSRJqm3fbGyLYufuzmOqWLmk+POJvQONpnAAAACAsSIiZmY9bFoLAKhjJadCgLK/Q3roOIw93836ezscAAAAAAAAAAAAAKOJ+XYw3w4AAABblU/SZbkkfcwlCxrlF2Q8nq3lq7NKHR2lF3lnA4xsuUJ6rc+v2nVTQ3NdX852RMeu1oFUZ53UvkvV9pSvNbV7jSUNqskz94+1P7vDuEuFbdiwIQ5+0wprrILtOH3fuPPuey2uLVj4qmOsE0mSNGbr6tk7Du6cF+e0TYsbGlvq+vdkSZJU/Va1JFHIzh/OYapISXp/rjCwi0kcAAAAYLSLiKas35vUAgDqXMnJEKDs75EeOg5j0zVZL7DLAQAAAAAAAAAAADBamG8H8+0AAABQllx3WsgViv/lkgWNhbK1/Mdckl6WtTBb3tt5hwOMwLNHUvycz6za9e9NHXV9KdvnmjutA6nOair0x3erdAH09Y2tXmNJg+riyz5vzKUKVn36Guurwp3wzgstrC345a9/a41IkqS6aULWvO694oSOWfGp5q748eTGuv59WZIkVacfTG6KYzpmxyTnL1WmR/LJwGLTOAAAAMBoFRGvyPq5SS0AgCg5HQKU/V3SQ8dh7PpElmdmAQAAAAAAAAAAADAqmG8H8+0AAABQtpe1pi/NFdIrXLCgMVWS3pUrFM/PdacF73KAkSNfSC/1OVW7Pt3cVfeXsu3SvchakOqsIzvmVGU/uamh2esrqez2fd3J8fTTG4y4VNidd98brbMPtMYq2I7T9930urJ551/6GetEkiTVbQ1Jf6RdC2JF+8z4YtOUuv+tWZIkVbavN7ZvOms4d2nb5wSL6yYkxdebyAEAAABGm4h4adbNprQAADYpOSEClP190kPHYWxbYacDAAAAAAAAAAAAYDQw3w7m2wEAAGDQ8km6LJ8UH3XRgsZga7NWbN/dP9k7HWCYzxuF9H0+l2rXRa2Fur+M7V/adrYWpDprUiGNbzW2VXw/WZvl9ZVUTu27HRx333Of0ZYKe/rpDbHf60+2xircCe+80OJ6DnsddJx1IkmS9Oem9SyON3TsGpe2JnFzQ1Pd//YsSZK2vduzzmvtjfaePuctbWsbNs4HmsoBAAAARouIeGHWV01oAQD8RckpEaDs75QeOg5j35vsdgAAAAAAAAAAAACMdObbwXw7AAAADMkOhYH2XCH9kUsWNDZLn87+vSGfpMeM7+17uXc8QO3lk+LJPo9q13vaZ9T9RWxrGlpjUpJaD1KdtbRzblX2lMn2E0ll9PmvXm+kpQou+cTnra8Kt+P0fePOu++1uLZg42tjnUiSJG2+jb+5zu/eM45vnxVXNHfH2jr/HVqSJG1bNzU0x/KOXWOCc5a2taR44bhxpz3PdA4AAAAwkkXEdlkfNaEFAPBXSk6KAGV/r/TQcRj71mcN2PEAAAAAAAAAAAAAGMnMt4P5dgAAABiyCTuXXpxL0ktcsqCxXK5QfCKfpFdnLRvf2/cS73yA2sgV0jf4HKpdJ3TMcglb1n6d860Hqc7aeOni55o7K76fdCR9Xl9Jz9kxp55nnKUKfn7Hb6Jx55I1VuHeevq/WlzPYeVHr7ROJEmSymzjbyZLp8yLC1qnxncbWvwuLUmShtQnm7tiRs9i5ytt21xgUvzcxhlYEzoAAADASBURp5vOAgD4GyUnRYCyv1d66DjUh0eyptv1AAAAAAAAAAAAABipzLeD+XYAAADYZvkkXZYvpA+7aEFj/yKN9MGsy3KFYv+4uXNf4N0PUD3ZXnuAz57addiU3Vy+lrWqJbEepDpsj6494vYK7ye9LnKU9Bzt0rc8HnrkUaMsFbZu/froW/pWa6zCtcw+IH7/33+0wJ7D4oPfYq1IkiQNsVk9i+L49llxRXN3rPUbtSRJGkRrJzfGivaZsVMhda7S0EvS7+SmD7zMlA4AAAAw0kTEa01mAQBsVslpEaDs75YeOg71456sSXY+AAAAAAAAAAAAAEYi8+1gvh0AAAAqYofCQHsuSW9z0YLqpVwh/U3279n5ZJ8eOwBA5Y1P+vfweVO7BjoXuHht48VrDY0xtWexNSHVYZe2JhXdT+Z07+V1lbTZJvXuE9+/5SdGWKrggks/a41VoY2vK1t25933xoSpA9aKJElSBWrv6YuDO+fFOW3T4ruNLX6zliRJZfXNxrbo71rgPKWhzwEm6W0TepbkTeoAAAAAI0VEzMl6wnQWAMBmlZwYAcr+fumh41Bf1mb9k90PAAAAAAAAAAAAgJHGfDuYbwcAAICK2XHu3P+TKxTPd9GC6rC1WSsmFPqb7AQAlTGxkE7z+VK7Zvfs5cK1P/eO9pnWhFSHTeteHD+e3FixvWSPrj28rpI221krLze6UgU/++Vd0TCzZI1V+vNx0WHx2OPuZnku517yKWtFkiSpCk0spDG/e884vn1WXNnUGbf77VqSJD1HG88KF7b2RkfS5yylIZVLir/NF/q7TesAAAAAwy0iJmfdZzILAGCLSk6NAGV/x/TQcag/X8l6vh0QAAAAAAAAAAAAgJHEfDuYbwcAAICKyxeK++UK6QMuW1BdlqQ3ZR2zffc+r7QbAAzdpGn7NvhcqV3NSb/L1v7cdxtbYlIhtS6kOuyMtukV20vSrgVeU0l/06KD3hJPPbXO2EqFrVu/Pha/+nhrrApd9ZXrLbCt2G2fN1krkiRJNWhKsiQO7pwXF7b2xk0NzX7LliRJm+0/G1pieceuMcH5SUMoVyj+cfzU4q4mdgAAAIDhEhH/mPVjU1kAAM+p5OQIUPb3TA8dh/r0ATsgAAAAAAAAAAAAACOJ+XYw3w4AAABVsX1PcadcUvyeyxZUtyXp+uzfr2f/LntFR+kf7AoAgzOpa8n/83lS21xE+v93UOc8a0Kqw1qTvk2XLVZiHzmgc77XVNJf1bTLq+IXd9xtXKUK3v/B1dZYFepb+tbYsGGDBfYcbr7tp9aKJEnSMDSpkMaSroXx7rYZ8a3GNr9pS5Kkv+mK5u6Y1rPY2UmDLlcoPpGbOvAqUzsAAABArUXEC7O+bioLAGCrSk6PAGV/1/TQcahfb7ILAgAAAAAAAAAAADBSmG8H8+0AAABQNU1Ni/4uVyie77IF1f1lG0n6WPbvZ7L3Q39v7/IX2h0AynHa8/JJut7nSO26pqnDBWvPuGTNmpDqs2M7ZlVkHzl0ylyvp6S/6rLPfsWYShX86PZfxo7T97XGKtyEqQPx/Vt+YoFtxclnXGy9SJIkjYCmdS+OozvmbPpdd+3kRr9xS5KkTd3a0BTHt8+KSUnqzKTBlaTrc0nR//ASAAAAqKmI+JCJLACAspScHgHK/q7poeNQv9Zl7WEnBAAAAAAAAAAAAGAkMN8O5tvthAAAAFRdvlDcL1dIH3DhglSMXFK8J1conjch6ZtudwB4btn54Q8+O2rXx1oSl6v9uduzZvYssi6kOmynQhrXNrVt8z5yZMccr6ekv/TaN58eGzZsMKZSYU8++VTsXjraGqtCb3r7+y2wrXjqqXXROe811oskSdIIq72nLw7unBcXtvbGzQ3Nfu+WJElxVXNnzPK3Xw2lpHj6uHHjtjO9AwAAAFRbRLzZRBYAQNlKTpAAZX/f9NBxqG9/ymq3GwIAAAAAAAAAAAAw3My3g/l28+0AAADUxPjevkn5JP2OyxakZ168kf46l6Rn5roHWuwSAH8rnxRv93lRu85sm+5StWf0rraZ1oVUpx0wZf427yFvb9/FaylpU927L4377v+j8ZQqeM95q6yxKtQ256D43b33W2Bb8dVrv2e9SJIkjfAmZS3qWhgr2mfGNxrb/e4tSVIdt3Zy46YzwU6F1DlJgypXKH68t3f5C03wAAAAANUSEXOynjSRBQBQtpJTJEDZ3zk9dBy4Peuf7IgAAAAAAAAAAAAADCfz7YD5dgAAAGpn7twX5AvFFflC+rQLF6S/aW3WiTtO33sHmwXA/8gV0mt9PtSu49tnuVDtGd3Y2ByTE5eqSfXa5c0927SHnN42w+soaVNfu+5GYylVcNOtP41JvftYY1Vo1aevscDKcPgJZ1ovkiRJo6xZPYs2/Q5+ZVNn/GRyo9/BJUmqw77a2BELu/ZwNtJg+9rLWtOXmuIBAAAAKi0idsy6zzQWAMCglJwkAcr+3umh48BGn896nl0RAAAAAAAAAAAAgOFivh0w3w4AAEDN5QppmvUHly1Imykprsslxa9k//fSV3SU/sGOAdSzbE/8pM+G2rW0c66L1J7Va6fsZm1Iddrs7kWxdhsuVz6vtdfrKClOeu8HjaNUwWOPPxG7DrzRGqtCfUvfGk8/vcEi24oHHnw4Js/c35qRJEkaxXX17B1HdOwan2jpjh9vw29AkiRp9LW2oTHe3TYjGpJ+5yKVXS4pfm+HpPQKkzwAAABApUTEi7NuMo0FADBoJadJgLK/e3roOPC/TrMrAgAAAAAAAAAAADBczLcD5tsBAAAYFrlpxYn5JF3jwgXpOS/jeDx7n1ydVeroKL3IzgHU3XkhST/g86B27dm9h0vUntWVTZ3WhlTHndk2fcj7x6WtiddQqvNmp2+IRx593ChKFZx69oetsSq004z94me/uNMCK8OHr/iiNSNJkjSGakj6Y//O+XFha2/c3NDkt3FJkuqkaxvbIu1a4DykQczypb/MJ0uaTfMAAAAA2yoitstabRILAGBISk6UAGV///TQceB/bcja384IAAAAAAAAAAAAwHAw3w6YbwcAAGD4zJ37gnyhuCJfSJ926YK0lUs5CsU/5pL0sqyF2btnOxsIUA+y/e9EnwG1qzNZ4vK0zTSney/rQ6rTWpO++H5D85D2jk81d3kNpTpux2n7xi0/+i9jKFVw4y0/iYm9A9ZZFXr/B93RUq75+x9tzUiSJI3RdiqksV/X7nFu67T4bkOL38glSRrj3Z618XO/JelzFlJ5M3xJ8Z58sk+PiR4AAABgW0TEiaawAACGrORECVD2908PHQee6aGsKXZHAAAAAAAAAAAAAGrNfDtgvh0AAIBhlysUF2y6bMClC1J5Jeld2fvm/Fx3WrCDAGP6jJD0v9a+X9tubmhyedqzOrNturUh1XFHdswZ0t7xpaYpXj+pjrvwI581flIFjz72eMxO32CNVaFdB94YTzz5pEVWhhtv+Yk1I0mSVCdNLKQxv3vPOKl95/h6Y7vfyyVJGsN9p7E1Sp3znYFUVrlC+sD4nv7ZpnoAAACAoYiIhVnrTWIBAAxZyakSoOzvoB46DjzbT7NeaocEAAAAAAAAAAAAoJbMtwPm2wEAABgRXtnZv32+UPyaSxekQbc2a8X23f2T7STAWDNhanEv+3xtu7qpw6Vpz+oHk5uiOem3PqQ6bVKSxjVD2Bu/3djm9ZPqtIFD3x7rn37a6EkVvO30f7XGqtCEqQNxw423WmBlOvZfzrduJEmS6rRZPYvi+PZZcWVTZ9zut3NJksZkl7QUoi1Z4uyjrZcUH51Q6F9ksgcAAAAYjIjYIeseU1gAANuk5GQJUPb3UA8dBzbn81nb2SUBAAAAAAAAAAAAqBXz7YD5dgAAAEaOUun5+UJxRT5J17t4QRps6dPZvzdk759jxvf2vdyGAowF+UJ/t/29tl3cOtVlaZvp8Cm7Wh9SHdfftWDQ+8ZNDc1eO6kOa9v1oLjrt783clIF3/7OLTFh6oB1VoVOPuNiC6xMDz38aDTt8irrRpIkSTGtZ3Ec2zErPtfcGbf7DV2SpDHV9Y2tUeza3Zm3QUcoAAAgAElEQVRHWy1XSJ/MTR14lekeAAAAoBwR8YKsNaawAAC2WcnpEqDs76IeOg5syTF2SQAAAAAAAAAAAABqxXw7YL4dAACAESffk87PJenvXLwgDfXCjuIT+SS9OmvZ+N6+l9hVgNFq++59Xmlfr22ntu/sorTNdHVzh/Uh1XkXt04d1L7xk8mNMSlJvXZSnXXll641alIFDz38aMxY/HprrArN2/fIeOzxJyyyMn3s01+2biRJkvQ3Jcnesbxj11jVksRav6dLkjRmuqSlEK1Jn/OOnrskXZ/vSQ834QMAAABsTUR8wAQWAEBFlJwuAcr+Luqh48CWPJU1x04JAAAAAAAAAAAAQC2YbwfMtwMAADAi7ZCUXpFLil9x8YK0beUK6QO5JL0sVyj2jyuVnm93AUaX056X7WFP2c9r12FTdnNB2hZa3LXQGpHq/HLkWyY3DWrf6HDRolRXHX7CmcZMquTYfznfGqtCk2fuHz/+6a8ssEHY66DjrB1JkiQ9Zxt/Dzp0ytxY1ZLEWr+rS5I06vtOY2vs1znfOUdba8P4QvFtZnwAAACALYmIYtYGE1gAABVRcsIEKPv7qIeOA8/lnqwd7JYAAAAAAAAAAAAAVJv5dsB8OwAAACPYac/LJcVT80m63sULUgVK0ruyf8/OF/q77S/AaJGdBX5rD69de3Xv4XK0LXRpa2KNSHXe8e2zBrVv7NK9yOsm1UnTF70uHvzTw0ZMquBr191ojVWpD13+BQtsEH7wo59ZN5IkSRpU7T19ceiUubGqJYm1kxv9zi5J0ijuwtbeaE76nXH0nOUKxTPGjRu3nUkfAAAA4JkiojnrQRNYAAAVU3LKBCj7O6mHjgNb862s59sxAQAAAAAAAAAAAKgm8+2A+XYAAABGvAmFdLdcoXi3ixekirY2a8XE3oFGuwwwkuWT4s327NrVmSxxKdoW+snkxpjes9g6keq4SVlfaeooe99Y3LXQ6ybVQdn36rjhxluNllTBHx98KJKFh1hnVeigN54WGzZssMgG4ciT3m/tSJIkach1JH1x+JRd4/KWnlg7udFv7pIkjcKua2yLtGuBs4221qpxc+e+wLQPAAAAsFFEvDjLgCEAQGWVnDQByv5e6qHjQDneaccEAAAAAAAAAAAAoJrMtwPm2wEAABgVxvf2vTxXSL/s0gWpCiXpTVnHbN+9zyvtNsBIkysUv2Svrm03NzS5FG0LvbdtujUi1XmLuxbG7WXuGQdMme81k+qgM1d+wkhJlbzxxPdZY1Woa/7S+P1//9ECG4SNr9dOM/azfiRJklSR2pIl8bopu8XHm3ti7eRGv71LkjSK2vg3ojPbpkdD0u9co+covaqpadHfmfgBAAAAIuKDpq8AACqu5KQJUPb3Ug8dB8rxdNYCuyYAAAAAAAAAAAAA1WK+HTDfDgAAwGiyXa4nfWsuSZ9y8YJU+XKF9Ml8UvxCrlA8YMLOpRfbcoCRINubPmyPrm1XNXe6EG0L/WByU7QkfdaJVOdd1Fooa89Y3rGr10sa4y1ZekKsW7feSEkVfOVb37PGqtS/f/v7Ftggve+iK6wdSZIkVaXWpC8OnTI3VrUksXZyo9/hJUkaJV3b1BZ7de/hPKMtz+Elxa+M7+17iakfAAAAqF8Rsa/JKwCAqig5bQKU/d3UQ8eBct2d9XI7JwAAAAAAAAAAAADVYL4dMN8OAADAqDOxkE7LJekvXL4gVfNij/Sx7N/P5ArF/t7e5S+08wDDJZcUT7Uv17ZzW6e5CO05OrZjtnUi1XmdPUvi5obmre4Xb+3YxesljeGaZx0Qv/z1b42SVMF99z8Q3bsvtc6q0DvO+pAFNkhPPvlUJAtfa/1IkiSp6rUlS+LQKXNjVUsSaxsa/R4vSdIIb23WivaZsWMhdZbR5ufvCun3c9MHXmbyBwAAAOpPREzM+oPpKwCAqig5cQKU/f3UQ8eBwbgmazu7JwAAAAAAAAAAAACVZr4dMN8OAADAqPTPMxb9Yz4pftLlC1INStL7c0l6yfjegTnZ28+PQ0BNZXvQMntxbTumY7ZL0J6j6xrbYpJ1ItV9x5axV767bYbXShrDffoL3zRCUiWHn3CmNVaFioecGE89tc4CG6RPfeEb1o8kSZJqXk/Pkji6Y05c2dQZt/tdXpKkEd0XmqbELt2LnGG02XKF4o8nFtKc6R8AAACoHxHxgqwbTF4BAFRNyakToOzvqB46DgzWm+2eAAAAAAAAAAAAAFSa+XbAfDsAAACjWj5Jl+WT4qMuYJBqVJL+OpekZ+a6B1rsQEAtTEgG5tp/a1vatcDlZ1vpoM551opU503Kurqp4zn3igtbe71W0hjt8BPONDpSJVd+6VprrAoV9jgk7r3vDxbYECx+9fHWkCRJkob3PN+zdxzdMSeubOr0+7wkSSO02xoa4/j2WTGxkDq/aHP9amLvQKMJIAAAAKgPEfFuU1cAAFVVcuoEKPs7qoeOA4P1RFbBDgoAAAAAAAAAAABAJZlvB8y3AwAAMOrlk3168oXiT12+INW2XFL87vhC/1E7JKVX2ImAatm+p7iTPbe2dffs7eKzrfRvTZ3WiqTYvXvPWNvQuMW94vLmHq+TNAabsfj18eCfHjY6UgX33veHmDLv1dZZhWuYWYpbfvRfFtgQfO8Ha60hSZIkjaim9SyO49tnxb83dfitXpKkEdjq5u4o9Ozt3KK/nbMrFO/eIUk7TAEBAADA2BYRc7PWm7wCAKiqkpMnQNnfUz10HBiKn2e91C4KAAAAAAAAAAAAQKWYbwfMtwMAADAmvKKj9A+5QvHjLmCQhqGkuC57/31pQlI8eHxv30vsSEAl9fYuf2E+Sdfbb2vbjY3NLj3bSgu79rBWJMXZrdO3uE98tbHDaySNsSb17hPfu/nHRkaqZOnR77LOqtDqq75ucQ3R695yhjUkSZKkEdtu3XvGaW0z4/rGVr/ZS5I0grqpoTmWdc51XtFmZuzS+yf0DMwwCQQAAABjU0T836y7TF0BAFRdyekToOzvqh46DgzVh+2iAAAAAAAAAAAAAFSK+XbAfDsAAABjSj5Jl+UL6cMuYZCGp1ySPpb9+5lcodjf27v8hXYloBJyhfQ39tja9pnmLheebaWLWgvWiqRoSfrjhsaWze4TNzY2e42kMdbZ/3qFUZEqueLf/t0aq0Knnv1hi2uIfnHH3TGxd8A6kiRJ0ohvYiGNxV0L45y2aXFTQ7Pf7yVJGiFd0lKI1qTPeUXP7pHxPQN7mgQCAACAsSciPmnqCgCgJkpOnwBlf1f10HFgW+xnJwUAAAAAAAAAAACgEsy3A+bbAQAAGHNy3QMt+UJ6iwsYpGEuSe/PJekl43sH5mRvze3sTsBQZXvKDfbV2nZW63QXnW2ltVmFnr2tF0nxminzNrtP3J41OUm9RtIYafGrj49169YbE6mC3/zuvmibc5B1VuH2OfTt8dRT6yywIXrLaRdYR5IkSRp17VRIY//O+XFha2/8sKHJb/mSJA1z321siWLn7s4p+qtyhfTJfJLubxoIAAAAxo6IONjEFQBAzZScQAHK/r7qoePAtrgvawe7KQAAAAAAAAAAAADbynw7YL4dAACAMampadHf5QrF8/OF4gYXMUgjoKR4e/bvinyypNkOBQxWrpBeYS+tbW+cMsclZ2W0on2m9SJpU6taks3uE709i70+0hioZfYB8ctf/9aISBVs2LAhXrX8VOuswu3Stzz++w8PWmBDdM/v74+dZuxnLUmSJGl0f5dN+uLQKXM3/W611u/5kiQNW7dnndE2PXYspM4oesYsXbp+fFJ8nYkgAAAAGP0iIp/1B1NXAAA1U3IKBSj7O6uHjgPb6gt2UwAAAAAAAAAAAAC2lfl2wHw7AAAAY1q+0L9vrpA+4CIGacS0IeuGXFJ8U276wMvsUkA5coXie+2ftW2Prj1ccFZGNzU0R1Oh35qRFFN7FscPG5r+Zp/YuJ96faTR32e++E2jIVXy0U9+yRqrcF3zl8Yv7rjb4toG7zr3o9aSJEmSxlQ9PUvi6I45cWVTp9/2JUkapr7YNCVm9ixyNtGz5ujS40wFAQAAwOgVEdtlXWPiCgCgpkpOogBlf2/10HGgEl5vRwUAAAAAAAAAAABgW5hvB8y3AwAAMOaN7+2blC8Ub3AJgzTCStL12b9fz/5dtn33Hn9vtwK2JFdI32DfrG2TkzTWTm50uVkZHdkxx5qRtKkTOmb9zR5xYOc8r400ylv+1rOMhFTJnXffGy2zD7DOKljTLq+Km279qcW1DR548OFonX2g9SRJkqQx2+zuRXFS+87xrcY2v/FLklTjbm1oiqP9fVnPKpekZ5oMAgAAgNEpIt5s4goAoOZKTqIAZX9v9dBxoBIeyWq2qwIAAAAAAAAAAAAwVObbAfPtAAAA1IXe3uUvzCfpWflCcYOLGKQRWFL8U76QfiyXpAvHlUrPt2sBz5RPBhbbK2vfNU0dLjYro40Xj04spNaMpJiU7QXP3juPdDGiNKqbuffr408PPWIkpAqefnpD7Pu6k62zCrbj9H3j2v+42eLaRh/40KetJ43ZDjn+vDj8pIviwKPOisVLT4k5+xwTPQsPjZ1m7O/1kSSpDtv4u/biroVxbuu0uLmh2e/9kiTVsA+3FKItWeJMor+UK6TvMR0EAAAAo0tEtGU9ZuIKAKDmSk6jAGV/d/XQcaBSbsh6np0VAAAAAAAAAAAAgKEw3w6YbwcAAKCuTCj0L8oX0t+7iEEawZeEJMXfZu/T9+e604JdC9hohyTtsD/WvvNae11oVmav6tzdmpG0qbnde8baZ+wP/9K2s9dFGqVN6t0nvveDtUZBquSDH7/KOqtgE6YOxGe++E0Laxs99vgT0b37UmtKY7I9X/32WLl6zRZ7/0e/HqddcFUce/rH43VvuzBKbzwjFr3m5NileFRMmbcsJmafi15HSZLGbjsV0ti/c35c0lL4q9+2JElS9fpuY0sMdC5wFtEzZ+bOHTdu3HamhAAAAGDk2/iApaw1Jq4AAIZFyYkUoOzvrx46DlTScXZWAAAAAAAAAAAAAIbCfDtgvh0AAIC6M6l3n/G5pPhNFzFIo6K1+aR48g6FfXe0e0H92r57j7+3H9a+N02Z4zKzMruqudOakfSX3tU28y/7w/mtvV4TaZT2vouuMAJSJT+/4zfRuHPJOqtgl3zi8xZWBXz4ii9aTxqTNc8+MM7+yNdi5eo1Q+6CK66P91785Tjx7E/GEadcHAcceVYsXnpyzCoeHVPmLYuJvft4rSVJGiN19ewdR3fMiaubOvz+L0lSlbs964y26bFjIXUO0Z9LLxo3btx2JoUAAABgZIuI401bAQAMm5ITKUDZ3189dByopEezmu2uAAAAAAAAAAAAAAyW+XbAfDsAAAB16rTn5ZLiqfkkXe8iBmlUtCF7v16fnzqwfFLXkv9nD4P6k+0D99oLa9vCrj1cZDaIFnctsG4kbaoh6Y9vNbZt2hsub+nxmkijsP5lb4t169cbAamCja/rkqUnWGcV7D3nf9zCqoDHHn8ikoWHWFMak73pHR+KlavXVLULLr8u3nPxl+NtZ30yjjj5g3HAm86MPV799pi+9xuiedaB/jtIkjRKm9+9Z5zZNj2+39Ds7wCSJFWxLzZNiek9i50/9D8lxY+MK5Web1IIAAAARqaIaNk4bmTiCgBg2JScSgHK/g7roeNApf1H1vPssAAAAAAAAAAAAAAMhvl2wHw7AAAAdS3fm87MF4q/chmDNHrKFdIn80l6dday7bv3+Hs7GdTJZ3aSrrEH1rbJSRprJze6xKzMLmvpsW4k/aW+roVxe7Y3fLWxw+shjbJaZh8Qv7rzt0Y/quS8D3/aOqtgR51ybmzYsMHCqoCLVn3OmtKYbLf9jouVq9cMe+d94tp49we/FMecvipec+w5seS1p8bsgTfHlHnLYuLUAf+tJEka4U1K0ki7FsQlLYX4sb8bSJJUlX4wuSmWdc519tD/lKSf6u1d/kLTQgAAADCybHygUtZ1pq0AAIZVyckUoOzvsR46DlTDUXZYAAAAAAAAAAAAAAbDfDtgvh0AAIC6N7637+X5JL3aZQzS6CtXSB/IF9JL8z3FeePGnfY8OxqMXfmk+BH7Xu37UtMUF5gNonlde1k3kv7Sua3TNl2A6LWQRldXfulaIx9VsvZnd8ROM/azzirU0qPfFevWrbewKuCRRx+P7t2XWlcaczXMKMV7L7kmVq5eM6I7/7JvxztXfj6OedfHYumx58aSQ06NXdIjo3XOwf47SpI0AmtN+mJ5x65xZVOnvwtIklSFLmztjcak37lDkUvSKzs6Si8yMQQAAAAjR0QcY9oKAGDYlZxMAcr+Huuh40A1PJrVaJcFAAAAAAAAAAAAoFzm2wHz7QAAAPA/tssn6TG5QvqkCxmkUXqRSKF4d9b543sH5tjSYOzJPqffbq+rfee2TnNx2SC6qLVg3Uj6Sy1JX6xpaI22ZInXQxolHfG2s417VMm6detj8cFvsc4q1MChb49HH3vcwqqQCz/yWetKY7LD3rYyVq5eM6o7/7Jvx4oLroqjTrs0XnPsObHktafGzL43RcPMV/lvLEnSCGhWz6J4Z9uM+E5jq78RSJJUwb7a1B6ze/Zy3lDkCuk1E3YuvdjUEAAAAAy/iJic9bBpKwCAYVdyOgUo+7ush44D1fKtrO3stAAAAAAAAAAAAACUw3w7YL4dAAAAnmFiIZ2WS9JfuJBBGuUXiiTpbeMLxbflphUn2tlgbMgX+ve1v9W+w6fs6tKyQbS2oTFm9Cy2diT9pf0658e8bpceSqOhnZccHg89/KhRjyo5a+Xl1lmF6lv61nj4kccsqgp56JFHo3Pea6wtjb3Ptb43xYVXXB8rV68Zs5354a/GW8+8Ig5964WRHrYiZg8cHa1zDvbfX5KkYWhiIY20a0Fc0lKItZMb/b1AkqQKdFtDYxzdMcdZQxv72vjevpeYHAIAAIDhs/EBSn9+kBIAAMOv5IQKUPb3WQ8dB6rpcDstAAAAAAAAAAAAAOUw3w6YbwcAAIBneVlr+tJcIb3CZQzSWCh9Ovv3hnySHjO+t+/ldjgYvSb0FrvsabVvl+5FLiwbZO9rm2btSPqrWpI+r4M00i//7h2I7970YyMeVXLb7b+IHafva61VoD0OOCYeePBhi6qCzr3kU9aWxlyTsj13xYWfj5Wr19Rl53zsm3HKB66Mo067NA486qxYcODbomfhYTFx6oD1IUlSDersWRJHd8yJrzR1+JuBJEkV6NLWJFr9rUlJev0/z1j0j6aHAAAAYHhExCEmrQAARoySEypA2d9nPXQcqKYHs8bbbQEAAAAAAAAAAADYGvPtgPl2AAAA2IJ8T3p4LkkfcymDNDbKJcXHs/f0leN7igNNTYv+zi4Ho8uEnUsvzhfSp+1ntW1C1vcaWlxWNohua2iMrp69rR9JkkZR51z8SeMdVfLkk0/F7qWjrbMKtOvAG+O++x+wqCroTw89Eu27HWx9acx18JvfFytXr9GzOu+ya+PUD/xbvOGUS2K/I94du+53bLTPXWrNSJJUxeZ37xnntE2LWyY3+fuBJEnb0PWNrbFn9x7OF/Vekn6nobf0TyaIAAAAoLYi4mVZ95m2AgAYMUpOqQBlf6f10HGg2i632wIAAAAAAAAAAACwNebbAfPtAAAA8Bx2KAy055LirS5lkMZWuUL6QC5JL8taOG7cac+z28HokE+Kd9rDat9HWnpcVDbITm+bae1IkjRK2vs1J8S6deuNdlTJ6R/4mHVWgWb1HxH33vcHC6rCzrjwE9aXxlyFPV8fF1x+XaxcvUZlds6qb8QpH7gyjjjl4tjviPfE3P2Oi5Y5B1tPkiRVsOakPw6dMjeuaO6O2/0NQZKkIbU266T2nWNiIXW+qO9+ML637+UmiAAAAKB2IuJjJq0AAEaUklMqQNnfaT10HKiFve24AAAAAAAAAAAAADwX8+2A+XYAAADYivG9fS/JF9JLXcggjdGS4p25QvG9E3v6p9jxYGTL3rNft2/Vvrd0zHZJ2SD7YUNTdCZLrB9JkkZ4bXMOijvvvtdIR5XcdOtPY1LvPtbaNjZt0WHWaRX87t77o3HnkjWmMdXEbM99x7mfjZWr16gCnfnhr8bx7/1ELD3uA7HoNSdHYa/Xb3qNrTVJkrat2d2L4vS2GfG9hhZ/T5AkaQitau6J9p4+54o6LpcUb92+e59XmiICAACA6ouI3bI2mLYCABhRSk6qAGV/r/XQcaAW7sj6e7suAAAAAAAAAAAAAFtivh0w3w4AAABlyheK++UK6QMuZpDGdGuzVmzf3T/Zrgcj8bM4vcg+Vfv26NrD5WRD6LS2mdaPJEkjvM99+dvGOarkscefiDnFN1pn21jPgmXx8zt+Y0FVwXGnnW+Nacy1/xvPiJWr16iKXXD5dbHigqviiFMujv2OeE/M3e+4aJl9kPUnSdIQmpSkkXYtiEtaCrHW3xQkSRpU1ze2bvo7vjNFXffTCT1L8iaJAAAAoHoi4kVZPzFpBQAw4pScVgHK/m7roeNArbzbrgsAAAAAAAAAAADAlphvB8y3AwAAwCBMKPQ35ZP0JpcySGO99Onsvf6NXCE99J9nLPpHux+MDPmpxWPtT8NwsWUhjVsbmlxONsh+mL1mHUmfNSRJ0gjtqFPONcZRRe8460PW2TbWs2BZ/OwXd1pMVXD7z38dk3r3sc40tvaMhYfGeZ+4NlauXqNh6L0XfzmOOX1VHHT02bHgwLfGlPmvtS4lSRpESbJ3vL19l7i+sdXfFyRJKrMfT26MozrmOEvUcbmk+PPxvX2TTBMBAABAdUTECpNWAAAjUslpFaDs77YeOg7UyrqsHjsvAAAAAAAAAAAAAJtjvh0w3w4AAACD1Nu7/IX5QnFFvpA+7XIGqS4uIHk8n6RXZ5U6OkovsgvC8Mn3pEvsS8PTZ5q7XUw2hE5p39n6kSRpBLZL3/J46JFHjXFUyQ033hoTpg5Ya9tQz4Jl8dOf32kxVcmrj3yndaYx1cY99+3v+1SsXL1GI6hzVn0jTsz+uxxy/Hmx12tOip6Fh/l8lCRpK00spJF2LYhLWgqx1t8YJEkqq0tbkmhN+pwl6rWkeOeEQn+TiSIAAACorIhoynrCpBUAwIhUcmIFKPv7rYeOA7V0XdZ2dl8AAAAAAAAAAAAAns18O2C+HQAAAIYoVyj255P0fpczSPVTrpA+kEvSy7IWZtuAH7qg1p+93QMt9qLh6dT2nV1INoRubmh2gZkkSSOsHaftG//5w9uNb1TJo489HrP6j7DWtqFk4WvjZ7+402Kqkv+48TbrTGOufY94d6xcvUajoHNWfTNOfN+n4pDjz4u9XnNS9Cw8LCZMHbCOJUnaTF09e8fx7bPi241t/t4gSdJW+mb2eblb957OEPU6z5YU75nY0z/FVBEAAABUTkR8yaQVAMCIVXJiBSj7+62HjgO1drDdFwAAAAAAAAAAAIBnM98OmG8HAACAbZCbVpyYT9I1LmeQ6rJf5ZPi6TsUBtrthlAbvb3LX5hL0qfsP7Uv7VrgMrIhdlL7LtaQJEkjqHMu/qSxjSo64V0rrbNtKFl4SPzsl3dZSFXy9NMbYtFBb7HWNKbqWnBInHfZtbFy9RqN0s5d9a048exPxrK3nBd7HnxidM4/xNqWJOkZTSykm/5GcUlLIdb6m4MkSVvstobGOLpjjvNDnZZLivdM6N6n02QRAAAAbLuI6DdpBQAwopWcWgHK/o7roeNArd2T9Y92YAAAAAAAAAAAAACeyXw7YL4dAAAAttXcuS/IJ8V35wvp0y5okOq0JL0p2wOOm9S7z3ibIlRX9p5ba9+pfZOTNG5taHIZ2RC6qaE5WpM+60iSpBHQwKFvj/VPP21so0qu++4tMWHqgLU2xKYtOizuuOt3FlIV/duXr7XWNKbauOee+L5PxcrVazTGet9HvxZvec9lceDRZ8fc/Y6LljkHW/OSJGV19+wdx7fPiusa2/z9QZKkLXRha280Jv3ODnU5v1b871x3WjBZBAAAAEMXEX+X9TOTVgAAI1rJyRWg7O+5HjoODIez7MAAAAAAAAAAAAAAPJP5dsB8OwAAAFRILkkX5pLiPS5okOr5cpJ0fb6Q/nv277KXtaYvtTNC5WXvr0/bb4anK5q7XUI2xE5sn2UNSZI0zLXtelDc9dvfG9eokocefjSmL3qdtTbENr52d9z1Owupih559PHo3esw601jquLr3xkrV69RnfSei78cR532kdjviHfHLumR0TCj5H0gSarbJhbSSLsWxCUthVjrbxCSJP1NX2tqj1k9i5wb6rBcofjHCT0DM0wXAQAAwNBExKkmrQAARrySkytA2d9zPXQcGA5PZrXZhQEAAAAAAAAAAAD4X+bbAfPtAAAAUEE7JKVX5ArpNS5okJRLio/nk/TqrFJHR+lFdkiojOy9dao9Zng6oWOWC8iG2E0NzdGa9FlHkiQNY1ddc51RjSo6+pRzrbMhNmPx6+PXv7nHIqqy95z/cetNY6op85bFuau+FStXr1GddsEV18eKC66KI065OJa89tToWXhYTJg64P0hSaq7pvYsjne0z4zvNLb6e4QkSc/oB5Ob4uDOec4LdTmzlj44oWdghgkjAAAAGJyImJj1iEkrAIARr+T0ClD2d10PHQeGy9ftwgAAAAAAAAAAAAD8L/PtgPl2AAAAqLzt8kl6TC5Jn3JJg6RNl5UUin/M9oTLshZu3CNskzB0E6am+9hXhqf53Xu6fGwbOrl9Z+tIkqRh6s3v+IARjSr66rXfs86G2C59y+Ou3/7eIqqyO+76XUyeub81pzHThKkDccIZl8fK1Wukv+qcVd/YtDYOPOqsmLvfcdE46wDvGUlS3TQp64DO+bG6uTtu9zcJSZI2tfEz8V1tMzd9TpStI/sAACAASURBVDov1NmsWpI+OKFnYIYpIwAAAChfRFxp0goAYFQoOb0ClP1d10PHgeG0j50YAAAAAAAAAAAAgI3MtwPm2wEAAKBKcklxVj4p3umSBknPurTkF9m/78x1D7TYKWHwJhT6m+wlw9PEQhrfb2h2+dgQu2VyU0xJllhLkiTVuF36lsdDjzxqPKNK/vDAnyJZeIi1NoTm7Xtk3PP7+y2iGnjNUe+05jSmSg87LVauXiNttQuuuD7+5fzPxetOXBmLlp4S3QsO9R6SJNVFM3oWx4r2mfGfDS3+PiH9f+zdeXicZb34f9Dj8fj16+8sHg90krY2SZM2bZNnkpYdSqFAS5uZtDDs+1JAoYgogoDgwQXQgtiAgCCINIiVg4JLWWRpKjuyliIiCrLveyk0+XwHfp5NQdI2k8w883pd1/vqn+dczJ37fuZ6Ps4tScV+NHpCjG/1rrrqZtSy+eeHtXW2mzQCAACA9xcRU0xZAQBUjIInWIB+f9/1o+PAUHqo2IftxgAAAAAAAAAAAACYbwfMtwMAAEAJjZgw459rsrlLXdIg6d0vL8ndXJPk5v7b+I517JjQX8d9oCbJv2YPGZrOasy6dGwNevsST+tIkqTBa+TE2XHbXfcbzSihA4842Vpbjabveng898JLFtAguOK6m605papxm+8R887/VXR190ir1UnfXRQHH3du5Pf7crRts3/UtnX625IkpbaGbEfMad40ft4wzjsKSVLVt6S+MbaasJVnhKqbTcs/P6x9ZptZIwAAAHhvEfGBYreZtAIAqBgFT7EA/f7O60fHgaF2hN0YAAAAAAAAAAAAAPPtgPl2AAAAGAQ1SW6PTJJ73UUNkt61JLey+O+SmrbOOR9vyn3Mrgl/WybJ32rvGJrevnzShWOr3511DTE+mWEtSZI0SJ169sVGMkroJ4sWW2er0fb7Hx2vvPq6BTQIVqx4MzbJH2TdKTXVtnXGESd2R1d3jzRgnXL+NfG5r18YOx18UmzcOTdGTJrt702SlMqmtGwd85vaY+moeu8rJElV29Jih4/dyLNBlZXJ5l6oTWZOMm0EAAAA7y4i9jJpBQBQUQqeYgH6/Z3Xj44DQ+3lYuvYkQEAAAAAAAAAAACqm/l2wHw7AAAADJLhrR3jMtn8vS5qkPQ3LzJJ8suL//6ouF90tLfP+ZDdE/5aTTZ3nv1iaJrYOt1lY2vYV8euZy1JkjQIzdr7yFjZ22sko0Seff6laN1yD2ttFdvr0K/EGytWWECD5JSzfmjdKV1n2/4nRFd3j1TSTv3+NfGFb/wwdvvMvJi83WFRt0HB358kKVWNb50Rh4/dKBbXN3lnIUmq2rqa2qIu6fBsUE3zaNncC8OzuYkmjgAAAOB/i4iPFHvEpBUAQEUpeJIF6Pf3Xj86DpSDLjsyAAAAAAAAAAAAQHUz3w6YbwcAAIBB9PGm3McySe4HLmqQ1M+ezGTzp9W2dq5nB4X/lknyh9sfhq4rGppdNLYG3V1XH0myrbUkSVIJG7vZLvGnx582ilFC+x1+orW2ih1y9Cnx1sqVFs8geeSxp6Jhwx2sPaWmli33iW9dcG10dfdIg9q3L7w+jpp3cez+mVNi8+0/G/Ub7uhvUpKUioZnc7H9+CmxYHRLLPPuQpJUhf2sYVxMbJnuuaCaSnLPZlrziakjAAAA+G8RcZxJKwCAilPwJAvQ7++9fnQcKAdv/48qx9mVAQAAAAAAAAAAAKqX+XbAfDsAAAAMgZokt0dNNveKyxokrcLFJn/MJLkTa5IZo+2iVLvatvw29oWh6/ix67tkbA07qWmStSRJUgm79JeLjWGU0MU//ZV1tood/fWzore3z+IZRHvOPcHaU2oa3j4rjp63MLq6e6Sy6Cvf+Vnsd+Tpsc1uR0Xz5N39nUqSKr71W6e98+7jtrrR3mFIkqqqW+saIz9+C88DVVQmm39+WFtnu8kjAAAAeOeH19Yp9rJJKwCAilPwNAvQ7+++fnQcKBc/sysDAAAAAAAAAAAAVC/z7YD5dgAAABgi62Y7x2aS3N0ua5C0yiW5GzJtuU+vmxQ+YTelGg3P5jL2gqFrm5atXDC2hi0dVR+TWqdbT5IklaBDj/2W8YsSevzJZ2PsZrtYa/2stq0zvn3OQgtnkP3Hz6+z/pSqdvjUidHV3SOVbSecflnM+eJ3YvruX4xxm+/h71aSVLGNTjri082bxFX1Y73LkCRVz7vruvr4fPOGUetZoIrmzvLP1GQ7WkwfAQAAUO0i4lyTVgAAFangaRag3999/eg4UE62tjMDAAAAAAAAAAAAVCfz7YD5dgAAABhCIydP/odMNn+ayxokrd4lJ7mVxX+vKv67xyeaC//Xrko1Ka77Z+0DQ9PwbC5urGt0wdgadkZjm/UkSdIAt+HMOfHyq68ZvSiRvr6+2O3gL1tr/eyT620Xl/z8WgtnkD3/4svRuuUe1qBSU9s2+8e3f3BddHX3SBXTid9dFAcfd07M2PPYGDt5d3/LkqSKq7ZYbsKWcX5jEsu8z5AkVUnnFc+9xqTDs0DVlHu6tj0/wfQRAAAA1SoixhVbadoKAKAiFTzRAvT7+68fHQfKyR3FPmB3BgAAAAAAAAAAAKg+5tsB8+0AAABQBmrbcrMy2fzzLmuQtLplktzrxX9/VNxLOtaaPPnv7KykXSbJX+9vf+j6VlO7i8XWsLcv4tx8wjbWkyRJA9TIibPjtrvuN3ZRQj/48SJrrZ81bbxTXPvr2y2aIXDosd+yBpWaRkyaHV867T+iq7tHqui+8p2fxX5Hnh5b7nRENGy4k79vSVJFNal1enx9zKS4Y1SDdxuSpNT3y4bmmNgy3TNA1ZR7urY9P8EEEgAAANUoIn5q0goAoGIVPNEC9Pv7rx8dB8rNTnZnAAAAAAAAAAAAgOpjvh0w3w4AAABlYp2WjlGZbO5mlzVIWtMySe7xTJI/ZVj7zDa7K2lVk+S7/L0PXTuOm+JSsQHowsZW60mSpAHqtHN+ZNyihB557Klo2ngna60ftW29d9x7/0MWzRC4/sY7orat0zpUatr10G9GV3ePlKrmL1gcx556Sex+2Kmx2XaHxaj1t/f3LkmqiBqTjjikeZO4rn6M9xuSpFR3a11j5CZs6fyvmnJPDW/tGGcKCQAAgGoSEesV6zNtBQBQsQqeagH6/R3Yj44D5eaBYh+yQwMAAAAAAAAAAABUF/PtgPl2AAAAKCPt7XM+VJPNfbMmm+9zYYOkAWppTdJx1LD2mSPssqRJbZLfz9/30FWXdMRddQ0uFRuAOlxIJknSGjd73y/Gyt5e4xYl0tvbF9vvf7S11o+2KBwSjz35jEUzBF5f/kZs1HGAdajUtN6Mg+LbCxZHV3ePlOq+feH1ceQ3fhg7fvrEd9b98LZOe4Akqawbns3F9uOnxILRLbHMOw5JUkpbWlcfh4/dyNlfPT25bpJrNokEAABAtYiIa0xbAQBUtIKnWoB+fwf2o+NAOTrADg0AAAAAAAAAAABQXcy3A+bbAQAAoAzVJPlta7K5p13YIGngyvVmsrnrapP8fiNb8/9kp6XSZVpyWX/XQ9v5o1tdKDYA/bRhXNRaT5IkrXZjN9slHn3iaWMWJXTOgsustX604wHHxsuvvGbBDJGvfOt861Cp6ZPrbR8nnH5ZdHX3SFXXvPOujkO+fG7M3Pu4GDdlT3uCJKms26xl65g3ZmLcVdfgfYckKZWd0dgWdUmHc786enLdJNdsGgkAAIC0i4hpJq0AACpewZMtQL+/B/vRcaAcPV7s/9ilAQAAAAAAAAAAAKqH+XbAfDsAAACUqdrWGTWZbO46FzZIGugySX55JptfOCzpyDc3F/7ejkslenvtFtfxG/6mh645zZu6SGyA2nn85taUJEmr2WVXLjFiUUK//+Nj0bDhDtba+/S5L8+Pt95aacEMkd/c89sYOXG2tajUtM8RXdHV3SOp2FfOuDz2PWJ+bLHD56NuA88kkqTybFwyIw4fu1Esrm/yzkOSlLoub2iObOu2zvzqmCd7Yt1s51gTSQAAAKRVRKxd7HbTVgAAFa/g6Rag39+F/eg4UK6OsEsDAAAAAAAAAAAAVA/z7YD5dgAAAChnhcIHa7L542uS3EoXN0gqyYUo2dxzNdncGcNaOzYu7jpr23ipJJls/hZ/x0NXczIzlo6qd5HYAHR1/dgYYU1JkrTKHXbcaUYrSqi3ty9m73OUtfY3GtE+K04/7xKLZQi99vry2CR/kPWo1DR5u8Ni/oLF0dXdI+kv+nbxb+Oob14cO376pJi47QFR29Zp35AklVUjs7nYffzk+EnDeO8+JEmp6ob6pthqwlbO+2qYI0vyTwxrnznGRBIAAABpFBE7mrYCAEiFgqdbgH5/F/aj40C5eqHYP9upAQAAAAAAAAAAAKqD+XbAfDsAAABUgNqkc3Imm3/UxQ2SSlqSeyST5E7MTMg12XmpBDVJ/jv+doe2HzS2uERsgDqweVNrSpKkVWijjgPilVdfN1pRQqefd4m19jdq2ninuPL6WyyUIXbkV79jPSo1jS7uKyd9d1F0dfdI6kcnn3tlHHzcObHNbkdF/YY72kckSWXVlJatY35Teyytq/cORJKUiu4ZVR/7j/NOu0p6ct0k12wqCQAAgDSJiA8Wu9+0FQBAKhQ84QL0+/uwHx0Hytm/26kBAAAAAAAAAAAAqoP5dsB8OwAAAFSIYe0z/zWTzf/MpQ2SBqmlxb7wb+M71rEDU65qk/x+/laHtn3GbeYCsQHqprrGaExmWleSJPWjkRNnx+13u9+ilB546E9Rt37BenuPNuo4IH774MMWyhC77oY7orat05pUajr0hPOjq7tH0mr07QWL4+hTfxw7HXxSrLftAc4HSVLZNLFlenx9zKS4s67BuxBJUiqaN2ZijHDGV0NPrpvkmk0mAQAAkBYRsZtpKwCA1Ch4wgXo9/dhPzoOlLOXiv2L3RoAAAAAAAAAAAAg/cy3A+bbAQAAoLKsXZPkDs1kcytc3CBpUEpyK4v/XlX8d49PNBf+r22YcpJpyWX9nQ5tjUlH3F1X7/KwAeq4MetbV5Ik9aP55y40TlFCb61cGdvu9jlr7T2atfeR8ezzL1koQ+y5F16K7FZ7WZNKTR17fym6unskrWFnXvzreOq5V+LpZ1+IhZdfEwcccXKM2WRn+4wkqQzep8yMQ5o3iSX1jd6HSJIqvgtHt0ZT8Wxzxqe+J9fNdo41nQQAAECli4gPFltm4goAIDUKnnIB+v2d2I+OA+Xuy3ZrAAAAAAAAAAAAgPQz3w6YbwcAAIAKNDybm5hJcg+6uEHSYFbcd14v/vujTDbfsdbkyX9nN2aotbfP+VAmyS/39zm0ndOYuDhsgLq7rj7aWqdbV5Ik/Y1m7/vFWNnba5SihOadeZG19h59/oTT4623VlokZeCAI062JpWaxk/ZK045/5ro6u6RtIY98Men/+rMeGvlyrj5jvviq6d9P6Zsd7B9R5I0pI3M5mLvcZNjUX2z9yKSpIruV/VjYoPWac731M+K5Z9YN9s51oQSAAAAlSwidjVtBQCQKgVPuQD9/k7sR8eBcvdSsX+2YwMAAAAAAAAAAACkm/l2wHw7AAAAVKi69sI/ZrL5hS5vkDQkl6Zk84/WZHPfqMl2tNiRGUqZbO5mf5ND2+7jNndp2AB2RmObdSVJ0ns0Ycru8cRTzxqjKKF7738oRk6abb39RaPW3z5+8ONFFkiZ+NFlv7IulZqGt8+KY05ZGF3dPZLWsFvvfaRf58jv//hYfHfBZbHzQce9c8bbiyRJQ9W0CVPj/MYklnk3Ikmq0G6ta4wZxfPMuZ72GbHcn9Zp6RhlQgkAAIBKFBEfLLbMxBUAQKoUPOkC9Pt7sR8dByrB8XZsAAAAAAAAAAAAgHQz3w6YbwcAAIAKV5Pk9qhJ8q+5wEHSELa02PEuUGFIzsFs7gx/g0NbXdIRd4xqcGnYAPX25Zlbt2xlbUmS9BfVtnXGomtvMj5RQm+++VZM3eFQ6+0vmjhtn7j97vstkDLxyGNPxZhNdrY2lZp2mfuN6OrukbSGLVqyenegvb78jVh8051x7MnfjUnT9rUvSZKGpM1ato75Te2xdFS99ySSpIprabFPjdvEmZ72kvzD67TmP2lKCQAAgEoTEbuYuAIASJ2CJ12Afn8v9qPjQCV4sdg/27UBAAAAAAAAAAAA0st8O2C+HQAAAFKgJtvRUpPkl7nAQdLQluvNJPlfZbK5vf9lvWn/n92ZwTAsye/rb2/oO6Mp68KwAew/Ro+PWutKkqT/1TEnnm10osS+Pv8H1tpftP3+R8fTz75gcZSJ3t6+mL3vF61NpaYNZn4qvr1gcXR190hag3585V2xsrd3QM6ae+9/KOafuzDye30hhrd32qskSYPa+NYZcdTYDeK2utHelUiSKq55YybGCOd5qstk8w+MaJ81zKQSAAAAlSIiPlDsHlNXAACpU/C0C9Dv78Z+dByoFMfbtQEAAAAAAAAAAADSy3w7YL4dAAAAUqJ2g8JHMtn8aS5wkFQWF6kk+eU1Se7yYoXm5sLf26UplUxrPvE3N/RtP36Ki8IGuJ3Gb25tSZL057YoHBLL31hhbKKE7rrvwRg5abb19udq2zrjq6d9P1b29locZeT08y6xPpWaRq2/fZxwxmXR1d0jaQ36/k9vjdeXv1mSc+e5F16KhZdfE3vOPeGdv1l7lyRpsGpMOuIzzRvH4vom70skSRXV+aNb3znHnOep7v6Rk7Zd17QSAAAAlSAidjJxBQCQSgVPuwD9/m7sR8eBSvFisX+0cwMAAAAAAAAAAACkk/l2wHw7AAAApExNkts+k+RedIGDpHIpk80/X9yXzhrW3rlJcZta207NQGpvn/Oh4vp63d/a0Dai2A0udxzQrqkfE5/M5qwvSVLVV7d+IZb97o9GJkpoxYo3Y8r2h1hvf27MJjvHz6++wcIoM7998OF39gNrVGnpoGPOiq7uHklr0Hd/fGM89+Jrg3IOvb78jbjy+lti7jGnvvOsYB+TJA3Ou5dc7D1uclxRP9Z7E0lSxbSovjkmtk53lqd5DizJ35WZ1PlxE0sAAACUu4i43dQVAEAqFTztAvT7u7EfHQcqyZF2bgAAAAAAAAAAAIB0Mt8OmG8HAACAFMq0dDbWZPO/cYmDpLIryT+cSXIn1iQzRtutGbBzL5u72d/X0Hf82PVdEjbAfa55I2tLklT1LbjkCqMSJfbled+z1v7cNjsfFn945HGLosysWPFmTN3hUGtUqWn67kdHV3ePpDXojB8uiUeeeGFIzqU3VqyIxTfdGcee/N1Ipu5lX5MklbzaYoXxU+KShvHenUiSKqKb6hpj2oSpzvF095sRE2b8s4klAAAAylVETDd1BQCQWgVPvAD9/n7sR8eBSvJksY/YvQEAAAAAAAAAAADSx3w7YL4dAAAAUqqhYdqHa5L8fBc4SCrT+mqS3A2ZJP+pzKTOj9u1WRPF867L39TQt37rtFjmgrAB7a66hsi2bmt9SZKqtjmfP8mYRIndeueyGNE+ywXlbZ1x7MnfjRUr3rQoytAJp55nT1Rqatlynzj1+9dEV3ePpDXo/oeeKoszamVvb9x4271x3DfOiQ1m7G+fkySVvGkTpsb5jYn3MZKksu+eUfWx57jNnN/pbsk6LVt91NQSAAAA5Sgirjd1BQCQWgVPvAD9/n7sR8eBSnOQ3RsAAAAAAAAAAAAgfcy3A+bbAQAAIOWGJR35TDb3nEscJJVtSW5l8d+riv/u4bIVVkdtkt/F31J5tHD0BBeEDXCnN7ZZW5KkqmzitH3ihRdfMSJRQq+9vjw2yR9U9Wtt/Oa7xZXX32JBlKmbfrM0RrTPsi8qFY2YNDuOPfWS6OrukbQG3XrPI2V7bv32wYdj3pkXxfRdPmvfkySVtE1aton5Te2x1HsUSVIZt6zYUWM3cHane+arx6wXAAAA5SYi1jd1BQCQagVPvQD9/o7sR8eBSvNQsb+zgwMAAAAAAAAAAACki/l2wHw7AAAAVIF1s7NH1mRzv3aRg6RyL5PkXqxJ8ufWtOY3X2ut4z5gB6c/1mnNf9LfT3m0z7jNXA5WgovGpk+Yan1JkqqqkRNnx8133Gc8osSO+tp3qn6tbbffF+PxJ5+1GMrUy6+8Futvu599Ualp789/O7q6eyStQb+66YGKOcf+8Mjjccb5/xH5vb4Qw9s77YOSpJLU1jo9vj5mUtxV1+CdiiSpbDutqT1GZnPO7tTOeuV/2dAw7cOmlwAAACgXEfFTk1cAAKlW8NQL0O/vyH50HKhEO9vBAQAAAAAAAAAAANLFfDtgvh0AAACqxeTJf1eTzR9fk831usxBUkVcupLNP1rstGHtM9ts4ryft9eLv5uhrz7piNtd3DjgXd7QHCMSl4xJkqqnU876obGIEltyy11R29ZZtWtseHtnHHvyd+Ott1ZaDGXs01+cZ09Uapq8/WExf8Hi6OrukbSaXXr13bGyt68iz7TnXngpFl5+Tew594QYtf729kVJ0oDXnMyMo8ZuELfWNXqvIkkqyy4aPSGaiueVczu1/aS9fc6HTC8BAAAw1CJibLFek1cAAKlW8OQL0O/vyX50HKhEdxVb2y4OAAAAAAAAAAAAkB7m2wHz7QAAAFBlhrV2bl2TzT/pIgdJlVXujkw299nh2VzGTs67ySS5H/s7KY/mNU10KVgJmtO8qfUlSaqKZu/7xVjZ606LUnr51ddiven7Ve0a23DmnLjp9nsthDJ30U+usicqNY3dbLf45rlXRVd3j6TVrPvnt8cbK95Kx7PYK6/Fpb+4Pvb97Ndi1Prb2yclSQNaQ7YjDmneJBbXN3m3Ikkqu35VPybWa53uzE5rSe7itQqFD5pgAgAAYChFxPkmrwAAUq/gyReg39+T/eg4UKmm28UBAAAAAAAAAAAA0sN8O2C+HQAAAKrQOi2z/i2T5H/pMgdJlVeut/jvkpq2zjkfb8p9zI7Of8pkc5/191EeTZ2wlQvBStBNdY3RlMy0xiRJqa558q7xp8efNg5RYocfP79q19jcY06NV1593SIocw89/Fg0bbyTfVGpaHhbZ3z+xAXR1d0jaTU779Kb45XX3kjlmff68jfi8iuXxJ5zT4hPrredfVOSNGCNzOZiv3GbxZUNY71jkSSVVTfWNcaWLVs5r1NaJpv//lprHfcBU0wAAAAMhYjIFFth+goAIPUKnn4B+v1d2Y+OA5XqKrs4AAAAAAAAAAAAQHqYbwfMtwMAAED1WrsmyR2aSXJvutBBUkVexJLklxf3scuLFdrb53zItl7dMtnODf1dlE+Xj252IVgJOnHMJOtLkpTqfnnNTUYhSuy6G+6I2rbOqltbrVvuEYuutb4qwYoVb8Y2Ox9mT1Rq2vmQk6Oru0fSanb2whvimRderYoz8MWXXomFl18Te849IUZOmm0PlSQNSMOzudh+/JS4rGGc9yySpLLp7rr62H3c5s7qtJbk55tiAgAAYChExFdMXwEAVIWCp1+Afn9X9qPjQCVrtZMDAAAAAAAAAAAApIP5dsB8OwAAAFS5Ye2dm9QkuUdc6CCpwnsyk81/qzaZOcnOXp0aGqZ9OJPkl/tbKI/2HjfZZWAlaGldfWzeso01JklKZUd97TtGIErspZdfjYnT9qm6tTXn8yfFcy+8ZAFUiGNOOtueqNS0Uf6QmL9gcXR190hajb7zwyXxyBMvVOV5+PSzL8R5F/88Zu9zVAxv77SnSpIGpNyELePS0eO9b5EklUXLih01dgNndGrL/btJJgAAAAZTRHyk2DOmrwAAqkLBEzBAv78v+9FxoJKdaycHAAAAAAAAAAAASAfz7YD5dgAAAGCtuvbCP9Zk8z9ymYOkVJTklxX/Pb4229Fgh68uxc99ib+B8uiT2VzcWN/oMrAS9NOGcTG8+N/XOpMkpakp2x8Sy99YYQSixA4++pSqWlfjNt81Lv3F9T74CvKrntuitq3TvqhU1LjJLnHi2b+Mru4eSavR6Rf1xO8edt/Z25546tk4Z8Fl0bn3kc5JSdKA1Dl+y1g4eoJ3LpKksuikpkkxIvH+O40Ny+aPMMkEAADAYImIOd4uAwBUjYInYIB+f1/2o+NAJXuj2Dp2cwAAAAAAAAAAAIDKZ74dMN8OAAAA/Jeats45mWz+DZc6SEpNSe62YoeumxQ+YZevgnMsmz/Zui+fvjh2A5eAlag5zZtaY5Kk1FS3fiHue+APxh9KbNG1N1XVutpz7gnxxFPP+uAryNuf14Qpu9sXlYqGt3XG575+YXR190haze68/zGH47t49Imn45wFl0Xn3kfabyVJa9y0CVPj/MbEexdJ0pB3bmNr1CUdzuf01ZfJ5g40zQQAAMBgiIi7vFEGAKgaBU/AAP3+vuxHx4FK9yW7OQAAAAAAAAAAAEDlM98OmG8HAAAA/pdh7TPbMtn8Ay51kJSmivvaGzVJ7vJiexT3uf9jt0+n2rbcLOu9fJrQum3cO6reJWAl6La60TE+mWGdSZJS0QULf2nsocSee+GlSKbuWRXrKZm6V/z86ht86BWmt7cvdphzrD1RqWnXQ78ZXd09klazG+/8g8OxHx557Kk4Z8FlMW3nz9p7JUlr1OYt28RZjdlY5v2LJGkIu3T0+BjnHXgKy/XWJvldTDQBAABQShGxtTfIAABVpeApGKDf35n96DhQ6Z4q9g92dAAAAAAAAAAAAIDKZr4dMN8OAAAA/JWPN+U+lsnmL3Spg6Q0lklyLxa7oNjU4pa3tl0/PdZpmfVv1nh5dXpjmwvAStRpTe3WmCSp4tv3s1838jAI5nz+pNSvpdq2zph7zKnxwouv+MAr0Cln/dCeqNQ0efvDYv6CxdHV3SNpNbrqxt86GFfDbx98OOadeVFsNutT9mJJ0mq3acs2Mb+pPZbW1XsPI0kakq6pHxOTa+s13AAAIABJREFUWqc7l9NWkltZbHtTTQAAAJRKRPzCW2MAgKpS8BQM0O/vzH50HEiDPe3oAAAAAAAAAAAAAJXNfDtgvh0AAAB4T7VJfr+aJP+ayx0kpbfcH4r73FfWzXaOteunQybJPWhdl09TWrZ2+VeJWlZsxoSp1pkkqWKbNG3feOHFV4w7lNilv1yc/ku/Ow+Km26/14ddoW6+474YOXG2fVGpaNzmu8c3z70qurp7JK1Gl117b/T29jkc19Bd9z0YX/nW+TFx2j72ZknSarVR67SY39QeS72LkSQNQTfWN74zZ+BMTleZJL88k+SmmmoCAABgoEXE6GJeNAMAVJeCJ2GAfn9v9qPjQBrcbkcHAAAAAAAAAAAAqGzm2wHz7QAAAMDfNKx95phMkr/L5Q6SqqClxb4wctK269r9K1cmyV1gLZdXl44e7/KvEnVF/dgYkc1ZZ5Kkimt4e2f8+pa7jTqU2FPPPB/jNt81teuofoNCzDvzonhjxQofdoV66eVXY4MZ+9sXlYpGTJodx5yyMLq6eyStRguvuDPefGulw3EA9fb2xc133BdHnHB6NG28k71akrTKTWydHl8fMynuGVXvnYwkaVC7Y1RDzBq/hfM4bSX514a15Tc12QQAAMBAiohTvB0GAKg6BU/CAP3+3uxHx4G0WM+uDgAAAAAAAAAAAFC5zLcD5tsBAACA91W7QeEjmWzuuy53kFQdl7jkVhb3vF/UtuZ2Xadlq486BSpL8bM70Dour3Ybt7mLv0rY4WM3ss4kSRXXvDMvMuIwCPb97NdSu4b2nHtCPPLYUz7kCrff4SfaE5Wa9v78/Ojq7pG0GnX//PZYvuItB2MJvfb68lh4+TWx04FfiuHtnfZtSdIqNbF1epzSNDGWjqr3XkaSNGi9fe7sNW4zZ3HKymRzL2Ra84npJgAAAAZCRHyk2HPeCAMAVJ2Cp2GAfn939qPjQFqcZ1cHAAAAAAAAAAAAqFzm2wHz7QAAAEC/ZbK5nWqS/EsueJBUPeVeySS5C4a1dm69VqHwQSdB+Vs32znWui2vRiS5uKp+rIu/StRddQ0xqXW6tSZJqphm7X1krOztNeJQYhf95KpUrp+NOg6Iqxff6gNOge//6Jf2RKWmrXf5QnR190hajc7/yS3xymtvOBgH0eNPPhtd3/txTNnuYHu4JGmVyrZuG18fMynuGVXv/YwkaVBaVuyosRs4h9M3i/VUZkKuyYQTAAAAayoi9vYGGACgKhU8DQP0+7uzHx0H0uL1Yv9iZwcAAAAAAAAAAACoTObbAfPtAAAAwCoZ3t5Zn0nyt7rcQVK1lUlyjxf3v1MyLbms06Csrf32Z2XNllf7jtvMpV8l7OLRE6LWOpMkVUDNk3eNR5942nhDiT325DMxZtOdU7V2Rm+0Y5x69sXxxooVPuAUuP93D0f9BgX7olJR69S945Tzr4mu7h5Jq9i5l9wUL7z0uoNxCN219HdxzElnR8sWu9vTJUn9rq11eswbMzGWej8jSRqkTmmaGCOcwekqyT+cmZgfbsQJAACANRERt3jrCwBQlQqehgH6/d3Zj44DaXKYnR0AAAAAAAAAAACgMplvB8y3AwAAAKusubnw95kkd2pNNt/nkgdJVdrSmqTjqGHtM0c4FcpPTTbXbY2WVyOyubiufowLv0rYvuM2s9YkSWXfz6++wVhDifX19cWun/5yatZMbVtnHHDEyfGnx5/24abEK6++HpNnfdqeqFRUt14hjp//0+jq7pG0ip298MZ45vlXHYxl4q23VsYV190c+3/uxBi1/vb2eElSv5rUOj2+3dQWS72jkSQNQuc0JTEqyTmD01SSu29Y+8x/NeUEAADA6oiIxJteAICqVfBEDNDv789+dBxIk98VW9vuDgAAAAAAAAAAAFB5zLcD5tsBAACA1TYs6diqJpt/0iUPkqq3XG/x3yU1Se5QF72Uj5q2zjnWZvn1qXGbuOyrhN1eNzpaWre11iRJZdtRX/uOkYZBcP7Fv0jNminMOSbuWfZ7H2rKHHL0KfZEpaLats44+Lhzo6u7R9IqdubFv47HnnrRoVimXnr51Vh4+TWx04Ffemevs+dLkt6v9tbpMW/MxFjqXY0kqcT9aHRLNCYznb8pKpPN3TmyNf9PJp0AAABYVRFxjre7AABVq+CJGKDf35/96DiQNlvY3QEAAAAAAAAAAAAqj/l2wHw7AAAAsEZqJsyqzST5613yIKnqL3pJ8ssz2fzCYUlHvrm58PdOiCE8m5IZo63J8uuT2Vz8ur7JZV8l7MymNmtNklSWbVmYG8vfWGGcocQefvTJaNx4x4pfL5t2HhSLrr3JB5pC37voZ/ZEpaadDj4purp7JK1iZ/xwSfzh0eccihXioYcfi2+csSA2mLG/vV+S9L5NbJ0e88ZMjKXe10iSStii+uZoad3W2ZuueatfNTRM+7BpJwAAAPorIv6p2Kve6AIAVK2Cp2KAfn+H9qPjQNostLsDAAAAAAAAAAAAVB7z7YD5dgAAAGDNFQofrMnmj69Jcitd9CBJ+chkcy9kktwFxaYWd8m1HRSDrybJP2wtll+fad7IRV8lbsfxU6w1SVJZ1bDhDvHb3z9ilKHEenv7Yrv9vljZl29P2yfOWXBZvPnmWz7QFLrjngfik+ttZ19UKtq8cHjMX7A4urp7JK1Cp1/UE7/949MOxQp1130PxrEnfzfGb76bs0CS9Le/37dMj3ljJsbSunrvbSRJJena+jExqXW6czdNJfmfrjV58t+ZdgIAAKA/IuIgb3ABAKpawVMxQL+/Q/vRcSBtVhT7hB0eAAAAAAAAAAAAoLKYbwfMtwMAAAADpqY1v3kmm3/URQ+S9N9lktzvi/9+OdPS2eikGDzF/+4XWH/lV33SETfVNbroq4TdUN8UTclM602SVDZ1X3qVMYZBcPaFP63YNTJhyu5x+nmXxPI3VvggU+r5F1+O9abvZ09UKmqdunfMO//q6OrukbSK3fu7JxyKKfD2M9ulv1wcOx90XAxv73Q2SJLes41aton5Te2xtK7e+xtJ0oB3Y31jbNaytTM3TSX5c9daa621TTwBAADwfiLiFm9uAQCqWsFTMUC/v0P70XEgjQ6zwwMAAAAAAAAAAABUFvPtgPl2AAAAYEANa5/5rzVJ7nIXPUjSX5dJ8jfVZvOHrJsUPuHEKK1MNre3NVeeHTF2Q5d8lbiTmyZZa5KksujTR33T+MIgePAPj0b9BoWKWx9jN9slvvXdi+PV15b7EFOst7cvdv30l+2JSkV1xb3237sui67uHkmr2G+WPepQTKGHH30yTuq6MNq23ts5IUl6zzZumRbzm9pjaV29dziSpAHttrrRMW3CVOdtqsp9w8QTAAAAf0tEjPemFgCg6hU8GQP0+3u0Hx0H0ugeOzwAAAAAAAAAAABAZTHfDphvBwAAAEph7Zokd2gmm3/DRQ+S9C4luZXFf68q/rvHOi1bfdSxMfCGtc8cYa2VZw3ZjrixvtElXyVsWbH8hC2sN0nSkLZRxwHx8quvGV8osd7evpi195EVtTbGb75bzDvzonjxpVd8gFXglLN+aE9UKqpt64zPfOX70dXdI2kVu/XeRxyIVfBMuvimO+OAI06OkRNnOzckSe/aJi3bxLmNrd7jSJIGtLvqGmI778bTNlN1pKknAAAA3svb40je0AIAVL2CJ2OAfn+P9qPjQFpNsssDAAAAAAAAAAAAVA7z7YD5dgAAAKBkhrXPbMtk8w+47EGS3rtMknux2AXFpq611nEfcHoMnJps7g/WWHn26eZNXPBV4q6rHxOjkw7rTZI0JI2cNDtuv/t+YwuDYP65CytmXbRssXvMO/OiePmV13xwVWLJLXfFiPZZ9kWlol3mfjO6unskrWI33PkHB2KVeeqZ5+P08y6JDWfOcX5Ikt61LVu2ivMbE+9yJEkD1tK6+thv3GbO2fTUV9PWOcfUEwAAAH8pIj5U7GlvZQEAql7B0zFAv79L+9FxIK3OsMsDAAAAAAAAAAAAVA7z7YD5dgAAAKCkPt6U+1gmyf3AZQ+S9P5lsrk/ZbL502qSWa1OkDVXk+S/Z12VZyOyubimfowLvkrcN8ZMtN4kSUPSWT/4iZGFQXD/7x6OUetvX/brYYMZ+8f3LvpZLH9jhQ+tijz97PORTN3LnqhUNGWHw2P+gsXR1d0jaRW67tYHHYhVrLe3LxbfdGcccMTJ8cn1tnOeSJL+qmkTpsaPRk/wPkeSNCAtK3ZY80bO2NSU681k8zuafAIAAOB/iojZ3sQCAFBU8HQM0O/v0n50HEirF4v9Hzs9AAAAAAAAAAAAQGUw3w6YbwcAAAAGRaY1v1dNNv+qCx8kqX9lsvlbapLc3HWTwiecIqun+N9xd2upfNt9/GSXew3CxWGd47e03iRJg3vGH/Lv0dfXZ2ShxN5auTKm73p4eV+OvfNnY+Hl17zz/ytVtj7fWhmdex9pT1Qqattm/zjl/Guiq7tH0ip09U0POBD5L88892Kccf5/xKadBzlbJEl/VWH8lPhlQ7P3OpKkAenYsRs4X1MzN5VbMSzp2Mr0EwAAAP8pIi739hUAgKKCp2OAfn+X9qPjQJrtYqcHAAAAAAAAAAAAqAzm2wHz7QAAAMCgyUzINdVkc3e49EGSVqEkt7L471XFf/dYp2WrjzpN+m94Npexhsq32mKXj3ZJYqlbUt8YTclMa06SNCglU/eMp599wajCIPjmd7rLcg0Mb++MPeeeEItvutOHVMWO/+a59kSloqZNdomvnfWL6OrukbQKXbFkWfT29TkQeVd33fdgHHHC6dGw4Q7OGknS/3pntMv4zePq+rHe7UiS1riTmybF8GzOGZuKman8a5ls54YmoAAAAIiIdYu95Y0rAABFBU/IAP3+Pu1Hx4E0u9JODwAAAAAAAAAAAFAZzLcD5tsBAACAQdXQMO3DmWz+tJpsvs/FD5K0amWS3IvFLig2tbilru1UeX+ZJP87a6d8y4/fwqVeg9ApTROtN0lSyRve3hk9N99lTGEQ3LPs9zFy0uyy+vzHbLpzHHHC6fHAQ3/yAVW5K667OWrbOu2LqvhGTtoujp63MLq6eyStQouWLIvevj4HIu/r5VdeiwsvuSK23ukzzh1J0n81otje4ybHtfVjvN+RJK1Rpze2vXOuOF9TUJJ/JjMh12QCCgAAoLpFxKHesgIA8GcFT8gA/f4+7UfHgTTrLVZjtwcAAAAAAAAAAAAof+bbAfPtAAAAwJAY1prvzGRzz7n4QZJW99KY3B9rkvxXhrXPHONUeW+ZJHem9VLedY9ucanXIDRr/BbWmySppH3jjAVGFAbBihVvxpaFuWXzuU/f5bNx4SVXxOvL3/DhEA89/FiM2XRne6Iqvtq2zpj75e9FV3ePpFVo0ZJl0dvX50Bkld1+9/3xuS/Pj8aNd3QOSZLeaWQ2F3OaN40b6xu945EkrXbfa0xiVJJztqagTJL7/chJ265rCgoAAKB6RcQt3qwCAPBnBU/IAP3+Pu1Hx4G0+4zdHgAAAAAAAAAAAKD8mW8HzLcDAAAAQ2ZY+8wRNUmux8UPkrSGl8dk87cU99O56yaFTzhd/uKsac13WiPl3RYtW8cyF3qVvJ66pmhKZlpzkqSSNHufo2Jlb6/xhEHw1dO+P+Sf97jNd41jTjw77l72oA+E//Lqa8tjy8Jce6JS0W6fOSW6unskrUJX3nB/9PX1ORBZI6+8+npceMkVMX3Xw51HkqR3qk864vCxG8VtdaO965EkrVYXNLZGXfE8ca6modwdde2FfzQJBQAAUH0ioqGYF9IAAPyngqdkgH5/p/aj40Da3WK3BwAAAAAAAAAAACh/5tsB8+0AAADA0CoUPliTzR9fk+RWuvhBktaw/38vvar47x7rtGz1UYfMWmt9vCn3sUySe9P6KO++3dTmQq9B6PTGNutNkjTgNU/eNf70+NNGEwbB7XffHyPaZw3J5zy8vTN2OvBLsfDya+L15W/4MPhf+vr64sAjTrYnKhVN3/2L0dXdI2kVWrRkWfT2ub+MgXXXfQ/GESecHg0b7uB8kiTFmGRGHDV2g/jNqAbveyRJq9yPRk+IxqTDmZqCMtnctSMnT/4H01AAAADVJSKO9wYVAID/oeApGaDf36n96DhQDRrt+AAAAAAAAAAAAADlzXw7YL4dAAAAKAs1rfnNM9n8oy5/kKQBukgmyb1Y7IJiU4vb7NrVfMZkkvz11kR5Nz6ZEbfVjXah1yC0+/jJ1pwkacCqbeuMRdfeZCRhELyxYkVM2e7gQf+M3/6/efp5l8RTzzzvQ+A9ffuchfZEpaINOj4dp11wXXR190jqZ4uWLIvevj6HISXz0suvxjkLLosNZuzvrJIkxYTWbeMbYybGUu97JEmr2E8bxsXY1pnO03T0k7UKhQ+auAUAAKgeEXG/N6cAAPwPBU/JAP3+Tu1Hx4FqcJwdHwAAAAAAAAAAAKC8mW8HzLcDAAAAZWNY+8x/zWTzP3PxgyQNbJls7k/F/fW0mmRWazWeLzVJ/ovWQfl3SPMmLvMahG6vGx1trdOtOUnSgPSlb5xjHGGwph6K/60H4zOtbeuMbXf7XMw/d2E8/OiT/sPzvq674Y4Y0T7LnqiKb9yUPePkc6+Mru4eSf1s0ZJl0dvX5zBkUPT29sXim+6MPeee8M4zq7NLkqq79VunxVmN2VjmvY8kaRW6oqE5WltnOEvTMAeV5M40bQsAAFAdImKSt6UAAPyFgidlgH5/r/aj40A1+J0dHwAAAAAAAAAAAKC8mW8HzLcDAAAA5WbtTJI/PJPNrXABhCSV4GKZbP6W2mz+kHWTwieq5WDJtOSyPvvyb0SSi583jHOZ1yD0o9ET3vnvbd1JktakbXY+LFaseNM4wiC45Y77Ynh7Z8k+y7r1C7HTgV+KcxZcFk889az/4PTbQw8/FmM328WeqFR07Lcuia7uHkn9bNGSZdHb1+cwZGgmgv/wpzjmxLNjzCY7O8MkqcrbsmWruHj0BO9+JEn97tr6MTGxZbpzNA3zT0n+WKO2AAAA6RcR3/KGFACAv1DwpAzQ7+/VfnQcqBYT7foAAAAAAAAAAAAA5ct8O2C+HQAAAChLw9o62zNJ/ncugJCkEpXkVhb/var47x7rtGz10ZQfK2tnktzjPvfyb9qEqbHMRV6D0mebN7bmJEmr3eiNdnznIntK77XXl8fGuQMH/DNs2WL3mHvMqXH5lUvilVdf9x+aVfbqa8tji8Ih9kSlpv2POiO6unsk9aNFS5ZFb1+fw5Ah9/Zz7IWXXBFbFuY6yySpyiuMnxKLGsZ6/yNJ6leL65ti/dZpztAUVJvNH2LSFgAAIL0i4gPFHvNmFACAv1DwtAzQ7+/WfnQcqBbftOsDAAAAAAAAAAAAlC/z7YD5dgAAAKBsfbwp97FMNn+hCyAkqbRlktyLxS4oNrW4/a6dxjOleJ5832ddGZ3R2OYir0HonlH1Mblla2tOkrRa/fhn1xpBGCRHfvU7A/KZtWyxe+x3+IlxzoLL4p5lv4++vj7/cVltb6+fA4442X6oVDVx+oHR1d0j6X1atGRZ9HqOoAzdfMd97zyfjJw427kmSVXa8Gwudhm/eVxXP8Z7IEnS+3ZjXWNs0rKNM7TSS3Iri/9uZ9IWAAAgnSJiY29CAQB4FwVPywD9/m7tR8eBavGHYmvb+QEAAAAAAAAAAADKk/l2wHw7AAAAUPYy2dw+Ndn8qy6CkKRBuXDmjzVJ/ivD2meOSdNZMizp3NnnWxmNb50Rt9eNdpHXIHRFQ3PUJR3WnSRplTr02G8ZPxgk1994R9S2da7W5zRp2r5x8NGnxA9+vCh++/tHoq+vz39QBsypZ19sP1QqO/rUH0dXd4+k9+iKX9/vmYKy99iTz8SJXT+I1i33cLZJUpX29nuPw8duFLd51yRJep9uqmuMTVu2cX5WeJkkv3xYW35TU7YAAADpExGneAMKAMC7KHhaBuj3d2s/Og5Uk4l2fgAAAAAAAAAAAIDyZL4dMN8OAAAAVIRh7TPH1GRzd7gIQpIGtaXFvvBv4zvWScE58q/Fc6TXZ1oZfaZ5Y5d4DVInjplkzUmS+t3GuQPjlVdfN3owCF5+5bVYb/p+7/uZjGifFRvOnBN7zj0h5p15UVx5/S3x9LMv+A9IyVx3w2/eWXf2RKWxGXseG13dPZLepUVLlkVvX5+DkIrx5ptvxeVXLomdDvySM06SqrQxyYw4fuz6cXddvfdBkqT37La60bFFy9bOzgovk+RerMl2tJiyBQAASI+IWLvYH735BADgXRQ8MQP0+/u1Hx0HqsnX7fwAAAAAAAAAAAAA5cl8O2C+HQAAAKgYIydP/odMNn9aTTbf5zIISRrEktzK4r9XFf/dY52WrT5aqedIJpu72edZGQ3P5uKShvEu8RqElhXbYfwW1p0k6X0btf72cc+y3xs7GCSHHXfaO//dGzfeMTbOHRj5vb4Q+xz2tTjuG+fE9y76WVy9+NZ44KE/xYoVb/qPxaD5/R8fizGb7mxPVKrPunnnXx1d3T36f+zdeZScdZ3of5jxd5253nHuz7kjUt1JSC9JuumlKguEsIRAAklIqjqBYhHZBEF0IDg6AbyAKDI4KEKkIzDAIAodFSJIUIEoSDpA2AMkRDZlB5ElECBk6f7cJo4zKCSpJN3V9VS9Xue8T878o051nefzPPX9nucrvacbFi6Lru5ug5DEenDZ4zHzjNlRt9P+5p0kVWCZ1slxzrCRsbSm1rqQJOkDu6emPsY3TzA3E14qk3s2NTI3wC5bAACA8hARo6x0AgCwHnl3zAAFP1976ThQSR515QcAAAAAAAAAAAAoTfa3A/a3AwAAAIlTlZk6PZXJveowCEnqh0No0tnlVZnsJdWZ7G49l+StkzU/cl/1N0xOO7VMjAcdcFi0Q8KGt07yvZMkbbD/mHO9LQdF9M6qVT4ESsobb74VY6d93vVQZd+RM8+P9o5OSf/ZTbf9Jrq6uw1CysIrr70esy+bGztOPsrMk6QKbEzrxLhoSMa6kCTpA7u3pj72aplgZiZ9T1Mmu/hjO0z8qB22AAAAyRcR37DCCQDAeuTdMQMU/HztpeNApWl19QcAAAAAAAAAAAAoPfa3A/a3AwAAAIn0icz0QVWZ7G0Og5CkfiydfbIqnfv6tiOmDEvC7Eilc2P83ZLVzIadHOBVpK6pb4qBmazvnSTpAzvyn/81uru7bTeACtXV1R1HnHCm66EqouF7fybaOzol9XTLXY+FW0DK0Zq1a+OnN3bG5E99yeyTpAos27xnzKtrtDYkSXpf9w2ui0nN483L5De/sTH/P+ywBQAASLaI+I2VTQAA1iPvjhmg4OdrLx0HKs3XXP0BAAAAAAAAAAAASo/97YD97QAAAEByjR37oVQme2ZVJtvlMAhJ6t9Smdxd1ZnccZ9I5/+xZOdGPv/XPf87X/X3Sk4De7qubnsHeBWpUxtG+95Jkt7XjpOPiuWvr7DVACrYty7ocD1URfXlc34c7R2dUkW34J4nDEAqwqL7lsaR//yvMWBEmxkoSRVUdU+fbNo9bq0dZn1IkvRnPVBTF9nmPc3LpO9hSmd/sNVWW21tgy0AAEAyRUSLlUwAADYg764ZoOBnbC8dByrNUld/AAAAAAAAAAAAgNJjfztgfzsAAACQeFWt2XGpdO45B0JIUgmUzq7t+Xd+z7+HbtMy4SMlNzMyuR/7OyWrXVv2jiWDax3gVYQe7vmcHRAmSXpvg0ZOj7sXL7PNACrYvJsWRvXwNtdEVVSTDz0l2js6pYrtniVPG4BUnKeefTFOPfviqB9zgFkoSRVUTXpqfLFhTNw3uM46kSTpv3pocG3s1zTOrEx4qUzuLDtrAQAAkikiTrOCCQDABuTdNQMU/IztpeNAJao3AQAAAAAAAAAAAABKi/3tgP3tAAAAQFnYpmXax1Pp3C8cCCFJJXRATTq7vCqTvaQ6k92t51K9dSnMi1R66mH+Nsnryw07ObyrSN1RMySaWyf73kmS1nXB5dfYXgAV7N4HfxM1O+ZdD1VxbbfDfnHOZb+M9o5OqeJa/JvnDEAq2mvLV8T5l14VmQmHm4mSVEG1tE6Oc4aNjKU1tdaKJEnrWjK4Ng5oGmdOJn7fUu5zdtYCAAAkT0TcZeUSAIANyLtrBij4GdtLx4FK9AUTAAAAAAAAAAAAAKC02N8O2N8OAAAAlJOtq9LZGalMdpVDISSpxA6qyWSfSWVys6rS01r7c1CkRrX9Q1U6t8bfJFkN7GlefaPDu4rUD+ubY2A667snSRXeIcd9Lbq7u20vgAr1zPMvRXr8Ya6HqtgO/5dZ0d7RKVVMs+csjIefeNEAhP+0evWamHfTwpj8qS+Zi5JUQe3evHf8uL7FWpEkaV1LBtdGvmmcGZnosl1VmanTbasFAABIjojYticbFwEA2JC8O2eAgp+zvXQcqES/MgEAAAAAAAAAAAAASov97YD97QAAAEDZGZDJjkylc485FEKSSralPZ348aap2/THnOiZEbf6GyTwIMOWveOhwbUO7ypSMxt28r2TpApu5MRPxyuvvW5rAVSoFW++HeP3n+F6qIqudfwR0d7RKVVEF/xwYTz+9B8MQFiPO+9/OA47/oyoHt5mRkpShZRt3jNurG2wXiRJiiWDa2P/pj3MxwSXSmff3rZ16s521QIAACRDRBxlhRIAgI3Iu3MGKPg520vHgUq0uqf/bQoAAAAAAAAAAAAAlA772wH72wEAAICy9LEdJn40lcle6WAISSrh0tm1Pf/O7/n30G1aJnykWDOiZz78s88/mc1o3NnBXUXq4cG1kXM4mCRVZINGTl93aDxQmbq6uuOIE850PZR6OumbP4r2jk6prLvwR7fFU8+/agBCAX771HNx6tkXR+3ovDkpSRXQwEw2jm7cNRbVDLH0Yo3QAAAgAElEQVRuJEkV3pLBtZFvGmc+Jnt/0svbjpgyzK5aAACA0hcRP7UyCQDARuTdOQMU/JztpeNApdrfFAAAAAAAAAAAAAAoHfa3A/a3AwAAAGWtOp07qiqde8vhEJJU2qXS2eVVmewl1Znsbj2X7637cjYMGNFW6zNPZtU9XTqk1cFdRerumiExonWS754kVVjt/3G17QRQwb7yzUtcC6X/bO9PnRztHZ1S2Xbx1XfE8y+9bvjBJnrp5dfiWxd0RMseh5iXklQBDU1PidMbdoyHBtdaO5KkCm5JzxzYr2mc2Zjsfjto1ORP2FELAABQuiLib3t604okAAAbkXf3DFDws7aXjgOV6vumAAAAAAAAAAAAAEDpsL8dsL8dAAAAKHvbjpgyLJXJLnYwhCQlo55r9jOpTG5WVXpaa1/Nhp7//CU+6+QeXrigdqiDu4rUtXVNsV0m67snSRXSwZ//anR1ddtOABWq45r5roXSexo0at/41qXzo72jUyq7Lv3JovjDq84igy2xatXquGrezTFu338yNyWpAtqhdVJcNCRj7UiSKrglg2tjv6Zx5mKSS2fv2aZlwkfsqAUAAChNEbGPVUgAAAqQd/cMUPCztpeOA5XqlZ4+ZBIAAAAAAAAAAAAAlAb72wH72wEAAICKMGjs2L9JZXKzHA4hSYlraU8nfrxp6ja9ORdSmeyZPtvkNql5fCytqXVwV5H6t6GjfO8kqQJKjz8sXnr5VVsJoELdcc+S2G6HfV0Ppb/osC+eF+0dnVJZ9b1r74pXX3/b8INe0t3dHQsWLY7Djj8jqoe3mZ+SVObt0zw+5tU1Wj+SpAptyeDa2LdpnJmY4FKZ3PVb5fN/bUctAABA6YmI71p9BACgAHl3zwAFP2t76ThQyXY2CQAAAAAAAAAAAABKg/3tgP3tAAAAQEWpSmf3S2WyrzkgQpISdqhNOru65xo+LzW8bf9BY8f+zZbOg+rWth18rsnuyw2jHdpVxD69/W6+d5JUxg0cMS3uuGeJLQRQoR773TPROPZg10PpA2odf0Scf+WCaO/olMqi7193dyxfsdLwgz7ywMOPx2e+9I0YMKLNHJWkMm5AJhtHbr9b3F471BqSJFVgD9bURq55DzMx2XuQvmMnLQAAQOmJiCesOAIAUIC8u2eAgp+1vXQcqGRfNQkAAAAAAAAAAAAASoP97YD97QAAAEDF2XbElIFVmdxCB0RIUmIPt1ne0/d7Gt9zWd96M8fB1qlM9hmfZ7IPLJxT3+zQriIeDLZ7y96+e5JUpp138Y9sH4AK9dryFbFL7ljXQmkDnXj2nGjv6JQSX8fP7o03315l+EERPPnMC3Hq2RfH4B33M0slqYyrTU+NkxtGx0ODa60lSVKF9e61f9/mPczDJDc8d4KdtAAAAKUjImqtMgIAUKC8O2iAgp+3vXQcqGR3mAQAAAAAAAAAAAAApcH+dsD+dgAAAKAyjR37oapM7vSqTLbLIRGSlNxSmewzqUxuVlV6WuumjoJUOnuhzzDZZVonx1219Q7tKlK/qh0WQ9JTfPckqczKH31KrO3qsn0AKtCaNWtj/6NPdS2UNtKEg0+K9o5OKdHNnf9ArFy1xvCDInv2hZfi1LMvjrqd9jdTJamMG9U6KS4akrGWJEkV1gM1dZFt3tMsTGzv7hudOt1GWgAAgNIQEcdaXQQAoEB5d9AABT9ve+k4UMnW9vQx0wAAAAAAAAAAAACg/9nfDtjfbn87AAAAVLRt01MnVGVyLzokQpKSXyqTvbM6kzvuE+n8PxYyA6rSbZN8bskv17xHLK2pdWhXkbpsSDoGZLK+e5JUJqXHHx4vvfyarQNQgbq7u+MLX5nlWigV0MBR0+PsS2+K9o5OKZH9fMHDsWZtl+EH/egPryyPs87/QQzb9SCzVZLKuGlNe8T82gbrSZJUQT1QUxdTm/c0B5NaOvdWdWvbDnbRAgAA9L+I+IlVRQAACpR3Bw1Q8PO2l44DlW4/0wAAAAAAAAAAAACg/9nfDmB/OwAAAFS8T6Tz/5jKZH/uoAhJKpdDb7Jre/6d3/Pvodu0TPjI+q7/dXUTP1yVzr3hM0t+JzSOcWBXETu1YbTvnSSVQQNGtMWtd9xvywBUqG9d0OFaKG1Ch5zw7Wjv6JQS14J7nojubnMPSsWKN9+OS668LjITDjdfJalMG5jJxnGNu8S9NfXWlCSpQnqgpi4mN483BxO7xyj3h+rM1Dq7aAEAAPpPRPx1T69aTQQAoEB5d9EABT9ze+k4UOkuMg0AAAAAAAAAAAAA+p/97QD2twMAAAB/tHVVOjsjlcmucliEJJVPqXR2eU/f72n8u9f6v7z4pzK5q3xO5dG5Q0c4sKtILevpkKaxvneSlPC+dUGH7QJQoTqume86KG1i2487LM6/ckG0d3RKiWj2nM64f9mzhh6UqFWrVsdV826OnbOfNWclqUxraJ0SZw0bFUtraq0tSVIFtLimLiY2jzcDk1o6t2xg8z7/vy20AAAA/SMixlhBBABgE+TdRQMU/MztpeNApXvSNAAAAAAAAAAAAADof/a3A9jfDgAAALxHdXrKqFQ6+7jDIiSp/Eplss+kMrlZVelprX+67ldlpn7KZ1MeDU5n49q6Jgd2FakHaupij5a9fPckKaHte9SXY21Xl+0CUIFuXnhvDBo53bVQ2oz+5RtXRntHp1TyXfDD2+LRJ18y9CAB1qxZG1fNuzl2n/55s1aSyrTdm/eOq61fSVJFdG9NfYyzhp7cPUXp3K11dRM/bActAABA8UXEV6wcAgCwCfLuogEKfub20nGAiHoTAQAAAAAAAAAAAKB/2d8OYH87AAAA8Bc+tsPEj1Zlsh0Oi5Cksm5pTyemmrNDU+nsap9HedTcOjkW1g5xYFeRWlA7NJrS+/juSVLCatnjkHjxpVdsE4AK9MDDj8eQnQ9wLZQ2s/EHzoz2jk6ppLv46jviud8vN/QgYbq6uuOmW++KfQ75kpkrSWVYdU+fbNp93bqK9SVJKu/urKmPMa0Tzb+kls7N2Wqrrba2gxYAAKC4IqLTiiEAAJsg7y4aoOBnbi8dB4j4vIkAAAAAAAAAAAAA0L/sbwewvx0AAABYj6pM7phUOvu2AyMkqXzruc6vfjefRfk0oXlCPDS41oFdRWpuXVNsl8n67klSQhowoi1+fft9tghABXrq2RcjPf4w10JpS+boyOnxbxffEO0dnVJJdtk1d8YfXnvT0IOEu+W2e2P6kV82eyWpDKtNT42TG0bHgzXWsSSpnLujZkiMadnb7Ets2a/ZOQsAAFA8EfE/e1pllRAAgE2QdycNUPBzt5eOA0T82EQAAAAAAAAAAAAA6F/2twPY3w4AAABsQHXLtKZUJrfEYRGSJCWnI7Yf67CuIjZr6AjfO0lKSGed/wPbA6ACvbr8jdht2udcB6Ve6OAZ34r2jk6p5Or42b2x4q13DD0oI3fd/3AcevwZUT28zQyWpDJrVOukuGhIxhqTJJVxnTVDY2TP9d7cS2ap1tzhds4CAAAUR0TsaWUQAIBNlHcnDVDwc7eXjgNE/L6nrU0FAAAAAAAAAAAAgP5jfzuA/e0AAADARgwaO/ZvUpncLAdG6L05xFCSSruvDdvRYV1F7PONu/jeSVKJN/XQmbFmzVrbA6DCrHxnVbQdcZLroNRLbb/7oXH+lQuivaNTKpmu/dVDsWr1GkMPytSyx56M4085NwaNnG4WS1KZ1da0Z8yvbbDOJEll2i11wyKdnmzmJbBUOru6avjUPeycBQAA6HsR8TUrggAAbKK8O2mAgp+7vXQc4I+GmQoAAAAAAAAAAAAA/cf+dgD72wEAAIACVWWmTk9lcq86OEJ/ao/8cXHKN/49dskd6/OQpBKruqdZQ0c4rKtILa2pjf2axvnuSVKJtv3uB8czz79kWwBUmK6u7jjqi99wHZR6uX8+8wfR3tEplUTzb38k1vZc74Hy99SzL8bMM2bHwBHTzGNJKqMGZrJxXOMucf/gOutNklSG/ap2WDS3TjbzElgqk30l1dI2xK5ZAACAvhURt1oJBABgE+XdSQMU/NztpeMAf3SMqQAAAAAAAAAAAADQf+xvB7C/HQAAANgE246YMrAqk1vo4Aj9qfT4w+Jnv7w9Hnni6Thz1uU9//fhPhdJKqGDCH8wpMVhXUXqvsF1sVvLXr57klRiVQ9vixt/factAVCBTj37YtdBqQ/aY/9/ifaOTqnfu+OBJw07qEBPPftizDxjdgwcMc1clqQyqrV1nzh/6AjrTZJUhv2irjEa01PMuwSWSmef2HbElP9j1ywAAEDfiIgP97TSCiAAAJso724aoOBnby8dB/ijDlMBAAAAAAAAAAAAoP/Y3w5gfzsAAACwqcaO/VBVJnd6VSbb5fAI/aljZp4dL7/6eqzt6oq77n943YGGQ3c+0GcjSf1cTXpq/KS+yWFdReq22qGRaZ3suydJJdSZsy63HQAq0Ozv/cQ1UOqjBoyYFmdd9PNo7+iU+qXZcxbGQ48+b9hBhXv0t8/E8aecGwN75pL5LEnl07SmPeLm2mHWnCSpzJpX3xhD01PMuiSWzi6oq5v4YZtmAQAAel9EjLXqBwDAZsi7mwYo+NnbS8cB/uh5UwEAAAAAAAAAAACg/9jfDmB/OwAAALCZqofn9q7KZH/v8Aj9qcaxB8cVc2/8r1+c3lm1KuYvuDuOmXl2bLfDvj4jSeqv63N6SsyvbXBYV7EOBKtrjLrMVN89SSqBpn/65Fizdq3tAFBhrvnFgqge3uY6KPVhBx13drR3dEpF76Krbo/fPfuKYQf8l9889tS6dagBI9z/SVK5NCiTjeMad4nFNXXWnSSpzNbRh6X3MeuSWDr3H3bLAgAA9L6IOM1qHwAAmyHvbhqg4GdvLx0H+G91JgMAAAAAAAAAAABA/7C/HcD+dgAAAGALbNMy7eOpdO4XDo/QezvkuK/F8y++/Ge/PC1/fUVcff0tceBnT3OwtST1QyNbJ8XttUMd1lWkvj+kNQb63klSv9a656Hxwu9ftg0AKsyCRYtj8I77uQ5KfVzDbp+K71y5INo7OqWi9b1r74qXXl1h2AEf6JHHn4rjTzk3BoywBiVJZbO21TIpvlffat1JksqoeXWNMSy9jzmXzE60WxYAAKB3RcR8q3wAAGyGvLtpgIKfvb10HOC/HWkyAAAAAAAAAAAAAPQP+9sB7G8HAAAAttzWVensjFQ6u9rhEfpTw3Y9KK6Ye2N0d3e/71eo5198OS7tmBfTjjjJZyVJRWyXlr3jnpp6h3UVqXOGjfS9k6R+6t1D1H99+/22AECFuffB30T9mANcB6Ui9YWvXx7tHZ1SUbr6pgfirZWrDTtgo37z2FNx/CnnrnsuNK8lqTzar2lc/Lp2mLUnSSqT5tU1xrD0PmZc8upOZbIH2ioLAADQOyLir3p63eoeAACbIe+OGqDg528vHQf4b5eYDAAAAAAAAAAAAAD9w/52APvbAQAAgF5SnZ4yKpXOPuEACb23T37u9Hj2hZfW+4vUI088HedcOCfGTD3G5yVJRWhS856xuKbOYV1F6rjGXXzvJKkfevcZA6gsyx57Mrbf/WDXQKmI7Z7/YrR3dEp93q8WPRpru7oNO2CT/Oaxp+KYmWdH9fA2c1uSyqCa9NQ4uWF0PDS41vqTJJVB8+obY1h6HzMuYaXS2berRmR3tFMWAABgy0VEixU9AAA2U94dNUDBz99eOg7w35aYDAAAAAAAAAAAAAD9w/52APvbAQAAgF70sR0mfrQqnZvjEAm9t7qd9o/Zl82Nro0cfPrAw4/Had+8JFr3PNTnJkl92KTmPWNxTZ3DuorQ0praOKBpnO+dJBWx/NGnxNquLsv/UEGefOaFyEw43DVQKnIDhrfFmRf+LNo7OqU+afachXH/smcNOmCLLHvsyThm5tlR3TO3zG9JSn6jWifFD4a0WIOSpDJoXn1jDEvvY74lrFQ6+3xqZG6AnbIAAABbJiKOtpIHAMBmyrujBij4+dtLxwH+27svffrfpgMAAAAAAAAAAABA8dnfDmB/OwAAANAHqtLZQ6vSubccJKH3Nu2Ik+KJJ5/b6K9Ua7u6YsGixTHj1PNiyM4H+OwkqQ+a2Dw+7htc57CuIrRkcG1km/f0vZOkIpQef3i89PKrlv6hgrz40iux05SjXQOlfurAf/q3aO/olHq9i666PX777CsGHdBrHn70d3HMzLOjenibGS5JZdDB24+NhbVDrENJUsL7SX1T1Kanmm0JK5XJLfnYDhM/apcsAADA5ouIS63gAQCwmfLuqAEKfv720nGAPzfBdAAAAAAAAAAAAAAoPvvbAexvBwAAAPrIJ9LZxlQ6+6CDJPTeakfnY/Zlc2NtV1dBv1atfGdVzLtpYRw+4+sxaNR0n6Ek9WITm8fHfYPrHNZVhO6tqYvdW/b2vZOkPmzQyOmx6L6llvyhgryx4q3Y68ATXAOlfmzoLp+M71xxa7R3dEq91vevuzteWf6WQQf0iaWP/C6OmXl2VA9vM8slKeHVpKfGyQ2jY8ngWmtRkpTg5tQ3x3aZrNmWsFKZ7M+3yuf/2i5ZAACAzfPuspWVOwAANlPeHTVAwc/fXjoO8OdOMx0AAAAAAAAAAAAAis/+dgD72wEAAIA+tO2IKf+zKpO9xEES+sumHjozHv3tM5v0y9Vry1fEFXNvjGlHnOSwQ0nqpfZumRD3Da5zWFcRWlQzJHZoneR7J0l91OzL5lruhwry1tsr1/224Pon9X/Hf+2yaO/olHqlufMfiLdXrjbogD5330OPxMGf/6pZLkll0JjWiXFVfbO1KElKcBcPycTAdNZcS1rp3Dl2yAIAAGy6iPj7nrqs2AEAsJny7qoBCn4G99JxgD/3M9MBAAAAAAAAAAAAoPjsbwewvx0AAAAoglQme2BVOve6wyT03gaNmh5nzro8Vq9es8m/Yj37wktxace82OvAE3yWkrSF7d0yIe4bXOewriJ0c+2waGrdx/dOknq5w44/I7q7uy33Q4V493eET37uK65/Uom0674nRHtHp7TF3XznY7G2yz0dUFz3PPCbyB99ipkuSQmvuqcjth8bd9bUW4+SpIT2naHD113PzbVklcpkj7A7FgAAYNNExF5W6QAA2AJ5d9UABT+De+k4wJ97paetTQgAAAAAAAAAAACA4rK/HcD+dgAAAKBIPpGZPqgqk73NYRL6y8bvPyMeXPb4Zv+i9cgTT8c5F86JnaYc7fOUpM1s75YJcd/gOod1FaGf1zXG0PQU3ztJ6qVGTTwyXnntdUv9UCG6urrj2BO/6fonldLh9cPb4usX/CzaOzqlzWr2nIVx79JnDDmgXy1YtDgmffKfzXZJSnhN6X3i/KEjrEdJUkL7xrBR5lnCSqWzq6tac7vbHQsAAFC4iDjF6hwAAFsg764aoOBncC8dB3i/ISYEAAAAAAAAAAAAQHHZ3w5gfzsAAABQTGPHfqgqkzu9KpPtcqiE3tugkdPjzFmXx6pVqzf7V613D9a+6/6H47RvXhLN4w7xuUrSJrZHy15xR80Qh3UVoR/WN8d2mazvnSRt6XPEqOlx9+JllvihQnR3d8fMM2a7/kklWP7Ys6K9o1Pa5C6++o54+oXXDDmgZO435920MHbJHWu+S1LCm9w8PubXNliTkqQENrNhJ7MsaaWzLw8Y0VZrcywAAEBhIuJaK3MAAGyBvLtqgIKfwb10HOD9DjIhAAAAAAAAAAAAAIrL/nYA+9sBAACAflCVbptUlcm+5FAJ/WV75I+L+x96dIt/4Vq1anXMX3B3zDj1vKgfc4DPVpIKbHTrxLildpjDuorQhUOHx8B01vdOkragSzvmWd6HCnLGuZe59kkl2tBdPhnfueLWaO/olAruinn3xKuvv23AASVnzZq18f2rfhGZCYeb85KU4GrSU+PkhtGxZHCtdSlJSlgzGnc2yxJWKp174B8b8//LzlgAAICNi4inrMgBALAF8u6qAQp+BvfScYD3O9uEAAAAAAAAAAAAACgu+9sB7G8HAAAA+sk2LdM+nkpnb3CohP6yQSOnx2nfvCTeentlr/za9caKt+Lq62+Jw2d8fd1/ts9YkjZcU+s+Ma++0WFdReg7Q4fHgEzW906SNqMjTjgzuru7Le9DpexkmX2la59U4h331UujvaNTKqjrb10a76xaY8ABJe3tle/E7MvmRuPYg816SUpwu7TsHT+pb7IuJUkJallPR26/mzmWsFKZ7M+3yuf/2s5YAACA9YuIf7AKBwDAFsq7swYo+DncS8cB3m++CQEAAAAAAAAAAABQXPa3A9jfDgAAAPSvravS2RmpdHa1gyX0l42ZekzcfvdDvfrL16vL34gr5t4Y0444KaqHt/mcJWk91WWmxhVDWh3YVYS+PXRkVPvOSdImtXP2s/HGircs7UOFOPfff+TaJyWgXafPiPaOTmmDzZ6zMO588Kno7jbfgORY/vqKOHPW5VE7Om/mS1JCe3cd5ojtx8ZdtfXWpiQpIS2tqY0DmsaZYwkrlcn9qy2xAAAA6xcRE6y+AQCwhfLurAEKfg730nGA93vZhAAAAAAAAAAAAAAoLvvbAexvBwAAAEpAdWvbDql09gkHS+h9h1sNb4uZZ8yON99a2eu/gj3z/Esx+7K5sWvbsT5rSfqABmWy8d0hwx3YVYT+ddgo3zlJKrCaHfPx4LLHLetDhbj4yutc+6QE/Y53xuzror2jU/rALpm7KJ5+4TXDDUisF37/8ro1q0Ejp5v9kpTQmlr3ifOHjrA2JUkJ6YGaupjcPN4MS1xTP2VHLAAAwAeLiBOtugEAsIXy7qwBCn4O99JxgA820JQAAAAAAAAAAAAAKB772wHsbwcAAABKRM2I/N9XpbM/dKiEPqidphwdCxYt7rNfwx554uk4c9blkZlwuM9bkt57KHpPpzfs6MCuInRyw2jfOUkqoCvn3mg5HyrEf8y53nVPSlj7HnNmtHd0Su/rRzfcH2+8udJwA8rCE08+F8fMPDuqh7eZ/5KU0KY37xG/rh1mfUqSEtC9NXUxrmUv8ytBpdK5lVXDp462IxYAAOD9IuKHVtsAANhCeXfWAAU/h3vpOMAHy5kSAAAAAAAAAAAAAMVjfzuA/e0AAABAialKZw+tSufecsCE/rJ3Dyeccep5sfz1FX32q1hXV3fcdf/DMfOM2TFsl4N87pL0n81o3DmW1tQ6tKuP+2LDGN83SdpAnzvpW5byoULMuXb+ut8BXPukZFU/5sCY9f1fR3tHp/Rf3Xr347G2q9twA8rOsseejGNmnu0eQJISWm16apwxbMdYan1Kkkq+RTVDYqeWieZXgkqlcy+kRuYG2A0LAADw5yLiEatsAABsobw7a4CCn8O9dBzgg51uSgAAAAAAAAAAAAAUj/3tAPa3AwAAACXoE+lsYyqTfcgBE/qgMhMOjxtuWdTnv5C9s2pVzF9wd8w49byo22l/n72kim9S857rDqtyaFffdkLjGN83SfqAdm07Nla8+balfKgAP77uVzFgRJtrn5TQPv+VS6K9o1OKC350Wzz8xIsGG1D27rz/4Zh2xEnuAyQpqb87tuwd19Q3WaOSpBKvs2ZoZFonm12JKnv/Ni0TPmI3LAAAwB9FxN/11GV1DQCALZR3dw1Q8LO4l44DfLCfmhIAAAAAAAAAAAAAxWN/O4D97QAAAECJqh6d/9tUJjfL4RJaXyecNiuWv76iKL+Wvfvfc+XcG2Pfo77sYG9JFd2o1knxi7pGh3b1Yct6+sz2u/q+SdJ7qh9zQDzy+FOW8aECXD//thg0crprn5TgxuSOi/aOTlV4P5h3d7z82psGG1BRFixaHHvmj3c/IEkJbGA6G//UuEvcP7jOWpUklXA31jbEsPQ+ZleCSqVzc7fa6it/ZTcsAADAuhedjbaiBgBAL8i7uwYo+FncS8cBPthvTQkAAAAAAAAAAACA4rG/HcD+dgAAAKDEVbdmD65K595wyIQ+qPT4w+Lq628p6i9nL/z+5bi0Y15MO+IkfwNJFVldZmpcNCTj0K4+bFlPn2/cxfdNkv6zYt/zA/3jZ7+8PQaNnO66JyW86uFt8bX266K9o1MV2vW3Lo13Vq0x2ICKtGbt2rhy7o0xcuKn3RdIUgIb0ToprqhvtVYlSSXcNfVNUZueam4lq9PtggUAAFj3orMjraYBANAL8u6uAQp+FvfScYAP1tXTR0wKAAAAAAAAAAAAgOKwvx3A/nYAAAAgAaozU+uq0tl7HDCh9XXY8WfE8y++XPRf0R797TNxzoVzYufsZ/0dJFXWIek9fbFhTCytqXVwVx+1rKfPN+7i+yap4jvx69+1fA8V4KZb74rtdtjXdU8qk6YffUa0d3Sqwpo9Z2Hc+eBT0d1trgGsfGdVtP/H1TFsl4PcG0hSAvtk0+5xV2299SpJKtG+V98aA82rJNVdPTw7zS5YAACg0kXEOVbRAADoBXl31wAFP4t76TjA+o00KQAAAAAAAAAAAACKw/52APvbAQAAgIRobMz/j1Q69+13D1lw0IQ+qGG7HhRXzL0xuvvp1NYHHn48TvvmJZEef5i/h6SKqa1pz7inxqGCfdWyno5r3MV3TVLFNvlTX4pVq1ZbuocyN3/B3TF4x/1c96Qyqm6nA+O8H9wS7R2dqpAumbsonn7hNUMN4C/84ZXlcdKZF8SgkdPdI0hSwmpK7xP/PiRjvUqSSrTZQ4ZHtXmVnNK5N6pbpjXZBQsAAFSyiLjB6hkAAL0g7+4aoOBncS8dB1i/Q00KAAAAAAAAAAAAgOKwvx3A/nYAAAAgYbZNT52QSudecNiE1tf0T58cTzz5XL/9qra2qysWLFocM049L4bufKC/iaSyb8fWiXFDbaODu/qoZT0d37Cz75qkimv73Q+Op5590bI9lLlfLrg7Bu+4n+ueVIZ97pR/j+OMoAgAACAASURBVPaOTlVAV9+0OFa89Y6hBrABj/3umThm5tnuESQpge3XNC4W1g6xZiVJJdhXh+1gViWq7O+2HTHl/9gBCwAAVKqIeNqqGQAAvSDv7hqg4GdxLx0HWL9/MykAAAAAAAAAAAAAisP+dgD72wEAAIAE+njT1G2qMtkbHTSh9VW30/5x0Q+ujbVdXf36C9tbb6+Ma35+axx6/BkxaOR0fxtJZdvgdDbOGjYqljm4q8/6l8adfNckVUwDRrTFzQvvtWQPZe76+bfFoFGelaVybfTUz0d7R6fKuNlzOuOOxb+Lru5uQw2gQAsWLY7x+89wryBJCWtoekqcM2ykdTBJKsG+0DjGrEpW87caO/ZDdsACAACVJiI+2pPFdQAAekPeHTZAwc/jXjoOsH7XmxQAAAAAAAAAAAAAxWF/O4D97QAAAEBybV2Vzs5IpbOrHTah9bXXgSfEg8seL4lf25a/viKumHtjTDvipKge3ubvI6ksyzXtEXfUDnF4Vx91YoMDwSRVRt++6IeW66HMXXfTwhg0crprnlTmnf6da6K9o1Nl2KU/WRRPPf+qgQawGbq6uuOqeTdHevzh7hckKYHrYLfWDrNmJUkl1LKejtp+N3MqUWW/ZesrAABQaSJitFUyAAB6Sd4dNkDBz+NeOg6wfr8zKQAAAAAAAAAAAACKw/52APvbAQAAgISrGpHdsSqT+63DJrS+Bo2aHmfOujxWrVpdMr+8PfP8SzH7srmxa9ux/kaSyq6W1snRUd/iAK8+6sSGMb5nksq6g479Sqzt6rJcD2Xs2hsWxKCR013zpEo4cP6or0V7R6fKrJ/e/FC8tXKVgQawhd56e2Wcc+GcqB2dd98gSQmqJj01Tm/YMR4eXGvdSpJKpKU1tXHA9uPMqQSVymQ/becrAABQSSLiSKtjAAD0krw7bICCn8e9dBxg/bp7+l+mBQAAAAAAAAAAAEDfs78dwP52AAAAoAzUjMj/fVU6+yMHTmhD7ZI7Nu64Z0nJ/Qr3yBNPx5mzLo/0+MP8nSSVTdU9Hde4SyxxoGCf9I1ho2JAJuu7Jqns2nHyUfHKa69bqocyds3Pb42BI6a55kmVctj86P3j3MtvjvaOTpVB352zMO588Kno7jbPAHrT8y++HDPPmB0DRrS5f5CkBLVXy4S4qa7BupUklUgP1NTFxObxZlRCSqVzK6tb23aw8xUAAKgUEXG2VTEAAHpJ3h02QMHP4146DrBhw00LAAAAAAAAAAAAgL5nfzuA/e0AAABAGalKZw9NpbNvO3hC66t6eNu6gwlXvPl2yf0St7arKxYsWhwzTj0vhux8gL+XpLJoXMte8ctaBwr2RecPHREDfccklVE1O+bjgYcft0QPZazjJzfFgBFtrnlShXXM/70w2js6lfAu/+nd8cIf3jDMAPrQA0sfi+mfPtn9gyQlqMHpbJzesGMstW4lSSXR3TVDYkzrRDMqIaXS2ecHZLIpu14BAIBKEBE/sRoGAEAvybvDBij4edxLxwE2bH/TAgAAAAAAAAAAAKDv2d8OYH87AAAAUGYGtE7dPpXJPuTgCW2o0ft8Jn59+/0l+6vcyndWxbybFsbhM74eg0ZO9zeTlOjqMlPjnKEjY5lDvHq9S4akY7tM1vdMUlnUcc18y/NQxq6Ye2MMGNHmeidVYDtOOTbaOzqV4G5YuCzeWbXGMAMokptuvSvGTD3GfYQkJahdW/aO6+q2t3YlSSXQwtohkWmdbD4lpXT29rq6iR+26xUAACh3EfGgVTAAAHpJ3h02QMHP4146DrBhXzYtAAAAAAAAAAAAAPqe/e0A9rcDAAAAZah6dP5vU5ncLAdPaGMdM/PseOW110v6F7oXX3olLu2YF9OOOMnfTFKim9g8Pm6qa3CQVy/3w/rmqE9P9R2TlOiO+7/ftjQPZez7V/0iqoe3ud5JFdyp582N9o5OJayLrro9fvO73xtkAP1gzZq1ccmV10XDbp90LyFJCWlgJhszG3aKhwbXWr+SpH7uF3WNMTQ9xXxKTNnL7HgFAADKWURs3dObVsAAAOgleXfZAAU/k3vpOMCGXWpaAAAAAAAAAAAAAPQ9+9sB7G8HAAAAylhVJndIVTr3hoMntKHS4w+Lq6+/JRG/1j3yxNNxzoVzYqcpR/vbSUpkg9PZOLlhdCxxoGCv9tO67aPRoWCSEtreB30hVr6zytI8lKnZ3/uJa52kyH769Gjv6FSC+tEv7o/X3njbIAPoZ6+89np8+awLY9DI6e4pJCkhjWmduG7dxvqVJPVvP65vXrc/wWxKRql027F2uwIAAOUqIqqsegEA0Ivy7rIBCn4m99JxgA271bQAAAAAAAAAAAAA6Hv2twPY3w4AAACUuVRL25CqdO5eh09oYx12/Bnx/IsvJ+JXu66u7rjr/ofjtG9eEs3jDvH3k5S4dm3ZO66ta3KYVy92Q11DtLbu4/slKVE1jj04nnr2RcvyUKbOOv8HrnWS1lUzOh/nXn5ztHd0KgEtuOeJWNvVZZABlJBHf/tMHHr8Ge4rJCkhDezpiw1j4qHBtdawJKkfu3Do8BiQyZpNCSiVzq7ednhuV7tdAQCAchQRY612AQDQi/LusgEKfib30nGADXvOtAAAAAAAAAAAAADoe/a3A9jfDgAAAFSAurqJH05lcudVZXLdDqHQhhq260Fxace86OrqTswveKtWrY75C+6OGaeeF3U77e/vKCk5Bwqms3FC487xQE2dA716qVtqh8VOLRN9vyQlogEj2tbdxwLl591n6pP/9QLXOkl/1mdO/m60d3SqhLv0J4viyedeNcgAStiCRYtjz/zx7i0kKSHt3DIxrq1rsoYlSf3Yvw0dZSYlpxerW/epstsVAAAoNxFxpFUuAAB6Ud5dNkDBz+ReOg6wYe++XOnvTAwAAAAAAAAAAACAvmV/O4D97QAAAEAF2ba1ba93D19wAIU21vRPnxyP/+7ZxP2a9/obb8bV198SB372tKge3uZvKSkRjWydFFfUtzrQq5e6p6Y+JjWP992SVPJ987tXWo6HMrS2qyu+8JVZrnOS3v/sN+mz0d7RqRJt3q+XxJtvrzLIABJgzdq1ccXcG6N53CHuMSQpAQ3s6YsNY+KhwbXWsSSpnzqhcYyZlJBS6dyiurqJH7bTFQAAKCcRcZYVLgAAelHeXTZAwc/kXjoOsHGtJgYAAAAAAAAAAABA37K/HcD+dgAAAKDCfLxp6jZVmdxNDqHQxqodnY/Zl81ddyB4Ej334h/i0o55sdeBJ/h7SkpE+zWNi5trhznUqxd692DGQ5rG+l5JKtkOOObUxN5nA+u3atXqOOqL33Cdk7TeTjn36mjv6FQJ9e9X3RFLHnvBEANIoNeWr4hTz744Bo6Y5j5DkhLQzi0T49q6JutYktQPLevp8O13M48SUiqdvdAuVwAAoJxExI+sbAEA0Ivy7rIBCn4m99JxgI2bZmIAAAAAAAAAAAAA9C372wHsbwcAAAAq0lf+qiqTO7EqnV3rIAptrL0OPCEeXPZ4on/he+SJp+PMWZdHZsLh/qaSSrqBmWwc17hL3FtT73CvXjgY7OSG0b5XkkquUROPjJdffd0yPJSZt95eGQcd+xXXOUkbbMrhp0V7R6dKpJ/e/FCseOsdQwwg4R54+PHIHjbTvYYkJWIdLBdfbBgTDw2utZYlSUVuac+1N9u8p3mUkKrTuaPscQUAAMpFRCyyogUAQC/Ku8sGKPiZ3EvHATbuBBMDAAAAAAAAAAAAoG/Z3w5gfzsAAABQwarTbWNTmewzDqLQxho0cnqcOevyWLVqdaJ/6evq6o677n84Zp4xO4bufKC/raSSraF1Spw1bFQsdbjXFvftoSPXHdLoeyWpJO6rR02PuxcvswQPZWb56ysie9hM1zlJG23wjvvFOd/7ZbR3dKofu/BHt8W9S5+J7m4zDKBcdPdc1K+ad3O07nmoew5JSkA7t0yMa+uarGNJUpG7t6YuxrbsZRYloFQm9051a9sOdrgCAADlICKes5oFAEAvyrvLBij4mdxLxwE27hwTAwAAAAAAAAAAAKBv2d8OYH87AAAAUOFSo9r+oSqdvc5hFCrocKvsZ+P2ux8qi1/93lm1KubdtDAOn/H1GDRqur+vpJJsp5aJcXl9qwO+trBLh7RGTXqq75Skfu/7V/3C8juUmZdefjXG7z/DNU5SwR15Ynu0d3Sqn7rqpsXx2htvG2AAZer1N96MU8++OAaNtO4jSaXewJ6+2DAmHhpcay1LkorYbbVDY3jrJLMoAaXS2ecHjpi2rR2uAABAkkXE/9fTWqtYAAD0orw7bYCCn8u9dBxg435sYgAAAAAAAAAAAAD0LfvbAexvBwAAAHjX1lXp7IxUJveOAym0saqHt8XMM2bHijfL5/DZ15aviCvm3hjTjjhp3f9//s6SSq19m8bF/NoGh3xtQdfUN0VTeh/fJ0n91vGnnGvpHcrMU8++GDtNOdo1TtImNXziZ6K9o1NF7rs/XBh3PvhUdHd3G2AAFeDhR38X04/8snsPSUpAO7dMjGvrmqxlSVIRu6GuIYZZO09EqUz2lq3Gjv2Q7a0AAEBSRcR2Vq4AAOhleXfaAAU/l3vpOMDGLTIxAAAAAAAAAAAAAPqW/e0A9rcDAAAA/JdtR0wZnsrkHnUghQpp9D6fiV/ffl/Z/Rr4zPMvxezL5sYuuWP9nSWVVAMz2Ti6cde4tXaYg742swW1Q2Nsy16+T5KK3vj9Z8TbK9+x9A5l5KFlT0R6/OGucZI2q/97zlXR3tGpIjXn5/fFS6+uMLwAKkx3d3dc8/NbY8Ten3b/IUklvwaWiy81jokHa2qtZ0lSkfpxfXNsl8maQwkolc59285WAAAgqSJiN6tWAAD0srw7bYCCn8u9dBxg454zMQAAAAAAAAAAAAD6lv3tAPa3AwAAAPyZfxia/btUOvsDB1Ko0Gacel68uvyNsvtV8N3DFu9evCy+fNaF0bT7p/ytJZXQwYLZOGL7sXFz7TCHfW1G7x7IeGjTWN8lSUVr+90PjiefecGyO5SRW++4P4bufKBrnBLV0F0PjurhbT6LEmnyoadEe0en+rjvzlkYix54Mrq6ug0vgAr25lsr48zzvhfb7bCv+5D/x96dR1lZ3om+T25On3N6ndXn9j19V+dYTNbEDLU3BTILKCgo7CqQLSgOqAk4RFFMiHNMcCbEgcImCYpGKWIiGURNRANKORsHVBQjapxxVgSVoep3KU6vrOTG6C6oXfXuqs9nre9/vbrb/b68z7Pf59n1SFLCG9p3bPymrLf1LElqoRZ16xed0hljUAG0V6r6MDtbAQCAQhQR06xWAQDQzLJm2gA5fy/3R8cBvlz9zv6rUQMAAAAAAAAAAAAgf+xvB7C/HQAAAOBzdUhlskWpzIcOpVAu9Ro5LW5cfkebfUO4o74+1jz4RMw694ooHzLFNZeUiDqnM3FMrxGxqrS7A7+a2LM7O7/HQAeEScp7nSqrY9W9j1pyhzZk+W2rY+99DvGMU0G136HfiXnXrozhk071eSSkvfeZHPOX3BU1tXXKUzfc8ki88fZHBi4A/uLFl1+PI0/+gbmIJCV9/SuVidN7DImnikutaUlSC/S97gONPwVQUSrzyV6V4/vZ1QoAABSaiDjDKhUAAM0sa6YNkPP3cn90HCA3xUYNAAAAAAAAAAAAgPyxvx3A/nYAAACAf+jrFVV7F6WqHnAwhXLtiG99P1594+02/aZw0+YtcfOtq2P6rAuiS/9Jrruk1j9cMJ2JY3qNiFWl3R361cR+0jUdpakJ7iNJeavm2psttUMbsnjpLdGpstrzTQXT3vtMjumnXxE1tXW7OnXu9T6XBHXMd676y7VR87Vw2b1x72MvxvYd9QYuAD7XynsejsHjZ5iPSFLCG9p3bNxS1st6liS1QCf2GmbsKYRSmT/vVTn+/7WrFQAAKCQRUWN1CgCAZpY10wbI+Xu5PzoOkJt9jRoAAAAAAAAAAAAA+WN/O4D97QAAAABfqLJyxj91SFed3yGdqXc4hXKpbPChsXDJ8thR3/YPrn3zrXfjmtoVMfGYM1x7Sa1e53QmZvQaHneXdnfwVxNaUdYz0hUHuYckNXvHzb4oGhoaLLVDG9D4b3nu5Us821RQ9R93fMxdeEvU1Nb9pQVL10Sf/af7fBJSasxxf3N9tOctu/2x2PjuJgMXAF9q27btsXjpLdF16BTzEklK9NpXVZzeY0g8XVxqTUuS8ti6ktKY3HuUsacwWvmVbPZrdrUCAACFIiJ+ZWUKAIBmljXTBsj5e7k/Og6QmylGDQAAAAAAAAAAAID8sb8dwP52AAAAgJwUpTKjd/aGgymUawcedlqsfWZDu3mD+NwLr8T8Rcti8PgZrr+kVq1TOrPrwKul5X0dAJZjD5WUx7g++7t/JDVbIyaeFJs2b7HMDm3A1q3b4oTvzvNsU+F8H+hXHYfMvDCuuvGeqKmt+7uOmn25zylBnfnDmz73OqlpLbrpvnjoyZdjR32DgQuAJnlj47txyjnmR5KU9Ib3PTBuLetlTUuS8thjxWUxou8Bxp3C6Pt2swIAAIUiIu6zIgUAQDPLmmkD5Py93B8dB8jNKUYNAAAAAAAAAAAAgPyxvx3A/nYAAACAnHWunLhXh1TmLgdTKNe69J8U581bHFs++bTdvEmsr2+Ihx9/Ztd/d++RR7gPJLVqI/scGAu6Vca64lIHgX1J63Z2eo8h7htJe1yPfQ+PF19+3RI7tAEfbdock447y7NNBVPvUdPjjHk3RU1t3T9s/pK7Yu99Jvu8EtLYI876wuulL+9Xd66N9z/6xKAFwB6554HHY3j1CeYnkpTgilOZOL/HwFhXYs1LkvLVfaXdIl1xkHEn8WXqO6SqDrKbFQAAKAQRscFKFAAAzSxrpg2Q8/dyf3QcIDcXGDUAAAAAAAAAAAAA8sf+dgD72wEAAACa6qsdUplZRenMVgdUKNeGTJgZdQ+tbXdvFbdu3RZ3rnkkZs65LPbe5xD3gqRWq3fFwXFmj0HxUEm5w8C+pKu79ovS1AT3jaTdqlNlddy1c/4HFL6Nb78XY6bM8mxTQdSxX3UcfPS58aPrVkVNbd2X1vg/63NLRl0GHBI/vObOnK6b/raf3vxAPPPCRgMWAM1m+/YdsXDJ8igeONk8RZIS3Jg+Y+Ku0h7WtCQpT92x8xnbLTXemJPwitJV73fuP6nEVlYAACDpIuJjq1AAADSzrJk2QM7fy/3RcYDc/NSoAQAAAAAAAAAAAJA/9rcD2N8OAAAAsFs6psYPKEplNjikQk054HnWuVfE+x9uapdvGD/atDluvnV1TD3+vF2fhXtCUmu0dzoTx/QaEb8r6+lAsC9oZVmPGNp3rHtGUpO7/Cc3WVqHNuCZP70U+4z7hueaCqJuww6PU+deHzW1dTl3/lW/9m4iQU0//YomXT/Vxa33rIvNn2w1YAGQFy+98kYcdsL3zFMkKcGVpCbE+T0GxjPFpda1JCkP/by8T3RJZ4w5Ca8onXmi46DsP9vJCgAAJFVE/LOVJwAA8iBrtg2Q83dzf3QcIDe3GDUAAAAAAAAAAAAA8sf+dgD72wEAAAB22//aZ+z/LEpnljqkQk0pNXp63Hzr6nb9tvH1je/EwiXLY9+JJ7onJLVKHXeW6bN/LOrWL55y4ODn9mhJWUztPdL9Iinnjjn1wqivb7C0DgVu9X2PRvdhh3muqSDaf+qc+OG1d0ZNbV2TG1z1LZ9hQuq7/7GxYOma3bqO7a1rf/1QbHjlHYMVAC1ixcp7o+9+R5qvSFKCa1zrWlPazbqWJOWhy7tVGmsKoKJU5sd2sQIAAEkVEcVWnAAAyIOs2TZAzt/N/dFxgNw8ZNQAAAAAAAAAAAAAyB/72wHsbwcAAADYY3ulqo7rkK7a7KAKNaWjT5kbr290CO5zL7wSF155faRGT3dfSGqVuqbGx4yew+Pmst4OB/uc5nfvH53TGfeKpC9sxMSTYtPmLZbVocD9dOkt0blyoueakj+HH3Z4zPrBkqiprdvtTj7/Wp9lgvruZcv26Hq2h1Y//Hxs3bbDYAVAi3r/w00x+3tXRcd+1eYskpTYda4Ju9ZyrGlJUvM3p8dgY00BVJSacLQdrAAAQBJFxECrTQAA5EHWbBsg5+/m/ug4QG7+bNQAAAAAAAAAAAAAyB/72wHsbwcAAABoFkV9Mt06pDOPO6hCTan7sMPiuptuj/r6hnb/BnL7jh2x6t5H46Sz5kfZ4EPdH5JapSF9D4zzewyMB0q7OiTsr/pleZ/oW3GQe0TS59Zt6NR47oVXLKlDAdtRXx/nXPITzzQVRPtPnROXXbMyamrr9qirbrwneux7hM80IR0w7cw9vqZttRtX/DFe2/ihwQqAVvXQ48/EqMknm7dIUoI7tPd+8UCJ9S1Jas6e3dlRvUcYZxJeUarq070qx/ezgxUAAEiaiMhYZQIAIA+yZtsAOX8390fHAXLziVEDAAAAAAAAAAAAIH/sbwewvx0AAACg2ZSVjf1vRemqKzukqxocWKGmVDX9u/HcC694DfmfPv1sa6xYeW9Mn3VBdOk/yT0iqcXrvLPJvUfF4m6peLq41IFhO2s8iLGq937uD0l/U8d+1XHbXfebwEIB27zl0zj6lLmeaUp83YZPi1N+sCRqauuarcNP+aHPNinfwQZMissWr2zW61voLbrpvnjkqVdiR329wQqARNi+fUcsXnpLlA+ZYv4iSUn97pwaHzXd+lnXkqRmbF1xaRzcZ7RxJuEVpaqe71JR9a92sAIAAEkSEcdaYQIAIA+yZtsAOX8390fHAXL3P4wcAAAAAAAAAAAAAPlhfzuA/e0AAAAAza4oncl0SGXedWCFmlKXAZPiwiuvj61bt3kV+VfefOvduKZ2RRww9VT3iaRWqWdqfJzUc1jcVN4n1pWUtusDw57d2dzu+0SXdMa9IWlX8xctM2GFAv++deBhp3meKdF17FcdBx99bsy/7g9RU1vXrF12zcro0v8Qn3NCOvK0y5v9Ghdqt695JjZt/tRABUAivfzaxjj8xPPNXyQpwR3ee2Q8XFrerte0JKk5a3ym7lMxzhiT9FKZW77yla981e5VAAAgKSLidCtLAADkQdZsGyDn7+b+6DhA7joaOQAAAAAAAAAAAADyw/52APvbAQAAAPLi33tP+HqHdOYOB1aoqQ2rOiHue/hJryM/x3MvvBIXXnl9pEZPd69IapV6VIyPY3qNiOu6puLp4tJ2e2jY70t7xtCKA90TUns/mPXE82NHfb1JKhSox5/6k+9WSny9Rh0d37lkadTU1uWtsUec5bNO0PVesHRNXq930rthxSPx59ffN0gBUBBW3vNwVB54rHmMJCW0vhUHxfXlFe12LUuSmruVZT2iW2q8MSb5fdfOVQAAICkiYq4VJQAA8iBrtg2Q83dzf3QcIHe9jRwAAAAAAAAAAAAA+WF/O4D97QAAAAD5k81+rShVdW6HVNV2B1aoKXXsVx1z5i6MTZu3eC35OXbU18eaB5+IWedeEeVDprhnJLVKjQdmHd57ZCzoVhmPF5e1u0PD1paUxck9h7kXpHba8OoT4qNNm01MoUCtWHlvlA0+1PNMia1T/0lx6ImXxBU3rI6a2rq8dvb8X/jME9R3Llma92uexBbddF889OTLu955AUAh+fCjj3etZzWua5nLSFIyO6bXiHa5jiVJ+egX5X2iSzpjfElyjfs0KzKjbFwFAACSICIWWE0CACAPsmbbADl/N/dHxwFyN8zIAQAAAAAAAAAAAJAf9rcD2N8OAAAAkHcdKjMDi1KZFxxcoaaWHjM9brvrfq8mv8CmzVvi5ltXx/RZF0TnyonuG0mtUklqQkzuPSoWdKuMR0vK29XBYT/tmo5uqfHuA6kd1XXolHhuw8smolCAGhoaYuGS5dGp0oH3Sm4Dx58Y51/166iprWuxBhx0vM8+IY0+7Lsteu2T0K33rItNmz8zSAFQ0B554tnYL3uy+YwkJbT+FePiF+V92tX6lSTlqyu6VRpbEl/mrY4VB3ewaxUAAGhtEXGjVSQAAPIga7YNkPN3c390HCB3E4wcAAAAAAAAAAAAAPlhfzuA/e0AAAAALaJzn4P/n6JU1XKHVmh3mj7rgnhj47teUX6Jxs/omtoVMWbKLPeNpFarcyoTo/oeEKf3GBJLy/vGuuLSNn9w2JrSbjGuz2jXX2oHdexXHbf/4X4TTyhAmzZv2fXd0rNMSa108JT45hlXx4Kla6Kmtq5FO+GcH7sGCalT/0lx6eI7WvweaI1uXPHHePmN9w1QALQZ27fviJprb46ywYea10hSEtevdta4dvV0O1i3kqR8N7vnUGNL0ktl6iorZ/yTXasAAEBriohbrSABAJAHWbNtgJy/m/uj4wC5O9LIAQAAAAAAAAAAAJAf9rcD2N8OAAAA0KKK0pnji1KZTxxeoabWffhhcU3tiqivb/CqMgfPvfBKXHjl9ZEafbT7R1KrVpaeEJk++8f5PQbG78t6tNmDw9aVlO76b9w7nXHdpTbcpTU3mmhCAXrx5ddj5KSTPMeU2A6YdmZcuviOqKmta5Wu/Nnd0XXY4a5FQjri1Pmtdi+0RD/+5f3x+LOveccHQJv18msb44hvfd+8RpIS2vC+B8btZT3b7HqVJLVEz+7siF4jjSvJ7zK7VQEAgNYUEfdaOQIAIA+yZtsAOX8390fHAXJ3ipEDAAAAAAAAAAAAID/sbwewvx0AAACgxXXsO7F3UbrqaQdXaHeaeMwZ8fxLr3pdmaMd9fWx5sEnYta5V0T5kCnuIUmtXv++42JGz+Hx467peKSka5s7QOyO0h4xqu8BrrXUBjtu9kVRX99gggkF5u77H4ueI6Z5jimRVYw5Lr598dKoqa1r9Q498RLXJCH1GnV0LFi6JhH3RXN36z3r4uMtYnUGdQAAIABJREFUnxmcAGgXbll5b6THTDe/kaQEVpzKxPk9BsYzxaVtbp1KklqqtSVlMbrPGONKsmsoSldNsFsVAABoLRGxzooRAAB5kDXbBsj5u7k/Og6Qu/OMHAAAAAAAAAAAAAD5YX87gP3tAAAAAK2iy4gR/70oXXWlwyu0O5UMzMb8Rcti27btXls2waaPt8TNt66OqcefFx37VbuXJLV6nVOZGNX3gPhWz2Fxddd+cXdp9zZxgNi64tI4q8eg6JzOuM5SG2nUId+KTZu3mFBCgblx+R3Rpf8kzzEl773GoEPjiFPnx1U33B01tXWJ6JKf/C46VU50fRLS6RfdkJh7ozn6+e2PxetvfWhgAqBdrsvMmbvQmowkJbRMn/2jrqRbm1ibkqTW6P7SbpGuOMiYkuCK0lXvf73vhGK7VQEAgNYQEa9aLQIAIA+yZtsAOX8390fHAXL3IyMHAAAAAAAAAAAAQH7Y3w5gfzsAAABAq9qroqq6KJ15zyEW2p32z54Sjz31nFeXu+GNje/GwiXLY9+JJ7qXJCWq3hUHx+Teo+LMHoNiaXnfWFtSVrCHiP2urGeM7HOg6yoV+nNp5BHx51ffNIGEAvLZ1q1x6nlXeoYpcXXsVx0HHnFmXLr4jqiprUtco6fOcZ0S0n5Tvp3Ie6SpLfn1Q/H0829GQ0ODwQmAdu3u+x+LgQd9wzxHkhJY19T4WNCtsmDXoiSptbujtMeuZ6kxJbkVpase7tkz+1/tVAUAAFpaRHxglQgAgDzImm0D5Pzd3B8dB8jdIiMHAAAAAAAAAAAAQH7Y3w5gfzsAAABAq9urcnznDumqex1iod2pU2V1zJm7MD7e/IlXmLvpuRdeiQuvvD4q9j/KPSUpcXVOZ2K/vgfEt3oOi6u79ovVpd0L6hCxp4tLY06PwTv/O1xLqRDbe59D4sHH1pkwQgF57c23Y9y00z3DlLgGjj8xzrn85qiprUts371smWuVmPddE+OSn/4+0ffLF7Xopvvi/ideim3bdhiYAOA/Na5jnXXxoujYr9p8R5IS2OG9R8bDpeUFtQYlSUnpZ10ronMqYzxJcEWpzOV2qQIAAC0tIrZaIQIAIA+yZtsAOX8390fHAXJ3vZEDAAAAAAAAAAAAID/sbwewvx0AAAAgGbLZr3VIV53fIZXZ4SAL7dbh1Ad9I+5a84jXmHtg+/YdccfdD8WM71waJQOz7itJia1ranwc0HdMzOw5PC7pPiB+Ud43HinpmuiDxH5b1iuGVhzo+kkF1g03/94kEQrIfQ8/GanRR3t+KVF1Gz4tZp69KBYsXRM1tXWJr3LsDNctKQe6nzKvIO6Zv27hsntj1UPPx5ZPnIsFAP/Iw48/E/tOPNF8R5ISWCp1UCwt75vo9SZJSmoX9tjHWJLsGjqkJ0yySRUAAGgpEfE1q0IAAORJ1owbIOfv5/7oOEDufmnkAAAAAAAAAAAAAMgP+9sB7G8HAAAASJSOqeoRRenMqw6y0O42fdYF8cbGd73O3EObPt4SN9+6OqYef1507Fft3pJUEHVLjY+xfUbHyT2Hxfzu/ePmst6xtqQsMQeJrdvZxd0HRFl6guslFUDnzVtsUggFoqGhIRYuWR6dKyd6fikxddp5P1Z94/sx/7q7oqa2rmD65hlXu34JqceII+OqpWsK5t757aqn4p0PNhuUACAHn362NS688nrfYSQpgXXc2Yyew+OJBK0vSVKhNHPn89NYktyK0pkPOvefVGKHKgAA0BIi4l+sCAEAkCdZM26AnL+f+6PjALm7zcgBAAAAAAAAAAAAkB/2twPY3w4AAACQOF0qqv61Q7rqFw6z0O7WffhhcU3tiqivb/Basxm8vvGdXQfUD68+wf0lqeDqvLOBFWNjUp/94qSew+KC7vvE4q6puL2sZzxe3DoHIq4q7R5VO///cX2k5HbYCd+L7Tt2mAhCAdi0eUscN/tizy4lqqHVp8T5C34bNbV1BdcVP1sdZYOnuo4JafYFP0v8PbP01kfjpdfeMyABwG54ev2LceBhp5n3SFICG9L3wLilrFerrCNJUqG2rrg0Du4z2jiS4IrSmSc6Dsr+sx2qAABAvkXE160EAQCQJ1kzboCcv5/7o+MAuVtt5AAAAAAAAAAAAADID/vbAexvBwAAAEiqr3ZMV51clKr61IEW2t2qjzkjntvwslebzWjtMxvivHmLo2L/o9xjktpEvVMHx+g+Y+LI3iNiTo/BcXm3yripvE/cU9o91uX5ULGru/bb9X/fdZCS1fDqE+LDjz428YMC8OSzG2Lw+BmeXUpMffc/NmZf+LOoqa0r6CbNvMD1TEgjs6cn9j5ZvPzBeGL969HQ0GBAAoA9sHXrtph39dLoMmCS+Y8kJazO6Uyc02NgrCspzet6kSS1pR4qKY/+FeOMI0kuVVVjayoAAJBvEVFsFQgAgDzJmnED5Pz93B8dB8jdg0YOAAAAAAAAAAAAgPywvx3A/nYAAACAROtUMaFXUSrzpAMttLs1HkJ44ZXXx2dbt3rF2Yx21NfHmgefiFnnXhFlgw91r0lqs5WkJkT/vuNibJ/RcXjvkXFyz2FxZo9BMb97/7iuaypuLusdq8u6x7ri3TtQ8Y8l5bv+d3ZKZ3zeUgLqPuyweG7DyyZ7UAB+uWKV7yJKTOVDp8b006+Iq268J2pq6wq+CxfdFp36Vbu2CajxOly083ok6f5YdNN9cf8TL8XWbTsMRgDQjJ59/s9x0BHfNgeSpAQ2us+YWFXafbfWgSSpPXZHWc/omhpvDElwHSsy0+xMBQAA8ikieln9AQAgT7Jm3AA5fz/3R8cBcvekkQMAAAAAAAAAAAAgP+xvB7C/HQAAACDxvt53zP/okM4sdqCF9qQhE2bGPQ887jVnHny0aXPcfOvqmHr8edHRoduS2uuhUzvrnTo4hlYcGAf3GR3Z3qPiqN4jYmbP4XF6jyFxXvdBcUn3AXFFt8r4Sdd0LC3vG78p6x2/L+sRa0q7xZKuqRjad6zPUmrFOldOjLvvf8zkDhLus61b4/TzF3huKRGVDDo0pp0yLy6/flXU1Na1qUZOnu0aJ6QpJ12aiHvi6mX3xqqHno/Nn2w1GAFAnmzfsSMWXPPLKBmYNQ+SpITVNTUh5nfvH+uLSyRJOXRD177ROZUxhiS1VNVHHVIHl9uZCgAA5EtEDLDyAwBAnmTNuAFy/n7uj44D5G6DkQMAAAAAAAAAAAAgP+xvB7C/HQAAAKBgdEhPmFSUrnrfwRbak2bOuSzeff8jrzvz5LU3346FS5bHsKoT3G+SpIKs+7DD4nvzFvss2mE/XXqLyRwkfdfGS6/FmCmzPLPU6nXqPykOPvrcuHTxHVFTW9cmm33hDa51Uuan+06Lq5auabV7YeGyulh5//r4YNMnBiIAaCF/fvXNmPzNs82FJCmBHdZ7ZDxS0jXWF5dIkr6k83sMNHYkuKJU5smOg7L/bFcqAACQDxEx1IoPAAB5kjXjBsj5+7k/Og6Qu1eNHAAAAAAAAAAAAAD5YX87gP3tAAAAAAXl630nFBelqh5wsIX2pF4jp8WNy++IhoYGrz3zaO0zG+K8eYuj735Huu8kSQXTt39QE59+tjUGj5/h82hP1/37C0zeIOFu+u0fonzIFM8stWqd+lXHuCPPjot+fHvU1Na16RYsXRN99z/WdU9Is36wpFXug9+ueireeX+zQQgAWkF9fUMsXnqL70GSlMDSFQfFTeV9Yn1xiSTpS/pmr+HGjgRXlMr82I5UAAAgHyJihNUeAADyJGvGDZDz93N/dBwgd28aOQAAAAAAAAAAAADyw/52APvbAQAAAApOZeWMfypKV13cIZ2pd7iF9qRDvnFWbHjpNa8+82zr1m1x55pHYuacy2LvfQ5x70mSEt0jTzy7a/xafd+j0bFftc+kHTTxmDNi27btJm2QUJu3fBonn/0jzyu1eqOyp8f5C34TNbV17abp37nStU9IIyaf1qLX/rernoq33v3YIAQACfDyaxvj0BnnmhNJUsLquLOTew6Lp4tLY31xiSTpH7Ru53NyXJ/9jR0Jrqhf9aF2pAIAAM0tIvazygMAQJ5kzbgBcv5+7o+OA+TubSMHAAAAAAAAAAAAQH7Y3w5gfzsAAABAwepQkRlVlKp63eEW2pNKB2Vj/qJlsW3bdq9AW8BHmzbHzbeujqnHnxcd+1W7ByVJiWp49QnR0NDwl3HrO3MX+lzaeAMP+ka8896HJmmQUM9teDlGTT7Z80qt2oCDTojvXrYsamrr2l3zr/tDlAw81H2QhMPa+1XHhYtuy/s1X37n2nhto7kRACRN4/uqX65YFb1GTjM3kqSENarvAXFnaY9YX1wiSfoHPVRSHv37jjNuJLSiVObDzv0nldiNCgAANKeIGGOFBwCAPMmacQPk/P3cHx0HyN17Rg4AAAAAAAAAAACA/LC/HcD+dgAAAICC9vW+E/+9KJ25zQEX2tP2z54Sjz653mvQFvTam2/HwiXLY2jmePegJCkRNY5Lf+3jzZ/E4PEzfDZttK5Dp8S6514yKYOEuvbnt0bxwMmeV2q1UmOOi1MvuD5qauvadVXHft/9kJCmnHRJ3q7zL+94Il567T2DDwAk3Bsb340jvmV+JklJqyQ1IS7uPiCeLS6J9ZKkz+22sl5Rlp5g3EhoRenMQ5WVM/7JblQAAKC5RMRYKzsAAORJ1owbIOfv5/7oOEDuPjJyAAAAAAAAAAAAAOSH/e0A9rcDAAAAtAVf7ZDOnFaUzmx1yIX2pI79qmPO3IWxafMWr0Nb2NpnNsR58xZHn1FHuhclSa1Sl/6T4q133v+7MerBR5+OTpXVPqM2VufKiXHH3Q+ZhEECffjRx3Hc7Is9q9Rq9Tvwm3Hy+dfGgqVroqa2rt33/Zrf7Hpf4t5o/brvOy2uuvGeZr2+P7/9sXjptfcMPgBQQBoaGuLG5XdE16FTzJEkKWFV994/HijtGuuLSyRJn9PirqnolM4YMxJbZp5tqAAAQHOJiIOt6gAAkCdZM26AnL+f+6PjALnbbOQAAAAAAAAAAAAAyA/72wHsbwcAAABoM/aqHN+vQzrznAMutKelx0yPm29d7ZVoK9i6dVvcueaRmDnnsth7n0Pcj5KkFuvoU+b+w/HpBz+61mfUxrqmdoWJFyTQvQ+vjf5jj/WcUuu8CzjwG/Gt7y2OBUvXRE1tnf6qYRNnuUcS0qy51zXLNV1666Px/MvvGHgAoIC98vpbccg3zjJHkqSE1afioLixa0WsLy6RJH1O5/QYaLxIbg1F6aoJdqECAADNISIyVnMAAMiTrBk3QM7fz/3RcYDcfWrkAAAAAAAAAAAAAMgP+9sB7G8HAAAAaFM6Dsr+c1G66kqHXKg5Om72RfHmW+96NdpK3vvgo7j257fG+CO/436UJOW92/9w/z8ck7Zu3Rb7Z0/xObWRzpu32EQLEmb79h0xf9Gy6FRZ7TmlFm/g+BNi1tzrYsHSNVFTW6fPadYPlrhXEtKIQ07bo2u57PbHYv2Lb0VDQ4PBBwDagMYxffHSW6J44GRzJUlKUB13NqPn8FhbUhbri0skSX/Vszs7otdI40Viy7zdKZ0psgsVAADYUxEx0UoOAAB5kjXjBsj5+7k/Og6Qu+1GDgAAAAAAAAAAAID8sL8dwP52AAAAgDapQ3rCER1SVZscdKE9rXzIlFi4ZHnsqK/3irQVbXjptZi/aFkMHj/DfSlJavb6jDoytm3b/oVj0dpnNkSXAZN8XgXesaddZF4HCfPchpdjzJRZnlFq8QZXfSu+c8nSqKmt05d01dI10WvkUe6bBNSpX3Vc9OPbm3wNb/rd4/H8y+8YdACgjXr2+T/HAVNPNV+SpIQ1tO/YuLWsV6wvLpEk/VVrS8piVN8DjBUJrShdteor2ezX7EAFAAD2REQM2tkvJEk5B0DusmbcAL6fS1IeusnIAQAAAAAAAAAAAJAfjb8J8rMogJw1GDkAAAAACsjXK6r27pDK3O+wCzVHBx52Wqxd97zXpK2svr4hHn78mZgzd2F0HTrFvSlJapbOm7c4p3Hoxzf8xudVwI07fHZs+eRTEypIyg6Mhoa4cfkdUTb4UM8otWgDx58Y3754adTU1qkJHXHqj9w/CWnqty7N+br9+g9PxqsbPzDoAEA7sH3Hjli4ZHl0GTDJnEmSElRxKhMXdR8QzxaXxHpJ0l9aXdo9elSMN1YktKJU1bl2nwIAAAC0HCveAE2SNXIAAAAAAAAAAAAAAABA4Wj8TZCfRQHkzsgBAAAAUGhGjPgvHdJV53dIZ+odeKE9rUv/SXHevMWxecun3pYmwKefbY0VK++N6bMuiM6VE92jkqTd7un1L+Y09jQ0NMQ3v32Jz6wA6z/22HjzrXdNoCAh3n73gzjqlLmeT2rRhlafEmfOvylqauu0G/3w2jtj730mu5cSUPd9p8VVS9d84fX67aqn4s13NhlwAKAdeuyp52LfiSeaN0lSwsr02T/uL+0W64tLJEn/2S/K+0TndMY4kcgy9R36TdjP5lMAAACAlmGlG6BJskYOAAAAAAAAAAAAAAAAKByNvwnysyiA3Bk5AAAAAApUx/SEsR3SmbcceKHmaPD4GXH3/Y95Y5ogb771bixcsjyGV5/gHpUkNamxh81u0pjz0abNMWTCTJ9dAdVj38PjuQ0vmzBBQvz2jrroPfIIzye1SJ0qJ8YB086Ic69YHjW1ddrDDjrqHPdVQpo197q/uz4Ll9XFrfesi7fe+9hgAwDt3JZPPo2zLl4UHftVmztJUoLqnTo4ri+viPXFJZKk/+yi7gOMEQmtKJ15tWhA9b/ZeQoAAACQf1a5AZoka+QAAAAAAAAAAAAAAACAwtH4myA/iwLInZEDAAAAoIB9ve/Efy9KZ2536IWaq5lzLot33vvQm9OEWfvMhjhv3uLoM+pI96kk6Uu79ue3NnmseeZPL0XpoKzPrwDqMmBS3PPA4yZIkACN351mfOdSzya1SCUDD42qb3w/Lvrx7VFTW6dm6rwrfuX+SkgjDjntL9fl6p/fG3fe/1y8/9EWgw0A8DfWPPhE9B97rPmTJCWojjs7ueeweLq4NNYXl0iSdvbNXsONEQmtKJ257Stf+cpX7TwFAAAAyC+r2wBNkjVyAAAAAAAAAAAAAAAAQOFo/E2Qn0UB5M7IAQAAAFD4vtohlZlVlM5sdfCFmqMe+x4e19SuiPr6Bm9QE2br1m1x55pHYuacy6LLgEnuV0nS37X3PofEex98tFvjzC9XrPIZFkA33Px7kyJIgBUr742++x3puaS812vkUTH99Cvi8utXRU1tnfLQoAknudeScAh7v+q49Ce/i7sf2RCbNn9qoAEA/qFNH2+JOXMXmkNJUsIa1feAuKu0R6wvLpGkdt9TxaUxus8Y40NSS2Vm2XIKAAAAkF9WtgGaJGvkAAAAAAAAAAAAAAAAgMLR+JsgP4sCyJ2RAwAAAKCN6FhRvU9RKvOCgy/UXE069sz404uveouaUB98+HHcuPyOmHjMGe5XSdJfmjnnsj0aX37wo2t9jglu3tVLTYKglb37/ke7nrWeScp3gyacFKd8f0ksWLomamrrlMdO+t5i91xCunShuQ4AkLsVK++N3iOPMI+SpARVkpoQF3cfEOuLSySp3fdAadeoqDjY+JDAitJVn+1VOb6fHacAAAAA+WNFG6BJskYOAAAAAAAAAAAAAAAAKByNvwnysyiA3Bk5AAAAANqQf+uW+ZeiVOYGh1+o2Q69GpiNH/3457F16zZvUxPsmT+9FN+ff22kRk9330pSO2/1fY/u0ZhSX98QR58y12eZwE747rxoaGgw8YFWdOeaR6LfAcd4JilvdexXHSMOOS3O/OFNUVNbpxbqqhvvie77TnMPJqD+Y4+NHfX1BhwAIGdvv/tBHHvaReZSkpSwpvYeGX8sKY/1xSWS1K77dXnv2DudMTYksKJU1fONey3tOAUAAADID6vZAE2SNXIAAAAAAAAAAAAAAABA4Wj8TZCfRQHkzsgBAAAA0AYVpTPHdEhXbXYAhpqroZnj454HHvdGNeHq6xtizYNPxKxzr4jyIVPcu5LUzqo88NjYUV+/x+PJpo+3xMhJJ/lME9Sk486KrVu3mexAqx3S/n7MnHOZ55HyVsmgQ+OQmRfExT/+XdTU1qkVmnqyf+NJaeU9Dxt4AIAmq/3Vyug2dKr5lCQlqH4V4+KX5X1ifXGJJLXrrurWz7iQ2DKL7TQFAAAAyA+r2ABNkjVyAAAAAAAAAAAAAAAAQOFo/E2Qn0UB5M7IAQAAANBGFfXJdOuQzjzu8As1Z40Hyb/7/kferBaATR9viZtvXR1Tjz8vOvardv9KUjvo4gU3NNs48tIrb0SfUUf6XBPQvhNPjA8+/NjkBlpBQ0ND1P76zug5YprnkfJS5biZ8c0zro7Lr18VNbV1asUu/envo1P/Se7LBHT0KXMNQADAbnn5tY0x6dgzzakkKUF13tmZPQbFupLSWF9cIknttpN6DjMuJLVUZrKdpgAAAADNzwo2QJNkjRwAAAAAAAAAAAAAAABQOBp/E+RnUQC5M3IAAAAAtGFlZWP/W1G66soO6aoGh2CouWo8UP6a2hVRX9/gDWuBeO3Nt2PhkuUxZMJM97AktdE69quOF/78erOOH48/9acoHzLF59uKVex/1K4DoYGW9+LLr0d2xjmeRWr2igdOjoOnnxtnX35z1NTWKUEdMO1M92gSDlyvnBivb3zHQAQA7JbGtav/uP7Xu+bd5laSlJwO6jM67i3tGuuLSySpXbZuZ+P67G9MSGBF6ar3i/pXdbLTFAAAAKB5Wb0GaJKskQMAAAAAAAAAAAAAAAAKR+NvgvwsCiB3Rg4AAACAdmCv1IQxRamqNx2EoeZs0rFnxnMvvOIta4FZ+8yGmDN3YXQfdpj7WJLaUBOPOSMv40bdQ2sdQtxKdRs6dde4DbSs7Tt2xOKlt0T5kCmeRWrWKkYfE0ecOj9+eM2dUVNbpwR25vyb3KsJaf6iZQYkAGCPPLfh5Rh96CxzK0lKUF1T4+M/uqVjfXGJJLXLHijpGqnUQcaEJJbKrPlKNvs1u0wBAAAAmo9Va4AmyRo5AAAAAAAAAAAAAAAAoHA0/ibIz6IAcmfkAAAAAGgnOqUzRUXpqlUOwlBz1mXApLjwyuvjs61bvW0tMI3XbMXKe2P6rAuiS/9J7mdJKvCW/ebOvI0Zv7rt7ujYr9rn3IIVD5wcdQ+tNWGBFvb4U3+KMVMcuq7ma+99Jse4I8+OM+ffFDW1dSqAKsfNdO8moAFjj4sd9fUGJgBgj3zy6Wfx3QuuNr+SpIR1TK8RsbakLNYXl0hSu+s3Zb1j73TGeJDAitKZs+0wBQAAAGg+VqwBmiRr5AAAAAAAAAAAAAAAAIDC0fibID+LAsidkQMAAACgXfne/9V4AESHVNV2h2GoORsyYWbcff/j3rgWqI1vvxfX1K6IA6ae6n6WpAKsfMiU+HjzJ3kdK35y42991i1Up8rqWLHyXhMUaEEffPhxnHHhf+z69+c5pOaoYsxxccy3r4r5S+6Kmto6FVAzz/oP93BCWnnPwwYooNls27HDhwDt2O9WPRC9Rk4zx5KkBDW04sD4fWnPWF9cIkntrvnd+hsLkljjfsp+EwbZXwoAAADQPKxUAzRJ1sgBAAAAAAAAAAAAAAAAhaPxN0F+FgWQOyMHAAAAQDtUlKoa0iGV+bMDMdTczZxzWbzz3ofevBaw5154JS688vqo2P8o97QkFUinnndli4wRl9bc6PNuga676XYTEmghDQ0N8fPf3hV99zvS80d7XMmgQ+Pgo8+NM+b9PGpq61SgXXHD6igfOtU9nYCmz7rAQAU0m9vvfjyOOu2yeOKZl3wY0E69sfHdmPzNs82zJClBFacycXH3AbG+uESS2l0zeg03FiSwolTmhf+1z9j/aXcpAAAAwJ6zSg3QJFkjBwAAAAAAAAAAAAAAABSOxt8E+VkUQO6MHAAAAADtVJeKqn8tSlf90oEYau567Ht4XFO7IurrG7yBLWA76utjzYNPxMw5l8Xe+xzi3pakBPfgo0+32Phw2cKlPvM8Nn/RMpMQaCHP/OmlqD7mDM8e7VGdKifGyMmz41vfWxxX3LA6amrr1AaafPxF7u8E1Hnnv6/XN75jwAKaxaYtn8WUEy+JTv0nxaEnzI2H127woUA71LhuddXiX0aXnc8C8y1JSk5Teo+KP5aUx/riEklqN60rLo0D+44xDiSwolTmZ3aWAgAAAOw5K9QATZI1cgAAAAAAAAAAAAAAAEDhaPxNkJ9FAeTOyAEAAADQznXoVz2jQ6pqi0Mx1Nw1HlD/3IaXvYVtAz786OO4cfkdMXHnNXVvS1KyGjJhZjQ0NLTouDB/0TKffR466+JFJh3QAjZt3hLfm7fYIerao/qPOz6O+fZVcdnilVFTW6c21gX/cVt06lftXk9AjfNOgOZywy0PR/qAb+x6vnTpf0gcfvLF8fDaF6O+hb9TA63vsaeei8HjZ5hvSVKC6lcxLn5V3jvWF5dIUrvp/tJu0afiIONAAutYkZlmVykAAADAnrEyDdAkWSMHAAAAAAAAAAAAAAAAFI7G3wT5WRRA7owcAAAAAHzlf6cyPYtSmScdiqHmrsuASXHevMWx5ZNPvY1tI55/6dVdh1oPOvib7nFJSkBX/PSmVhkPrlz8C59/M3bKOZdHfb2D3CGfGv+N1f76zkiNPtpzR7tVjxFHRvaEi+L7Nb+Jmto6tfFGTp7tvk9AA8YeFzvq6w1iQLO4//GX4pzLb45OlRP/8pwpGZSNY759efzx6T/7TgbtzKbNW+Lks39kziVJCarzzs7sMSieKS6N9cUlktQuurms987nX8Y4kLCKUpkPv953QrFdpQAAAAC7z6o0QJNkjRwAAAAAAAAAAAAAAABQOBol9IrKAAAgAElEQVR/E+RnUQC5M3IAAAAAsEuXESP+e4d0ZqGDMZSPBo+fEavve9Qb2Tak8ZDZhx9/JubMXRhdh05xn0tSK9Spsjpe3/hOq40FNdfe7Do0Q8fNvji279hhcgF51DhvHXf4bM8cNbmSQdkYd+TZMeeS2liwdE3U1NapnTT7wp/5N5CQ7lzziIEMaBavv/Xhrmf8ITMv+LtnTddhh8fx51wdj657def3s3ofFrQjy29bHd2HHWbeJUkJanLvUfFwaXmsLy6RpHbRBd338fxPYqnM/V8ZMeK/2FUKAAAAsHusRgM0SdbIAQAAAAAAAAAAAAAAAIWj8TdBfhYFkDsjBwAAAAB/o2O/zMSidOY9h2MoH02fdUG8sfFdb2bbmE8/2xorVt4bU48/Lzr2q3avS1ILdfiJ32v1MWDx0luiU6Vn/+5fw/Nj69ZtJhOQJ69vfCdOOvOH5qhqUqWDp8TYI8+OUy+4Pq782d1RU1undtiCpWui96jp/k0k5F0SQHOob2iIn978QFx+/aroNfKoz33m9Bp1dJw2d0k8/uxrsX1HvQ8N2omXX9sY44/8jrmXJCWoVOqg+EV5n1hfXCJJ7aJjeo3w/E9kmR/YTQoAAACwe6xEAzRJ1sgBAAAAAAAAAAAAAAAAhaPxN0F+FgWQOyMHAAAAAH+nqH9Vpw6pzBoHYygfdR9+WFxTuyJ21DuUtC16Y+O7sXDJ8hhWdYL7XZLy3G9+vyYRz/7frXowygYf6po0sUnHnhmffPqZyQPkweYtn8b8Rcs8m5Rz5UOmxkFHnxOzL/xZXHXjPVFTWyfFkadd7t9HAupcOXHXuwaA5vD7e5/d9YyffeENX/js6X/QzDj/quXx6LpXY/sO77GhPdi+Y0dcUnNDdKqsNgeTpKR8H0xl4sweg2JdSWmsLy6RpDbd2pKyGNnnQM//pJXK7NirYsJQu0kBAAAAms4qNECTZI0cAAAAAAAAAAAAAAAAUDgafxPkZ1EAuTNyAAAAAPD5stmvdUhXnd94OIRDMpSPxh0+O9Y+s8Fb2jas8fqeN29x9Bl1pHtekpq5niOmxWdbtybmmf/4U3+K1OijXZtc50HTTo9Nm7eYLEAz27Zte1y77Nao2P8ozxp9aV2HHR7jj/lefPvipXHV0jVRU1sn/U0/vObO6DLgEP9eEtD8RcsMckCzePbFt/7ynD9g2hlf+Ozp2K86xhz23bji+jvjifWvx44d9T5AaAfuf+Sp6D/2WHMwSUpQB/cZHfeVdov1xSWS1Ka7u7R79KgY79mfsIpSmRf+rVvmX2wmBQAAAGgaq88ATZI1cgAAAAAAAAAAAAAAAEDhaPxNkJ9FAeTOyAEAAADAF+qYzuzbIZV5xSEZykdd+k+K8+Ytjs1bPvW2tg3bunVb3LnmkZg557LoMmCSe1+SmqGzLl6UuOf9K6+/FaMO+Zbr8yWNO3x2fPjRxyYI0Izq6xviV7fdHYPHz/Cc0RfWfd8jInPc+THn0mVx1dI1UVNbJ31h444827+dBDRg7HGxo77egAfssU8+2xYLl/2fZ/xli1dG+ZCpX/4Oe8AhkT3h4vjJL+6NJ9a/7nkE7cAHH34cx82+2DxMkhJU79TBsbS8b6wvLpGkNt115RXRKZ3x7E9aqapr7CIFAAAAaBorzwBNkjVyAAAAAAAAAAAAAAAAQOFo/E2Qn0UB5M7IAQAAAMCXKqnM/t8dUpmfOyRD+Wrw+Bnxh7o/emPbDrz97vux6Ge/if2yJ7v3JWkPWrvu+UQ+5z/e/ElMO+n7rtE/6MDDTov3P9xkQgDNaM2DT+z6t+UZo39Uxehj45CZF8Z35/08FixdEzW1dVLOnXv5cv+OEtJdax4x6AHN4he/f/wvz/mZZ/1Hzs+hbsOnxcyzF8V1v3konn7+zahvaPBhQhv3yxWronzIFHMxSUpIHXd2cs9hsa64NNYXl0hSm21Oj8Ge+0kslXGgKQAAAEATWHEGaBLvoAEAAAAAAAAAAAAAAKCANP4myM+iAHJn5AAAAAAgZ0WpqhN39qmDMpSvps+6IF7f+I43t+3Ecy+8EhdeeX303e9I978kNaH9s6ck+vm+bdv2OOfSn7hW/7/GHT47PvzoYxMAaCaPPrk+DvnGWZ4v+rtKBh4a+0/9Tsw4a1Fc+tPfR01tnbRH9T9opn9bCXlnBNAcHn7q5b884xcsXRNDq09p0vNoSNXJcf6C38QNKx6J9S++FQ0NDT5UaMP+9OKrMWbKLPMxSUrSGknfMbG6tHusLy6RpDbZM8WlUdV7P8/8pJWqeqfLgIP+tx2kAAAAALmx2sz/x96dR3dV3ov+t/d3zx1+6977W/fcdU5PA4gJg6Ii3zCI4oB1xApJACM41qmgtYpDxalOBa0Tjokz4gBBFHAAK4oKEgSZFEQgCoqIzPNMQpLPj3BP762t1oQp+5u8Xmu9/2m7IPl+936eh7330w3USL6ZAwAAAAAAAAAAAAAAANJH1Z4g26IAqs/MAQAAAECNNMjuckSD7Nw5XpahfdUhx50dA4tGRXlFhSu49URpaVmMnTAteve9Lxq36+Y8kKSf6OnBb6TF+P7a2xOi+TE9fGc7O/2ca2P9hk0mfdgLPitZGGdffmc0bJ1nfNH/6YiTLopuvfrF9fcMiUcHfxgFRcXSXqv3zU84zxLQgW26xtLlq02EwB5bsXrT98b5/o+PisbtutdoTGq0c0zq1rt/DHj+/RgyenrMX7TKBwt1/B7Grfc949+hkpSgmqc6x1PNs6MkM0uS6mTTsppH61anG/MTVkZ2zp8POOCAn3mCFAAAAOCnudMMUCP5Zg4AAAAAAAAAAAAAAABIH1V7gmyLAqg+MwcAAAAANfaLNp3/34zs3Ke9LEP7stPOviZmfv6lq7j1zIpVa2Ng0ag4pUcf54Ek/UCN23WLVWvWp824/sVX38ZJ+VfV6++sywV9Y/2GTSZ52E1btpbGgm9XxfAxU6PrpXdEIy8x184y258Zx3e/Ji687pHo//ioKCgqlvZZD784Lpoe3dO5l4AGPDnUxAjsscrKiOdGfvy9sb7HFffu1rh08HHnxuW3PrPrz3j1nZmxePk6HzDUYX9+f1IcctzZ1mWSlKB6HXpcfJ7ZJEoysySpzvVas8OjcXaO8T5hZbTOucLTowAAAAA/zR1mgBrJN3MAAAAAAAAAAAAAAABA+qjaE2RbFED1mTkAAAAA2G0NW+d0zcjOWeOFGdpXNW7bLf744HOxecs2V3ProU9mfxE33vVEtDj+HOeDJP17l1z7p7Qbz0tLy+KuR16IRm3y6t33deZvbolNm7ea1KGaKisrY/W6zTH7y6UxdtIX8eKb06L/E6PjjF/funMM6WoeqMdVff9tO/WK7r3vit//aXA88uL4KCgqlvZb3Xv3dy4moLadLo7yigoTJrDH3pv8xffG+YdfHBeHnXDBbo9PR+f+Lu4seGPXnzVi7KxYunKDDxnqqMVLV0aXC/pam0lSgvrlEafGuCaHRElmliTVuf50SDtjfcLKSOVua3hE18M9OQoAAADwj7m7DFAj+WYOAAAAAAAAAAAAAAAASB9Ve4JsiwKoPjMHAAAAAHvk561yD2qQypnkpRnal7U+9aIYPnqcK7r1VGlpWYydMC16970vGrft5pyQVK97Z/yUtB3PP5z8abTrdEm9+a4uufZPu+Yw4MeV7SiPpSs3xIw5i2P0h3Pi2eGTo6CoeFe3PTIyTj77hmjYOs/4Xw9rtPN7b/ur3nHmZXfHdXe/FA+98MH/OTak2qj/46OMRwnpvQnTTKDAHpu/aNXfjfVX3Tloj8ang448M867ekA8OvjDXX/eGx/MjtXrNvuwoY7es7j5T09am0lSgmqe6hzPNM+OkswsSapzXXjY8cb6hJWRyp3Wpk2vf/LkKAAAAMCPc2cZoEbyzRwAAAAAAAAAAAAAAACQPqr2BNkWBVB9Zg4AAAAA9lzHjv8xIzvnrgbZORVenKF92a+v6hffLlnhym49tnzlmhhYNCpOPquPc0JSvSt18oWxo7w8rcfxTZu3xh/ueToatcmr09/VNbc/EuUVFSZu+BsbN2+PL75ZGR9OXxDD3v40CodOjIKi4u91y4BX44T866Jh6zxjfz2q6vtOnXJJ5F56Z1z1x0ExYNB7f3dsSLXdcd2vdr4moIuuvsuECuyx0rId8fjLf78WPa7bnl9zzD710rhpwLBdf17h0OIYM3FebNi0zYcOddAb7xTHIceebY0mSUm5vrSzKw89NuZkNomSzCxJqjN9mtk0jjmik7E+aaVy+3toFAAAAODHuaMMUCP5Zg4AAAAAAAAAAAAAAABIH1V7gmyLAqg+MwcAAAAAe02D1l1OzEjlLvHiDO3LmhyVHwOeHBplZTtc4a3nZs1dELfd/2wcfsJ5zg1J9aJ+Dw2qM2P4tJnz4qT8q+rk93T3oy9GZWWliZp6r3Tnen3pyg0xs2RJjJk4L54bOSUKiop/tL73Do1ju/Yx3teTMtufGcfkXRk9rrgnrr3rxRjw/Hv/8PiQktDV/V9w/iagxm27xdLlq020wB4b+d5nfzfW31nwejTaOc7s6VjVsHVe5Fx8RwwY9P6uP/eJlyfGuKnzY8u2Uh881DFfL1oSp/Twb1lJSlInHXFKjG9ySJRkZklSnWlskxbRPNXFOJ+kUjnlv2jV5RhPjAIAAAD8MHeTAWok38wBAAAAAAAAAAAAAAAA6aNqT5BtUQDVZ+YAAAAAYK/6t1T+vzRI5Yzy8gzt647LuzyKp8xylZfYXloao96dGBf26b/r5drOD0l1tS+++rZOjd/lFRXxwitvR8tfnl8nvp+Djuwew95438RMvVRWVh5LV26ImSVLYuykL6LorRlRUFT8kz06ZEL87vaB0b7zb43zdbwWHc+PU8+5IS68/pH4w0PD49HBH1brGJGS1GM7x6zDTrjAOZ2AHnzqZZMvsMdmzFn8g+N9997999p4dfBx58bV/V/4P3/2U69OiimfLYqyHeW+AKhDtm0vjev7FVqnSVKCOjTVOV5s3ipKMrMkqc70xMHZxviElZHK+ep/HZzz3z0xCgAAAPD33EkGqJF8MwcAAAAAAAAAAAAAAACkj6o9QbZFAVSfmQMAAACAfeFnDVI5fTKyc7d7gYb2ZQ1b50WfWx+O1Ws3uNrLLstWrI7CQSPi2NzLnSOS6lSdz7++zo7d6zdsijsHPBdNjspP2+/n8BPOi8nTPzcRUy/sKK+IZas2xqwvlsTYSV/EkNHTo3BocRQUVb8HBo6N865+MFp0PN8YXwfLan9WHNXliuj6mz/GFbc9E3966u0aHR9Skjvv6gHO8wR05OmXRnlFhUkZ2CMr12z6wbF+wPPvx8HHnrNXx61Tz71x1xr4L3/HsyM+jhlzFu8cyyp9EVCHjHxrfDQ/pof1miQl5VmCnV156LExJ7NJlGRmSVKd6Iqd45oxPmGlcgd6VBQAAADg77mDDFAj+WYOAAAAAAAAAAAAAAAASB9Ve4JsiwKoPjMHAAAAAPtMxhE52Q2yc0u8QEP7ukM7nhsDi0ZFhZeQ8ldmzV0QffsVxsHH9HSeSEr7Xho+ps6P28tXrok/3Pt0ZLXPT6vv5uSz+sTCb5eaeKk3tpXuiPmLVsW4qfNj0GtToqCouNrd8ehr0fnC2+KgI880tteRso7Kj6NzfxfdevWLy299Ju4seCMeGzKhRseFlE7d9+y7cWC7bs7/BPTehGkmZWCPVFZGPDvi4x8c7y//w1N7fdxqfuw5cdWdz33v7xk8avqutTVQd8xfuDhOzL/Sek2SEtTpLU+Oj5ocHCWZWZKU9s3JbBKnHXGK8T1h/aJVbp4nRQEAAAC+z91jgBrJN3MAAAAAAAAAAAAAAABA+qjaE2RbFED1mTkAAAAA2Kf+5dD8/9YgO2eQF2hof9T1ohujZP4iV375nu2lpTHq3YlxYZ/+cWCbrs4VSWlXk6PyY8PGzfVm3F62YnX0f/j5OLTjuYn/bm66+4ld8wzUV5WVEStWb4qpsxfF8HdnRuHQiVFQVPy9Hh38YVz1x0FxTN5V0bB1nnE9jWt2TM+d3+OV0b13/7jitmeiX+Gb8diQCX/3nUt1vdPOu8mYkIAuuvouEzGwx94unveDY33VGqd959/uk/HrlLNviPsGvvu9v+/VnWvppSs3+EKgjti6bXtcc/sj1mySlKAOT50RRc2OiJLMLElK+yY0OThatOpsfE9UOSv+LZX/L54UBQAAAPi/3DkGqJF8MwcAAAAAAAAAAAAAAACkj6o9QbZFAVSfmQMAAACA/aJhKvecBqncDV6ioX1d47bd4rb7n43NW7a5AszfWbp8dRQOGhHH5FzmfJGUNl1x0wP1cszesnVbPD/sz9Gx6xWJ+05aHH9OjB77kYkV/kbZjvJY+N2aGDd1fgwYOCbOvOzuOPjYc4zlaVbWUfnRvvPlccavb42Lfv9oXH/PkLj32XeioKhY0s5uGjDMWJGQ6z/LVqw2+QJ7ZPb8ZT863t/60Iho1Dpvn4xhzY85O353+7N/93eO/nBOrN/oujbUFcPeeD+aHn2WtZskJaSGO7uuRYeYk9UkSjKzJCmte7F5q2iUnWN8T1AZqdyRnhAFAAAA+L/cMQaokXwzBwAAAAAAAAAAAAAAAKSPqj1BtkUBVJ+ZAwAAAID9plGbvCYZ2TlTvEhD+6M2p10cb703yVVgftSsuQuib7/COPiYns4ZSYlu/KRP6/2Y/cnsL+IP9z4dR5x4fq1+FzvXs3HdHY/FqjXrTaTwA7Zu2x6vjvogul1yczRsnWcMT3hNOvSIdr+6LDqdf0ucd/WDce1dL8bdT74VBUXFkn6iNp16GUcS0INPvWzyBfbI+o3b/uF43+Wi2/bpOHZSz+vjvoHvfu/vfPzliTFu6vzYsq3MFwR1QMn8RXFCtyus3SQpQZ3R8uSY1OTgKMnMkqS07roWHYzriavLeZ4QBQAAAPjf3C0GqJF8MwcAAAAAAAAAAAAAAACkj6o9QbZFAVSfmQMAAACA/apNm17/1CCVc2+D7NxKL9LQ/ujCPv3ju2UrXQ3mR20vLY1R706MnpfdFg1b5zlvJCWqtp0ujvKKCoP1v9uxozw+nPxp3H7/s3Fs7uX77Xs4sE3XOO93d8ans7/0JcDf2La9NN56b1JcfsP90axDD2N3wso66qxoe/plceo5N0SPK+6Jy//wVNw84JV4YODYKCgqllSDXnxzWoybOj/mL1oVL7z6jjEmAR15+qXWysAee+GNaT869t//3LvR9Oie+3QsO/jYc+La/i/+3d/91CuTYspni2JHuXEO0t3mLdvid7c8aP0mSQnq8NQZMaTZEVGSmSVJaducnZ3e8mTjeoLKyM5Z16Bl14aeEAUAAADY9X8GCUD15Zs5AAAAAAAAAAAAAAAAIH1U7QmyLQqg+swcAAAAANSKX7TKO7VBdu5yL9TQ/qjp0WfFgCeHRlnZDleF+YeWLF8VhYNGRIcuvZ07khLRPQUvGZz/gYXfLo2hr4+Nvv0K45QefeLANl332md/dOde8Zvf3xOPPz8yli5f7cOGHzDz8y/jipseiI5dr4iDjuxu3K6FstqfFalTL4mO3a+JnItvj3P7PBC//cPTcdMDw+K+ge9GQVGxpN3shdenxvsffxklC1fE5q2l3xv/tm7bHod2PNc4lIDemzDNhAzskQ+mfPkP54OLrn90n49lDVvnRZeLbouHXvjg7/7+53fOR5/PXxaVlZW+LEhzQ0a8s/PfcPnWcJKUkA7c2R0t2se8zKwokaQ0bWKT5nFY6gzjeoLKSOWMOeCAA37m6VAAAACgvnOHGKBG8s0cAAAAAAAAAAAAAAAAkD6q9gTZFgVQfWYOAAAAAGrNvx7e5edVL5LwQg3tr04+q09Mn1XiyjA/qaKiMqZ+Ojf69iuM5sf0cP5IqpWqXqr91TdLDMo1sHXb9vi85Ot4671JUfj8yLih/+PR6/p7o+dlt8Wvzvt9HN/1t3FMzmVx+jnX7qrqP/v1Vf12/e8efOrlePmN92Ly9M9j46YtPkyoofKKilj03fIYP+nTGDTsrej/8PPxu1sejG4X3xRHd+4Vme3PNLbXoEY754CDjz0nsk+7NI7vfk10Ov+WOPPyP8VF1z8aV/d/IW5/9LUYMOj9KCgqlrSXGjjy4xgzcV58Pn9ZrN+47SfHvTseGGi8SkAXX3O3SRjYI19+s/Ifzg+PDv4wjjjp4v0yprU86cK4ZcCrP/hzFL01IxZ+t8YXBmluzhcL47i8y63jJClBdT/8lzE9q1mUZGZJUlpW1OyIODCVY0xPUBnZOZd5MhQAAACo79wdBqiRfDMHAAAAAAAAAAAAAAAApI+qPUG2RQFUn5kDAAAAgNr2s4xU7u8zsnNKvVRD+6OGrfOiz60Px5p1G1whplq2bS+NUe9OjJ6X3bbr+HEeSdpf5V10o0EYqFNWrVkfn5d8He9+ODWGvj42CgeNiH4PDYprbn8kLuzTP3IvvGHXy8UPP+G8OjemZ7Y/M1p0PD9an/ab6JB7ZZzU8/o449e3xpmX3R3nX/1g9L7lybju7pfi9kdfi3ufGROPDZkQBUXFkvZhg0dNj/c+/jLmfrU81m3YWuMx7atvlvg3YgJq3LZbLFux2iQL7Lat28p+cs7o0+/5/TauNWrTNXpccW88OvjDH/xZRo37PNZu2OKLgzS2cfOWuKzvfdZykpSgslv9Kt5oeliUZGZJUlp2/aFHG88TVc6mRm3ymngsFAAAAKjP3BkGqJF8MwcAAAAAAAAAAAAAAACkj6o9QbZFAVSfmQMAAACARGiY6twuI5U730s1tL867IRzY/CId6KystKVYqrtu2Uro3DQiDi6cy/nkaR93pCd8xRAfVVRURmr1qyPL79eHLPmLogJH8+M18d8FE8Nfiv++MjQ6HPnM3He1QOixxX3Rvfed0Xni26PX13whzipZ984vvs1cUzeVbs6qvNvo22nXt/riJMu3vnvgQui9Wm/+bv/7q87OueKXX/GsV377Ppzqzr9/JvjjF/fGjkX377r7z3nqgfi19c9HJfeWBi/u/3ZuLrfC3H9PUPiloeGR7/CN+PeZ8bEoy+Nj4KiYkm1WOHQiVH01owYN3V+lHy9IjZu2b5XxqqzL7/dujUBPfT0MBMnsEeG/vmTn5xLOuReuV/Htra/6h1/LHjzB3+Wx3fOa1Vz2tbtZb48SGNPvvh6NG7bzXpOkhJSZionBhzcNkoysyQp7Zqb2SS6tDzJeJ6kUjnFBxxw+3/wVCgAAABQX7kjDFAj+WYOAAAAAAAAAAAAAAAASB9Ve4JsiwKoPjMHAAAAAInxvw7O+e8Z2bmDvVhD+7Nul9wcX3z1ravF1EhFRWVM/XRu9O1XGM069HAuSdrrNT36rNi4eYsBF+AfKCsrj6UrN8SMOYtj9Idz4tkRH0dBUbEkxVOvTIoRY2fFpJkLY+F3a6K0bMc+GYfe/uBja9cEdOTpl0Z5RYWJEdhtEz/5+ifnlj88NDwats7br+PbQUeeGZfeWPijP9MzwyfvWgsbAyF9fTT1szjixPOt6SQpQV10WMeYldU0SjKzJCmtmpzVPA5vdYaxPEFlpHJ/74lQAAAAoL5yNxigRvLNHAAAAAAAAAAAAAAAAJA+qvYE2RYFUH1mDgAAAAASp0Eq54IG2TmbvFxD+6vG7brFbfc/G1u2bnPVmBrbuHlLDB89Lnpedtt+f7GupLrblbc8aIAF2A1rN2yNeV8tj/FT58crYz6NJ4Z9FAVFxZLqcI+/PDGG7Tzfq877uTvP/9XrNkdlZeV+GXPKKyriqDN+Y/2agN4vnm4SBHbbN0vWVmvO6XTezbUyxv3yrN/HA8+N/dGfa/Co6TF/0SpfJKSpZStWR5cL+lrTSVKC6njEqfFBk0OiJDNLktKql5u1jANTOcbyhJSRnbu9YZvclp4GBQAAAOojd4IBaiTfzAEAAAAAAAAAAAAAAADpo2pPkG1RANVn5gAAAAAgkX7eKvegjFTuZC/Y0P7smJzLYvykT105ZrctWPhd3P3oi9H61IucU5L2qOIpswyqAHtBRWVlrFm/JUq+XhETpn8VI8bOiqdemRQFRcWS0rQX35wWYyd9ETNLlsTSlRtiR3lFrY4zjzz7ivVrArrk2rtNesBuK9tRHk+8PPEn56A/PfXnOOjIM2tlnGvR8fy48f6X/+HP9/r7s2P1us2+UEhDpaVlcX2/Qus6SUpQzVNd4pnm2VGSmSVJadWNLY42jierT9q06fVPngYFAAAA6ht3gQFqJN/MAQAAAAAAAAAAAAAAAOmjak+QbVEA1WfmAAAAACCxmjbt9J8zUrkPNsjOrfSCDe3PLuzTP5YsX+UKMrutoqIyJnw8M3r3vS8at+vmvJJUo448/dJd4wgA+0ZlZWWsWb8lvli4MiZ+8nW89t5n8fSrk6OgqFhSwnrxzWkxZuK8+GTu4vhuxfooKytP3JiycvW6OOjI7taxtVzjtt1i2YrVJjlgt40cO6tac1P+5X+qtbGuUZuucd7VA+KxIRN+9Od7fOjEGDd1fmzdVuZLhTT00vAxkdn+TOs7SUpIDXd25aHHxpzMrCiRpDRpbmaTyGl5knE8QWWkcm73JCgAAABQ37j7C1Aj+WYOAAAAAAAAAAAAAAAASB9Ve4JsiwKoPjMHAAAAAImXkco5eWdLvWRD+7NmHXpE4aARUV5R4Uoye2T9hk0xeMQ7cfJZfZxbkqrV/Y8PMXgC1Ma6beO2mL9oVUz5bFG8XTwvBo+eHo8PnRgFRcWS9nFPDvsoXn1nZnwwZX589uXSWLpyQ5SW7Uib8eOKmx6wjk1ADz09zGQG7LapsxdVa8568PkPovkxZ9fqeNch98q45+m3/+HP+czwyTFjzmLXtyENfTZvQbT/1aXWd5KUoDq3PDkmZzWPkswsSbwHKuUAACAASURBVEqLJjU5OA5PnWEMT0qp3B0NU53beQoUAAAAqE/c+QWokXwzBwAAAAAAAAAAAAAAAKSPqj1BtkUBVJ+ZAwAAAIC0cGCbrr9okMp5z4s2tL87tefVMeOzEleT2StmzV0QffsVxsHH9HR+SfrBGrbOi4XfLjVgAiRERUVlrFm/JeYvWhVTPlsUYybOi6K3ZkTh0OIoKJK0Oz332pR444PZMWH6V1Hy9Ypd51hlZWVajxVTPp1rLZuA2v/q0iivqDB5Abtl6coN1Z7LLrj24Vof85ofe05cd/dLP/mzDh41fddaFkgvK1evi26X3GyNJ0kJqlWrM2J408OjJDNLktKiwc1bRaPsHGN4QsrIzv28adNO/9lToAAAAEB94a4vQI3kmzkAAAAAAAAAAAAAAAAgfVTtCbItCqD6zBwAAAAApJOfNUjl9MnIzin1sg3tzxq2zos+tz4ca9ZtcFWZvWJ7aWmMendi9Lzstl3Hl/NM0l+qelkuAMlXtqM8VqzeFHO/Wh4fffJ1vDnu83j+9alRUFQs6d+rOife+GB2fDhtQcz+cml8t3x9bCvdUWfHhdPOvsZ6NgF9MHGGSQrYLRUVlfHUq5OqNcc9+tL4OOyECxJx3Tr30jt3/Tw/9TNXzclr1m/xRUMa2VFeHnc98oI1niQlqAN3dkeL9jEvMytKJCkNuq5FB+N3gsrIzrnL458AAABAfeGOL0CN5Js5AAAAAAAAAAAAAAAAIH1U7QmyLQqg+swcAAAAAKSdBq27HNUgO/drL9vQ/u6wE86NwSPeicrKSleX2WsWLPxu14sxUyf/2nkmKYa+PtbACJDGyisqYsOmbbHwuzUxY87iGDd1frzxwex48c1pUVBULNW5Hh86cdfxXXWcT5j+VXw+f1ksXbkhSsvK6935/9LwMdazCejia+42GQG7rWo+q+4c2OvmJxMz9rXvfHn86am3f/JnLhxaHGMnfRFbt5X5siGNjHxrfDQ9+ixrPUlKUGcdfmLMyGoWJZlZkpTo5uzslJanGLuTUip3R6PsnLae/gQAAADqA3d6AWok38wBAAAAAAAAAAAAAAAA6aNqT5BtUQDVZ+YAAAAAIC3985Gd/kdGds4QL9xQbdTt4puiZP4iV5jZq8orKmLCxzOjd9/7onG7bs41qR7WrEOP2LR5qwERoI4qKyuPlWs3xfxFq2L6nMXx/sdfxsixs+K5kVOioKhYSmyFQyfGC29Mi9ffnx0fTJkfM3Yev199uzrWbtgSFRWVTu5/t3nLtjjkuLOta2u5xm27xbIVqx2QwG6Z9vm31Z4fHx0yIVqdckmCrin0jOvufqlaP/szwyfHZ18sjYpK8ziki7lfLowOXXpb70lSgjr6iE4xpmmLKMnMkqREN67JIdE81dnYnZRSOXMbd+z4Xzz9CQAAANR17vIC1Ei+mQMAAAAAAAAAAAAAAADSR9WeINuiAKrPzAEAAABAWmuQyrmgQXbuZi/dUG28pPm2+5+NTZu3utLMXrdi1doYWDQqTsy/0vkm1aOuvu0RAyBAPVW2ozxWrt0U8xetihlzFsf4aQti9Idz4uU/fxLPDp8cBUXF0j7tyWEfxdCdx9tbE+bGxE++jtlfLo1FS9fGuo1bo7yi0klaTX+492nr2gT08DPDHIzAblmyYn2N5s+r7hyUqPGvUeu86Pm7e+OxIROq9fMPGT09vl22zhcPaWLj5i1x8TV3W+9JUoJqmt0lnmqeHSWZWZKU6J7eOVYZtxNUKrefpz4BAACAus4dXoAayTdzAAAAAAAAAAAAAAAAQPqo2hNkWxRA9Zk5AAAAAEh7v2jT+ZAG2TmfeumGaqM2p10cw0ePc7WZfWbW3AXRt19hND+mh3NOquN9NPUzgx4AP2hHeUWs3bAlvl22LuZ+tTymzl4U73/8ZbzxwewYMnpGPDnsoygoKpZ+sMKhE2PQa1Ni+Lsz4+3ieVE846uYWbIkFny7Kpat2hhbtpY6yfaSL79eHA1b51nb1nLtOl0S5RUVDkigxsp3rrmeeLlm66r2nS9P3DjYsfs18cBzY6v9O4z+cE5s3LLdAQBpoLKyMgoHjYhGbaw5JSlJ9Tr0uJiT2SRKMrMkKbFVjVXG7ISUyt3RKDunrac+AQAAgLrM3V2AGsk3cwAAAAAAAAAAAAAAAED6qNoTZFsUQPWZOQAAAACoE5o27fSfM7JzH2mQnVvp5RuqjS64ql8s+m65q87sMxs3b4nho8dFz8tuc85JdbD2v7o0KioqDXYA7LZtpTti9brNsfC7NTH7y6UxeebCGDv5i3hz3Ocx9M+fxHMjp0Th0IlRUFSsOtTTr06OIaOnx8j3PosxE+fFhOlfxSfzvosvv1kZS1duiE1btkdFpTXG/nRWr1utbxPQBxNnOBiB3TL83Vk1motvuG9oIsfBQzueH7cMeKXav8eTwz6KKZ8tivKKCgcBpIGxE6ZFi+PPse6TpAR1esuTY3JW8yjJzJKkRPZZVpM4/ohTjdnJaU7V846e+gQAAADqKnd1AWok38wBAAAAAAAAAAAAAAAA6aNqT5BtUQDVZ+YAAAAAoE7JyM7JaZDKWe3FG6qNmhyVHwOeHBqlpWWuPrNPzV+4OO565IVoddIFzj2pjlQ1fwDAvlZZGbFlW1msXrc5vl22LkoWrohP530Xkz5dGO9//GW8NWFujBg7K4remhHPjfw4Hh86MQqKirUfe2LYRzHotSm7voOR730WYybOiwnTv4pps7+NOQuWxcLv1sTy1Rtj05btUV5e4aBOoLfem2R9m4AuufZuByOwWybNXFjj+fu4blcncixs3K579L75iRr9LoNHTY9vlqx1IEAaWLDwuzih2xXWfpKUoFKpX8VrzQ6PkswsSUpkY5q2iKxUF2N2Ysr5o6c9AQAAgLrKHV2AGsk3cwAAAAAAAAAAAAAAAED6qNoTZFsUQPWZOQAAAACoc/718C4/z0jljPHiDdVWx+RcFuMnfeIKNPtcWdmOGDthWvTue180btvN+SelaQ1b58U3i5cZ1ABIpO2lO2L9xm2xfPXG+Gbp2vjym5Xx+fxlMWPO4pg8c2GMn7Yg3p1UEqM/nBMjx86KoX/+JF54Y1o8M3xyPPHyR1FQVFyveuqVSfHcyCnx0pvTYtiYT+O19z6LUePnxDsT58W4qfN3fWafzPsu5ixYHl8tXh1LVqyP1es2x+atpbGjvMIBVwfsKC+Ptp0uts6t5ar+jbx85RoHJFBj3yxZU+P5/5aHhu/6t31Sx8TTzrspHn5xXI1+p6q13YZN2xwQkHCbt2zbdX/A+k+SktNB2Tkx4OC2UZKZJUmJbMAhbY3XSSmVu+MXrfPaeNoTAAAAqIvczQWokXwzBwAAAAAAAAAAAAAAAKSPqj1BtkUBVJ+ZAwAAAIA66vb/0CCVe3PVyye8hEO11YV9+seS5atciWa/qHpZeOGgEdGhS2/nn5Rmdb/0ZoMYAHXa9tIdsWVraWzYtC1Wrt0Uy1ZtjG+XrYuvvl0dX36zMj6fv2xXM0uWxIw5i3c1edY3MWnmwpj06cIYN3X+rt77+MsYM3HeP+zNcZ/HGx/M/l5vTZj7g//b93f+eX/5s6saP23B//47d/aXn+OzL5fu+tlKvl4R8xetiq8Wr971sy9evi5WrtkU6zZsjU1btu/6HeEvBjw51Do3AT3y7CsORqDGSst2ROHQiVFQVFyjOna/JtFjYpvTe8ddT75Vo9/pyWEf7VoXle0od2BAglVWVu5a9zRqk2cNKEkJ6qLDOsasrKZRkpklSYnr/MM7GqsTUkZ2zsxDD83/T571BAAAAOoad3IBaiTfzAEAAAAAAAAAAAAAAADpo2pPkG1RANVn5gAAAACgTmuY6twuI5U730s4VFs169AjCgeNiPKKClek2W9mzV0QffsV7jr+nIdS8nvlzfcNXAAAdciKVWujcbtu1rq13NGde0VFRaUDEqixoX/+JAqKimvUHx4aHg1b5yV6XGx6dM+4/p4hNf7dnn99apR8vcKBAQn3fvH0OOTYs60DJSlBndDytBjf5JAoycySpEQ1I6tZtG11urE6Od3hKU8AAACgrnEHF6BG8s0cAAAAAAAAAAAAAAAAkD6q9gTZFgVQfWYOAAAAAOq8fz6y0//ISOW85AUcqs1O6dEnps8qcVWa/Wrjpi0xeMQ70fWiG52HUkJr1qFHbN6yzYAFAFDH9O57n/VuAvpw8qcORqDGPpy2IAqKimvcL8+6LvHjYqM2XeOi3z+6W7/f6+/PjjXrtzhAIMHmzf8mjjrjN9aBkpSgDk+dEcOatYySzCxJSlSvNz08DszOMVYnoVTujl+0zmvjKU8AAACgLnH3FqBG8s0cAAAAAAAAAAAAAAAAkD6q9gTZFgVQfWYOAAAAAOqNBqmcCxpk52zyMg7VVg1b50WfWx+ONes2uDrNfvfFV9/GXY+8EC1/eb7zUUpQ197+qAEKAKAOmjRttvVuAurd9z4HI1BjXy5aFQVFxTXu9kde23UNOB3GxzN+fWs8OvjDGv+Oj788MSZM/ypKy8odKJBQa9dvjDN/c4u1oCQlqANTOXFHi/YxLzMrSiQpQd12yFHG6YSUkZ0zs02bXv/kCU8AAACgrnDnFqBG8s0cAAAAAAAAAAAAAAAAkD6q9gTZFgVQfWYOAAAAAOqVn7fKPahBKmeSl3GoNjvshHNjYNGoqKiodJWa/a60tCxGvTsxLuzTPw5s09U5KdVyH8/43MAEAFBHnZh/pTVvLXfQkd1j1Zr1DkagRrZsLY2CouLd6sQev0+bMfKozr+Ne599Z7d+z+demxIlX69wsEBClZXtiOvueMx6UJIS1lmHnxgzsppGSWaWJCWiuZlNonPLk43RCSkjlXObpzsBAACAusJdW4AayTdzAAAAAAAAAAAAAAAAQPqo2hNkWxRA9Zk5AAAAAKh3Dj00/z81yM55oEF2bqUXcqg263rRjTFv/jeuVFNrlq1YHYWDRsTRnXs5J6VaqOrcq6ysNBgBANRRg4a9Zd2bgAqfH+lgBGrsxTenRUFRcY27/ZHXomHrvLQZIw874YK4/dHXdut3rWrk2Fmxet1mBwwk1FMvvR4HtulqTShJCeqoVp3inaaHRklmliQlouKsg6NFq87G6ASUkZ1T2rBNbktPdwIAAAB1gbu1ADWSb+YAAAAAAAAAAAAAAACA9FG1J8i2KIDqM3MAAAAAUG9lZOeelJHKXeKlHKrNGrfrFv0eGhSbt2xzxZpaU1FRGeMnfRq9+94XBx3Z3bkp7acefOplAxAAQB22afPWOOTYs619a7kOXXpHZWWlAxKokfcmfxEFRcW71cln35BW42Rm+zPjyjsH7vbv+/jQiTFh+ldRVlbuwIEEGj/pk2hx/DnWhZKUoJqnOseg5qkoycySpET0dPNs43NCysjOnXpAfv7/48lOAAAAIN25UwtQI/lmDgAAAAAAAAAAAAAAAEgfVXuCbIsCqD4zBwAAAAD12r8e3uXnGanct72UQ7Vd61MviuGjx7lqTa1bv2FTDB7xTpyYf6VzU9qHNWqTF98uWWHQAQCo4266+wnr3wT00dTPHIxAjcxZsCwKiop3qzseeyMatc5Lq3Gy4c6ft+eV98VjQybs9u896LUpUfK1ax2QRF9+vTiOybnMulCSkrT+2tl1LTrE3MwmUZKZJUm13qWHHW98TkgZ2TnXeqoTAAAASHfu0gLUSL6ZAwAAAAAAAAAAAAAAANJH1Z4g26IAqs/MAQAAAAAHHPCzqpdRZGTnbvdiDtV2Z/W6NeYvXOzqNYkwa+6C6NuvMJoefZbzU9oH4z0AAHXfvPnfWP8moCtuesDBCNTIug1bo6CoeLc7+ewb0nK8PKln33johQ/26HcfNX5ObNi0zUEESRvX1m+KHr1vtTaUpITVveWJMSOrWZRkZklSrTYzq2kc1aqTsTkZbT6wbbcsj3QCAAAA6cwdWoAayTdzAAAAAAAAAAAAAAAAQPqo2hNkWxRA9Zk5AAAAAODf/aJN59YNsnNLvJhDtV2To/LjoaeHRWlpmavYJMLa9Rvj6cFvxAndrnCOSnup4aPHGVwAAOqJvItutAau5TLbn7nr37YANTFw5MdRUFS8W932yMho2DovLcfM1p1+E/c8/fZu/+5VPTnso5g+Z3GUV1Q6kCBBdpSXx81/etL6UJISVvtWneKdpodGSWaWJNVqbzY9LBpn5xibk1Aq570DDjjgZ57oBAAAANKVu7MANZJv5gAAAAAAAAAAAAAAAID0UbUnyLYogOozcwAAAADAX2l4VP5/zcjOfcTLOZSEOnTpHe8XT3clm0SZNXdB9O1XGM069HCeSrtZ82N6xOYt2wwoAAD1xPDR46yDE9DTg99wMAI18taEuVFQVLzbnXDmtWk7Zh583Llx60Mj9uj3r2rwqOnx7bJ1DiZImMEj3onG7bpZI0pSku4dpbrEwOatoiQzS5JqtTtatDcuJ6SM7JyLPc0JAAAApCt3ZQFqJN/MAQAAAAAAAAAAAAAAAOmjak+QbVEA1WfmAAAAAIAf0CA7t3tGdu5aL+hQErqwT/9YvHSlK9okysZNW3a9ePPUnlc7T6Ua9vs/FhhEAADqkdLSsjjixPOthWu5jl2viMrKSgckUG3TPv82CoqKd7tbBrya1uNmZvsz4+p+L+zRZ/CXxkycF1u3lTmoIEGmfDrXGlWSElbDnd3U4qiYl5kVJZJUS83NbBJdWp5kXE5AGamc9Q1bndHAk5wAAABAOnJHFqBG8s0cAAAAAAAAAAAAAAAAkD6q9gTZFgVQfWYOAAAAAPgRv2jT+cAGqZxiL+lQEmp69Fkx4Mmhu17EDUkza+6C6NuvMJof08P5KlWjqhfWAgBQv/zxweesha3FgTTz7bJ1UVBUvEcdk3dVWo+bjVrnxcV9C/b4c6jqmeGTY2bJkqisrHRwQUJ8s3hZ/PLMK60TJSlhnXtYx5iZ1TRKMrMkqVaa2KR5tGjV2ZichFI5b3qKEwAAAEhH7sYC1Ei+mQMAAAAAAAAAAAAAAADSR9WeINuiAKrPzAEAAAAA/0jHjv+xQXbuHQ1SOeVe1KEkdEK3K2Li1FmubpNIGzdviRdffTs6nX2t81X6kY7NvdzLowEA6qFvFi+Lhq3zrIlruT63PuxgBKqttGxHFA4tjoKi3a/vPUV1YvzMvfTOeGzIhD36LP7SsDGfxorVmxxgkBCbNm+Ni66+y1pRkhLWcUecFuOaHBIlmVmSVCs92zxlPE5O3T3ECQAAAKQbd2IBaiTfzAEAAAAAAAAAAAAAAADpo2pPkG1RANVn5gAAAACAamjQKveEjOycxV7SoaR0YZ/+sWT5Kle5SaxZcxdE336F0axDD+es9Fc98uwrBggAgHqqR+9brYlruSZH5cf6DZscjEC1DR49PQqKiveoozr/tk6MoSf1vD4efnHcHn8eVT0+dGJMmP5VlJaVO8ggAcorKuKuR16wXpSkhNWiVecoanZElGRmSVKt1OvQ44zHCSgjlbvswJZn/E9PcAIAAADpxF1YgBrJN3MAAAAAAAAAAAAAAABA+qjaE2RbFED1mTkAAAAAoJqy2uT/fw1SOS97WYeSUrMOPWLAk0OjrGyHq90k1sZNW2LwiHfipPyrnLeq9zVqkxffLVtpYAAAqKdGj/3IujgBPffyaAcjUG1jJ30RBUXFe9Q1/V+oM2PokWdcHvc9++4efyZ/adBrU6Lk6xUONEiI196eEE2OyrdmlKQEdWAqJ+5o0T5KMrMkab83M6tptG/VyXichFK5Az29CQAAAKQTd18BaiTfzAEAAAAAAAAAAAAAAADpo2pPkG1RANVn5gAAAACAGspI5V2ekcrZ6oUdSkrHd/1tTPh4piveJN6suQuib7/CyGrvpZyqn519+e0GAgCAemzHjvLIPuVCa+Na7uSz+jgYgepfz/piSRQUFe9Rjw2ZEG069aoz42jLky6M/o+P2uPP5a8bNX5ObNi0zQEHCTD107nR8pfnWzdKUsI6//COMSuraZRkZknSfu3NpofFgdk5xuLarzIjO/ckT24CAAAA6cKdV4AayTdzAAAAAAAAAAAAAAAAQPqo2hNkWxRA9Zk5AAAAAGA3/Ft2XouM7JyZXtihpNSwdV70ufXhWLl6nSvfJF7VcVo4aEQc3bmX81f1qtf+/KEBAACgnruvcIi1cQL6ZPYXDkagWpav3hgFRcV73O9uH1inxtEmHXrEDfcN3SufzV96cthHMeWzRVFeUeHAg1q26Lvl0bHrFdaNkpSwOh5xaoxvckiUZGZJ0n7t5hZHG4cTUc7Cfzk0/795chMAAABIB+66AtRIvpkDAAAAAAAAAAAAAAAA0kfVniDbogCqz8wBAAAAALup4VH5/7VBdk6hF3YoSbU4/pwYWDTKi0dJCxUVlTHh45nRu+990bhtN+ew6nSHHHd2bNte6sQHAKjnvlu2Mg5s09UauZa77o7HHIxAtVRdZ33i5Y+ioKh4j3psyIQ44qSL69RY2rhd97jyzoF7/Nn8bUNGz4glK9Y7+KCWrV2/MbpedKO1oyQlrENTnWNos5ZRkpklSfutOTs7ueUpxuEklMod4KlNAAAAIB244wpQI/lmDgAAAAAAAAAAAAAAAEgfVXuCbIsCqD4zBwAAAADsoV+0ys1rkMpZ7cUdSlKn9rw6ps8qcRWctLF85ZooHDQi2nW6xDmsOtn1/Qqd6AAA7PLrq/pZI9dyzTr0iI2btzgYgWp59Z2ZUVBUvMddekNhnRtPG7XOi0tvLNwrn8/fNnbSF7Ft+w4HINSi7aWlcfkN91s/SlLCOnBn9xzSLkoysyRpv/VBk0OiaXYX43Btl8opb5jq3M4TmwAAAEDSudsKUCP5Zg4AAAAAAAAAAAAAAABIH1V7gmyLAqg+MwcAAAAA7AX/eniXn2ekcsZ4eYcS9ULTNnlxfb/CWLt+o6vhpI0dO8rjjXeKI++iG53HqlNNn1XiBAcAYJexE6ZZIyegl4aPcTAC1fLh9AVRUFS8xz3y4vhofuw5dXJM7d77rr3yGf1tz438OEq+XuEghFpUWVkZA54cav0oSQms16HHxZzMJlGSmSVJ+6X7D2lr/E1AGancWW3a9PonT2wCAAAASeZOK0CN5Js5AAAAAAAAAAAAAAAAIH1U7QmyLQqg+swcAAAAALD3/KxBKqdPRiqnzAs8lKQO7XhuDCwaFeUVFa6Kk1Zmz/sq+vYrjKZHn+VcVlp3XN7lu14+CwAAVSoqKuOoM35jrVzLndKjj4MRqJaSr1dEQVHxXqnnlffV2XE19+I747EhE/baZ/XXjRo/JzZu2e5ghFr08hvvReN23awjJSlhnd7y5Pg4q3mUZGZJ0n6p++G/NP4moIxU7u89qgkAAAAkmTusADWSb+YAAAAAAAAAAAAAAACA9FG1J8i2KIDqM3MAAAAAwF6WkZ13dIPsnIVe4KHEvVDrnGvjk9lfuDJO2tmwcXMMLBoV7X91qXNZadljA191IgMA8D2PPPuKtXICmjV3gYMR+ElrN2yNgqLivdL9z70bBx15Zp0dV08776Z4dPCHe+3z+uueemVSzJizOCorHZNQW8ZP+jQOOfZs60hJSljtWp0e7zRpESWZWZK0z/s4q3kcnjrD+Fv7bf55q9yDPKkJAAAAJJW7qwA1km/mAAAAAAAAAAAAAAAAgPRRtSfItiiA6jNzAAAAAMA+8M9HdvofGdm5g73AQ0mrUZu86HPrw7F2/UZXyEk7FRWVMXbCtOh52W3RsHWec1ppM+4uWb7KCQwAwPesXL02GrfrZs1cy9141xMORqBanhk+OQqKivdKuRffWafH1o5nXhMPvfDBXvu8/rbh786KNeu3OCihlpTMXxRHnn6ptaQkJaym2V3i2eapKMnMkqR93sDmrYy9CSgjlfu2pzQBAACApHJnFaBG8s0cAAAAAAAAAAAAAAAAkD6q9gTZFgVQfWYOAAAAANiHGqRyLmiQnbPJizyUtA474dwYWDQqKioqXSknLc1fuDhuu//ZaNahh3Naie7sy293wgIA8IN6973PmrmWa35Mj9i0eauDEfhJb3wwOwqKivdK/Z8YHY1a59Xp8bXdry6L+597d699Zn/b4y9PjEkzF0Z5RYWDE2rBilVr4/RzrrWelKSE1XBnN7U4KuZlZkWJJO3jfnPYccbeBJTROu8sT2gCAAAASeSuKkCN5Js5AAAAAAAAAAAAAAAAIH1U7QmyLQqg+swcAAAAALCP/fyILpkZqdzJXuShJNbt4pti3vxvXC0nba1dvzEefmZYtDrpAue0EtnIt8Y7UQEA+EHFU2ZZMyegotfGOhiBnzR51jdRUFS81zqp5/V1fnxtdcol8aen/rxXP7e/bfCo6fHdivUOUKgFW7Zuiwv79LeelKQEdt5hJ8SsrKZRkpklSfusmTvHmSNbnW7creUyUrnLDmx5xv/0hCYAAACQNO6oAtRIvpkDAAD4/9m78yipykPR28l3c4ez7jrnfitZ6yTpBkkXQyNjdTcoigoOUVSoahrLWYMTiaLibOJsxGg0GIfGeTY0zkbUaJwwtAOCOKK2EqMIKiAyTw3d/V7LdW5WEhmqoKt2VdfzrPX7z792vcOm937dAAAAAAAAAAAAQPFInwlyLAogc3YOAAAAAMiHIUO+V16VvKi8KtHqgx4qtLoMqAsXXHlrWLFqtb+aU7Sam9eHBx+fGnYbeYJ5rYKpx+CDwqrVa01QAAA2qq2tLexae7x754gbfsSZBiOwRR/NWxzqGxrbrXMn3F8Sa2zvoUeESyZOaddr969NnNwY/vLaX8P69S0GKuRZS2trOO/ym91TSlIBNrTfPmFa18rQVBGTpJz1ULc+Ybt4wrobcWXxxI1ezgQAAAAKjaepAFlJ2TkAAAAAAAAAAAAAAACgeKTPBDkWBZA5OwcAAAAAwDrRsAAAIABJREFU5FFZPLHX133ugx4qxKr3Pio88qe/fPNRbyjmj3hOefrFsO+hp5nXirzTL7rOpAQAYLNuvPuP7p0LoNlNfzMYgc1asWpdqG9obNcGjRhbEmtsj10ODef//qF2v37/2h2PvBo++nSxwQoRuHXSlNC5ptZ9pSQVWP367xf+2K1PaKqISVLOOqPXztbcyEu0/rimdhdvZgIAAACFxFNUgKyk7BwAAAAAAAAAAAAAAABQPNJnghyLAsicnQMAAAAA8uw/+4z4YVk88ZQPeqhQqzvmnPDehx/7CzpFb8Yb74XR48aHTtU+5qlomj5rtokIAMBmLVm2InQdlHL/HHHnXX6zwQhs0S0PvhLqGxrbrZN/fUfJrLOxr/e6s6+Y3K7Xb1M9/pd3w6o1zQYs5NkTz77svlaSCrCfVCXCtZXVoakiJkk5aXZF17Brv32suRFXVpWc3atX6n94MxMAAAAoFJ6gAmQlZecAAAAAAAAAAAAAAACA4pE+E+RYFEDm7BwAAAAAEI3vlsWTp5dVJZp92EOFWJcBdeGCK28NK1au9pd0it4tk6aY18p7Ow0fE9ra2kxAAAC2aNz5V7uHjrjtdzs0rF3XbDACm/Xws2+H+obGduu6SdNC3z1Hl8xa+5MdDghnXDapXa/hprrlwVfC7DlfGLSQZ7Pebgr99jjC/aUkFWAn9dolvFfRNTRVxCSp3XuiW+/QpSphvY24sqrEuV7JBAAAAAqFp6cAWUnZOQAAAAAAAAAAAAAAAKB4pM8EORYFkDk7BwAAAABE6Mc1w6vLqxIf+LCHCrU+Qw8PtzU8Flpb2/xFnaJ2y6Qp5rTy2oQbJ5t4AABkZOab77uHLoAeeOx5gxHYrGmvfRTqGxrbtaPOuLak1trtBtaFcZfc2e7XcVM9/OzbYenyNQYv5NHc+QvC0Lqx7i8lqQAb2WePMCvWPTRVxCSp3Ttv+x2ttRFXVpVcV9Y3UemNTAAAAKAQeHIKkJWUnQMAAAAAAAAAAAAAAACKR/pMkGNRAJmzcwAAAABAxDoNSv1bWVXyGh/3UCG372Gnhzfe+dBf1Slqt0yaYj4rL3Wqrg2fzPvCpAMAIGP7HHKqe+moPy5+1C8NRGCz3v3rglDf0NiuTbjzuRAblCqp9bbzgLpw8sV3tPu13FQ33vdSePXtuaG1tc0ghjxZtnxlOOC4c91jSlIBtnP/YWFqt56hqSImSe3au1+3Z7+fWmsjrqwqMfU73/nOd72RCQAAAETNU1OArKTsHAAAAAAAAAAAAAAAAFA80meCHIsCyJydAwAAAAAKRFlV4uCyeGKZD3yoYD92WlMbxp1/dfhq6XJ/Xado3TJpivmsnFd3zDkmGwAAWbnr/ifdSxdAH3z0qcEIbNLCr1aG+obGdi9xzEWl97fmAXXh5Itvz8n13FT3/un1sHDxSgMZ8qS5eX0Ye84E95iSVIBt3394uK9739BUEZOkdu3pbtuHWHyEtTbq4okjvYkJAAAARM0TU4CspOwcAAAAAAAAAAAAAAAAUDzSZ4IciwLInJ0DAAAAAArID/uNqCiLJ1/xgQ8Vcr2HHhZua3gstLS2+is7RemWSVPMZeW0yX98xkQDACArK1atDj0GH+R+OuIuvPJWgxHYpA0treH6yS+G+obGdu3X9VNCp+rakltzO9eMDGMvvLXdr+fmSv9+L7/x8Te/JZB7bW1t4eIJt7vPlKQCrEtVIlxTWROaKmKS1K6N77mDdTbyEovKBtb+wJuYAAAAQJQ8LQXISsrOAQAAAAAAAAAAAAAAAMUjfSbIsSiAzNk5AAAAAKDQDBnyvfKq5EXl8USLj3yokNv/iDPCm7M/9Jd2itLtkx8PnWtqzWW1e10HpcKKlatNMgAAsnbWJRPdU0dcn6GHh3XNzQYjsEkNT8wK9Q2N7d6udaeU5Lrbubo2/PycG3JyTTfX3VNmhs8WLjOgIU9unTTF3+MlqUA7qdcu4b2KrqGpIiZJ7VJ6Tdmv717W2Igrq0rc4iVMAAAAIEqekgJkJWXnAAAAAAAAAAAAAAAAgOKRPhPkWBRA5uwcAAAAAFCgyvsnh5ZVJeb50IcKuU7VtWHc+VeHL7/yAVKKz5PPvxK6DkqZy2rfjw+ee5XJBQDAVnn3g4/dUxdAjzw5zWAENunPLzWF+obGdu/U8XeV9N+Yj/vV9Tm5rltq6ow5Yf2GFgMb8uChJ6aGLgPr3G9KUgFW13eP8HpFt9BUEZOkdumFrj1D9/gIa2y0tZXFkzt7AxMAAACIiiekAFlJ2TkAAAAAAAAAAAAAAACgeKTPBDkWBZA5OwcAAAAAFLAu/ZP/f3k8cZ8PfajQ6zXksHBbw2OhpbXVX94pKq+/80Hot8cR5rHarWnT3zSxAADYasOPONN9dcSlxpxnIAKbNOvdeaG+obHdu27StNB3z9Elu/Z2qq4No8+8JifXdkvdPWVmmL9wmcENeZD+22nl4IPdc0pSAbZrv33CtK6VoakiJknt0oSeA6yvEVdWlXinpmbMf/cGJgAAABAFT0cBspKycwAAAAAAAAAAAAAAAEDxSJ8JciwKIHN2DgAAAAAoAuXxxJHl8eRqH/xQoTfskNPCa281+es7RWXOx/NC9d5HmcPa5mr2OTq0tLaaVAAAbLV7H33WvXXEdaquDR998pnBCGzU3M+XhPqGxpz0s9OvLvn1d/TX1yBX13dLTZ0xJ6zf0GKQQ469OfvD0G+PI9x3SlIB1rf/fuHRbr1DU0VMktqlur57WF8jL3GqNy8BAACAKHgyCpCVlJ0DAAAAAAAAAAAAAAAAikf6TJBjUQCZs3MAAAAAQJH4UVXt9mXx5Fs+9qFi+PjpuPOvDosWL/VXeIrGp58tDDsNH2MOa5u67Lp7TCYAALbJ2nXNoffQw9xfR9ylV99pMAIbtXpNc6hvaMxJE+58LsR2PLDk1+BDT/5dzq7xlrp7yswwf+EyAx1y7JN5X4SdR/zcfackFWAV8US4vkd1aKqISdI291LXytAzvr/1NcriyRWd+u9f7s1LAAAAIN88FQXISsrOAQAAAAAAAAAAAAAAAMUjfSbIsSiAzNk5AAAAAKCIdBqU+rfyePIGH/1QMbT9boeG2xoeCxtaWvw1nqIw7/NFYafhY8xfbXVzPp5nIgEAsM0uuPJW99cR13/PI8P69RsMRmCjbnt4eqhvaMxJiaMvtA5/3eGnTMjZNc6kqTPmhPUb/F0bcumLhYvDHqmTrHmSVIB1+rrztt8xvF8RC02StI3VV1ZbW6Pvfm9dAgAAAPnmiShAVlJ2DgAAAAAAAAAAAAAAACge6TNBjkUBZM7OAQAAAABF6MfxEcnyeGKxj36oGNrrwHFh+uvv+os8RWHu/AWh6qejzV1l3YgjzzKBAArMex9+HNra2lwIoOjM+Xhe6FRd6z474h5/5iWDEdioR59/J9Q3NOakX9dPsQf8V4efMiFn1zmT7p4yM8xfuMyAhxxavmJVqDv6V9Y8SSrU+7HeQ8NbsW6hqSImSdvUQb13t65GXTy5nzcuAQAAgHzyNBQgKyk7BwAAAAAAAAAAAAAAABSP9Jkgx6IAMmfnAAAAAIAiVd53ZKeyqsRUH/5QsTR63Pjw2YIv/WWegvf+nE9CryGHmbfKqrvuf9LkASggq9esDTfc9YgLARStA4471312xB1y/IUGIrBRL77+t1Df0JizBteebB3+uk7VteGoM6/L6bXOpKkz5oT1G1oMfMiRteuaw9Gn/sa6J0kF2l59fxpeifUITRUxSdrqXu5aGXrG97euRlhZPDmny5Ah/8sblwAAAEC+eBIKkJWUnQMAAAAAAAAAAAAAAACKR/pMkGNRAJmzcwAAAABAcftueTwxrqwq0ewDICqGuu98UJhw4+Swfv0Gf6GnoL3y2uwQ2zFl3iqjfrLDqLBk2QoTB6CAnH/FLWHa9DddCKBo/fGpae61I65TdW34ZN4XBiPwLU0fLwz1DY0568QLb7UO/8NafOwvJ+b0emfS3VNmhvkLlxn8kCMtra3h7PHXW/ckqUCLx/cLj3XrFZoqYpK01V1bWW1Njb6LvGoJAAAA5IunoABZSdk5AAAAAAAAAAAAAAAAoHikzwQ5FgWQOTsHAAAAAHQAneLDB5bFk3N8/EPF0u6jTgwvznjLX+kpaI/+ufGbD/eas9pSPz/rChMGoIC88c6HoffQw8L69RtcDKBopdew+F4/c78dcb+t/4PBCHzLl0tWhfqGxpx17R/+Eip3OdQ6/F+l/z53/Hk35fSaZ9LEyY2hcdZHYUNLq0kAOTLxjoese5JUoHWPjwh3de8fmipikrTVjeq7hzU1wsqqkuvK+iYqvWkJAAAA5IOnnwBZSdk5AAAAAAAAAAAAAAAAoHikzwQ5FgWQOTsHAAAAAHQQP6hM/HtZPHGTj4ComBo9bnyY9/kif62nYF169Z3mqrbYs9NmmiwABWJDS0vY++BTwknnXuViAEXvN9fe7X474uJ7jQ4bNrQYjMC/3HO2homTG0N9Q+4a9fNLrcP/UOfq2jD2gltyes0z7e4pM8P8BctMBMiRO+57InSuqbX2SVIBtl08ES7rOTA0VcQkaat6uWtlqIwPt6ZG29PesgQAAADywZNPgKyk7BwAAAAAAAAAAAAAAABQPNJnghyLAsicnQMAAAAAOpjyeCJVVpVY6iMgKpa67XRgmHDj5NDcvN5f7Sk4ra1t4bCxF5ur2mT99zwybNjQYrIAFIjf33zfN+vzn5572cUAit7c+QtC55pa990R9+Tz0w1G4FvuenRmqG9ozFnjb3g8dKq2B/xjnWtGhlPG35XT655NU2fMCev9TQhyIn3/FdsxZe2TpAJtTK9dw7sVsdAkSVvR1ZU11tKoiyd8nBUAAADIOU89AbLi77YAAAAAAAAAAAAAAABQRNJnghyLAsicnQMAAAAAOqAfVdV1Ka9KvuhDICqmdht5Qnjh5Tf85Z6Cs2TZirDjfseap9pov77qdpMEoEB89Mln33x0u+ugVFi9Zq0LAnQIh4292H13xB1x0q8NROBbpkydHeobGnPazsmTrMP/UucBdeG08Xfn/Npn2t1TZob5C5aZEJADL898J/Tc9RBrnyQVaLV99gyzYt1CU0VMkrJuZJ89rKURVhZPfhGrSf0fb1gCAAAAueSJJ0BWUnYOAAAAAAAAAAAAAAAAKB7pM0GORQFkzs4BAAAAAB3VkCHfK69KXlQeT7T4IIiKqdHjxodPP1voL/gUlBlvvBe2qxlpjupbvffhxyYIQAFoa2sLdUf/6pu1+ehTf+OCAB3Gk89Pd98dcZ1rasO8zxcZjMA/aZz1UahvaMxpJ1xwi3V4I/1khwPCWb+dnPPrn01TZ8wJ6ze0mBjQzprmzA01+xxt7ZOkAm3XfvuEaV0rQ1NFTJKy6qWv147K+HBraYSVxZNXebkSAAAAyCVPOwGykrJzAAAAAAAAAAAAAAAAQPFInwlyLAogc3YOAAAAAOjgyvsnh5ZVJeb5IIiKqa6DUmHCjZPDuuZmf8mnYFw84XbzU//UPoecamIAFIi7H3jy7+vzfY8+54IAHcaGlpYwYNjR7r8jLv03CoB/NHvOF6G+oTGnXXvPC6H74IOtwxsptuOB4dwJD+T8N8imu6fMDPMXLDM5oJ3Nnb8gDE78wtonSQVav/77hce69wpNFTFJyqqrKgdYR6MsntxQXjWinzcrAQAAgFzxpBMgKyk7BwAAAAAAAAAAAAAAABSP9Jkgx6IAMmfnAAAAAIAS0KlX6vtl8eTDPgqiYmvnET8Pz0yb6a/5FITm5vVhj9RJ5qb+3i2TppgYAAVg4ZdLwva7HfrN2rxdzcjw1dLlLgrQoUy4cbL774gbOOyY0NLaajACf/fZwmWhvqEx59X9fLx1eBN13emgcP7VD+Xld8imqTPmhPUbWkwSaEdffrUsDDvkNGufJBVo3apGhDt7xENTRUySsqq2z57W0SiLJ6Z95zvf+a43KwEAAIBc8JQTICspOwcAAAAAAAAAAAAAAAAUj/SZIMeiADJn5wAAAACAElIeTxxZXpVc5cMgKrZGjxsf5s5f4K/6RO7N2R+GzjW15qVClwF1YdHipSYFQAE45rTL/r4+p8ac54IAHc7CL5eELgPr3IdH3LPTZhqMwN+tWbs+1Dc05rxf108Jnar9LWpTdR98cLjo2kfy8ltk0z2PzQxffLncRIF2tGLl6lB71C+tfZJUoG0XT4TLew4MTRUxScq4F7v2CJXx4dbRCOvUP3GYNyoBAACAXPCEEyArKTsHAAAAAAAAAAAAAAAAFI/0mSDHogAyZ+cAAAAAgBLzo6ra7cuqEm/6MIiKrZ/sMCpccOWtYdXqtf66T6TOuPg6c1LhqFMuNRkACsDjz7z0T+vzbQ2PuShAh3TMaZe5D/dvAKDA3PrQK6G+oTHn7ZQ80Tq8mSp3OTRcMnFKXn6LbJo4uTFMe+2j0NLaarJAO1m9Zm045PgLrX2SVMCd1GuX8F5F19BUEZOkjPpdzwHWzwgriyc/+0Fl4t+9UQkAAAC0N083AbKSsnMAAAAAAAAAAAAAAABA8UifCXIsCiBzdg4AAAAAKEHdug37n2XxxOXlVYlWHwhRsTVg2NHhwcen+gs/kfnyq2Wh566HmI8l3p+ee9lkAIjYipWrQ80+R//T+jx3/gIXBuiQXnj5dffhEddlQF34YuFigxH4uweffivUNzTmvBPOu9k6vIW23+3w8Jub/pSX3yPbGp6YFRYtWWnCQDtZv35DOPb0y619klTAHdR79/BWrFtoqohJ0hZ7/+uG993L+hltV3ibEgAAAGhvnmwCZCVl5wAAAAAAAAAAAAAAAIDikT4T5FgUQObsHAAAAABQwsriib2+7nMfB1ExduCY88MHH33qL/1E4vo7HzYPS7jeQw8Lzc3rTQSAiJ15ycR/Wp/3PfQ0FwXosNra2sIuyePdj0fcNbfebzACf/fc9A9DfUNjzrvm7hdC98EHW4e3UHzvY8Lvbn8mL79Jtl1/74vh1bfnfrOfA9uupbU1nHLBNdY+SSrghvTbOzTGKkNTRUySttgLXXuGrvER1s+IKosn1v+oqnZ7b1ICAAAA7clTTYCspOwcAAAAAAAAAAAAAAAAUDzSZ4IciwLInJ0DAAAAAErcf/YZ8cOyePJJHwlRMfaTHUaFy667J6xes9Zf/Mmr9es3hEH7H2celmjnXnaTSQAQsVdemx06Vdf+0/p8za33uzBAhzbxzofdj0dc+t+Bra1tBiPwjdffmxfqGxrzUu2xv7YOZ9BOyRPDNXe/kLffJdseePrNsHTFGpMH2kH6nuzs8ddb+ySpgOvff//weLfeoakiJklb7Nc9d7R2RtvT3qIEAAAA2pMnmgBZSdk5AAAAAAAAAAAAAAAAoHikzwQ5FgWQOTsHAAAAAJD23fKqxKllVcl1PhKiYqx676PCg49P9Vd/8ur2ex83/0q0N2d/aAIARKi5eX0YWjf2W+vzB3+d6+IAHdriJcvDT3YY5Z484l54+XWDEfjGx/O/CvUNjXnp/KsfsgZn2J4HnxmumzQtb79Ntt1430vhzabPTCBoB21tbeHXV91u7ZOkAq57fES4q3v/0FQRk6TN9l5F1/DTvj+1dkbbKK9QAgAAAO3F00yArKTsHAAAAAAAAAAAAAAAAFA80meCHIsCyJydAwAAAAD4u879R/Quiyfe9pEQFWsHHHduaJoz11//yYs1a9eFfnscYe6VWLuPOtHgB4jYZdfd8631eXDiFy4MUBJ+cdYV7ssjbsyZvzUQgW8sXbEm1Dc05q2qvY+1DmfY8NEX5PW32Zoeff6dsHL1OhMJ2sHEOx6y9klSAbddVSL8vrImNFXEJGmz/albr2/WDGtnRMUTn/6w30//tzcoAQAAgPbgKSZAVlJ2DgAAAAAAAAAAAAAAACge6TNBjkUBZM7OAQAAAAD8k06DUv9WVpW8xsdCVKx1GVAXLrjy1rBi1WpPAci53998n3lXYk2882EDHyBC78/5JHQZWPet9fnSq+90cYCSMG36m+7LC+DvDgu/XGIwAqGtrS3ccO9Lob6hMS8dccpV1uEsOvikK/L222xtNz/wSpg95wuTCdrBHfc9ETrX1Fr/JKmAO6nXLuH9ilhokqTNdPb2O1szo+1ib08CAAAA7cETTICspOwcAAAAAAAAAAAAAAAAUDzSZ4IciwLInJ0DAAAAANioTtWJkeXxxGIfC1GxVr33UeGRP/3lm4/bQq4sXbYydN/5IHOuREp/lPXzBYsNfICItLS2hv0OP2Oja/TMN993gYCSkP437i7J492fR9zEOx4yGIFvNDwxK9Q3NOal397yVOhcM9I6nEWjz7wmb7/PtvTUi++Htes2mFCwjR58fGroMqDO+idJBdxRvYeEdyu6hqaKmCRttHe+XiMG9xtmzYyosqrkuvL4/t29OQkAAABsK08vAbKSsnMAAAAAAAAAAAAAAABA8UifCXIsCiBzdg4AAAAAYJPK+47sVFaVeMFHQ1TM7Xf4GeH1dz7wRICcGXvOBHOtRDps7MUGPECEbrrnjxtdn+N7jQ6trW0uEFAy6m9/0P15xO00fExoa7P3ACE82fh+qG9ozFu7jjrFOpxFnatrw0kX35bX32hru+ORV8OnXyw1qWAbPfrnxtBlYJ01UJIKuBF99wyzYt1DU0VMkjbaI937hO3iCWtmVMWTj3prEgAAANhWnlwCZCVl5wAAAAAAAAAAAAAAAIDikT4T5FgUQObsHAAAAADA5qVS/62sKnFueTy5wYdDVLQfT62pDePOvzp8+dUyTwZod881vmaelUiPPDnNgAeIyLzPF4Uegw/a6Pp87mU3uUBASVm0eGnoMrDOPXrEvTjjLYMRCC+98XGob2jMWydccIs1OMu6DBwVzr7y3rz+TtvS1BlzwvoNLSYXbIOn/zIjxHZMWQMlqYAb3H+fMK1rZWiqiEnSRhvbaxfrZZT1T+zvpUkAAABgW3hqCZCVlJ0DAAAAAAAAAAAAAAAAikf6TJBjUQCZs3MAAAAAABnpFB8+sCyenOPDISrmtt/t0DDxjofC+vUbPCGg3WxoaQnxvX5mjnXweu5ySFizdp0BDxCRQ0+4cJNr9Isz3nKBgJJz3BmXu0+PuLHnTDAQgfDOh5+H+obGvHX1PVNDbNCB1uEsiw1KhQuufjivv9W2NOnxWWHRkpUmGGyDV16bHSoHH2wNlKQCrl///cLj3XqHpoqYJH2rN2PdwoD++1ovI6osnvhrlyFD/pc3JgEAAICt5YklQFZSdg4AAAAAAAAAAAAAAAAoHukzQY5FAWTOzgEAAAAAZOwHlYl/L4sn7vbxEBV7u408ITz/4ixPCWg3519xi7nVwTvzkokGOkBE7nv0uU2uz32GHh42tLS4SEDJeeHl192nR1zFjgeEr5YuNxihxM39fEmob2jMa/v97Dzr8FZUueth4dIbn8j777W1XT/5xfDq23NDW1ubiQZb6c3ZH37zdwNroCQVbt3jI8I9PfqFpoqYJH2ru3v0t1ZGWTx5jrclAQAAgK3laSVAVlJ2DgAAAAAAAAAAAAAAACge6TNBjkUBZM7OAQAAAABkrbwqeUR5PLnCB0RU7B17+uVh7vwFnhawzV55bbY51cGb8cZ7BjpABL5aujz02+OITa7Pp190nYsElKTW1raw0/Ax7tUj7raGxwxGKHFLV6wJ9Q2Nee3sKyZbg7ey/nsdFa68/em8/2bb0oNPvxmWrVxrssFWmt30t9B/zyOtgZJUwHWpSoT6yurQVBGTpG/1s967WSuja1V535GdvCkJAAAAbA1PKgGykrJzAAAAAAAAAAAAAAAAQPFInwlyLAogc3YOAAAAAGCrdK6p7VoWT073AREVez/ZYVS44Mpbw8pVazw1YKs1N68PXQelzKkO2uDEL0JbW5uBDhCB48++crNr9LPTZrpIQMm69tYH3K9H3J6pkw1EKHEtra1h4uTGUN+Qv66bNC30HnqkdXgr22H/48Pv73o+r7/ZtnbzAy+H2XO+MOFgK835eF4YMOxoa6AkFXCdvu6CnoNCU0VMkv6pV2PdQ+/4/tbKiCqrSkzyliQAAACwNTylBMhKys4BAAAAAAAAAAAAAAAAxSN9JsixKIDM2TkAAAAAgK03ZMj3yquSF5XHEy0+JKJir2afo8ODj08NbW1tnh6wdf/3yjHnmUsdtKtvuc8AB4jAc42vbXZ9rhx8cFjX3OxCASVr0eIlocvAOvfsEffGOx8ajFDi7njk1VDf0JjXDj7xt9bgbWjIqFPDtZOm5f1329aebHw/rF23waSDrTDv80VhcOIX1kBJKvCO6b1beLeia2iqiEnS36uvrLZGRlfbj6uTu3pJEgAAAMiWJ5QAWUnZOQAAAAAAAAAAAAAAAKB4pM8EORYFkDk7BwAAAACwzcr7J3Yvq0rM8yERdYT2P+IMH8Rmq1x1073mUAesc01t+PSzhQY4QJ6tWLU6DBx2zGbX6LHnTHChgJJ3zGmXuW+PuDMvmWggQol7+Jm3Qn1DY14bf/1joVN1rXV4G6obc0nef7f26PaHXw2ffL7ExIOtsGDRV2H3USdaAyWpwEv03TPMinULTRUxSfp76bXBGhlNZVXJGd/5zoX/nzckAQAAgGx4OgmQlZSdAwAAAAAAAAAAAAAAAIpH+kyQY1EAmbNzAAAAAADtIlaT+j/l8eRkHxNRR2i7mpHhl5feEJYsW+FJAhmbPmu2+dMBS405z+AGiMCvfnPDFtfox595yYUCSt7zL85y3x5xPQYfFFauWmMwQgl75pUPQn1DY97bcfgJ1uFt7Kgzr43kt2uPps6YEza0tJqAkKXFS5aHPVMnWwMlqcDbtd8+4cWuPUJTRUySvumFrj1D1/gIa2RElfVPjvZ2JAAAAJANTyYBspKycwAAAAAAAAAAAAAAAEBtInYpAAAgAElEQVTxSJ8JciwKIHN2DgAAAACgXZVXJX9eHk+u9kERdYR6DTks3NbwWNjQ0uKJAlu0YtVq86YDdv+U5wxugDx77a2m0LmmdrPrc9dBqbB6zVoXCyh5ra1tYcf9jnXvHnENjzxjMEIJe/XtuaG+oTHvHXPWddbgbaxzzchw2vi7I/n92qPJf3o9fLVstUkIWVq8ZHnY68Bx1kFJKvBq+u8bnu62fWiqiEnSN13Yc0frY0SVxROf/6Ay8e/ejAQAAAAy5akkQFZSdg4AAAAAAAAAAAAAAAAoHukzQY5FAWTOzgEAAAAAtLsf1wzvWV6VfN1HRdRRGjJybHjh5dc9VWCL+u95pDnTgeq+80Fh5ao1BjZAHjU3rw+7jzpxi2v0Madd5mIB/JerbrrX/XvEJX52loEIJez9vy0M9Q2Nee+K254OnWtGWoe3sdgOqXDB1Q9H8hu2Rzfc91J4s+kzExGytGz5yrDvYadbByWpwKuMDw8PdO8bmipikhTe/brd+u1tfYyosqrkZd6KBAAAADLliSRAVlJ2DgAAAAAAAAAAAAAAACge6TNBjkUBZM7OAQAAAADkRLduw/5nWTxxeXlVotWHRdRRGj1ufJg7f4GnC2xS7VG/NFc6UKdccI1BDZBnv63/Q0Zr9ENPTHWxAP7Lwi+XhC4D6tzDR9wHf51rMEKJ+mzhslDf0BhJg2tPtga3Q5W7HhYuu+nJyH7H9ujR598Jq9c0m5CQheUrVoX9Dj/DOihJBd5PqhLh5h5VoakiJknhke59Quev1wXrY/4rq0o0l8f37+6tSAAAACATnkYCZCVl5wAAAAAAAAAAAAAAAIDikT4T5FgUQObsHAAAAABATpXHk/uVVyUW+riIOkpdB6XCpdfcFVatXuspA99y6oXXmCcdqBdnvGVQA+TR+3M+CV0G1m1xfU7/N8uWr3TBAP7BUadc6h4+4i688lYDEUrUytXrQn1DYyQd98vrrcHtVM2wMeH3dz0f2W/ZHt328PTwyWdfmZSQhaXLVoZ9Dz3NOihJBd528US4sueA0FQRk6Twi167WhsjqiyefNjbkAAAAEAmPIkEyErKzgEAAAAAAAAAAAAAAADFI30myLEogMzZOQAAAACAnPthv5H/WVaVfNzHRdSR2mHfY8NjT7/oSQP/5LrbHjA/Okg77ndsaG1tM6gB8iS95iZ+dlZGa/RhYy92wQD+xTPTZrqPj7g+Qw8Pzc3rDUYoQW1tIdxw70uhvqEx7/3u9mdC5wF11uF2avcDzwjXTZoWyW/Znk177aPQ0tpqckKGlq9YFYYfcaZ1UJKKoNO33zk0VcQklXizYt1C//77Wxcj6sf9a/f2NiQAAACwJZ5CAmQlZecAAAAAAAAAAAAAAACA4pE+E+RYFEDm7BwAAAAAQL58tzyeGFdWlVznAyPqSI069pzw3ocfe+LANyY99GfzooN0xcRJBjRAHt10zx8zXqPT+y0A/6y1tS3ssO+x7uUj7tE/NxqMUKL+8Nhrob6hMZJ2rTvFGtyOpY6/LLLfsj1reGJWWLx0lckJGVqxcnUYfsSZ1kFJKoKO6b1beLciFpoklXQ39aiyJkbXu98ZMuR7XoUEAAAANscTSICspOwcAAAAAAAAAAAAAAAAUDzSZ4IciwLInJ0DAAAAAMirzv1H9C6LJ972gRF1pDrX1IZx518dFi9Z7slDiXvoianmRAfprx/PN6AB8mTe54tCj8EHZXzftWjxEhcNYCMm3DjZvXzEHXL8hQYilKhHn38n1Dc0RtKYc26wBrdjnaprw/Hn3RTZ79me3XDfS+HNps9MUMjQipWrw4gjz7IWSlIRlOqze3gr1i00VcQklXDptcCaGE1l8eQJ3oIEAAAANsfTR4CspOwcAAAAAAAAAAAAAAAAUDzSZ4IciwLInJ0DAAAAAMi7ToNS/1ZWlbzGR0bU0eo15LBwW8NjYUNLiycQJepPz71sLnSAkqPPNpgB8ujQEy7MeI0edew5LhjAJny+YHHYrmake/oI61RdGz6Z94XBCCXohRlzQn1DYyRNuOPZsN3AOutwO9ZlwKjwqwn3Rfabtnd/mvZeWLtuvYkKGVi9Zu03f3uwFkpS4bdX35+GV2PdQ1NFTFKJNq1rZehWNcKaGEFlVYmvygbW/sBbkAAAAMCmePIIkJWUnQMAAAAAAAAAAAAAAACKR/pMkGNRAJmzcwAAAAAAkSmvSo4qq0ou8bERdbSGjBwbXnj5DU8hStDUl2aZAx2gPzz0Z4MZIE/ue/S5rNbo2xoec9EANuPIky9xTx9xV0ycZCBCCZo5+9NQ39AYWUNGnWoNbucqdzk0XHbTk5H+ru3Z7Q9PD598vsRkhQysXLUm1B71S2uhJBVBO/fbJ0zrWhmaKmKSSrRLeu5gPYyosqrkNd5+BAAAADbFU0eArKTsHAAAAAAAAAAAAAAAAFA80meCHIsCyJydAwAAAACIVNmAZOeyqsQLPjaijtjocePDp58t9DSihEyfNdvYL/JiO6bCsuUrDWaAPPhq6fLQb48jMl6jO1XXhvlfLHLhADbjqanT3ddHXM0+R4eW1laDEUrMex8tCPUNjZH1i3NvsgbnoOphx4Xf3/V8pL9tezZxcmN46Y2PQ2trm0kLW7B6zdqQGnOetVCSiqB4fL/wVNdeoakiJqkEe/frhvbbx3oYRfHkhk79Rvbx9iMAAACwMZ44AmQlZecAAAAAAAAAAAAAAACA4pE+E+RYFEDm7BwAAAAAQPRSqf9WVpU4L/2xDR8dUUer204HhqtuujesXdfsqUQJmP76u8Z9kTfmzN8ayAB5cvzZV2a1Ru9/xBkuGsAWbGhpCTX7HO3ePuKemTbTYIQSM/fzJaG+oTGyJtzxXNhuYJ01OAftefCZ4bpJ0yL9fdu7+596IyxbsdbEhS1YtXptqDvmHGuhJBVBlfHh4f7ufUNTRUxSCfZot96hc1XCehhBZfHkk158BAAAADbG00aArKTsHAAAAAAAAAAAAAAAAFA80meCHIsCyJydAwAAAAAoGJ3iwweWxZNzfHREHbEBw44ODz4+1ZOJDu6pqdON9yLv6b/MMJAB8iC93ma7Rk+84yEXDiADV0yc5N4+4o457TcGIpSYxUtXhfqGxkjbPXW6NThHHXzSFZH/vu3dTQ+8HD74eJHJC1uwZu26cNDPz7cWSlIR9JOqRLixsjo0VcQklWA/77WrtTCiOlUn9/HWIwAAAPCvPGkEyErKzgEAAAAAAAAAAAAAAADFI30myLEogMzZOQAAAACAgvL9HYb9R1k8cbePjqijdsBx54b3PvzYE4oO6r5HnzPOi7h+exwRNmxoMZABcmzFqtVh4LBjsl6nP5n3hYsHkIH5XywK29WMdI8fYV0G1IUFi74yGKGErF23PtQ3NEbaCefdbA3O2QfCa8Mp4++K/DfORc+8/EFY7+9hsFlr1q4LB//iAuuhJBVB28UT4beVA0NTRUxSifVarHvoE9/fWhhF8cR73xky5HveegQAAAD+kaeMAFlJ2TkAAAAAAAAAAAAAAACgeKTPBDkWBZA5OwcAAAAAUJDKq5JHlMeTK3x8RB3149pnXTIxfLV0uScVHczNf3jUGC/izvvtzQYxQB786jc3ZL1GDzvkNBcOIAuHjb3YPX7E1d/+oIEIJeaG+14K9Q2NkTXhzudCl4GjrME5KjYoFS6ufzTS3zhX/eHx18KXS1aZxLAZa9auCwf/4gLroSQVSb/cfqfQVBGTVGJdW1ltDYyq/onjvO0IAAAA/CNPGAGykrJzAAAAAAAAAAAAAAAAQPFInwlyLAogc3YOAAAAAKBgbTegLlYWT77i4yPqqPUeeli4reGx0NLa6olFB3Hl9ZOM7SLurXfnGMQAOfbaW02hc01t1mv0tbc+4OIBZOHJ519xjx9xgxO/CG1tbQYjlJC7p8wM9Q2NkbbHgWdag3NYvz2PDhPufDby3zkX3XDfS+HNps9MZNiMteuaw6EnXGg9lKQi6ejeu4V3K2KhSVLJ9P7X7d93L2tgBJXFk1/8oDLx7952BAAAAP4fTxcBspKycwAAAAAAAAAAAAAAAEDxSJ8JciwKIHN2DgAAAACgsA0Z8r3yquRF5fFEi4+QqKO2zyGnhumvv+upRQdw3uU3G9NF2tC6sQYwQI41N68Pu486cavW6Tkfz3MBAbKwoaUlVO99lHv9iHt55jsGI5SQh555K9Q3NEbaz8+90fqb678hHXBauG7StMh/61z1xLT3wtrmDSY0bOZvG6PHjbceSlKRdFCf3cPbsa6hqSImqUR6qtv2YbuqhDUwiuLJS7zoCAAAAPw/niwCZCVl5wAAAAAAAAAAAAAAAIDikT4T5FgUQObsHAAAAABAUfhxdXLX8njiEx8hUUetU3VtOOGXvwvzv1jk6UURO/LkS4znIq3+9gcNYIAc+239H7Zqjd7rwHEuHsBWuLz+Hvf6EXfiuVcZiFBCnnrx/VDf0BhpV97+dOhcM9IanOMOGnt55L91LrvzjzPCZ4uWm9SwCeuam8NhYy+2HkpSkbR/373CrFi30FQRk1Qinb79zta/KIonV5cNSHb2liMAAACQ5qkiQFZSdg4AAAAAAAAAAAAAAAAoHukzQY5FAWTOzgEAAAAAFI3v7zDsP8riiXt8iEQdua6DUuHSa+4KK1at9hSjCO2SPN44LsI619SGzxZ8aQAD5ND7cz4JXQbWbdU6/fub73MBAbbC3PkLvrnXdc8fXbEdU2HpspUGI5SIxlkfhfqGxsjbKTHWGpzjOlXXhhMvvLUgfu9cNXHyi+HVt+eGtrY2kxs2Yu265nDgmPOtiZJUJO3eb+8wPdYjNFXEJJVAb8W6hQH997X+RVBZPHG3NxwBAACANE8UAbKSsnMAAAAAAAAAAAAAAABA8UifCXIsCiBzdg4AAAAAoOiUxxNHlseTK3yMRB256r2PCvc9+lxobfXR0mLR3Lw+dBlQZ/wWYemPnwKQO+n7mcTPztrqdfrDv81zEQG20iHHX+ieP+Jun/y4gQglYtZ780J9Q2PkHXna762/eSi2QypcXP/HgvjNc9kjz74dVq1pNsFhI1avWRtqj/qlNVGSiqSd+g0L07pWhqaKmKQS6LYe/a19kZRo/XF1bY23GwEAAABPEwGykrJzAAAAAAAAAAAAAAAAQPFInwlyLAogc3YOAAAAAKAo/aiqrkt5PNHoYyTq6A075LQwfdZsTzSKwFvvzjFmi7T7pzxnAAPk0E33/HGr1+jdDzjJBQTYBo89/aJ7/ojbM3WygQglounjhaG+oTHyxl//mPU3T/Xb86gw4c5nC+J3z2W3PjQ9fPLZVyY5bMSKVavD/kecYU2UpCKpb//9wpPdeoWmipikEuiAPrtb+yKorCrxgjcbAQAAAE8SAbKSsnMAAAAAAAAAAAAAAABA8UifCXIsCiBzdg4AAAAAoHgNGfK98qrkReXxRIuPkqijN3rc+DB3/gJPNgrYHx76s7FahHXb6cCwctUaAxggR+Z9vij0GHzQVq/TE26c7CICbIMNG1pC1U9Hu/ePuDdnf2gwQinc+y5YGuobGgui/nsdbf3NU3sdcnbB/O65btprH4WW1jaTHf7FipWrw76HnmZNlKQiqTI+PDzUrU9oqohJ6uBN61oZusZHWPsi6MfxEUkvNgIAAEBp8xQRICspOwcAAAAAAAAAAAAAAAAUj/SZIMeiADJn5wAAAAAAil559YhBZfHEX32URB292I6p8Jtr7w4rVq32hKMAnXnJROO0CDvp3KsMXoAcOvSEC7dpnW6aM9dFBNhGl15zl3v/iDt7/PUGIpSAJcvXhPqGxoLogOMvs/7msdGnX1Mwv32uu/+pN8LylWtNePgXXy1dHnY/4CRroiQVSV3jI8I9PfqFpoqYpA7ehT13tO5FUPo9vl69Uv/DW40AAABQujxBBMhKys4BAAAAAAAAAAAAAAAAxSN9JsixKIDM2TkAAAAAgA7h+zsM+4+yeOIeHyZRKdRn6OHhtobHQktrqycdBWTX2uONzyLshZffMHgBcuT+Kc9t0xqd3lsB2HZz5y8Inapr3f9HWI/BB4VVq9cajNDBrV/fEuobGguiX024z/qbxzrXjAxnXzG5YH7/XHfzA6+Ev376pUkP/+LLr5aFoXVjrYuSVCR1qUqEGyqrQlNFTFIHbnZF17BTv2HWvQjqVJU8yRuNAAAAULo8PQTISsrOAQAAAAAAAAAAAAAAAMUjfSbIsSiAzNk5AAAAAIAOpTyeSJVVJZb6OIlKofTHGZ9/cZanHQVg4ZdLjMkirHrvo0JLa6sBDJADXy1dHvrtccQ2rdNXTJzkQgK0kwPHnO/fABF376PPGohQAm66/+VQ39AYeddNmhYqdznU+pvHenx9vS+/5amC+P3z1Uuv/y20traZ+PAPPl+wOOw0fIx1UZKKpE5fN77nDqGpIiapAzepez9rXgSVVSWXdOqV+r63GQEAAKA0eXIIkJWUnQMAAAAAAAAAAAAAAACKR/pMkGNRAJmzcwAAAAAAHc6Pquq6lMcTjT5QolLp6FN/E/429zNPPSL04ONTjcUibPzVdxq8ADly/NlXbvM6Pbvpby4kQDv541PT/Bsg4pKjzzYQoQTc9eiMUN/QWBDtP/p862+e2zl5Urj2D38pmDGQj+5/6o2wfOVakx/+wfwvFoVB+x9nXZSkIur07XcOTRUxSR24g/sMtd5FUuJ33mQEAACA0uSpIUBWUnYOAAAAAAAAAAAAAAAAKB7pM0GORQFkzs4BAPB/2bvzKKnLO/H3mfnlnnvn/pH7uznnTibdKFY1IMrSVQ2Ca8Adla5qkHINxn2NURO3aBLcNRr3dg0qUSjc9y1mRLERXHBBRcsVcRcVFUFoaOq5tr+cucncLNUKVd+n+vU65/3XnDNnTvXj5/Hr833mCwAA1KdRo77bmMmf2pjJdflAiXpDfTcaH4499ZLwyaefO/2ogYOPPds6jLCXXn3T4gVYCx7smPutZ/QmYw/0QwKsQStXrgpDt5roOaDGvfz6WxYj1Lkb7nsmtBc7EtGRp/3B7K1BEw4+IzFroFpdedOc8NpbHxkA8BfeWPhuyG67t7koSRF12IabhxdTTaGUSkuqwx5pWj+kM63mXZVryOZXrDt8fNqLjAAAAND7ODEE6JGCnQMAAAAAAAAAAAAAAADi0X0nyLUogMrZOQAAAACAutbY0rpxQyb3mg+VqLc0aPSe4ariXWFVV5dTkCpZtaorbPCjPay/yNp+96MsXoC1YMnSZWGjMft96zl9xkXX+jEB1rBTz7/Gs0CNO/ncqy1EqHN3zHg+tBc7EtEF1z4U1hsxwfytcn1a2sLPTrkmMeugmj0y9/XQtbpsEMCfvbbgnZDZZm+zUZIiauLgUWF+qimUUmlJddivNhhp1tWiTH66NxgBAACg93FaCNAjBTsHAAAAAAAAAAAAAAAAxKP7TpBrUQCVs3MAAAAAAHXv+yPGfK8hk7vOh0rUm9pywuHh4dlPOwmpgplznrHmIuzKqXdYvABrwS/PuGyNzOl5L77mxwRYw15/893Qp6XN80ANGzz6x6Gzc6XFCHXsj4+WQnuxIzFtucsvzN8a1LTJruH0y+9J1FqoVjfe/0z4/IvlhgH82YuvLPj63wHNRkmKp50HbxnmpfuFUiotqc56IdUURjaPMeuqX/mHLW3DvMEIAAAAvYuTQoAeKdg5AAAAAAAAAAAAAAAAIB7dd4JciwKonJ0DAAAAAOg1GjO5QkM296mPlag3tdvBvwmlVxc6EVmLjpp0obUWWX2Hjw+LPl5s8QKsYU89VwrrDGv71nN6450OCOVy2Q8KsBbsvP8Jnglq3J0PzLIQoY7NfPK10F7sSEwHnnCZ2VujNtrxkHDR1JmJWg/V6sqb5oTX3vrIQIA/e6H0Rthw1J5moyRF1A5Dtg5PpfuFUiotqc6a2r/ZnKtBDdncQ95cBAAAgN7FKSFAjxTsHAAAAAAAAAAAAAAAABCP7jtBrkUBVM7OAQAAAAD0KusMa2tqyOQf88ES9ab6Dh8fjj31kvDx4s+djKxhKzo7w8AtdrfOImvi4adYvABrWGfnyrDlzj9dI3P6tAum+EEB1pLb7p3pmaDG7X7IJAsR6tjjzy0M7cWOxHT25AdCn5Y287dGTTj4jESth2r3yNzXQ9fqssEAX3ny2ZfCgM12NRslKaK2HLpdeDzdP5RSaUl11oTBW5pzNahPS357by4CAABA7+GEEKBHCnYOAAAAAAAAAAAAAAAAiEf3nSDXogAqZ+cAAAAAAHqfUaO+25jNn9SYyXX5aIl6U4NG7xkmT7szrFrV5YRkDbnjjx3WVoTdfv8jFi/AGvbb9qlrbE4/8/wrflCAtaSzc2UYsuVEzwU1/XhsW3jz7fctRqhT815+N7QXOxLVsB0OMn9rOPOPOOWaxK2Janbj/c+EJUuXGw7wlcefeTH033RX81GSImqzoWPCrKYBoZRKS6qjHuo3MKQyOXOuyjVk8vO+851J/+rFRQAAAOgdnA4C9EjBzgEAAAAAAAAAAAAAAADx6L4T5FoUQOXsHAAAAABAr9XY0rpxQyb3ug+XqLe1Rdsh4a4HZjklWRP/HysP/JU1FVkDN989fLl8hcULsAa99Oqboe9G49fInN5ozH6hXC77UQHWol+ddaVngxr3u8uKFiLUqZcXLArtxY5EVTjkTLO3hjVtums44/J7ErcuqtnkW+aEhe8tNiDgKzPnPBPSIwvmoyRF1PDmHcKMpoGhlEpLqqN+ucEmZlxtmuiNRQAAAOgdnAwC9EjBzgEAAAAAAAAAAAAAAADx6L4T5FoUQOXsHAAAAABAr/b9EWO+15DJXeejJeqN7XrQr8OLryxwWvINLXjrvdCnpc1aiqyjT77Y4gVYg1avLofcT45dY3P65HOv9qMCrGXdz4GeDWr8Qe4x+4au1astRqhDb763OLQXOxLVsb+dbvbWuI1bDwsXTZ2ZuLVR7WY/uyCUy2WDgl7voUefCqmRE8xHSYqoIc07hvv6bRhKqbSkOmleul8Y3ryDGVftMrk3+/Ub8797YxEAAADqn1NBgB4p2DkAAAAAAAAAAAAAAAAgHt13glyLAqicnQMAAAAA4CsNmdafNGbyS3zARL2tdYeNC8effln4ePHnTk166KTfXWUNRdicuS9YvABr0BXX3b5G5/STz77kRwWogh32+Lnngxr3n488aSFCHfrg4yWhvdiRqC667uGQHlEwe2tc4ZAzErc2atFtDz4Xli3vNCzo9e56YNbX5zPmoyTF08DMTuG2/oNDKZWWVCdNHpAx32pQQzb3c28qAgAAQP1zIgjQIwU7BwAAAAAAAAAAAAAAAMSj+06Qa1EAlbNzAAAAAAD82TrD2poaMvnHfMBEvbEBm+0azr18eljR6YOmlViydFkYuMXu1k5kbbzTAaFcLlvAAGvI2+8t+vrfIdbUnB62/b5h9WpzGqAaptxwr2eEGrffz8+0EKEOffbF8tBe7Ehcoyf83OytcX1a2sIxZ01L5Pqodtfc9nh4b9HnBga93s13PxTWGdZmRkpSRPXLtoZi/6GhlEpLqpPGD9nKfKtyDdncJ32b8//Tm4oAAABQ35wGAvRIwc4BAAAAAAAAAAAAAAAA8ei+E+RaFEDl7BwAAAAAAH9p1KjvNmbzJzVmcl0+ZKLe2KatB4U7H5gVyuWyU5R/4JIpt1ovEXbOpdMsXoA1aI9DJ63ROf3rs3/vRwWokiVfLAv9NtnFc0IN6zt8fPjwo8UWI9SZFZ2rQnuxI3Htc/RFZm8CGvijH4ezr3ogkWuk2l06fVZ4av7bhga93pQb7jUfJSmy1svmwuQBmVBKpSXVQTOaBn79z7X5Vt0aMrmzvKQIAAAA9c1JIECPFOwcAAAAAAAAAAAAAAAAEI/uO0GuRQFUzs4BAAAAAPA3NLa0btyQyb3uQybqrY2deEx47On5TlL+hs7OlaFlu32skwh7bcE7FjDAGnLjnQ+u8Tn92FMv+GEBquinJ57nOaHGXXLNLRYi1KFLp88K7cWORHVy+x3mbkL60c5HhYunPZK4NVKr7pk5P6zoXGVw0Kv97rKi+ShJkdU3mwuXr98SSqm0pDroyA03NduqXEMmv/yHw8au6w1FAAAAqF9OAQF6pGDnAAAAAAAAAAAAAAAAgHh03wlyLQqgcnYOAAAAAIC/4/sjxnyvIZuf6mMm6s3tdvBvwkuvvulE5S9MueFeayPCWvc61uIFWEM++fTzMHSriWt0Tme33TusXl324wJU0awn5nlWqHGbth4UymX7H9Sbq255LLQXOxLXoNF7mb0Jad9j2xO5RmrV1Lvmho8+XWp40Kud9LurzEdJiqx1M7lw7vrDQymVlhR5T6f6hSHNO5pt1S6Tv8rbiQAAAFC/nAAC9EjBzgEAAAAAAAAAAAAAAADx6L4T5FoUQOXsHAAAAAAA/0RjJldoyOY+9UET9db6Dh8fjj31krDo48W9/mBlRWdnGD5mX+siwqbccK+TQYA15JDjzlnjc3rSOZP9sABVVi6Xw6atB3leqHFz5r5gMUKdmXb33NBe7EhcO+39a3M3Mf+9defwmwtvTeQ6qVWX3fBoeOHV9w0QevW/mx816UIzUpIiq89XnTpwRCil0pIi77z1h5tr1S6T6+ozdNxgbyYCAABAfXICCNAjBTsHAAAAAAAAAAAAAAAAxKP7TpBrUQCVs3MAAAAAAFTgB8359Rqz+Vk+aqLeXP9Ndw2nX/iHsGTpsl57sDJ52p3WQoStN2Ln8MmnnzsZBFgDHuyYu1Zm9dx5JT8uQA1c8PsbPDPUuJ/96nwLEerMTQ88G9qLHYnrp5Mmm7sJqnnb/cIF1z6UyLVSyx587JWwqmu1QUKvtGpVV9jrZ6eakZIUYb/YYNNQSqUlRdyLqaaw1dDtzLRqlyDsljMAACAASURBVMnd5a1EAAAAqE9O/wB6pGDnAAAAAAAAAAAAAAAAgHh03wlyLQqgcnYOAAAAAIBKjRr13cZs/qTGTK7Lh03Um8tuu3eYdssfQ9fq3vVx088+/yJktvmJNRBh+/38TKeCAGvAkqXLwvAx+67xOT1ih/1DuVz2AwPUwPsffhzWHTbOc0MNa9q48PXzJlA/7pjxfGgvdiSu3139p7BOS5vZm6Dy+56cyLVS666/9+nw2ZLlhgm90vIVnWH8vr80IyUpwn6xwaahlEpLirhb+g0Ofcyz6tfSupWXEgEAAKD+OPkD6JGCnQMAAAAAAAAAAAAAAADi0X0nyLUogMrZOQAAAAAAeqhPNvejxkx+oQ+bqLe35c4/DX98+PFec6hy9MkX+7tH2n0z5jgVBFgDjj/9srUyp089/xo/LkANTTz8FM8NNe7q6++2EKGO3PvIi6G92JHINtrxYHM3QfVpaQtHnDolseulll1x0+zw+lsfGyj0Sp8vWRq22eUIc1KSIuyQQZuHF1NNoZRKS4q0iYNHmWdVriGTn+NtRAAAAKg/Tv0AeqRg5wAAAAAAAAAAAAAAAIB4dN8Jci0KoHJ2DgAAAACAb+D7I8Z8ryGbn+rjJlI+jJ14TOh4fF5dH6jMmfvC1x+59feOr0Gj9wydnSudCgIkeC989oVX/MAANXTPf8727FDjttnlCAsR6sifZr8c2osdiWzXQ88ydxNW/013C7/9/f2JXTO1bvazC0K5XDZY6HU++uSz8KNxh5qTkhRhBwzaIryYagqlVFpShHWk1w9NmVbzrMo1ZHM5byMCAABAfXHiB9AjBTsHAAAAAAAAAAAAAAAAxKP7TpBrUQCVs3MAAAAAAHwLjZlcoSGb+9QHTqR82P2QSeHZF16pu8OUZV8uD1u0HeJvHGknnnmFE0GAb6mzc2UYPf6wtTKnNxl7oA+kA9TYypWrQvPWe3l+qHHz5r9qMUKdePiJV0N7sSORHXf2dDM3gW0x/shw8bRHErtuat1tDz4Xvly+0nCh11n4zgchu+3e5qQkRdjEQaPD/FRTKKXSkiLshA02NsuqXEM29/x3vjPpX72JCAAAAPXDaR9AjxTsHAAAAAAAAAAAAAAAABCP7jtBrkUBVM7OAQAAAADwLf2gOb9eYzY/y0dOpP/Vbgf/Jsx/eUHdHKYcctw5/q4R9/TzLzsRBPiWTr9gylqb02dcdK0fGCABTj73as8PNe740y+zEKFOPPr0G6G92JHILpo6M6Q3Lpi7CeyA4y9N7LpJQlNufyJ88PESA4Zep/TqwjBo9J7mpCRF2ITBW4bn0k2hlEpLiqx56X5hWPMOZlmV69Oc29NbiAAAAFA/nPQB9EjBzgEAAAAAAAAAAAAAAADx6L4T5FoUQOXsHAAAAAAAa8KoUd9tzORPa8zkunzoRMqHdYa1hSN+fUF4Y+G7UR+kXH7t7f6eEbdF2yFOAwG+pRdKb4S+G41fa7O6+38/ALX38utveYaocQM33z0s+3K5xQh14PHnFob2YkdiG134hbmbwFIjJ4TTLr0r0Wun1l12/aNh/mvvGzL0Ok8++1Lot8kuZqUkRdi4wVuFeel+oZRKS4qsy9dvMceqXEMm99qwYQf+b15CBAAAgPrglA+gRwp2DgAAAAAAAAAAAAAAAIhH950g16IAKmfnAAAAAABYgxpbWjduyORe97ET6X/Vp6Ut7HHoSeGPDz8eulavjuoQ5cGOuaHv8PH+jhF3we9vcBoI8C2s6uoKY3b/+Vqb05u2HuRHBkiQ1r2O9RxR426440ELEerA0y+9E9qLHYlt4pHnmbkJbeTYQ8JF0x5J9PpJQn+a/fJXz6urDRt6lUceezakRk4wKyUpwnYYsnV4OtUvlFJpSZG145BtzLEq15DNHeztQwAAAKgPTvgAeqRg5wAAAAAAAAAAAAAAAIB4dN8Jci0KoHJ2DgAAAACANez7I8Z8ryGbn+pjJ9Jf17LdPuHcy6eHjz75LPEHKA89+lRIjyz4u0Vcn5a2sPCdD5wGAnwLF06+ca3O6rMvmeZHBkiQabf80bNEjRu3z/EWItSB5195L7QXOxLbiefeZOYmuD1+9rtEr5+kdMN9z4QlS5cbOPQq9z44O6w7bJxZKUkRttXQ7cKT6QGhlEpLiqh7+g0K62Zy5lgVa8jk3vvhsLH/p7cPAQAAIH5O9wB6pGDnAAAAAAAAAAAAAAAAgHh03wlyLQqgcnYOAAAAAIC1pDGTKzRkc5/66In016VGTgg/PfG8MHdeKZGHJw/MfOLr/xv9reJu5/1PcBII8C28tuCdkB5ZWKuzuvTqQj80QIIsXbY8DNhsV88TNe7l19+yGCFypQUfhvZiR2K7aOrMkB5RMHMT2jrDxoUTz70x0WsoKU2+5bHw1vufGjr0Kn+48T6zUpIibfSQ7cPj6f6hlEpLiqgDB21hhlW5hubcMd46BAAAgPg52QPokYKdAwAAAAAAAAAAAAAAAOLRfSfItSiAytk5AAAAAADWoh8059drzOZn+eiJ9LfbfvejwpQb7g2LP1tS80OT1avL4fwrbwjrDhvnb1MHFW/7k5NAgG+xJ47b5/i1OqdHjTvMDw2QQEdNutDzRI079fxrLESI3Otvfxzaix2JbrO2n5m5Ca55m33CBdc+lPh1lIQumT4rPP7cwlAumz30Ht3nGGalJMXZpkO3D482rR9KqbSkSJqTHhAGZFrNsCrWkM0vXnfITv+3tw4BAAAgbk71AHqkYOcAAAAAAAAAAAAAAACAeHTfCXItCqBydg4AAAAAgLVt1KjvNmbypzVmcl0+fiL97dYbsXPY96gzwj3/OTus6Oys+oHJhx8tDnscepK/RZ3UtHEhLFm6zEkgwDd09fS71/qsPvfy6X5ogAR6/JkXPVPUuOat9worV66yGCFib73/aWgvdiS63Q4/28xNeOMPPDXx6yhJ3T1zfljRaf+k9/j12b83KyUp0jZuHhM60uuHUiotKZJ+vcHG5lfVy53ihUMAAACImxM9gB4p2DkAAAAAAAAAAAAAAAAgHt13glyLAqicnQMAAAAAoEoaW1o3bsjkX/XhE+kf12+TXcLeR5wWbr77obDki2Vr9aDky+UrwiXX3BIGbr67376OOuyXv3MKCPANvfP+orD+Zrut9Vn98utv+bEBEmr0+MM8V9S4+2bMsRAhYu9/tCS0FzsS3bFnFc3bhNenpS0cd/b0xK+lJDXt7rlh8efLDCF6hXK5HH5x0sXmpSRF2vChO4SZTQNDKZWWFEHz0v1CtnlH86uq5b7498GtP/C2IQAAAMTLiR5AjxTsHAAAAAAAAAAAAAAAABCP7jtBrkUBVM7OAQAAAABQRd8fMeZ7DZnctT5+IlVWauSEsPshk0L71TeHZ55/JXStXr1GDkgWvvNB+N1lxZDddm+/cx32YMdcp4AA39DeR5y21uf0Nrsc4YcGSLBLptzquaLG/eRnp1qIELGPP10a2osdie6Cax8K62403sxNeEO23juc/4cZiV9PSeqKG2eH1976yCCiV1i1quvrf280LyUpzrLNO4YZTQNDKZWWFEGXDmgxu6pcQyZ/njcNAQAAIF5O8wB6pGDnAAAAAAAAAAAAAAAAgHh03wlyLQqgcnYOAAAAAIAaaMzkJjRkc5/4CIrUswZusXvY7eDfhNMumBJuu++RUHp1Yfhy+Yp/eiCyZOmy8PDsZ8K5l08P4/c7IfRpafN71mnNW+8VVnV1OQUE+AZuumtGVWb1RZNv8mMDJNiijz8NfTca7/mihvUdPj58sOgTixEi9fkXy0N7sSPxjRx7qJkbQW37nxLFekpas59dEMpl84j6t3xFZ8jvfZx5KUmRlm3eMcxoGhhKqbSkhPfSV20/dFuzq4o1ZPLLG4bn1/GWIQAAAMTJSR5AjxTsHAAAAAAAAAAAAAAAABCP7jtBrkUBVM7OAQAAAABQI90f/mjI5mf4EIr07dvgR3uELSccHiYccGLY7eDffF3hwF+FLXf+6df/M79R7+nkc692AgjwDXzy6edh6FYTqzKr31j4rh8cIOH2PeoMzxc17pJrbrEQIVJfLl8Z2osdiW/CwWZ9DPVpaQvHnT09ijWVtO6eOT90ruwylKh7iz9bEn407lAzU5IibXDzTuH+fhuEUiotKeHd1n9w6GNuVbWGbO733jAEAACAODnFA+iRgp0DAAAAAAAAAAAAAAAA4tF9J8i1KIDK2TkAAAAAAGrrXxozuSMasvkVPoYiSd++F0pvOAEE+AYOPvbsqszpMbv/3I8NEIEHZj7h+aLGbdF2SCiXyxYjRGhF56rQXuxIfEed9gfzNpIGjd4rnDdlRhTrKmlNvWtu+OSzZQYTdW/hOx+EzDY/MTMlKdIGZ3YK9zdtGEqptKSEt+egUeZWNcvkun44bOxArxcCAABAfJzgAfRIwc4BAAAAAAAAAAAAAAAA8ei+E+RaFEDl7BwAAAAAAAnQZ+i4wQ2Z/DwfRJGkb96WEw53+gfwDfzpkSerNqsvmXKrHxwgAqu6ukLLdvt4zqhxTzzzosUIEVq5qiu0FzsS37lT/jOs09Jm3kZSfv+To1hXSeyKm2aH19/+2HCi7s2b/2oYsNmuZqYkRdrgzE7hvn4bhlIqLSnBPdQ0MKQyOXOrmmVy13uzEAAAAOLj9A6gRwp2DgAAAAAAAAAAAAAAAIhH950g16IAKmfnAAAAAABIiD4bF/6tMZNvb8zmyz6KIkk979Iptzr9A+ihJUuXheFj9q3arH7z7ff96ACROOOiaz1n1LijT77YQoQIdXWtDu3FjihqGXOAeRtJfVrawrG/nR7N2kpis59dEMplM4r69qdHngx9h483NyUp0tbPjA139hsUSqm0pAT3iw02NbOqW7kxM67Zm4UAAAAQFyd3AD1SsHMAAAAAAAAAAAAAAABAPLrvBLkWBVA5OwcAAAAAQMI0ZvI7NmbzH/goiiRV3rrDxoUPFn3i9A+gh4459ZKqzeqxE4/xgwNE5I2F74Y+LW2eN2r5Me3NdgvLvlxuMUJkyuVyaC92RFF+/5PN24gatOVPwvl/mBHN+kpidz08P3SuXGVQUdem3vJHM1OSYv5vAZmx4Y5+g0IplZaU0J5O9QuDm3cys6pa7jZvFAIAAEBcnNoB9EjBzgEAAAAAAAAAAAAAAADx6L4T5FoUQOXsHAAAAAAACfQfmcL/05jJ3+GjKJJUWXscepKTP4Aemv3k86FPS1vVZvUV193uRweIzPh9f+l5o8bdcMeDFiJE6JLpHaG9mPx+Oukqszayxh1wShRrK8lNvWtuWPz5MoOKunb2JdPMTEmKuPUzY8Nt/QeHUiotKaGdvf5G5lV1K/fJjN3IG4UAAAAQDyd2AD1SsHMAAAAAAAAAAAAAAABAPLrvBLkWBVA5OwcAAAAAQII1ZnJ7NWbzS30cRZL+cbfe87CTP4Ae+HL5irBZ7uCqzek+LW3h7fcW+eEBInPjnQ963qhx4/c7wUKECF12/azQXuxIfGdPfuDrf1c3b+Op++/1y9/dEMX6SnJX3DQ7vP72x4YVdatcLoefT7rI3JSkiBuQGRtu7T84lFJpSQlsfropbNa8vXlVzTK5u7xJCAAAAPFwYgfQIwU7BwAAAAAAAAAAAAAAAMSj+06Qa1EAlbNzAAAAAAAkXMOQ3PqNmdxcH0iRpL/d+pvtFpZ9udzJH0APnHLe1VWd1W37HO9HB4jQl8tXhIGb7+65o4b1aWkLbyx812KEyFx+w6OhvdgRRUO33se8jazMtvuFi6bOjGaNJbnZzy4I5bKZRX1ataor7HHoJHNTkiKuKdMabug/JJRSaUkJbEr/ZrOq2g3LjfQmIQAAAMTBaR1AjxTsHAAAAAAAAAAAAAAAABCP7jtBrkUBVM7OAQAAAAAQg1GjvtuYzZ/UmMl1+UiKJP11R0260KkfQA88+8IrYd1h46o6q68q3uWHB4jUsade4rmjxp3Vfp2FCJG58qY5ob3YEUU7TDzBrI2w3Q8/O5o1lvTunjk/dK5cZXBRl75Y+mXYfvejzE1JirimTGuY3n9IKKXSkhJY65Ctzaoq1pDJ3+clQgAAAIiDkzqAHinYOQAAAAAAAAAAAAAAACAe3XeCXIsCqJydAwAAAAAgIg3Ztk0aMrnXfChFkv6/Zj0xz6kfQIVWdXVV/WPK6wxrC+9/+LEfHyBSzzz/iueOGjds+31D1+rVFiNEZPItj4X2YkcU7XfsxWZthK270fhw0sW3R7POkl7xnqfC518sN7yoSx9+tDiM3HF/s1OSIi6daQ3T+g8NpVRaUsK6u9+gsE42Z1ZVsR+25LfwBiEAAAAkn1M6gB4p2DkAAAAAAAAAAAAAAAAgHt13glyLAqicnQMAAAAAIDLfHzHmew2Z3BU+lCJJPi4P0FPnX3lD1Wf1zvuf4IcHiNy2ux7h+aPGzZj1lIUIEbn61sdDe7Ejin59/i3mbKRttOMh4eJpj0Sz1pLe5JvnhLc/+NQAoy698sbbYdDoPc1OSYq4dKY1FPsPDaVUWlLCmjh4lDlV3f7k7UEAAABIPid0AD1SsHMAAAAAAAAAAAAAAABAPLrvBLkWBVA5OwcAAAAAQKQaM7lCQzb3iY+lSOrNnXnxdU78ACr06oK3Q3pkoeqz+rqb7/fjA0Tuyql3eP6ocQcde7aFCBGZcvsTob3YEUUXTZ0Z1hsxwayNtH2OuTiatRZDl06fFZ6a/7YhRl167On5NfnvQpKkNVc60xqK/YeGUiotKUE93DQwrJfNmVNVrE+mbZQ3BwEAACDZnM4B9EjBzgEAAAAAAAAAAAAAAADx6L4T5FoUQOXsHAAAAAAAEfuP7Pi+DZn8TB9MkdRbe/n1t5z4AVRg9epyaNvn+KrP6b4bjQ+LP1viDwAQuU8+/TysN2JnzyA1rPv37/47AHG49s4nQ3uxI5o2HnuoWRtp6ZG7hDOuuDeq9RZDDz3xauj66jka6s2dD8wK6wxrMz8lKeZ//8u0hun9h4RSKi0pQR254WZmVBVryOYe9tYgAAAAJJuTOYAeKdg5AAAAAAAAAAAAAAAAIB7dd4JciwKonJ0DAAAAACB2hcL/aMzkjm/I5Fb6cIqk3tSY3X/utA+gQr+fdmdNZvXeR5zmxweoEwcde7bnkBo3+av9HIjD1LvmhvZiRzSNP/BUczbiRu18VFTrLZZu+dO88OXylQYadefKqXeYnZIUeelMa5jef0gopdKSEtLcdP8wMLOTGVXFGrL5rb00CAAAAMnlVA6gRwp2DgAAAAAAAAAAAAAAAIhH950g16IAKmfnAAAAAACoE32G5Yc0ZHLP+XCKpN5S98c/Afjn3n5vURiw2a41mdW33feIPwBAnfjTI096DqlxWxd+ZiFCJIr3PBXaix3RdNikyeZs5B1+0tVRrblYmnL7E2HR4i8MNerOSb+7yuyUpMhLZ1rD9P5DQimVlpSQTtpgpPlU1XKPelsQAAAAksuJHECPFOwcAAAAAAAAAAAAAAAAEI/uO0GuRQFUzs4BAAAAAFBH+mxc+LeGbP7Cxmy+7OMpkuq5dYeNC4s+Xuy0D6ACexx6Uk1mdf9Ndw1Lly33BwCoE6u6ukJmm709j9S4eS++ZjFCBK6/9+nQXuyIptMvv8eMjbz1N98jnHvNg1Gtu1i64qbZ4Y23PzbYqCvlcjn89MTzzE9Jirx0pjVM7z8klFJpSQnouXRTaGnewXyqYn1a8tt7WxAAAACSyYkcQI8U7BwAAAAAAAAAAAAAAAAQj+47Qa5FAVTOzgEAAAAAUIcaWtrGNmZzH/qAiqR6bY9DT3LSB1CB6+/4z5rN6sNPPM8fAKDOnHzu1Z5HatyJZ15hIUIEpt/7dGgvdkTVgM12N2cjr23/U6JbdzE1+9kFhht1ZUVnZxi/7y/NT0mKvHSmNVzff0gopdKSEtDF6w8zm6pYQyb/mLcEAQAAIJmcxgH0SMHOAQAAAAAAAAAAAAAAAPHovhPkWhRA5ewcAAAAAAB16t8Ht/6gIZu/20dUJNVjt9zzkJM+gH9i0ceLw6DRe9ZsVj/YMdcfAaDOzH95geeRGrfhqD3Dis5OixESrnjPU6G92BFVW+x8pDkbeeu0tIVfn39LdGsvpu6f9VJY1bXakKNufPrZF2HUuMPMUEmKvHSmNVzff0gopdKSatyLqaaw5dDtzKZq1pzbyVuCAAAAkDxO4gB6pGDnAAAAAAAAAAAAAAAAgHh03wlyLQqgcnYOAAAAAIA615jJ7dWYzS/1IRVJ9VL/TXcNS5ctd9IH8E8ccPRZNZvVQ7acGFat6vJHAKhD2+56hOeSGnf7/Y9YiJBwU++eG9qLHVFVOORMM7YOGrbDQeGiaY9Et/5i6vr7ng5Llq4w6KgbC9/5IDRvvZcZKkmRl860huv7DwmlVFpSjev+Z9FcqmKZ/FPf+c53/sUbggAAAJAsTuEAeqRg5wAAAAAAAAAAAAAAAIB4dN8Jci0KoHJ2DgAAAACAXuA/sm0bNGbzT/uYiqR66PATz3PKB/BPPDDziZrO6hPOvNwfAaBOXTn1Ds8lNW73QyZZiJBwU++aG9qLHVF1+MlXmbF10j7HXBzd+outq255LLz74WeGHXXjsafnh9TICWaoJEVeOtMabug/JJRSaUk1Lj94K3OpijVkczlvBwIAAECyOIED6JGCnQMAAAAAAAAAAAAAAADi0X0nyLUogMrZOQAAAAAAeotRo77bmM2f1JjJdfmgiqSYe3j20075AP6BJV8sC8O237ems/rxZ170hwCoUx998lnou9F4zyY1bJ1hbeHt9xZZjJBg1975ZGgvdkTV6ZffY8bWSemRu4SzrrwvujUYW5dd/2h48fUPDDzqxk13zTBDJakO6pdtDTf1HxJKqbSkGnZ3v0FhnWzOXKpWmfxT3/nOd/7Fy4EAAACQHE7fAHqkYOcAAAAAAAAAAAAAAACAeHTfCXItCqBydg4AAAAAgF6mIdu2SUMm97qPqkiKseat9wqrurqc8gH8A7846eKazuoRO+wfyuWyPwRAHdvrZ6d6Pqlx511xvYUICfaHO54M7cWO6Oq/6W5mbJ203R7HRbkGY+zRp98IHoGpF2defJ0ZKkl1UFOmNdzQf0gopdKSatjEwaPMpGqWadvBW4EAAACQHE7eAHqkYOcAAAAAAAAAAAAAAACAeHTfCXItCqBydg4AAAAAgF6ob3P+fzZm8tN9VEVSbE06Z7ITPoB/4NEnngt9WtpqOqvPuOhafwiAOnfXA7M8n9S4TcYeGMrlssUICTXl9idCe7EjujYfd4QZW0f94ozrolyHMXbnQy+EzpVdhh/RW726HA44+iwzVJLqoP6Z1nBzv8GhlEpLqlEzmgaGdbM5M6lKNWTyc7wRCAAAAMnh5A2gRwp2DgAAAAAAAAAAAAAAAIhH950g16IAKmfnAAAAAADoxRozuUJDNr/Yx1UkxdK8F19zwgfwd3y5fEXYtPWgms/qF19Z4I8BUOdWrlwVBo/+sWeUGvfoE89ZjJBQ19z2eGgvdkTXzgedbr7WUYO33DtceO3DUa7FGJt+79NhydIVBiDRW76iM4ydeIw5Kkl10IBMa7it/+BQSqUl1ahDB21uHlWxH2Zat/U2IAAAACSDUzeAHinYOQAAAAAAAAAAAAAAACAe3XeCXIsCqJydAwAAAACgl/tBc369xkyuw8dVJCW90eMPc7oH8A9MOmeyWQ1A1Rx/+mWeU2rc4SeeZyFCQl196+OhvdgRXYdNmmy+1lk/PvLcKNdirHX/s//Bx0sMQaL3waJPwvAx+5qjklQHDciMDXf0GxRKqbSkGjQnPSD0z7SaR9Uqk+vwJiAAAAAkgxM3gB4p2DkAAAAAAAAAAAAAAAAgHt13glyLAqicnQMAAAAAgK9M+tfGTO6Ihmyu00dWJCW1iybf5HQP4O945vlXwrrDxpnVAFTN3Hklzyk1rmnjQvh8yVKLERLoqlseC+3Fjug6pf1O87XOSo2cEM684t4o12OsXXb9o+HlBYsMQqL3QumNMGCzXc1SSaqD1s+MDXf13zCUUmlJNejYDTYxi6pZc25L7wECAABA7TltA+iRgp0DAAAAAAAAAAAAAAAA4tF9J8i1KIDK2TkAAAAAAPgv62Rzwxuz+ZKPrEhKWn1a2sLCdz5wugfwN6xcuSpsVTjcrAag6kaNO8zzSo277ub7LURIoMm3zAntxY7ounjaI2G9ERPM1zpr2z2Pj3I9xt7sZxcYhkTvwY65Yd1h48xSSaqDBmV2Cn9s2iCUUmlJVe6pdP+wQfNYs6hKNWTzM7wBCAAAALXnpA2gRwp2DgAAAAAAAAAAAAAAAIhH950g16IAKmfnAAAAAADgr/TZuPBvDdn8hY3ZfNnHViQlpfH7neBkD+DvOPfy6YmY1fm9j/PHAOhlLpx8o+eVGjd24jEWIiTQ72+eE9qLHVE2fIeDzdc67NizitGuyZi7f9ZLYVXXakORqF065VZzVJLqpMGZncL9/TYIpVRaUpU7eeAIc6iK/bAlv4U3AAEAAKC2nLIB9EjBzgEAAAAAAAAAAAAAAADx6L4T5FoUQOXsHAAAAAAA/E0N2VyuMZv70MdWJCWhqbf80ckewN/wyhtvh9TICYmY1Vdff7c/CEAv8877i8I6w9o8s9S4l19baDFCwlx50+zQXuyIsh33+pXZWodlt9s/XDR1ZrTrMuZueuDZsGz5SoORqB198sVmqSTVSc3NO4UZTQNDKZWWVMWeSzeFbPOO5lD1esCbfwAAAFBbTtgAeqRg5wAAAAAAAAAAAAAAAIB4dN8Jci0KoHJ2DgAAAAAA/q4fDB33743Z/O0+tiKplq03Yufw6WdfONkD+G9Wry6H/N7HJWJW9x0+Piz6+FN/FIBeaJcDf+25pcadct7VFiIkzBU3zg7txY4o2/sXF5itddo+R18Umx4uhQAAIABJREFU7bqMvSm3PxEWLfbfN4nXqlVdYdeD/Hu/JNVL2eYdw0NNA0MplZZUxc5df7gZVMV+2Ny6mTf/AAAAoHacsAH0SMHOAQAAAAAAAAAAAAAAAPHovhPkWhRA5ewcAAAAAAD8U42Z3F6NmfwSH12RVIsOOPosp3oAf8Pl196emFm952En+4MA9FI33vmg55Ya17z1XmHVqi6LERLksusfDe3Fjig75qxpZmudlh65S/jt7++Pdm3G3hU3zQ5vvrvYgCRan372Rdii7RDzVJLqpGzzjuHhpoGhlEpLqlLz001h06Hbm0FVqiGbu8cbfwAAAFA7TtcAeqRg5wAAAAAAAAAAAAAAAIB4dN8Jci0KoHJ2DgAAAAAAKvKD5vx6DZn8TB9ekVTt7psxx6kewH/z1rsfhgGb7ZqYWX3z3Q/5owD0Usu+XJ6oPan3Pjc9ZjFCQpTL5dBe7Ii2c65+wFyt43bc61dRr8/Yu2T6rPDU/LcNSqK18J0PwpAtJ5qnklQnbdS8Q3i0af1QSqUlVakrB2TNnyrWJzN2I2/8AQAAQG04WQPokYKdAwAAAAAAAAAAAAAAAOLRfSfItSiAytk5AAAAAACoXKHwPxozrb9syOY6fXxFUjUaNHrP0Nm50qkewF8ol8th90MmJWZWp0cWwpKly/xhAHqxI39zoeeXGrf3EadZiJAQK1d2hfZiR9Stv8WeZmu9flC8pS2ceO6N0a/R2Jvx+Kth9eqygUmUHn3iudB3o/FmqiTVSSObx4Q5TQNCKZWWVIVe+qpthmxr/lSrTP4OL/sBAABAbThVA+iRgp0DAAAAAAAAAAAAAAAA4tF9J8i1KIDK2TkAAAAAAOixhuZ8piGbf8EHWCSt7Y477VInegD/TfHWBxI1qw857hx/FIBebtYT8zy/1Li+w8eHDz9abDFCAixbvjK0FzuibvNxR5itddzIsYeGi6c9Ev06jb07ZjwfVnSuMjTx36YkSTVv86Hbh8fT/UMplZZUhab1H2r2VK9y9ztu3vQDAACA6nOiBtAjBTsHAAAAAAAAAAAAAAAAxKP7TpBrUQCVs3MAAAAAAPCN9B016v9oyOTOaszmVvsIi6S11ePPvOhED+AvfPjR4rDhqD0TNavvf+gxfxiAXq5cLodNxh7oGabGXTLlVosREuDzL5aH9mJH1I074BRztc47bNLk6NdpPXTdXU+GT5d8aXASpVPPv8Y8laQ66kdDtwtPpgeEUiotqQrtOGQbs6dKNWRyN3vLDwAAAKrPaRpAjxTsHAAAAAAAAAAAAAAAABCP7jtBrkUBVM7OAQAAAADAt9LYnNuyMZNf6EMsktZ0G+90QCiXy070AP7Cfj8/M1GzesNRe4bOzpX+MACE37ZP9RxT40aNO8xChAT45LNlob3YEXX7H3eJuVrnDRo9MVxw3UPRr9V6aPItc8J7iz43PInO6tXlsM+Rp5upklRHbT102/BUul8opdKS1nI39R9i7lSvcp+h4wZ7ww8AAACqy2kaQI8U7BwAAAAAAAAAAAAAAAAQj+47Qa5FAVTOzgEAAAAAwLeWHlb4vxoyuWt9iEXSmuy37VOd5gH8hbsemJW4WX3MqZf4wwDwtdfffNdzTAJ68tmXLEaosQ8//iK0Fzui7rhzrjdTe0F7/uyc6NdqvXTZDY+GV95cZIASnaXLloftdjvSTJWkOmrbIduGZ1L9QimVlrSWyw/eytypUg3Z/FRv9wEAAEB1OUkD6JGCnQMAAAAAAAAAAAAAAADi0X0nyLUogMrZOQAAAAAAWGMas/mdGzP5j3yQRdKa6OXXFjrNA/izTz/7ImS2+UniZvWjTzznjwPAf2nd61jPMjXu6FPaLUSosXc//Cy0Fzui7pyrHzBTe0GpkRPCWb+/P/r1Wk89/pz/Hkp83nl/UWjeei9zVZLqqNyQrcNz6aZQSqUlrcXu7Dco9DFzqlMm19Un29rPm30AAABQPU7RAHqkYOcAAAAAAAAAAAAAAACAeHTfCXItCqBydg4AAAAAANaofx/c+oPGTO5OH2WR9G3a8cdHO8kD+AtH/ubCxM3qlu32CV2rV/vjAPBfrr3pPs8zNW7AZruGpcuWW4xQQ2++tzi0Fzuib8Bmu5urveG/we31q7pYr/XUjMdfDavLZcOUqDzxzIthvRE7m6uSVEcVBm8Z5qeaQimVlrQW2/Wrf9bMnGqVu9RbfQAAAFA9TtAAeqRg5wAAAAAAAAAAAAAAAIB4dN8Jci0KoHJ2DgAAAAAA1orGTG6vxmzuCx9lkfRNmjztTid5AH8264l5oU9LW+Jm9WkXTPHHAeCvLPliWWjauOCZpsbdeOeDFiPU0GtvfRTaix3Rt0nuMDO1F9T9rHni+TfXxZqtp+6Y8XzoXNlloBKVa264x1yVpDprt8Gjw/x0Uyil0pLWUvc3bRjWyebMnCrUkM2v+Oq3bvBGHwAAAFSH0zOAHinYOQAAAAAAAAAAAAAAACAe3XeCXIsCqJydAwAAAACAteYHQ1tTjZlch4+zSOpJfYePD4s+XuwkD+Ary75cHjYZe2Ai5/WLryzwBwLg/+egY8/2XFPjdt7/BAsRaqi04MPQXuyIvrH7TDJTe0mb5H9aF2u23pp+79Phi2UrDFWicsypl5irklRn7TvoR+GlVDqUJK21Jg4abd5Uq0zut97mAwAAgOpwcgbQIwU7BwAAAAAAAAAAAAAAAMSj+06Qa1EAlbNzAAAAAACwdo0a9d2GTO43X7XSB1okVdKeh538/7J3J15Sl3ei/zN3Mnd+59w55977O7+ZxO4WU8Uqa1W3iqIG96iB6kYtUdQY1JCoQY1bjEs0ahL3GGxcolGMWi7jvkWJS6AQjEhc0ULNIO5xQQFZGrr7+dmOZyaLYFXT1V3f7/f1Ouf9F9RTn4fq5/vwdYoH8JlTz/1VTc7q3fY7xocDwOd6aPZ8v2v6uIbGlrD4tbcsRugjz7/8dmgtFCPf5OOnmakJ6qifXB2LdRu3rrnjD+HdpSsMViKjrW1tGP+tE81VSYpZRw7dLpRSaUlV6uH+Q0I/s6Z3yjQv7zfim//Xw3wAAABQfU7OACqSt3MAAAAAAAAAAAAAAABAdHTdCXItCqB8dg4AAAAAAHpFQ2bclvWZ5he9pEXSF3XbfY86xQP4xB+fWxT6NU2oyVl9xXV3+oAA+Fzr2ttDZpeD/bbp485pvc5ihD7ydOmN0FooRr7jfnadeZqghu/07TDt+lmxWLtx64pb5obFb3xguBIZ77z7QWjcbbLZKkkx64ebjwmlVFpSlTpk2NfNml6qLtN8mqf4AAAAoPqcmgFUJG/nAAAAAAAAAAAAAAAAgOjouhPkWhRA+ewcAAAAAAD0ms3Gjv1/6jK5c+qzuQ4vapH0eQ3YZt/w8crVTvGAxGtrWxt23GdqTc7qfk0TwrvvL/UhAbBeZ1zwa79v+rimbxwS2js6LEboA/Offy20FoqR7+zL7jNPE9bkEy6JxdqNY9NvnBOefektA5bIWPBsKaRG72O2SlLMOn3I6FBKpSVVoVn9h4TNsjmzpjfK5N7/16H5f/EUHwAAAFSXEzOAiuTtHAAAAAAAAAAAAAAAABAdXXeCXIsCKJ+dAwAAAACAXrfJqJbd6rLNb3hZi6S/7cgfXeAED+AT502/oWZn9YHf/4kPCIANer70H37f1ECPzFlgMUIfmPfMq6G1UIx8026YHfptuZd5mqAGbTcpXDjj4Vis37g296nFobPTnCUabrzzd2arJMWws4aMDqVUWlIVOnzYduZMb9XYfIyn9wAAAKC6nJYBVCRv5wAAAAAAAAAAAAAAAIDo6LoT5FoUQPnsHAAAAAAA9Il0U/5/12Vyv/GyFkl/2UOz5zvBAxLvhZcWh81q+OX1d/x2tg8JgC+04z5T/cbp44446QILEfrArPmvhNZCMRaN3PkQ8zRhTTzynNis37h2f/GFsK69w7AlEk4951dmqyTFrIZPunDwFqGUSkvq4eb2HxzSmfFmTS9Ul829PnRo/n96eg8AAACqx0kZQEXydg4AAAAAAAAAAAAAAACIjq47Qa5FAZTPzgEAAAAAQJ+qz+TyddncB17aImnYDgeEtWvXOcEDEq29oyPsccBxNTurh2y3f1i1eo0PCoAvdPGVN/ud08elR+fDsuUfW4zQy2Y+VgqthWIsGrv3D8zThPW1rfYJ51z5QGzWcFy7debTYfWatQYuNW9de3vITznVfJWkmNUvkwuXD24MpVRaUg939NBtzZleapNM86Ge2gMAAIDqcVIGUJG8nQMAAAAAAAAAAAAAAACio+tOkGtRAOWzcwAAAAAA0Oc223LPr9Zlc/d5aYuU7E7++eVO74DEu3TG7TU9q4874xIfEgBlWfLGO6GhscVvnT7uhtsetBihl9396POhtVCMRS2HnWmWJrBxk0+PzRqOc7+5e374cPkqQ5eat/Sj5WGbcVPMV0mKWf2yuXDNoEwopdKSerB56UEhnRlvzvRCdZncK1/K5//RU3sAAABQHU7JACqSt3MAAAAAAAAAAAAAAABAdHTdCXItCqB8dg4AAAAAAGrFP9Q3tkypzzZ/7OUtUjJ74qkXnN4BibbkjXfCwDETa3pWz53/nA8KgLKN/9aJfuv0cRMmn2QhQi/79wefDq2FYiyafMI0szSBbdrYEs645K7YrOM4d9Vt88Lb7y0zeKl5Cxctrvm/eUmSKi+VyYXCwJGhlEpL6sGOGbqtGdNbZXJeVAsAAABV4oQMoCL+VgkAAAAAAAAAAAAAAAAR0nUnyLUogPLZOQAAAAAAqClfzbZsXp/JPenlLVKyGr3nYaGzs9PpHZBYXTNwv+/9uOZndUeHWQ1A+X5duMfvnRroT6++aTFCL7r+nidDa6EYi4772XXmaELbad8TYrOO494Vt8wNr775geFLzbvvobmhobHFjJWkmJXOjA+3DhgeSqm0pB5qXnrQp98tM6b61WVzT3/pS1/6B0/rAQAAQM9zOgZQkbydAwAAAAAAAAAAAAAAAKKj606Qa1EA5bNzAAAAAABQe8aO/XJ9tvmHdZncWi9xkZLROa3XObkDEu26Wx+o+Vl9buv1PigAKvLeBx+FzbbYy2+ePu7Cy2+0GKEXXXXb46G1UIxFZ196jzma4E46/6bYrOW4N/3GOeH5l982gKl5Z188w3yVpBg2ODMu3DdgWCil0pJ6qGOGbmu+9FIN2fG7e1APAAAAep6TMYCK5O0cAAAAAAAAAAAAAAAAEB1dd4JciwIon50DAAAAAICaVZdt2aYu0/yyl7hI8W/RK0uc3AGJ9c67H4TNvz6p5mf1y4tf92EBULH9Dz/db54+bptxU0JnZ6fFCL3k0hvnhNZCMRZNu35W2LRpglma0LYed0Rs1nJSmvv0YkOYmtbe0REmHXGGGStJMWzkqD3Do/2HhFIqLakH+kN6YBiQHW++9EaZ3GxP6AEAAEDPczIGUJG8nQMAAAAAAAAAAAAAAACio+tOkGtRAOWzcwAAAAAAUNO+MnLX/1WXyV1en23u9DIXKZ7tOvFop3ZAok0+5qc1P6u/edDxPigAuuWmux7yu6cGmvfk8xYj9IK2te2htVCMVcN2+JY5muCOOfva2K3puPfQ4y+Fjo5OA5ma9dGyFWHb3PfMWEmKYVuO2iPM7T84lFJpST3QMUPHmC29VF2meYwn9AAAAKBnORUDqEjezgEAAAAAAAAAAAAAAADR0XUnyLUogPLZOQAAAAAAiISGxuZv1GWa3/QyFyl+XTrjdqd2QGLd+cDsSMzqa2/5rQ8LgG5Z/vHK0H/rvN8+fdzxP7nEYoRemXmrQ2uhGKvGNE81RxNcZtdDwyU3zI7duo57dz3yXFi7tt1Qpma9vPj1MGT7/c1ZSYph2476RpifHhRKqbSkjewP6YFhQHa82dIL1WWab/dkHgAAAPQsJ2IAFcnbOQAAAAAAAAAAAAAAACA6uu4EuRYFUD47BwAAAAAAkbFJ07j/ry6Tu9ULXaT4tGlTS3jznfec2gGJtPSj5SGzy8E1P6vTo/Pho2UrfGAAdNt3jj/H758+bsh2+4dVq9dYjFBl7y5dEVoLxVi1x0GnmKMJ78gfXxm7dZ2EbnngqbBy9VqDmZr120fmhYbGFnNWkmLYLiN2DU+lBoRSKi1pIztm6BhzpVfKddSNbBnkyTwAAADoOU7DACqSt3MAAAAAAAAAAAAAAABAdHTdCXItCqB8dg4AAAAAACKnPpPLf9L7XuoiRb99vnOKEzsgsaaeclEkZvXhPzzfhwXARrnvobl+/9RAd9w/y2KEKnv9nQ9Da6EYqyYeea4ZmvBG7PztMO36WbFb20noN3fPDx8uW2U4U7MuvPxGc1aSYtr4ETuH51L9QymVlrQR/SE9MAzIjjdXeqG6TO4KT+QBAABAz3ESBlCRvJ0DAAAAAAAAAAAAAAAAoqPrTpBrUQDls3MAAAAAABBJm2ZzdXXZ3H1e7CJFuxtue9CJHZBIj8xZEJlZ/ehjC3xgAGyUNW1tYcj2+/sN1MdNOuJ0ixGq7JXX3guthWKs+u7Jl5mhClM+WQdxW9tJ6apb54W33l1mQFOTOjo6w7ePPtuclaSYNnH4jmFhKh1KkjaqHwwdY6b0QnWZ5tX/Nnz8VzyRBwAAAD3DSRhARfJ2DgAAAAAAAAAAAAAAAIiOrjtBrkUBlM/OAQAAAABApNVncvm6bPNSL3iRotfXtto7LP1ouRM7IHGWf7wybLXHYZGY1U3fOCS0d3T40ADYaFNPucjvoD5u06aW8NY771uMUEULX3k7tBaKserEcwpmqMLQsQeFX/7m97Fb30np8psfC4vf+MCQpiYtW/5xGDP+u2atJMW0ycPGhhdT6VCS1O3+kB4YBmTHmym9Uab5LE/iAQAAQM9wCgZQkbydAwAAAAAAAAAAAAAAAKKj606Qa1EA5bNzAAAAAAAQeV/N7rVZXab5YS94kaLVocf+zGkdkEgn/fSyyMzqn19ynQ8MgB7x4O//4HdQDTR9xu0WI1TRgoWvh9ZCMVadfdm95qc+bfIJ02K3vpPU9BvnhOdeesugpia98NLiMGCbfc1aSYpp3x+6XSil0pI2oh8MHWOe9EJ12eal/zo0/y+exAMAAICN5wQMoCJ5OwcAAAAAAAAAAAAAAABER9edINeiAMpn5wAAAAAAIC7+ob6xZUp9NrfCi16kaHTv7x5zWgckzrwnnw8NjS2RmdUvL37dhwZAj2hrWxuGbLe/30J93I57f99ihCp67KnFobVQjFXTrp8VNm2aYIYqDN5uUvjFtY/Ebo0nrceffdWwpibddt+jZq0kxbjTh4wOpVRaUjeblx4U+mfGmye9USZ3lEfwAAAAYOM5/QKoSN7OAQAAAAAAAAAAAAAAANHRdSfItSiA8tk5AAAAAACIlfrMNwfWZ3JzvehFqu2GbLd/WL2mzWkdkChdc2+75sMjM6tbJp/kQwOgRx158oV+D9VAzyx82WKEKpk5txRaC8XYNXTsQeanPu3AYy6K5RpPWg/NWxQ6OjsNbWrOcWdcYtZKUkxr+KQLhmwRSqm0pG52zNAx5kmvlFv8pbFjv+wJPAAAANg4Tr4AKpK3cwAAAAAAAAAAAAAAAEB0dN0Jci0KoHx2DgAAAAAAYuj0/1GfyR1dl21e42UvUm32g9N/6aQOSJwzL7o6UrO6cPtMHxoAPeq3jzzu91ANdNp5V1qMUCV3PvxcaC0UY9focUeYn/q0AdvsFy6c8VAs13nSum/WwrCuvcPgpqasaWsLe0w61ryVpJi2aTYXLh/cGEqptKRuNLf/4JDK5MyTXmiTTMv+nr0DAACAjePkC6AieTsHAAAAAAAAAAAAAAAAREfXnSDXogDKZ+cAAAAAACC2GkZOGF6faV7ghS9S7TVr3lNO6oBEeeq5l0K/pgmRmdP9t86HZcs/9sEB0KNWr2kLg7fdz2+iPm7EjgeFtWvXWZBQBTfcuyC0Foqxa+f9TjQ/9V9NPPLcWK7zJHb7Q8+GNv8moMa8+vrbYfOvTzJvJSmm9cvmwvWDRoVSKi2pGx05dDuzpDfKNC/w1B0AAABsHKdeABXJ2zkAAAAAAAAAAAAAAAAgOrruBLkWBVA+OwcAAAAAAPE2duyX67PNP6zL5tq8+EWqjbK7fju0d3Q4qQMSY+3adWGn/NRIzeqjTv2FDw6AqjjyRxf4XVQDPfDo4xYjVMGVt84LrYVi7Go57EyzU/9Veut8uPCah2K51pNY4b4F4eNVbQY4NeV3s+eHhsYWM1eS4vrvycz4cPvA4aGUSkuqsNn9B4fNsjmzpBeqyzbv7KE7AAAA6D4nXgAVyds5AAAAAAAAAAAAAAAAIDq67gS5FgVQPjsHAAAAAACJsEljS1Ndtvl5L36R+r7Tz7/KKR2QKOdfekPkZvVjTzzrgwOgKu5/eK7fRTXQd44/x2KEHtbe3hFaC8VYduAxF5md+qv2m3pebNd7Erv2rvnhw+WrDHJqys+m/ca8laQYNzQzLvyu/+ahlEpLqrDvDNveHOmF6jK5BzxtBwAAAN3ntAugInk7BwAAAAAAAAAAAAAAAERH150g16IAymfnAAAAAAAgMQYM2P2f67LNP6/PNK/zAhip73pm4ctO6YDEeOGlxeFrW+0dqTk9es/DQkdHpw8PgKpYvaYtDNp2ot9GfVx6dD4sW/6xBQk9aNmK1aG1UIxlR5z6K7NTf1X/MRPDhTMeiu2aT2JX3/54eHfpCsOcmtHe0RHyU041cyUpxmVH7Rlm9x8cSqm0pAp6dMCQ0M8M6Y066zMTRnnaDgAAALrHaRdARfJ2DgAAAAAAAAAAAAAAAIiOrjtBrkUBlM/OAQAAAABA4myazW1Rl8095wUwUu+3fcvhTuiAxFjX3h72OOC4yM3qCy+/0YcHQFV978Tz/D6qgW6883cWI/Sgt99bFloLxVh24jkFc1N/16Sjzo/tmk9qV9wyN7z29ocGOjXj3fc/DI27TTZzJSnGbTvqG+HJ9MBQSqUlVdC3h33dDOmF6jK56zxlBwAAAN3jpAugInk7BwAAAAAAAAAAAAAAAERH150g16IAymfnAAAAAAAgkZqapvxTfbb5h3XZXJsXwUi910VX3OSEDkiM6dfcFrk5vWlTS3j9rXd9eABU1e33/d7voxpo3ymnWYzQg1557b3QWijGsrOm321u6u/qP2ZiuHDGw7Fd90ntspvmhJeXvGeoUzMWPFsKX9tqb3NXkmLcLiN2Dc+kB4RSKi2pzGYO2Dxsms2ZIVWuLpNbu0nTuH6esgMAAIDKOeUCqEjezgEAAAAAAAAAAAAAAADR0XUnyLUogPLZOQAAAAAASLRNmsY11mWan/EyGKl3+o8lbzqhAxLhT6++GfpvnY/cnD5o6pk+PACqbulHy0O/pgl+I/Vxmza1hLf//L4FCT3k2UVvhdZCMZb94tpHzE19bgccdX5s132Sm37jnPDcy28b7NSMK66708yVpJi3z/Adw8JUOpQkld0Bw8aaH71RpvlCT9cBAABA5ZxwAVQkb+cAAAAAAAAAAAAAAACA6Oi6E+RaFED57BwAAAAAACReU9OUf6rPNv+wLptr80IYqXqNO+gEp3NAInR0dIa9DvlRJGf1bx953AcIQK+I6l4Zt6647k6LEXrIvGdeDa2FYmxLb503N/V3Ddhmv3DhjIdjvfaT3NynFxvu1ITOzs7w3RPPM3clKeZ9e9jXw4updChJKqsH+28eNs3mzI9ql2lenm7K/29P1wEAAEBlnHABVCRv5wAAAAAAAAAAAAAAAIDo6LoT5FoUQPnsHAAAAAAA8Jm6Uc2Z+mzuKS+FkarTVTfc7XQOSISrb7o3knM6s8vBYd26dh8gAL1i+jW3+Z1UA+2+/7EWI/SQhx9/KbQWirFt5M6HmJv63A485sJYr/2k9/v5r4TOTjOevrf845Vh+5bDzV1Jinknbr5NKKXSksosP3xHs6M3amw+xlN1AAAAUBmnWwAVyds5AAAAAAAAAAAAAAAAIDq67gS5FgVQPjsHAAAAAAD8pbFjv1yfbf5hXbZ5jRfDSD3Xpk0t4Z13P3A6B8Te62+9GwZvu18kZ/XPpv3GBwhAr1n0yhK/lWqkrs8C2Hh3P/p8aC0UY9vW4480M/W5Ddhmv3DRjEdivf6T3v2zXwjt7R0GPX2u9PKSMHDMRLNXkmLe2UO2CqVUWlIZ3TNwaGgwN3qh3OIv5fP/6KE6AAAAKJ+TLYCK5O0cAAAAAAAAAAAAAAAAEB1dd4JciwIon50DAAAAAAA+R312/Mj6TPMCL4aReqaJ3z3NyRyQCJOOOCOSc7qhsSX8x5I3fYAA9Kptxk3xe6kGOm/6DRYj9ICb7v9jaC0UY9tOE483M7XeDjzmolivfxXDHQ8/G9rWthv29Lnb7nvU3JWkmNfwSdMGN4ZSKi2pjJqH72R29E57e5oOAAAAyudUC6AieTsHAAAAAAAAAAAAAAAAREfXnSDXogDKZ+cAAAAAAID1aGqa8k/12dyZXgwjbXyF22c6mQNi76a7HorsnN53ymk+QAB63ann/MrvpRpom3FTQmdnpwUJG+nXtz0eWgvF2DZ+8o/NTK23QdtNChf/5tFYfwdUDDc/8FRYtWatgU+fO+mnl5m9khTzNsvmwg0DR4ZSKi3pC/r3gSPMjd4okyt6kg4AAADK50QLoCJ5OwcAAAAAAAAAAAAAAABER9edINeiAMpn5wAAAAAAgA3YZFTLbl4OI21cX9tq7/DRshVO5oBYe/f9pWHo2AMiO6vvfGC2DxGAXve72fP9ZqqRnnymZEHCRli7rj20FoqxbuKR55iX2mCTT7gk9t8DFcMN9z4ZVqxcY/DTp9ra1oY9Dzze7JWkmDcgOz7cPWBYKKXSkr6g3UfsYm70Qg2ZcVt6kg4AAADK40QLoCJ5OwcAAAAAAAAAAAAAAADo2z25AAAgAElEQVRER9edINeiAMpn5wAAAAAAgA2oz+Yu8GIYaeM65Ac/cyoHxN5hx0X3BfPDdzgwrGlr8yEC0OuWfrQ8NDS2+N1UA516zq8sSNgIH3y0MrQWirFu8gnTzEttsGE7fCtMu35W7L8LKoZr73oifLh8leFPn3rznffCiB0PMn8lKeYNzYwLD/XfPJRSaUkbaMbAUWZGr5QreJIOAAAAyuM0C6AieTsHAAAAAAAAAAAAAAAAREfXnSDXogDKZ+cAAAAAAIANqMvmnvZSGGnjuvOB2U7lgFi768FipOf0GRf82ocIQJ/5+oQj/G6qgUbudFBY195uQUI3LX7jg9BaKMa6759+lXmpL+zwU6+I/XdB/9nVtz8e3vvwYxsAferh4pOhobHF/JWkmLflqD3CvPSgUEqlJW2gHUZ+w8yocnWZ3Nr6ERMaPE0HAAAAX8xJFkBF8nYOAAAAAAAAAAAAAAAAiI6uO0GuRQGUz84BAAAAAADr8ZWRE/6tPtvc6cUwUvcbOGZiWLlqtVM5ILaWfrQ8ZHY5ONKzetErS3yQAPSZH5z+S7+daqRH5iywIKGbnln0ZmgtFGPdiecUzEp9YaN2mRwuuWF27L8P+s+uvHVeePu9ZTYB+tSZF11t/kpSAtpx5G7h6fSAUEqlJa2nSwc1mhe9UF0md44n6gAAAOCLOcUCqEjezgEAAAAAAAAAAAAAAADR0XUnyLUogPLZOQAAAAAAYD0aMs2TvBBG2ri+f8pFTuSAWJv6yZyL8pxu/vYPfYgA9Knrb3vQb6caaarfb9Btc/74H6G1UIx1Z1xyp1mpsjr6zGti/33Qf3fFLXPDa29/aCOgz6xb1x5yB59o/kpSAtp7xE5hYSodSpI+t4Xp/mHLUXuYF1WuLtu89F+H5v/FU3UAAACwYU6xACqSt3MAAAAAAAAAAAAAAABAdHTdCXItCqB8dg4AAAAAAFiP+mzuGi+EkTaumbOecCIHxNbDxScjP6dvu+9RHyQAfaprL/LbqTYatO3EsGr1GosSuuH+2S+E1kIx1p131UyzUmW15Z6Hx/77oL/uspvmhFdee89mQJ9Z8sY7Ycj2+5vBkpSAvjNs+1BKpSWtp/MGb2lW9EJ1meYjPFUHAAAAG+YEC6AieTsHAAAAAAAAAAAAAAAAREfXnSDXogDKZ+cAAAAAAID1qM/kXvMyGKn7DR17QFi7dp0TOSCWln+8Mmy5+6GRntMjdjworGlr82EC0KdaJp/k91MNdf/Dcy1K6Iabf/tUaC0UY92062eFhsYWs1JldeI5hdh/J/TXTb9xTlj4yjs2BPrMPTPnmL+SlJBO3nzrUEqlJX1Oz6X6hxGj9jQrqlxdtvmlL33p9P/hyToAAABYP6dXABXJ2zkAAAAAAAAAAAAAAAAgOrruBLkWBVA+OwcAAAAAAHyOr2ZbNvciGGkjX5571nSncUBsnfDJjIv6nP7ZtN/4IAHoUwsXLfbbqcb6/ikXWZjQDVfeOi+0FoqxLzV6H7NSZbX9Xkcn4juhv++pF9+wKeDvdZKkqnfu4C1DKZWW9DmdPmS0OdEL1TW2jPN0HQAAAKyfkyuAiuTtHAAAAAAAAAAAAAAAABAdXXeCXIsCKJ+dAwAAAAAAPkd9JneUl8BIG9fc+c85jQNiqWu+NTS2RHpGb9rUEpa88Y4PE4A+dfyZrX471ViDt90vrGlrszihAm1r14XWQjERbf71A81Kld2pF/17Yr4b+uvmPr3Y5kCf6Pp37K4TjzaDJSkB9cvkwq8HjQqlVFrS37QgPSAMzowzK6pcXab5YU/XAQAAwPo5uQKoSN7OAQAAAAAAAAAAAAAAANHRdSfItSiA8tk5AAAAAADgc9Rncnd7CYzU/Rp3mxw6OjqdxgGxs2r1mrBt7nuRn9MHH3WWDxOAPvXRshVhwDb7+v1Ugz1cfNIChQq8u3RFaC0UE1Fm10PNSZXdzvudkJjvhv6+WfNfCZ3+PEwfWPTKEr8zJCkhpTPjw+0Dh4dSKi3pbzp+6BhzojfKTBjlCTsAAAD4fE6tACqSt3MAAAAAAAAAAAAAAABAdHTdCXItCqB8dg4AAAAAAPhbY8d+uT7TvMwLYKTu95MLr3YSB8TS6edfFYs5/XDxSR8mAH3q8t/c6bdTjXbcGZdYoFCBP73+fmgtFBPR1uOPNCdVdg2NLeGsS+9OzPdDf9/v5i4KHZ2dNgp63fW3PWgOS1JCGpoZFx7qv3kopdKS/qJ56UEhnRlvTlS/GR6yAwAAgM/nxAqgInk7BwAAAAAAAAAAAAAAAERH150g16IAymfnAAAAAACAv7FJY/P2XvwibVxPPfeSkzggdv743KLQr2lC5Gf06D0PC+0dHT5QAPpMR0dn2Db3Pb+darQROx4U1rW3W6hQpqdefCO0FoqJaIf8ceakKqr5kJ8k5vuhz+++WQtDe7u/QdD7Dv/h+eawJCWkLUbuEealB4VSKi3pLzpi2HZmRJWryzav2WzLPb/qSTsAAAD4e06rACqSt3MAAAAAAAAAAAAAAABAdHTdCXItCqB8dg4AAAAAAPgb9dncmV7+InW/MeO/Gzo7O53EAbHS1rY27LjP1FjM6ekzbveBAtCnHi4+6bdTjTfniWcsVCjT7Cf/FFoLxUS0+4Enm5GqqK9ttU84/+qZifmO6PO765Hnwtp17TYMetXHK1eH7VsON4slKSHtPHLX8HR6QCil0pI+69H+Q0I/86Hq1WVyP/akHQAAAPw9p1UAFcnbOQAAAAAAAAAAAAAAACA6uu4EuRYFUD47BwAAAAAA/I26TPM8L36Rut/5l97gFA6InXNbr4/FjE6N3ie898FHPlAA+tRBU8/026nGO/nnl1uoUKZ7Hn0+tBaKiaj5MPNblTfpqAsS8x3R+rt15jOhbe06mwa96pmFL4evbbW3WSxJCWnv4TuGhen+oZRKS/qsg4aPNR+qXF0m99bQofn/6Wk7AAAA+GtOqgAqkrdzAAAAAAAAAAAAAAAAQHR03QlyLQqgfHYOAAAAAAD4C5uNav4/9ZnmdV78InW/Ra8scQoHxMoLLy0Om225Vyxm9NGnXewDBaBPvfr622HTpha/nWq8zC7fDh0dnRYslOHau+aH1kIxEe33/XPNSFXcoO0mhYuvezQx3xOtv5t/+1RYvWatjYNeddm1d5jFkpSgpgzbPpRSaUmfdd+AYaHBbKh6ddncfp64AwAAgL/mlAqgInk7BwAAAAAAAAAAAAAAAERH150g16IAymfnAAAAAACAv7DJqOYWL3yRut+uE492AgfEyrr29rDHpGNjM6cXPFvyoQLQp8686Gq/nSLSE0+9YMHCF/5e6AjTbyyG1kIy+taxvzAf1a2mnHx5Yr4n2nA33LsgfLyqzQZCr+ns7AwHTT3TLJakBHXmkNGhlEpL+qzxI3Y2G6rfHE/cAQAAwF9zSgVQkbydAwAAAAAAAAAAAAAAAKKj606Qa1EA5bNzAAAAAADAX6jP5qZ72YvU/VqvvtUJHBArl/z632MzoxsaW8LBR50VLr7y5jBr3lNh+YqVPmAAetWq1WvCsB0O8NspIv304hkWLXyBd5euCK2FYmI67KTp5qO6VWbXQ8MlN8xO1PdF6+/6e58MK1ausYnQa95fuiw07jbZPJakhNTwSZcOagylVFrSJ103aKTZ0Att0jSu0VN3AAAA8N+cUAFUJG/nAAAAAAAAAAAAAAAAgOjouhPkWhRA+ewcAAAAAADwF+qzuUVe9iJ18wVljS3htTf/7AQOiI2XF78e0qPzsZ3bmza1hB33mRpOPedX4b6H5oYPPlzmQwegqgq3z/TbKULtMelYixa+wEuvvhtaC8XEdPipV5iP6nbH/vS6RH1ftOGuvWt++GjFahsJveaxJ54N/ZommMeSlJBSmVy4dcDwUEqlJX3S2JG7mQ3VLtN8tafuAAAA4L85nQKoSN7OAQAAAAAAAAAAAAAAANHRdSfItSiA8tk5AAAAAADgM/2aJmziRS9S92uZfJLTNyA2Ojo6P51rSZrjDY0tYdeJR4efXjwjzHvy+bCuvd1CAKBH7b7/sX47RahNm1rCBx8us3BhA/7w7JLQWigmpqN+co35qG63/V5HJ+r7oi9uxp1PhA+Xr7KZ0GvOv/QG81iSEtTmo8aFh/pvHkqptJT4pg1uNBeqXF22ec1XRk74N0/fAQAAwH9yMgVQkbydAwAAAAAAAAAAAAAAAKKj606Qa1EA5bNzAAAAAADAZxoyzZO86EXqflffdK/TNyA2fl24J/Fzfcj2+4cpJ5wbbr/v92H5ipUWBQAb5YmnXvC7KYLd//Bcixc24IE5L4bWQjExHf/z681GdbuGxpZw+rQ7EvWd0Rd39e2Ph/c//NiGQq9o7+gIex16spksSQlqi5F7hHnpQaGUSkuJbmGqf8iO2tNcqHaZ3EmevgMAAID/5GQKoCJ5OwcAAAAAAAAAAAAAAABER9edINeiAMpn5wAAAAAAgM/UZZt/5SUvUvfabIu9wrvvf+j0DYiFJW+8EwaOmWi+/0Wp0fuEg486K9xy98Nh+YqVFgkAFTvyRxfYUyPYhZffaPHCBtx4/x9Da6GYmH50wc1mozaqPQ46OVHfGZXXVbfOC39+f4VNhV7x1jvvh+E7HGgmS1KC2nnkruGZ9IBQSqWlRHfmkNFmQrXLNC/50tixX/YEHgAAAHz6n0ECUL68nQMAAAAAAAAAAAAAAACio+tOkGtRAOWzcwAAAAAAwGfqss0vecmL1L0mHXG6kzcgFjo7Oz+daWb7+kuN3iccfNRZ4Z6Zc8K6de0WDQBf6N33l4avbbW3fTSCTT3lIgsYNvDb4bKbHwuthWJiOn3aHWajNqp+W+4Vzr3qwUR9b1ReV946L7z93nKbC71i5qwnQkNji7ksSUk6yx6+Q3gh1T+UUmkpsf0xNSAMyowzE6re+L08gQcAAACf/meQAJQvb+cAAAAAAAAAAAAAAACA6Oi6E+RaFED57BwAAAAAAPCJTbO5Oi92kbrfTXc95OQNiIXCHb8z1yto1M7fCmdedHX406tvWjwArNdFV9xk34xoJ5w13QKG9fho+erQWigmqrMvu9ds1Ea339TzEvfdUXldccvc8Po7H9pg6BWnnXelmSxJCeu4zceEUiotJbofDB1jHlS5umzuUU/hAQAAwKf/GSQA5cvbOQAAAAAAAAAAAAAAACA6uu4EuRYFUD47BwAAAAAAfKIh0zzJy12k7pUavU9YvmKlkzcg8t7+8/thyPb7m+3dqKGxJew75bRwz8w5Yd26dosJgP/StS807jbZfhnRzpt+g0UM67H4jQ9Ca6GYqM698gGzURvd4O0PCNOun5W474/K6/KbHwuvvf2hTYaqW9PWFnbKTzWXJSlhnTNky1BKpaXENqf/oLBZNmceVPvcdOSE4Z7EAwAAIOmcRgFUJG/nAAAAAAAAAAAAAAAAgOjouhPkWhRA+ewcAAAAAADwibpM7govdpG61+RjfurUDYiFQ37wM3O9B9pqj8PCVTfcHVauWm1RARDunjnH/hjh7rh/lkUM6/HHF14PrYViovrFtY+YjeqRjvjxlYn7/qj8LrvpsfCn19+30VB1CxctDqnR+5jLkpSg+mVy4deDRoVSKi0ltsnDxpoHVa4uk7vck3gAAAAknZMogIrk7RwAAAAAAAAAAAAAAAAQHV13glyLAiifnQMAAAAAAD5Rn80t8mIXyUvWgeS69d5HzfQebsSOB4ULL78xLP1ouQUGkGB7HfIj+2KEe+GlxRYxrMfDj78UWgvFRDXt+llmo3qk0eMOT9z3R5V12U1zwiuvvWezoeouu/YOc1mSElY6Mz7cOWB4KKXSUiJ7oP/Q0GAWVLdM88qGofn/19N4AAAAJJlTKICK5O0cAAAAAAAAAAAAAAAAEB1dd4JciwIon50DAAAAAIDE69c0YRMvdZG6+dKx0fmw/OOVTt2ASHt/6bIwcqeDzPUqNXDMxHDaeVeGN9/xMmyApFn0ypLQ0NhiP4zwHr5uXbuFDOtx68ynQ2uhmLjMdfVUp1x4SyK/Qyq/S2+cExa9+q4Nh6rq6OgM+045zVyWpIQ1YtSeYXb/waGUSkuJrHn4TmZBlavL5o71RB4AAABJ5hQKoCJ5OwcAAAAAAAAAAAAAAABER9edINeiAMpn5wAAAAAAIPEaMs2TvNBF6l7fOf4cJ25A5E054VwzvRf62lZ7h+N/ckl46533LTqAhDjxrOn2wAi3/+GnW8SwHp2dIVxxy9zQWigmrs222NuMVI+0+0GnJPI7pMqafmMxvPCnd2w8VNXbf34/DNvhALNZkhLWtiN3DwvSA0MplZYS1/UDR5kDVS+3+Ev5/D96Kg8AAICkcgIFUJG8nQMAAAAAAAAAAAAAAACio+tOkGtRAOWzcwAAAAAAkHh1mdwVXuYida+7Z85x4gZE2j2fzDHzvHfrv3U+/PSX14blH6+0AAFibNnyj8PAMRPtfRHu4itvtpBhPT5ctiq0FoqJLD16XzNSPdJmW+wdzrtqZmK/S6qs5156y+ZDVd3x29lmsyQlsJbhO4eFqXQoSQls+5HfMAeqXF1jyzhP5QEAAJBUTp8AKpK3cwAAAAAAAAAAAAAAAEB0dN0Jci0KoHx2DgAAAAAAEq8+21zyMhep8gZss29YuWq1EzcgspZ+tDxkdjnYTO+jRux4ULjqhrvDuvZ2ixEghn51/V32u4j3+B8XWsiwHi8teS+0FoqJbOCY/cxI9ViTjjo/sd8lVd6zL71lA6Kqjjz5QrNZkhLY1KHbhVIqLSWuiwZvYQZUubps7j5P5QEAAJBUTp4AKpK3cwAAAAAAAAAAAAAAAEB0dN0Jci0KoHx2DgAAAAAAEq1f04RNvMhF6l6H//B8p22AF+Vqo/v6hCPCPTPnWJAAMdLZ2Rm2bzncPhfh0qPzYU1bm8UM6zHv6cWhtVBMZIO3P8CcVI/VtZ6mXT8rsd8nVd4zi960CVE1y1esDKP3PMx8lqQEds6QLUMplZYS1XOp/mF45ptmQFXLdXxl5PiUp/MAAABIIidPABXJ2zkAAAAAAAAAAAAAAAAgOrruBLkWBVA+OwcAAAAAAIm2SaZlfy9xkbrXbx+Z57QNiKyZs54wy2us/b734/AfS7wcGyAOHn1sgb0t4u3znVMsZNiAux99PrQWiols2A4HmZPq0Y48/arEfp/UvZ5Z5G8HVM/jf1wY+jVNMJ8lKWH1y+TCjEGZUEqlpUR10ubbmAFVri7b/HNP5wEAAJBETp0AKpK3cwAAAAAAAAAAAAAAAEB0dN0Jci0KoHx2DgAAAAAAEq0uk7vcS1ykyhu87X5h9Zo2p21AJC1fsTJssfsh5nkN1n/rfJh+zW2hvaPDQgWIsIOPOsu+FvEuuKxgIcMGXH37H0JroZjIRuz8bXNSPdrW449M7PdJ3e/p0ps2I6rm7ItnmM+SlMAGZsaH+wcMDaVUWkpM89KDQiqTMwOqWu7PAwbs/s+e0AMAACBpnDgBVCRv5wAAAAAAAAAAAAAAAIDo6LoT5FoUQPnsHAAAAAAAJFp9trnkBS5S5U095SInbUBkHXfGJWZ5jbfbfseEZ198xWIFiKDX33o39GuaYD+LeE8+U7KYYT1WrV4bWgvFxJbZ7VBzUj3e6b+8I9HfK3Wvp0tv2pSoira2tZ/+bcp8lqTk1ThqjzAvPSiUUmkpMR0y7Ou+/1Vuk0zL/p7QAwAAIGmcOAFUJG/nAAAAAAAAAAAAAAAAgOjouhPkWhRA+ewcAAAAAAAk1r8NH/+V+mxzpxe4SJX34O//4KQNiKQ5TzwTGhpbzPIItNkWe4Wf/vLaT19kDEB0nH3xDPtYxBu+w4GhvaPDYob1WPLW0tBaKCa2pt2nmJXq8XKHnpHo75W635MLX7cxURWLXlkS0qPzZrQkJbAdR+4WnkkPCKVUWkpED/QfGhp896taXaZ5lqf0AAAASBqnTQAVyds5AAAAAAAAAAAAAAAAIDq67gS5FgVQPjsHAAAAAACJVZ8dv5eXt0iVt/nXJ4W2trVO2oDIWfHxqjB6z8PM8oi1U35qePr5lyxggAhYvaYtDN/hQPtXxJt6ykUWM2zAgoWvh9ZCMbFtsfsUs1I9XnrrfcMvrn0k0d8tdb8nn3/N5kRVXHXD3Wa0JCW0/YfvEF5MpUNJSkjjRuziu1/lGkZOGO5JPQAAAJLESRNARfJ2DgAAAAAAAAAAAAAAAIiOrjtBrkUBlM/OAQAAAABAYtVnc+d7cYtUeT84/ZdO2YBIOvnnl5vjEW2zLfYKF15+Y+jo6LSQAWpY4Y7f2bdi0J0PzLaYYQMefKwUWgvFxNa0x3fNSlWlKSdfnujvljau+c+/ZoOix3V2doYDv/8TM1qSEtpJm28TSqm0lIhmDMr43le7TPMlntQDAAAgSZw0AVQkb+cAAAAAAAAAAAAAAACA6Oi6E+RaFED57BwAAAAAACRWfbZ5jhe3SJX3yJwFTtmAyJn35POhobHFHI943z767PDhRyssaIAatcekY+1XEa9f0wR7LXyB6+99MrQWiomtaY/vmpeqSlvueXiiv1va+OY//5pNih73zrsfhOE7HGhOS1ICa/ikSwY3hVIqLcW+Fz9pm5G7++5XsbpM7qOvjNz1f3laDwAAgKRwygRQkbydAwAAAAAAAAAAAAAAAKKj606Qa1EA5bNzAAAAAACQSAMG7P7PdZnm1V7cIlXW0LEHhLVr1zllAyJl1eo1Ydvc98zxmLTVHoeFBc+WLGyAGjP/6RftUzFor0NPtphhA9auaw/TbyyG1kJy22IPv61UvU77xW2J/n5p45v/3Gs2K3rcbx+ZZ0ZLUkLrl82FmwaOCKVUWop95w7e0ve+yjVkmg/zxB4AAABJ4YQJoCJ5OwcAAAAAAAAAAAAAAABER9edINeiAMpn5wAAAAAAIJHqG8dv7YUtUuUdf2arEzYgcs644NdmeMzabIu9wvRrbgudnZ0WOECNOPLkC+1RMWj6jNstZtiAt99bHloLxUS3xZ7fNS9VtcZP/nHiv2Pa+OY//5oNix53zI9/aU5LUkIbmhkXHuk/JJRSaSnWPZ0eEIZkvul7X9VyT3liDwAAgKRwugRQkbydAwAAAAAAAAAAAAAAAKKj606Qa1EA5bNzAAAAAACQSHXZ3LFe1iJV3uzHn3bCBkTKgmdLoV/TBDM8pn33xPPCylWrLXSA/5+9Ow+TqjoUva3nS85J7vnOcM+5uTk2g3Y1k6BQTYOIMyqKCNWAtmMwSpyNJipqoiYah6gx4lSoOE802mqMonHAONCAA86KVscBxXkWZRB6WN9u7C8JkaEKu7qrdr3v8/z+95G91tq719q1O9lHn3weyofsbm2KQQ2vvumChjV4NvNOSNfWl3SDRx5qvlTear2fOO/aB0p+nOnbN+fZ+RYt2tWixUvDlilroCSValv03zk8legZMuUJKdYdu/EWxnye6zpgzGZO7QEAAFAK7C4B5KTGygEAAAAAAAAAAAAAAADFo/WdIK9FAWTPygEAAAAAQEnqUlld52MtUm713358aGxqssMGFI1ly5aHYbsfaQ6PecP3/Fl49/2PXfAAneiCK262JsWgzXc9yMUMa3Hf7ExI19aXdINHHmbOVF478BeTS36cqX2a8+x8Cxft6vFnXgrdq8aaqyWpRKveZPswrzwRMlKMm1nRO3Q33vNbsvpqp/YAAAAoBXaWAHJSY+UAAAAAAAAAAAAAAACA4tH6TpDXogCyZ+UAAAAAAKAklVVWv+1jLVJu/eLMS+2uAUXlrItvMH+XSFU7TwjzGua76AE6QWNTUxg0YoL1KAad+vurXNCwFtffOTeka+tLusEjDzNnKq9V7nxgyY8ztV+PP/+mxYt2dU76RnO1JJVwP++7ZciUJ6RYt2e/YcZ7HitLppZ07VvzX07uAQAAEHd2lQByUmPlAAAAAAAAAAAAAAAAgOLR+k6Q16IAsmflAAAAAACg5GxQNaq7D7VIuTf7ieftrgFF48XM62HDwePM3yVU7y33Cg/NfsrFD9DB7pox2zoUkx57ep4LGtZgydLlIV1bX/INGXWYOVN576TzbjHe1G7NfWGBRYx209jYFHba6+fmakkq4c7rMyhkyhNSbLup56bGet5LHe30HgAAAHFnVwkgJzVWDgAAAAAAAAAAAAAAACgere8EeS0KIHtWDgAAAAAASk5ZZWovH2iRciu54/6hqbnZ7hpQHB+3bWoKI/Y+xvxdgm04aFy48bb7DAKADrT7QSdZg2LxzPdjz3ywFq+99XFI19aXfENGHWbeVN4b+eOTjTe1a0++uMBCRruZ1zA/bLTZbuZrSSrRulemws09Nw2Z8oQU27buv7Pxnt8y66233vpO8AEAABBndpQAclJj5QAAAAAAAAAAAAAAAIDi0fpOkNeiALJn5QAAAAAAoOSUJVMX+UCLlFsnn3O5nTWgaEyacpO5u4TrOnDMimsAgPxreG3BinnX+lP8nXDGJS5oWIs5z84P6dr6km/QLoeaN5X3yofsHiZd+6Axp3btqXlvWczw90dJUru08YBR4cGKPiFTnpBi2Xl9Bhnr+W5AapgTfAAAAMSZ3SSAnNRYOQAAAAAAAAAAAAAAAKB4tL4T5LUogOxZOQAAAAAAKDllyeq5PtAi5dZjT8+zswYUhZdfeSNstNlu5m6F0yZdbUAA5Nkvf3upNScmPTznaRc0rMXtDzwf0rX1Jd/AEQeZN9UhHXLipcac2r2nX3rLgka7aGxsCiP2PsZ8LUkl3Bb9dw5PJXqGTHlCil3PJXqEjQeMMtbzWTJ1sxN8AAAAxJndJICc1Fg5AAAAAAAAAAAAAAAAoHi0vhPktSiA7Fk5AAAAAAAoKV03r/l+WTK13AdapOwbNGJCaG5usbMGFP7HbJuawsgfTTR366+dNulqAwMgT75ctI2q6TIAACAASURBVCT03nIv600M2nibfcLy5Y0ualiDlpaWMKVuTkjX1pd8A4b/xNypDmlo6ghjTnnp+b+8a2GjXTS8tiAkhtSYsyWphBu7yfZhXqIiZMoTUuw6uu8WxnkeK6tMLfufZM0PnOQDAAAgruwkAeSkxsoBAAAAAAAAAAAAAAAAxaP1nSCvRQFkz8oBAAAAAEBJ6Zocs62Ps0i59etzr7SrBhSF9NW3mrf1jX5z3tUGB0AeXFU73ToTk448aZILGtbiw0+/DOnaekX13+EAc6c6pK4Dx4TTL7nTuFNeeuGV9yxutIsLrrjZnC1JJd6xG28RMuUJKXY9UtEndE+mjPM8VpasPtZJPgAAAOLKLhJATmqsHAAAAAAAAAAAAAAAAFA8Wt8J8loUQPasHAAAAAAAlJQuydG/9GEWKbcef+Ylu2pAwXt1/tuhYvMa87ZW2am/v8ogAWhHLS0tYZuxh1tjYtI9Dz7mooa1eOEv74Z0bb2i+m23n7lTHVbNYWcZd8pbL77yngWOb62xqSmM/NFEc7YklXiTeg8KmfKEFLv22GR7Yzy/ZdZbb731neYDAAAgjuwiAeSkxsoBAAAAAAAAAAAAAAAAxaP1nSCvRQFkz8oBAAAAAEBJ6VKZut1HWaTsS+64f2hubrGrBhS01nlq7AG/MG9rjZ1y7pWhpcWaBtAeHp7zjLUlJvUYukdYsvQrFzWsxQOPNoR0bb2i+myzr/lTHVafbX4ULpo609hTXpo8rT5k5n9gkeNb+8vrb4XEkBrztiSVcBtWpkJdz01Dpjwhxaranv2N8Ty3QdWYrZzmAwAAII7sIAHkpMbKAQAAAAAAAAAAAAAAAMWj9Z0gr0UBZM/KAQAAAABASemSrH7TR1mk7DvprCl21ICCd+XUO83Zyqpz0jcaMADt4ICfn2ldiUkHH3eOCxqycONdT4Z0bb2iem21j/lTHdoxZ1xv7ClvTZ42KzS88aGFjm/toitvMWdLUom3SXLXMLOid8iUJ6RYtVX/nY3x/Hat03wAAADEkd0jgJzUWDkAAAAAAAAAAAAAAACgeLS+E+S1KIDsWTkAAAAAACgZZYPH/LePsUi5NeuJ5+yoAQXtzbffD7223NOcray75ua7DRyAb2HBOx+E7lVjrSkx6fZ7ZrqoYS2WLmsM6dp6tdVj6F7mT3VoO+x1vLGnvHbJtFnh1QUfWfD4VhqbmsLIH000b0tSibdN/53Cs4keIVOekGLT73oPNr7zWbJ6caKq5j+c6gMAACBu7B4B5KTGygEAAAAAAAAAAAAAAADFo/WdIK9FAWTPygEAAAAAQMnYYMCYnXyQRcq+TYeNX/EhSIBC1dLSEvY69NfmbOVU96qx4d6HHjOAANbRmRdcaz2JST2G7hEWLV7qooa1eP2tj0O6tl5tJTarMYeqQ+s2aFz43VX3G3/Ka5fcNGvFfA/fxivz3wqJIdZJSSr19txkWHi5PBEyUkx6LtEj9EnuanznsbLkmMOc6gMAACBu7BwB5KTGygEAAAAAAAAAAAAAAADFo/WdIK9FAWTPygEAAAAAQMnoUll9go+xSNk38bS03TSgoF1Xd4/5WutUj6F7hKeezxhEADn6atmysOmw8daSmHTI8b9zUUMW6p96PaRr69XWhoN2M4eqw9v/2AuNP+W9S2+aFea//YmFj28lffWt5m1JUjhp481DpjwhxaajNt7S2M5vTzvVBwAAQNzYNQLISY2VAwAAAAAAAAAAAAAAAIpH6ztBXosCyJ6VAwAAAACAktGlsrrOh1ik7Ht4zjN204CC9d4HH4eNt9nHfK11rv/248P8Be8aTAA5uOmOB6whMepPf57jooYs3HzPMyFdW6+oi6fODF0HjjGHqsNLDv+JMagO6dKbZoU33vnE4sc6a2puDruOn2julqQSr2vU5b0qQ6Y8IcWiByv6rLiuje/8tcHAMVVO9gEAABAndo0AclJj5QAAAAAAAAAAAAAAAIDi0fpOkNeiALJn5QAAAAAAoGSUJatf8SEWKbv6brtvaGxsspsGFKx9j/iN+Vrfum3HHhE++/xLAwogS7vse6z1Iyb13nKvsPSrZS5qWIuvljWGydNmhXRtvaLOv+5Bc6g6rV+df5txqA7psptnh7fe/8wiyDpreG1BSAypMXdLUonXMzk63FvRN2TKE1IsGr3pDsZ2PktWX+pkHwAAAHFixwggJzVWDgAAAAAAAAAAAAAAACgere8EeS0KIHtWDgAAAAAASkKiquY/ulRWt/gQi5RdP//1hXbSgIJ10x0PmKvVbu15yK9CU3OzgQWwFk+/0GDdiFFHnHieixqy8PpbH4d0bb3aOufK+8yh6rTGHnS6cagO67KbZ4d3PvjcQsg6m3ztH8zdkqQwaMAu4fFEz5ApT0hF3xW9Ko3rfJasXvjD/sP/1Qk/AAAA4sJuEUBOaqwcAAAAAAAAAAAAAAAAUDxa3wnyWhRA9qwcAAAAAACUhC4DUsN8hEXKvhkz59pJAwrSBx99Gvpuu6+5Wu3aeZdNM7gA1uLIkyZZM2LU/Y884aKGLNQ/9XpI19arrTMuvcscqk6r91b7hIumzjQW1WFNqZsT3v1wocWQddLc3BLGHvAL87ckKaQ23SHMS1SETHlCKurmRSWTI43rPFY2oHp/J/wAAACIC7tFADmpsXIAAAAAAAAAAAAAAABA8Wh9J8hrUQDZs3IAAAAAAFASypLVE32ARcryA7Vb7hW+WrbMThpQkH5yzFnmarV73arGhIdmP2WAAazGx58uDIkhNdaMmLTxNvuEZcuWu7AhCzfd83RI19arrVMvut08qk7t2N/eYCyqQ7vi1kfDh59+aUFknbw6/+1QsbnnKElSdTim75YhU56Qir5fbry5MZ3XUrOd8AMAACAu7BQB5KTGygEAAAAAAAAAAAAAAADFo/WdIK9FAWTPygEAAAAAQEkoq0xN9fEVKbt+etIku2hAQbr9T4+Yp5W3+m23b1jwzgcGGsAqXHDFzdaKOH3I+ZSLXNSQhaXLGsPkafUhXav/v5POqzOPqlMb8aMTjUV1eFfd9lj4dOFiCyPr5NLrbjd/S5JWdEHvqpApT0hF3ZyK3qF7ZcqYzmPdBozu55QfAAAAcWCXCCAnNVYOAAAAAAAAAAAAAAAAKB6t7wR5LQoge1YOAAAAAABKQpdk9cs+viJl1z0PPmoXDSg4n3y2MAzYYT/ztPLaruMnhmXLlhtwAH+nsakpDBoxwToRox6e87QLG7Lw2lsfh3Rtvf6u48+uNY+qU9tos93DpGsfNB7V4V37xyfCwi+XWhzJWXNzSxh7wC/M4ZKkUJ5MhTt69AuZ8oRU1O29yXbGdB4rS1ZPcsoPAACAOLBLBJCTGisHAAAAAAAAAAAAAAAAFI/Wd4K8FgWQPSsHAAAAAACx94O+Nf9vl8pUs4+vSGuvx9A9wpKlX9lFAwrOocf/zjytDunksy834AD+zl0zZlsfYtSmw8aHxsYmFzZkof6p10K6tl5/19FnXGcuVad3+MmXG4/qlG64c25YtGSZBZKcvTr/7VCxeY05XJIU+g8YGWZX9A6Z8oRUtE3ruanxnM+SqY979BjxL077AQAAUOzsEAHkpMbKAQAAAAAAAAAAAAAAAMWj9Z0gr0UBZM/KAQAAAABA7G0wYPSWPrwiZdchx//ODhpQcO558FFztDq0B2bONfAA2ux+0EnWhhh13OmTXdSQpZvueTqka+v1d/30lKvMper0th73c+NRndaNdz0ZFi9dbpEkZ5dd/0dzuCRpRTv1Hx5eKK8ImfKEVLRtMWCE8ZzHyipTezntBwAAQLGzOwSQkxorBwAAAAAAAAAAAAAAABSP1neCvBYFkD0rBwAAAAAAsde1svpIH12RsuuO++rtoAEF5dPPvwjJHfc3R6tDqxy+f/js8y8NQKDkZV5507oQs2Y/8bwLG7KwdFljmDytPqRr9fcdctJl5lJ1et2qxoZzrrjXmFSnddOfng5fResE5KK5uSWMGn+ceVyStKIJ/bYJmfKEVLSd1WewsZzf7nfaDwAAgGJndwggJzVWDgAAAAAAAAAAAAAAACgere8EeS0KIHtWDgAAAAAAYq8smZrigyvS2ksMqQlfLlpiBw0oKD89aZI5Wp3SUSefbwACJe+EMy6xJsSogTsdEJqam13YkIXX3vo4pGvr9Q/tf+yF5lMVRPsfe4ExqU7tthnPheWNTRZMcvLyK2+EDQePM49LklZ0bp9BIVOekIqypxI9Q0VytLGct1LNG1SN6u7EHwAAAMXMzhBATmqsHAAAAAAAAAAAAAAAAFA8Wt8J8loUQPasHAAAAAAAxF6XZKreB1ektfeTY35r9wwoKDNmzjU/q1O7+4E5BiJQshZ+sSj03GJP60GMOv38a1zYkKWHnnglpGvr9Q/tecQ55lMVRFW7HGJMqtP7459fCE1NzRZNcnJ2+gbzuCRpRd0rU+GWnpuGTHlCKsoO7re1sZzHyipTJznxBwAAQDGzKwSQkxorBwAAAAAAAAAAAAAAABSP1neCvBYFkD0rBwAAAAAAsdclWf2RD65Ia++2ux+yewYUjC++XByqdp5gflan1n/78eGjTz43IIGSdPmNd1gLYtbzL7/qwoYsXXfHEyFdW69/aOxBp5lPVTCdetHtxqU6vbsfmReam1ssnGRt2bLlYbtxR5jHJUkr2mTArmF2Re+QKU9IRdf0Hn2N4zxWVln9l/XWW299p/4AAAAoVnaFAHJSY+UAAAAAAAAAAAAAAACA4tH6TpDXogCyZ+UAAAAAACDW/u8mo3/oYyvS2ttos93Cwi8W2T0DCsbPfnWB+VkF0eG/+L0BCZSclpaWsPWYw6wDMWrbsUe4sCFLny5cHNK19VpFI/c72ZyqgqnmsLOMSxVE99S/vOL+GbL16JMvhq4Dx5jLJUkr2nHT4eGF8oqQKU9IRdcO/Ycbx3lsg6oxWzn5BwAAQLGyIwSQkxorBwAAAAAAAAAAAAAAABSP1neCvBYFkD0rBwAAAAAAsdZlQGqYD61Ia2+/o063cwYUjAdmzjU3q6C67+HHDUygpDw46ynzf8w6//KbXdiQpWdefjuka+u1iobtMdGcqoKp33b7hYunzjQ2VRA98GhDaGmxhpK9iaelzeWSpL92aN+tQ6Y8IRVdk3oPMobzWupKJ/8AAAAoVnaDAHJSY+UAAAAAAAAAAAAAAACA4tH6TpDXogCyZ+UAAAAAACDWypLVh/vIirT2pv1xhp0zoCB88eXiMHjET0pyLt5wUMqaVKANHXVw+GrZMgMUKBk/Pup083+M6jpwTHjjrfdc2JClOx58IaRr67WKtqg+0ryqguqk8281NlUwPfLkqxZRsvb5wi9Dcsf9zeWSpL82qfegkClPSEXVs4keoVdytDGcr5LVX/yw//B/dfoPAACAYmQ3CCAnNVYOAAAAAAAAAAAAAAAAKB6t7wR5LQoge1YOAAAAAABirUuyOu1DK9Ka6141Nnz86UI7Z0BBOOaUi0pyLk4O2zV88HifMPnczUPvoT4+V4hdfNUtBihQEha888GKZwRzf3wavd/xLmzI0vLGpnDpzbNDurZeq2jgiIPMqyqodjvkDGNTBdVjz71hMSVr0++fZS6XJP218mQq3NGjX8iUJ6Si6rB+WxnD+W28038AAAAUIztBADmpsXIAAAAAAAAAAAAAAABA8Wh9J8hrUQDZs3IAAAAAABBrZcnqP/vAirTmxk34pV0zoCDMfOzZ0HXgmJKci+surwqhoWJF7z/WO0w8dpvQrSplnSqgegzdI7z93ocGKhB7p0262rwfs66qne7ChizNf/uTkK6t12rqt91+5lUVVBtvOz5cPHWm8amC6ql5b1lQydqEo39rPpck/bXKASPDo4leIVOekIqmP/Xoa/zmsdZzb07/AQAAUIzsAgHkpMbKAQAAAAAAAAAAAAAAAMWj9Z0gr0UBZM/KAQAAAABArJUlq9/zkRVpzV163e12zYBO98WixWGzXQ4syXk4tefw0JKpCKFh5V64t18YvcdO1qoC6siTJhmsQKwt/WpZ6Lfdvub8GNW9amz48ONPXdyQpUfmvhrStfVaTYnN9zC3quA68bw641MF1wuvvGdRJSvvf/hJ6LP13uZzSdJf23XTHcO88kTISEXU9v3tZ+axlu6DxiWcAAQAAKDY2AUCyEmNlQMAAAAAAAAAAAAAAACKR+s7QV6LAsielQMAAAAAgNjq2rfmv3xcRVp7r73xjl0zoNNNPC1dknNwt6pUeObuTUNoqFhlLZmKcOuVVaH/trtaswqgrgPHhMeenmfAArFVe/sM833M2ufwU1zYkIMb7pwb0rX1WkUXT50ZukX3w+ZWFVpjDzrNGFXBNXlaffjLmx9ZWMnKNTffbT6XJK3Uz/tuGTLlCalomtR7kLGbx8qSqVOcAgQAAKDY2AECyEmNlQMAAAAAAAAAAAAAAACKR+s7QV6LAsielQMAAAAAgNjaoGrMVj6uIq257cYdYccM6HSPPPpM6FqiH2c/9uhtQmioWGsfz+0dDjt8O2tXAbTLPseE5uYWAxeIpRF7H2Ouj1m3TH/QhQ1Z+uyLJSFdW6/VdO7V95tXVZD13nrfcPHUmcapCq5LbpoV3nz3Uwssa9X6d6YxB/zCnC5JWqmLeg8MmfKEVBQ9m+gReiVHG7t5KzV/vfVO+ScnAQEAACgmdoAAclJj5QAAAAAAAAAAAAAAAIDi0fpOkNeiALJn5QAAAAAAILa6DEgd5MMq0po784Jr7ZgBnWrxkqVh6KiDS/PD30NHhw8e7xNCQ0XWPTAtGap22NUa1slNv3+WwQvEzhPPvGSOj1kVm9eELxYtdnFDlp5reCeka+u1mn6T/qO5VQXbCefeZJyqILvs5tnh3Q8XWmRZq4ZX3wwbbbabOV2S9NcSydFhes++IVOekIqiQ/tubezmswGpYU4CAgAAUEzs/gDkpMbKAQAAAAAAAAAAAAAAAMWj9Z0gr0UBZM/KAQAAAABAbJUlU+f7sIq05p58LmPHDOhUJ5xxScnOwVMmbRZCQ0XOLXy6Vzh+og/TdWbDdj8yNDe3GMBArBx2wrnm+Jh1xC9/78KGHNz50IshXVuv1XT8OdPMrSrYqif8xjhVwXblbY+GTz5fbKFlrc69ZKo5XZK0UlUDdglPVPQMmfKEVPDd3aOfcZvfrnUSEAAAgGJi5wcgJzVWDgAAAAAAAAAAAAAAACgere8EeS0KIHtWDgAAAAAAYqusMvUnH1WRVt+AHfYLzc0tdsyATjP7iedD14FjSnIO3nbXEaHxpR4hNFSsc/dOTYZNtxllTeuk7rx/lkEMxMYHH30aNhw8zvwesx6c9ZSLG7K0vLEpXHrz7JCurddqOvLUq82tKth6bbVPuGjqTGNVBds1tz8evli01ILLGi1btjxsO/YI87okaaVSm+4Q5iUqQqY8IRV8w/rvZNzmr0X/3Tv1b04DAgAAUCzs/ADkpMbKAQAAAAAAAAAAAAAAAMWj9Z0gr0UBZM/KAQAAAABAbHVJVr/soyrS6pv4m4vtlgGdZvGSpWGL0YeU7Bz84M3JEBoqvnUfPt477PPjHaxrndCw3X4amptbDGYgFs67bJq5PWYld/xxaGxqcnFDll5586OQrq3XGjrguIvMryrojjt7qrGqgu6G6XPD4qXLLbqs0WNPzwtdB44xr0uSVuoXGw8NmfKEVPBN6j3ImM1jZZWpCU4DAgAAUCzs+gDkpMbKAQAAAAAAAAAAAAAAAMWj9Z0gr0UBZM/KAQAAAABAXK3fJVm92EdVpNV338OP2y0DOs2JZ11WsvPvhIO2D6Ghot1qyVSEqy7YLGw4KGV96+D+eO9Mgxkoeo2NTaFq5wnm9Zh1+vnXuLghB/fPzoR0bb3W0F4/Pcf8qoJu1P6/NlZV8E3709Phq2WNFl7W6PjTJ5vXJUkr1TXqyl7JkClPSAXdM+U9Qq/kaOM2XyVTMx0HBAAAoFjY8QHISY2VAwAAAAAAAAAAAAAAAIpH6ztBXosCyJ6VAwAAAACAWPq/m4z+oQ+qSKuvx9A9wpKlX9ktAzrFnLkvhK4Dx5Tk/LvR4FR4/ZGNQ2ioaPeeuXvTsMWIXaxzHdjWYw4LTc3NBjVQ1O64r96cHsNe+st8Fzdkqbm5JVxx66MhXVuvNZSacIr5VQVdry33DhdNnWm8quC7/YHnQ1OTvyWwel98uTgM3OkAc7skaaV6J0eFhyr6hEx5QiroDum7tTGbv1q6Vo7u4VQgAAAAxcCOD0BOaqwcAAAAAAAAAAAAAAAAUDxa3wnyWhRA9qwcAAAAAADEUpeq1BAfU5FW34Sjf2unDOgUi5csDVuMPqRk59+zfrNlCA0VeWvh073C/gdub63rwP5470wDGyhqYw74hfk8Zu2899EubMjBm+9+GtK19VpLO+x1nDlWBd/x50wzXlUU3f3IvNDc0mIRZrXufmCOeV2S9I226b9TeC7RI2TKE1LBdkePfsZrfjvVqUAAAACKgd0egJzUWDkAsr7P/PsfHV8U9ek/9GHUa1F/iXoyalbUjKjbo+qipkRNjjojamLUgVG7R+0YVRWViPqvqH/yfxsAoOTuNev8iQIAgDxbvoq/abY2v+3vms9EPdH2N8272u5Rr2n7u+Y5Ub+MOixq76gRUZtH9Yn6n6jvuasHAACgSPdovtf2bNun7Vl3l7Zn38PanoXPaXs2vqbtWfnutmfnJ9qepV9re7Ze1TP3cn+OAFgnzrcDZH8/W2PZAACgA3y2ir9/vtP299EXw9fvUj4UdX/b31FvbPu76vlRp0T9LGq/qFTUNlH9o7pF/Zu7egAAAIB2UFZZvacPqUirb9ofZ/gzL9ApTj7n8pKde6t22DUseq5nCA0Vea0lUxHOO3No6DrQetcR7bLPMQY2ULRezLxuLo9hl994h4sbcvDwE6+EdG291tLmo48wx6rgqz7wNONVRdOMOQ0WYdboJ8ecZW6XJH2j/fttEzLlCamg26b/TsZrnipLpl5db7311ncyEAAAgEJnpwcgJ350HCD7+8yO+tHx5qj3o54PX3+E54aoSVHHR/04fP3xnn5R/+5fBQAgNveadf5EAQBAkVsYlYmqj7o1Kh3166hDoqqjNovaIMp5dAAAAPK977J+2zPokLZn0kPbnlFbn1Vva3t2zbQ9ywJQeJxvB8j+3rfGsgEAQJFbGrUg6vGo6VFXR50RdVTU3lHbRCWi/tkTAAAAAMBqdKmsPsHHVKRV161qTPjw40/9KRbocHOffXnFHFSq8+8frqoKoaGiw7rzuoGhx+ajrX0d0DMv/MUAB4rSxN9cbB6PWRsOGud5D3LQ0hLC1bc/HtK19VpL/XeYYJ5Vwdd32/Hh4qkzjVkVTTOffM1izGp98NGnYeNt9jG/S5K+0aTeg0KmPCEVbGduvJmxmsfKKscMdTIQAACAQmenByAnfnQcIPv7zEL80fHWj/u8GHV31JSok6P2C1//WOQG/tUAAIrmXrPOnygAACgRy6JaX259OOr6qDPD1x833yWqZ9R3PSEAAACwln2V70b1ihoZdVjbs2XrM+Yjbc+cyzx+AxQ159sBsr83rrFsAABQIlqi3o16POrWqAuijo7aPaoy6t88IQAAAAAlq0tlarIPqUirrnr/E/x5FehwS5Z+FbaqPqxk597UnsNDS6YihIaO7cX7+oUhw3ex/uW5I0+aZJADReezz78MPYbuYR6PWfsddbqLG3Lw3kdfhHRtvbKoYuie5lkVRSedf6sxq6Lq6ZfesiCzWtfe/CdzuyTpG5UnU+HOHv1CpjwhFWRPVPQMG1WmjNe8lbrEyUAAAAAKnV0egJz40XGA7O8zi/FHxxdFPRu+/qHIs6MOihoW1cW/KABAQd1r1vkTBQAArNAY9WrUvVGTw9cfvxkd1Tvqu54eAAAASmbv5LtRfaJSUce0PSPeF/Va27MjAPHlfDtA9vfNNZYNAAD4qw+iZkddG3Vy1F5Rg6P+3dMDAAAAEGtllam7fURFWnWTr/2DP50CHe6Uc68s2Xm3W1UqPPunTUJoqOiUPnmyV9ht3x2tgXlso812Cx9+/KmBDhSVS6LnAnN4/Jp+/ywXN+Rg9jPzQ7q2Xmvp/OseNMeqaNrj8LONWxVd8159z6LMKjU3t4Rdx080v0uSvtHAAbuEJyp6hkx5QirI9tlkO2M1T5VVpj7p0WPEvzgdCAAAQCGzywOQEz86DpD9fWbcfnT886gno66POiF8/WHaRNT6/rUBADr8XrPOnygAAGCtloevP54+PersqP2iqqK+56kCAACgaPdIvtN2XmV02/mV69vOsyzxGAxQspxvB8j+frrGsgEAAFl5N2pG1IVRB0dtFfXvnioAAACAWOhSWT3Ph1SkVffq/Lf9eRToUE8+lwndq8aW7Lx73MRtQmio6NSWvdgjHHHkttbBPHbeZdMMdqBotH6Yfeiog83fMavP1nuHpV8tc4FDDm6c/mRI19ZrLf0mfYd5VkXTgB0nGLcquiZPmxVeXfCRhZlVem7eK6Fb1RhzvCTpG+226fbhpfKKkClPSAXXDb36G6d5bIPk6GqnAwEAAChkdngAcuJHxwGyv88slR8d/yxqVtTFUROiKqO+6woAAMjrvWadP1EAAMA6a/2hk+ejbow6JmpY1H960gAAACi4/ZD/HbV91LFRU6NejFrusRaAf+B8O0D299g1lg0AAPhW3oi6K+r0qHFRG3nSAAAAAIpOl8rqRT6iIn2zLVOH+hMo0KGWLVsehu3205Kdd/tsMTp8+ETvEBoqOr2WTEU489dbWA/zVOXw/cPy5Y0GPVAU7n/kCXN3DDvhjEtc3JCDTz5fHNK19cqiiWdNNc+qqPpN+g5jV0XXpTfNCgve+8wCzSodf/pk87skaZX9auPNQ6Y8IRVcL5VXhMoBI43T/FXndCAAVlwOfQAAIABJREFUAACFzO4OQE786DhA9veZpfyj460fpX0q6oqow6M2j/qeqwIAoN3uNev8iQIAANrda1G3Rp0YtUvUDzx9AAAAdNjexw+iRkad1PZs9rrHVACy5Hw7QPb33TWWDQAAaHefRj0QdW7UPlG9o9b3BAIAAAAUpP9J1vzAx1OkVXfGBdf6cyfQoU4//5qSnnevvGCzEBoqCqqrov+mblUp62IeuuO+eoMeKAr7HH6qeTuGzX32ZRc35GDuiwtCurZeWXTIiZeaZ1VU7fuz3xu7Ksouv2VO+OizRRZpvuGzz78M/bcfb46XJH2jbpWpcGOvASFTnpAKrhM23sI4zVNlyeqlGw6o/k+nBAEAAChUdncAcuJHxwGyv8/0o+Mra4yaFzUlar+ofsGPQwIArOu9Zp3bSwAA6BDvtt1//yxqq6h/8UQCAADwrfc5vtN2buTgqOvbzpO0eAQFYB053w6Q/b248+0AANAxFkbNijo7anTU//FEAgAAABSErslRg31ARVp1c+a+4E+bQId5+oWG0L1qbMnOucNGjwiNL/UIoaGi4Jo2ZVD0b5OyNrZzPz7qdAMfKHjzF7wbulWNMW/HrC1Th4aWFu8uQi5uvueZkK6tVxbtc9S55loVVYNGHmLsqmi75vbHwxeLvrJQ8w21t88wx0uSVlmf5K7h4Yo+IVOekAqqh6Lrslul/ch81TVZfaBTggAAABQqOzsAOfGj4wDZ32f60fG1+yDqjqhfhq8/SPvPrhwAgKzuNevcSgIAQKdYEr7+4M3vo8YGH7wBAADIZl/jB1HjoiZFzY5a6vESgHbkfDtA9vfmzrcDAEDnaP0400tR10QdFNXHEwoAAADQKbpUjh7n4ynSN+u15Z5h+fJGf8oEOsSyZcvDsN2PLOl59+FbBoTQUFGw3XHtwLBhlfWxPdtw0Ljw4cefmQCAgnbKuVeas2PYpCk3ubghB58uXBLStfXKstSEU8y1Kq4Piw8cE86aco/xq6Lthulzw5KvlluwWfmUdktLqN7/BPO8JGmV7dB/eHihvCJkyhNSQbXrpjsao3mqrDL1sFOCAAAAFCo7OwA58aPjANnfZ/rR8dy1HkR7MursqB2jvu9KAgBY5b1mnVtHAAAoGK9FTYnaL6qbJxYAAMA+Rvhh1Oi28x+t50CaPToCkEfOtwNkf6/ufDsAABSOD6KmR50QVRX1T55aAAAAgLwrq0wd6uMp0jf78VGn+5Ml0GHOvPC6kp5zf3LwsBAaKgq++2uToXyzlHWyHbv6prtMAEDBWrL0q9B3233N1zGr68Ax4c2333eBQw4ee/6NkK6tV5Ztt/sx5lsVXfsfd6Hxq6LulvueDcsbmyzarOTlV94IGw4aZ56XJK2yI/puFTLlCamgmtxroPGZv1p+OKB6IycFAQAAKER2dQBy4kfHAbK/z/Sj49/eV1Ezo1pfON8u6p9dWQAAK+4169wqAgBAwXo56rKoPaP+2xMMAABQAvsWP4jaK+ryqIzHQgA6mPPtANnfuzvfDgAAheujqD9EHRnVxxMMAAAAkBdllamTfThF+mZXT7vLnyiBDvH8y6+GDQeX7sddE5ulwpv1G4fQUFEU3XV9ZehelbJWtlOj9zveJAAUrOvq7jFXx7DdDjzRxQ05unH6kyFdW68sGzjiIPOtiq4tqo80flX03fXIvNDc0mLhZiUnn3O5eV6StNrSvQeGTHlCKpieT1SE3slRxme+So7+pZOCAAAAFCI7OgA58aPjANnfZ/rR8fa3OGpG1AlRVVHru9IAgBK916xzawgAAEWhOerJqLOjdoz6F080AABADPYpvtN2bqP1/MastmcfAOgszrcDZH8v73w7AAAUj/fD1+8NHBxV5okGAAAAaBdlydT5PpwifbNX57/tT5JA3i1btjxsX3NkSc+3554+NISGiqLq1iurQreqlPWynXrtjXdMBkBBKvU1Oq7V3j7DxQ05+ODjL0O6tl451Gurfcy3Krq6VY0Nv796hjGsou+hJ16xeLOSL75cHJI77m+ulyStsh6Vo8N9PfqGTHlCKpgO67eV8Zm/5jkpCAAAQCGyowOQEz86DpD9faYfHc+/t6Kujtor6n+76gCAErrXrHMrCAAARWlR1N1RP4/q5ekGAAAoor2JPlFHR/0parHHOwAKiPPtANnf1zvfDgAAxak56smos6K2i/qOJxwAAABgnZQlUzf4aIq0cpvvepA/QQId4uz0DSU93w7acWRY/HyPEBoqiq5pUwaFrgOtme3ReZdNMxkABWfO3BfM0TGsYvOa8MUi70FCLuqfej2ka+uVZRde/3D0nDDGnKui7LBfXWEcKxbNfXGBBZyV/OHuh83zkqTVtnX/ncNziR4hU56QCqI7e/QzNvPYBlWjBjotCAAAQKGxmwOQEz86DpD9faYfHe9YTeHrH4Y8NarKFQgAxPxes87tHwAAxMJrUVOiRkf9s6cdAACggPYi/p+oraLOjnrJ4xsABcz5doDs7/OdbwcAgHhYFDU96uCoH3raAQAAALJWlkzd66Mp0sodf/pkf3IE8u65l14NGw4aV9Lz7e1XV4XQUFG0XXj25tbNdmibsYebEICCc9DEs83RMeyIE89zcUMOWlpCuOb2x0O6tl5Zdlr6TvOtirad9v2lcazY9NJr71vIWckeB//KXC9JWm0H9ds6ZMoTUsG0df+djc18law+z2lBAAAACo2dHICc+NFxgOzvM/3oeOfyMVoAIM73mnVu9wAAIHZ87AYAAOjs/Yf/ajvvcn3UZx7TACgSzrcDZH/P73w7AADET1PUk1GnRlV58gEAAADWqEsy9aSPpkgrd/cDc/yZEcir5csbww41R5X0XDtmr+GhJVMRQkNxd+IJW1s726HX33zHxAAUjPc//CRsOHic+TmGPTT7KRc45ODt9z8P6dp65dAxZ15vvlXRVrHFnuGiGx8xlhWLLrlpVnjz3U8t5vxVw2sLPOdJktbYRb0Hhkx5QiqITuszxLjMX++vt+2233FiEAAAgEJiJwcgJ350HCD7+0w/Ol44Wg+zXRs1Oup7rk4AIAb3mnVu8QAAINYao2ZEHRr1P56CAACAPO45bBB1eNSfw9cf3gSAYuN8O0D29//OtwMAQPy9HHVm1EBPQQAAAMA3dKlMzffBFOlvda8aGxZ+scifFYG8OveSqSU913arSoXn7tkkhIaKoq/p5R7hgAO3t4Z+y66YeqeJASgYv5s81dwcwyqH7x+amptd4JCDBx9/JaRr65VDE45Pm3NV1J3wu2nGsmLTZTfPDu999IUFnb8684JrzfWSpNWWSI4Od/foFzLlCanTezTRK3Q3LvNW14HVOzsxCAAAQCGxiwOQEz86DpD9faYfHS9Mi6OmR+0X9W+uVACgSO8169zWAQBAyWj9oZZZUSdEVXgiAgAA2mGfoVvUz6JmRDV67AKgyDnfDpD9s4Dz7QAAUFreiLowaquo9T0VAQAAAOt1SVYv9sEU6W+N2PsYf0YE8mpew/yw4eBxpf2R7uO2DqGhIjZ9+WzPMHzMTtbRb9Heh51icgAKwvLljSG544/NzTHsjAuudYFDDpqbW8KVtz0a0rX1yqFxh5xhzlVRt9shZxrLilVX3vZY+OyLJRZ2Vliy9KswZOSB5ntJ0mobMmBEeLq8R8iUJ6ROb+wm2xuXeaosmbrBiUEAAAAKiV0cgJz40XGA7O8z/eh44VscdWvUnlHfd9UCAEV0r1nnVg4AAEpSS9SjUROjuno6AgAActhb6B51XNTjbc8WABAXzrcDZP9c4Hw7AACUrgVRF0QNjVrfExIAAACUoK6b13zfx1KklfvV767wp0MgbxqbmsIu+xxT0vNs361GhU+e7BVCQ0Wsemv2xmHTbUZZS9exjTbbLXy5yEeugc53290PmZdj2suvvOEChxzMf/uTkK6tV45tv+dEc66KugHDf2IsK3bdcOfcsHjpcos7K9z9wBzzvSRpjY3vt13IlCekTu/S3pXGZN5KfblB1aj/5eQgAAAAhcIODkBO/Og4QPb3mX50vLi0vlhXFzU66ruuYACgwO8169y+AQBAyWuOmhX1s6gfeFICAABWsZ/wn1H7Rc1oe4YAgDhyvh0g+2cE59sBAIBWb0ZdGJX0pAQAAAAlZIOqUd19KEVaubtmzPbnQiBvzrtsWsnPs1dfNDiEhopYNvPWAaF7Vcp6uo7d+9BjJgmg040af5w5OYbtvPfRLm7I0X2zMyFdW68cGzjiIPOuir4zLpluPCt21d37TFje2GSBZ4XxR55mvpckrbHzeg8KmfKE1Kk9n6gIvZOjjMk8VVZZvaeTgwAAABQKuzcAOfGj4wDZ32f60fHi9UnUlKitotZ3NQMABXivWeeWDQAA+DtfRU2P2i/qXz01AQBASe8hfC9qdNtewjKPSwCUAOfbAbJ/XnC+HQAA+Efzok6NKvfUBAAAADG3QdWogT6UIq3cBx996k+EQF689Jf5YaPNdivpOXbY6BGh8eWKEBri28XnDLGermPHnz7ZRAF0qudfftV8HNOumHqnCxxysHx5U5hSNyeka+uVY4nN9zDvqug7YOJFxrNi2fSH54XmlhYLPWH+gndDYkiNOV+StNrKk6kwvWffkClPSJ3aIX23NibzVFmy+g9ODgIAAFAo7N4A5MSPjgNkf5/pR8fj4ZWoX0d1d1UDAAV0r1nnNg0AAFiNhVFXR23l6QkAAEpm32D9qK2jrml7JgCAUuJ8O0D2zw7OtwMAAKvTHPXnqPFR/8sTFAAAAMRQWTK1ow+lSH9ry9Sh/iwI5EVjU1MYsfcxJT/PzvpD/xAaKmJdS6YijJ+wvXV1HRo0YoLJAuhUR59yofk4hm04eFz48OPPXOCQg3mvvhfStfXKsd9fNcO8q1i09bifGdOKbTPmNFjoWeHcS6aa8yVJa2zwgF3CU4meIVOekDqtP/TcxHjMU2XJ6qWJqpr/cHoQAACAQmDnBiAnfnQcIPv7TD86Hi+tPwo5K+rg4EchAYDOv9esc3sGAABkofWl3lOjNvQkBQAAsdwvKIs6IeovHn8AKGHOtwNk/wzhfDsAAJCNhVHXR+0Ytb6nKQAAAIiJDQZUj/GhFOlvHXPKRf4UCOTFhVfWlfwce/Chw0JoqCiJPp7bOyS329Xaug69+fb7JgygU3zy2cKQGFJjLo5hPznmty5wyNGt9z8X0rX1yrGTJ91i3lUs6j54XDjv2j8b14ptjz//psWesPSrZWHoqIPN+5KkNbbPJtuFTHlC6tSG9h9hPOapsuToHzs9CAAAQCGwcwOQEz86DpD9faYfHY+vz6OmRG3lSgcAOules84tGQAAkIPmqBlR+0V931MVAAAU9R7BP0eNbtsraPS4AwDOtwPk8DzhfDsAAJCrl6NOiPqhpyoAAAAocl0HpPb1kRTpb0374wx//gPaXcNrC0JiSE1Jz68VQ0aHBbM2jv5nVJRMD9UNCF0HWltz7ba7HzJpAJ3i4qtuMQ/HtPsfecIFDjn4bOGSkK6t1zp0xClXmncVm476zdXGtWLdvFffs+gTHpr9lDlfkrTWzu4zOGTKE1Kn9auNNzcW81RZsvoepwcBAAAoBHZtAHLiR8cBsr/P9KPjpeGZqEOj/s1VDwB04L1mndswAABgHX0YdW5UhacrAAAoqr2BnlG/j/rYYw0ArMT5doDsnyucbwcAANbV8qg/RA2PWt8TFgAAABShLgNSB/lIivS3XnvjHX/2A9pVY1NT2GXfY0t+fv39GUNDaKgouU48YWvra4798reXmjiADtfU3ByGjDzQPBzDKofvv+J+DMjenGfnh3RtvdahfY8619yr2DRyv5ONa8W6S26aFRa895mFn3DAz88070uS1thGlalwZ49+IVOekDqlmRW9Q7foOjQe81CyunGDqlH/xwlCAAAAOpsdG4Cc+NFxgOzvM/3oeGn5ImpK1ABXPwDQAfeadW6/AACAb6klakbb37K/40kLAAAKcj/gn6J2jJredg8PAHyT8+0A2T9jON8OAAC0h1eiTojyW6IAAABQTLokUz/zkRTp6/pvP96f+YB2N2nKTSU/vw7ecWRY/HyPEBoqSq4lz/cMQ3ceaZ3NoeF7/szEAXS4ex58zBwc08688DoXOOSguaUlXHP74yFdW691aMT4k8y9ik29ttonXDx1prGtWDflljnh488WuQEocW++/X4oH7K7uV+StOa9rgG7hKcSPUOmPCF1SqM33cFYzFNllalDnSAEAACgs9mxAciJHx0HyP4+04+Ol64now6O+r6RAADk6V6zzi0XAADQjt6NOjuqmycuAAAoiH2A/wlff4zyDY8rALBWzrcDZP+s4Xw7AP8fe/fhJ1V5L/A/avLz5ndLbnvdGxcQd2elCsxSVETFggIqs4u9G2s0tthCbFETC8ZgiWshlmjURTcxFqIYuy4iGhVRgdmosRcMIdLr7vM7RG5+Bilndmdmd8+836/X5x/Qc77zPGcfzgGAfFoavvi3DcPsuAAAAKADKKvKnOsDKdIXHXrSRR7vAXk184/vhC223qfk5+vE26tCaEyVbE/ek/Y7m0NdBtSE+QsWGSBAUR3w3fPN4IT25jsfuMAhB+98+JdQW9egFjZoj+PNXiWqH139W/e2Et8v73shLFi01CKgxF3681+Z+5KkDXbwVjuFbHmF1CZd232A+7BAlVVlnnaCEAAAgLbmrzUAOfHScYD460wvHWd21CVRZe4IACDPa816Sy0AAKAAlkfdEzXYzgsAANrk+f+Q1X8DWG57AgCxOd8OEH/P4Xw7AABQKC9HHRG1qd0XAAAAtFOd0tU/8YEU6Ysur73TIz0gb1asXBlGHnx6yc/W0QcOC83ZVAiNpd1xx+/stzaHnp4yzRABiuaPf/ogdO5fY/4msL2POtsFDjl6uGFmqK1rUAur2HZ/81eJ6tDvX+neVkl0zyPTwvIVKy0EStiChYtD1W7fMfslSRtsXPeBIVteIRW9Vysqw5bpUe7DgpRp6txvz05OEQIAANCW/LUGICdeOg4Qf53ppeP8n1Ufu1r10SsfogUA8rXWrLfEAgAACmzVh24Oj/qGXRgAABT0mf83Vp8xec42BABaxPl2gPj7D+fbAQCAQpsdNTbKO0YBAACgvSmrqr7Mx1GkL5r05FSP8oC8GXfjhJKfq5sPyISZj/UOoTFV8s1+oUfoMWQvv7dxP0oZ3T8AxXLuZePN3oRW/+ATLnDIwZKlK8INdz8Xausa1ILG3vSI2avENaTmZPe3SqaJT78RmpubLQhK2D0PPGH2S5I2WHk6Ex6q7B2y5RVS0Tuy91D3YcHKnOYUIQAAAG3JX2oAcuKl4wDx15leOs7avBS++BDt190lAEAr1pr1llUAAECRfBJ1YdR/2Y0BAEBen/V/K+rUqPdtOwCgVZxvB4i/D3G+HQAAKJZlUb+K6ms3BgAAAO1Ep6rqn/owivRFH386xyM8IC9mNL4Ttth6n5Kfq+eO2SGExpRWd+3l2/i9jdlRp11qkABFsWDh4tBj+4PM3gTWbcgBYeGiJS5yyMG0WR+G2roGtbCzxt5l/ipxdRm4d7jytifd4yqZGl5+24KghDU1NYc9DzvT/JckbbDt+o0I0ysqQ7a8Qipqd27Zzz1YoMqqMi84RQgAAEBb8pcagJx46ThA/HWml46zPn+KOi3qX9wtAEAL1pr1llMAAECRLYq6IarSrgwAAFr1jL9b1PjVa2wAoPWcbweIvx9xvh0AAGgLj0ftEbWRnRkAAAC0obJ09ZU+jiJVh767HOaRHZAXK1auDCMPPr3k52rvHfYMf3mpWwiNKa1uyetbhkHD9vC7G6MhmeMNE6Aobp3wO3M3oZ31k+tc4JCjCQ+/EmrrGtTCjvpBrfmrRHbaxbe7x1VSTW/8yKKghL00PRs6968x/yVJG+zY3juEbHmFVNRmlqdCv357ugcLVOeqUV6sDQAAQJvxVxqAnHjpOED8daaXjhPHvKhrojZz1wAAOaw16y2jAACANtIUNTFqa7szAADI6dl+OupXUSttKwAgr5xvB4i/L3G+HQAAaEuvRR0e9XU7NAAAAGgDZVXV1/gwilQdDj3pIo/qgLy44vq7zNWo22u3DqExpTWqu3Gg6yNGXQbUhCVLlxkoQEE1NzeHoaNPNHcT2iuvN7rIIQez5ywItXUNakXVx/zY/FUiW3Vtu8dVSl03YXJ458O/WByUsBPP/pn5L0mKVW33/iFbXiEVtVN7DXH/Fap09TlOEgIAANBW/IUGICdeOg4Qf53ppePkYmn44uNZle4eACDGWrPe8gkAAGgHJkeNsksDAID1PtPfPmpiVLMtBAAUhPPtAPH3J863AwAA7cE7UadG/b92agAAAFBEndLVtT6MIlWHy2vv9IgOaLU3sn8KXQftXfIzdVj18LByVmUIjSmt0ar/LjuPGuG3N0ar7ieAQnp26qvmbULbed+TXeCQoyem/jHU1jWoFW0/+lQzWIms765HucdVct14z3Ph0znzLRBK1Eef/jlUDt7fb4AkaYNVVo0Kj6V6hmx5hVS0Hqzs7f4rUGXpzGtOEgIAANBW/IUGICdeOg4Qf53ppeO0xPKoX0X1dhcBAOtZa9ZbNgEAAO3IK1GHR21ixwYAAH97jr9x1Kio520XAKDgnG8HiL9Xcb4dAABoTz6LujDqP+3YAAAAoAg6patrfRhFqg6Tnpzq0RzQKsuXrwi77neKmRo15b6+ITSmtI7uu2WA6yRG9z38jMECFNRRp11q3ia08Xfc7wKHHCxdtiLceM9zobauQa2o19DDzGAltktvfMh9rpLr1vteCPMXLbVQKFHjbpxg/kuSYrVD3+HhtYpUyJZXSEVru34j3H8Fqku/UT4MCAAAQJvw1xmAnHjpOED8daaXjtMazVETowa4mwCAtaw16y2XAACAdmhG1OFRm9i5AQBQos/vN44aFTXN9gAAisb5doD4exbn2wEAgPZoQdTYqP+0cwMAAIACKquqvtpHUaTq8O4Hn3gkB7TK5bV3mqdRJ3xvpxAaU1pPK2alwja7jXS9bKBV9xRAoXzw8Wdh8wGjzdsEtsXW+4Q5c+e5yCEH02Z9GGrrGtSKrrr9ydC5f405rMR2zJjr3OsqyeoeejksXbbCYqEELV6yNAwacbTfAElSrE7utX3IlldIRev8ntu69wpVuvonThMCAADQFvx1BiAnXjoOEH+d6aXj5ENz1MSoAe4qAOBLa816yyQAAKAdmxF1eNQmdnAAAJTIc/uNV58TmWk7AABF53w7QPy9i/PtAABAe7YgamzUf9rBAQAAQAF0SleP81EUlXqVg/cPTU3NHsUBLfb6rLdD10F7l/w8TW0zKnzwXM8QGlPaQDddvY3f4A109OmXGi5AwVxyze1mbUI79syxLnDI0Z0TXwq1dQ1qReeOqzeDleh2PfAH7nWVbPc98VpY6e8HJem+Sc/6DZAkxapz1M3d0iFbXiEVpWdSPf523bn/8l9ZOvPW1772tY2cKAQAAKDY/GUGICdeOg4Qf53ppePk06qDdBOjBri7AIBoTVBveQQAAHQAM6MOj9rETg4AgIQ+r9949fmQWZb/ANBmnG8HiL+Hcb4dAADoCBZErfr41X/ayQEAAEAedUpnLvdRFJV6ww86zeM3oMWWLVsedtnvZPM06qrLBofQmFKMFr1WGbbaYS/XzXraeZ+TDBigIJYuWxb67HyYWZvQnmh4yUUOOXj347mhtq5BrezYs683g5XoUoMPCD+/61n3u0q2J1/4o0VDCWpubg41R/7Q74AkKVbd03uFp1M9Qra8QipKI/oMc+8VqM361/gIIAAAAEXnLzMAOfHScYD460wvHacgR6uifhvVx10GACW91qy3LAIAADqQmVEHRm1sRwcAQEKe028cdUhU1nIfANqc8+0A8fcyzrcDAAAdybyon0T9ux0dAAAA5EFZVfWlPoiiUu/kc6/02A1oscuuvcMsjdp295FhyetbhtCYUswuPHd71876PkA55EADBiiIux943JxNaAOGHxVWNjW5yCEHE5+eEWrrGtTKqo/5sTmsxHf2uHvc7yrpXp75gYVDCXp91tuhy4AavwOSpFgN77tbmFFeEbJSEbqix0D3XYEqq6q+zIlCAAAAis1fZQBy4qXjAPHXmV46TiGt+scb9VGV7jYAKMm1Zr3lEAAA0AG94e+NAAAk4Bn9sKhXLO8BoN3wvAkg/n7G+XYAAKAjmht1YdS/2tkBAABAK3Sqqr7IB1FU6l1zs3d1AC3z2qy3QtdBe5ulUQ/fURVCY0o5lH28t2tnAy1YuNigAfJu5CFnmLEJbWztHS5wyMH8hUvDdRMmh9q6BrWy7apPNoeV+A448XL3u0q+xnc/s4AoQaddcI3fAUlS7H7Yc3DIlldIBe8PFd3CFlUZ910BKktXv+lEIQAAAMXmLzIAOfHScYD460wvHacYlkeNjypz1wFASa01vagHAADoyKZEDbW7AwCggz2bHxz1tOU8ALQ7zrcDxN/XON8OAAB0ZKs+UjAmalM7PAAAAGiBzaqqf+CDKCr1Jj35vMdsQM6WLVsedtnPh9NXtf+hw0JoTKkF7Vazu2toPb35zgeGDZBXL7+WNV8TWuf+NeHdDz5xkUMOnpv2Tqita1Ae2nK7A81iJb5t9/qe+10l3w33PBc++fM8i4gSM/vPc0P3IX7rJUnx6lKVCRO27BOy5RVSwdt/q13cdwWqrF912qlCAAAAislfZABy4qXjAPHXmV46TjEtihob9R/uPgAoibVmveUPAACQAI9FVdnlAQDQzp/J9/ZcHgDaNefbAeLvb5xvBwAAkuDdqOOiNrHTAwAAgBxsVjXqJB9DUan31jsferwG5OySa243Q6M2H5AJsx7vHUJjSi3oF1dt7TpaTw0vTDdsgLw66dwrzdeEtu+x57rAIQfreUjzAAAgAElEQVQrVzaFm++dGmrrGtTKLhv/sDmskqjLwL3DVbc/6b5XyXdL9Ps5f+ESi4kSU3vrb/wWSJJil07vEV5MbRmy5RVSQRvfrco9V6jS1Rc7VQgAAEAx+WsMQE68dBwg/jrTS8dpC3Ojzoza1F0IAIlea/p4JwAAkBRNUXdEbW63BwBAO3sW3zXqrtVrVgCg/XK+HSD+Psf5dgAAIEmmRe1mtwcAAAAxlfWr/o6PoaiU22LrfcKKlSs9VgNy8srrjWHzAaPN0ajzzt4+hMaUWthnL3SPrqWMa2kd1T/4hIED5M2cufNC+Tb7mq8J7d6HnnKRQw5mvf1pqK1rUB467eLbzWGVTKdfcof7Xoqqe+jlsGz5CguKErI8+v+9ffUJfgskSbE7oPfOIVteIRW01ypSoXt6L/dcQco0OlUIAABAMflrDEBOvHQcIP4600vHaUvvRx0etZG7EQASudast9wBAAASZlnUNVHfsusDAKCNn8H/S9SFUUss0wGgQ3C+HSD+fsf5dgAAIIkei+pr1wcAAAAb0Cmd2deHUFTK7bLfyR6lATlZtmx52Hnfk83QqN477BnmvtwthMaUWlHmgN1cT+vo5zf/2tAB8ubqm+4xWxNajx0OCouXLHWRQw7qH5kWausalIcO/f6VZrFKpn2+e4n7Xlrd756ZEZqbrSlKycNPTPFbIEnKqXE9BoZseYVU0I7uvaP7rUB1HlDdx8lCAAAAisVfYgBy4qXjAPHXmV46TnvwQtT27kgASNxas94yBwAASKg5UadGfd3uDwCAIj973zjq8KhPLcsBoENxvh0g/r7H+XYAACCpmqJ+FfW/dn8AAACwDp2rRo3wIRSVckd+/xKP0YCcXHz1bebn6u68flAIjSm1snGXDHY9raNzLxtv6AB5sWLlyjBwxFFma0L74SU3uMghB5/8eX6orWtQntr9kLPNYpVMA/f4rvte+lLPTXvHwqLE7HfceX4PJEmxK09nwqTKXiFbXiEVrDu79XO/Fa6LnCwEAACgWPwVBiC3P9365QCIvc700nHak4lRFe5MAEjMWrPe8gYAAEi4Wf42CQBAEZ+7D4t6zTIcADokz5AA4u99nG8HAACSbmHUhVHftAsEAACANXQakNnGR1BUyl1wxc0enwGxvfxaNmw+YLT5GTV87+Fh5azKEBpTamWvPLSVa2odnXLeVQYPkBcTH51sria46TPedJFDDiY1zAq1dQ3KU+ndjzaLVTJ16V8Txv3ycfe+9KVmvPWJxUUJaXzrvdB14N5+EyRJsRvSb3iYXlEZsuUVUkGaEbVVek/3WwEqq6p+w8lCAAAAisVfYQBy4qXjAPHXmV46TnuzJOrSqH92hwJAh19r1lvaAAAAJWJSVHc7QQAACvS8vWfUY5bdANChOd8OEH8P5Hw7AABQKt6N2tdOEAAAAL6kc9WoSh9CUSl3S91Ej82AWJYtWx523ucks3N1U+/vE0JjSnmoaVZl6DvUx+7W1tGnX2b4AHmx77HnmqsJbdj+p7rAIQfzFiwJ102YHGrrGpSHrvnV06HLgNHmsUqqU39ym/tf+lLX3z05fDT7c4uMEjLm4uv9HkiScurkXtuHbHmFVLBO6L29e61AfbuqpqfThQAAABSDv8AA5MRLxwHirzO9dJz26qOow6M2cqcCQIdda9Zb0gAAACVkedQ1Uf9mRwgAQJ6es/9z1IVRSy23AaDDc74dIP5eyPl2AACg1DwVtZUdIQAAAES69qv+dx9BUSn36DMvelwGxHLRuFvNzdWdeNLQEBpTymPHHb+za2stHfy9CwwfoNWyb75npia4m+960EUOOXjmpbdCbV2D8tS54+rNYpVco4/9sftfWqOb730+fL5giYVGiZgzd17ouePBfhMkSbHrHPXLbumQLa+QClL9ln3cawWqLF19vtOFAAAAFIO/wADkxEvHAeKvM710nPbu6ag+7lYA6JBrzXpLGQAAoAR9HHV41EZ2hgAAtOIZ+6io9y2vASAxnG8HiL8fcr4dAAAoRSuiron6NztDAAAASt1GZenMch9CUanW+NZ7HpUBG/TS9GzYfMBoczOqcttR4cPneoTQmFIeu/bybVxfa6n6O2MMIKDVxlx8vZma0LbYep+/fdAeiGfJshVhfP2UUFvXoDx15Fk/N49VcvUffqz7X1pLdQ+9HJYtX2HBUSKu++W9fhMkSTnVO71nmJLqHrLlFVLem1meCun0Hu61AlSWrp7uaCEAAADF4K8vADnx0nGA+OtMLx2nI/i/F0J+y10LAB1qrVlvGQMAAJSwZ6L62h0CAJDjs/V+UQ2W0wCQOM63A8TfFznfDgAAlLJPoo6L2tgOEQAAgJLVqar6Ux9CUSnWuX9NWLR4iUdkwHotXrI07FBzgrm5umvGbhtCY0p57qn6fq6vtbTbAacaQkCrzJu/MGy53QFmakI7YcwVLnLIwR/eeD/U1jUoj4087FzzWCX5TPWKWx81A6S1NPGpN0Jzc7NFRwlYsnRZGDTiaL8LkqScyvTZNcwsT4VseYWU977fa4j7rECV9a3p5nQhAAAAheavLwA58dJxgPjrTC8dpyP5NOowdy4AdJi1Zr3lCwAAUOJWRF0T9W92iQAAbOCZ+reiro1aaRkNAInkfDtA/P2R8+0AAAAhTI7qY5cIAABASSpLV0/3ERSVYulhR3gsBmzQBVfcbGaubvDwkWHpG5UhNKaU5/78YnfX2FrabtR3DSGgVX5x5wPmaYKb8ofXXeQQ08qmpnDrfS+E2roG5bF+ux1tHqskO/miW8wAaR1NefUdC48SUf/gE34TJEk595Me24RseYWU9+6v3Mo9VqjS1ec4XQgAAECh+csLQE68dBwg/jrTS8fpiJ6J6uEOBoB2v9ast2wBAAD4m4+jDrdTBABgHc/TR0W9b9kMAInmfDtA/D2S8+0AAABfWBF1TdS/2C0CAABQUsqqMg/5CIpKscwRP/BIDFivl6Znw+YDRpuZq3vkrnQIjSkVqP677Ok6W6P0sCMMIqDFmpubww41J5inCW3H0d/72/9jIJ4Zb30aausalMeuuv3J0KV/jZmskqz6qIvMAWk9zXjrE4uPEtDU1ByGH3Sa3wVJUk5tXpUJ9225VciWV0h5b+t+I91nhekVpwsBAAAoNH95AciJl44DxF9neuk4HdXyqLFRm7qTAaDdrjXrLVkAAAD+wcSornaMAACsfo7eKepey2QAKAnOtwPE3ys53w4AAPCP/hQ1wo4RAACAklGWztzoAygqxY7/wU89CgPWafGSpWH76hPMy9UddMSuITSmVMAOOGxX19oabbXToYYR0GJPTn7ZLE1w4++430UOOah76OVQW9egPDbmpxPMY5Vs/YYdZQ5I6+n6uyeHj2Z/bgFSAp56zr5TkpR72/QbEV6tqAzZ8gopr53Va7B7rEB1rhpV6YQhAAAAheSvLgA58dJxgPjrTC8dp6P7Y9Su7mYAaJdrzXpLFQAAgK9YFDUm6ut2jgAAJfv8/OtRp0YtsDwGgJLhfDtA/D2T8+0AAABrNzGqs50jAAAAiVeWrj7fB1BUiv3oips9AgPW6fyf3mRWrq7rgOqQfbx3CI0pFbBTThnqeluj9LAjDCOgxQ4/5SdmaUIr32bfMGfuPBc5xPTuR38JtXUNynOHn36VmazS/Zh4/5pw+U2PmAXSerr53qlh3oIlFiIl4KATLvDbIEnKueN67RCy5RVSXptU2cv9VbjGOGEIAABAIfmLC0BOvHQcIP4600vHSYLmqJui/sNdDQDtaq1Zb5kCAACwTi9HDbB7BAAouWfnW0e9ajkMACXH+XaA+Psm59sBAADWbW7UcVEb2UECAACQWGVVmSN9/ESlWO2tv/H4C1irF6fNDF0G1JiVq7vw3O1DaEypwF1ywXautzXqv/uRBhLQIu9+8Inf8gR38rlXusghB/c98VqorWtQntv94DFmskq6Ey+42SyQNlDdQy+HZctXWowk3IzGd+w/JUkt6hfdqkK2vELKa9v1G+H+KkBlVdUvOmEIAABAIfmLC0BOvHQcIP4600vHSZJPo/Z2ZwNAu1lr1lueAAAArNeKqLFRm9pFAgAk/pn5P61e+3nJDACUJufbAeLvn5xvBwAA2LCGqC3tIgEAAEikTv0yO/sAikqxex54wmMv4CsWL1kahmSONydX12+nPcO8V7qF0JhSgbv56q1dc2u09chjDCWgRX585a3maIJ7YdpMFznENPsvC0JtXYMK0Fa7fMdMVkmXOfpCs0CK0UPPzgzNzdYkSXfSuVf6bZAk5Vyv9F5hSqp7yJZXSHnr3J7bur8KU/P/9qvewilDAAAACsVfWwBy4qXjAPHXmV46ThLVR/23OxwA2nytWW9ZAgAAEMubUTvaSQIAJPZ5+eAoL0YEgNLmfDtA/D2U8+0AAADxLI4aE7Wx3SQAAACJUjawuouPn6gUe3rKKx55AV9x3thfmJFfqu6GgSE0plSEJt5e5Zpbo8F7HWcoAbn/VXfJ0tBr6CHmaELbed+TXeSQg4eenRlq6xqU58b98vHQuX+NuaySrv+IY80DKWZTXn3HoiTh3v9odijfZl+/D5KknKvus0uYVV4RslKeejLVw71VoMqqMqc7ZQgAAECh+GsLQE68dBwg/jrTS8dJqtlR+7rLAaBN15r1liQAAACxNUWNj/pnO0oAgMQ8J/9m1NiolZa7AFDynG8HiL+Xcr4dAAAgN89FdbejBAAAIEk2KktnFvsAikqtGY3veNQF/IMXp80MXQb4MPr/NXLv3UPTrMoQGlMqQs/+pp/rbo22rz7BYAJyVvfbR83QBHdL3UQXOcT0l88XhesmNITaOuW7My69w0xWydelf00Y98snzAQpZjPe+sTiJOEuGner3wdJUosa22NQyJZXSHlr5767u7cKUTrzrCOGAAAAFIq/tADkxEvHAeKvM710nKRb9Q9MytztANAma816SxEAAICcvR21k10lAECHf0a+XVTW8hYAWM35doD4+ynn2wEAAHK3OGpM1CZ2lgAAACRCWVXmdR9AUak1Z+48j7mAv1u0eEkYkjnefFxd5/7VYeoDfUNoTKlITf5tX9feGg0dfaLhBORsxEGnm6EJLbXtfuHzeQtc5BDTI5Nnhdq6BhWgA04cay5LUWdceoeZIMXshrufC5/8eb4FSoKt2qv03ukQvw+SpJwrT2fCpMpeIVteIeWlC3ps494qSJmmroP2+LZThgAAABSCv7QA5MRLxwHirzO9dJxS8FnUaHc8ABR9rVlvGQIAANAiTVFXRG1qdwkA0OGejf9T1LjVazoAgP/jfDtA/H2V8+0AAAAtNzmqwu4SAACADq9TVeY+Hz9RKdV10N6hqanZ4y3g7869bLz5+KVOOWVoCI0pFbEp9/V17a3RsP1PNZyAnEx9ZYb5meBOu+AaFznENHfeonDdhIZQW6dCNKTmZHNZitr/e2PNBCmHbv3tC2Hh4mUWKgl23W2/9fsgSWpRO/UdHt4oT4VseYXU6p6q7OG+KlCbpauPdsoQAACAQvBXFoCceOk4QPx1ppeOU0rqo/7DnQ8ARVtr1lt+AAAAtMobUVV2mAAAHea5+FZRr1rGAgBr4Xw7QPy9lfPtAAAArbMoatVHHTeyywQAAKDDKquqvtTHT1RK9d/9SI+1gL977sXXQuf+Nebj6roNHhU+ndo9hMaUitjU+/u4/tZov+POM6CAnJww5grzM8G9/FrWRQ4xPTolG2rrGlSAfn7Xs6Fi6/3MZSlqcOZEc0HKsd88Oj2sbGq2WEmopcuWha1HHuM3QpLUos7ouV3IlldIeWmnvsPdV4UonXnQKUMAAAAKwV9ZAHLipeMA8deZXjpOqXk3aid3PwAUZa1Zb+kBAADQasujLozaxE4TAKDdPg/fOHzxYcJllq8AwDo43w4Qf4/lfDsAAEB+TIoqs9MEAACgQyqryhzo4ycqpXbZ72SPs4C/WbR4Sdhu1HfNxi9V+9NtQ2hMqci9+GAf198aHXfW5YYUENvsP88NXQftbX4mtGH7n+oih5g+X7AkXD9hcqita1ABOu+q35jL0uq6Dton/PyOp80GKccef77RgiXBfj3xSb8RkqQW1aUqEyZs2SdkyyukVvejHtu6rwpQWVX10v/qnvlXJw0BAADIN39hAciJl44DxF9neuk4pag56pqoTU0BACjoWrPesgMAACBvpkRV2m0CALS7Z+FbRD1juQoAbIDz7QDx91nOtwMAAOTPZ1E1dpsAAAB0ON+uqunp4ycqpUYf+UOPsoC/+eElN5iLX2rIyJFh2RuVITSmVOSm3t/HNbhGq+5PgLjG3TjB7Exwt9dPcpFDTI9P/WOorWtQgTryzJ+by9KXOnvcPWaD1IJef/MTi5aEampqDiMOOt1vhCSpRaXTe4Q/VHQL2fIKqVU9merhnipU6cy+ThoCAACQb/7CApATLx0HiL/O9NJxStn0qD4mAQAUbK1Zb7kBAACQV/OjjrLjBABoN8/Bj4laYJkKAMTgfDtA/L2W8+0AAAD5d0vUv9p1AgAA0HHst98mZenMYh8/Uan0nVMv9ggLCJNfnB46968xF7/Uo3XpEBpTaoN+96sq1+AaXV57p0EFxLJixcowYPhRZmdC6zbkgDB/4SIXOsQwf9HScMPdk0NtXYMK1LCDxpjN0pc69PtXmg1SC7o++r3+aPbnFi8J9fSUV/xGSJJa3EFb7RSy5RVSq9ux7+7uqQJUls7c4aAhAAAA+eavKwA58dJxgPjrTC8dp9QtiTo1aiMTAQDyvtast9QAAAAoiHuj/sPOEwCgzZ5//1tUnWUpAJAD59sB4u+5nG8HAAAojHeitrXzBAAAoMPolM685OMnKpVOOe8qj6+gxM1fuChss8cxZuKXP9J3xK4hNKbURt127SDX4Rr94s4HDCsglvsmPWtuJrizfnKdixxieurFN0NtXYMKWM8dDzWbpS+1835nmA1SC7v1t1PDgkVLLWAS6qATLvA7IUlqcdd16x+y5RVSqzq/57bupwJUVpX5a69e+/0/ThoCAACQT/6yApATLx0HiL/O9NJx+ML9Uf9lKgBAXtea9ZYYAAAABfNu1BC7TwCAoj/73jrqLctRACBHzrcDxN93Od8OAABQOMujLoza2A4UAACAdq8snRnv4ycqlc7/6U0eXUGJO+PCa83DL9V1YCa89VSvEBpTaqPGXTLYtbhGv574pGEFxFL9nTHmZoKbPtO/L4U4FixaGm64e3KorWtQgbr0xofMZWmNttzuwHDtXc+aEVILu2fStLBiZZOFTALNaHwndBlQ47dCktSiuqX3Ck+neoRseYXU4h5P9XQ/FaiydGaYk4YAAADkk7+sAOTES8cB4q8zvXQc/n/vR+1oMgBA3taa9ZYXAAAABbUi+MgNAECxnnlvFHVq+OJDgwAAuXK+HSD+/sv5dgAAgMJ7LOrbdqEAAAC0a2VVmaN8+ESl0s9uqPPICkrY48/+wSxco5/8aEgIjSm1YeeM2cG1uEar7lWADXkj+yczM8HtfuD3XeQQ09N/eCvU1jWogJ1w/k1ms7SWLrz2fjNCakVPTP2jhUxCnXzulX4nJEktbkSfYWFGRSpkyyukFrdD3+Hup0KUrq510hAAAIB88lcVgJx46ThA/HWml47DP1oZvvgI7SYmBAC0eq1Zb2kBAABQFE9EldmJAgAU7Hn3/0RNsuwEAFrB+XaA+Hsw59sBAACKY3bUcDtRAAAA2q1vpzO9fPhEpdIv7nzA4yooUfPmLwwDRxxlFn6p9M57hvmvbhlCY0pt2LHH7+R6XKPsm+8ZWsAGnXHhtWZmgrvr3t+7yCGG+QuXhBvunhxq6xpUwDJHXWg2S2vpmB9eZ0ZIrWx640cWNAn0wcefhYpt9vNbIUlqcT/psU3IlldILe7cntu6lwpQWVX1h1/72tc2ctoQAACAfPFXFYCceOk4QPx1ppeOw9o9FbWZKQEArVpr1ltSAAAAFM2nUcPsRgEA8v6se3j44oOCAACt4Xw7QPx9mPPtAAAAxdMU9eOoTexIAQAAaIcu2Lgsnfncx09UCt39wOMeVUGJ+t4Pf2YOrjkTxw8MoTGlNm6nvUa4Hr9U5/41YdHiJYYWsF5//XxBSG3rA+VJrcf2B4WFi/wWQByPTWkMtXUNKnBVw48xn6W1NOLQc8wIqZVdP2Fy+HD25xY1CfTjK2/1WyFJanFbVGXCpMpeIVteIbWox1I93UuF+ltmeq9BzhoCAACQL/6iApATLx0HiL/O9NJxWLfPgo/QAkBr1pr1lhMAAABF1Rw1Nmpju1IAgFY/494oakzUSstMACAPnG8HiL8fc74dAACg+J6K+rZdKQAAAO1Op6rqR334RKXQg49O9ogKStCkJ6eagWs0cu/dQ9OsyhAaU2rDlr1RGboOcD1+uardvmNoARt0w+33mZkJ7uxLb3CRQwx/+XxRuG7C5FBb16AC9tNbHg2d+9eYz9Ja6rvrkeaElIduvvf5MG/BEoubhPnr5wtCr6GH+L2QJLW4nfoOD2+Up0K2vEJqUUP6DXcvFaCyqswlThoCAACQL/6iApATLx0HiL/O9NJxWL9VH0i7MPgILQC0ZK1ZbykBAADQJp6I+h87UwCAFj/f/q+oSZaVAEAeOd8OEH9P5nw7AABA2/gwaoidKQAAAO1KWbr6fB8+USn06DMvejwFJWbO3Hmh366Hm4FfqnP/6vDy77YKoTGlNu61R3q7Jteo5sgfGlzAejU1NYfBex1nZia412e97UKHGB5+dmaorWtQgTvpglvMZmmdzxdqws9ufcyskPLQ3ZNeCStWNlngJMy1t/za74UkqVWN6bldyJZXSC3qnJ7buo8K0wwnDQEAAMgXf00ByImXjgPEX2d66TjEMzHqP0wNAMhprVlvCQEAANBm3o/a1u4UACDnZ9sDo96xnAQA8sz5doD4+zLn2wEAANrOiqgxURvZoQIAANAubNZv1BAfPVEp9Mzz0zyaghJz7Jljzb81Ou20HUNoTKkddM/4ga7JNTr1/KsNLmC9fv/0C+Zlght1+A9c5BDD7DkLQm1dg4pQ5qgLzGdpPZ1x6R1mhZSnHp2StchJmEWLl4T0sCP8XkiSWtzmUfdtuVXIlldIOfdIZU/3UYEq65Pp7rQhAAAA+eCvKQA58dJxgPjrTC8dh/jei9ra5ACA2GvNessHAACANvW3j9zYoQIAxH6ufVzUMstIAKAAnG8HiL83c74dAACg7d0f9e92qQAAALS5AQOO+0anqswCHz5R0pv6ygyPpKCE1D/4hNm3Rt0HjwqzX+gRQmNK7aCLztvedblG426cYHgB63Xw9y40LxPcqvUbEOO0yROvh9q6BhWhvrseZT5L6+nAk35qVkh57NXshxY6CXPTXQ/6vZAktaqBfUeGaeWVIVteIeXc4L4j3EcFaLOq6h84bQgAAEA++EsKQE68dBwg/jrTS8chN0uijjQ9ACDWWrPe0gEAAKBduDPqm3aqAADrfJ79z1F3WzYCAAXkfDtA/D2a8+0AAADtQ2NULztVAAAA2lxZunqSD58o6U2f8abHUVAiPpk9J/QaeojZt0bX/WzbEBpTaifVHLib63KN7n3oKQMMWKc/vfdR6DKgxrxMaH12PiwsXbbMhQ4b8NHsz0NtXYOK0NibHjGfpQ204z6nmRdSHrtuwuTw3sdzLXgSZNUeZ9CIo/1mSJJa1fd6bx+y5RVSzp3Zazv3UCFKZ6Y4aQgAAEA++EsKQE68dBwg/jrTS8ehZcZHfcMUAYD1rjXrLRkAAADajVejtrBbBQD4yrPsLlEvWS4CAAXmfDtA/H2a8+0AAADtx4Kove1WAQAAaFNl6eozffhESS/75nseRUEJaG5uDoeedJG5t0ZDRo4My96oDKExpXbQ/Fe3DF0HZlyba/RG9k+GGLBOP7riZrMywV127R0ucojh14++GmrrGlSETjhvvPksbaAttzswXHvXs2aGlMdu/s3z4fMFSyx6EuSO3zziN0OS1Ko6R/2qW7+QLa+QcuqByt7uoYKUadp8wOjNnDYEAACgtfwVBSAnXjoOEH+d6aXj0HINUf9rkgDAOtea9ZYLAAAA7cqcqF3tWAEA/v4ce8eo2ZaJAEARON8OEH+v5nw7AABA+9IcNTZqY7tWAAAA2sS305lePnqipPfO+x97DAUl4Pb6SWbeWnri7nQIjSm1kx6+o8p1uUYV2+wXVqxYaYgBa7Vg4eLQY4eDzMuEtvmA0eH9j/wbVNiQtz+YE2rrGlSk9jj8PDNaitHF1080M6Q8d/ekV8KKlU0WPwmx6nnXdqO+6zdDktSq+vbbI/yholvIlldIsZsVVRVdO+6hAtQvc6zThgAAALSWv6IA5MRLxwHirzO9dBxa54OoQaYJAKx1rVlvqQAAANDurIgaY9cKAHiGHY6LWm55CAAUifPtAPH3a863AwAAtE+/i/qWnSsAAABtoiydecuHT5TkPpk9x+MnSLj3Pvw0dB9yoJm3RocfvUsIjSm1o35w5g6uzTXa67CzDDFgnW69+3dmZYI79syxLnLYgObmEOoeejnU1jWoSPXe6XAzWorRCeeNNzOkAvTYlEYLoASpf/AJvxmSpFZ32FZDQ7a8Qsqpk3pt7/4pROnqB5w0BAAAoLX8BQUgJ146DhB/neml49B6S6KOMFEA4CtrzXrLBAAAgHbrzqhv2r0CACX47HrTqFstBwGAInO+HSD+vs35dgAAgPZr1ccQetq9AgAAUHSd0tW1PnyiJPfZnL969AQJ1tTUHPY55hzzbo22GJQJbz3VK4TGlNpRg4fv4fpco3MvG2+QAWvV3Nwcho4+0axMcM+9+JoLHTZgxlufhtq6BhWpi294yHyWYpY5+kJzQypQr//xY4ughFjZ1GRfK0nKSzd0rwrZ8gopdvds2ce9U5gWdj7N3XgAACAASURBVB069J+cNgQAAKA1/AUFICdeOg4Qf53ppeOQP5dHbWyyAMDf15r1lgcAAADt2vNR37aDBQBK6Ln1ZlEvWgYCAG3A+XaA+Hs359sBAADat1UfeN7dDhYAAICi6pSuGemjJ0pyc+bO89gJEmz8HfebdWvpkh9tF0JjSu2ot57q5dpcS3c/8LhBBqzV01OmmZMJbud9TgrNzc0udFiP5StWhlvveyHU1jWoSB179vVmtBSzgXt819yQCtT1d08OH3/m7xpJ8eCjk/1uSJJaXff0XuHZVPeQLa+QYjWjIhV6p/d0/xSidPUeThsCAADQGv56ApATLx0HiL/O9NJxyK+Hov7VdAGAv6016y0NAAAA2r0Po/rbxQIAJfDMuk/Ue5Z/AEAbcb4dIP7+zfl2AACA9m9l1Ml2sQAAABRN16FD/6lTunqeD58oqc2Z6+OTkFRvvvNBSG27n1m3Rumd9wzzp3ULoTGldtTPLh7s+lxLs9581zAD1uo7p15sTia42+snuchhA6ZOfzfU1jWoiO1+8BgzWorZ5oP2Dtf86mmzQypQt93/Yli8dLkFUQI0NTWH3Q441W+HJKnVjd5qlzCrvCJkpZgd03tH905BylzvtCEAAACt4a8nADnx0nGA+OtMLx2H/JsetbkJA4C1Zqi3LAAAAOgQFkSNspMFABL8vHpElBfNAwBtyfl2gPh7OOfbAQAAOo7xUV+3mwUAAKAoyqqq7/TREyW1uZ/P96gJEmjFypVhr8POMufW0q9vGhBCY0rtqOZsKgwePtL1uUaVg/f/270MsKb3P5odNh8w2qxMaD13PDgsXLTEhQ7rsWDR0nDjPc+F2roGFalr73o2bDnkQHNayqFzxtWbH1IBu/+J10Nzc7OFUQL8/ukX/G5IkvLSuO4DQ7a8QorVbd3S7ptClM68/7WvfW0jpw0BAABoKX85AciJl44DxF9neuk4FMZHUQNNGQBKfK1Zb0kAAADQYax6odsYu1kAIIHPqk9dvdYBAGhLzrcDxN/HOd8OAADQsTwS9S07WgAAAApus/Soah8+UVKb+/l8j5kgga65ud6MW0uj9t89NGdTITSqPTXlvr6uz7W0zzHnGGbAWl007lZzMsFdcMXNLnLYgEefy4baugYVsXPG2WNKufadM642P6QCN/W1dy2MEmKvw87y2yFJanWp9KjwZKpHyJZXSBvs9fJU6BZdM+6dQjSqr9OGAAAAtJS/mgDkxEvHAeKvM710HApnYVSNSQNACa816y0HAAAAOpxfRH3DrhYASMAz6q9H1VreAQDthPPtAPH3c863AwAAdDyvRXW1qwUAAKCgug4d+k+d0tXzfPRESeyvny/wiAkSZkbjO2GLrfcx49aoy4BMmPZQnxAaU2pnnXbajq7RtXT1TfcYaMBXLFq8JPQaeog5mdA2HzA6vPfhpy50WI9P58wPtXUNKnIHnHi5OS3l2G6H/ND8kIrQ2x/MsUBKgGeen+a3Q5KUl/bqMyzMKq8IWSlGh/beyX1TiNLV5zhtCAAAQEv5qwlATrx0HCD+OtNLx6GwmqLONG0AKNG1Zr2lAAAAQIf0+6h/s7MFADrw8+l/j3rcsg4AaEecbweIv6dzvh0AAKBj+iRqkJ0tAAAABVWWztzhwydKYp/PW+DxEiTIihUrw8iDTzff1tIZp+0YQmNK7axFr1WG7oNHuUbX0iuvNxpqwFfc8ZtHzMgEd+yZY13ksAH3PjY91NY1qMgN2uMEc1rKsT67fsf8kIrQTb95PsxbsMQiKQH2OeYcvx+SpLx0efdBIVteIW2wG7pXuWcKUTozxUlDAAAAWspfTABy4qXjAPHXmV46DsXx86iNTR0ASmytWW8JAAAA0GG9HtXZ7hYA6IDPpsuiplnOAQDtjPPtAPH3dc63AwAAdFwLo/ayuwUAAKBgOvevHu7DJ0pi8+Yv9GgJEmRs7R1m21rqsd2o8NkL3UNoTKmdNWH8QNfoWuq548FhZVOToQZ8xa77nWJOJrg/vDrLRQ7r8cd3Pwu1dQ0qcj+79bHQpX+NOS3lWOfovhn3yyfMEakI3f3wK2HFSs9ROroXp830+yFJykup9KjwZKpHyJZXSOttWnllKE9n3Dd5L9P0P1uN+l+nDQEAAGgJfzEByImXjgPEX2d66TgUz31R3zR5ACihtWa9n38AAIAO7cOovna4AEAHei7dO+o9yzgAoB1yvh0g/t7O+XYAAICObWXU8Xa4AAAAFMZ++21SVpX5wIdPlLT++vkCj5UgIabPfCt0HbS32baWxl+5dQiNKbWzmrOpsHNmhGt0LR19+mWGGvAVk1+cbkYmuD0PO9NFDus7EbKyKdz+wB9CbV2Ditz3fnSTOS21sDE/nWCOSEXqyRfetGBKgENOvMjvhyQpLw3vu1uYWZ4K2fIKab3t02cX90wBKkuPOsJhQwAAAFrCX0sAcuKl4wDx15leOg7F9XzUf5s+AJTIWrPeTz8AAECHNzdqR7tcAKADPJMeHDXH8g0AaKecbweIv79zvh0AACAZxkZtZKcLAABA3pVVVV/mwydKWp/NmetxEiTAsmXLw877nmyuraXtR44My96oDKExpXbWpDurXKPr6LZ7HjbYgK846rRLzcgE98DvG1zksB4vzfgg1NY1qA0acdi55rTUwo4442pzRCpiM9/+1KKpg5s+863QuX+N3xBJUl66tMegkC2vkNbbld0Hul8KUFlV9a+dNAQAAKAl/LUEICdeOg4Qf53ppeNQfG9GVZpAAJTAWrPezz4AAEAiLI06wE4XAGjHz6P3jlpi2QYAtGPOtwPE3+M53w4AAJAct0V9w24XAACAvCrrW9PNh0+UtD74+DOPkiABLvzZLWbaOnrynnQIjSm1wzIH7OYaXUd/eu8jgw34B6vW7ZsPGG1GJrSBI44KK1asdKHDOixavCz84tdTQm1dg4rctXc9G7pvf7BZLbWwEYeeY5ZIRezGe54Lf5670OKpgzv69Ev9hkiS8lJFelR4PNUzZMsrpHX2fEW30KUq457Je5kFlZUjNnXaEAAAgFz5SwlATrx0HCD+OtNLx6FtfByVNoUASPhas95PPgAAQGI0RZ1stwsAtMNn0aetXqsAALRnzrcDxN/nOd8OAACQLA9F/bMdLwAAAHnVqap6sg+fKEm9/e5HHiNBBzf15TdClwE1ZtpaOvKYXUJoTKkd1nBvP9foOhqSOd5gA77ikqtvMyMT3A233+cih/V49LlsqK1rUBt0/lX3mtNSK+q329FmiVTkbn/gxbBk6QoLqA5s1pvvet4tScpbu/XZLcyoSIVseYW0zoZF14n7Jf+VpTPDnDQEAAAgV/5SApATLx0HiL/O9NJxaDsLonY1iQBI8Fqz3s89AABA4oy14wUA2tFz6DGWZwBAB+F8O0D8vZ7z7QAAAMnzYtR/2/UCAACQN537ZQ7x4RMlqVUfJwQ6rkWLl4QhmePNs7W0xaBMePvpXiE0ptQOO+CwXV2n6+jy2jsNN+AfLFm6LGy106FmZELrscNBYf6CRS50WIePPpsXausa1EYdcsoVZrXUirr0rwlX3f6keSIVud89MyM0N1tHdWQnnv0zvyOSpLz14x7bhGx5hbTOftRjW/dKASqrqr7aSUMAAABy5a8kADnx0nGA+OtMLx2HtrU0qsY0AiCha816P/UAAACJdH3Uxna+AEAbPn/eKOpqyzIAoANxvh0g/p7P+XYAAIBkmhHVyc4XAACAvKisHLFpp6rMbB8/UVKaPuNNj4+gAxtz8fVm2Tq69MLtQmhMqR320sQ+rtH1NOvNdw034B/U3feY+Zjgxt04wUUO69DU3BwmPPxKqK1rUBu17V7fM6ulVnb2uHvME6kNeumN9y2mOrC33/0odB24t98RSVJe2qIqE36f6hmy5RXSWnsk1cu9UoDK0pm3nDQEAAAgV/5KApATLx0HiL/O9NJxaHsroo4wkQBI4Fqz3s88AABAYt0V9Q27XwCgDZ49fz3qNssxAKCDcb4dIP6+z/l2AACA5HonqtLuFwAAgLwoq6q+1MdPlJRenDbToyPooJ6d+mro3L/GLFtL6Z32DPNf3TKExpTaWc3ZVNhrv91dp+to6OgTDTfgK3Y74FQzMqH12P6g8NfPF7jIYR1emfVhqK1rUBt1+c2/D13sOaVWd+RZPzdTpDbougkN4f1P/mpB1YGdceG1fkckSXlrpz7Dw4zyVMiWV0hrbVC/ke6VAvTtqpqeThoCAACQC38hAciJl44DxF9neuk4tA/NUd83lQBI2Fqz3k88AABAov0u6pt2wABAEZ87bxp1n2UYANABOd8OEH/v53w7AABAsn0S1dcOGAAAgFb7dtXeXTulMyt9/ERJaPKL0z02gg5o/oJFYdCIo82xdfTbWwaE0JhSO+w3Nw9wja6ncTdOMOCAfzD15TfMxwR36c9/5SKHdVi4eFkY/+spobauQW3UsWdfb1ZLeaj6qB+ZKVIbdctvp4YFi5ZaWHVQ7380O3QdtLffEklS3rqgxzYhW14hrbVTeg5xnxSgsn6Zs5w0BAAAIBf+QgKQEy8dB4i/zvTScWhfxppMACRorVnvpx0AACDxnon6ll0wAFCEZ87fimqw/AIAOijn2wHi7/+cbwcAAEi+uVHb2QUDAADQap3SmXt8/ERJ6PFn/+CR0f/H3p24SVXeCf+Oybwz72SW30zmzWTSoNhVrCJSDSjuQgSVCN2AIi4xajQaY1ziHpcYNa5xt3GPEpdG2n3fUWkEFFEEgW5RUVABFQVk6/X5FV5JJkSWU921dt33dX3+AKsP3/M8px5PQQE64ZyrzbCNVD56cGipjYdQp3xr9cwuYYfBP3adbqK69xYYcMB6jj7tMvOxndZ5pwPCZ0uXuchhI56ZNDdUVtUohw3Y/2TzWkpDex5wYri5erK5IuWo+5+dEZqbWyyuCtSp51/vXiJJSltbl5WHZ+I9Qm1pTPpG93bp5d9JBipJVLzslCEAAACp8O0IQEq8dBwg+jrTS8ch/1xmOgHQTtaa1W7rAAAARWHdS1u/ZycMAGTwefP/S/aGZRcAUMCcbweIvgd0vh0AAKA4fJVsgJ0wAAAAbdKx9/Ad/PiJ2kMPPTXR4yIoMM+89Kr5tZG27FseZjy5bQh1ceVhl1+4s+t0Ew064EQDDljPx4s/C536jTQj22mXVt7lIoeNzb8ly0JlVY1y2NV/mhA6bb+feS2loa132C/Uvr84jBlntki5atIb71tgFagPFi6yL5YkpbUB2+0dZpfGQ21pTFqv2bF46NF7qH8n6S5R0dipd8V/OGkIAABAVL4dAUiJl44DRF9neuk45Kcbkm1hSgFQ4GvNard0AACAojEj2ffthgGADDxr/u9kb1luAQAFzvl2gOj7QOfbAQAAiseqZIPthgEAAGiTkkTFy34ARYXeXfc/7VERFJClXy4PiUGHmV8b6bRTdw+hLq487JPJ3UPnHYe5TjfRjX96yJAD1nNp5V3mYzut794/C1+tXO0ihw1oam4J9zw+PVRW1SiHnXD+7ea1lMbemvNueH32QvNFymHvL/zcQqtAnXDO1e4lkqS09rse/UNtaUz6Rj/ddg//RjJRonx/pwwBAACIyjcjACnx0nGA6OtMLx2H/HVzsm+bVAAU8Fqz2u0cAACgqMxNVmJHDACk8TnzD5LNsswCANoB59sBou8FnW8HAAAoLmuTldsRAwAA0GolZeXlfvxEhd4NYx/0mAgKyDGnX252baQeuw4Nn73WLYS6uPKwn/9igOt0E8V3HBW+WLbCkAP+95vM+vqw3Y8ONSPbWZ36jQyjjzk3TJsx10UOGzF99sJQWVWjHLfPoWeb21Iau+eBZ76ecRNenWfGSDnq1vunhBUr11hsFaB58xeGrfqOcD+RJKWtrcvKw9Ode4Ta0pi0Xjd2K/NvJCOV3+aUIQAAAFH5ZgQgJV46DhB9neml45Dfbk32bdMKgAJda1a7lQMAABSd2mQd7IoBgDQ8Y/6fZLMtrwCAdsL5doDo+0Hn2wEAAIpPfbLhdsUAAAC00nnfLikrn+XHT1TIXT7mHo+IoEA89OTL5tYmuu2aHUKoiysPq76lr2t0M5183nWGHLCe8Y+8YD4WeF13GR32PujX4RenXx7GjH0wvPLazLBi5SoXN2zCipVrw83Vk0NlVY1y2HV3vxw673SgWS6lsTMvuvHrOdfU3BweeO4ts0bKUfc/+1Zobmmx6CpAx57xB/cTSVJaG9xrcJgdi4fa0pj016bHOodOZeX+jaS5krKKj771rW9t4ZwhAAAAUfhWBCAlXjoOEH2d6aXjkP/WvfDgH0wsAApwrVntNg4AAFCU3k+2tZ0xANCG58tbJptnWQUAtCPOtwNE3xM63w4AAFCcGpLtZ2cMAABAq5SUVYz2Aygq5M69/FaPh6AALPnsi9BzwCHm1kYaMHSf0Dincwh1ceVZH9b0CN13HuY63Uwz3n7HoAPWM+Tgk83HAqi0//5hjxHHhZ/9+uJw4dV3hLsfeCZMnjYrLFryuYsYWuHxl2eHyqoa5bjTL60y46U0V3H4GX+ddWvWNoa7Hp1m3kg5avKM+RZdBWjuvA9Cxz7D3VMkSWnt4u7bh9rSmLRe5b329O8jIw3bzilDAAAAovCtCEBKvHQcIPo600vHoTDcnew7phYABbbWrHYLBwAAKFrvJetkdwwAtOLZ8tbJ3recAgDaGefbAaLvC51vBwAAKF6NyUbbHQMAANAK5327pKx8lh8/UaH26/Ou9WgICsBPT7jQzNpEL93XO4S6uPKsxrnxMOyAvVyjm2nvg35tyAHree3NOeZjnrTNHoeEIQefHA5LrsVOv3BMGHPHA+GxZyeFV5N/ow8/Whyam1tcsJAmtfOXhMqqGuVBFUdd4B4gpbluuxwYWlr+d93wxfJV4Zb7ppg5Uo6a/9FSi68CdOTJl7inSJLSWiwxLEyIdw+1pTHpr13afXv/PjJQSe/y05wxBAAAIArfiACkxEvHAaKvM710HApHdbJ/MLkAKKC1ZrXbNwAAQFH7MNnWdsgAQArPlbdM9p5lFADQDjnfDhB9b+h8OwAAQHFrSnaQHTIAAAAp65ioONgPoKhQW/cjhEB+q3rwWfNqU3Ps6IEh1MWVh116wc6u0Qjd+8jzBh2wnl+eeYX5mMG27Ds8JAYdHgaPPjEcevwF4dfnXRsurbwr/LHqsfDYs5PCtBlzwyeLPw9Nzc0uRsiSNWsbwh8fmBoqq2qUB/Uc8FP3CykDLfh4yXqz78NPvghjxk0yd6QctG7dsXJ1vUVYgZk5993Qsc9w9xRJUlob2mtQmFsaC7XSn3s53t2/jQxUUlYxwQlDAAAAovCNCEBKvHQcIPo600vHobCMTfZt0wuAAllrVrt1AwAAFL15yTrYJQMAEZ4pd0j2ruUTANBOOd8OEH1/6Hw7AAAATclG2yUDAACQmlGjvtMhUT7Hj6CoEDvg6HM9EoI8tvCTT0P3XQ8yrzZS6Q7l4f2Xe4RQF1eeNfWR7cJWfctdp5up54BDwpq1fsQZ+F+LP10aOm0/0oxMsU79RobEoMPDj0YdH/b/+dnhF6dfHs657JZwza3jw72PPB+enzgtzJr7Xljy2RehqbnZhQZ55plXakNlVY3yoHOvfsB9RcpQz7782jfm34zaj8weKUc9+PzM0NLSYiFWYH56woXuKZKktHdF936htjQm/bVdeu/t30aaKykrr/+vbuX/5pAhAAAAm+PbEICUeOk4QPR1ppeOQ+H5Y7Jvm2AAFMBas9ptGwAAgKR3kv3QThkA2MTz5B8km2PZBAC0Y863A0TfIzrfDgAAwDoNycrtlAEAAEhJSVnFMD+CokJs3Y/OA/mpubkljDr6HLNqE11+4c4h1MWVZy1/o2voP3iIazRCV940zrAD1nPFjVXmY7Jt9jgk7DT06LDvoaeGQ4+/IJx47jXh/CtvD9f/8b4w7uHnwjMvvRpee3NOeHf+R2HZ8q9cOFDAPvjki1BZVaM8af9jL3EfkjLUdbfdt8E5+NJr88wfKUdNnfmBxViBeWNWnXuKJCntdU0MCxPj3UJtaUz6ulN67OzfRgb6YWJYhROGAAAAbI5vQwBS4qXjANHXmV46DoXp1mRbmGIA5Plas9otGwAAgD+rTfY/dssAwAaeJX8/2duWSwBAO+d8O0D0faLz7QAAAPxFfbJ97ZYBAABISUlZ+Ut+BEWFVmLQYR4FQZ668U8PmVObqN+gH4dVMzuHUBdXnnX0Lwa6RiPUfbeDwrLlXxl2wP9+Q1nf8PX6vD3MuG67HJj8bzk87DzsmDDk4JPD6GPODUefdlk47cIx4aJrxoYxdzwQ7n7gmfDYs5PCxKkzwltz3g0ffrTYXIQi09DYFO58dFqorKpRntRz4GHW6lKG+uWZV2xwFjY3t4SHX5hlBkk5aMy4mrBg0ZcWZQXmoGPPc1+RJKW9Yb32DHNLY6FWSlbdpZd/F5koUXGj04UAAABsjm9CAFLipeMA0deZXjoOhesaUwyAPF9rVrtdAwAA8DfeSvZfdswAwN88R/5/yWZaJgEARcD5doDoe0Xn2wEAAPhba5MNsWMGAAAgso6Jodt3KKto8UMoKqS26jvi6x9uBfJL3XsLQqz/KHNqEz18R5/kBxVXnnXTlf1dnxG78qZxhh2wngeeeDEn82jEEWeGY06//OuOP/uqcPqFY77unMtuCRdd+6evWzezxtzxQLjpzofD3Q88Ex55piY8N3FaeOW1meGtOe+G9z/8OCz+dGlY8dUqf0ggspenvRsqq2qUJ5199f3W6VIGG7j/8Rudh2vqG8Pdj71uFkk56I8PTg0rV9dbmBWQqW/Mdl+RJGWka7v1DbWlMSnMjsVD98S+/l2kvfL5ThcCAACwOb4JAUiJl44DRF9neuk4FLZLTTIA8nitWe1WDQAAwN+Znuw/7JoBgOSa4HvJZlgeAQBFwvl2gOj7RefbAQAA+HvrfvRtd7tmAAAAIutQVl7lR1BUaC39crnHQJBHGhubwpBDTjGfNtHwAweHltp4CHXKp157tFfo1K/cNRqh7rsdFJYt/8rAA9az76GnZn0e9Rp4aFhb7wfkgexb9NmKMGZcTaisUr603zG/t1aXMlinfiNDfX3DRufil8tXh1vvn2IeSTnooednhpaWFgu0ArLfUWe5t0iS0l7XxNBQE+sWaktjUvhJzwH+XWSgkl7l3ZwuBAAAYFN8CwKQEi8dB4i+zvTScSh8Z5lmAOTpWrPabRoAAIANmJLsX+2cAaConx9/N1mNZREAUEScbweIvmd0vh0AAIANWfej0v3snAEAAIjkB70rti4pq1jrh1BUSNW9t8AjIMgjF193p9m0ibbsWx7eemrbEOriyqOWvNo9lA38sWs0YlfeNM6wA9bzxqy6nMyjS66/y4cPZF1Tc0uoemJ6qKyqUZ50/T0TQ88Bh1qrSxludt38Tc7Hj5csCzfeO8lcknLQtFm+JykkNa++5b4iScpI+207MNSWxqRwfbe+/k1koj4VJzldCAAAwKb4FgQgJV46DhB9neml49A+nGiiAZCHa81qt2gAAAA24rlk/2T3DABF+ez4H5M9ZTkEABQZ59sBou8bnW8HAABgYz5L1sPuGQAAgEg6JCqu9EMoKqQmT5vl8Q/kiWkz5oat+o4wmzbRmaftFkJdXHlU45zOYfiBg12fEeu+20Fh2fKvDDxgPb86+6qsz6N1a44FHy/x4QNZN2XG/FBZVaM86jdXjrdWl7LQA0+8uNkZOeudT8wlKQeNGTcpfLRkmYVaARlxxJnuLZKkjHRDt7JQWxpTkfdqrEvYKlHu30SaK0lUPOVkIQAAAJviGxCAlHjpOED0daaXjkP70JzsIFMNgDxba1a7RQMAALAJDyb7jh00ABTVc+PvJBtvGQQAFCHn2wGi7x2dbwcAAGBTPkq2tR00AAAAm7VVr33/s0Oi/HM/hqJC6bFnJ3n0A3lg5ao1YaehR5tLm2ibXYeGpa93DaEurjzqjNN2c32m0FU332vgAev5bOmyUNp//6zPoyNPvsSHD2Tdos9WhDHjJoXKqhrlUSN+fqG1upSFLrpmbKRZOfH198wmKQfd/uDUsGpNvQVbgZgwabp7iyQpM99HJoaGqbGuobY0piJvUK/B/k2kuZJExZof9h36XacLAQAA2BjfgACkxEvHAaKvM710HNqPhmT7mmwA5NFas9rtGQAAgM1Y95KBLeyiAaAonhlvkexWyx8AoEg53w4Qff/ofDsAAACbMy/Z/9hFAwAAsFkliYpT/BiKCqXbxz3usQ/kgVPPv95M2ty8um77EOriyqPuv62vazOFtt/nyLB6zVoDD1jPVTffm5OZNHHqDB8+kFWNTc3h7sdeD5VVNcqjrr9nYuixx6HW61IW+smvzo80L1taWsLjL882o6Qc9PALs5L/Bq3bCsWQQ05xf5EkZaQjeu4RaktjKvLO6dHfv4dMlBg+xMlCAAAANsa3HwAp8dJxgOjrTC8dh/ZldbLdTTcA8mStWe3WDAAAQATX2EUDQFE8M77csgcAKGLOtwNE3z863w4AAEAUbyX7TztpAAAANqlz533+qSRRMc+PoagQuuiasR75QI49+/Jr5tFm+lH53qFxbjyEOuVLbz21bYjtUO76TKEnX5hs4AHraWxsCn32OiLr82jAyONCi1+KB7Ls5dffDZVVNcqzzvzDeGt1KUv12+dnkWdmfUNjuOfx6eaUlIOmz15o4VYgnn5xqvuLJClj3d2ld6gtjamIe6zzNv4tZKCSsoprnSwEAABgY3z7AZASLx0HiL7O9NJxaH+WJUuYcADkwVqz2m0ZAACAiE6zkwaAdv28+DeWOwBAkXO+HSD6HtL5dgAAAKKamOyf7aYBAADYpJI+w4f6MRQVQseddaXHPZBDS79cHhKDDjePo5Nt5QAAIABJREFUNtNL1b1DqIsrT1o8tVvoN+jHrs0UOuDocw084BseempiTmbSHeOf8OEDWbVw8ZehsqpGeVjFURdYr0tZ7ItlKyLPzi9XrA633j/FrJKy3A3jJoVPPl1uAVcAWlpawuDRJ7q/SJIyUp/eQ8KbpZ1DbWlMRdrcZL177+vfQ/qrdaoQAACAjfHtB0BKvHQcIPo600vHoX36JNnWphwAOV5rVrslAwAAEFFLssPspgGgXT4rPvjP93oAgGLmfDtA9H2k8+0AAACk4tFk37GjBgAAYJNKyioe92MoyvdGHnmWRz2QQ0efdplZtJmO/sXAEOriypO+mtElDB6+l2szhTr1GxnmzvvAwAO+oeLwM7I+k7rtcmBYsXKVDx/ImvqGxjD24ddCZVWN8qzr7pkYuu/+E2t2KYtNef3tlGboBx8vDWPGmVdStlu3dllb32ghVwAee3aS+4skKWOdtM0uobY0piLu5z13828hA23Vb2TMqUIAAAA2xDcfACnx0nGA6OtMLx2H9mtOsu+ZdADkcK1Z7XYMAABAChqS7WVHDQDt6jnxj5LVW+YAADjfDpDCXtL5dgAAAFJ1kx01AAAAm9SxbFjnkrKKtX4QRfncTkOP9pgHcuTeR543hzZTvP+wsGBSjxDq4sqDmuZ2Dkcc9SPXZoqd94fbDDzgG96a825OZtLZl9zswwey6rnJdaGyqkZ52CkX32W9LmW5kUeeFRqbmlKao9PeXmBmSTnoyZo5FnIFoLm5JQzc71fuMZKkjLRlWXl4sMu2obY0piLttq4J/xYyUEmi4pdOFQIAALAhvvkASImXjgNEX2d66Ti0b1OTfde0AyBHa81qt2IAAABStCJZwq4aANrFM+JeyZZZ3gAAfM35doDo+0nn2wEAAGiN0+2qAQAA2KSSsoqL/SCK8rnS/vuHlpYWj3kgyxZ8vCR03/Ugc2gzXXnRTiHUxZUnnfObXV2XKZYYdFhYvmKloQd8w4nnXpOTuVQ770MfPpA17y/8PFRW1ShP2+uQM63ZpRx0wVW3pzxPn54019ySctCc9xZb0BWAB594yf1FkpSxdt1u7zC7NB5qS2MqwmbEOoety8r9W0hzJYmKB50oBAAAYEN86wGQEi8dB4i+zvTScWj/Hkn2HRMPgBysNavdhgEAAGiFj5N1srMGgIJ+PlyabJFlDQDAXznfDhB9T+l8OwAAAK2x7genD7OzBgAAYKN+sN3gfykpK1/oR1GUz336+Zce80AWNTe3hP1/frb5s5m2H/TjsGpm5xDq4sqD/njNDq7LVvTE85MNPeAbPv9ieYj1H5X1mTT6mHN9+EDWrFnbEG5/cGqorKpRHnbV2Alh6x32t2aXclDHPsNT3is2NDaFqiemm19Slru5enL4cvlqC7s819TcHHYedox7jCQpY53To3+oLY2pSCvvtad/B2mupKz8y2+NGuUH7QAAAPgG33oApMRLxwGirzO9dByKw40mHgA5WGtWuwUDAADQSnOSfc/uGgAK8tnwfyWbazkDALAe59sBou8rnW8HAACgtRqS7WV3DQAAwEaVlJUf6EdRlM+9Neddj3ggi24Y+6DZE6HH/lQWQl1cedCE8YnQqa9rMtVO+d31Bh6wQdfeVp2TufTUhKk+fCBrnpw4J1RW1ShPO+asG63ZpRzWdZfRoe69BSnN1S9XrA633j/FDJOyXPXTb4bm5haLuzw3dvyT7i+SpIy1dVl5eLpzj1BbGlMRdkH3/v4dZKK+5f2dKAQAAODv+cYDICVeOg4QfZ3ppeNQPE419QDI8lqz2u0XAACANpiY7J/ssAGgoJ4L/99kr1jGAAB8g/PtANH3ls63AwAA0BbLk/WywwYAAGCjSsoqJvhRFOVrT74w2eMdyJK6dz8Msf6jzJ7NtN8hg5IfVlx50Myne4auOw1zXabYjvv+PKxYucrQA76hsakp9NvnZ1mfSzsMOSo0NTf7AwBZMWveolBZVaM8bpfhx1u3Szlu9xG/DF+tXJ3SfF2w6MswZtwkc0zKcpNnzLfAy3Nr6+tDYtDh7i+SpIw1uNfgMKc0HmpLYyqynuq8jX8DGaikrPxspwkBAAD4e77xAEiJl44DRF9neuk4FI91/+PUcJMPgCyuNavdfgEAAGije5NtYZcNAAXxTHiLZHdbvgAAbJDz7QDR95fOtwMAANBWHyXrYJcNAADABm3Ze1jPkkR5gx9GUT52w9gHPdqBLKivbwiDR59o7mymrfqWh9nPbhtCXVw5bv7LPUJiwL6uyxTbsu/wMHnaLEMP2KBHn52Uk9lUefv9PnwgK5YuWxVuGv9KqKyqUZ52yc1Phi37DLd2l/KgX555RcpzdtrbC8wyKcuNGVcTFi7+0kIvz111873uLZKkjHZ5t+1DbWlMRVhZ7x/7N5DmSsrKX3SaEAAAgL/n2w6AlHjpOED0daaXjkNxWZ1sB9MPgCytNavdegEAAEiDs+2yAaAgngn/zrIFAGCjnG8HiL6/dL4dAACAdHg92XfttAEAANigkkT5dX4YRfnYGb+/wWMdyIKLrhlr5kTo7DN2C6Eurhy3eGq3sONeQ1yTreiCq2438ICNGnHEmVmfS6X99w+fLV3mwwcyrqmpOdz75BuhsqpGedwhJ15h3S7lUbePezzlefv0pLnmmZTl7njo1bBmbaMFXx77ctlXoesuo91bJEkZq2tiWJgY7xZqS2Mqso7qubt/A2mupKy8/gfbDf4XpwkBAAD4W77tAEiJl44DRF9neuk4FJ9PknU0AQHIwlqz2m0XAACANGhJdpCdNgDk/dmDFssWAICNcr4dILU9JgAAAKTDfcm2sNsGAADgG763wz7/XpKoWOTHUZRvHfiL33qkAxn26ptzwlZ9R5g5m2mbXYeGpa93DaEurhy2/I2uYfDwvVyTrWjg/seHtfX1hh6wQW/Xvp+T2XTSb6/14QNZ8dJr80JlVY3yvMReR1q7S3lUp+1Hfv3cKBUNjU2h6onpZpqU5Z6cOMeCL8+de/mt7i2SpIw2stePQm1pTEXWTd36uP4zUMeyYfs4TQgAAMDf8k0HQEq8dBwg+jrTS8ehOL2R7F9MQQAyvNasdssFAAAgTdYk29FuGwDy8llwv2SrLFcAADbJ+XaA6PtM59sBAABIpwvstgEAANigjomKo/wwivKtHff9ucc5eeat2fN8CO3IVytXh52GHm3eRGjs9duHUBdXDls9s0sYfuBg12Mr6r7rQWHe/IWGHrBRp55/fU7m05uz3vHhAxn33oLPQ2VVjfK8s6++39pdysP67fOz8NnSZSnN3S9XrA633j/FbJOy3Ox3F1n45bEFHy8JnfqNdG+RJGW0W7qWhdrSmIqo12NdwlaJctd/uktUXOkkIQAAAH/LNx0AKfHScYDo60wvHYfi9Xiy75iEAGRwrVntdgsAAEAarfufmLey4waAvHoOvHWyxZYpAACb5Xw7QPS9pvPtAAAApFNLskPtuAEAANiA877doaziDT+Oonxqq74jQkNDo0c6eWLd3+Jnv77YB9GOnPK7682aCA0s3yc0zo2HUKdc1Tinc/jJET9yPbaijn2Ghyeen2zgARu1bPlXofNOB2R9Pg099DQfPpBxX61aG257YEqorKpRnldx1AXW71KeNuroc0JjU1NK83fBoi/DmHGTzDcpi91cPTl8sXy1BWAeO+6sK91XJEkZbdve+4bXY11CbWlMRdTgXoNd/2mupKx8hnOEAAAA/C3fcgCkxEvHAaKvM710HIrbpSYhABlca1a71QIAAJBmbyX7V7tuAMiLZ8D/lmyW5QkAQCTOtwNE32863w4AAEC6rU22i103AAAA39CxT8XefhxF+dZ7H3zscU6emPrG7BDrPyqsWVvvw2gHnnnpVTMmYpMf2i6EurhyVPPczuGXxw1wLbayK28aZ+ABmzRm7IM5mU/3PTbBhw9kVEtLCA+9MDNUVtUoz7vu7pdD110Osn6X8riLr7sz5Tk87e0FZpyU5cY/9WZoam6xEMxTs+a+554iScp4x/bcNdSWxlRE/abHjq799Nfy39sO+4GThAAAAPyFbzkAUuKl4wDR15leOg4cZBoCkKG1ZrXbLAAAABnwULIt7LwBIKfPf7dIdp9lCQBAZM63A0TfczrfDgAAQCYsTtbRzhsAAIBv6FBW/owfR1E+9ULN6x7l5Imrbxn/9d/k5Slv+jAK3OdfLA+JQYeZMRH6xbEDQqiLK0e11MbDGaft5lpsZUecdFFo9kPKwCY0NTeH/j8+KuvzabsfHRrq6xv8AYCMenXmh6GyqkYF0PG/u936XcrzOvYZHp5+cWrKs/jpSXPNOSnLTX5zvoVgHjvo2PPcVyRJGW3LsvJwf+dtQ21pTEXSQ122de1nYh+cqDjYKUIAAAD+wjccACnx0nGA6OtMLx0H1iTrZyICkIG1ZrXbLAAAABlyjp03AOT0+e/5liMAAClxvh0g+p7T+XYAAAAy5Y1k/2z3DQAAwHo6JEb07lBW3uwHUpQv3XzXwx7j5InRx5z79d/kgqtu92EUuJ/9+mLzJULx/sPCwld6hFAXVw5qqY2Hc87czbXYyvYYcVxYsXKVgQds0lMTpuRkRl1y/V0+fCCjPl6yLIwZNylUVtWoANpt5EnW8FIB1GP3g8P8BZ+kNI8bGptC1RPTzTopi40ZVxMWLv7SgjBPTZw6wz1FkpTxdum9d5hdGg+1pTEVQbNj8dCj91DXfrpLVNzuFCEAAAB/4RsOgJR46ThA9HWml44D63yY7PumIgBpXmtWu8UCAACQIc3Jhtp9A0BOnv1W/PleDABAdM63A0TfdzrfDgAAQCbdafcNAADAN6z7YRA/kKJ86dQLKj3CyQMNDY2h804HfP03GTDyOB9IARv38HNmS8SuuninEOriylEX/XZn12Er22aPQ8K8+QsNPGCz9jvqrKzPqK36jggLPl7iwwcyZtWahnDHQ6+GyqoaFUAX3/xk2LLPcOt4qUDac9QJYfWatSnN5eVfrQm3PTDFzJOy2Lq10Jq1DRaGeWqfg052T5EkZbzzuvcPtaUxFUk/6TnAdZ/mSsoqPnKCEAAAgL/w7QZASrx0HCD6OtNLx4G/qEn2jyYjAGlca1a7vQIAAJBBK5JtYwcOAFl97ts92TLLEACAlDnfDhB97+l8OwAAAJl2gh04AAAA6+nYe98OHRIVq/xIivKh8sNO9/gmD0x9Y/Z6f5cPFi7yoRSgDz9aHLrvepDZEqHtB/04rJ7ZJYS6uHLQReft7DpsZZ13OiC8+uYcAw/YrNl183Myp448+RIfPpAxLS0t4ZEJs0JlVY0KpNHHXWodLxVYJ/322pTn84JFX4Yx4yaZe1IWe3Ki50P56uGnJ7qfSJIyXiwxLEyIdw+1pTEVQdd06+u6z0Alvcq7OUUIAADAOr7dAEiJl44DRF9neuk48LeuMRkBSONas9qtFQAAgAyrTfb/2YUDQFae+f5nsnmWHwAAreJ8O0D0/afz7QAAAGRaY7KBduEAAACsp0Oi4kI/kKJ8qMfuB3t8kweuuXX8en+XO8Y/4UMpMM3NLWG/o84yVyL2xJ19QqiLKwddcv4ursFWtvUO+4UXX5lu4AGRnHzedTmZVZNee8uHD2TM5Dfnh8qqGhVI198zMfTY41BreakAu/eR51Oe0a+/vcDsk7Lc2/MWWSDmoabm5rDzsGPcTyRJGW/fXoPC3NJYqFW7b0q8a+jomk97JX3Kj3OCEAAAgHV8uwGQEi8dB4i+zvTSceDvHWY6ApCmtWa12yoAAABZ8Giyb9uJA0BGn/d+J9lTlh0AAK3mfDtA9D2o8+0AAABkw6fJOtmJAwAA8Fff32bUv5YkKhb5kRTlQ4s/XerxTY4d+Ivfrvc3OfT4C3woBWbMHQ+YJxE74CeDQqiLKwdddsHOrsFWtlXfEeGxZycZdkAkS79cHmL9R2V9Vg0YeVxoaWnxBwAyYv5HS0NlVY0KqJMu/JO1vFSgrVtLzq6bn/KsfnLiHPNPymI3jX8lfLF8tYViHrp93OPuJ5KkrFTZrU+oLY2pCNptu71d82mv/CEnCAEAAFjHNxsAKfHScYDo60wvHQf+3ppkfUxIANKw1qx2WwUAACBLzrETB4CMPu+90HIDAKBNnG8HiL4Hdb4dAACAbHkz2T/bjQMAAPBXJYnhx/qBFOVDE6fO8Ogmhxobm0LnnQ5Y728S33FUWL1mrQ+nQMx5Z34o7b+/eRKhrfqWh7nP9wyhLq4sd/mFO7sGW1nHPsPDfY9NMOyAyK69rTon82rs+Cd9+EBGLFuxJtxy35RQWVWjAmrgqFOs56UCbrfhx4avVq5OaV6vrW8Mdz46zQyUstj4p94MTc0tFox5Zt33K70GHup+IknKeNskhoZXY11CbWlM7byTtvFda9pLVCz/1h57/IMThAAAAPhmAyAlXjoOEH2d6aXjwIZ8kOx7piQAbVxrVrulAgAAkCXNyfa2GweAjDzrHZSsyXIDAKBNnG8HiL4Pdb4dAACAbLrRbhwAAID/NWrUd0rKKt72QynKdX+sesxjmxya8fY7G/y7PD9xmg+nANTXN4RBB5xolkTs3LN2DaEurix3xe93cv21oZvvetiwAyJrbGwK/fb5WdZnVbddDgwrVq7yBwDSrqmpOYx/6s1QWVWjAuqyW58OW/YdYT0vFXjH/eaKlOf2Z1+uDDeNf8UslLLY5BnzLRrz0JU3jXMvkSRlpaN67h5qS2Nq593VdTvXeybqM2xHBwgBAADwrQZASrx0HCD6OtNLx4GNWfdihS1MSgDasNasdjsFAAAgi5Ym62RHDgBpfc67ZbLPLDMAANrM+XaA6HtR59sBAADItsPsyAEAAPirH/auGO5HUpTrTrtwjEc2OXTbPY9u8O9y1iU3+XAKwIVX32GORKznbvuGL6Z3DaEurizVUhsP5521i+uvDV13230GHZCSh5+emJN5dc6lt/jwgYx4fuo7obKqRgXWISf8wXpeaieNf+SFlGf3rHc+MQulLDZmXE34eMkyC8c88/kXy0PnnQ5wL5EkZbyOycZ16RVqS2Nqx70V6xy2Lit3zae5kkTFuU4PAgAA4FsNgJR46ThA9HWml44Dm3KaSQlAG9aa1W6lAAAAZNmUZP9oVw4AaXnG+3+SvWJ5AQCQFs63A0TfjzrfDgAAQLatTpawKwcAAOAvtihJVEzzQynKZT/+yake2eTQsWds+IeudxhylA8nz7325pywVd8R5kjE7hqzfQh1cWWpprmdwym/3t2114auvc37rIDUlR92evZ/tLXP8DBv/kIfPpB2b89bFCqralRgXX/PxNBz4GHW9FI7qcvOo0PdewtSnuHPTakzE6Usduej00JDQ5MFZJ4565Kb3EskSVmpf+99wsxYPNSWxtSO27fXINd7mispK3/J0UEAAAB8owGQEi8dB4i+zvTScWBT1h34G2RaAtDKtaaXEAAAAJALV9uVA0BanvFWWlYAAKSN8+0A0fejzrcDAACQC+8k+3c7cwAAAL7WITF8iB9KUS6L7zgqNDb5scdc2X6fIzf6t2nND+aSHStXrQm7lP/CDInYXiP2Dk1zO4dQF1cWWvdZn3DCHq69NnTNreMNOiBlb856Jycz68Bf/NaHD6TdkqVfhRvHvxIqq2pUYJ16yT3W9FI7a+D+x4fVa9amNMcbGptC1RPTzUUpi7007V2LyDzz4UeLw1Z9R7iXSJKy0lk9dgq1pTG1437bfUfXeporKatY23HHUf/s9CAAAEBx840GQEq8dBwg+jrTS8eBzVmcrMTEBKAVa81qt1EAAAByxHfGANC257ujLScAADyrAMjRntT5dgAAAHLl4WRb2J0DAADwtQ6J8ol+LEW5rHbehx7X5MCiJZ9v8u9yw9gHfUh56uTzrjM7UmjKQ9uFUBdXFmqY3TkcefRA110buvY277ECWue4s67Mydx6+sWpPnwgrVataQhjH34tVFbVqAAbOOoU63qpHbbuWVSqvlyxOtx832SzUcpiH3z8hcVknjn2jD+4j0iSslKnsvLwbOceobY0pnbaw523da1not7lA50cBAAAKG6+zQBIiZeOA0RfZ3rpOBDFhGTfNjUBSHGt6WUEAAAA5MryZJ3tzgGgVc92uyb7ynICACCtnG8HiL4vdb4dAACAXPqV3TkAAABf+2Fi2GA/lKJc9sATL3pUkwOPPjtpk3+XkT/7jQ8pDz01YYq5kULH/WqPEOriykKrZ3YJBx++p+uuDV11872GHNAqSz77Imy9w35Zn1s7DDkqNDU3+wMAadPc3BIefH5mqKyqUQH2+xufCFv2GW5tL7XTqh99IeW5/s4Hn5qPUha746FXw5r6RovKPDK7bn7oaH0kScpS5b32DLWlMbXTZsfioXtiX9d6+jvfyUEAAIDi5tsMgJR46ThA9HWml44DUZ1tagKQ4lqz2u0TAACAHHo92T/aoQNASs91/ynZdMsIAIC0c74dIPre1Pl2AAAAcmltsoQdOgAAAF8rKSt/yQ+lKFedf+XtHtXkwO+u+OMm/y5b9R0RPlu6zAeVRxYt+Tz0HHCIuRGxLjuWh48ndw+hLq4Mt/yNrmHEgYNcd23oqpvvNeSAVrt8zD05mV1j7njAhw+k1YRX54XKqhoVaCN+foG1vdSen7PsPDrUvbcg5dn+0rR3zUgpiz37Sq1FZZ4Zfcy57iOSpKx1Q7eyUFsaUztt9LYDXedpriRR8bJTgwAAAMXNNxkAKfHScYDo60wvHQeiaky2i8kJQAprzWq3TwAAAHLsD3boAJDSc91rLR8AADLC+XaA6HtT59sBAADItXeS/ZtdOgAAAN/qmBi+hx9LUa464OhzPabJgaGHnrbZv03VQ8/5oPJEc3OLH99MsWsv3TGEurgy3JJXu4e9RuztmmtDV98y3pADWq2+viH03vOnWZ9dsf6jwtIvl/sDAGkzo/bjUFlVowLtqrETQmzHUdb3UjvvR6OOD6vXrE1pvjc1N4fqp980K6Us9s6Hn1lc5pEJk6a7h0iSsta2vfcNr8e6hNrSmNphl3fb3nWe5krKKtb+sO/Q7zo5CAAAULx8kwGQEi8dB4i+zvTScSAVC5J9z/QEIOJas9qtEwAAgBxrSTbULh0AIj3THfLneycAAOnnfDtA9P2p8+0AAADkg9vs0gEAAPhah0T5834wRbmo54BDQkuL893ZVF/fELbeYb/N/m0OP/H3Pqw8cdOdD5sXKbTT3kPC2rc7h1AXVwb7YGKPsPM+Q1xzraxjn+Fh7PgnDTigTaoffSEnM+yk317rwwfSZsGiL8MN4yaFyqoaFWiHn3atNb5UJJ3yu+tTnvMrVq0Ntz0wxbyUstSt908JXyX/3ZEf1n3/tceI49xDJElZ67htdg21pTG1wybEu7vGM1BJWcWeTg0CAAAUL99kAKTES8cBoq8zvXQcSNUDpicAEdea1W6bAAAA5IFPk/3QTh0ANvk8t0OyzywbAAAyxvl2gOh7VOfbAQAAyBcH26kDAADwrZJExc5+LEW5av6CTzyiyaIZb78T6e9S2n//8NXK1T6wHKud92GI9R9lVqTQU3eXhVAXVwab8eS2Ybs99nW9tbKt+o4I4x5+zoAD2mzIIafkZI6tW08CpMPyr9aE2x6YGiqralSgXX/PxLDdnkdY50tF1H2PTUh53n/w8VIzU8pij0yYZaGZR8aOf9L9Q5KUtbYsKw8Pd9421JbG1A7r13uI6zzdJSoudGoQAACgePkWAyAlXjoOEH2d6aXjQGscY4ICEGGtWe2WCQAAQJ54Mdl37NYBYIPPcr+d7HnLBQCAjHK+HSD6PtX5dgAAAPLFV8m62K0DAADwrZJExVN+MEW56MEnXvKIJov+VP1U5L/NE89P9oHl0Nr6+rDnqBPMiRQafeieIdTFlcEm3t87dNtpmOutlXXqNzI88MSLBhzQZlOnv52TOTbsp6f78IG0aGhoClVPTA+VVTUq4E668E/W+VKR1WXn0eGd9xemPPcnz5hvbkpZbPa7iyw488TqNWtDzwGHuIdIkrLWwO32CrNj8VBbGlM76+c9d3ONp7tEeY0TgwAAAMXLtxgAKfHScYDo60wvHQdaddQs2bamKACbWWtWu2UCAACQR860WweADT7LPccyAQAg45xvB4i+T3W+HQAAgHzyarL/Y8cOAABQ5Dr2Hr6DH0xRLjr38ls9nsmiU8+/PvLf5oRzrvaB5dA5l95iRqRQp74VYe7zPUOoiytD3X9b39CpX7nrrZVtvcN+4akJUww3IC1+fuqlOZll9z/+og8faLOWlhAef3l2qKyqUYG328gTrfWlImzPUSeENWvrU5z9LeHhF2aZnVKWurl6cli2Yo2FZ5644Krb3T8kSVnt8m7bh9rSmNpZN3Yrc32nuZKy8vofbDf4X5waBAAAKE6+wQBIiZeOA0RfZ3rpONBabyf7vyYpAJtYa1a7XQIAAJBHGpNtb8cOAOs9x+2brMEyAQAg45xvB4i+V3W+HQAAgHxzvh07AAAA3+qQKH/ej6Yo2w099DSPZrJorwNPivy32WaPQ0JDQ6MPLQcmTJoeOvYZbkak0G/P2jWEurgyVOXlOyavSddZa+u2y4Gh5tW3DDcgLT5a9Gno1G9k1mfZdj86NKytr/cHANps8pvzQ2VVjQq8313/sH2rVMSdfcnNKc//Vavrw+0PTjVDpSz14PMzQ0uLtWc+WPjJp2GrviPcPyRJWatrYliYHO8Waktjake9Fu8Stiwrd42nuR8mhg12YhAAAKA4+QYDICVeOg4QfZ3ppeNAW1xqkgKwibVmtVslAAAAeWZOsn+2aweAr5/hfjdZreUBAEBWON8OEH2/6nw7AAAA+WbdjyPvaNcOAABQ5Nb9UIgfTFG2K+2/f6ivb/B4JgvW1teHTtuPTOnv80LN6z64LPv8i+UhMejAhYY2AAAgAElEQVRw8yGFeg/YNyx/o2sIdXGluaa5ncPZZ+zmOmtDPQccEqbP9P82Aenz+2vG5mSeXT7mHh8+0Gaz310cKqtq1A7a97BzrfelIu/pF6emfB/4aMmycMO4SeaolKXemPuRBWieOPLki907JElZ7bCeu4fa0pjaWQN67e36TnMlZeUXOTEIAABQnHx7AZASLx0HiL7O9NJxoC2akw0wTQHYyFqz2q0SAACAPHS1XTsAfP0Mt9KyAAAga5xvB4i+X3W+HQAAgHz0XrJ/s3MHAAAoch0S5a/70RRluzdnvePRTBa8Masu5b/Nr8+71geXZUecdJG5kGJVN/YLoS6uNLfyrS7hsCMHusbaUP8fHxXene/Hi4H0Wb1mbdh2wE+yPs869RsZPln8uT8A0CYffvJFuGHcpFBZVaMC74rbnwtb77C/Nb9U5G2zxyHho0Wfpnw/eP3tBWaplKVuHP9KWLpslYVoHpg8bZZ7hyQp643r0ivUlsbUjjppm51d22mv/BWnBQEAAIqTby8AUuKl4wDR15leOg601fxk/26iArCBtWa12yQAAAB5qCXZPnbuABT589vBf74nAgCQHc63A0TfszrfDgAAQL660c4dAACgyJWUVYz2gynKdrff+7jHMllwx/gnUv7b9Nj94NDQ0OjDy5I773vKTEixvUfuHZrndg6hLq40tmhKt68/W9dY6xu436/CJ4s/N9iAtLrr/qdzMtOOOuVSHz7QJkuXrQq33DclVFbVqB108Al/sOaX9HUHHH1uaG5O/Z0eT0ycY55KWWr8U2+Gpmbv3skHg0ef6N4hScpq/XvvE2aVxkNtaUztpLFderu201xJorzh+9uM+lcnBgEAAIqPby4AUuKl4wDR15leOg6kw+0mKgAbWGtWu0UCAACQpz5K9j27dwCK9NntfyRbYDkAAJBVzrcDRN+3Ot8OAABAPhtq9w4AAFDMRo36TkmiYp4fTlE2++WZV3gkkwUnn3ddq/4+EyZN9+FlwfwFn4Suu4w2E1KoY5+KMPWR7UKoiyuNzX5229Bv0I9dY21o6KGnhS+WrTDYgLTbc9QJOZlrr7w204cPtNrK1fVh7MOvhcqqGrWDrv7ThOTe9SDrfkl/rfL2+1O+N6xZ2+jeIGWxqTM/sCjNA+Mefs59Q5KU9X7bfcdQWxpTO+mN0s5hK9d1Js4d7O3AIAAAQPHxzQVASrx0HCD6OtNLxwFrMAAytdasdnsEAAAgj91j9w5AkT67vdcyAAAg65ytAoi+b3W+HQAAgHy2JNkP7OABAACKWEmi4pd+NEXZrO/eP/NIJgv2PujXrfr7nHzedT68DGtoaAxDDj7ZPEix44/fI4S6uNLYhPGJ0G2nYa6vNnT4ib8Pa9bWG2xA2r00+c2czLWB+/0qtLS0+AMArdzrNIV7n3ojVFbVqJ10xKnXWfdLWq9O/UaG6TNrU75HfPzp8jBm3CSzVcpCNyT/rS3+fIXFaY7V1zeExKDD3DskSVktlhgWXox3D7WlMbWTBvUa7NpOcyVlFZc4LQgAAFB8fHMBkBIvHQeIvs700nEgXT5N9n2TFYC/WWtWuz0CAACQ53y3DECxPbcd7fYPAOAZBECe712dbwcAACDf3WcHDwAAUMQ67bHH/y1JVCzywynKZh9+tNgjmQxqbGoKsf6jWvW32WaPQ0JDQ6MPMYMuvu5OcyDFuu40LCya0i2EurjS1B+v2SFs2bfc9dWGTrtwzNfzFiATfnrChTmZbX+qfsqHD7RKS0tLePzl2aGyqkbtpOvufjn0HHCotb+kb7TT0KPDipWrUr5XvDrzQ/NVylJ3PTotNDR6bpVrl1Xe7b4hScp6o7YdGGpLY2onnbrNzq7rNFeSqJjitCAAAEDx8a0FQEq8dBwg+jrTS8eBdBpvsgLwN2vNardGAAAA8txnyf7bLh6AInlm+/+SLXH7BwDICefbAaLvX51vBwAAoBDsbxcPAABQxErKys/xwynKZvc9NsHjmAx65/2Fbfr7TJg03YeYIVNefzts2Xe4OZBi11/WP4S6uNJQw+zO4YzTdnNdtaGOfYaH6267z0ADMmb+gk9ysl7otsuBYcXKVf4AQKu8+Nq8UFlVo3bUL86+2fpf0kY74ZyrU75XtLS0hAefe8uMlbJUzfT3LVJzbPGnS8PWO+znviFJynpjuyZCbWlM7aC7u/R2Tae7REXj93bY59+dFgQAACguvrUASImXjgNEX2d66TiQbvuZrgD8ea1Z7bYIAABAARhnFw9AkTyz9QJaAIDccb4dIPr+1fl2AAAACsFnyf7bTh4AAKBIbdVr3//skKhY4cdTlK1OvaDS45gMeuSZmjb9fU489xofYgYsX7Ey7DDkKDMgxXbeZ0hY+3bnEOriamNfTO8aRv1kkOuqDa37EdwHnnjRQAMy6pzLbsnJjPvtH27z4QOtMn32wlBZVaN21PX3TAyJvY60B5C0yVqzP/5q1dpw2wNTzFopC40ZVxM++XS5xWqOHfebK9wzJElZb/veQ8LMWDzUlsZU4L0V6xw6lZW7rtNdYvgQpwUBAACKi28sAFLipeMA0deZXjoOpNunyb5vwgKQvB9Uuy0CAABQIEbayQPQzp/XVrjdAwDklPPtANH3sM63AwAAUCiq7OQBAACKWElZxbV+OEXZavcRv/QoJoMuq7y7TX+fbrscGFavWeuDTLNjz/iDf/+t6NmqRAh1cbWxOc/1DDvuNcQ11Ya22eOQMHnaLMMMyKgVK1eF7rselPUZ17HP8PDu/I/8AYCU1c3/NIwZVxMqq9SeOvGCO+wBJG22devWDz9anPK9472Fn5u1Upa6+/HXQ1NTs0VrDk2fWeueIUnKSWf12DHUlsbUDtqn1yDXdPq73ElBAACA4uIbC4CUeOk4QPR1ppeOA5lwtwkLQPJ+UO2WCAAAQIFYlOx7dvMAtNNntf+VbLHbPQBATjnfDhB9H+t8OwAAAIVkpN08AABAkfph36HdO5RVtPjhFGWjjn2Gh8+WLvMoJkOOOOmiNv+NHnmmxgeZRnfd/7R/+63owJ/uGUJdXG3ssT+VhS47lrum2tCO+/48vPP+QsMMyLjb7nk0J3Pu4F/+zocPpOyDj5eGG+6dFCqratTO6j/0WPsASZEaeuhpobGxKeV7yEvT3jVvpSw1ecZ8C9ccWzcr3TMkSdkulhgWXox3D7WlMRV4Z/bYyTWd5koSFVOdFAQAACguvq0ASImXjgNEX2d66TiQKSNMWYCiX2tWux0CAABQQO60mwegnT6rHec2DwCQc863A0TfxzrfDgAAQCFZlOx7dvQAAABFqkOi/Hk/nqJs9dizkzyKyZCdhx3T5r/P4Sf+3geZJu+8vzB03ukA/+5TrFO/8jDvxW1CqIurlbXUxsOYP+wYtuxb7ppqQ0MOPjl8+vkXhhmQcS0tLWG34cfmZNZNmDTdHwBI7WTBZyvCzdWTQ2VVjdpZp182zj5AUkpdWnlXyveRpqbmcO+Tb5i7Uha6YdyksOTzryxgc+ihJ192v5Ak5aQDtv1RqC2NqcC7t0sv13OaK0mUN/yw79DvOikIAABQPHxbAZASLx0HiL7O9NJxIFM+SfafJi1AUa81q90OAQAAKDDD7egBaGfPaYe5vQMA5AXn2wGi72WdbweA/5+9O4+uqjwU/l97p9/7u++df++6twhiTphEIQlhkMEioggCCaAoaG0dWtRSldaxVrHWoQ5FrQZFxalKkIgTVXEeCCKCKAhI4kRRVGSSQWRIcp7fwevyvbZVzknOfD6ftb5r9Z+uhrP3eZ69n/N0bwAg19ztjh4AAKBA7V1WeaSXpyhdnXfZTZZhUuCzbdtD624jWnx82vYYFTZ8utkH2kI7d+4Kg8ZM8J1vRr+5qG8I9cVqZp8taR9OHjfAudTCjj/9N2HrZ58bzIC0eOrFBRkZ6/pVnhaamqIOABC3DZu2hakzXw5V1bXKww4a5R5WUmK1KR8Ral9Z0qz5ZMqMl4y9Uhqa/vhrodF9X8Y0NDSG7oNPMmdIkjLSXe1LQl1RRDncG5HiECkd7nxOdiUVA+wUBAAAKBx+rQBIiIeOA8R/nemh40Aq3WKkBSjoa80aUyEAAAA55v1Y/+SuHoA8WaP951irTe8AAFnB/naA+O9n7W8HAAAgFx3hrh4AAKAQ9e//t63KKld7eYrSUZ/hp1iCSYHXltYn7RjdXTPbB9pCE6+Z6vvejEoHDA1bXu8QQn2xmtG7L3QOAyoGO5da2BU3/CE0edkwkEZjTp2YkfHujumP+vCBuG3euj3c8dAroaq6VnnYRdc/EFp3G+F+QFLClR9+Uti4aUvC88qytz82/kpp6pU3VrmYzaDrb5thvpAkZaQeJUPCG5HiUFcUUQ43tMuhzuck16q0YqKNggAAAIXDLxUACfHQcYD4rzM9dBxIpd3/59Z+RluAgr3WrDEVAgAAkIOudVcPQJ6s0VaZ1gEAsob97QDx38/a3w4AAEAuWhnrH93ZAwAAFKBWpRUXe3mK0tUHH621DJNkNbOeTdrxGXni+T7QFnj+pUVeRt7M7rulewj1xWpGT1WXhv36DXMetaB9ex4ZZjzyrEEMSKv6d1Zl5LqhU7+xYetnnzsAQFw+37Er3Pvoq6GqulZ52oCjz3JPIKnZnfyLK5o1vzz5Up0xWEpDN02fG9Zu3OqiNkPWb9wcIr1Gmy8kSRnpV/sdGOqKIsrhdh9D53LSe8ouQQAAgMLhlwqAhHjoOED815keOg6kWl2sfzDiAhTktWaNaRAAAIAc1Bir3J09ADm+PtvjyzkNAIDsYH87QPz3tPa3AwAAkKsuc2cPAABQgPYpH/m9VqUVu7w8Relo+sNPW4JJsiur7kna8WndbURYtXqND7UZ1m3YFEoPPcH3vBkNGTUoNK1oF0J9sRKoMfaZTbq8d2hTXuE8akH7H3xcmLdwqUEMSLtzL52ckXHv4mum+vCBuOzc1RhmzH49VFXXKk+78LqZX6wDuC+Q1JKqH0p8vXfHzoZw9yMLjcVSGrpv9muhqSnq4jZDfnHxDeYKSVJGipQOD88Xdwp1RRHlaPe37+JcTnoVW7/Tv//f2ikIAABQGPxKAZAQDx0HiP8600PHgXS4wIgLUJDXmjWmQAAAAHLUq7H+xt09ADm6Nvu3sV4znQMAZBX72wHiv6+1vx0AAIBc1RCrxN09AABAAWpVVnm/l6coHY2/YJIlmCT7ydlXJvUY/X6qZ60kKhqNhmN/+mvf8WbUultlWPToASHUFyuBNi7qEI49YaBzqIUdPGp8WLV6jUEMSLtNm7eG9n2OycC8OyK8+6cPHQBgjxqbouGR55aGqupa5XH9j/q5+wJJLW73de17qxK/xlyzfku46b65xmMpDb26/AMXuBlS9/aqL+7FzReSpEx09AGHhLqiiHK0ZUXFIVI63Lmc5L7XbUS5XYIAAACFwa8UAAnx0HGA+K8zPXQcSIcdsToadQEK7lrTg14AAADIZWe6uwcgR9dmzzGNAwBkHfvbAeK/r7W/HQAAgFw2P9Z33eEDAAAUmL27DT/Ey1OUjkoPPSFEo1FLMEk0cPQZST1GfYaf4hglaMofHvb9bmYTJvQPob5YCfTGE/uHAwcNcf60sGN/enHYsnWbAQzIiMl3PZiRse9HZ1zqwwf2qLEpGh59cXmoqq5VHnfBpBr3BZKS1ogTz4/NH00JzzkLl71vTJbS0M0zXgobN1sHy5Qjf3yBuUKSlLHual8S6ooiytGGdTnUeZzsulVOsEsQAACgMPiFAiAhHjoOEP91poeOA+nyXKy9jLwABXWtWWP6AwAAIIdtidXaHT4AObYuu0+sraZxAICsY387QPz3tva3AwAAkOt+4g4fAACg8Oy1d2nlCi9QUTpaVvee5ZckaWqKhkiv0Uk/RvMWLvXhxumNFe+EfXse6bvdjDr2Hh7WzO8YQn2x4mzm1PJQ3Gu486eFnXvp5NDQ0GgAAzKiobEx9Bzy44yMfy++/LoDAHyraDQannypLlRV1yrP6zfyTPcGkpLaDVPvb8a8E8LDzy41Lktp6P4nF39xrUf6Pf7sPPOEJClj9SgZEt6IFIe6oohysF/ud6DzOMm1Kq2YaYsgAABAYfALBUBCPHQcIP7rTA8dB9LpWCMvQEFda9aY+gAAAMhxD7nDByDH1mUfNX0DAGQl+9sB4r+3tb8dAACAXLcx1n+6ywcAACgwe5dWXuAFKkpHVXfMtPySJKtWr0nJMTrjwut8uHHY9vn20H/keN/rZjb5dweGUF+sONr2RrswYUJ/500LK+p1VLjvkWcMXkBG/fGpuRkZAwcc+TMvUAe+1e4x4ql5daGqulZ53vnXzHB/ICnpte0+Kixe9lbC889nn+8MUx+Yb3yW0tDrK1a76M2AhsbGUH74SeYKSVLG+tV+B4a6oohysPvad3EOJ781dggCAAAUBr9QACTEQ8cB4r/O9NBxIJ3WxPoXoy9AwVxr1pj6AAAAyAND3eUDkCNrsiNM2wAAWcv+doD472/tbwcAACAf3OkuHwAAoMB8r3zYPnuXVTR5gYpS3aiTL7D0kiTPv7QoJceo+MDRYfOWz3zAe3DWr2/0nW5mfYcMCTuXtQuhvlh76O3nO4eBFYc7b1pYt0EnhteW1hu4gIwbeeL5GRkH75n5hA8f+EbRaAjPzH8rVFXXqgDqU3m6ewRJKengUePD9h07E56HVq7eYHyW0tCUGS+FTVu2u/jNgElTppsnJEkZK1I6PLxQ3CnUFUWUYy2JtAv7llU4j5Nd6dD2dgkCAADkP79OACTEQ8cB4r/O9NBxIN1+Z/QFKJhrzRrTHgAAAHngnVj/4E4fgCxfj/1fsd4zbQMAZC372wHiv8e1vx0AAIB8EI11kDt9AACAAtOqtPJFL1BRqmvbfVTYvOUzyy9JcHv1H1N2nO6ume0D/haznprr+9yCnr2vNIT6Yu2hmVPLQ/sDvSitpVX86NzwybqNBi4g45aueDcj4+B+3z82bPvci9OBb/bCwndCVXWtCqDzrrnPPYKklDbxmqnNmovmvPqucVpKQzOfWhKiUde/6fbRmvVf/DZmnpAkZarj9u8f6ooiysEO73qYczjJtSqrOMkOQQAAgPzn1wmAhHjoOED815keOg6kW0OsLkZggIK41qwx7QEAAJAnfulOH4AsX4/9tekaACCr2d8OEP89rv3tAAAA5ItFsf7G3T4AAEAB2buk4ideoKJ09Ngz8yy9JMHul9Sm6hgNOe4sH/A3WLV6Teh00Fjf5WZ27AkDQ6gv1re0Y1m7MPGCfs6XJHT6r64N23fsNHABWeHMi67PyFh42fV3+fCBbzTn1XdDVXWtCqTeFePdJ0hKaa27jQjPzV2U8HzU2NQU7pv9mrFaSkNL3/rIRXAGnPTzK8wTkqSMdl/7LqGuKKIc6+zOfZy/ya608g47BAEAAPKfXyYAEuKh4wDxX2d66DiQCc8YgQEK4lqzxpQHAABAntgWq627fQCydC12ny/nKgAAspf97QDx3+fa3w4AAEA+OcXdPgAAQAGJlI/+l1alFZ97iYpS3dmX3GjZJQlS/RLGN99a6UP+M7t2NYQjfnC273Ez27dHRXjn+c4h1BfrG3o79vkMrDjc+dLC2nYfFe6471GDFpA11m3YFCK9Rqd9PNynfGRYtXqNAwD8VfMWrwxV1bUqkM664h73CpLSUvnhJ4VPN21NeF7auHlbmDLjJWO2lOJuqZkXNm/d7mI4zZ6bu8gcIUnKaH1KBoflRZFQp5zqDx1KnL9JrlVZ5Vt2CAIAAOQ/v0wAJMRDxwHiv8700HEgU44yCgPk/bVmjekOAACAPHKfu30AsnQt9iHTNABA1rO/HSD++1z72wEAAMgnG2L9f+74AQAACkirssr7vURFqa7boBNDNBq19NJChx1zZkqP00VX3+ZD/jO//t3tvsMt6LKL+4ZQX6xv6P7bykP7AyucKy2s9NATwvxFywxYQFa59pb7MjImnvyL3/rwgb9q/pI/harqWhVIN06bE7ofcYr7BUlp66fn/65Z89Piug+N21IaevjZpS6I06ypKRp6DxtnjpAkZbQrO/UIdUUR5VCvFbUL+zh3k17bHkf8lx2CAAAA+c0vEwAJ8dBxgPivMz10HMiU92P9o5EYIK+vNWtMdwAAAOSZQ9zxA5Bl67CHmZ4BAHKC/e0A8d/r2t8OAABAvrnJHT8AAEAB+V5J5QgvUFE6em1pvWWXFup00NiUHqP9vn9s2Pb5dh/0l56tfTW07jbC97eZlQ4YGra83iGE+mL9WVsXtw9nnNHfeZKEhhx3Vlj98VoDFpBVGhoaQ/nhJ2VkXHz51WUOAPAXXnljVaiqrlUB9dOJt7lfkJT2Hpo9p1nz1Kznlxm7pTS0/J01LozT7Mbb7zc/SJIyWsfSYeGVSPtQVxRRDjWg6yDnb7IrrTjKDkEAAID85lcJgIR46DhA/NeZHjoOZNKlRmKAvL7WrDHVAQAAkGd2P/jqb931A5Ala7B/H6vO9AwAkBPsbweI/37X/nYAAADyTWOsMnf9AAAABaJz59F/v3dp5TovUVGqu/z3d1t2aYFNm7em5Tjd+8CTPuyYj9asD10GHO+724Luv608hPpi/VlLZh8Q+g0Z4hxJQudeOjns2tVgwAKyzgOPPZ+RcfGQ0aeHaDTqAABfM+/1laGqulYF1A33vBD2H/Aj9wyS0t5+3z82rP54bcJz1dZtO8JtM182hksp7tb7Xw6ffb7TBXIard+4ORT1OsocIUnKaKd2PijUFUWUQ53Zua9zN8m1Kqu83g5BAACA/OZXCYCEeOg4QPzXmR46DmTS9lhtjcYAeXutWWOqAwAAIA+Nd9cPQJaswf7ctAwAkDPsbweI/37X/nYAAADy0Qvu+gEAAApIq9KKKV6iolTXr/I0Sy4tsHTFu2k5TgOOOj1Eo9GC/qwbGhvDyBPP971tQUOOHBSaVrQLob5YXxatKw63X98z7NujwjnSwiK9RofpDz9tYgCy1hE/ODsj42P1Q8ZG4OtqF70bqqprVWD96Kzr3TdIBViXgSdkxd8x5tSJzVpbrP/TWmO4lIZm165wkZxmp513jXlKkpTR2pRVhFnt9g91RRHlSFM7lDp3k11p5SK7AwEAAPKbXyQAEuKh4wDxX2d66DiQadOMxgB5e61ZY5oDAAAgD62L9S/u/AHI8Prrv8Vab1oGAMgZ9rcDxH/Pa387AAAA+WqEO38AAIAC0bps+GAvUVE6WvH2nyy5NNPs515O23F6+dVlBf1ZX1l1j+9rS17MVl4RXn+sSwj1xfqydQs6huNOGOj8SEI9h/w4LF72lkkByFqvLqnLyPjYZcDxYfuOnQ4A8JU5r74bqqprVWBNuvOZ0K73GPcOUgE29ISLwpDjL8iKv2XqtFnNmruefKnOWC6lofc+8OyfdJq3cKl5SpKU8QZ1PSysKIqEOuVECyMdQpuyCuduMiutaPyPjhX/ZIcgAABA/vKLBEBCPHQcIP7rTA8dBzItGquPERkgL681a0xzAAAA5Kmr3PkDkOH11+tNxwAAOcX+doD473ntbwcAACBfvRPrH9z9AwAAFIB27Qb/w96llVu8SEWp7tpb7rPk0ky3TZuVtuM07pyrCvZznjN/cWhTPsL3tQWd9fPvh1BfrC97oaYklB481LmRhH7ws0vCps1bTQhAVjvl3KszMkb+9sZ7fPjAV15Y+E6oqq5VAXbkKZe5d5AKtEOOPidcd/dzoevAkzL+t0R6jQ71776f8Py1Y2dDuPvhBcZzKcXdFfue7drV6KI5TaLRaOg/cry5SpKU8W7q0C3UFUWUI/UtOdx5m+Rad6s83A5BAACA/OUXCYCEeOg4QPzXmR46DmSDebH2MioD5N21Zo0pDgAAgDy1M1Y7d/8AZGjtNRJrh+kYACCn2N8OEP99r/3tAAAA5LMJ7v4BAAAKRKuyyvu9REWp7rBjzrTc0ky/ufaOtB2ntt1HhY/WrC+4z3jdhk2h7LATfFdbUKc+w8PaVzqGUF9c8G1f2j5c+Mt+u1/O5dxoYfuUjwyTpkwPTU1RkwGQ1T74aO0X11HpHicL9doN+EvRaDQ883J9qKquVQF2xZTHYnPCke4hpAKtd8X4L8aCidc/mBVjwZDjzgoNjY0Jz2Xvf/ypMV1KQ7WL3nPxnEa3TZtlrpIkZbySkqHh9aJ2oa4oohzop/v3c94mvYrf2B0IAACQv/waAZAQDx0HiP8600PHAddwAKTqWrPG9AYAAEAem+HuH4AMrb0+aBoGAMg59kYBxH/fa387AAAA+WxjrP+wAgAAAFAA9i6t+KEXqCgd/emDjy25NMP4Cyal9ThdPXlaQX2+TU3RMPa0i31HW9gt1/YMob644FvxzP7h0MrDnRNJqPzwk8L815abBICccMmkOzIyVp523jU+fCBEo9Hw9Lz6UFVdqwJt0HHnu4eQCrjSQSd/NR6ceM4NWfE3XX/bjGbNaXNefde4LqW4ydPnhrUbtrqITpPNWz4L7Xofbb6SJGW8czr3DnVFEeVAN3Usc84mv6fsDgQAAMhffo0ASIiHjgPEf53poeNAtngv1j8YmQHy6lqzxvQGAABAnutnBQCANK+79okVNQUDAOQc+9sB4r/3tb8dAACAfHedFQAAAIAC0Lrz6H/fu7SywUtUlOpuvvshyy3NMHrchWk9Tl0POT7s2LmzYD7f3S/59f1sWf2GDAk7l7ULob64YGta0S7cfn3PsG+PCudEEjrmlIvC2vUbTQBATtj62eeh00FjMzJeLly8wgGAAtfYFA2za1eEqupaFWgTr38wtO42wn2EVMB16Hfs18aFw8ael/G/ad+eR4Y331qZ8LzW0NgUpj26yPgupbgZs18P0ajnAaXLhIm/N19JkjJe27KK8Gxxp1BXFFGWN7e4g3M22ZVWbv7O6NF/Y25MbcEAACAASURBVIcgAABAfvJLBEBCPHQcIP7rTA8dB7LJ2UZmgLy61qwxtQEAAJDnXo61l1UAANK05rpXrAWmXwCAnGR/O0D897/2twMAAJDvdr88ub1VAAAAgALQqrTyRS9SUaqrPOE8yy3N0H/k+LQfq5pZzxbEZzv/teWhbfdRvp8t7LkZpSHUFxds78/dL4w69jDnQjJe6Bf7PlbdMdNLfYGcctu0WRkZMweP/YUPHwrcrobGMOv5ZaGqulYFXN8RZ7iXkAq8NuUjw43T5nw1Lky685mw/8HHZ/zvGjRmQmiIzVWJWrtxa7j5vrnGeCnFLa5b7YI6TV5dUme+kiRlRUcfcEioK4ooByorOcI5m+Radx15gN2BAAAA+ckvEQAJ8dBxgPivMz10HMgmn8b6d6MzQN5ca9aY2gAAACgAR1oFACBNa67HmHYBAHKW/e0A8d//2t8OAABAIbjPKgAAAEABaFVaebaXqCj1L3gdET5Zt9FyS4I69Rub9mN18Kjxoakpmtef67oNm0L54Sf5brawE398SAj1xQXbzKnloWPv4c6FJNR98EnhldffNOgDOaWxqSn0HjYuI+Pm/X98zgGAArZjZ0OY+dSSUFVdqwJuwmV3u5eQ9EWT7nrma+PD+dfMCG3KR2b+75oyvVnz3MKl7xvnpRQ3ZcZLYfPW7S6s0+SwY840X0mSsqJ7O5SEuqKIsrzj9z/Y+ZrsSip+YncgAABAfvIrBEBCPHQcIP7rTA8dB7LN5UZngLy51qwxrQEAAFAA6mP9rZUAAFK83vo3sVaYdgEAcpb97QDx3wPb3w4AAEAh2P3y5G5WAgAAAPJc67Lh7bxEReno7prZllsS8Pn2HRk7VrOfezlvP9empmgYe9rFvpMtrKhnRVj54n4h1BcXXOsWdAwnjxvgPEhSY06dGNau/9SgD+Scx5+dl5Fxs2TgD8OOnTsdAChQ2z7fGaY//lqoqq5VAXfDPS+ELgNPcD8h6Ysuu/mxvxgnjjvjmoz/XW27jwpL3nwn8d1q0RAefHqJ8V5KcX98fpmL6zTZ/duY+UqSlA316Xp4WF4UCXXK6q7s1MP5muxKK2+3OxAAACA/+RUCICEeOg4Q/3Wmh44D2eazWP9lhAbIi2vNGtMaAAAABeJEKwEApHi9dZzpFgAgp9nfDhD/PbD97QAAABSK2VYCAAAACkCr0op3vUhFqW7MqRMttSRg5fsfZexYHfGDs/P2c7168jTfxyT020v6hlBfXHA9M700lA04wjmQpJdrT5oyPTQ1RQ34QE4addIvMzJ+/u7mah8+FKjNW7eHe2YtDFXVtSrwjj3jGvcUkr7qwmvv/4tx4sZpc0K/kWdm/G877Jgzw65dDc2a8265f54xX0px77y/zkV2Gmz97PPQse8Yc5YkKSu6qmOPUFcUURb3x3adnavJb7mdgQAAAPnJrxAACfHQcYD4rzM9dBzIRjcaoQHy4lqzxpQGAABAgVgd639ZDQAgRWut/0+s9023AAA5zf52gPjvg+1vBwAAoJAMsBoAAACQ5/YurbzDS1SU6tr2GBU2btpiqSVOC15/M6PHa878xXn3mT43d1FoUz7C97GFlR48NGxZ3D6E+uKCafNrHcK5Zx/k+CepnkN+HBYuXmGgB3LWkuVvZ2T83LfnkeGTdRsdAChAGzZtC3c+9Eqoqq5VgXfFlMdi88FR7iskfdVZV9zzV8eLq257InTod2zG/75rbprWrLlv2dsfG/elFHdH7Ppyx84GF9tpcN5lN5mzJElZUafSoWFBcftQVxRRlrY8Uhw6lA53via1iqa2JZX/ancgAABA/vELBEBCPHQcIP7rTA8dB7LRrljFRmmAnL/WrDGlAQAAUEAmWA0AIEVrreeYZgEAcp797QDx3wfb3w4AAEAheSXWXlYEAAAA8lir0uE/8hIVpaO7a2ZbaonT7OfmZ/RYHT3uorz6PD9csy50GXC872ESevD28hDqiwum52tKQvnAoY59kvrRGZeGjZu2GOSBnDb+gkkZGUNP/9W1PnwoQB9+sincev/Loaq6VgoDx5zjvkLS1/rphbd+45hxzpXTQptuIzL697XtPiosXvZWs+bAR19cbuyXUtyLC99xwZ0Gy+tXmrMkSVnTGfv1DXVFEWVxFV0GOleTXOtulYfbHQgAAJB//AIBkBAPHQeI/zrTQ8eBbPUHozRAzl9r1pjOAAAAKCDrYv2zFQEAkrzO+i+x1ptmAQBynv3tAPHfC9vfDgAAQKGpsCIAAACQx75XPmwfL1FROqr40bmWWeI0/eGnM368Fi5ekRefZUNDYxhx4vm+g8n4Dh9zWIjWFYdQn/9tWdw+nHv2QY57El+iPWnK9NDUFDXAAznt40/Wh7Y9RmVkLH196VsOABSYlas3hCkzXgpV1bVSOOfKae4tJP1FJ559w7eOHUedekXG/8aDR40PO3buTHge3LZ9Z7j9gfnmACmFTZ5eGz5et8WFdxoMO/4c85YkKSvaJ9aTxfuFuqKIsrQL9uvtXE1+v7Y7EAAAIP/49QEgIR46DhD/daaHjgPZqilWFyM1QE5fa9aYzgAAACgwF1sRACDJ66yXml4BAPKC/e0A8d8L298OAABAoXkj1netCgAAAOSxvcsqVnqJilJd624jwnurPrTUEoeb734o48frpJ9fkRef5YVX3er7l4TalFeEJU8cEEJ9cd73Qk1J6HHoEY57kuox+OSw4PU3DexAXrjihj9kZCwd/sNzffhQYN58d0246b65oaq6Vgo33PtiKDn0JPcXkv6iMT+7ao/jR8+hp2X877yy6p5mzYfvfbDePCCluOmPvxaamqIuwFNsxiPPmrckSVnTkV0OCXVFEWVp09p3dZ4muValFU/YGQgAAJB//PoAkBAPHQeI/zrTQ8eBbDbTSA2Q09eaNaYyAAAACszmWP9uVQCAJK2x/kesLaZXAIC8YH87QPz3w/a3AwAAUIjGWBUAAADIY3uXVd7lRSpKR7+7udoySxyuqro348eqdbcR4c23Vub05zjrqbm+d0nqnLO/H0J9cV63+bUO4dyzD4qd+453sjpxwuXh001bDepAXvh8+45wwME/yMh4+tDsOQ4AFJB5i1eGqupa6at++Ivr3F9I+qtVnnTJHseQy25+NER6HZ3Rv7Nt91Hh9aVvNWtefGb+W+YCKcUtWv6Bi/AU275jZ9j/4OPMXZKkrOmeDl1DXVFEWdhrRe3CPqUVztMk1qqs4tPvfOfi79odCAAAkF/8+gCQEA8dB4j/OtNDx4FsFo1VYrQGyNlrzRpTGQAAAAXoEqsCACRpjfUK0yoAQN6wvx0g/vth+9sBAAAoRG/G8hxZAACAfNWqpPIEL1JROuo9bFyIRqOWWvbg/Mtvzorj9YOfXZKzn+F7qz4MnfqN9b1LQp36DA9rF3QMob44b3t6elkoHzjU8U5SkV6jw9Rps4z3QF65u2Z2RsbUboNODA0NjQ4AFIDGpqbw1Et1oaq6Vvqqq257InZ9fbT7DEl/tUHHnhfXWHLKr6Zk/G8dcOTPws6duxKeH3fuagx3P7zAnCClsCkzXgqbtm53QZ5iF151q7lLkpQ19el6eFheVBzqiiLKwvp3HeQ8TXL/VVrR2e5AAACA/OKXB4CEeOg4QPzXmR46DmS7+43WADl7rVljGgMAAKAAbYr1b1YGAGjh+up/xNpiWgUAyBv2twPEf09sfzsAAACF6hgrAwAAAHnqP7sOL/ISFaWrV15/0zLLHpx67tVZc7xefPn1nPv8tu/YGQaNmeD7lqRuu75XCPXFednaBR3DuFMHOM5J7JDRp4c331ppIAfySlNTNHx/5E8zMq5ed+sMBwAKwI6dDeHBZ94IVdW10tca/IML3GdI+sb6jTwz7vHk0LHnZfzvvfz3dzdrnnz/40/NCVKKm/X8MhflKbZ0xbvmLklSVnVlpx6hriiiLGx8537O0STXqqziJLsDAQAA8otfHgAS4qHjAPFfZ3roOJDtorFKjNgAOXmtWWMaAwAAoED92soAAC1cX73cdAoAkFfsbweI/57Y/nYAAAAK1fJY37U6AAAAkKdalVV84EUqSkfnXjrZMssejD3t4qw5XoPH/iI0NUVz6vP72a+u9V1LUgcPGxwa3mwXQn1xXhWtKw4zp5aHAw4a5jgnqTblI8Ll198Vdu1qMIgDeefpOQszMrYW9ToqrNuwyQGAPLd56/Yw7dFXQ1V1rfS1zrlyWmjdbYT7DUnfWPngcXGPKZPufCbs1//4jP69+5SPDIveqGvWfPns/LfMDVKKe+tPa12cp9igMRPMX5KkrKlj6bCwoLh9qCuKKMu6qUM352iSa1VWcZudgQAAAPnFrw4ACfHQcYD4rzM9dBzIBfcbsQFy8lqzxhQGAABAgdr9AK1/szoAQDPXVv891mbTKQBAXrG/HSD++2L72wEAAChkx1gdAAAAyFN7l1bM8iIVpaPO/Y8LO3butMzyLYYef3ZWHbMHHns+Zz67KX942Pcsib1wf0kI9cV51araTmHMDwc6vkmsx+CTw7yFSw3eQN46etxFGRlfJ0z8vQ8f8twn67eGOx6cH6qqa6Wvdf0fng8HHHKC+w1Je1hnPT6hseXcq6aH1t1GZPRvPnjU+LBz566E58yduxrCXQ8vMEdIKWz3demOnQ0u0lPo9uo/mr8kSVnV6Z37hbqiiLKsOcUdnZ9JrlVZxVI7AwEAAPKLXx0AEuKh4wDxX2d66DiQC6Kxuhq1AXLuWrPGFAYAAEAB+7XVAQCaubZ6mWkUACDv2N8OEP99sf3tAAAAFLLlsb5rhQAAACAP7V1WeYkXqShdPfr0S5ZZvsWAI3+WVcer++CTwvYdO7P+c5szf3Fo232U71iSOnncgBDqi/OmphXtwr039Qgdeg93fJPYuHOuCp9u2mrgBvL3l7H6lRkbY99Y8Y4DAHnsvQ/WhykzXgpV1bXSX3TUab91vyFpj0V6HZ34+HLqFRn/u6+qurdZc+fK1RvMEVKKe37B2y7UU2jDp5vDvj2PNIdJkrKmfcoqwlPt9gt1RRFlWSUlQ52jSa2iKVI++l/sDgQAAMgffnUASIiHjgPEf53poeNArqgxagPk3LVmjekLAACAArYp1r9ZIQAgwXXVf431qWkUACDv2N8OEP+9sf3tAAAAFLqjrRAAAADkodbdKkZ6iYrS1YkTLrfE8i16HfHjrDtmN931YFZ/Zu9/+EnoMuB4368kVdSzIrz34n4h1BfnRSue2T8MHX2YY5vEOvUbG+594EkDNpD3Jkz8fUbG2ZEnnu/Dhzy2uO7DMHn63FBVXSv9RRN//2BoUz7SfYekPda624hw47Q5CY0xN9zzQug+eFxG/+62PUaF5fUrmzWHPj2v3lwhpbDJ02vDmvVbXLCn0LhzrjKHSZKyqoouA0NdUURZ1pgDDnZ+JrnvlQ4/zO5AAACA/OEXB4CEeOg4QPzXmR46DuSKplidjdwAOXWtWWP6AgAAoMBdZIUAgATXVX9t+gQAyEv2twPEf29sfzsAAACF7o1Ye1klAAAAyDP/WVK5r5eoKJ0vTt3w6WbLLN+gy4Djs+6Yde5/XPh009as/Lw+27Y9DBx9hu9WErv60j4h1BfnfA1vtguTrzkw7NujwnFNYiNPPD+8/+EnBmsg761ZuyHs2/PIjIy1jz79kgMAeaixqSk8M/+tUFVdK/3Vbpw2J/Qcepr7DklxN+nOZxIeay69aVYo6nVURv/uQWMmhIaGxoTn0h07G8KdD71izpBS2IwnXg/RaNTFe4o8M2eh+UuSlHXd26Ek1BVFlEVd0qmnczPJtSqtmGh3IAAAQP7wiwNAQjx0HCD+60wPHQdyyZ1GboCcutasMXUBAABQ4NbH+kerBADEuab6j7HWmT4BAPKS/e0A8d8f298OAAAAIQy1SgAAAJB/9mpVVvGpF6koXd1x36OWWL5BpNforDxm519+c9Z9Vrtf7nnquVf7TiWx8oFDw7Y32oVQX5zTLfxjl3DwsMGOaRJr231UmDRlemhsajJQAwXhihv+kJHxtsfgk0NDY6MDAHnm8x27woPPvBGqqmulb+yEs37v3kNSQl0+5bFmjTcnn1eV8b/9prsebNacunL1BnOGlOKWvf2xC/gU2X2/323QieYwSVJW1afr4WF5USTUKWuqad/FuZnkWpVVPG5rIAAAQP7wiwNAQjx0HCD+60wPHQdyya5YbY3eADlzrVlj6gIAAIBwulUCAOJcU/25aRMAIG/Z3w4Q//2x/e0AAAAQwhyrBAAAAHmoVVnF816konR12DFnWmL5K5qaoqF1txFZeczalI8IC15/M6s+r+tvm+H7lOQeur08hPrinG3L6x3CBecdFDtfKxzPJNZ72Lis+/4DpNJn27aHzv2Py8iYW3XHTAcA8sy6Tz8Ldz+yIFRV10rf2BVTHguRnqPdf0hKqIm/f7DZ487Bo8/K6N/ervfRYeX7HzVrbn3qpTpzh5TCps58OWzfscuFfIpc/vu7zWGSpKxrUsfuoa4ooixpSaRd2KfM793JrFVZxYbvfOc7e9kdCAAAkB/82gCQEA8dB4j/OtNDx4Fcc53RGyBnrjVrTFsAAAAQ3o/1d1YKANjDeurfxVpl2gQAyFv2twPEf49sfzsAAAD8t75WCgAAAPJMq9KK67xIRens1SV1llj+zNbPPs/qY3bI6NNDQ0NjVnxWL8x7LexTPtJ3KYlVHnNYiNYVh1Cfmz09vSx0P/QIxzLJnXHhdeGzbdsN0EBBmTptVkbG3Ha9jw4bN21xACCPvL1qXZgy46VQVV0rfWv9j/q5+w9JCXfe1dObPe5cPfWp0LHfsRn9+0ePuzBEo9GE59ftOxrCHQ++Yv6QUtjzC952MZ+qe4SVH5jDJElZ1wGlQ8OiSLtQVxRRljSg6yDnZrIrHdre7kAAAID84NcGgIR46DhA/NeZHjoO5Jptsf6PERwgJ641a0xbAAAA8IXjrRQAsIf11BNNlwAAec3+doD475HtbwcAAID/9kcrBQAAAHmmVUnlCV6ionR25kXXW2L5M+s2bMr643b9bTMy/jm9s3J16HTQWN+jJNamvCIsmX1ACPXFOdd7L+4Xjj1hoOOY5Loecnx44vn5Bmag4DQ0NoYDh/4kI2PveZfd5ABAHlm0/IMweXptqKqWvr3xE29zDyKpWU247O4WjT9nXXFPaN1tREb/DdMeeLJZ8+x7qzeYQ6QUtvs6ds36LS7qU6TyhPPMY5KkrOu8/fqEuqKIsqTxnfs5L5Pc90pHjLU7EAAAID/4pQEgIR46DhD/daaHjgO56NdGcICcuNasMWUBAADAF96M9V2rBQB8w1rqXrGWmy4BAPKa/e0A8d8n298OAAAA/y0aq9RqAQAAQB75Xsnwvl6ionQW6TU6bNzkpYz/05q1G7L+uLXtMSosefOdjH1G6zZsCr2HjfMdSnLnn3NQCPXFOdX2pe3DpMt7h6KeFY5hkjtu/CVh7fqNBmWgID3yZG1Gxt7W3UaEt1d+4ABAHtjV0Bger30zVFXXSnvs6qlPhQ59x7oPkdSsTrvwlhaPQ5U/viSj/4ZOB439Yk20OZ6cu8JcIqWw+59cHKJR1/epMO2BJ81jkqTs279ROjzMKe4Y6ooiyoJu7FjuvExyrUorr7U7EAAAID/4pQEgIR46DhD/daaHjgO5aPcm3P9tFAfI+mvNGlMWAAAAfKXCagEA37CWOso0CQCQ9+xvB4j/Ptn+dgAAAPi/7rFaAAAAkEf2KR/5PS9RUbq75Z6HLbH8D6s/XpsTx63/yPHh8+070v75bN+xM1T86FzfnSTXud+wsOHVDiHUF+dMT08vCwcOGuL4JftF1v3GhnsfeDJEvS0XKGBH/ODsjIzBx5/+Gx8+5IFPt3weqh9bFKqqa6W4OuToc9yLSGp2J55zY4vHoevveT6UHHZyRv8dJ//iimauFe4Kdzw433wipbDl73zsIj8Ftny2LbTrfbS5TJKUdZ2w//dDXVFEWdCzxZ2ck8mutGKO3YEAAAD5wS8NAAnx0HGA+K8zPXQcyFUTjOIAWX+tWWO6AgAAgK/MtVoAwDespb5smgQAyHv2twPEf59sfzsAAAD8Xw2x2loxAAAAyB977V1auc2LVJTO+lacGqLRqGWWL61avSZnjt0vr7g5rZ9NY1PTFy/Y9b1Jfnf8vmcI9cU50UfzOoVxpw5w3FLQmFMnhg8+WmsgBgravIVLMzYO176yxAGAHPfe6g3h1vtfDlXVtVJcnfqrW9yLSGpRx51xTVLGo4uueyC06T4qo/+WPz41t1nz79ur1plTpBQ2debLYfuOXS72U+D0X11rLpMkZV2tY81qt3+oK4oow62I1bl0mPMymZVWbvtO//5/a3sgAABA7vMrA0BCPHQcIP7rTA8dB3LVylh/YyQHyOprzRrTFQAAAHxNLysGAPzZOmof0yMAQEGwvx0g/ntl+9sBAADg635nxQAAACCPtCqrXOZFKkp3ta8sscTypZXvf5RTx276w0+n7bOZeM1U35cUNGD44NDwZrsQ6ouzut1/4+3X9wwdeg933JJcu95Hh8l3PhCamqIGYaDg/eiMSzMyFh8y+vQQjRqHIVft/v7OW7wyVFXXSnH321seD8W9j3FPIqlFHXnK5Ukbl44Zf1VG/y1dBhwf1m/c3Ky5eHbtCnOLlMJeWPC2i/4UmLtgiblMkpSVDekyMNQVRZQFjepyiHMyybXuOvIAuwMBAAByn18ZABLioeMA8V9neug4kMtGGckBsvpas8ZUBQAAAF9TbcUAAOuoAAAFyf52gPjvle1vBwAAgK/b/TKTf7ZqAAAAkCf2Lq2Y5SUqSnennHu1JZYvvb3yg5w6dpFeo8OSN99J+edy672P+K6kqBdqSkKoL87qXn6oaxgwfLDjlYJGnfTLsPL9jwy+ADHvrFwd2pSPyMh4POORZx0AyFHbtu8KDz3zRqiqrpXi7sZpc8JBR05wTyKpxQ078eKkjU033Pti6H7EKRn990yY+Ptmz8dTH5hvjpFS1OTptWHthq0u/pMsGo2GPsNPMZ9JkrKy2zuUhLqiiDLcBfsd6HxMcq3KKk60OxAAACD3+ZUBICEeOg4Q/3Wmh44DuWyOkRwgq681vQwWAAAAvq4hVhurBgB8uYa6z5dzAwAA+c/+doD475ftbwcAAIC/dLpVAwAAgDzRqrTiOi9RUbpr231UWLN2gyWWmPp3VuXc8es55MfhozXrU/aZPP7svNCmfITvSgr6yakHx0664qxt7YKO4cwz+4fW3RyrZNex75jwh/tnf/HiVgD+2zmXTs7ImFwy8Idhx86dDgDkoE82bA13P7IgVFXXSgl14jk3ui+RlJQGHXteUsenS6oeDm17HJnRf9ML815r1rz81p/WmmOkFFbzxOvBUmLyTZoy3XwmScrKepQMCcuKikNdUUQZ7N72Jc7HpFcx2e5AAACA3OcXBoCEeOg4QPzXmR46DuS6HkZzgKy91qwxTQEAAMBf+K1VAwC+XEO92rQIAFAw7G8HiP9+2f52AAAA+EvvxfobKwcAAAB5YO/SijO8QEWZ6PrbZlhiiVnx9p9y8vgNOOr08OmmrUn/POYtXBqKDxztO5KCinsND6tqO4VQX5x1NbzZLtxybc/Qqc9wxyoFHT3uovD+h58YcAH+h3UbNmXsmuO6W10HQy5a9vbH4eb75oaq6lopoS67+dFQ1Oso9yaSktL3j/x50sepH/7iuoz+m3od8ePw2bbtzZqfH69901wjpbDl76xxI5BkH3y0NrQpH2FOkyRlZb/t1CPUFUWUwRZF2oc2ZRXOxyTWqqxygd2BAAAAuc8vDAAJ8dBxgPivMz10HMh19xjNAbL2WrPGNAUAAAB/YWOsf7RyAFDw66f/b6wNpkUAgIJhfztA/PfM9rcDAADAX1dh5QAAACAPtOo2YpiXqCgT9Rzy49DY1FTwKyxvvfdBzh7Dih+dG7Zs3Za0z2Lh4hWhQ99jfD9S1KTLe4dQX5x1zZlZEgZUDHaMUtDu79PdNbNDNBq1nA3wZ353c3VGxuZIr9Fh/cbNDgDkkJ27GsOTL9WFqupaKeFumDYnHDjsp+5PJCWt3WNKsseqG3ePVcPHZ/TfNfGaqc2ap7d9vjNMnfmyOUdKUVMfmB+272xwU5Bkx5xykTktBbWO1ber3xokqSV1LB0WFkY6hLqiiDKY+Sy5tSqr3NG58+i/t0MQAAAgt/l1ASAhHjoOEP91poeOA7luV6zWRnSArLzWrDFNAQAAwF91mpUDgIJfPx1vOgQAKCj2twPEf89sfzsAAAD8dc9ZOQAAAMgDrUtG9PQSFWWq2c/NL/gVlvdWfZjTx/CwY84Mn6zb2OLP4fWlb4VOB431vUhR3Q89Imx7o10I9cVZ03sv7hdOOW2A45Oijh53UVi1eo1lbIC/4vPtO0KXAcdnZHw++zdVDgDkkE82bA33zFoYqqprpWb1gwnXuj+RlNRKB52ckvHqspsfDUW9jsrYv2uf8pFh8bK3mjVfr3jvE3OOlMJeWPiOG4Mke/CxF8xpKepH+38/jOpyiM9CklrQhM59Ql1RRBns5Nh85lxMbm3KKrrbIQgAAJDb/LoAkBAPHQeI/zrTQ8eBfHCZER0gK681a0xRAAAA8FetiLWX1QOAgl07/W6sOtMhAEBBsb8dIP77ZvvbAQAA4JuVWj0AAADIcf/ZdXiRF6goU4088fyCX11ZtXpNzh/H3sPGhbq3VzX7M5i7YEno2HeM70QKm3V3txDqi7OibW+0C5Mu7x2KelY4NimoQ99jwl0zHg/RaNTyNcA32D1OZmKMbt1tRKh/Z5UDADlicd2H4eb75oaq6lqpWV143cywT49R7lMkJbX9vv+DlI1bPz5/ckb/bYeP/XloaGxs1rz9yHNLzT1Sipo8vTasWb/FDUIS9ItGbgAAIABJREFUbd+xM3Q6aKx5LQXtU1oRZrXbPwzrcqjPQ5Ka2b5lFeH54k6hriiiDHVVxx7OxSTXqnTEaXYIAgAA5Da/LgAkxEPHAeK/zvTQcSAfrIv1D0Z1gKy71qwxRQEAAMA3OszqAUDBrp0ONg0CABQc+9sB4r9vtr8dAAAAvtltVg8AAABy3P/pPPp/e4GKMtmiN+oKenXlwzXr8uI4RnqNDndMfzREo9GE/v1/fGruF/9d34XUNXLMoSFaVxxCfWbb/TfMnFoeSg8e6rikqNHjLgyrVq+xbA3wLRqbmkKf4adkZJw+bvwlDgDkgO07GsKjLy4PVdW1UrO77u7nQteBJ7lPkZSCNbijUzp+ff/In2f033frvY80a/7+dMvnYcqMl8xBUoqqeeL1kODSP3tw7qWTzWspaswBB4clkXZhaJdDfR6S1MyOP6B/qCuKKEM90m5/52GyK6283Q5BAACA3OaXBYCEeOg4QPzXmR46DuSLsUZ1gKy71qwxPQEAAMA3etDqAUDBrp0+YhoEACg49rcDxH/fbH87AAAAfLNtsf7NCgIAAECOa1Vaud1LVJSpTjn36oJeXflk3ca8Op6jTr4gzF+0bI//7oaGxvCba+8IrbuN8D1IYfuUV4TlTx0QQn1xRlv8+AFh+NGDHJMU1aHvMeHOGY+FqDfbAuzRzEefz9h4/cK81x0AyHJr1m8Jf5i1MFRV10otavAPLnCvIikl7V5Lu3HanJSNX1feOjsU9zkmY/++dr2PDu9/+Emz5vGFy943B0kp7M1317hhSKJFb9SZ11LYQ+0PCEsi7cIRXQ71eUhSc+47Ys1qt3+oK4ooAy0rKg77llU4F5NYq9KKN+wOBAAAyG1+WQBIiIeOA8R/nemh40C+eNGoDpB115o1picAAAD4Rg2x9raCAFBw66ZtYjWaBgEACo797QDx3zvb3w4AAADf7nQrCAAAADmuVVnFB16ioky1T/nIsGp14b6Mcf3GzXl5XEed9Mtwe/UfwzsrV3/1b21sagp1b68K98x8IvStONX5n4YuOO+gEOqLM9aa+R3DmWf2D627ORapavS4Cwt6DAVIRDQaDQOOOj0j4/Xu/93d//tA9lpc92G46b65oaq6VmpRp114i3sVSSlt0l3PpHQc++mFt2b033fyL65o1lzeFLvevu/x18xFUoqa+sDLYfuOBjcOSXTwqPHmtRQ1pMvAUFcUCYsj7WL/+VCfiSS1YCxVZhrQdZDzMJmVVjT+Z9fD/tEOQQAAgNzlVwWAhHjoOED815keOg7kkwOM7ABZda1ZY2oCAACAb3WxFQSAgls3vdT0BwBQkOxvB4j/3tn+dgAAAPh2b8bayyoCAABADtu7rPI1L1FRJrvo6tsKdmVly2fbCuIYt+9zTIj0Gu18T2Od+w0LG17tEEJ9cdrbtbxduP36nqFj7+GORaqOb//jQvVDT4doNGqJGiBOTzw/P2PjdvWDTzkAkKW2btsRHnr2jVBVXSu1uEtvmhUiPd37SkptV972RMrHs4Fjzsnov3H3tXtzfLxuc5g83XwkpaoXF77jBiKJqu6YaV5LYdPadw11RZGwONIuDOlyqM9EkprRXe1LvhhLlf5O27+fczDJfa98RD87BAEAAHKXXxUAEuKh4wDxX2d66DiQT240sgNk1bVmjakJAAAAvtVHsf7OKgJAwayZ/l2sD01/AAAFyf52gPjvn+1vBwAAgD37vlUEAACAHLZ3WeVTXqCiTNa+zzFh46YtBbmq0tQUDa27jXAeKOndeWOPEOqL01q0rjg8dHt56HXYEMcghf3ojEvDx5+stywNkKDKE87LyLjd9ZDjw46dOx0AyEJvr1oXps58OVRV10ot7oZ7Xww9jjjNPYuklHfZTX9M+Zh29e1PhQ79js3Yv7HH4JPDZ9u2N2t+f2HB2+YlKUVNnj43rP/0MzcSSbL647WhTbnfh1LVgK6DwoqiSKiLtSjSPhza5TCfiyQlWJ+uh4flX46lSm/XdSx3Dia7bpUT7BAEAADIXX5VAEiIh44DxH+d6aHjQD7Z/aCGfzK6A2TNtWaNqQkAAAD2aKRVBICCWTM92rQHAFCw7G8HiP/+2f52AAAA2LPpVhEAAABy2N6lldO9QEWZruqOmQW7stKu99HOASX3ZZEVg0PDiuIQ6tPXokcPCCPGeCllKis//KQw+7mXLUcDNMPcBUsyNn7/7uZqBwCyzM5dDeHpefWhqrpWSlqjTrnMfYuktDTx+gfTMq6dccmdGf13XjLpjmbO843hzodeMTdJKerhZ5e6oUiiUSf90tyWwm7pUBbqiiJftCjSPhzSdZDPRZIS7NqO3b8aS5W+Zrfr7PxLcq3KKqbZIQgAAJC7/KIAkBAPHQeI/zrTQ8eBfPMToztA1lxr1piWAAAAYI+esooAUDBrps+b9gAACpb97QDx3z/b3w4AAAB7tjPWf1pJAAAAyFF7l1be4QUqynTdBp0Ydu1qKMiVlZKBP3QOKKnNe6hrCPXFaendFzqHU04b4HNPYW3KR4RzL50ctn72uaVogGYac+rEjIzhkV6jw9r1Gx0AyCLvf/xpuOvhBaGqulZKWmddcU9o3W2E+xdJaemXv5uRtvHtsLHnZezfuU/5yLB0xbvNmu/feX+d+UlKYStXb3BjkSR/uH+2uS2F9SoZHJYXRULdl70aaR8O7nq4z0aSEqhryRFhcaTdV2Op0tPySHEoLh3uHExircoq37JDEAAAIHf5RQEgIR46DhD/daaHjgP5ZpHRHSBrrjVrTEsAAACwR9FY7awkAOT9emnHL8d8AAAKk/3tAPHfQ9vfDgAAAPE530oCAABAjtq7rOImL1BRNlQz69mCXFXpM/wUx19J69TTDg6hvjjlbVzUIVx+cZ+wb48Kn3sKO+yYM8PrS9+y/AzQAouXvZWxcfzcSyc7AJAlGhubwrzFK8Pk6bWhqlpKXlfeOjt06DvW/YuktHX2b+9N2xh39dSnQvu+YzL2bx16/Nmhqal5z0V57MXl5ikpRd0za2FobGpyk5EEGzdtCfv2PNL8lsImdeoe6ooiX/VKpH3oW3K4z0aSEuii/Q782liq9DS4y6HOv+QWbVtS+a92CQIAAOQmvygAJMRDxwHiv8700HEgH5Ua4QGy4lqzxpQEAAAAcbnMSgJA3q+XXmW6AwAoaPa3A8R/D21/OwAAAMRn94td97KaAAAAkINalVZe6+UpyoYGjj4jRKPRgltVOeyYMx1/JaXiXsPD+3P3C6G+OGXtWt4u3H59z9Cp7zCfeSqP5YGjw6Qp00NDQ6OlZ4AWOvkXv83IWN6mfER4908fOgCQBdZ/+lmY/vhroaq6VkpqN9z7Yug17KfuYSSltTN+c2dax7rxE2/L6L/3jvsebdb8v2XbjnDL/fPMV1KKWly32o1Gkpxw5mXmtxRWUjI0vBEpDnVFka96ubhD6FUy2OcjSXHWvnR4eDnS4WtjqVLfmZ37Ov+SXKuyyoF2CQIAAOQmvyYAJMRDxwHiv8700HH+f/buO8qqKl/0ffdJ75xz733jjnHfPfccgloBQUCoAhUxYwIUiiSK2mbbrG0b0DbbtnY3tglBDJglWIqKWUBUQFQQEREoBMWMmMi5qn6vtHvcToa9d+28P58xvv+dMc5g7dVzzjVruhYUo5uM8AB5sdasNSUBAABAQr75D5b/0W4CQNHulf5TU5+a7gAASprz7QCJP0c73w4AAACJ28NuAgAAQAFqUd3vGh9PUb406aVZJbejMuC4C/32SkvXX9M9YnFFRmqsq4gn7q2O7j0Pcq0z3JGnXxkffrLCdjNAGixZ9lG07to/J+P5Cef81g8AOVbf0BivvfVB3DJ+RowYO11Ke/2Ov9IzjKSsd+qld2R9vNv30PNz9u9tt8fhsXzFlymtBd6s+8R8JWWoOx5+JTZu2uKhIw0efWaa+S3DXdNu56grK/+rppe3jZ069XZ9JCnBTm+/x9+Npcpst2zfxb2X5lpU9TvPKUEAAIDC5K8JAEnx0nGAxNeZXjoOFKNvDt3+P0Z5gJyvNWtNSQAAAJCwXnYTAIp2r7SvaQ4AoOQ53w6Q+HO08+0AAACQuDvtJgAAABSgFlU1l/l4ivKl3keeG42NjSW1o3Lc2Vf77dXsuh3QOzbObxOxuCLtzXikU/Qa2NN1znAd9jkyHpjwnG1mgDQ665Ibcjauz5q70A8AOfTFynXx4DNzY8TY6VJGOvWS2zzHSMpJJ14wMutj3u/veDYqdjssZ//mk4cOS2k98M0280OT3jRvSRnqpdlLPXikwYaNm2L73Q8zx2Wwjp0PjnnllVFXVv5XTatoG10693aNJCmBtqmuiecr2v3dWKrM9c31du+ltxbVNWOcEgQAAChM/poAkBQvHQdIfJ3ppeOANSEAmVpr1pqOAAAAIGEP2k0AKNq90kdMcwAAJc9ZJoDEn6OdbwcAAIDErWvqf9hRAAAAKDAtq/td4OMpyqemTJtdUjsq515xs99dze6p+7pELK5Ia4untI+TT+3h+ma4Vl36x1mX3BBfrVxtixkgjd59/5PYdqeBORnbDz7qPD8A5Eh9fUO89tYHccv4GTFi7HQpI10+/NHYbpdDPM9IyknHnntjTsa+ky++Naf/7skp7hl/uXKddYGUoUaOmxFfrVrvISQNzrz4enNchruq3S5RV1b+dz1f0S527HyQayRJCXREx32+cyxVZlrUVLuqg9176ayqZqFTggAAAIXJXxIAkuKl4wCJrzO9dBwoVk8b5QFyvtasNR0BAABAwjY39f/ZUQAoun3S/2hqi2kOAKDkOd8OkPiztPPtAAAAkJzj7SgAAAAUmJZVNb/w8RTlU72POCcaGxtLZjfl6pvu9burWR36s/0jFlekrY9e3iGGnrdnbNO1xvXNcLv1PTmmvfqmbWWADDhl6LCcje/PTH3FDwA5sPyLNTHmyTkxYux0KWNdd/eU6NjjWM8zknL3Ifuz/pCzMbDH4HNz9u/udtCJsX7DxpTWCDPeeM8cJmWox56f70EkDabOmGOOy3Dtq/rE3LLKqCsr/7smV+wQHasOdp0kKYEmVHb8zrFUmalmx/3cd+msqqb+/3Q64L85KQgAAFB4/CUBICleOg6Q+DrTS8eBYtXQVGsjPUBO15q1piMAAABIyll2FACKbp/0XNMbAADhfDtAMs/SzrcDAABAcqbbUQAAACgwLaprTvHxFOVb33xAsFTccs8jfnOl3DZda2Lh5A4Riyua3Zez28bVl+8WZbvUuLYZbtudB8bVN90bmzZvtqUMkAEL31kWrbv2z8kYv0e/U6OhodGPAFm0ZWt9TJ/zbowcNz1GjJUy181jpsXeg37pmUZSTht86jU5Gwd/e9szUb7r4Jz927/ZS0l1rXDvxNnmMilDvf/J1x5KmmlrfX103u9o81yG+3W7blFXVv6dPVXZIdpVHew6SdKP1HvH/b93LFX6O6/9bu67dNel765OCgIAABQef0kASIqXjgMkvs700nGgmF1spAfI6Vqz1lQEAAAASXnLjgJA0e2TzjO9AQAQzrcDJPMs7Xw7AAAAJK+dXQUAAIAC0qJLzek+nKJ8q+aYoSWzk/LgxOf95kq5S361R8Tiima19s02MfLaXaNt976uaRY65OcXx+KlH9hGBsigI0+/Mmfj/H0PPeMHgCz6+LNVcf/js2PE2OlSxhty5jDPNJJyXr8Tf53TsfDEC0bm7N++3S6DYsmyj1JaM7z/6dfmMilDjXlyTjQ0NHo4aaZLfne7eS7Dta/qE2+UVUZdWfl39mibjtGmyt9JJOnHumf7qu8dS5Xebtu+2j2X5lpU9T/VSUEAAIDC468IAEnx0nGAxNeZXjoOFLMlRnqAnK41a01FAAAAkLROdhUAimaPtKtpDQCAP3G+HSDx52nn2wEAACB5V9lVAAAAKCAtq2rO8uEU5WMvzpxbEjspk6fN9nsrpTrseXB8PWf7iMUVKbVlQWU8cMvO0Xmfg13PLFR9wLHx0BNTo7HRB2YBinVt1Wnfo2Ljps1+BMiCjZu3xguzlsSIsdOlrHTOb+6LVl36e7aRlPMOPvbSnI6HN4+ZFrv3PzNn//4hp1yW8vrhuZfrzGlShpq3+BMPKc30+rw681wWumKHblFXVv69TajsGJXVfV0rSfqB9ujUMxaWVfzgeKr0NLWinXsuzbWo7ne7k4IAAACFx18RAJLipeMAia8zvXQcKHZdjfYAOVtr1pqGAAAAIGm/s6sAUDR7pNeZ1gAA+BPn2wESf552vh0AAACS935TP7WzAAAAUCBaVtf80odTlI/1P+7CkthJmbdgid9bKXXfiJ0jFlck3daFlfHALTtH1/0Odh2z0LY7D4yrbrg71q7bYOsYIMMWvrMsdul9Ys7G/OtuHedHgCyoe29FjJ7waowYO13KSlfcPDHKdx3s+UZSXnTAkRfmfFz8zagno6zbITm7Bk9MmpHSGmL9xi1xx8OvmNukDPTN/7Y2btrqYaUZGhsbo3ufk8x1GW6Hzn3ijbLKqCsr/97GtukU21XXuF6S9APd3LbrD46lSk+Lmmpb1cc9l8ZaVPWb7aQgAABA4fFXBICkeOk4QOLrTC8dB4rddUZ7gJytNWtNQwAAAJC0D5v6BzsLAAW/P/oPTX1sWgMA4E+cbwdI/Jna+XYAAABITXc7CwAAAAWiReea8304Rfna9NfmFf0uyudfrvRbK+kOHNAz6hdVRiyuSLitCyvj4dFdY/fevV3DLDXoxIuibskHtosBMmzr1vq4/YGJUdn90JyN+d/8//5q5Wo/BmTQlyvXxcOT5sWIsdOlrHXtXZOiQ49jPN9Iypt6DD43L8bHY8+/KWfXYOdeJ8T6DRtTWk8sWLrc/CZlqGmvv+uhpZmGjRxjrstCl7XbNerKyn+w0dtXxTaulSR9b1069475ZRU/Op6q+R284/7uuTTWoqrfxq5dT/pnpwUBAAAKi78gACTFS8cBEl9neuk4UOw+beofjfgAOVlr1pqGAAAAICV72lkAKPj90f1MZwAA/AXn2wESf6Z2vh0AAABSc7OdBQAAgALRsqrvr3w4RfnawON/VfS7KI2NjVHW7RC/t5LqlUc7RSyuSKiGRZXxxL3VsUfv3q5dtj4kd+Bx8dATU7/93zcAmdPQ0BhPTZkZew04Ledj/0W/vdUPAhmytb4hXnvrgxg1fkaMGDtdylrD738xutec7hlHUl61e/+z8mKMvHnMtNi1b+7GyGuG35fy2uLhSW+a56QMdMu4GfHVqvUeYJrhnfc+MtdlobZVfeL18jZRV1b+g93ctmu0rq5xzSTp+9bk7Xb+0bFUze/s9ru539Je305OCwIAABQWf0EASIqXjgMkvs700nGgFOxnxAfIyVqz1hQEAAAAKRllZwGg4PdH7zKdAQDwF5xvB0j8mdr5dgAAAEjN5039k90FAACAAtCiuuYSH0xRPjd52uyi30np3uckv7US7vQz9o5YXPGjNSyqjCfurY49D+rlumWpbXceGJcOuyPWrttgixggg7Zs2RrjJ06JvQecnhfj/zZdB8SyDz/1w0AGLPv4q7h34qwYMXa6lPUOOvoSzzmS8q5ufU7Nm3HyyhETY9udBuXkOmy3y6BYuuzj1E61fb02Ro6bYa6TMtATLy7wENNMPQ//pfkuC12yQ7eoKyv/0X7TbhfXS5K+p/ZVfWJOeWVC46lSb+T2Xdxv6a6q5minBQEAAAqLvx4AJMVLxwESX2d66ThQCu404gPkZK1ZawoCAACAlHzV1L/YXQAo2L3Rf21qpekMAIC/4Hw7QOLP1c63AwAAQOp62V0AAAAoAC2r+13hoynK5/YdfGbUNzQU9S7KoBMv8lsroSp37RsfvbxDxOKK761hUWU8cW917HVwL9csiw0+6ZJYvPQD28IAGfTZ51/FyLsnRNeex+fVHHDahX/w40CarVyzIZ58aUGMGDtdyklH/fIGzzmS8rLqnifm1Xg55IxhObsWQ065LOW1xouzl5rvpAz14XLvOGqOW+55xHyXhXbo3CfeKKuMurLyH+1XO3R3zSTpe7qoaYxMZCxV6j1X2d69luZaVNXc4LQgAABAYfHXA4CkeOk4QOLrTC8dB0rB6qb+zagPkPW1Zq0pCAAAAFLW1+4CQMHujR5iGgMA4G843w6Q+HO18+0AAACQuvvsLgAAABSAFtU1V/toivK9Byc+X9S7KGdefL3fWQl10+92jVhc8Z01LKqMJ+6tjr0P7uVaZbEuBx4XDz0x1XYwQIZs3LQ5Jj43PY4566rYpuuAvJsHWnXpHwvfWeaHgjTZsrU+Xnvrgxg1/uUYMXa6lJPOvureaN00vnvekZSPdexxbF6NmcPvfzE67398zq7HU1NmprTm2LR5a9w54VXznpSBxjw5JxoaGz3cpOjTz76M1l2tRbPRr9t1i7qy8oQ6u/1urpkkfUeV1X3jlfLtEx5PlXwLyyq+vc7ut/TVorrmRacFAQAACou/HgAkxUvHARJfZ3rpOFAqBhn1AbK+1qw1/QAAAEDKxtldACjYvdEJpjEAAP6G8+0AiT9XO98OAAAAqVvb1L/bYQAAAMhzLapqhvtoivK9rj2Pj42bNhftLsqwkWP8zvrRuvfsHZveroxYXPFXNdZVxORx1XHggJ6uUxbbbpdB8dub74/1GzbaCgZIs4aGxnht7sIYetXIaLfH4Xk9Hxz7i9/4wSBN6t5bEXc98lqMGDtdyllX3Dwxyncd7JlHUt7Wbq8j827svOi62mjVpX9OrsfOvU5IeW9mwdLPzH1Shpr/zqcecJrhkJ9fbM7LQh2rDo555ZVRV1b+oy1q6ucd9nTdJOk7Or39HgmNpUq9Azsd4F5LZ1X9Vv/kJz/5qRODAAAAhcNfDgCS4qXjAImvM710HCgV4436AFlfa9aafgAAACBl68MHbgAKcV/0vze1wTQGAMDfcL4dIPFna+fbAQAAoHkG2WEAAADIcy2r+t3loykqhEbd+2jR7qA89MRUv7F+tGceqI5YXPF/a6yriMnjqqPnwJ6uT5Y79KRLY/G7H9r+BUizRUvej9/ceE/s1Ov4gpkT5rxV54eDZlrx1dp4eNK8GDF2upTTfn/Hs9Fhn6M880jK69rsPiQvx9A+x12es2vyuxH3p7QGaWyMpjXIm+ZAKQONfviV2Lh5q4edFI19ZJI5L1tzSLudo66sPKEWlFfEER33cd0k6W/aprompla0S3g8VfKd3n4P91qaa921f4UTgwAAAIXDXw4AkuKl4wCJrzO9dBwoFWub+jcjP0BW15q1ph8AAABolgF2GAAKbl/0MNMXAADfwfl2gMSfrZ1vBwAAgOYZa4cBAAAgz7Wo7veQD6aoEOqwz5Gxes26otxBmfNWnd9YP9iQo/eLWFzxbQ2LKuPJ+6pj/349XZss17Xn8fHQE1Nt+wKk0dt178UfRo2N/QafVXDzwmEnX+oHhGZYv2FzTHllcYwYO13Kedfd83x07XWS5x5JeV95t0Pzcxy9+/lou+eRObkmZd0OiXff/ySl9cjnX6+NkeNmmAulDDTjjfc89KRo1eq1345t5r3MV1V1ULxdVhF1ZeUJ9c3/bf+O+7l2kvQ3Hd1x74THUiXfDW27us/SXVXNIU4MAgAAFA5/OQBIipeOAyS+zvTScaCU9DfyA2R1rVlr6gEAAIBmecAOA4B9UQAAioLz7QCJP1s73w4AAADNs7apf7PLAAAAkMdaVtc854MpKpSuvuneotxBWblqrd9X39u2XfvFoikdYuvCynh4dNfYp08v1yXLVXY/NK67dVxs2LjJli9AMzU0NMa8hUu/HVf3GnBaQc8PL896yw8KKdiytT5mzf8gbntoZowYO13KecMfeCn2GPALzz6SCmOfaKdBeTuennH5nTm7LoefennKa5MXZy81H0oZaNT4l2PNuo0egFJ0wjnXmPey1HVtd4q6svKEm1deGb123N+1k6S/qHV1TTxR2T6p8VSJ92RlB/dZmmtRXXO1E4MAAACFw18NAJLipeMAia8zvXQcKCX3G/kBsrrW9PFYAAAAaJ41Tf2rXQaAgtkT/bf448fJAADgbznfDpD487Xz7QAAANB8NXYZAAAA8ljLqpqZPpiiQqm82+D45LMvinIHpeM+P/Mb6zv71dA94uHRXWP33r1djyzXqkv/OHnosPjo089t8wI0Q31DQ7w2d2FcOuyOqD7g2KKYI/ocdb4fFpLU0NgYby9ZHnc9+lqMGDtdyotuHjMteh91kecfSQW1V5HP42qPwefm7No8M/WVlNYomzZvjTsnvGpelDLQ5JmLPQil6IlJM8x7WWqnTr1jQVl51CXRnPI2sU+nnq6fJP1FA3fcN6mxVIm3oKwiyqpq3GdprEV1zdNODAIAABQOfzUASIqXjgMkvs700nGglKwOH6AFyOZas9bUAwAAAM3Wxy4DQMHsiQ4wbQEA8D2cbwdI/Pna+XYAAABovnvtMgAAAOSxFlU1b/lgigqpX1x6Y1HuoNQcM9Tvq++scte+rkMO6nPU+fH6vDrbuwApWvHF1zF+4pQ4eeiwaLfH4UU3T0yeNtuPDEn4cPnKGPvUnBgxdrqUVx1yyjWefyQVXMMfeClvx9Vrbns6yncZnJPr0u2gE2PDxk0prVUWLP3MvChloJHjpsfnX6/1QJSCjZs2R9vdh5j3stTNbbtGXVl5Ur1Svn3s2rmX6ydJf1Ftmx2THk+VWD06HegeS2Mtqmo+dWIQAACgcPirAUBSvHQcIPF1ppeOA6XmYKM/QNbWmrWmHQAAAGi2u+0yABTMnugDpi0AAL6H8+0AiT9fO98OAAAAzbeyqX+x0wAAAJCnWlbVvO+DKSqkWnXpHzNnzy+6HZTzrrzZ7yvlQbv1PTmemjLTti5AkuobGmLewqUx8u4J0f+4C79dsxXrXHHAYb+NUmwhAAAgAElEQVSIxsZGPzokYPkXa+KRKW/FiLHTpbzrhKGewyUVZjfcOzWvx9djz70pZ9dm2MgxKa1ZvlnePzzpTfOjlIEef+FtD0YpOu3CP5j3slT3Tr1iYVlF1JWVJ9W0irbRpXNv11CS/tSBnQ5IeixVYp3UYU/3WJrbdueD/tOpQQAAgMLgLwYASfHScYDE15leOg6UmruM/gBZW2vWmnYAAACg2XzgBqAw9kP/pamvTVsAAHwP59sBEn/Gdr4dAAAA0qO3nQYAAIA81aK65isfS1Ghte/gM2Pr1vqi2j25a9yTflsph22/+2Fx3a3jYtPmzbZzARK04ouvY/zEKXHy0GGxw15HlMyc8fikGX58+BFfrVofT01bGCPGTpfysjOvuCtadenvWUhSQfaHOyfn9Rg7fMy02Omgk3Nybcq6HRLLPvw0pfXL51+tjZHjZpgnpQz00WcrPSSl4KkpM817WezWtl2irqw86Z6vaBcdqw52DSXpT93TpnNK46l+uN+129n9leZaVfft5dQgAABAYfAXA4CkeOk4QOLrTC8dB0rNl039kxkAICtrzVrTDgAAAKTFgXYaAPJ+P7S36QoAgB/gfDtA4s/YzrcDAABAeoy20wAAAJCP9t77n1pW92v0sRQV5Mft7nusqHZPXp3ztt9VykHb7jQwhl41Mr74apVtXIAfsX7Dxnhx5hvxmxvviQOHnB2tuvQvuXljv8FnRUNDo5sBvseadRvjhVlLYuS4GTFi7HQpL7tg2Lim54BBnockFWy/u+PZvB9rL7vxkWjddUBOrs/xv7wm5bXMi7OXmiulDFT77FwPSynYsHFTVHY/1NyXpXbr3CsWllVEXVl50j1V2SHaVvVxHSWpqT069Ux5PNX391CbHd1faa5F55rzHRwEAAAoDP5iAJAULx0HSHyd6aXjQCnaywwAkJW1Zq0pBwAAANLiZjsNAHm/HzrKdAUAwA9wvh0g8Wds59sBAAAgPVY09Q92GwAAAPLMNl0H/JcPpahQa7v7kFi+4sui2T1ZvWZdtOrS328rZbEhp1wWi5a8b/sW4HvUNzTEvIVLY+TdE74dM8u6HVLyc8ezL7zqxoDvsGbdpnhh1pK4ZdyMGDF2upS3XXbjI1HR/TDPQ5IKuqtvfaogxtxBJ1+ds2v04sw3UlrTbNq8Ne6c8Ko5U8pA73zwhQenFJx0/u/NfVnsru2roq6sPKUmVHaMiqq+rqMkNTWqbXXK46m+uznlldHKvZXWWlTV3OfkIAAAQGHw1wKApHjpOEDi60wvHQdK0TAzAEBW1pq1phwAAABIiw/sNADk9V7oT5v6yHQFAMAPcL4dIPHnbOfbAQAAIH12sdsAAACQZ1pW9+3kQykq5E4ZOqyodk92PfjnflcpC+094PSYMm22LVuA7/DBx5/FAxOei5Ob1lk77HWEeeMvOuhn50VjY6ObBP7CmvWbYuprS+KW8TNixNjpUl535YiJsf0e5jZJhd9VIx8viHH3xvteiA49jsnJNeox6IzYWl+f0vpmwdLPzJtSBrr/idnR0OCZOlmPPTvN3JfF9tmxZywqK4+6FHugTefYrrrGtZRU8u3SuXcsaMZ4qu9up6br6v5KZzVznRwEAAAoDP5aAJAULx0HSHyd6aXjQClaZAYAyMpas9aUAwAAAGnT0W4DQN7uhVabpgAA+BHOtwMk/pztfDsAAACkz6/tNgAAAOSZll367usjKSr0Xpw5t2h2T0445xq/qZTBOu93dNz/8LNR39BguxagyTfj4VuLlsboMY/Hz8/7XXTa9yjzxQ80c/Z8Nw38yYaNW2Lmm8ti1IMvx4ix06W876pbHo+2exxhPpNUFF0+/NGCGX/Pveb+nF2nux98KqV1TmNjxEOT3jR/ShnorcWfephK0tp1G6K822DzXxYb06ZT1JWVp9wt23eJ1tU1rqWkku+Gtl2bNZ7q7zusYw/3VhprUd1v00/23vufnB4EAADIf/5aAJAULx0HSHyd6aXjQKlqYxYAyPhas9Z0AwAAAGnzK7sNAHm7F3qZaQoAgB/hfDtA4s/ZzrcDAABA+rxhtwEAACDP/FdV/8N9KEWF3u41p8SmzZuLYvdk+OiH/KZSBtpul0Fx6bA7Ys3a9bZpgZK2tb4+5i1cGiPvnhDHnHVVtN/7SPNEgp0ydJgbCJqsWbcpXnp9aYx68OUYMXa6VBD99rZnosM+R5vPJBVNl9zwcEGNw/sNOT8n1+mb552vV61Jac3z+VdrY+S4GeZRKc3d+cirsWVLvQerJJ1wzjXmvyzWd8f9oq6svFnd2LZrtHItJZV41Z0PivllFc0eU/XnfrVDd/dWmvvPqpr2Tg8CAADkP38pAEiKl44DJL7O9NJxoFSdbRYAyPhas9Z0AwAAAGkzw24DQN7uhc42TQEA8COcbwdI/Dnb+XYAAABIn8amWtlxAAAAyCOtqvud6SMpKoZuvOPBotg9eXnWW35PKY216tI/Tr3g2vjwkxW2Z4GStHrNunh++uvx25vvjwHHXRhl3Q4xP6TQjj2Oik8++8INRUlbtXZjTHv93Rg1/uUYMXa6VDD9/o5nY8f9jjWfSSqqLrz2wYIai3972zNRvsvgnFyrS4fdkfL658VZS8ylUgZ67a0PPGAlacJTL5j/stzjlR2irqy8WV3erptrKank+227nZs9nurPjd6+yn2V5lpU9zvM6UEAAID85y8FAEnx0nGAxNeZXjoOlKopZgGAjK81a003AAAAkDYNTf2HHQeAvNsH/a/440fIAADghzjfDpD4s7bz7QAAAJBeJ9txAAAAyCMtq2t+7SMpKoYqdh0cHy//vOB3TtZv2Bjb7jTQbyqloSGnXBbzFi61JQuUjK1b678d9+558Ok4+7KbYu8Bp0erLv3NCc2svNvgmDV3oRuMkvXF1+ti8szFMXLcjBgxdrpUUF1716SoOuAE85mkomvo78YW3Jh81C9vyMm12nbngfHOex+ltA7atHlr3DnhVXOqlOZuq50Z6zdu9rCVhDVr10dZt0PMgVnsiI77RF1ZebM7u/3urqekkq5D1cHxRlllWsZUlcfUinbuq3RX1e8qpwcBAADyn78UACTFS8cBEl9neuk4UKq2NPU/zQQAGV1r1ppuAAAAIK2OtuMAkHf7oCeangAASIDz7QCJP2s73w4AAADp9YQdBwAAgDzSsqrfKB9JUbF0+kXXFcXuyYFDzvZ7Ss2oz1Hnx4xZ82zFAkXvw09WxGPPTosr/nBn9D/uwqjYdbB5IM1tu/PAeGrKTDcbJemjz1bGxKnz/++H76VC67p7psROvU8xn0kqys695v6CG5eHP/BSVB1wQk6u15GnX5nymmjB0uXmVSkDvTh7qYeuJB191lXmwCy2TVVNPF/RLurKypvVoqaO77CXayqppLu8Xbdmj6f687yyfVVf91V6e8zpQQAAgPznrwQASfHScYDE15leOg6UskPMBAAZXWvWmmoAAAAgrcbbcQDIu33QR0xPAAAkwPl2gMSftZ1vBwAAgPTa0NS/2nUAAADIEy2r+k30gRQVS6269I85b9UV/O7Jr64Z5feUUmifgafHE5NmRGNjo21YoCitWr02Hnt2Wpxx8fVRtf8xxv4MV9n90Jg6Y44bj5LyzTpq6YdfxEPPvfmdH76XCqXr7pkS3fqcaj6TVLT94qp7CnJ8vuDa8d/u4ebimk2ZNjvF9VHEg8/MNb9Kae6W8TNi5ZoNHsKS8ODE582BWe7k9ntGXVl5s1tQVhEDOu7rmkoq2dpW9YnZ5dunZUxVeRzY6QD3VRprUVXzrtODAAAA+c9fCQCS4qXjAImvM710HChlt5kJADK61qw11QAAAEBafdnUP9h1AMibPdB/amqV6QkAgAQ43w6Q+PO28+0AAACQfgfYdQAAAMgTLatqXveRFBVTfY8e+u2H4AvZI0+96LeUkqh7n5Pi4SdfiIaGRluvQNFZsuyjGHXvo3HIzy+ObXcaaNzPUl0OPC5en1fnBqRkbNlSH2/WfRL3Tpz9gx++lwqh6+6eEjsfdIr5TFJRd8bldxbsON37qItycs32GnBa05pna0prpU8/X22OlTLQszMWeRhLwspVa2Pbne0NZbPtqmtiZkXbqCsrb3bzyivjwE4HuK6SSrahO3RPy3iq8ji1wx7uqfTW+L/a1vwPJwgBAADym78SACTFS8cBEl9neuk4UMreNxMAZHStWWuqAQAAgLTb2a4DQN7sge5uWgIAIEHOtwMk/rztfDsAAACk3zC7DgAAAHmiZXW/z3wgRcXWo89MK+idkxVffB2tuvT3W0o/0o49joqRd0+ITZs323IFikZ9Q0O8NndhXH3TvbHPwNON9zlo8EmXxOdffu1mpCSsXrsxZr65LO54+JWEP3wv5XPX3T0ldj7oFPOZpKLvtEtuL9ix+tq7JkWb3Ybk5Lrddv9jKa+bnpm+yFwrZaDlX6zxYJaEI067wjyY5c5v3z3qysrT0qyKNrFbp56uq6SSrKKqb7xSvn3axtRS7tp2O7mn0l2Xvrs6QQgAAJDf/IUAICleOg6Q+DrTS8eBUtfGbACQsbVmrWkGAAAA0u4iuw4AebMHeoVpCQCABDnfDpD487bz7QAAAJB+b9p1AAAAyANdu570zy2raxp8IEXF1i69T4yNmzYX9O7JPgNP91tK39P2ux8WV990b6xZt95WK1AUvvx6ddQ+/nycdP7vo90ehxvrc/VRz10Hx8i7J0RDQ6ObkqL3+VdrY/LMxXHLuBkpffheyseuvWtSdO11kjlNUkl00kWjCnrMPmHozTm5bjvsdcS3z1+pWL12Y4x68GVzrpTmHpnylge0JIyZ8Jx5MNt/j6jqE3PK20RdWXlaml7eNqo7H+TaSirJzmy/R9rG01LukTYd3U/prkv/k5wiBAAAyG/+QgCQFC8dB0h8neml40CpO91sAJCxtWataQYAAADS7gW7DgB5swf6smkJAIAEOd8OkPjztvPtAAAAkH7ffIzwv+w8AAAA5Nh/Vg/c1sdRVKzdeMeDBb17csnvbvc7Sn/TdrsMiqFXjYwvvlplixUoeAsWL4vhox+KvkcPjdZd+xvnc9zgky6JZR9+6sakqG3ZWh8Lln4WDz4zt9kfvpfyrWGjJ0V1zxPNaZJKphMvHFnQ4/bNY6bFTgednJNrd8Fvbkl5PTVz7jLzrpSB3v/0aw9sCfry69Wx7U4DzYVZ7qp23aKurDxtPVexQ7SrOti1lVR6f+utrolpFW3TOqaWYnPLKqN107V0T6WvFlU1w50iBAAAyG/+QgCQFC8dB0h8neml40Cpe8xsAJCxtWataQYAAADSbnNT/93OA0DO9z//36a2mJYAAEiQ8+0AiT9zO98OAAAAmfEzOw8AAAA51qKq324+jqJibfvdD4sVXxTuhxifmfqq31H6U998JPSsS26IDz9ZYVsVKFgbN22O56e/Hr+6ZlTs3OsE43uetEvvE2PCUy9EY2Ojm5SitXL1hpj55rIY/fAraf3wvZQv/X70c1F1oLlVUml1wtCbC378vviGh6N1l/5Zv3bbdB0QCxYvS2ldtWVLfdz1yGvmXynNjXv6jfBYnrjDTr7UXJjlOnc+ON4uq4i6svK09WibjlFR1df1lVRyndJ+z7SOp6Xazp17u5/SWIvqmhecIgQAAMhv/joAkBQvHQdIfJ3ppeNAqVvT1D+bEQAystasNc0AAABARvSx8wCQ8/3PAaYjAACS4Hw7QOLP3M63AwAAQGbca+cBAAAgx1p06X+oj6OomDvn8uEFu3Oyes262HangX5HlXStuvSP0y78Q7z3wSe2U4GCtHzFl/HAhOfi2F/8Jiq7H2psz6Pa731k3HLPI7Fp82Y3KkWpvqEhlnzwRUycOj9jH76X8qHf3/FsdN7/eHObpJLruPOHF8U4XnP8FTm5foNPuiTlddbbS5abg6UMVPfeCg9yiZ68rX3GXJiDbmzbNerKytPaPW06xzauraQSa5vqmnihol3ax9RS67COPdxP6ayq5kunCAEAAPKbvw4AJMVLxwESX2d66ThAxJ5mBICMrDVrTTEAAACQETfZeQDI+f7nLaYjAACS4Hw7QOLP3M63AwAAQGYsb+qndh8AAAByqGV1zS99HEXFXOuu/eOtRUsLdvfkm4+7+h1Vqh1z1lUxf9G7tlGBgtLQ0Bhvvv1OXHvLmOh1+DnRqkt/Y3qe1X7vI+O6W8fFqtVr3bAUpZVrNsTLb7wXoye8mpUP30u57DejnoyOPY41v0kqyY47b3hRjOXX3T0ltt/jiJxcw6efn5nSequxsTHGP/2GuVhKc/dOnBX1DQ0e6hLw+ZdfxzZdB5gPs9yunXvFwrKKqCsrT2sj2naJVq6vpBLrpPZ7pn08LbUu2GE391K6zxdV17RwkhAAACB/+esAQHL/OZqZAyDhdaaXjgNEXGlGAMjIWrPWFAMAAAAZscDOA0DO9z8Xm44AAEiC8+0AiT9zO98OAAAAmdPR7gMAAEAOtazqd50Po6jYO+TnFxfszsntD0z0G6rkGnLKZTF3/ju2ToGCsW79xm8/xn7uFTdH1f7HGMvztM77HR0j754Qa9dtcNNSdDZvqY+691bExKnzs/7heylXXX7To9F2zyPNcZJKtmPPvbFoxvRTL7ktJ9dw95pTYsuWrSmtvz7+bJX5WMpAby3+1ANeggaecJH5MAfduX3nqCsrT3tX7NDN9ZVUUm1TXRMvVLTLyJhaKt3Sttq9lOZadenX00lCAACA/OUvAwBJ8dJxgMTXmV46DhDxghkBICNrzVpTDAAAAGREY1P/YfcBIGd7n/9lKgIAIEnOtwMk/tztfDsAAABkzml2HwAAAHKoRVXNwz6MolLoxZlvFOTOyQcff+b3U8k05JTLYu78d2yZAgXhk8++iLsffCqOOO3yKOt2iHE8j9v/0F/E2Ecnx8ZNm924FJXGxohPP18dL8xaErfVzszph++lbPer6x6Mit0OM89JKumOPufGohnXbx4zLXbte3pOruOdY59IeT329LSF5mUpzd316Guxtb7BA18C7hr3pPkwB+3X6YCoKyvPSGe33801llRS/bzDnhkbU0uhZyvau4/SXIuqfuc5SQgAAJC//GUAICleOg6Q+DrTS8cBIjY29a9mBYC0rzVrTTEAAACQMYPsPgDkbO9ziGkIAIAkOd8OkPhzt/PtAAAAkDkP2n0AAADIoRZV/Wb7MIpKod5HnhuN33x1vgD1GHSG31BF3ZBTLou589+xVQrkvYXvLIsbbn8weh9xTrTq0t8Ynsdt03VAnHDOb+PlWW+5cSk6K1dviNfe+iDue3x23nz4Xspm51x9f2y3yyHmO0kl31G/vKGoxvfLbnwkWufgOWvHHkfF6jXrUlqXrV67MUaNf9n8LKW5uYs+9uCXgOUrvozWXe1P5aLaNjtGXVl52lvU1PEd9nKNJZXOPn51TbxQ2S4jY2optKCsIrZtuobupfTVorrfvU4SAgAA5C9/GQBIipeOAyS+zvTScYA/2tOsAJD2tWat6QUAAAAyZrjdB4Cc7X2OMg0BAJAk59sBEn/udr4dAAAAMmdFUz+1AwEAAJAjLav6feHDKCqVnpn6SkHunvz25vv9firKfnbGlTF3/ju2SIG8Vd/QEK/NXRhX33Rv7DXgNGN3AdS15/Hf/l4fffq5G5iisnb9pniz7uN46Lk38/bD91I2OuvKu2PbnQaZ8yTpm32Vs68vunG+73GX5eRaXn3jPSmv02a88Z45Wkpzdz7yamzZWu9BMAH9jr3AnJiDBnXsEXVl5RlpQVlFDOi4r+ssqWQ6ocNeGRtTS6HdO/d0H6W3N5wkBAAAyF/+KgCQFC8dB0h8neml4wB/dIlZASDta81a0wsAAABkzDy7DwA52/tcaBoCACBJzrcDJP7c7Xw7AAAAZFZbOxAAAAA58F9d+/x7y+p+jT6KolJp38FnRkNDY8HtnCxYvMzvp6KpVZf+cdzZV8ebb79jWxTIS+s3bIynn58Zv7j0xui4z8+M3QVQebfBccrQYfHizLkFudaD77Nx09aoe29FTJw6P0aOy/8P30uZ7oShN3/7PGHuk6Q/duQv/lB0Y/21d02Kit0Oy8kzxUeffp7Smm3Llvq465FXzdVSmpuz4CMPhQm4/YGJ5sRc/J2jqWcrd4i6svKM9GZ5Zey/4wGutaSSaJuqmphckbkxtdg7qsM+7qM01qKq38afDB78j04UAgAA5Cd/FQBIipeOAyS+zvTScYA/mmxWAEj7WrPW9AIAAAAZ882Lxv6XHQiArO97/u8/jcEAAJAM59sBnG8HAACAfHGSHQgAAIAc+M/q/jv4KIpKrUeeerEgd096HHKm308FXeuu/eOYs66KeQuX2g4F8s7Xq9bEuMcmfztOffMxdeN2/rftTgPjiNOuiAcnPh9r1q53E1M0Nm7eGnXvrYgnX1oQt4ybUXAfvpcy1ZAzh5n/JOlvOuKsPxTlmH/c+cNzcj3PuPj6lNdw89/51HwtpbnRE16JzVvqPST+iI8+/TxadelvXsxBJ3XYM+rKyjPWrIo2sVunnq61pJLouA57Z3RMLeYu2aGbeyjdVR3cxolCAACA/OSvAgBJ8dJxgMTXmV46DvBH3/wHev9iZgBI61qz1vQCAAAAGdXPDgRA1vc9DzH9AACQAufbAZxvBwAAgHwxxg4EAABADrSq7tvLB1FUanXvc1Js2bK14HZPbrj9Qb+fCrJtdx4YZ11yQyxZ9pFtUCCvrFy1Nh56Ymocc9ZVsd0ug4zZBVLvI86J0WMej8+//NpNTNFYs25TzFv8STz2/Py4ZdyMgv7wvZTuhj/wUvQ59jJzoCR9R4efOaw4x/4x06K654lZv56tuvSPeQuWpLSea2xsjLFPzTF3S2lu1vwPPDAmoNfh55gXc9B21TXxSvn2UVdWnrFmVGwfXTr3dr0lFX3bVNXE5IodMjqmFmujt69yD6W5FtU1NU4UAgAA5Cd/EQBIipeOAyS+zvTScYA/625mAEjrWrPW1AIAAAAZdb0dCICs73vebPoBACAFzrcDON8OAAAA+eJTOxAAAAA50KK65hQfRFEpNmbCcwW3e/L+R8u//bCr308F80HJXQbFWZfcEO998IntTyBvfL1qTTz0xNQ45qyrYtudBxqvC6Qeg86I624d9+16CIrFV6vWx5wFH8WEyfOK7sP3Urq67p7nY89BZ5sLJel7GnLGsKKdAy64dnxO9kIHnXhRyuu7jz5baf6W0tztD70SGzdv9QD5I66/bbx5MUddtMOuUVdWntGerdwh2lUd7HpLKvqO6bBXxsfUYmxqRTv3T/q7wIlCAACA/OQvAgBJ8dJxgMTXmV46DvBn/l4KkN61Zq2pBQAAADJqth0IgKzve841/QAAkALn2wGcbwcAAIB8Um4XAgAAIMtaVPe7xsdQVIrt1Ov42LR5c8HtnvQ56ny/n/K+trsPiV9ff1d89vlXtjyBvLB8xZdx17gnY+AJF0Xrrv2N1QVSj0POjOtuHRdLl33sJqYo1Dc0xIfLV8ZLs5fGPY/NKuoP30vp6Jpbn4qqA08wJ0rSDzTkjN8X9Vyw/5ChObmuk16alfKa78mXFpjHpTT36rz3PVD+iAWLl5kXc1THzgfH/LKKqCsrz2gTKjtGeVVf11xSUbdNVU08V9k+42NqsbWwaR6qMEektRbV/e51ohAAACA/+YsAQFK8dBwg8XWml44D/NmjZgaAtK41a00tAAAAkFFbmvp3uxAAWdvz/G9NbTX9AACQAufbAZxvBwAAgHxyhF0IAACALGtRXTPGB1FUqt0x5vGC2z0ZM+E5v53yts77HR3X3TouVq5aa6sTyLmvV62Jex58OgYcd2G07trfOF0IH8zsOiAGnXhR3Hb/Y/H+R8vdxBSF1Ws3xttLlsezMxbF7Q/NLKkP30vN6eIbHo62exxhfpSkH+mw035X1PPBNbc+FdvtckjWr+s+A0+PrfX1Ka3/VjWt/0aNf9l8LqWx22pnxoZNWzxg/ohdD/65uTFH3dS2a9SVlWe8e9p0jm1cb0lF3lEd987KmFps9eh0oPsnjbWo7jfLiUIAAID85K8BAEnx0nGAxNeZXjoO8GcrzAwAaV1r1ppaAAAAIOP2tAsBkLU9zx6mHQAAUuR8O4Dz7QAAAJBPhtuFAAAAyLKW1TUv+yCKSrVO+x4Va9dtKKjdk3XrN0bb3Yf4/ZRX7db35Bg95vHYuGmzLU4gpzZt3hyTXpoVJw8dFtvtMsgYXQBV7Do4jjnrqnhgwnPx+Zdfu4kpeBs3bY0lH3wRL8xaEvc+NqukP3wvpdq519wf5bsMNk9KUgINPvW3RT8vDDljWE6u7X0PPZPymnD6nPfM6VKam/nmMg+cP+LSYXeYG3PU7p17xqKy8qjLQte33ck1l1TUta6uiWcq22dlTC2mju+wl/snrdWs/clPfvJTpwoBAADyj78GACTFS8cBEl9neuk4wF/bzuwAkLa1Zq1pBQAAADLufLsQAFnb8/yVaQcAgBQ53w7gfDsAAADkk1l2IQAAALKsRXW/j30MRaXc8NEPFdwOynm/HuG3U17U6/Bz4qEnpkZ9Q4OtTSBnGhoaY/pr8+KXl98U7fY43PhcAFXtf2ycf9XImDJtdmzavNlNTEHbuGlLvPfRlzF9znvx4LNzY+Q4H7uXmtNx5w2P1l36my8lKcEOOeWaop8bbrzvheiwz1E5eG45Jtau25DSGnHT5q0xesIr5nYpjd1WOzPWb9ziIfQHzJg1z9yYw8a26RR1ZeVZ6Vc77OqaSyrqjuywd9bG1GLp1+26uXfSXIud+rV2qhAAACD/+GsAQFK8dBwg8XWml44D/LUhZgeAtK01a00rAAAAkHET7EIAZG3P8zHTDgAAKXK+HcD5dgAAAMgn33z04N/tRAAAAGRJ+/aD/0VjOVsAACAASURBVKVldU2Dj6GolGu/95GxZt36gtpBmTv/Hb+dclbrrv3juLOvjlfnvG07E8ipRUvej19ff1d0OfA443MB1GPQGXHN8Ptizlt10dDQ6AamYK3fuDmWfPBFTHv93Xjw2bkxcpyP20vpaPj9L8bBx15qzpSkJBt08m9KYp4484q7cnJ9h40ck/K68c26j83xUpqbPuc9D6U/YGt9/bd/8zI/5mhO3nHfqCsrz1qnt9/DdZdUtLVq6unK9lkdVwu9+7fv5N5J933YpV9PJwsBAADyj78GACTFS8cBEl9neuk4wF+70ewAkLa1Zq1pBQAAADLuU7sQAFnb81xu2gEAIEXOtwM43w4AAAD5Zg87EQAAAFnSumv/Ch9CkfrFiLseLrgdlD5Hne+3U1bbfvfDYuhVI+Od9z6yhQnkzObNW+KJSTNiyCmXGZvzvMruh377O40e83h8+MkKNy8Fqb6+IZZ/sSbmLf4kJs9cHPc/PtuH7KUMNOzOSdG93xnmT0lKoUEn/6Zk5os9Bvwi69e3YtfB8clnX6S2lmxoiHsnWj9K6WzUgy/Hug2bPaz+gDMvvt78mKNaNfVcZfuoKyvPSgvKK+KwDj1ce0lF2+Ed98namFoMTato675Jd136ne1kIQAAQP7xlwCApHjpOEDi60wvHQf4a6+aHQDSttasNa0AAABAVmxjJwIg4/udZaYbAACawfl2AOfbAQAAIN+cZycCAAAgS1p26buvD6FI/WLHHkfFuvUbC2oH5bFnp/ntlJWqDzg2rrt1XKxctdbWJZAzyz78NK6+6d7otO9RxuY8rnufk+LSYXfEtFffjM2bt7hxKSiNjY3x1ar1Uffeipj2+rsxYfK8bz/Y7sP1Uma77MZHosM+5ndJSrWBJ11VMnPGFTc/Fq27Dsj6NT7n8uEprzHrlq0w30tp7qXZSz3A/oAnJ79sfsxhp7TfM+rKyrPWvPLK6NnpANdeUlHWqqmnKjtkdVwt5BY1VVnd172TxlpU1dzmZCEAAED+8ZcAgKR46ThA4utMLx0H+Gubm/pXMwRAWtaataYVAAAAyIpD7UQAZHy/c4jpBgCAZnC+HcD5dgAAAMg3D9mJAAAAyJIW1TXH+RCK9MdGj3m8oHZQttbXxy69T/TbKWP1PuKceOiJqbF1a70tSyBnc91TU2bG4adeHq269Dc252E77HVEnHT+72Pso5Nj+Yov3bQUjA2btsRHn62MN+s+iamvLYmHnnszbqud6QP1UpY77bI7YrtdDjGnSlIz6n/ir0tq7qg54YqsX+PWXfvHwneWpbTubGyMGP/0G+Z9KY2NGv9yrFm/yYPt91i7bkOUdbPGzlXlVX3jtfI2UVdWnrVmVbSJ7p16uf6SirLDOvTI6pha6PXodKD7Jp1V1Ux3shAAACD/+EsAQFK8dBwg8XWml44D/L1dzRAAaVlr1ppSAAAAICuusxMBkPH9zutNNwAANIPz7QDOtwMAAEC++dBOBAAAQJa0rO53hQ+hSH9sp17Hx+bNWwpqF2XkPY/47ZTWvvnY5hkXXx9vzF9smxLImXXrN8btD0yMXXqfaGzOs1p16R+9Dj8nfjfi/nht7sLYWl/vhiWvrV2/KT7+bFUsWLo8ps95LyZOnR93PfKqD9FLOe7mMdPikFOu+XZeMb9KUvPqd+KVJTWH/OHOyVGx22FZv84/O+PKlNekH3z6tflfSnNTX1vigfcHfDNmmSNz12Xtdo26svKsNr28bVRVHeT6Syq+v0k0NbGyQ9bH1ULtmA57uW/SWVXNl04WAgAA5B9/BQBIipeOAyS+zvTScYC/d6oZAiAta81aUwoAAABkxVQ7EQAZ3+980XQDAEAzON8O4Hw7AAAA5KP/bTcCAAAgC1pW19ztQyjSnxsz4bmC2kFZvWZdtNvzcL+dmt0uvU+M4aMfii++WmVrEsiZlavWxu9HPBDt9z7S2JxHVR9wbJx1yQ3x8JMvxOdfrnSjkle2bKmPr1atjw+Xr4z573waM954L556aUGMfWpOjHrwZR+bl/KwP9w1OfY+5JfmWElKU/1OvLLk5pJjzr0xJ9f61Tlvp7xufez5+dYBUhq7ZfyMWL12o4fi73H/w8+aI3NYp84HxdtlFVFXVp7VnqlsH22r+vgNJBVdgzv2yPqYWqhd1m5X90ya+z+dBvyH04UAAAD5xV8BAJLipeMAia8zvXQc4O/dboYASMtas9aUAgAAAFnxzcvRfmo3AiBje50/bcoLiwEAaA7n2wGcbwcAAIB8dKDdCAAAgCxoUd1vqo+gSH9ut74nR31DQ0Htolx7yxi/nVKu/3EXxhOTZsTW+npbkkDOrF23Ia6/bXy02/NwY3Me1Ga3w+KoM38dtz8wMeqWfOAGJeu2bK2Ptes3xRcr18XHn62KpR9+EW+982m8Ou/9mPzK4njs+fkx5sk5cVvtTB+Tlwqsi294ODrsc7T5VpLSubdz4q9Lbj4Zfv+L0XHfY7N+rfsde0HKa9wVX621FpDS3JRX3/EA/T2Wr/gyWnXpb57MYTe37Rp1ZeVZb3ybHWO76hq/gaSia2Jlh5yMq4XW6LZV7pc016qq/95OFwIAAOQXfwUASIqXjgMkvs700nGAv/e6GQIgLWvNWlMKAAAAZE2Z3QiAjO11VppmAABoJufbAZxvBwAAgHx0gd0IAACALGhRVfOuj6BIf93jk2YU1C7KylVro90eh/vtlHDt9jw8Lrt2dCxd9rFtSCCn6hsa4v6Hn40dexxlfM5h23QdEH2OOj9+P+KBeOX1t2PLlq1uTr77f7P1DbFh45ZYtWZjfP7V2vhw+cp498MvY8kHX8Q7738eby9Z/n+bu+jjmLPgo2+b/faHMfPNZTF9zrvxwqwlMfmVxfHsjEXx5EsLYuLU+fHwpHkx9qk5cdejr8Wo8S/7OLxUpB0/dERss/NAc68kpbkBP7+qJOeVs668OyfX+7kXX0t5Pf1c0xrYmkBKXyPHzYiVazZ4WP8evQ4/xzyZw/bs1DMWlZVHXQ66pW11tK6u8TtIKqoGdeyRkzG10JpUuYP7Jc21qOp/qtOFAAAA+cVfAACS4qXjAImvM710HODvbWrqn80SAM1ea9aaUgAAACBrBtqNAMjYXuehphkAAJrJ+XYA59sBAAAgH423GwEAAJBpgwf/Y4uqmi0+giL9dQf97LyC20n53Yj7/Xb60XofcU48MOG5WL9ho+1HIOden1cXPQ//pfE5R+3W9+S48OpR8fTzM2PV6rVuyBK1fuOW+GrV+vhw+cqoW7Yi3qz7OGbOXRZTXlkcT7zwdtQ+Ozfue3x2jJ7waowaP8NH2yWl1PX3TI0DjrzQ/Pv/s3ffUVaVecLv35l1577rzr135n3XuvfOdAFqnSLHUxSKCgYUBRSqChBFFMXcGNA2x1bMWRpaEEHFQCNFgwkTCgoNqAgGgpSiKIoJCZJDhedir55Zvj2Gc07tOmefqs9nre/fM13P6f3s/ePpvSWpnhpwzs2Ndo85qPS8rP+9jxh0Qaipqc3o/vv7LTvDWPfVUqTNWlDp4f5n3DV2sn0yx01t0SFUFiZy0o2tu1oDSQ2up1q0z9l1NV9aUVgU9i0u9XuJsIJk6WgHDAEAAOLFvwAApMVLxwFSv8/00nGAn9bRLgFQ53vNCtsJAAAAZM1NphEA9TbrvM02AwBAHTnfDuB8OwAAAMTRh6YRAAAA9axJh/5NfQBF+uneWLw8ryYpG7/fElofcqK103+pQ4+hYeQ9D4ePVn9h5AjEQlV1dbjngSlhn5L+rtNZrFW3weHUETeFJ6a/HNas/cYPsVH8d60mbNy8Paz5amNYvurr8Mb7n4VZCyvD9FfeD5OeXhTunzLfB9gl1Xsj//h0SB59hr1Ykuqxgefc0mj3metGTQ9NO5dn/W/+55mvZXyfPnfxx+4RpAi7f8pf/vrsy3/17rKP7JM5blD7HqGyMJGzLmzbzTpIalD1b39ETq+r+dLBHXv5vUTbK04YAgAAxIt/AQBIi5eOA6R+n+ml4wA/bZhdAqDO95oVthMAAADImpmmEQD1Nut8yTYDAEAdOd8O4Hw7AAAAxFHN3v5vEwkAAIB69JtO/br5+In005064qa8m6aMeWiatdNfa1ZSHspPuzI8Mf3lsHPXbqNGIDa2btsR+p1yuWt1lvaCY4deGu4d/2R4f8WqUFNT6wfYAO3ZUx3WbdwaPvpsXXh72edh1sLKMO3l98JDM970cXVJOe+314wP+x1wnH1Zkuq54357a6Peb3oPvSbrf/OD+p699168KqN7+B0794Tx0xa6V5Ai7JWFHxoQ/NQJ3JrakOx5qr0yhzXd26zmbUJlYSInrdzbsHaHWgtJDappLTrk7LqaL53QvoffSoQVJMu+dMIQAAAgXvwLAEBavHQcIPX7TC8dB/hpf7BLANT5XrPCdgIAAABZ85VpBEC9zTq/sc0AAFBHzrcDON8OAAAAcdXdRAIAAKAeNU2WDfEBFOlnPnTXuTx8+MnneTVJ2blrd9i/9xnWrxF3cL9zwj0PTAlr1vrfmgDxs3v3nnDCOde5XtdjbQ4dEn57+Z2h4tnZ4bsN3/vRNSBbtu8Kn325Mbyzcm14bdGq8NSrS8MjT73l4+mSYtm9k+aEY0651t4sSVlq0PBbG/W+c9v4F8J+BxyX9b/7w1NmZnx/v2jZGvcMUoSNnTI/bN660/DgJ1x8/Wh7ZY47r233UFmYyFnLC4tCaYcjrYWkBlNZhyNyel3Nhy5vc5DfSsQlSgb9q1OGAAAA8WH6D5AWLx0HSP0+00vHAX7aXLsEQJ3vNStsJwAAAJBV/2YiARD5nLPA9gIAQAScbwdwvh0AAADi6nwTCQAAgHrUJFl2tY+fSD/fpSPH5N00peLZ2daukdX6kBPDiGvvC/PefC/U1tYaKQLxnfhfc6/rdj3UY+D54eZRk8LCt5eFqupqP7Q8t3tPVVi3YWuoXP1tmLf4k/DMnGXhoRlv+ki6pLzp2nunhQ5HDrNHS1IWO+Hc2xv9/jP4/Duy/ndP9jw1bNu+M6P7/j1V1eHhGW+5d5Ai7LVFqwwVfsLzry60V+a4omS/sDjRIlQWJnLWkr3/97t37GU9JDWYKlp0yOl1Ne7d37Kz30nUde53oFOGAAAA8WH6D5AWLx0HSP0+00vHAX7aersEQJ3vNStsJwAAAJBVPUwkACKfcx5tewEAIALOtwM43w4AAABxNc5EAgAAoB4VJEvH+/iJ9PMVdj0urFu/Ka+mKTU1taH3iRdbvwbevvsPCMMuvDk8N2t+2LV7tzEiEHtPvTDX9TuqD/EeOCicfP7I8MjU58Oatd/4ceWxLdt3hU++WB/efP+z8Nzry8Okpxf5ELqkvG3M5Hnh5IvuCc1K+tuvJSnLDT7/jka/D9336JzQ6pCTsv63HzVhasbPA8s++so9hBRh455cELbtMCv/e1u37Qj7HTDQfpnjbm59QKgsTOS0BUWtQudOfayHpAZRaYcjc35djXPPtWjrdxJxBcWlpzllCAAAEB+m/wBp8dJxgNTvM710HODn/ZudAqBO95oVthIAAADIqvNNJAAin3P+zvYCAEAEnG8HcL4dAAAA4mqeiQQAAEA9KkiWvuTjJ9Ivd9+DU/NuovLOsg9Ds5Jy69fA+mFNjzvrmvBoxYth/cbNRodA3vj62/Wh3eEnuZbXoWTPU8OIa+8Lz82a/9ePIZN/fviw96drN4S3lq4JM+euCA/PeNNHzyU1mO6Y8FI4ZMBF9mxJylGDz7/TfrS3s68el/W/fatug8N3G77P6BmhprY2TJ652NpJEfaXJZ8YQPyEwb/9vf0yx+3fqU/4oLAoVBYmctpLzduE1sljrYmkBtH05u1zfl2Na+8nmodmxaV+JxFWUFx2m1OGAAAA8WHyD5AWLx0HSP0+00vHAX7eEXYKgDrda1bYSgAAACCrxplIAEQ+55xgewEAIALOtwM43w4AAABxtdFEAgAAoB41SZat9PET6Zcr6XV6qKqqzrupyuU33W/9GkDNSspD+WlXhomTnw3frNtgXAjkndra2nDi8Otd09Nsn5L+YcDpV4X7H5keVq76zA8pz+zeUxXWfLUxLFq2Jjz72vIwcfobPm4uqcE2YuQjoflBg+3fkpTDTrzgTnvS3sZMnhc69z4r63//m+57JONnh1VrvrN2UoQ9MHVB2LFzj8HE3/nh3xfsl7nv8ZYdQ2VhIudNa9EhJJL9rImkvG9Q+x6xuK7Gtc6d+vidRFhBsmyGU4YAAADxYfIPkBYvHQdI/T7TS8cBft4FdgqAOt1rVthKAAAAIKvmmUgARD7nXGh7AQAgAs63AzjfDgAAAHH276YSAAAA9eMfmiTLtvv4ifTrPTtrft5NVDZ9vzV0PGKo9cvDmpWUh7JhV/z1Q5dff7veeBDIa9Off821PcU69BgaLrjm3vD0S/PC95u3+vHkkc1bd4bK1d+GeYs/CVNfejfcP8WHzCU1/O6dNCcce+p19nBJikFDRtxtb/pbl90+Oet//0TXQeGrbzKf4f151nvWToqwN9771KDi73z6+Vf2yxg0sH2PUFmYiEWPtEyGfZKl1kVSXtd0b883bxeba2vcKm9/pN9JhBUUly5zzBAAACA+TP4B0uKl4wCp32d66TjAzxtnpwCo071mha0EAAAAsmqjiQRA5HPOTbYXAAAi4Hw7gPPtAAAAEGdHmkoAAADUg3/r2P//8+ETKbX6n3ZlXk5VnnphrvXLk4oOHBSGXXhz+NOMWWHd+o1GgkCDsHXbjtD56NNc53+hg/qeHa67c0KY9+Z7oaqq2o8mD1RV14Qvv/0+vL3s8/Dsa8vDg9Pe8NFySY2uK+96MrTvMcxeLkkx6aQL77Y//agegy7J+hpceuMfM37GWLv3+cK6SdH14LSFYdfuKgOMv3NY//PsmTmuWXFpeK1561BZmIhFd7XuYl0k5X0ntzs8NtfVuHV+2+5+IxFWkCzd8d/+2/X/6LQhAABAPJj6A6TFS8cBUr/P9NJxgJ83z04BUKd7zQpbCQAAAGTdv5lKAEQ242xqWwEAICLOtwM43w4AAABxdoGpBAAAQD1omuy7vw+fSKm3vHJ1Xk5Wzr7sDusX0zr0GBpGXHtfeG7W/LB12w5jQKDBuXnUJNf7v6uw63FhyLk3hIefnBk+//JbP5I8sKeqOnz+9abw1tI14Zk5y8K4qQt8pFxSo+2+R+eE0jNuCE07l9vXJSlOH5K/6F771I8a+cdnQrOS/lldg327DAgff7o24+eO515fbu2kCHt72ecGGn9n5D0P2zNj0O/aHhwqCxOx6aK23ayLpLyuWXFpeLmoTayurXHp9tb7+41E3L8XD9jXaUMAAIB4MPUHSIuXjgOkfp/ppeMAP2+jnQKgTveaFbYSAAAAyLojTCUAIptxHm1bAQAgIs63AzjfDgAAAHH2gKkEAABAPWiSLB3koydS6l06ckxeTlbWrd8UOvQYag1j0L77DwgDTr8q3Pfg1PDOsg9DTU2t0R/QYK1e82Uo7Hqc6//eftiHR1x7X3hu1vywZdt2P46Y27m7Knzy+fowb/EnYeqL74b7p8z3QXJJ2ttVd08NHY4cZm+XpBg29KJ77VV/V99hv8/6Opxz+Z0ZP4es37Rt77OHdZOiauL0N8KeqmpDjh+Z9+Z79swY1CrZN7yfaB4qCxOxaOXeTml/mLWRlNed1u6w2FxX49QTLTr5fURcQbK0p9OGAAAA8WDqD5AWLx0HSP0+00vHAX7Zb+wWABnfa1bYRgAAACDrLjCVAIhsxnmRbQUAgIg43w7gfDsAAADE2V9MJQAAAOpBQbLsEh89kVKv6MBB4fvNW/NyujLzlQXWMEcd1v+8cO0dD4ZZcxeFbdt3GvUBjcZJ541stNf+pp3LQ+8TLw53jZ0c3lv+UaipqfWDiLEfPrK95quNYcE7q8PUF9/1IXtJ+rtGPfZa6H/WjX/d3zzjSVI8O+Xi++xZf9ftE14K+x1wXNafBd//4OOMn01mLay0dlKEvbNyraHHj+zevSe0OPgE+2YMurdVl1BZmIhNywuLQt8OPa2NpLxtn2RpmFPUOlbX1jg0d+/fxO8j2gqSZec6bQgAABAPpv4AafHScYDU7zO9dBzglx1qtwDI+F6zwjYCAAAAWTfaVAIgshnnWNsKAAARcb4dwPl2AAAAiLNvTCUAAADqQUGydLSPnkjp9fCUmXk7YbnspvutYZZbsrTSaA9olBYsWtrorvnNDzo+DLvw5vDE9JfD19+u9yOIsZra2rBuw9awZMUX4Zk5y8K4Jxf42Lgk/UxX3PVk6HjkaZ7vJCnmDbtklH3rJxo0/Lasr8UpI27K+Fll05YdYeyU+dZOiqiHZ7wVqqprDEJ+5IfZlX0z9x3W8ehQWZiIVUsSLUL3jr2sj6S87bdtD4ndtTXXfVBYFBLJfn4fEVaQLL3PaUMAAIB4MPEHSIuXjgOkfp/ppeMAv+x0uwVAxveaFbYRAAAAyLoXTCUAIptxzrKtAAAQEefbAZxvBwAAgLj7F5MJAACAiDVJlj7roydSeh05aETeTld27d4djjrhQuuYpQ7qe7aRHtBo9Tvl8kZxre905ClhxLX3hedmzQ/btu+08DG2afOO8P6HX4bnXl8exlcs9HFxSfqV7nlkdig7c2Ro2rnc850k5UGnXTra/vVT+9mk2aFltxOzvh7vLPsw42eX2W9+ZO2kCFv60VeGIj/yyNTn7ZsxaXrz9qGyMBGrXi9qHdp3Otb6SMrL9isuDfOLWsbu2prrunfs5fcRYQXFZTOdNgQAAIgHE3+AtHjpOEDq95leOg7wy26xWwBkfK9ZYRsBAACArPvIVAIgshnnatsKAAARcb4dwPl2AAAAiLtikwkAAICIFRSXvuejJ1L6LVlambcTlg8/+Tw0P+h465iFrrtzgpEe0Ci9MHthg76+9xlycRg1YWpYXul/2xdne6qqw+dfbwrzFn8SHn3mbR8Sl6Q0Ov/6h0Kr7kM810lSHnXaZaPtYT/TsEtGZX09hpx7Q8bPMlu27Qrjnpxv7aSImvT0olBdU2tQ8jdr1n5j34xJQ9sfFioLE7HruRZtQ/PiftZIUl42ok23WF5bc9ng9of7bURYQXGZlykDAADEhIk/QFq8dBwg9ftMLx0H+GVT7RYAGd9rVthGAAAAIOuq9vZPJhMAdZ5v/u97q7atAAAQEefbAZxvBwAAAHNMAACAxqYgWfq9j55I6XfpyDF5PWV55uW/hKady61lPffWux8Y6QGNTnVNTegx8PwGdT1vVlIeyk+7Mtz/yPSwes2XFjnGvt2wNby97PMw/ZX3w9gpPkIvSel2+4MvhiNOuNTznCTlYadf/kd72c80+vHXQ7sep2Z9Td5csjzjZ5vXF62ydlKEffDJN4YmP3JI+XB7Zwzap7g0LChqFSoLE7HrsZad9v7/Z40k5V+JZL/wRqJlLK+tuerStgf7bURZsqyqpORsL1MGAACIAdN+AC/rAain+0wvHQf4Ze/YLQAyvtessI0AAABAThSZTADUeb7ZynYCAECEnG8HcL4dAAAA4u4qkwkAAIAI7dup7H/44ImUWS0OPiFs2bY9ryctt//xcWtZj3UvGx5qa2uN9IBG508zZjWMj9qW9A/lp10ZJk5+Nnz73UYLG1NV1TXh07UbwmuLVoVHnnrLh8IlKcPGTJ4Xzrzy/pA4YJDnOUnK08644o/2tF9o+LXjs74mJ5xzXcbPOtt27A4PTF1g7aSIevzZt83rf+S6OyfYO2PS1W0ODJWFiVh2b6su1khSXnZp24Nje23NRaNalfhdRFxBx/KWTh0CAADknmk/QFq8dBwg9ftMLx0H+GVb7RYAGd9rVthGAAAAICd6m0wA1Hm+2dd2AgBAhJxvB3C+HQAAAOLuIZMJAACACDVJ9u/kYydS5j3+55fyetJSU1Mbhl14s7Wsp/4w0TttgMZnz56qcECfM/P22l104KBw5iW3hxnPvx42b9lmQWNq89adYfmqr8PMuSvCuCd9ZF6S6to190wLJX3O8RwnSXneWVeNta/9QmMmzwude52V9XVZ+PayjJ995i3+xNpJEfbRZ+sMVf7mtQVL7J0xqUOnY8KKwqJQWZiIZVe1Ocg6Scq7Wib7hcWJFrG9tma76c3b+11EXEHn8r5OHQIAAOSeaT9AWrx0HCD1+0wvHQf4df9mxwDI6F7TC0gAAAAgN843mQCo83zzItsJAAARcr4dwPl2AAAAiLu5JhMAAAARKiguLfWxEynz+px0Sd5PW7Zu2xH6DLnYekZc0YGDwncbvjfOAxqdx6a9mHfX7H1K+och514fKp6dHbZs224RY6i2NoSv1m0O899ZHZ54brEPgUtSRN0x8eVwzCnXhqadyz3HSVID6LfXjLe//UqX3Pp41tdlwBlXZ/wstH3n7vDA1AXWToqoKS+8Y8jyNzt37f7rv2PYP+PR+JbFobIwEctW7u2MdodaJ0l511VtDozttTXbvZVo4TcReaW/c+oQAAAg90z7AdLipeMAqd9neuk4wK/rZscAyOhes8IWAgAAADlxn8kEQJ3nm2NsJwAARMj5dgDn2wEAACDuvjSZAAAAiFDT4rILfOhEqluVq9bk/cRl/cbN4ZDy4dYzwq6+7QGjPKDRqaqqDgcee1beXKt7DDw/3P/I9PDtdxstXgzV1taGr9ZtDvMWfxIefuotH/+WpAgb/cTccOaV94cWBw/2/CZJDajzrp9on0uhbuUjsr428958L+NnowXvrLZuUoStXrvB0OVvTjpvpP0zJvXpcGSoLEzEthWFRaGs/RHWSlJe1Tp5bHinsHmsr6/Z7Ie/h99FlJWOdeoQAAAg90z6AdLipeMAqd9neuk4wK872Y4BkNG9ZoUtBAAAAHLiaZMJgDrPN2faTgAAiJDz7QDOtwMAAEDcxw4LoAAAIABJREFU1e7t/zCdAAAAiEiT4tK7fehEqlu3jn6sQUxdPv38q9DpyFOsaQTtu/+A8NkXXxvlAY3O439+KfbX6O5lw8M9D0wJq9d8acFiqKq6Jny6dkN4ZeGH4cFpb/jYtyTVQ5ffMSUkjzrDs5skNcBGjHzEXpdC1947LTTtXJ7VtSk99fKMn5N27toTxk9baO2kiJr64rsGMH/z0J+es3/GqBebtw2VhYnYtiTRPBzW8WhrJSmvuqFN11hfW7NZzw5H+U1EWbL0VacOAQAAcs+kHyAtXjoOkPp9ppeOA/y6q+0YABnda1bYQgAAACAn3jGZAKjzfHOp7QQAgAg53w7gfDsAAADkgxamEwAAABEpKC6b5mMnUt06oM+ZoaamtkFMXT746NPQocdQ61rHrr3jQSM8oNHZs6cqdD3mzFhelwu7HhfOvfLusGDR0lBbW2uxYmbnrqpQufrb8NL8lWF8hQ/FS1J9ddv4F8NRJ17hmU2SGnAX3/yYPS/FeuZgT5wzf0nGz01vvP+ZdZMi7POvNxnI7PXJZ1/aP2PUOW0PCZWFiVi3oKhVSCaPsV6S8qb2yWPD+4nmsb++ZqPT2h3mNxFlydLPnToEAADIPZN+gLR46ThA6veZXjoO8OvG2TEAMrrXrLCFAAAAQE6sN5kAqPN800saAACIkvPtAM63AwAAQD44wnQCAAAgIgXFZYt87ESqewsWLW0wk5fllatDu8NPsq4Z1rr7iWH9xs1GeECj88T0l2N3TU72PDX8YWJF2LDJdTlutmzbFd6r/DLMeHVpuH/KfB/0lqR67J5Js8Og4beF/Q44zjObJDXwLr1tsr0vxW4e+1xoVtI/q+tzzMmXhtra2oyeoXbtrgoT/vyGtZMi6qlXlxrO/M2Bx55lD41JiWS/sDjRIlQWJmLdcy3ahqK9/79aM0n50m2t94/9tTUbXdfmQL+HaKv9TUnff3byEAAAILdM+QHS4qXjAKnfZ3rpOMCvm2nHAMjoXrPCFgIAAAA583+aTgBkPNv8v2wjAABEzPl2AOfbAQAAIB8MM50AAACISJPi0m996ESqexdfP7pBTV+Wrvw4tDv8JGubQY9Mfd74Dmh09uypCl2POTM21+If/n+ZPP3lsHv3HosTI5u37gzvVX4Zpr/yvg94S1IWGv3E3HDGFX8MLbsP8awmSY2kK+560h6YRmWnj8z6Gs2auyjjZ6pFy9ZYNynCvlm/xbBmr8tuut8eGqNuaXNAqCxMxL6JLZOhWXGpNZOUFyWTx4TlhUV5cX2tz8a1KvZ7iLx+HZ08BAAAyC1TfoC0eOk4QOr3mV46DvDrltoxADK616ywhQAAAEDOtDKdAMh4ttnWNgIAQMScbwdwvh0AAADywXWmEwAAABH4TUnff25SXFbrIydS3Wvd/cSwc9fuBjWB+Wj1F2H/3mdY3zQqPfXyUFNTa3wHNDpTnn4lFtfhVt0Gh7GTZoRdu3dblJjYuHl7eGvpmvDEzMU+2C1JWeyimx4NnXqe7jlNkhpZ19wzzT6YRndMeCnsd8BxWV2jXif+LtTWZjY/3L2nOkyc/oa1kyLq5QWVBjd7PTdrvj00Ru3fqU/4oLAoVBYmYt/vWx9ozSTlTfe06pIX19b67Nnm7fwWom+g04cAAAC5ZcoPkBYvHQdI/T7TS8cBft0mOwZARveaFbYQAAAAyJmjTCcAMp5t9rKNAAAQMefbAZxvBwAAgHzwoOkEAABABH5T0re1D5xI0fX0S/Ma3BRm7dfrwmH9z7O+KdSq2+Cwes2XRndAo1NTUxsO7X9uzq/Dhw84L6z69AsLEgNbtu8K71V+Gaa/8r6PdEtSlrtu1PTQrfwCz2iS1Ej7/agZ9sM0G3jOLVlfpxdmL8z4eWvJii+smxRR90+ZHzZv3dno5zibvt8a9inpbx+NUU+07BQqCxN50dntDrFmkvKiLh37hBV5cm2trxYnWvgtRF2y31VOHwIAAOSW05oAafHScYDU7zO9dBwgNf9i1wBI+16zwvYBAAAAOXO66QRAxrPNs2wjAABEzPl2AOfbAQAAIB+8ZDoBAAAQgaady3r5yIkUXadddEuDnMRs2LQ5DDj9Kmv8Kz3z8l+M7YBG6flXF+b8Gtz6kBPDmrXfWIwc2rlrT1i+6usw/ZX3fZhbknLQTfc/G4466crQtHO55zNJasTdMOYZ+2Ka3fXwrJA4cFBW1+nIQSNCTU1tRs9ee6qqw8Mz3rR2UkT9ZclqQ529jjn5UvtojBrUvkeoLEzkRcsKi0LvDj2tm6S86I+tOufN9bW+apXs67cQZcmyh50+BAAAyC0TfoC0eOk4QOr3mV46DpCadnYNgLTvNStsHwAAAJAzN5hOAGQ827zRNgIAQMScbwdwvh0AAADywQrTCQAAgAg06Vx+to+cSNGV6DoobNm2vUFOY/bsqQqX3vhH6/wzXXfnBCM7oNHqc9IlOb8Oz3j+dQuRA7t2V4XK1d+GmXNXhLFT5vsYtyTloFsfeD4cc+q1oVlJf89mkqRw87iZ9scMOuG8O7K+Vs/Omp/xs9i7K9daNymixk9b+Nf5RmN3+x8ft4/GqH32Nr+oZagsTORFi4pahP079bF2kmLfwR17hQ8Ki/Lm+lofHdHxaL+FCCsoLn3d6UMAAIDccooTIC1eOg6Q+n2ml44DpKaXXQMg7XvNCtsHAAAA5MxE0wmAjGebD9lGAACImPPtAM63AwAAQD7YYjoBAAAQgYLislt95ESKthnPv96gpzIP/em5sO/+A6z1jzrtoltCdU2NkR3QKM19492cX4dPHH69hciiquqasGrNd2Hm3BVh3JPzfYBbknLUnQ/NCgPPuSXs22Wg5zJJ0n922/gX7JMZdO+kOaFFt8FZXaseA88PNTW1GT2XVe99Lpv09CJrJ0XUkhVfNPp5z8K3l9lHY9Y1bQ4MlYWJvGlW8zahVbKvtZMU+x5sWZxX19eoG9rucL+DKEuWrXH6EAAAILec6ARIi5eOA6R+n+ml4wCpOcWuAZD2vWaF7QMAAABy5jnTCYCMZ5vP20YAAIiY8+0AzrcDAABAvvhnEwoAAIA6KigunewjJ1K0nf67Wxv8VOadZR+GA489y3rvrfy0K8OOnbuM6oBG6/izr8vpdXi/AwaGjz9dayHqWVV1TVi15rvwwrwPwripC3xwW5Jy2N0PvRIGn39HSHQ93jOZJOm/dOdDs+yXGXbyRfdmfb1enPNGxs9pSz/6yrpJEfXIU2+F6praRj372bOnKrTsdoK9NEYVdzomrEgUhcrCRN70RItOYR9rJynmHdrx6LAyj66tUXd5m4P8DiKttKZ5897/3QlEAACA3HG6EyAtXjoOkPp9ppeOA6TmMrsGQNr3mhW2DwAAAMiZRaYTABnPNhfbRgAAiJjz7QDOtwMAAEC+2M+EAgAAoI6aFJfN94ETKdoSXQeFrdt2NPjJzPebt4YzL7m9Ua91+WlXNoq1Bvg57y77KOfX4ptHTbIQ9aS2NoSv1m0Ory1aFR6cttBHtiUpx9350KwwaPhte585j/fsLUn62e55ZLZ9M8Pue3ROaNV9SFbXq9eJv9v77FWb0TNbdU1teOzZt62dFFErV3/b6GdBp4y4yV4asx5r2SlUFibyqntbdbF2kmLfpBb5d32NqlGtSvwGIq6gY3lLJxABAAByx0lPgLR46ThA6veZXjoOkJq77RoAad9rVtg+AAAAIGfWmE4AZDzb/MI2AgBAxJxvB3C+HQAAAPJFVxMKAACAOiooLv3CB06k6HvqhbmNZkIz/fnXQtvDTmp0azz4t78PW7ftMKIDGrUzLr4tp9fiNocOCZu3bLMQEdu0ZUd48/3PwqPPLPJRbUmKQXdMeCkMPOfmUNj1OM/bkqRfbdTjr9k/69Cwy/6Q9TV7dd7bGT+/rfj4a+smRdSUF95p9DOhiZOftZfGrBPa9QiVhYm867y23a2fpFjXs8NReXl9jaKKFh38BiKuaXG/3k4gAgAA5I4TnwBp8dJxgNTvM710HCA1j9s1ANK+16ywfQAAAEDO7DSdAMhorvkPe9tlGwEAIGLOtwM43w4AAAD5otSEAgAAoA5KSs7+pybJ0mofOJGi74yLb2tUU5pv1m0Ip110S6NZ30tHjglVVdXGc0CjtnrNl6FZSXlOr8f3PTjVQkRk1+6qULn62/DMnGU+pC1JMemOiS+HgefcEvY74DjP2ZKklBszeZ59tA6Nfvz10O7wU7K6Zn2HXpbxs1xNTW149JlF1k6KqDVfbWzU86EPP15jL41Z++xtQVGrUFmYyKtWJIrCwPY9rKGkWPenFh3z7voaRfOLWlr/iCtIlp3rFCIAAEDuOP0JkBYvHQdI/T7TS8cBUjPLrgGQ9r1mhe0DAAAAcupfTSgA0p5r/k/bBwAA9cD5dgDn2wEAACBfnGVCAQAAUAf7dBmQ8HETqX4qOnBQ2LZ9Z6Ob1syauygc1PfsBruuhV2PCw8/OdNYDmCva24bn9NrcrvDTwpbtm23EHVQW1sbPv96U3hl4YfhgakLfDxbkmLSzeOeD/1O+33YZ/8Bnq8lSWnVrKS/vTSCzrpqbNbXbu4b72b8bLf0w6+smxRRz8xZ1ujnRSW9Trenxqzr2hwYKgsTedc7hc1D9469rKGk2HZsh555eX2tayv3lkj28xuItNK7nUIEAADIHSdBAdLipeMAqd9neuk4QGres2sApH2vWWH7AAAAgJxqaUIBkPZcs7XtAwCAeuB8O4Dz7QAAAJAvrjWhAAAAqIMmnUp7+LCJVH+9MHtho5zY7Ny1O4yaMDW07n5ig1rPQ8qHh6UrPzaSA9hr0/dbQ4uDT8jpdXnMQ9MsRIY2fL89LHzv0/DQjDd9MFuSYtQ19/05HHXiFaFZSX/P1JKkjNrvgOPsqRE0+om5of0Rw7K6dgPOuDrjZ7zq6prwyFNvWTspor7buK1Rz40u+v0f7Kkxq7jTMWFFoihUFibyrteLWof2yWOto6TY9lSL9nl5fa1r3Tr2tv4RVpAsm+EUIgAAQO44EQqQFi8dB0j9PtNLxwFS87VdAyDte80K2wcAAADkVHcTCoC055qH2T4AAKgHzrcDON8OAAAA+WK0CQUAAEAdFBSXnubjJlL9dfH1oxv15Gbj91vCLX94NBQdOCiv13HfLgPCdXdOCNt37DSOA/iP6fzEaTm9NnfoMTRs3bbDQqRh6/ZdYcmKL8LkmUt8IFuSYtYVdz0ZDhv4O8/RkqQ6V3TwCfbWiDr32gezvn5vLlme8TPfuyvXWjcpol5Z+GGjniFVPDvbnhrDnmjZKVQWJvKyPzdvH/YtLrWOkmLZie0Pz9vra106rn0P6x9ppe86hQgAAJA7TocCpMVLxwFSv8/00nGA1FTv7R/tHABp3WtW2D4AAAAgpwaaUAD4N3QAAGLB+XYAz+YAAACQL6aaUAAAANRBk+KyG3zYRKq/Oh15SqipqW30E5xv1m0IN4+aFFp3PzH/PqI1/PrwwUefGsMB/EhVVXXo0vv0nF6fx06aYSFSUFtbGz7/elN4af7KMHbKfB/GlqQYNfrx18M51zwQkkef4flZkhRZrboPsc9G1JjJ80JxrzOzPovM1J69z+oPTX/T2kkRNPbJ+WHr9l2Ndp709bfr7akxbHD7w0NlYSJvG92qs3WUFMuaFZeG2UWt8/oam0kj2nSz/lGWLNviFCIAAEDuOCkKkBYvHQdI/T7TS8cBUvc/7RwAad1rVtg6AAAAIKfONqEASHuuOdz2AQBAPXC+HcD5dgAAAMgXr5hQAAAA1EGTZNnDPm4i1W/vLvvICOdvtmzdHu6fNCMc3O+c2K9bv1MuD68tWGLRAH7C9Odfy+k1Otnz1LBj5y4L8Qs2bdkRFr73aXh4hg+qS1LcumPiy2HIiLtCq0NO8swsSYq8tocNtd9G2IiRD2d9DZcsrcz4WfDt5Z9bNymiFr77aaOeLR1SPty+GrP22duColahsjCRtw1v191aSopl57Q9JK+vr5l0e+v9rX3E/aak7//jJCIAAEBuODEKkBYvHQdI/T7TS8cBUldo5wBI616zwtYBAAAAOXW5CQVA2nPNq2wfAADUA+fbAZxvBwAAgHzxtgkFAABAHRQky2b7sIlUv901drIRzt+pra0Nc994Nwy/4q7Q/KDj4/NBwpL+4bSLbglvLF5ukQB+Qe8TL87p9frBJ56xCD+huromrFrzXXhmzjIfv5akGHbtvdNC75OvDvvsP8CzsiSp3upw5DD7boSNmTwvlPQ5J6treMqImzJ+Lty9pzpM+PMb1k6KoAenLdz736mqRjtnuvKWcfbVGHZ9666hsjCRt60oLAp9OhxpLSXFrsJkaXgj0TKvr7Hp9ljLTtY+4pp2Kj/ASUQAAIDccHoUIC1eOg6Q+n2ml44DpK7YzgGQ1r1mha0DAAAAcupWEwqAtOead9g+AACoB863AzjfDgAAAPniYxMKAACAOihIln7swyZS/dbrxN8Z4fyCbdt3hqdenBfOuPi20Krb4Jys0RGDLgh/mFgRvlm3wYIA/IqFby/L6b7a+ejTws5duy3Ej2z4fntY+N6nYeJ0H06XpLg1+vHXw7nXPhj2P2a452NJUlYq7nWmPTjiLrr50ex+iL1zeVi68uOMnxHffP8z6yZF1Lsr1zbaedOzs+bbV2NYl059wgeFRaGyMJG3LSpq8df/HNZTUty6rO1BeX19TbdZzdtY94grKC4d7CQiAABAbjhFCpAWLx0HSP0+00vHAVJ3hJ0DIK17zQpbBwAAAOTUWBMKgLTnmuNtHwAA1APn2wGcbwcAAIB8sd6EAgAAIGPX/2NBceluHzaR6v8jqF9/u94YJwV79lSFBYuWhltHPxYGnH5VKDpwUL2sSatug8PQC24MDzz2dPj086/84QHSMOzCm3O6r4579CmLsNfuvXvm8lVfh6kvvusj15IUw24b/2IYfP4doWX3IZ6LJUlZrWvf4fbiiBszeV7o0vvsrK7jmZfcnvHz4s5dVWH8tIXWToqgSU8vCjU1tY3zZO7GzX/99y17a/ya3KJjqCxM5HUzm7cLiWQ/6ykpVrVM9g1LEi3y/hqbau8nmoem1j3akmVXO4sIAACQG06UAqTFS8cBUr/P9NJxgNQNsHMApHWvWWHrAAAAgJyaYkIBkPZcc6rtAwCAeuB8O4Dz7QAAAJAvqvf2D6YUAAAAGWjSoX9THzWRstMT0182xslAVVV1eP+Dj0PFs7PDLaMmhWEX3hx6Hn9haH/4ySn93ZsfdHzoMfD8MPSCG8MNdz8Upj4zOyxb+Umoqq72xwXIwCeffRmaleTuY7qtDzkxbNm2vVGvwZfrNodXFn4Yxk1d4OPWkhSzRk+eFy688ZFw2MDfhWY+Pi9JylHdykfYl+uhC2+alNV1/OHZu3LVmoyfHRe8s9q6SRH10WfrGu0c6od/j7G3xq8h7Q8PlYWJvO/+lp2tp6TYdVPrrg3iGptq7Tsda90jrKC4dILTiAAAALnhdC9AWrx0HCD1+0wvHQdI3Rl2DoC07jUrbB0AAACQUy+aUACkPdf0Ym0AAOqD8+0AzrcDAABAPvkXUwoAAIAM/KZTv24+aiJlp7Mvu8MIJ2K7du8O6zduDp998XV4/4OP/7OPVn8Rvlm3IezYucsfCSBiV906Lqf76a2jH2uUf/fde6rD8lVfhydfeMfHrCUpht02/oVw8kX3hLaHDfX8K0nKeT2Ov8T+XE916fPbrK7leVfdnfFz5Pade8IDUxdYNymCfpjHNFbX3zXR3hrD9ikuDQuLWoXKwkTed1HbbtZUUqzq1OnYsLywqEFcY1OpZ4ejrHuUJUtfdRoRAAAgN5zuBUiLl44DpH6f6aXjAKm7xM4BkNa9ZoWtAwAAAHLqTRMKgLTnmotsHwAA1APn2wGcbwcAAIB8so8pBQAAQAaaJsuG+KiJlJ3aH35yqKmpNcYBIG9t+n5raH7Q8TnbSwu7Hhe+WbehUf3NN3y/Pcxb/EkYX7HQR6wlKWaNfvz1cMHIh8IhAy8KTTuXe+6VJMWmo0660l5dT4248ZGsruU+Jf3DJ599mfEz5Q/Pk9ZNiqa133zfKOeBs+YusrfGtBvadA2VhYm8b0WiKPRvf4Q1lRSr/tCqpEFcY1NpaPvDrHmklX7qNCIAAEBuOOELkBYvHQdI/T7TS8cBUneTnQMgrXvNClsHAAAA5FSlCQVA2nPNj2wfAADUA+fbAZxvBwAAgHzSyZQCAAAgA02S/a7yQRMpey1d+bExDgB5a/TEaTndRy+5YUyj+DtXVdeElZ98E6a9/J6PVktSDLvmnopQdvrI0PygwZ5zJUmx7Nhh19mz66kxk+eFzr3Pyup6XvT7P2T8fLl1+64w7sn51k6KoOdeX9Eo54Fbtm4P+3YZYH+NYV069gkfFBaFysJE3rc40SLs36mPdZUUmw7q2LvBXGN/rUvbHmzNoyxZWl1ScvY/OZEIAACQfU74AqTFS8cBUr/P9NJxgDT+56d2DoC07jUrbB0AAACQU1+ZUACkPdf8xvYBAEA9cL4dwPl2AAAAyCeHmFIAAABkoCBZ+oCPmkjZa+ykGcY4AOSlqqrq0KX36TnbQ5t2Lg8ffvJ5g/4bb9qyIyx879MwcfqbPlYtSTHr9gdfDMMuGRU69zrLs60kKfaVn3mj/bseGzHy4ayu5777DwhffLUu42fNOW+tsm5SRG3cvKNRzgX7Dr3M/hrT/tSiY6gsTDSIXm7eNrRM9rOukmLTpJbJBnON/aXuad3Fekdcs5LyIicSAQAAss8pX4C0eOk4QOr3mV46DpC6CXYOgLTuNStsHQAAAJBT35tQAKQ919xi+wAAoB443w7gfDsAAADkk16mFAAAABkoSJa96IMmUvYacu4NxjgA5KVpz83J6R467MKbG+TftaamNnz8+Xfh6dnLfJxakmLWPZNmh+HXjg+HDLgoNOtc7plWkpQ3DRp+m728HhszeV4o7nVmVtf0+rsmZvzcuXnrzjB2ynxrJ0XQvMWfNMq54G1jHre/xrST2x0eKgsTDaaJLZOhqXWVFJP6dOjZoK6xP9fkFh2td8T9JtnvKCcSAQAAss8pX4C0eOk4QOr3mV46DpC6yXYOgLTuNStsHQAAAJBTe0woANKea1bZPgAAqAfOtwM43w4AAAD5pNyUAgAAIANNkmUrfdBEyl7NDzo+7N69xygHgLxz9OCLcrqHvvXuBw3q77lj556wZMUX4dGnF/kotSTFqFGPvxYuvGlS6HXyVWG/A47zHCtJystOGnGXfb2eu+CGh7O6pi0OPiFs2LQ542fQVxZ+aN2kCBo/bWHYvafxvefp9YXv2F9j2r7FpeGNRMtQWZhoMF3R5mBrKyk2TW/evkFdY3+q2UWtrXX0neNEIgAAQPY55QuQFi8dB0j9PtNLxwFSN8POAZDWvWaFrQMAAABy7n8zpQBIeab5320bAADUE+fbAZxvBwAAgHwyxJQCAAAgff/QJFm23cdMpOz2xuLlRjkA5JX5i97P6d7Z75TLG8zfct3GreG1RavCA1MX+Bi1JMWk0Y+/Hi666dFw9ElXhsQBgzy3SpLyvmGXjLLH13NjJs8LxUefmdV1vXf8kxk/i27cvCPcP8W6SVH0XuWXjW42uG37zrBvlwH22Jg2svUBobIw0WD6oLAoHNe+h7WVFItO2Hs9akjX2J9q+d7rbrPiUusdZcnSOxxJBAAAyD4nfQHS4qXjAKnfZ3rpOEDqXrJzAKR1r1lh6wAAAICc+xdTCoCUZ5r/w7YBAEA9cb4dwPl2AAAAyCdnmlIAAACk6d+Tg/5fHzORst9dYycb5QCQV04dcVNO984XZi/M679fTU1tWLXmu/DMnGU+Pi1JMWnU46+FC2+aFPoMvToUHXyCZ1VJUoPqrCvH2u+z0PnXP5TVde3QY2jYsXNXxs+mL81fad2kCHr82bdDbW3jmw/2HXqZPTamde3UO6wsTITKBtSSRPNwUMfe1ldSzmu6t5eat2lQ19ifqlOnY613lCXLpjiVCAAAkH1O+gKkxUvHAVK/z/TScYDUzbNzAKR1r1lh6wAAAICc+3dTCoCUZ5oFtg0AAOqJ8+0AzrcDAABAPhlhSgEAAJCmZsWlXXzMRMp+A8642igHgLyxes2XoVlJec72zUPKh4eamvz8UvGOnXvCkhVfhElPL/LRaUmKQfdMmh3O+/2E0HPw5aGw63GeTyVJDbbh102w92ehMZPnheTRZ2R1bR+eMjPjZ9TvNm2zblJEfbp2Q6ObEd4yapI9NsY92aJDqCxMNKheLWoTWib7WV9JOe+sdoc0uGvs39e7Q09rHWmlC5xKBAAAyD6nfQHS4qXjAKnfZ3rpOEDqFts5ANK616ywdQAAAEDOFZpSAKQ802xu2wAAoJ443w7gfDsAAADkkytMKQAAANLUpLhsoA+ZSNmv+UHHh6qqauMcAPLC9XdNzOm++cT0l/Pub7Zuw9bwysIPw7gnF/jQtCTluDsmvBTOumpsOPy4i8O+XQZ6JpUkNYouvPER9wFZ6vzrs/vMfOCxZ4Wq6sxnyzPnrrBuUgQ9M2dZo5sRvjrvbXtsjBva7vBQWZhocD3QqrP1lZTz9ikuDfOKWjXI6+x/dGq7Q611hBUUl37hVCIAAED2Oe0LkBYvHQdI/T7TS8cBUrfCzgGQ1r1mha0DAAAAcq6dKQVAyjPNjrYNAADqifPtAM63AwAAQD65wZQCAAAgTQXFpRf7mImUm95b/pFxDgCxt33HztDm0CE52y87HjE07Nq9Oy/+VrW1IXy6dkN46tWlPi4tSTlszOR54br7pocTL7gzdDnmnNC0c7lnUElSo+vS255wX5DFe49OR52R1fWd8fzrGT+7frN+i3WTImrD99sb1Zxwy9btYZ+S/vbZmLZvcWl4K9EiVBYmGlwXtO1ujSXlvEvaHNyPMTWgAAAgAElEQVQgr7H/0ZVtDrLOUZYsrS4pOfufnEwEAADILid+AdLipeMAqd9neuk4QOo+tXMApHWvWWHrAAAAgJzb35QCIOWZZlfbBgAA9cT5dgDn2wEAACCf3GVKAQAAkKaCZOloHzNpOJ103kh/hzzqoT89Z5wDQOw9/ueXcrpf3nn/5Nj/japrakLl6m/Dn55f4oPSkpSj7nt0Trjo5kdD32G/D60PPckzpySp0XfV3VPdI2Sx834/Iavr2/P4C0NtbW3Gz7EzXl1q3aQIev3tjxvdrLDPkIvtszHu9tb7h8rCRINrRWFR6NOhpzWWlNNaJvuFxYkWDfI6+0P3tSqxzhH3b53K9nMyEQAAILuc+AVIi5eOA6R+n+ml4wCpW2vnAEjrXrPC1gEAAAA5d7ApBUDKM83utg0AAOqJ8+0AzrcDAABAPrnPlAIAACBNTZJlz/iQSQP5gE+3E8K27TvDYf3P8/fIk8698m7jHABi78hBI3K2V+67/4Dw9bfrY/u32bFrT1iy4ovwyFNv+ZC0JOWgm8fNDMMuGRW6lY8I+3YZ6DlTkqQfdf3op9wvZLHRk+eFDkcOy+oaz/7L4oyfZz9du8G6SRH0wNQFYefuqkY1K7zh7ofsszGuR8ejQ2VhokH2RlHL0KHTMdZZUk67oU3XBnud/VOLjtY44poWlx7qZCIAAEB2OfELkBYvHQdI/T7TS8cBUveNnQMgrXvNClsHAAAA5NwhphQAKc80D7dtAABQT5xvB3C+HQAAAPLJGFMKAACANBUUl77nQyYNo8MHnPfXp+PllatDousgf5M86IA+ZxrnABBrC99eltO98ryr74nl32Xj5u1hzlurwripC3xAWpKy2B0TXgrDrx0fep18VWjZfYjnSkmSfqGbxz7n/iHLnXXV2Kyu8cAzr67Ts+2fnl9i3aQIenfl2kY1L3z59bfsszHv+ebtQmVhokH2ZIsOYR9rLCmHtU8eG5YmihrkNXZ2UWtrHHn9TnYyEQAAILuc+gVIi5eOA6R+n+ml4wCp+87OAZDWvWaFrQMAAABy7nBTCoCUZ5pH2jYAAKgnzrcDON8OAAAA+WSsKQUAAECaCpKl3/uIScNoyLk3/OcT8mPTXvQ3yZO++ma9kQ4AsXXWpbfndJ98d9lHsfp7fLVuc5g5d4UPRktSlrrzoVnhwpsmhYHn3BK69D47NO1c7jlSkqQUu2PCS+4nstzoJ+aGNocNzeo6v/3eyoyfcT/45BvrJkXQo88sCrW1tY1mXrjp+62hWYlnszg3ok23UFmYaLBd37qrdZaU0+5t1aVBXl+XJopCU+sbbcmyq51MBAAAyC6nfgHS4qXjAKnfZ3rpOEDqNto5ANK616ywdQAAAEDO9TSlAEh5pnm0bQMAgHrifDuA8+0AAACQT8abUgAAAKQhUTLoX33EpOF06Y1//F+eks+76m5/lzzouVnzjXQAiKWvvlkf9u0yIGd7ZL9TLo/F36GmpjasWvNdmPbyez4ULUn13J0PzQojRj4cys4cGZJHnRGadvahdkmSMu2eSbPdX+SgYZeMyuo6n3HxrXV63p309CLrJkXQZ19ubFRzw6NOuNBeG+PadOoblhUWhcrCRINs5d5OaN/DWkvKWQd26h0+aKDX2fbJY61xhBUkSx9wOhEAACC7nPwFSIuXjgOkfp/ppeMAqdti5wBI616zwtYBAAAAOdfLlAIg5ZlmH9sGAAD1xPl2AOfbAQAAIJ88ZEoBAACQhibF/Tr6iEnD6d7xT/4vT8lbt+0Ih5QP97eJeSPvedhIB4BYuvP+yTndI596cV5O//Pv3lMVlnzwhQ+MS1I9dtPYZ8M5V48Lx5x6bejU87TQtHO550RJkiJq9OR57jdy0H2Pzgktug3O2jo3KykPH63+IuNn3yUrvrBuUgQ99/ryRjU3vO7OCfbamDexZTJUFiYabIsTLcL+nfpYa0m5u862apjX2R4dj7a+EVZQXPqC04kAAADZ5eQvQFq8dBwg9ftMLx0HSN12OwdAWveaFbYOAAAAyLljTSkAUp5p9rVtAABQT5xvB3C+HQAAAPLJJFMKAACANBQUl/XzEZOG09RnZv+XJ+UVH34aEl0H+fvEuEFnX2ukA0Ds7N69JyR7npqz/bGk1+mhqqo6J//Zd+zaE95auiZM+PMbPgotSRF276Q54Yo7p4RTLr4vHHH8ZaFl9yGeCSVJqqf27TLQ/UcOGzLirqyu98XXj878+X9PdXhwmudfKYo2bdnRaGaHz7+60H4b8wa27xEqCxMNuheatw2JZD/rLSknHdnxqAZ5bT2hXQ/rG2EFxWXLnU4EAADILqd/AdLipeMAqd9neuk4QBpHU+0cAGnda1bYOgAAACDnSk0pAFKeaZbZNgAAqCfOtwM43w4AAAD55AlTCgAAgDQ0LS67wEdMGk4LFi396afl6S/7+8S4NocOCbW1tcY6AMTKn2e+ltP9cfTEaVn/z7xl+64wb/En4YGpC3wIWpLq2Ogn5oYbRj8VzrnmgVB25sjQpffZoVnncs+AkiRlqeYHDXZPksPueWR2SBx4fNbWe9/9B4S1X6/L+Hl4/jurrZsUQQv2/nepsVi3fpP9Nubt88O/HRe1CpWFiQbd/S07W29JOauiRYcGd129oG13axtlybItTicCAABkl9O/AGnx0nGA1O8zvXQcIHXVdg74/9m7zyipqkTh+/dZ97nPWs+n530/3TsNqFVNjtUNiKgYEBURqhsQTOgYEHMYs6Ij5oAYQDAxioEBzAFzZkBUxoAIlI5jQsecRSR07wd9Z93X6zWcU111quv077fW/9tdV6tPWWfvs/ecDbHGmre4dQAAAEDFjfSUAiDyM81RbhsAAJSJ/e0A9rcDAABANZnjKQUAAEAM7erykx1ikp7efOcfvzhjPvzUKf5GrbhV//jIYx0AWpUR+55YsftidsCY8MlnXyb6eZ9fvirMmLvQAdCSVERTb34qTLz0tnDgSVeEYb8/LdTvfFDo0HekuZ4kSRWsx3b7GKdUuN0OOS/Ra37WJdcVPSf+evV35sRSCZp5++KwfkNTm3l+OHD4BPfcVt6kbgNCIZNNfRN6DHK9JVWk0T23T91v6tldB7i2JW6TXrv+v3YoAgAAJMfuX4BYvHQcIPo400vHAWJw5wCINda8xZ0DILLF/5yjS5KiBUB0u3lKARD5meZubhsAsXhGIUnRa2/EDWB/O4D5uSRVvMVuGwCR3eIpBQAAQAzt6hpucYBJOmpf3xi+W7v2F2fM36xeE7ZuONTfqpX24BPPeKwDQKuxdPnfKnpfPG7StEQ/7/eHHV9722KHP0tShKZc/2g4efLcMP7k6WHE/n8M/XY5JGzSf5R5nSRJray6nccbu1S4C699MGzaf3Ri17zroD3D1998W/Tc+JGnX3XdpBK08u8ftJlniEdMvMQ9t5U3oM/QsDKTDYWUtyxTG7bvvZNrLin5fTrf7/Wo7Z6q39SrutS7tqUuN7KPHYoAAADJsQMYIJYx7hwAkceZXjoOEIM7B0CsseYt7hwAkXnpOID1cwDr5wDWzwGsnwMAYH5ufg5gfg5QvrGm/e0A0dnfDgAAEEdNXcNzDjBJR7kh+/3mrHnpitfDZpuP9vdqhU25ao7HOgC0Gsf88fKK3heXv/pmop93+evvO/RZkn7SlFmPhomX3hYOnnhVGH3wuWHb0X8IPbbbN7SvbzSHkySpChrYcIQxTSuo4YAzE73u186+p+i58Seff+OaSSVo3gMvtplniLPm3e+eWwXd0alnKGSyqe+p2q6hW5/hrrmkxDuwxzap+j29c+N9w3UtbTV1DSPsUAQAAEiOHcAAsTgUDCD6ONNLxwFicOcAiDXW9NJxgOi8dBzA+jmA9XMA6+cA1s8BADA/Nz8HMD8HKN9Y0/52gOjsbwcAAIijXV3DBw4wSUfDxh0faeZ81Y13+Xu1xoOWjj3fYx0AWoVPP/8yZAeMqdg9cbeDJib+mec9+KJDnyW12abMeixMnHJLmHDqlWHUweeEQaOOCd223cc8TZKkKm+7MccZ67SCzr3qvtCh78jErvvA4RPChqamoufH9zzxiusmlaAPPvmqTTxHfKXwhntuFXRQj0GhkMm2iWZ16hPau+aSEm6zunxYXNs5Nb+lCzd+Fte1tNXU5w+3QxEAACA5dgEDxOJQMIDo40wvHQeIwZ0DINZY00vHAaLz0nEA6+cA1s8BrJ8DWD8HAMD83PwcwPwcoHxjTfvbAaKzvx0AACCq9luM+d/t6hqaHWCSjiaccGGkmXNzc3PY96iz/c1aWd8fdgoArcG0P91a0Xvig088k+jn/fCTrx32LCn1XXzdI2HipbeFI86YGcYdMyXs+vvTw1aNR4Ue2+0b2tc3mpNJkpTCho471TiolTR0n4mJXvv5jywqeo686oPPXTOpBD26+NU28RxxQ1NT6DpoT/fdVl7n3IjwUrZjKGSybaLjum3puktKvFO6DUzN7+iKTG3YtC7vupawmlz+ArsUAQAAkmMXMEAsDgUDiD7O9NJxgBjcOQBijTW9dBwgOi8dB7B+DmD9HMD6OYD1cwAAzM/NzwHMzwHKN9a0vx0gOvvbAQAAovpd3+FdHV6Sns6YPDPy7PmjTz4PuSG/93drRX1/kP2XX33j0Q4AFfX9QbgDho2v2P1w4PAJP/w7JOmxZ15z2LOkqu+SWY+HSdPuDseee2PY/4RpYeRBZ4ftxx4XcjseGDbbfDdzLkmS2mD5AycZJ7WSzrzirh+e/yZ17Rv2O6lF8+R5D7zoukkt7Mq5i8K3a9a1ieeJex56hvtuFXRFl/pQyGTbRMs3tlPvHV13SYnWI7drWJrtmJrf0r59dnFdS1muYY5digAAAMmxExggFoeCAUQfZ3rpOEAM7hwAscaaXjoOEJ2XjgNYPwewfg5g/RzA+jkAAObn5ucA5ucA5Rtr2t8OEJ397QAAAFG1r2/Y2eEl6enqm+6KNYN+YtHziR7kqd/u2RdXeLQDQEU98PgzFb0XXnXjXYl+3u/Wrg9X3/K0w54ltdqmzl4QLrjmgTBxyq3hqLOuD/udcHkYc+h5Yei4U8NWjUeGPkP2D9nNx5hPSZKk/9bYwy4wnmpFDd79+ESv//MvF4qeK7/21keumVSCXlixqk08T5xy1Rz33SqoodfgUMhk20wLaruErrldXXtJiXZJl36p+R3dpdcQ17Sk5RfZpQgAAJAcO4EBYnEoGED0caaXjgPE4M4BEGus6aXjANF56TiA9XMA6+cA1s8BrJ8DAGB+bn4OYH4OUL6xpv3tANHZ3w4AABBVu/rGCQ4uSU/zH1kUexZ91iXX+du1oube/ahHOwBU1O4Hn16x+2DHgWPDF19+nejnXfrqew55lpRo02YvCBfOfChMmnZ3OOmiOeGoM68P40+aHvY66uIw8qCzwtBxp4ZtRv8h9NvlkNB1m3GhQ32juZIkSSqqfY65xPirFTXx0tsSvf4Hn3hR0XPl5ubmcNM9S1w3qYV9/9/Rxv+cUu/Jp190362COtTlw4LaLqGQybaZZnXOhfauvaQE26LP0LAyJb+h+/bc1jUtYTV1+VV2KQIAACTHTmCAWBwKBhB9nOml4wAxuHMAxBpreuk4QHReOg5g/RzA+jmA9XMA6+cAAJifm58DmJ8DlG+saX87QHT2twMAAERVU5c/1+El6enFZa/FnkWvW7c+7LLXsf5+raTzpt7o0Q4AFfPaG6tC+/rGit0Hjz/risQ/85/ve94hz1KEpsx6NEyccms47LRrwn7HXRb2OPKiMPrgc/9bex81OYw7Zko44MQrwviTp4dDT782HHHGzHDsOTeG48+/OZw8eV6YeOltYdK0u8I5V87f2H3h4use+aFLb3i81X7+abMX/Oe/5//37z3/h89x4oVzwjHn3PDD5/z+837/2ccedkFoGH9WGLbvaWGHPU4MWzUeFfoPOzT03uGA0GnLPcx7JElSYh108gxj2VbWVo1HJnb9N+03Krzz3odFz5eXvvqeayaVoFUffJ76Z4pffb06dOjb6N5bBU3qNiAUMtk21WE9tnbtJSXaTZ17p+L38/juW7qepSyX39C374R/s1MRAAAgGXYDA8TiUDCA6ONMLx0HiMGdAyDWWNNLxwGi89JxAOvnANbPAayfA1g/BwDA/Nz8HMD8HKB8Y0372wGis78dAAAgqpq6hpsdXpKePvrks6Jm0m+8/V7ovNXu/oatoPHHXeDRDgAVM/H8qyt6H1y28u+Jft73PvzC4c7SrzT15qfCUWdeH7Yfe1zo0G9Uor8Hm22+W6gduPsP9dhun43tG3oO3i/0GzrhhwYMPzRs1XjUr7bt6D+EHfY4cWMn/OL/Tb9dDvnP/5/f12fHA3/4Z3XdZu8f/tnZzceYp0iSpKrtiDNmGte2so4998ZEvwNnTrmu6Dnz+g1NYebti103qYU9uHBlm3iuOGTs0e69VdBWvYeGQibbplqWqQ3b9d7Z9ZeUWA29Bqfi9/OCrv1dzxL3730aNrNTEQAAIBl2AwPE4lAwgOjjTC8dB4jBnQMg1ljTS8cBovPScQDr5wDWzwGsnwNYPwcAwPzc/BzA/BygfGNN+9sBorO/HQAAIKp2dQ0LHVySjjIDdgtNTc3Fz6bveczfsRW0w5ijPNoBoCK+/ubb0GWrPSp3yOB+JyX+mR9eVHC4s/QzTZu9IBw56brQe4f9jdElSZKquOPOu8n4thWOtXM7HpjYd6Dr1nuGr75ZXfS8+Zmlb7luUgubMXdhWP3t2tQ/Wzz53Cvde6ukezr2CIVMtk31eG3X0Dk3wvWXlFj3d+xe9b+dMzvnXMsS97s+I7ayUxEAACAZdgQDxOJQMIDo40wvHQeIwZ0DINZY00vHAaLz0nEA6+cA1s8BrJ8DWD8HAMD83PwcwPwcoHxjTfvbAaKzvx0AACCqmrqGdx1cko62HHFwi2fUh5x4kb9lhavdYkxoamr2eAeAxN1wywMVvQfecd+TiX7eNd+tC1fOW+RwZ+knnX7p7aH/sEONzSVJklLQxCm3GuO2wg4+9cpEvwfX3Hx30XPnb9esC1eZO0st7vnlq1L/bPG2+U+491ZJR3TfOhQy2TbXlV3qXH9JiXVQj0FV/7t5d8cermWJq6lvHGunIgAAQDLsCAaIxaFgANHHmV46DhCDOwdArLGml44DROel4wDWzwGsnwNYPwewfg4AgPm5+TmA+TlA+caa9rcDRGd/OwAAQBTdu4/5X+3q8k0OLklHYyec3uIZ9ZdffRP6Dz3Q37PCvfv+Rx7vAJC4nff8Q8Xufb0H7xPWrl2X6Od9fsUqhzpLP2rqzU+FccdMCR36jTImlyRJSklnT7/HWLeVjr27bTMuse/BgGHjw/oNG4qePz/+7N9cN6mF3XTPktDcnO5ni2+tet+9t0rq1md4eCVTGwqZbJvrgB7b+A5ISqTN6vJhcW3nqv7NXFTbxbUsdfUNx9itCAAAkAw7ggFicSgYQPRxppeOA8TgzgEQa6zppeMA0XnpOID1cwDr5wDWzwGsnwMAYH5ufg5gfg5QvrGm/e0A0dnfDgAAEEX7uhEdHVqSno754+UlmVU/+fSLoX19o79pBVvwzEse7wCQqL8uLVT03nfBFTcl/plvvvevDnWW/tmkaXeHfkMnGItLkiSlrAuvfdB4t5U27phLEv0u3PvwwqLnz59+sdo1k0rQO+9/nvpnjLkh+7n/Vkl/6twnFDLZNtdL2Y5hy947+w5ISqRTum1R1b+Zy7O1YZNc3rUsbRfZrQgAAJAMu4IBYnEoGED0caaXjgPE4M4BEGus6aXjANF56TiA9XMA6+cA1s8BrJ8DAGB+bn4OYH4OUL6xpv3tANHZ3w4AABDF73IjdnRgSXqaPGN2yWbWp114jb9pBZs1736PdwBI1DF/vLxi971N+o4Mq/7xUaKf9+1/fOYwZ+mfHXXW9SG7xRjjcEmSpBR2+Y1PGvO20qbMejTRcfiwcce3aB5912PLXDephT3wl5Wpf8Y4/rgL3H+rpN17bh8KmWyb7MHa7iGbG+F7IKns9cztGl7O1lb1b2bvPsNcyxJWU5efbbciAABAMuwKBojFoWAA0ceZXjoOEIM7B0CssaaXjgNE56XjANbPAayfA1g/B7B+DgCA+bn5OYD5OUD5xpr2twNEZ387AABAFO1zDeMdWpKebr79oZLNrNd8tzZsN+pwf9cKdfal13u8A0Bivvjy61Cb4EHeP+3AY89L/DPfv2CFw5zV5pt681Nh5EFnh/b1jcbgkiRJKWzTfqONe1t5oyacneh34q9LC0XPo99Y9YlrJrWwGXMWhm++XZvq54xX3nCne3C1jBPq8uHZbKdQyGTbZJO79vM9kJRIl3TpV9W/l4N77+Q6lrCauvwTdisCAAAkw85ggFgcCgYQfZzppeMAMbhzAMQaa3rpOEB0XjoOYP0cwPo5gPVzAOvnAACYn5ufA5ifA5RvrGl/O0B09rcDAABE0S7XcLZDS9LTE4ueL+ns+uWVr4dN+4/yt61Ah59yscc7ACTm2tn3VPS+t+CZlxL9vKu/XRtmzF3oMGe16SZf93AYmD/c2FuSJCnFdd56L2PfVt55V98fOvQdmdh3YsIJFxY9l25uDuGme5a4blIL++vyVal+zvjXpQX34Crqwi79QyGTbbPt03Nb3wNJZW/LPkPDyir+rdy95/auYwmrqWt4zW5FAACAZNgZDBCLQ8EAoo8zvXQcIAZ3DoBYY00vHQeIzkvHAayfA1g/B7B+DmD9HAAA83PzcwDzc4DyjTXtbweIzv52AACAKGpy+ZscWpKeXv37OyWfYU+deau/bQUadeCpHu8AkIjm5uaw7cjDK3bP22bkYT/8OyTpuWVvO8RZbbpzrpwfeu2wn3G3JElSyvt+zGf82/rbae+TE/tObNJ3ZHjnvQ+Lnk+/uPJd10xqYTfesyQk/CgsUWvXrgvZAWPch6ukIb12DIVMts32QqZjGNBnqO+CpLJ3c6c+VftbeXj3rV3D0vaN3YoAAADJsDsYIBaHggFEH2d66ThADO4cALHGml46DhCdl44DWD8HsH4OYP0cwPo5AADm5+bnAObnAOUba9rfDhCd/e0AAABRtMvl/+LAkvT0zeo1JZ9hNzU1h9HjT/X3TbiBwyd4vANAIhY993JF73l/+vO9iX7e5ubmcMPdzznEWW22iVNuCZ233suYW5IkqQ3Uf9ghxsBV0BlT7wzt6xsT+16ce9msoufUa9dtCNfc+rTrJrWwd97/PNXPGxv3P9l9uIp6uGO3UMhk22x3d+wRNq3L+y5IKmuNPXeo2t/JP3bdwjUscdm+Y/6PHYsAAADlZ3cwQCwOBQOIPs700nGAGNw5AGKNNb10HCA6Lx0HsH4OYP0cwPo5gPVzAADMz83PAczPAco31rS/HSA6+9sBAACiqKnLr3JgSTrqsd3eZZtlv/3uB6Hr1nv6Oyd5iM6AMaG5udkjHgDK7tCTJlfsftd5q93DV1+vTvTzvrHqE4c3q8123Hk3hezmY4y3JUmS2kiDRh1tHFwlfX+tkvpedN927/Dtmu+Knlc/ueR110xqYQ8tKqT6eeM5l81yH66iTug+MBQy2TbdpG4DfBcklbX2G3uwY7eq/I2c2qXeNSxx/5HLd7djEQAAoPzsDgaIxaFgANHHmV46DhCDOwdArLGml44DROel4wDWzwGsnwNYPwewfg4AgPm5+TmA+TlA+caa9rcDRGd/OwAAwG/p3n3M/2pXl29yYEk62mmPY8o6055z1yP+zgn36edfesQDQFl9f6/JDNitYve6k86ZkfhnvueJVxzerDbZYaddEzr0HWmcLUmS1IYasseJxsJV0nHn3ZTod+PPdz5S9Lz686++DdPnuGZSS7py7sKw5rt1qX3m+MDjz7gPV1H1fXYJKzPZUGjDrcjUhl17DfF9kFTWJvQYVJW/kbM79Xb9SlxNLj/ErkUAAIDys0MYIBaHggFEH2d66ThADO4cALHGml46DhCdl44DWD8HsH4OYP0cwPo5AADm5+bnAObnAOUba9rfDhCd/e0AAAC/pUPfxlqHlaSn/Y4+p+yz7e//Gf7WybX81Tc94gGgrKZff3tF73UrXkv2XvfVN9+F6XMWOrxZba4DT5wW2tc3GmNLkiS1sYb9/jTj4SqqfueDEvtu7LTHMS2aX9/zxCuumdTClr76XmqfOX786Rfuw1XWbR17hkIm26b7S7ZL6Jrb1fdBUtnarC4fFmc7V93v40Mdu7t+pS6X39euRQAAgPKzQxggFoeCAUQfZ3rpOEAM7hwAscaaXjoOEJ2XjgNYPwewfg5g/RzA+jkAAObn5ucA5ucA5Rtr2t8OEJ397QAAAL+lpq5hB4eVpKeJ519d9tn2hx9/Frpvu7e/d0I9umCJRzwAlE1TU3MYOHxCxe5zI/c/OfHP/PRLbzq0WW2uff5waWhf32h8LUmS1AYbdfA5xsRV1KGnXZ3o9+PZF1cUPb9+673PXDOphc25/4VUP3vcKn+Ie3EVdWiPrUMhk23zXdO5zvdBUlk7tdsWVffb+Hy2k2tX6nIjTrFrEQAAoPzsEgaIxaFgANHHmV46DhCDOwdArLGml44DROel4wDWzwGsnwNYPwewfg4AgPm5+TmA+TlA+caa9rcDRGd/OwAAwG+pqcsf4LCS9DT9+tsTmXHfNv8Jf++Euvn2hzziAaBsnnz6hYre5+56cEGin3dDU3O47o5nHNqsNtUeR1xkXC1JktSG2/uoycbFVdTUm58KXQbtndj349CTJrdonn3z/L+6blIL+/DTr1P77PHo0y9zL66iuuZ2Da9kakMhk23z/b7HNr4TkspWz42/ty9nq+/3tmPdCNevlOUaptm1CAAAUH52CQPE4lAwgOjjTC8dB4jBnQMg1ljTS8cBovPScQDr5wDWz+kold8AACAASURBVAGsnwNYPwcAwPzc/BzA/BygfGNN+9sBorO/HQAA4Le0q8uf5bCS9HTnAwsSm3Xvf8y5/uYJdOk18zziAaBsDjz2vIrd43JD9gvr1q1P9PO+9vbHDmtWm2rsYRcYU0uSJLXxxp803di4ytrrqMmJfT827T8qfPDRp0XPs5e++p5rJrWwJ577W2qfPV4/7z734irr+s65UMhk23zPZzuFvn128Z2QVLYu69K36n4bB/QZ6tqVsJpcwx12LQIAAJSfXcIAsTgUDCD6ONNLxwFicOcAiDXW9NJxgOi8dBzA+jmA9XMA6+cA1s8BADA/Nz8HMD8HKN9Y0/52gOjsbwcAAPgtNbn8jQ4rSU/PvrgisVn3hx9/Fnpst7e/e5mbdPGfPOIBoCze//CTsGm/URW7x100fXbin/nOR192WLPaTHseeZHxtCRJksJRZ15nfFxlXfSnh8Om/Ucn9h2ZPKP4+fm6dRvCNbcudt2kFvT9f0PrNzSl8vnji8tecy+ussb12C4UMllt7LaOPcMmubzvhaSytFWfncPKKvtd3KXXDq5dCavJNTxj1yIAAED52SkMEItDwQCijzO9dBwgBncOgFhjTS8dB4jOS8cBrJ8DWD8HsH4OYP0cAADzc/NzAPNzgPKNNe1vB4jO/nYAAIDf0i6XX+CwkvT03gcfJzrzvuO+J/3dy9yxZ0z1iAeAsphy1ZyK3d869G0Mq/7xUaKf97Mvv3VQs9pMvz/uMmNpSZIk/dBJF80xRq7Chv3+tMS+I70H7xPWrl1X9Hz7L8//3TWTWljhjQ9T+fxx3br1ITNgN/fjKiqTy4fns51CIZPVxk7sNtD3QlLZmt2pd1X9Jo7rsZ3rVspy+XfsWgQAACg/O4UBYnEoGED0caaXjgPE4M4BEGus6aXjANF56TiA9XMA6+cA1s8BrJ8DAGB+bn4OYH4OUL6xpv3tANHZ3w4AAPBbvj+kw2El6WjTfqPC+g0bEp99jz/uAn//Mnbgsed7xANAyW1oagoDho2v2P1tv6PPSfwzO+RbbaX9j59qHC1JkqT/bNK0u42Tq7BJU+8M7esbE/ue3HHfk0XPt7/4ek2YPsc1k1rSHY++nNrnkMPGHe9+XGVN7VIfCpmsNrZ8Y0N67eh7Iaksjeo1uKp+E4/svrXrVspyDev/ZcyYf7VzEQAAoLzsFgaIxaFgANHHmV46DhCDOwdArLGml44DROel4wDWzwGsnwNYPwewfg4AgPm5+TmA+TlA+caa9rcDRGd/OwAAwK/p23fCv7XL5Tc4rCQdbb7L+IrMvj/65LPQY7u9XYMytdtBEz3iAaDkHnry2Yre3x5ZsCTRz7t+Q1OYedtihzQr9R144rTQvr7ROFqSJEn/2YUzHzJWrtK2ajwyse/J8H1OaNG8e/5Ty10zqYV99uW3qXwOeer5V7kfV1n5XjuEQiarf/Z4bdfQKTfCd0NSyWu/sYc6dq+a38Mzug5w3Urcpv2H/YfdiwAAAOVltzBALA4FA4g+zvTScYAY3DkAYo01vXQcIDovHQewfg5g/RzA+jmA9XMAAMzPzc8BzM8ByjfWtL8dIDr72wEAAH7NJv1GZR1Skp5G7n9yxWbgd9z3pGtQpnba4xiPeAAouXFHnFmxe9vmu4wPG5qaEv28K//+gcOZlfoOPf3a0L6+0RhakiRJ//8h7RvHh1NnLzBertKOPntWot+Xl155reh59zvvf+6aSS3s6ZfeTOcu3nsec0+usjrU5cPC2s6hkMnqn03p0s93Q1JZOrj7oKr5Lby0S1/XrMT9ru/wersXAQAAystuYYBYHAoGEH2c6aXjADG4cwDEGmt66ThAjP+5gjsHgPVzAOvnANbPAayfAwBgfm5+DmB+DlC2sab97QDR2d8OAADwa9rVjxjskJL0dPipUyo6Cx9/3AWuQxkaMGy8RzwAlNS7738UNuk7smL3tstnJr/eeetDLzmcWanu+PNvDpv0H2X8LEmSpP9Sx4F7GC9XcdNmLwi9d9g/se/L0adf1qK595z7X3DdpBZ0/Z3Phubm5tQ9i3z17++4J1dh53TdPBQyWf2ovXpu57shqeRlcyPCs9lOVfE7eEOnPq5Ziaupaxhh9yIAAEB52TEMEItDwQCijzO9dBwgBncOgFhjTS8dB4jOS8cBrJ8DWD8HsH4OYP0cAADzc/NzAPNzgPKNNe1vB4jO/nYAAIBfU1OX398hJenp3MtvqOgs/KNPPgs9txvnWpS4roP29IgHgJI6f9pNFbuvbdp/VPjw488S/bwff/6Ng5mV6k6ePC9stvluxs6SJEn6b/XaYT9j5ipvv+MuT+z7khmwW/j40y+Knn8ve+0frpnUwt55//PUPYtsamoOXbfe0325ytq+906hkMnqRz2b7RR69xnm+yGp5J3ebYuq+B28t1N316v0HWz3IgAAQHnZMQwQi0PBAKKPM710HCAGdw6AWGNNLx0HiM5LxwGsnwNYPwewfg5g/RwAAPNz83MA83OA8o017W8HiM7+dgAAgF/Trq7hTAeUpKfr591X8Zn4vLsfcy1KXPv6xrChqcljHgBKYt269SE3ZL+K3dcmnHBh4p/5ief+5lBmpbYzLr8z1A7c3bhZkiRJP9uA4YcaN1d5U2Y9FrIDxib2nbl8ZvF7lNdvaAozb1vsukkt6OFFhVQ+kxwz4TT35SrswY7dQiGT1Y+a3al3aO+7IanE9e4zLCzP1Lb638BFtV1cr9I3ye5FAACA8rJrGCDesp47B0DkcaaXjgPE4M4BEGus6aXjANF56TiA9XMA6+cA1s8BrJ8DAGB+bn4OYH4OUL6xpv3tANHZ3w4AAPBrauoabnBASXp6+KnnKj4Tb25uDrsffLrrUeK+/Oobj3kAKIl7H15Y0XvagmdeSvTzrlu3IVx969MOZVYqO+fK+aHLoL2NlyVJkvSLbbfbscbOKahx/FmJfWf6DT0grN+woeh5+MIX3nDNpBZ01bxFYe269al7JnnuZbPcl6uwk7sNDIVMVj/pyO5b+35IKnlXdalv9b9/yzfWoS7vepWyXMOVdi8CAACUl13DALE4FAwg+jjTS8cBYnDnAIg11vTScYDovHQcwPo5gPVzAOvnANbPAQAwPzc/BzA/ByjfWNP+doDo7G8HAAD4NTV1+ScdUpKeXim80Spm42++849Qu8UY16SEffzpFx7zAFASYyecXrH72dYNh4bm5uZEP++y1/7hQGalsov+9HDoOXg/Y2VJkiT9arvsM9H4OQWdM+Pe0L6+MbHvzfxHFhU9D//i6zVh+hzXTGpJy19/P3XPJL//XXFfrr769d4lrMxkQ0H/pZeztWHL3jv7jkgqaUN7DamK38CeuV1drxJWk2u4w+5FAACA8rJrGCAWh4IBRB9neuk4QAzuHACxxppeOg4QnZeOA1g/B7B+DmD9HMD6OQAA5ufm5wDm5wDlG2va3w4Qnf3tAAAAv6ZdLv+WQ0rS0xdfft1qZuTT/nSra1LCPvjoU495AGixt1a9n+gh3D/tqhvvSvwzz3vgRYcxK3VdduMTYcDwQ42TJUmS9JuNPvhcY+iUtP2Y4xL73uxxyB9bNBe/+/FlrpnUgm5/ZGnqnku++/5H7stV2p2deoZCJqufdG+n7mGTurzviKSSdk/HHq3+929Q751dq5KWX2T3IgAAQHnZOQwQi0PBAKKPM710HCAGdw6AWGNNLx0HiM5LxwGsnwNYPwewfg5g/RwAAPNz83MA83OA8o017W8HiM7+dgAAgF+07bb/s12uYb0DStJR5612b1Uz8vXrN4QhY492bUrUO+996DEPAC127mWzKnYvyw4YEz79/MtEP+/7H3/pIGalrmmzF4TBux9vjCxJkqRIjTvmEuPolHTCBbMT+960r28Mb7z9XtHz8dff+dg1k1rY519+m7pnk7khv3dvrsKO7r5VKGSy+plO7DbQd0RSSRvfY5tW/9vX0Guwa1XCanINf7OBEQAAoLzsHAaIxaFgANHHmV46DhCDOwdArLGml44DROel4wDWzwGsnwNYPwewfg4AgPm5+TmA+TlA+caa9rcDRGd/OwAAwC/5994jMg4oSU/b73Zkq5uVv/TKa2GTviNdnxLUkgNMAeB76zdsCHU77lexe9lRp12a+Gd+ZPGrDmFW6mocf5bxsSRJkiJ30CkzjKNTVN3O4xP77pxz2ayi5+NNzc3h+jufdc2kFvTMy2+l7vnkuCPOdG+uwnr1GRaWZ2tDIZPVT1qeqQ3b997J90RSydqsLh8WZzu36t++/Xts61qVslzDV3YwAgAAlJfdwwCxOBQMIPo400vHAWJw5wCINdb00nGA6Lx0HMD6OYD1cwDr5wDWzwEAMD83PwcwPwco31jT/naA6OxvBwAA+CXt+jRs54CS9LTXYZNa5cz89IuudX1K0Kuvv+0xDwAtct+jT1f0XvbsiysS/bzfrV0frpq3yCHMSlX7HXeZsbEkSZJidfRZ1xtLp6iDTp6R2Hen9+B9wtq164qelz+z9C3XTGpBN9z9XGhuTtfzyYumz3ZvrtJu6dQ7FDJZ/Uz3dewRNq3L+55IKlmTug1o1b97x3bfynUqce23GPO/7WIEAAAoH7uHAWJxKBhA9HGml44DxODOARBrrOml4wDReek4gPVzAOvnANbPAayfAwBgfm5+DmB+DlC+sab97QDR2d8OAADwS2rq8vs7nCQ9nXj29FY5M1/97ZowcPgE16iFvVJ4w2MeAFpkr8MmVew+tv3oIxL/vC+ufNcBzEpVR589K3SobzQ2liRJUqxOnjzPeDpFXXbjE6F2y90T+/7c+cCCouflX6/+Lkyfs9B1k1rQux98karnkw88vti9uUo7pPugUMhk9QtN7LaF74mkklXXZ1hY3op/887uOsB1KnH/3qdhM7sYAQAAysfuYYBYHAoGEH2c6aXjADG4cwDEGmt66ThAdF46DmD9HMD6OYD1cwDr5wAAmJ+bnwOYnwOUb6xpfztAdPa3AwAA/JJ2dQ2THE6Sni69Zl6rnZ0/smCJa9TCXlz2msc8ABRt1T8+Ch36NlbsPnbd3PmJf+Y/3/e8w5eVmiZOuSVs2n+0cbEkSZJid+YVdxtTp6yRB52V2Pdn9PhTWzQ3v/fJ5a6Z1IIeXfxq6p5RujdXZ91zw8PyTG0oZLL6mZZvbHDvnXxXJJWsmV1yrfY3b3rneteo1PXND7CLEQAAoHzsIAaIxaFgANHHmV46DhCDOwdArLGml44DROel4wDWzwGsnwNYPwewfg4AgPm5+TmA+TlA+caa9rcDRGd/OwAAwC9pV9cwy+Ek6enWex9v1TP0g0+8yHVqQUteWukxDwBFmzxjdsXuYR0Hjg1ffvVNop931QefO3hZqemCax4IXbfZ25hYkiRJRXXxnx4xrk5ZZ8+4J7Svb0zsO/Tq628XPT9/891PXTOpBV19y9Nh3foNqXpO2XvwPu7PVdpNnXuHQiarX+ihjt1DJpf3XZFUknbtNaTV/t7N7tTbNSpxNXUNI+xiBAAAKB87iAFicSgYQPRxppeOA8TgzgEQa6zppeMA0XnpOID1cwDr5wDWzwGsnwMAYH5ufg5gfg5QvrGm/e0A0dnfDgAA8Etq6vJPOJwkPS167uVWPUP/6JPPQrdt9nKtiuzpJcs85gGgKBuamkK/oQdU7B52/FlXJP6ZH1y40sHLSkWX3vB4qB96kPGwJEmSiqpDfWOYNnuBsXUKGzTq6MS+R2dMnln0/Ly5OYQb7n7ONZNa0KtvfpSqZ5V7HXaGe3SVdkCPbUIhk9WvNKnbAN8VSSXr/o7dW+Vv3fyOPVyfEtc+1zDeLkYAAIDysYsYIBaHggFEH2d66ThADO4cALHGml46DhCdl44DWD8HsH4OYP0cwPo5AADm5+bnAObnAOUba9rfDhCd/e0AAAC/pF1d/k2Hk6Snt9/9oNXP0q+bO9+1KrJnXljuMQ8ARXlkwZKK3sOWrng90c+7es3aMGPuQocuq+qbNntBGLLHicbCkiRJKrrOW+1pbJ3Sjjrr+sS+R9222St8u+a7oufpS5a945pJLejeJ15J1bPK86fd5B5dreOK3IiwNNsxFDJZ/UIrMrVhl15DfF8klaSDuw9qlb91C2s7uz4lrqYuP9EuRgAAgPKxixggFoeCAUQfZ3rpOEAM7hwAscaaXjoOEJ2XjgNYPwewfg5g/RzA+jkAAObn5ucA5ucA5Rtr2t8OEJ397QAAAD9r223/Z7tcw3qHk6SjDn0bw9q161r9LH1DU1PYec8/uGZF9MKyVz3mAaAo+x9zbsXuX7vsfVzin3fJKw7rVjra7ZDzjIMlSZLUovoM2d/YOqVNnb0gdNt2n8S+S7fe+3jR8/TVa9aGGXMXum5Skc2Ys/CH/47SYv4ji9yjq7iZXXKhkMnqV3qiY9fQsW6E74ukFpfNjQhLsp1b3e/cK5na0N71KWk1dQ2X28gIAABQPnYRA8TiUDCA6ONMLx0HiMGdAyDWWNNLxwGi89JxAOvnANbPAayfA1g/BwDA/Nz8HMD8HKB8Y0372wGis78dAADg5/xH3ahNHUySnup23K9qZup/XVoI7esbXbeYvVJ4w2MeAGL74KNPw6b9RlXs/vXnOx5O9PM2N4dww91LHLisqu/giVcZA0uSJKnFbTH8MOPrFLfXURcn9l1q2O+kFs3X7//LCtdMakEvFd5LzfPKt9/9wD26ihvXY7tQyGT1G53Xtb/vi6SSdE7XzVvl71zn3HDXp5Tl8nPtZAQAACgfO4kBYnEoGED0caaXjgPE4M4BEGus6aXjANF56TiA9XMA6+cA1s8BrJ8DAGB+bn4OYH4OUL6xpv3tANHZ3w4AAPBz2ucat3UwSXoase+JVTVbP/aMqa5bzF57Y5XHPADEdvnMWyp27+q69Z7hm9VrEv28b733qYOWVfWdNHlu2KT/KGNgSZIktbjBux9vjJ3iLpz5UOjQL7m5w4rX3ix6vv7O+5+7ZlILuuXBF1PzvLK5uTl033Zv9+kqLZsbEV7MdAyFTFa/0opMbRjWa4jvjKQW17fPLmF5trbV/c713/jv5fqUrpq6/BN2MgIAAJSPncQAsTgUDCD6ONNLxwFicOcAiDXW9NJxgOi8dBzA+jmA9XMA6+cA1s8BADA/Nz8HMD8HKN9Y0/52gOjsbwcAAPg5NbkRv3cwSXo69KTJVTVb//jTLxyYF7O33/3AYx4AYvn+gNotRxxcsXvXSefMSPwzz39quYOWVdVdcM0Docsg42RJkiSVpvyBk4yzU96Oe5+c2Pdp4vlXt2jOfvO9f3XNpBb0+Zffpua55e4Hn+4+XcXN6FwfCpmsfqMna7uGTrkRvjOSWtysTn1a3W/cTr13dG1K23I7GQEAAMrHbmKAWBwKBhB9nOml4wAxuHMAxBpreuk4QHReOg5g/RzA+jmA9XMA6+cAAJifm58DmJ8DlG+saX87QHT2twMAAPycmlz+DIeSpKdzL5tVdTP26+bOd+1i9I8PPvGYB4BYnlr8YkXvXUtXvJ7o5/169Xdh+pyFDllW1XbZTU+EfrscYuwrSZKkkrXXURcba6e8kyfPTez71HXQnmH1t2uKnrc/v2KVaya1oGdffjs1zy2/X9d0n67exvTcPhQyWUVoctd+vjOSWlxDz8Gt7vdt7MZ/J9emhOXyn9jJCAAAUD52EwPE4lAwgOjjTC8dB4jBnQMg1ljTS8cBovPScQDr5wDWzwGsnwNYPwcAwPzc/BzA/BygfGNN+9sBorO/HQAA4Oe0yzVc52CS9HTd3PlVN2Pf0NQUdt7zD65fxD7+9AuPeQCI5eATL6rYfev7e3zSnln6lgOWVdXtPO4U415JkiSVtINOmWGs3Qaq23l8Yt+pP9/5SNHz9jXfrQtXzl3kmklFdtM9S1Lz3PKuBxe4T1dxm9Xlw1+znUIhk9VvtHJj+V47+N5IalHtN/Zwx26t6vftoB6DXJvS1ty374R/s5sRAACgPOwmBojFoWAA0ceZXjoOEIM7B0CssaaXjgNE56XjANbPAayfA1g/B7B+DgCA+bn5OYD5OUD5xpr2twNEZ387AADAz6mpa3jcoSTp6ZEF1XmQ3pKXVob29Y2uYYS++ma1xzwARPbp51+GzIDdKnbfuuGWBxL9vE3NzeH6O591wLKqtn2PvdSYV5IkSSXv2HNuNN5uA40/eXpi36lh445v0fz9oUUF10xqQe9//FUqnl2+9sYq9+kq77IufUMhk1WEnujYNdTmRvjeSGpRh3ffulX9tp3QfaDrUuI61OVr7GYEAAAoDzuKAWJxKBhA9HGml44DxODOARBrrOml4wDReek4gPVzAOvnANbPAayfAwBgfm5+DmB+DlC+sab97QDR2d8OAADwc9rVNbzhUJL0tOK1N6t25n7sGVNdwwit+W6txzwARHblDXdW7J7VceDY8NXXqxP9vK+/87GDlVW1HX/+zaFD35HGvJIkSSp5p116mzF3G+jSGx4P2S3GJva9ennl60XP39/78AvXTGpBTy15PRXPLjc0NYXaLca4V1dxI3sODoVMVhE7p+vmvjeSWlSn3IjwfLZjq/ldO7eb37VSV9M7X2c3IwAAQHnYUQwQi0PBAKKPM710HCAGdw6AWGNNLx0HiM5LxwGsnwNYPwewfg5g/RwAAPNz83MA83OA8o017W8HiM7+dgAAgP9mzJh/rcnl1zmUJD19+dU3VTtz//jTL0K3bfZyHX+lDn0bQ1NTs8c8AETS3Nwcthl5WMXuW3844/LEP/Pdjy9zsLKqsnOunB86DtzDmFeSJEll6YJrHzTubiM1jD8zse/VKedd2aI5/J/ve941k4ps5m2Lw4aUrBcNG3e8e3UVt0ldPizJdg6FTFYRWpGpDTv13tF3R1LL5ndd+7ea37XpnetdkxLXvr5hZxsaAQAAysOuYoBYHAoGEH2c6aXjADG4cwDEGmt66ThAdF46DmD9HMD6OYD1cwDr5wAAmJ+bnwOYnwOUb6xpfztAdPa3AwAA/NTv+g7fxIEk6anroD2rfvZ+3dz5ruWv1GO7vT3iASCyZ55/paL3rSUvrUz0837+1bcOVVZVdukNj4e6ncYb70qSJKksdahvDFNnLzD2biOdecVdof3Ga57Ed6vbNnuFNd+tLXoe/1LhPddMakFvvfdpKp5hHn/WFe7XVd7lXfqGQiariD3csVvYrC7vuyOp6Dbvs0tYkaltFb9pN3fq45qUulx+XzsaAQAAysOuYoBYHAoGEH2c6aXjADG4cwDEGmt66ThAdF46DmD9HMD6OYD1cwDr5wAAmJ+bnwOYnwOUb6xpfztAdPa3AwAA/FT7uvw2DiRJT0PGHl31s/cNTU1hhzFHuZ6/0NYNh3rEA0BkR068pGL3rO1HH5H45130whsOVFZVtuOeJxnrSpIkqWx13nov4+421sD84Yl9v+6478mi5/HfrV0frpq3yDWTiuyRp19NxTPM6+bOd7+u8kb1GhwKmaxidEq3gb47klrUzZ36tIrfs3s7dnc9SlxNn/wJdjQCAACUh13FALE4FAwg+jjTS8cBYnDnAIg11vTScYDovHQcwPo5gPVzAOvnANbPAQAwPzc/BzA/ByjfWNP+doDo7G8HAAD4qXa5/L4OJElP+x19Tipm8AufW+p6/kIj9j3RIx4AIvnyq29Cx4FjK3bPunb2PYl+3g0bmsLM259xoLKqrn2Pvcw4V5IkSWWtfuhBxt5trENPuzqx79fuB5/eovn8I4tfdc2kIrv61qfD+g1NVf8c85kXlrtfV3mb1OXDkmznUMhkFbFXMrVhyz5DfX8kFd3ontu3it+zhbWdXY9Sl8tfaEcjAABAedhZDBCLQ8EAoo8zvXQcIAZ3DoBYY00vHQeIzkvHAayfA1g/B7B+DmD9HAAA83PzcwDzc4DyjTXtbweIzv52AACAn6rJ5f/oQJL0NPH8q1Mzix93xJmu6c+071Fne8QDQCR/+vO9Fbtfbbb56PDJZ18m+nkLb37oMGVVXadcPC906DfKOFeSJEllbZvRfzD+bmNdfuOTodOWeyTy/Wpf3xjeWvV+0fP5dz/4wjWTWtDr73xc9c8xv/pm9Q+/Je7Z1d3ULvWhkMkqRnd26hk2yeV9fyQVVYe6fHiiY9eK/5Yty9S6HqUu1/AnOxoBAADKw85igFgcCgYQfZzppeMAMbhzAMQaa3rpOEB0XjoOYP0cwPo5gPVzAOvnAACYn5ufA5ifA5RvrGl/O0B09rcDAAD81PcHcTiQJD3NmHVHambxr72xKmzab5Tr+pOOOu1Sj3gAiGTH3Y+u2P3q8FMuTvzz3v7IUgcpq6q68NoHQ5dBexvjSpIkqewN2/c0Y/A2WMP4sxL7jk25ak6L5vQ33bPENZOK7MGFK1PxLHPg8Anu2VXe6F6DQyGTVcyO7L6174+kojum+1at4resY90I16O03WVHIwAAQHnYWQwQi0PBAKKPM710HCAGdw6AWGNNLx0HiM5LxwGsnwNYPwewfg5g/RwAAPNz83MA83OA8o017W8HiM7+dgAAgJ+qyTU85jCS9HTPwwtTNZM/+dwrXdefdMbkmR7xAPCbnn+5UNH71aLnXk708376xWqHKKuqmnrzU2GLEYcb30qSJCmRxhx6vnF4G2zStLsT+471G3pA2NDUVPS8/rllb7tmUpFdOW9RWLtuQ9U/zzzw2PPcs6u8Tery4a/ZTqGQySpGS7MdQ7/eu/gOSSqqLrnh4aWNvyOV/i2r6zPM9Shlufxf7GgEAAAoD7uLAWJxKBhA9HGml44DxODOARBrrOml4wDReek4gPVzAOvnANbPAayfAwBgfm5+DmB+DlC+sab97QDR2d8OAADwUzW5/N8dSJKenn+5kKqZ/CeffRm6DtrTtf1Rl14zzyMeAH7TcZOmVexeNXD4hNDc3Jzo531qRTxXXAAAIABJREFUyesOUVZV1TD+LGNbSZIkJdZ+J1xuHN5GGzD80MS+Z08tfrHoef3Xq78L0+csdM2kInv1zY+q/nnmlKvmuGenoKld6kMhk1XM5nTqFdr7/kgqsou79qv479h2vXd2LUpZLr/CjkYAAIDysLsYIBaHggFEH2d66ThADO4cALHGml46DhCdl44DWD8HsH4OYP0cwPo5AADm5+bnAObnAOUba9rfDhCd/e0AAAD/xZgx/1qTy69zIEl6+vDjz1I3m7/iuttc2x81a979HvEA8Ku+Wb0mdNlqj4rdq6Zff3uin3f9hqZw7W2LHaCsqumwP15rXCtJkqREO+KMPxmLt9EmnHpVYt+zw06+uEXz+7seW+aaSUU2/6nlVf9M84HHF7tnp6DRPbcPhUxWRbR/j219hyQV1ZZ9hoaVFf4NG9FrB9eipOU/tKkRAACgPOwwBojFoWAA0ceZXjoOEIM7B0CssaaXjgNE56XjANbPAayfA1g/B7B+DgCA+bn5OYD5OUD5xpr2twNEZ387AADAj9X0a+jgIJL0lBmwW2hqak7dbP67tWvDgGHjXeN/dteDCzziAeBX3Xz7QxW7T23af1T46JPPEv28y19/3+HJqpomTb0zbLb5bsa1kiRJSrSTJs81Hm+jXXrD4yG7xdhEvmfZAWPC5198XfT8/tU3P3LNpCKbMXdhWLN2fVU/03z73Q/cs1PQpnX58Ndsp1DIZBWzJdnOoWduV98jSUU1t1Oviv6G7d1jW9ehlOUa1v/Lv/zL/7CzEQAAoPTsMAaIxaFgANHHmV46DhCDOwdArLGml44DROel4wDWzwGsnwNYPwewfg4AgPm5+TmA+TlA+caa9rcDRGd/OwAAwI/9rm/j1g4jSU9b5Q9J7Yz+zgcWuMb/7OklyzziAeBXDd/nhIrdp8Yfd0Hin3fegy86PFlV0SWzHg99huxvTCtJkqTEO3vGPcbkbbj8AZMS+65dN2d+0fP7DRuawrW3LXbNpCJb/voHVf1Ms7m5OXTZag/37RQ0rUvfUMhkVURXdan3HZJUVHv32Laiv1+HdB/kOpS4Tfs0/D92NgIAAJSeHcYAsTgUDCD6ONNLxwFicOcAiDXW9NJxgOi8dBzA+jmA9XMA6+cA1s8BADA/Nz8HMD8HKN9Y0/52gOjsbwcAAPixdnUN+ziIJD3tfvDpqZ3Rf3+QXuP+J7vOG3vnvQ894gHgFxX+9nZF71NPPv1Cop/3w0++dmiyqqah4041npUkSVJFuvSGx43J23B/vPyOxL5rQ8Ye3aJ5/hPP/c01k4rs7seXVf2zzeH7nOC+nYLG9Nw+FDJZFdnuPbb3PZIUu03q8mFRbZeK/Xad2G2g61DiOvRtrLWzEQAAoPTsMgaIxaFgANHHmV46DhCDOwdArLGml44DROel4wDWzwGsnwNYPwewfg4AgPm5+TmA+TlA+caa9rcDRGd/OwAAwI/V5BpOdxBJejr2jKmpntU//3IhtK9vbNsHIfUdGdav3+ARDwC/6IzJMyt2n+o/9MCwoakp0c/72DOvOTRZVdH4k6ebs0iSJKkiZQeMNSZX6LfLIYl955at/HvR8/wPPvnK9ZKKbPqchWH1mnVV/Wzz+DOnuXenoM3q8uH5bKdQyGRVRE/XdgldcsN9lyTF7vRuW1Tst+vsrpu7BiWufZ/Gze1sBAAAKD27jAFicSgYQPRxppeOA8TgzgEQa6zppeMA0XnpOID1cwDr5wDWzwGsnwMAYH5ufg5gfg5QvrGm/e0A0dnfDgAA8GPt6vIzHUSSnqZcNSf1M/uDT7yoTV/j/kMP9HgHgF+0bt360HvwPhW7T11y9dxEP+/ajZ/36luedmiyWn2nX3Z72LTfaHMWSZIkVaSeg/czLlc46OQZiX3nTrvgmhbN9+fc/4JrJhXZstf+UdXPN2fOvse9OyVN71wfCpmsiuzCLv19jyTFrq7PsLA8W1uR362pXepdg1KXa9zFzkYAAIDSs9MYIBaHggFEH2d66ThADO4cALHGml46DhCdl44DWD8HsH4OYP0cwPo5AADm5+bnAObnAOUba9rfDhCd/e0AAAA/1i6Xf9RBJOlp3t2PpX5m/8bb74VN+41qs9d41AGneLwDwC+a/8iiit2jNuk7Mrz7/keJft6lr77nsGS1+i6Z9XjovcMB5iuSJEmqWAPzhxub64e5SXbA2ES+cz222zt8t3Zt0fP9F1ascs2kIrvrsWVV/XxzwTMvuXenpLE9B4dCJqsiW5GpDTv03tF3SVLsZnXOVeR36/qN/1x//1I3YpydjQAAAKVnpzFALA4FA4g+zvTScYAY3DkAYo01vXQcIDovHQewfg5g/RzA+jmA9XMAAMzPzc8BzM8ByjfWtL8dIDr72wEAAH6sJtfwN4eQpKeFzy1tE7P7P5xxeZu9xkdOvMTjHQB+0d6Hn1mxe9Tvjzo78c/75/ued1iyWn077X2KuYokSZIq2pA9TzI21w/t+vvTE/ve3f3QX4qe769esy7MmLvQNZOKaPqcheHbjf8NVauPPvncvTslbVaXDy9kOoZCJqsiu79j97CJ75KkmI3uNbgiv1m3d+zp71/q6huOsbMRAACg9Ow0BojFoWAA0ceZXjoOEIM7B/B/2bvvKCuqhOHX87333nXX+9217lr3/vN+NqCe0+TUpwmCioqKAYFuogETjoFRHHXMCuoYx6wDKgYMqAxiBjMqCmICIwq0WQcjIhJFQve+yHrHO45hqrrr1Dl9zvOs9fvfripO7V17W0WssaaXjgNE56XjANbPAayfA1g/B7B+DgCA+bn5OYD5OUD+xpr2twNEZ387AADA/++c/6iorv3eh0hKp4+XfFEWs/slny8N2243rCzP8SXX3OnxDgC/6IuvloWtuw8p2D3qiWdfTvXv/eyrFT6UrKLvsJPHm6dIkiSp4A0+4jzjc21p3JX3pHbdjTzmnCbN+x+evdA5kxrZ2+817/XCrrsd7P5dIt3QtjrUZbJqQsd27ONakhSrVtU14ZnK9qn/Xs1s3cHxT7pc7fn2NgIAACTPbmOAWHwUDCD6ONNLxwFicOcAiDXW9NJxgOi8dBzA+jmA9XMA6+cA1s8BADA/Nz8HMD8HyN9Y0/52gOjsbwcAAPiHllUDWvgISQl9GKf74LB+/YaymeGf+Zfry/I8T7nvCY93APhFV980rWD3p257HhY2btqU6t878/k6H0lW0X+sfuueQ81VJEmSVPAOOuEKY3T9WPVeR6S2ZvHZl183et7/wZJlzpfUyKbPeqtZP+cccdQ49+8S6eDOu4S6TFZN6LVM61BVNcD1JClWJ3fcIfXfq5eybR37xKu5zu5GAACA5NltDBBv6c6dAyDyONNLxwFicOcAiDXW9NJxgOi8dBzA+jmA9XMA6+cA1s8BADA/Nz8HMD8HyN9Y0/52gOjsbwcAAPiHrboP7uMDJKVTtz0PK6sZ/ldfLw+tt9+37M7z7Bdf93gHgJ9paGgIOwwaXbD70yXX3Jnq37vu+w1h4rTnfSRZRduVt80KXXYfZZ4iSZKkouiYcTcap+vHDj3p6tSuvWtvva/Rc//6hoZwy/0vOWdSI7pu6tzw3fcbmu2zznGX3Oj+XSK1yQ0KC7KVoS6TVRO6vl0315OkWHXKDQhvZdL9/V24uZaOfbLlaqbZ3QgAAJA8O44BYvFRMIDo40wvHQeIwZ0DINZY00vHAaLz0nEA6+cA1s8BrJ8DWD8HAMD83PwcwPwcIH9jTfvbAaKzvx0AAOAfWlbVHOgjJKXToENOLbtZ/nlX3lJ25/mDjz/zeAeAn3l+3oKC3ZtadR8cPvn0y1T/3lcXLfGBZBV1exx4ujmKJEmSiqbTLp1qnK4fu3TSzNCqx9BUrr1dh/+xSfP/51790DmTGtnC979sts8677zvCffvEmpym6pQl8mqiQ3rspvrSVKsJrarTv23qm1uoGOfZLmap+xuBAAASJ4dxwCx+CgYQPRxppeOA8TgzgEQa6zppeMA0XnpOID1cwDr5wDWzwGsnwMAYH5ufg5gfg6Qv7Gm/e0A0dnfDgAA8A8V1TVjfYSkdDr6tMvKbpb/zbcrQ7sd9y+bc7xNz6Fhw4aNHu8A8DPHjr2yYPenA44+J/W/986HXvFxZBVtR515vfmJJEmSiqoLJj5irK6ftOu+J6d2/S1Y/H7j1wBWrHW+pEb20DNvN9tnnfPfWOz+XUId2WmnUJfJqonNqmwfsrlBrilJkevfZffUf6t6dO3v2Cdazet2NwIAACTPjmOAWHwUDCD6ONNLxwFicOcAiDXW9NJxgOi8dBzA+jmA9XMA6+cA1s8BADA/Nz8HMD8HyN9Y0/52gOjsbwcAAPiHiuraG32ApHS68OrbynKmf+m1U8rmHO8+4jiPdgD4mVWr14bW2+9bsPvTQzPnpvr3fvL5ch9GVtF2wXUPhex2I8xPJEmSVDS17DY4jL/jWeN1/aTjz7s1tWvwnMsmNek5wLTHX3fOpEZ03V1zw7r1G5vl887Va77bcv9yHy+NOuYGhoWZbKhTkxvbobdrSlKsnqjskOrvVN8ueznuSZar+bvdjQAAAMmz6xggFh8FA4g+zvTScYAY3DkAYo01vXQcIDovHQewfg5g/RzA+jmA9XMAAMzPzc8BzM8B8jfWtL8dIDr72wEAAP6hRXXtTB8hKZ1unfZIWc70V65aEzrucmBZnOMxZ1zu0Q4APzP57scKdm/qutvBYcOGdD/O++icRT6MrKJs/B3Phh57H2VuIkmSpKKqXZ+Rxuv6+fzlztmh7eZrI41rMNfv0LBx06ZGPwdY8O7nzpnUyBZ/8GWzfebZa58j3MdLqLvbdA11maya2NuZyrBD171cU5Iid2zHPqn+Tg3o0s9xT7Jc7Vq7GwEAAJJn1zFALD4KBhB9nOml4wAxuHMAxBpreuk4QHReOg5g/RzA+jmA9XMA6+cAAJifm58DmJ8D5G+saX87QHT2twMAAPxDRXXtuz5CUjo9OWd+2c72x0+6pyzO8Q9/JwD8q/4jTyzYven8q25N9W9d+936cN1dc30UWUXZ0KPONy+RJElS0dVjn9HG6yr4HGbW3Fcb/Szg+/Ubw/XTnnfOpEb08OyFzfaZ54FjznUfL6H+2LFPqMtklUB3t+kaWrqmJEWsbW5geCPbOrXfqP067eq4J1zL3iP+0w5HAACAZNl1DBCLj4IBRB9neuk4QAzuHACxxppeOg4QnZeOA1g/B7B+DmD9HMD6OQAA5ufm5wDm5wD5G2va3w4Qnf3tAAAA/+1/VORq1/kASem0+L2Py3a2v/a7dSHX79CSP8dPPPuyRzsA/MQP9/9C3pve/XBJqn/vvLc+8UFkFWUnXXRHaNltsHmJJEmSiq7d9jvZmF2/2J/HP5DadTjmjMub9DzgibmLnTOpEU286/mwfsPGZvnc89wrbnEfL6FyuX3C4kw21CmRDu20s+tKUuSubNcjtd+nw/0+JV+XIS1tcQQAAEiWnccAsfgoGED0caaXjgPE4M4BEGus6aXjANF56TiA9XMA6+cA1s8BrJ8DAGB+bn4OYH4OkL+xpv3tANHZ3w4AAPCDVtU1FT4+UlqtWr22rGf8Eyc/UPLn+JNPv/RoB4CfOOvSmwp2Xxp6+Jmp/q0NDQ1h8vR5PoisouuSmx4PbfuMNCeRJElSUVZ7xHnG7frVuvcfncp1WNl7RFi1pvFrGB9/9o3zJTWydz5a2iyfe/7t/pnu4yXWjNadQl0mqwR6Mds2tMsNdF1JilTfrnul9vt0fMcdHfOEq6iqzdnlCAAAkCw7jwFi8VEwgOjjTC8dB4jBnQMg1ljTS8cBovPScQDr5wDWzwGsnwNYPwcAwPzc/BzA/Bwgf2NN+9sBorO/HQAA4AdbVQ3a0cdHSqcOO48s+xn/2u/Whc59DyrZc9xmh/1CfX2DRzsA/GjDho2hy64HF+zedN8jz6T69364ZJkPIavomjBlTthl+J/MSSRJklS0HXLiVcbu+tUOO2V8atfiXdOfavQzgfqGhnDz/S85Z1Ijenzu4mb57HPe64vcx0usUzpuH+oyWSXUpe16uq4kRW5G606p/Dad0aG34510VTW72uUIAACQLLuPAWLxUTCA6ONMLx0HiMGdAyDWWNNLxwGi89JxAOvnANbPAayfA1g/BwDA/Nz8HMD8HCB/Y0372wGis78dAADgBy1ztSN9fKR02mO/4035N7v02ikle44HHnyKEwzAT0x/4rmC3Zc67DwyfLfu+1T/3hnPvO1DyCq6Dj7hSvMRSZIkFXXHnjPJ2F2/2uU3Pxm26TEslWtxxFHjmvRc4Nn57ztnUiO64e4XwqZN9c3u2ee3K1a7j5dYvar2DnWZrBJqUaYy7NFlD9eWpEgd2WmnVH6bLmrf0/FOuK2qagfb5QgAAJAsu48BYvFRMIDo40wvHQeIwZ0DINZY00vHAaLz0nEA6+cA1s8BrJ8DWD8HAMD83PwcwPwcIH9jTfvbAaKzvx0AAOAHLXK1Z/r4SOk06vgLTPk3W75iVWizw34leY5PPneCEwzATxxw9DkFuy+Nu+TGVP/WVWu+D9dOnetDyCqqxl51b2jVY6j5iCRJkoq6M66YZvyu36zf/qemci227DY4/P2zrxr9bODzpSudL6mRffTpN83y+WfV7oe4l5dYT7TuGOoyWSXUQ5uP59a5GteWpH9bNjcovJJtk/ffpfHtujneCVeRG3SoXY4AAADJsvsYIBYfBQOIPs700nGAGNw5AGKNNb10HCA6Lx0HsH4OYP0cwPo5gPVzAADMz83PAczPAfI31rS/HSA6+9sBAAB+UJGrucHHR0qncRffaMr/38ZdcmNJnuObpsxwcgH40ZLPl4ZW3QcX7L606N2PUv17X3jjIx9AVlF15W2zQufdRpmLSJIkqej7yw2PGcPrNzvxgttTux4n3HxPk54P3D5jvnMmNaJZL7/bLJ+BDj9yrHt5iXVWh96hLpNVgo3p2Me1JSna3LB9z7z/Jt3ctsqxTrpczfF2OQIAACTLDmSAWHwUDCD6ONNLxwFicOcAiDXW9NJxgOi8dBzA+jmA9XMA6+cA1s8BADA/Nz8HMD8HyN9Y0/52gOjsbwcAAPhBi+qaJ3x8pHSaOPkBU/7/9tmXX4dteg4tuXM87/VFTi4AP7ri+qkFuycNPPiUVP/WTfUN4Zb7X/IBZBVVex90pnmIJEmSir5W3YeE8VPmGMPrN5uw+RrpsPNBqVyTfYeOadIzghff/Ng5kxrRpPteCg0NDc3uGejpF050Py+xdu26Z6jLZJVgr2TbhI65ga4vSf+2HbruFRbn+TdpWpsujnXCVeRqzrbLEQAAIFl2IAPE4qNgANHHmV46DhCDOwdArLGml44DROel4wDWzwGsnwNYPwewfg4AgPm5+TmA+TlA/saa9rcDRGd/OwAAwA9aVNe84+MjpdOMmXNN+f/JceOuKqnzu+12w8L369c7sQBsUV/fEHoPOLJg96W/3T8z1b/33Y+X+vixiqpjxt1oDiJJkqRmUYddDjaGV6SG/+Gi1K7LNxe93+hnBMtXrnW+pEb22dKVze456C1TH3Y/L7Fabm52ZftQl8kqwS5r38P1JSlSd7fpmtffo4dbd3Kcky5Xe4VdjgAAAMmyCxkgFh8FA4g+zvTScYAY3DkAYo01vXQcIDovHQewfg5g/RzA+jmA9XMAAMzPzc8BzM8B8jfWtL8dIDr72wEAAH73u3P+oyJXu87HR0qnVxfUmfL/k7r3Pgktuw0umfM76JBTnVQAfjT7xdcLdk9qt+P+Yc3adan+vQ88tcCHj1U0XTDx4ZDtta85iCRJkppFvQYeYxyvSJ17zfTUrsuzL5vUpOcEdz32mnMmNaK5r33Y7J6DznnpDffzEuwv7XuGukxWCbYoUxl27bqn60vSv+3gTn3z+nv0bGV7xznpcrU32+cIAACQLLuQAWLxUTCA6ONMLx0HiMGdAyDWWNNLxwGi89JxAOvnANbPAayfA1g/BwDA/Nz8HMD8HCB/Y0372wGis78dAACgVXVNhQ+PlFZLly035f8Xo46/oGTO73lX3uKEAvCjY06/vGD3pFPPvzbVv3X5yu989FhF0/g7Z4ftBhxt/iFJkqRm0x4HnGYsr8j16P+HVK7Lqt0PCRs3bmr0s4LXFn/qfEmNaPL0+c3uOegXXy1zPy/BBnXZPdRlskq4+1p3Di1dX5L+TdtU14QXs23z9lv0SraN45xwFbmae+10BAAASJZdyACx+CgYQPRxppeOA8TgzgEQa6zppeMA0XnpOID1cwDr5wDWzwGsnwMAYH5ufg5gfg6Qv7Gm/e0A0dnfDgAAUJGr3cGHR0qnTK/hob6+wZT/X8x/Y3HJnONHnnrBCQVgi29XrA7ZXiMKdk964+13U/17n3v1Ax89VtE0/A8XmX9IkiSpWTV09AXG8orcqJP+mtq1+dSc+Y1+VrDmu/Xh2qlznTOpES37dk2zehba0NAQ2vc5wD29xNq6uia8km0T6jJZJdwhnXdxjUn6t53TvlfefocWZSpDq82/845zguVqnrLTEQAAIFl2IgPE4qNgANHHmV46DhCDOwdArLGml44DROel4wDWzwGsnwNYPwewfg4AgPm5+TmA+TlA/saa9rcDRGd/OwAAQMuqmgN9eKR02rHmD6b7v2Lo4WeWxDn+6uvlTiYAW9wy9eGC3Y/23P+EVP/WjZvqw033vuiDxyqKTv7LlNCy22DzD0mSJDWrRp30V+N5Re6Smx4PrboPSeXa/OPYK5v0zODBp99yzqRGNO+tT5rd89CBB5/inl6CXde2W6jLZJVwL1a2DW1zg1xjkn6z6qp9wsJsZd5+i9rlBjrOCVaRq51vpyMAAECy7EQGiMVHwQCijzO9dBwgBncOgFhjTS8dB4jOS8cBrJ8DWD8HsH4OYP0cAADzc/NzAPNzgPyNNe1vB4jO/nYAAICK6pqxPjxSOu03+izT/V/x9HOvNPvzu/3Ao5xIAH605/4nFOyedNu0R1P9Wxd98KWPHasouvTmmaFdn5HmHpIkSWp2HXfuLcb0itVOw9J57tBux/3Duu/XN/qZwcL3PTOQGtNdj73W7J6HHn/W1e7pJdjBnfqGukxWeeic9r1cY5L+/Zpfm6q8/Q51q+rvGCdYRa72PTsdAQAAkmUnMkAsPgoGEH2c6aXjADG4cwDEGmt66ThAdF46DmD9HMD6OYD1cwDr5wAAmJ+bnwOYnwPkb6xpfztAdPa3AwAAVFTX3OTDI6XTSX+eYLr/KxoaGkLfoWOa9fk9duyVTiQAWyxY/H7B7kett983rFy1JtW/954n3vCxYxVFu+17inmHJEmSmmXjrrzHmF6xOnrcDaldnw8/+Xyjnxl8v35jmDjteedMakSr1nzfrJ6J/nXS3e7pJVjb3MDwdqYy1GWySrgfjmvvqr1dZ5J+s+Gdd83b79COVXs5xolWs9RORwAAgGTZjQwQi4+CAUQfZ3rpOEAM7hwAscaaXjoOEJ2XjgNYPwewfg5g/RzA+jkAAObn5ucA5ucA+Rtr2t8OEJ397QAAAC1yNU/56EjpdOUNd5nu/4bJdz/WrM/vD//9APCDsX+5oWD3oxPO/muqf+vXy9f4yLGKotFnTjTnkCRJUrPtkklPGNcrVldNnhUyvYancn0eefLFTXp28Ohzi5wzqREtePfzZvVMdMbMue7pJdqUNl1DXSarPHRnmyrXmKTfrFV1TXi2sn1efoP26LKHY5xgFbmaDXY6AgAAJMtuZIBYfBQMIPo400vHAWJw5wCINdb00nGA6Lx0HMD6OYD1cwDr5wDWzwEAMD83PwcwPwfI31jT/naA6OxvBwAAqMjVvufDI6XTtOlPm+7/hjVr14UOO49stuf37boPnUQAwvr1G0KnvgcW7H708uuLUv17n5n3no8cq+BddP0jIdt7hDmHJEmSmmVb9xwaJkyZY2yv2O154OmpXKOVm+dbq9d81+hnB+///WvnS2pEM555u1k9F134zkfu6yXamI59Ql0mqzw1rMturjNJv9mpHbbPy+9Prd+fxNuq+8D/abcjAABAcuxIBojFR8EAoo8zvXQcIAZ3DoBYY00vHQeIzkvHAayfA1g/B7B+DmD9HAAA83PzcwDzc4D8jTXtbweIzv52AACg3J3zHxXVNet9dKR0en7eAtP9f+PcK25plue2y64Hh/r6BicQgDBj5tyC3Y92GTImNDSkdz/asHFTuPGeF3zkWAVtwpQ5YYfaP5pvSJIkqdnWaddDje3VqE688PbUrtN7H36m0c8PNm2qDzfd+6JzJsVs4l3Phw0bNjWb56Jrv1sXWnYb7N5eglVX7RMWZ7KhTnlpVmX7sG11jWtN0q/vR9n8O7wwD78/B3Tu6/gm3Nbdh2xlvyMAAEBy7EgGiMVHwQCijzO9dBwgBncOgFhjTS8dB4jOS8cBrJ8DWD8HsH4OYP0cAADzc/NzAPNzgPyNNe1vB4jO/nYAAKC8VfSobeWDI6XVx0u+MN3/Nz759MvQqnvz++DemDOvcPIA2OKgY88t2P3ohjseTPVvfevdz33gWAXvkBOvNteQJElSs2772mON7dWoxt85O7TtMzKV6/SQ485v0jOEp1961zmTGtEHf1/WrJ6N9tz7cPf2Eu3h1p1CXSarPHVyxx1cZ5J+s5vbViX+23N4p50d24T7X9WDO9jxCAAAkBw7kgFi8VEwgOjjTC8dB4jBnQMg1ljTS8cBovPScQDr5wDWzwGsnwNYPwcAwPzc/BzA/Bwgf2NN+9sBorO/HQAAKG9bdavdyQdHSqdW3QeHDRs2mu5HMOr4C5rd+b334WecOADCF18tC1t3H1KQe9G22w0Ly5avTPXvnfbY6z5urIL25/EPhG16DDPfkCRJUrOu/8Fjje/V6GqPOC+V63SbnkPD8hWrGv0TrscxAAAgAElEQVQMYcmX3zpfUiN66qV3m9Xz0f1Gn+XeXqKd2aF3qMtklafezLYO1VX7uNYk/WrDuuyW+G/PsR37OLZJ121QbzseAQAAkmNXMkAsPgoGEH2c6aXjADG4cwDEGmt66ThAdF46DmD9HMD6OYD1cwDr5wAAmJ+bnwOYnwPkb6xpfztAdPa3AwAA5a1FruYQHxwpnbrteZipfkSz5r7arM5tq+6Dw9ffrHDiAAgTbr6nYPejI0++ONW/9YuvV/qwsQra+Dtnhx79/2CuIUmSpGbfAX+81BhfjW7sFXendq1Oue+JRj9HaGgI4bYH5zlnUsxuvu+lzf9+GprN89EzLpro3l6i7dp1z1CXySqPXde2m2tN0q/vS6muCXMq2yX6u3Nqh+0d24RrWT1obzseAQAAkmNXMkAsPgoGEH2c6aXjADG4cwDEGmt66ThAdF46DmD9HMD6OYD1cwDr5wAAmJ+bnwOYnwPkb6xpfztAdPa3AwAA5a0iV3O2D46UTjWHnmqqH1F9fUPoPeDIZnNu+x94kpMGwBa7DBlTsPvR08+9kurf+uSL7/iwsQraiKMvMs+QJElSSXT0uBuM8dWkuu5+WCrX6r5HndWkZwlzX/vQ+ZIa0Rdfr2o2z0dvvHO6e3uJ1nJzz2XbhbpMVnlq8eb27tLP9SbpVxvboXeivzt/7tDLcU24iura/ex4BAAASI5dyQCx+CgYQPRxppeOA8TgzgEQa6zppeMA0XnpOID1cwDr5wDWzwGsnwMAYH5ufg5gfg6Qv7Gm/e0A0dnfDgAAlLcWudpbfHCkdDrm9MtN9WO4+qZpzebcXnbdFCcMgDDv9UUFuxd13+v3YVN9fWp/6/frN4brpz3vo8YqWGdcPi206jbYPEOSJEkl0Q/jW+N8NaX9j700lWu1VffB4cul3zT6ecLS5audL6kRvfjGR83mGelTc+a7t5dwl7brGeoyWeWxh1p3DK2qa1xvkn6x6qp9wsJsZWK/OZds/l13XBNvtB2PAAAAybEzGSAWHwUDiD7O9NJxgBjcOQBijTW9dBwgOi8dB7B+DmD9HMD6OYD1cwAAzM/NzwHMzwHyN9a0vx0gOvvbAQCA8lZRXTvLx0ZKpwv/OtlUP4aly5aHbXoObRbndt7ri5wwAMLJ504o2L3o4mvuSPVvfaPuUx80VsG6avKs0GX3UeYYkiRJKpkuuelxY301qQsmPhJadhucyvV6898eatIzhb898qpzJsVs6qOvNZtnpB9+8pl7ewk3uPPuoS6TVZ47tNPOrjdJv9qdbasS+72Z0K67Y5pwW1XXnmrHIwAAQHLsTAaIxUfBAKKPM710HCAGdw6AWGNNLx0HiM5LxwGsnwNYPwewfg5g/RwAAPNz83MA83OA/I017W8HiM7+dgAAoLy1qK75yAdHSqfbpj1qqh/T4Sf+pejPa8ddDgwbN21ysgDK3Nrv1oX2fQ4oyL3oh49m//Cx2jT5ALYK2cBRZ5tfSJIkqWTadrvhYcKUOcb6anK9Bh6dyjVbO+q0Jj1TeHnBJ86X1IhWrl7XLJ6T/rBmtu12w9zjS3XcUl0TXs22DnWZrPLY3Mq2IZsb5JqT9Isd0LlvYr83k9rmHNOEq6iuudCORwAAgOTYnQwQi4+CAUQfZ3rpOEAM7hwAscaaXjoOEJ2XjgNYPwewfg5g/RzA+jkAAObn5ucA5ucA+Rtr2t8OEJ397QAAQBnbZZf/vUWudqMPjpROT86Zb6of0zPPv1r053X0qZc6UQCEex6aVbB70dDDz0z1b13y5bc+ZKyCdeIFt4eW3QabX0iSJKlkqtrjcGN9JdJhp0xI5Zr9YU625POljX6u8M2Ktc6X1IjefOezZvOsdJchY9zjS7gb2laHukxWee6Ujtu73iT9YttU14QXs20T+a2Z2qaLY5p0udprbHoEAABIjt3JALH4KBhA9HGml44DxODOARBrrOml4wDReek4gPVzAOvnANbPAayfAwBgfm5+DmB+DpC/sab97QDR2d8OAACUr/+qqt3Wx0ZKq8XvfWyqH9Om+vrQfa/fF/V5nfrgk04UAGH4kWMLdi+6e8bTqf6tj89d7EPGKkiX3TIztOsz0txCkiRJJVXf4Sca7yuRLrnp8dCq2+BUrttrb7u/Sc8Wpjz8qnMmxWzGM283m2elhx53vnt8CTeq086hLpNVnnst0zp0zg1wzUn6xc5r3yuR35rprTs5nglXkau5w65HAACA5NidDBCLj4IBRB9neuk4QAzuHACxxppeOg4QnZeOA1g/B7B+DmD9HMD6OQAA5ufm5wDm5wD5G2va3w4Qnf3tAABA+WpRVdvXx0ZKq1Vr1prqN8KFV99WtOd06+5DwtJl3zpJAGXuk0+/DC1T+mj1v9a+zwFh7XfrUvtb165bH667a64PGasg7b7/qeYVkiRJKrlqjzjPeF+JtePg41K5bvc64E9Ner7w0oKPnS8pZhOnPR82bqpvFs9Lz75sknt8Cdc+NyAszFaGukxWee7y9j1cc5J+sV5Ve4fFCfzOzGzdwfFMvJoH7HoEAABIjh3KALH4KBhA9HGml44DxODOARBrrOml4wDReek4gPVzAOvnANbPAayfAwBgfm5+DmB+DpC/sab97QDR2d8OAACUr4rqmsN8aKR06rDzSNP8Rnrng78X7Xnd/w9nO0EAhMuum1Kwe9Gp51+b6t86/+2/+4ixCtIfxt5gXiFJkqSSbNRJVxvzK7GOOO3a1K7ddz9c0ujnC8u+XeN8SY3o48+WN4vnpTf/7SH3+BLv/jadQ10mqzy3MFsZ+nTdyzUn6Re7u02XJv/OzK1s61gm30y7HgEAAJJjhzJALD4KBhB9nOml4wAxuHMAxBpreuk4QHReOg5g/RzA+jmA9XMA6+cAAJifm58DmJ8D5G+saX87QHT2twMAAOWrRXXtn31opHTaY7/jTfOboP+BJxXleZ1y3xNODkCZq69vCL32OaJg96JXF9Sl9rc2NIQwefp8HzBW6l10w6Mh23tf8wpJkiSVZMeff5txvxLrsltmhlbdh6Ry7V5147QmPWeY8vArzpkUs9mvvN8snpk+NWe+e3yJd2qH7UNdJqsUuqNtV9ecpF9sVKedm/wb82q2tWOZcBW52hftegQAAEiOXcoAsfgoGED0caaXjgPE4M4BEGus6aXjANF56TiA9XMA6+cA1s8BrJ8DAGB+bn4OYH4OkL+xpv3tANHZ3w4AAJSviurayT42UjoddsKFpvlNcPPfHiq6c7pNz6Fh+YpVTg5AmZvz0hsFuxftMmRMqn/rx5994+PFSr0JU+aEPkOON6eQJElSyfbn8Q8Y+yvRdhp2QirX7h77Hd+k5wwvvfmx8yXF7PYZ85vFM9P3PlriHl/i7dJ1z1CXySqlajvv5rqT9LOyuUHhlWybJv2+LMxWOpYJV5GrWWDXIwAAQHLsUgaIxUfBAKKPM710HCAGdw6AWGNNLx0HiM5LxwGsnwNYPwewfg5g/RwAAPNz83MA83OA/I017W8HiM7+dgAAoHxV5Gpn+9hI6TTu4htN85tg2fKVYZseQ4vqnB507LlODADh2LFXFuxedP3tD6b6tz48e6GPFyv1Rp10tfmEJEmSSraW3QaHqybPMvZXoo0+c2Jq1/BHf/+80c8Zvl6+xvmSGtG3q74r+mem69dvCK26D3avL+UxzOaey7YLdZmsUujx1h3C1q47Sb/Qxe17Nvk3ZtvqGscy2T606xEAACA5dikDxOKjYADRx5leOg4QgzsHQKyxppeOA0TnpeMA1s8BrJ8DWD8HsH4OAID5ufk5gPk5QP7Gmva3A0RnfzsAAFC+WuRqP/GhkdJp4uQHTPObaOQx5xTVOb17xtNOCkCZW7V6bajsPaIg96Fteg4NX3+zIrW/dfXa78O1U+f6cLFS7c8Tpm++1oeZT0iSJKlka9tnpLG/Eu+KW58KW/ccmso1fO2t9zXpecMdD813zqSYvfnOZ83i2WnPvQ93ry/xrmjfI9Rlskqpozrt5LqT9LN26rpXk39f2ucGOJaJVrPUrkcAAIDk2KkMEIuPggFEH2d66ThADO4cALHGml46DhCdl44DWD8HsH4OYP0cwPo5AADm5+bnAObnAPkba9rfDhCd/e0AAEB56t79qP+jRa5mkw+NlE4PP/m8aX4T/e2BJ4vmfGZ6DQ+rVq91UgDK3B33Pl6we9ERJ12c6t/60oKPfbRYqTb+ztmhR/8/mEtIkiSppOs18Gjjf+WlviNOSuUa3uegk5v0vOGFNz5yvqSYzXjm7Wbx7HTYEWe615d4IzrvGuoyWaXUi9m2oW1ukGtP0s+a3rpTk35fcrl9HMcky9WutfMRAAAgOXYqA8Tio2AA0ceZXjoOEIM7B0CssaaXjgNE56XjANbPAayfA1g/B7B+DgCA+bn5OYD5OUD+xpr2twNEZ387AABQnlp1H1zpQyOl1Rtvv2ua30Tfrlgdtuk5tCjO5+//dJETAkAYdMipBbsXPTlnfmp/Z31DQ7j1gZd9tFiptt+Yi80jJEmSVPLteeAZxv/KS8eMuzGVa7hlt8Hh0y+WNvqZw9JvVjtfUswmTns+bNxUX/TPTk8+d4J7fYlXmRsUFmQrQ10mq5Qa16GXa0/Szzqq405N+m3pXbW345hwvxsx4n+z+xEAACAZdioDxOKjYADRx5leOg4QgzsHQKyxppeOA0TnpeMA1s8BrJ8DWD8HsH4OAID5ufk5gPk5QP7Gmva3A0RnfzsAAFCeKqprd/eRkdJq2fKVpvkJOPiP5xXF+Xzw8TlOBkCZe/+jTwt2H8r1GxU2btqU3t/69699sFipdvbV94dW3YeYR0iSJKnk2++Yi80BlJeuvG1W2KbnsFSu45umzGjSc4c7Zsx3zqSYffz58qJ/fjp+0j3u9WXQnW2rQl0mq5R6M9s6VFft49qT9JNaVw8Kr2VaN/q3pW/XvRzHhPt/t9v7/7b7EQAAIBl2KwPE4qNgANHHmV46DhCDOwdArLGml44DROel4wDWzwGsnwNYPwewfg4AgPm5+TmA+TlA/saa9rcDRGd/OwAAUJ5a5mqP8JGREvqAzfb7muIn9aRgxtNFcT7XrF3nZACUuQuuvq1g96K/TLgj1b91+qy3fKxYqTX+ztmhx95HmUdIkiSpLDrqzInmAcpbu+13cirX8ZDDTm/Sc4cXXv/I+ZJiNueVD4r++en0J55zry+DxnTsE+oyWaXY+HbdXHuSftaV7Xo0+ndl7y79HMOEa1VdU2H3IwAAQDLsVgaIxUfBAKKPM710HCAGdw6AWGNNLx0HiM5LxwGsnwNYPwewfg5g/RwAAPNz83MA83OA/I017W8HiM7+dgAAoDy1yNWe7yMjpVPfoWNM8ROyYuXqsE2PoQU9n8ecfrkTAVDmNm7aFHL9RhXkPtSy2+DwwcefpXfvXb0uXDvVh4qVXvsfe6k5hCRJksqmUy+Zah6gvHXsOZPS+WB898Hhq6+XN/rZw1fLVjtfUsxunzG/6J+hvrnwPff6MqhH1/6hLpNVii3KVIa+XfZy/Un6Sf267NHo35XaLrs5hglX0XVwW7sfAQAAkmHHMkAsPgoGEH2c6aXjADG4cwDEGmt66ThAdF46DmD9HMD6OYD1cwDr5wAAmJ+bnwOYnwPkb6xpfztAdPa3AwAA5akiV3OHj4yUTgcde64pfoKGHzm2oOdz7rw3nQSAMvfknPkFuw8N/f0Zqf6tz7/2oQ8VK7XOGf9AaNVjqDmEJEmSyqaLrn/EXEB566rJs0Km1/BUruXbpj3apOcPk6fPd86kmH276ruifoa6YuVq9/oyaWbrDqEuk1WKTWnT1bUn6Wc90rpTo35T9uu0q+OXcFt1H9jN7kcAAIBk2LEMEIuPggFEH2d66ThADO4cALHGml46DhCdl44DWD8HsH4OYP0cwPo5AADm5+bnAObnAPkba9rfDhCd/e0AAEB5alFdO9dHRkqnMy6aaIqfoBvueLBg53KHQaNDQ0ODkwBQ5g4/8S8FuxdNm/50an/npvr6cPN9L/lIsVJp/J2zQ/f+o80fJEmSVDa16jE0jJ8yx3xAeW2PA05L5Xre96izmvQMYu5rHzpfUszeevfzon+O2mHnke75ZdD57XuFukxWKTeoy+6uP0k/6Y8d+zTq9+SQzrs4fgnXsrpmZ7sfAQAAkmHHMkAsPgoGEH2c6aXjADG4cwDEGmt66ThAdF46DmD9HMD6OYD1cwDr5wAAmJ+bnwOYnwPkb6xpfztAdPa3AwAA5amiuvZTHxkpna699T5T/AR9vOSLgp3LiZMfcAIAytzyFatCptfwgtyH2u64X1izdl1qf2vdR1/5QLFSa+Rxl5k7SJIkqazqsvsocwHlvePOvTWV63nr7kPCsuUrG/0M4ouvVzlfUswenbOo6J+l7rn/Ce75ZdCALv1CXSarlJvRulNo6fqT9E+1zw0IC7KVsX9Pjuq4k+OXdLnafex+BAAASIZdywCx+CgYQPRxppeOA8TgzgEQa6zppeMA0XnpOID1cwDr5wDWzwGsnwMAYH5ufg5gfg6Qv7Gm/e0A0dnfDgAAlJ/Wrff+P1tU19T7yEjp9ODjc0zxE7bLkDGpn8dMr+FN+igoAKVh0pQZBRtTnHzeNan+rfc9+aYPFCuV/jzhwbB1z6HmDpIkSSqr+gw53nxAee/qO54J2e1GpHJN/+2BJ5v0HGLy9HnOmRSjG+55IdTXNxT1s9TDT7zIPb8M2rq6JrySbRPqMlml3AGd+7oGJf2k69p2i/1bclyHHR27hKvoNnhfOyABAACSYdcyQCw+CgYQfZzppeMAMbhzAMQaa3rpOEB0XjoOYP0cwPo5gPVzAOvnAACYn5ufA5ifA+RvrGl/O0B09rcDAADlp0VuQBsfGCmtXl1QZ4qfsAuuvi3183jM6Zc78ACEPfY7vmBjilfeTG9M8c2KtT5OrFQaP2VO6LHPaPMGSZIklV0DDzvHnECptMcBp6VyTR907LlNehbx3KsfOl9SzD5furKon6Wec9kk9/wy6ca21aEuk1XKPVXZIWzt+pP0Tw3o0i/2b8mpHbZ37BKuorrm93ZAAgAAJMOuZYBYfBQMIPo400vHAWJw5wCINdb00nGA6Lx0HMD6OYD1cwDr5wDWzwEAMD83PwcwPwfI31jT/naA6OxvBwAAys9WVYP39IGR0uqrr5eb4idszktvpH4en5+3wIEHKHMLFr9fsPFE36FjUv1bZ89/34eJlUoHnXClOYMkSZLKsoP/dJU5gVLp2HMmpXJNb7vdsLBy1ZpGP4v44uuVzpcUs5cXfFLUz1MnTZnhnl8m/b7TzqEuk1UBOqrTTq5BST/WcnNPV7aP9Ttydvvejl3y5+GPdkACAAAkw85lgFh8FAwg+jjTS8cBYnDnAIg11vTScYDovHQcwPo5gPVzAOvnANbPAQAwPzc/BzA/B8jfWNP+doDo7G8HAADKT4vq2tE+MFI6ZXuNCA0NDab4Cft+/fpQ2XtEaudxh0GjnUcAwrhLbizYmGLi5AdS+zs3bqoPN937og8TK++de830sE3PYeYNkiRJKsuOP/828wKl0pW3zUpt7nXfI8806ZnEbQ/Oc86kGN07882ifp762KyX3PPLpM65AWFRpjLUZbJKueey7UI2N8h1KOnHTu64Q6zfkYva93Tcki436Aw7IAEAAJJh5zJALD4KBhB9nOml4wAxuHMAxBpreuk4QHReOg5g/RzA+jmA9XMA6+cAAJifm58DmJ8D5G+saX87QHT2twMAAOWnorr2Ih8YKZ12HnKM6X2e7Df6rNTO4/W3P+iAA5S5DRs2hi67HlyQ8cQ2PYaGpcuWp/a3Lnz/Cx8lVt6bMGVO6D3wGHMGSZIklW3nXTPD3ECpteuIk1K5rg8/8aImPZOY88oHzpcUo+umzg3rN2ws2meqb9d96J5fRs1o3SnUZbIqQCd23NE1KOnHOlcNCAszlZF/Q65s18NxS7pc7QV2QAIAACTD7mWAWHwUDCD6ONNLxwFicOcAiDXW9NJxgOi8dBzA+jmA9XMA6+cA1s8BADA/Nz8HMD8HyN9Y0/52gOjsbwcAAMpPi+qav/nASOk08phzTO/z5Jpb7k3lHGZ6DQ/ffLvSAQcoc4/NerFg44mmfpA6rmmPv+6jxMp7h5x4tfmCJEmSyrZW3YeE8XfONjdQao0ee30q13Zl7xFhzdp1jX4m8emXK5wvKWYfLFlWtM9UV65a475fRp3VoXeoy2RVgF7JtgntcwNch5J+bFK7XOTfkGvadXPMEq6iuvavdkACAAAkw+5lgFh8FAwg+jjTS8cBYnDnAIg11vTScYDovHQcwPo5gPVzAOvnANbPAQAwPzc/BzA/B8jfWNP+doDo7G8HAADKT4tczQs+MFI6nXL+tab3efLmwvdSOYdjzrjcwQYgHHbChQUbT8ycPS+1v/OrZat9jFh57/xrZ4RttxtuviBJkqSyrfNuo8wNlGqX3/JkaNV9SCrX9yNPvdDo5xINDQ1h0n0vOmdSjJ6d/35RP1ftsPNI9/4yqX+XfqEuk1WBOrt9b9ehpB8b2mW3yL8fN7atdsySLld7sx2QAAAAybB7GSAWHwUDiD7O9NJxgBjcOQBijTW9dBwgOi8dB7B+DmD9HMD6OYD1cwAAzM/NzwHMzwHyN9a0vx0gOvvbAQCA8lORq/3CB0ZKp/GT7jG9z5P6+oZUPsT3+lvvOtgAZe7rb1aEbXoOLchYonqPUWHjpk2p/a2zXn7Xx4iV1yZMmRN6DxpjriBJkqSybpdhfzI/UOrtNPT4VK7v48+6uknPJma+UOd8STG686FXivrZ6p77n+DeXyZtvblXs21CXSarAvRmtnXI5fZxLUraUqvqmjCnsl2k34/b2uYcs6TL1UyzAxIAACAZdjADxOKjYADRx5leOg4QgzsHQKyxppeOA0TnpeMA1s8BrJ8DWD8HsH4OAID5ufk5gPk5QP7Gmva3A0RnfzsAAFBeWvYe8Z8tqmsbfGCkdLr/kWdN7/No5DF/zuv5G/r7MxxkAMJNU2YUbCxx4V8np/Z3rt+wMdxw9ws+Rqy8dtjJ480TJEmSVPYNOfJ88wOl3uGnXZPK9d2570FhU319o59PvPfJ186XFLOVq9cV7bPVw0+8yL2/jJrUNhfqMlkVqEvb9XQdSvqxc9r3ivTbMaVNV8cr4Sqqax+2CxIAACAZdjADxOKjYADRx5leOg4QgzsHQKyxppeOA0TnpeMA1s8BrJ8DWD8HsH4OAID5ufk5gPk5QP7Gmva3A0RnfzsAAFBe/lf14A4+LlJazXt9kel9Hl1x/dS8nr8nnn3ZQQYg7LHf8QUbS7z30ZLU/s433/nMR4iV1y6Y+EjI9BpuniBJkqSy7/DTrjFHUOpdctPjoVW3walc4y+9+najn09s2LgpTLzreedMitHC978o2mer51w2yb2/jDqq406hLpNVgVqYqQw9q/q7FiVtqVfV3mFxhN+Ou9t0cbwSriJX+7RdkAAAAMmwgxkgFh8FA4g+zvTScYAY3DkAYo01vXQcIDovHQewfg5g/RzA+jmA9XMAAMzPzc8BzM8B8jfWtL8dIDr72wEAgPLSsnrQ3j4uUlp9/uUy0/s8evaF1/N27vrUHh3q6xscZIAyt/Cdjwo2jhhy2Omp/q1/e+RVHyFW3powZU7YofaP5giSJEnS5k65eIp5ggpS70FjUrnGz7vyliY9o5g+6y3nS4rR43MXF+3z1UlTZrj3l1HVVfuEukxWBey6dtWuRUk/dl/rzv/2d2N6606OVdLlal6wCxIAACAZdjEDxOKjYADRx5leOg4QgzsHQKyxppeOA0TnpeMA1s8BrJ8DWD8HsH4OAID5ufk5gPk5QP7Gmva3A0RnfzsAAFBeKnKDj/ZxkdJp2+2Ghfr6BtP7PFq1em1o1X1wXs7f5Lsfc4ABCOdcNqlgY4m7pj+V2t/52VcrfIBYee33p15jjiBJkiT9d3+54VHzBBWkQ0+6OpVrvE/t0U16TrHg3c+dLylGN9//UtE+X31s1ovu/WXWzNYdQl0mqwK1eHN9u+zlWpS0pSM77fRvfzcea93RsUq+1+yCBAAASIZdzACx+CgYQPRxppeOA8TgzgEQa6zppeMA0XnpOID1cwDr5wDWzwGsnwMAYH5ufg5gfg6Qv7Gm/e0A0dnfDgAAlJcWuZpLfFikdNph0GhT+xTsNuKPiZ+7XL9Dw7rv1zu4AGVu48ZNoWr3Qwoyjmi34/5hzdp1qf2tM5+v8wFi5a0Lr38kZLcbYY4gSZIkbS7Ta3iYMGWOuYIK0kWb52ctuw1O5Vp/98MljX5Osea79c6XFLNl364pymesby58z/2/zLqww3ahLpNVAbuzbZVrUdKW2uYGhTezrX/zN+PpyvaOVdLlahbZBQkAAJAMO5kBYvFRMIDo40wvHQeIwZ0DINZY00vHAaLz0nEA6+cA1s8BrJ8DWD8HAMD83PwcwPwcIH9jTfvbAaKzvx0AACgvLXI103xcpHTab/RZpvYpOP6sqxM/d9fedr8DC0B44tmXCzaOOPm8a1L7O7/7fkOYeNfzPj6svDRhypzQZ8jx5geSJEnSf9d976PMFVTQuvcfncq1fu2t9zXpecW0x153vqQYvfnOZ0X5jHXpsm/d/8uswZ13D3WZrApc/y79XI+StjShXfff/L2YU9nOcUq+D+2CBAAASIadzACx+CgYQPRxppeOA8TgzgEQa6zppeMA0XnpOID1cwDr5wDWzwGsnwMAYH5ufg5gfg6Qv7Gm/e0A0dnfDgAAlJeK6tp5PixSOp187gRT+xRMnPxAouet/U4HhFWr1zqwAIQjTrq4YOOI+W8sTu3vfHXREh8eVt464vRrzQ0kSZKkf2qPA04zV1BBO/C4y1K51mtHndak5xUvL/jE+ZJi9OicRWT+3R4AACAASURBVEX5jLWhoSFkeg03BiijsrlB4c1s61CXyaqATW3TxfUoaUsDuvT7zd+Ll7JtHaeEq8jVfG4XJAAAQDLsZAaIxUfBAKKPM710HCAGdw6AWGNNLx0HiM5LxwGsnwNYPwewfg5g/RwAAPNz83MA83OA/I017W8HiM7+dgAAoLy0qK5Z6uMipdNVN04ztU/B7BdfT/S8XXH9VAcVgLB8xaqCfex15yHHbPnYbFrufOgVHx5WXvrLDY+GbO99zQ0kSZKkf2r/Yy8xX1BBO//aGalc6626Dw5Lly1v9POKpctXO19SjG6698VUnynGsf3Ao4wByqw721SFukxWBW6fLv1cj5JCy83Nqmz/q78Vr2VaO04JV1Fd861dkAAAAMmwmxkgFh8FA4g+zvTScYAY3DkAYo01vXQcIDovHQewfg5g/RzA+jmA9XMAAMzPzc8BzM8B8jfWtL8dIDr72wEAgPLxX133+L98WKS0uuehWab2KVi67NvEzlnbHfcLy1esclABCLdMfbhgY4jrbrs/tb/zk8+X++iw8tZOQ08wL5AkSZL+paPH3WC+oIJX1e/3qVzvUx98sknPLSZPn+98STFa+s3qonzWOuyIM40ByqwTOu4Y6jJZFbh7W3d2PUra0pkdtv/V34qFmUrHKOEqcrXr7IQEAABIht3MALH4KBhA9HGml44DxODOARBrrOml4wDReek4gPVzAOvnANbPAayfAwBgfm5+DmB+DpC/sab97QDR2d8OAACUj1ZVgzr5sEhp9dKrb5vapyTX79BEztlF4293MAHYov/IEwsyftim59CwdNny1P7OR+cs8sFh5aWjx91gTiBJkiT9QmOvuNucQQVv2OgLU7nef/+ni5r03GL2/PedLylGry1aUpTPWo8de6UxQJm1Y9e9Q10mqyJoYJd+rklJoVtV/7AoU/mrvxVb52ocp2Rr+N3vfvc/7IYEAABoOruZAWLxUTCA6ONMLx0HiMGdAyDWWNNLxwGi89JxAOvnANbPAayfA1g/BwDA/Nz8HMD8HCB/Y0372wGis78dAAAoHy2qagb4qEhpteTzpab2KRlx1Lgmn6/2fQ4Iy1escjABCHXvfVKw8UNTPzYdx9rv1ofr7prrg8NKvEtvnhna7Li/OYEkSZL0C11x69PmDSp4p182LZXrvfX2+4Z1369v9LOLv3/xrfMlxeihZ94uyuetF42/3RigDJtT2S7UZbIqcPe17ux6lLSlqW26/OpvRWVukGOUcC17j/hPuyEBAACazo5mgHj/e507B0DkcaaXjgPE4M4BEGus6aXjANF56TiA9XMA6+cA1s8BrJ8DAGB+bn4OYH4OkL+xpv3tANHZ3w4AAJSPraoHHeujIqXTNj2Gho2bNpnap+Tk865p+sdsr5/qQAKwxflX3VqwMcQTz76c2t85761PfGxYeWnvg840J5AkSZJ+obZ9RpozqCiaMGXOlusxjet+5ux5jX52UV/fEG6690XnTIrYDXe/sOXfTbG5bdqjxgFl2BXteoS6TFZFUE2X3V2TksKhnXb+1d+J9rkBjlHCbd1lwP9jNyQAAEDT2dEMEIuPggFEH2d66ThADO4cALHGml46DhCdl44DWD8HsH4OYP0cwPo5AADm5+bnAObnAPkba9rfDhCd/e0AAED5aFFdc7mPipROvQccaVqfovGT7mnS+eqw88iwYuVqBxKAsHHTplC9x6iCjB9y/Q4NGzduSuXvbGhoCJOnz/OxYSXeKRdPCS27DTYnkCRJkn7pufGgMeYNKpr6Hzw2lev+5POuadIzjMfnLna+pBh98fXKonvmOnP2POOAMmz/zn1DXSarIuj+Np1dk5JCNjcovJJt84u/E12r9nGMEm7r7kO2shsSAACg6exqBojFR8EAoo8zvXQcIAZ3DoBYY00vHQeIzkvHAayfA1g/B7B+DmD9HAAA83PzcwDzc4D8jTXtbweIzv52AACgfFTkau71UZHSafiRY03rU/TAY3OadL7GT7rHQQRgi6fmzC/Y+OHCv05O7e/8cMkyHxlW4l19+zOh066Hmg9IkiRJv9I+h44zd1DRdNy5t6Ry3Vftfkior29o9DOMdz5a6nxJMZr/9t+L7pnr23UfGgeUYW1zg8LCTGWoy2RVBA3uvLvrUlK4ol2PX/yN6NG1v+OTcP/VdVDGbkgAAICms6sZIBYfBQOIPs700nGAGNw5AGKNNb10HCA6Lx0HsH4OYP0cwPo5gPVzAADMz83PAczPAfI31rS/HSA6+9sBAIDy0SJX84qPipROJ5z9V9P6FL3+1ruNPle5foeGNWvXOYgAbDH61EsLNn5476Mlqf2dDz3zto8MK/GGjb7AXECSJEn6jQ76/9i78yipqwTB985Uz+meN+ctZ97M6zYTtCLYlDWSdMEVcV8wEpB0LdQSxVJLLZeiLJeyLDdcEBUVF0RREBEV911RFFAURRENRUVFCy1EQEAgycz70DfP07YKv19GxpK/+HzO+f7T53TbGQtx7+/ec+8frjJ3UNl01e3PhS23Oagon/05b+Va/Axj7br14YZJL3nPpIg98Oy8snvmunTZCuOACm1Kpx4hl0qrDHqgY3efSUlhrx57/ey/Edv32tfr08r9Wybb1W5IAACA/NnVDBCLS8EAoo8zHToOEINfDoBYY02HjgNE59BxAOvnANbPAayfA1g/BwDA/Nz8HMD8HKBwY0372wGis78dAACoHNWZ7FcuFUlOI2+cZFpfRF993fLL+Mbf87gXEIDvLV+xMqS3ry/J2GHAb88q2t/5zaq14XqXUauVO+/q+0L72oHmApIkSdJGOuVvt5k/qKza9aDTivLZv3T0nXk9y5j67FveLyliN06eERqbmsvquWtzc3Po0KfeWKAC+/PWfUIulVaZdFCP3X0uJYUnO3b9yb8PO/Xax2vTym1e27+33ZAAAAD5s7MZIBaXggFEH2c6dBwgBr8cALHGmg4dB4jOoeMA1s8BrJ8DWD8HsH4OAID5ufk5gPk5QOHGmva3A0RnfzsAAFAZ/vt2+/4fLhRJVnc/+IxpfRE1NTWHLbcZFPt92nXgiWH9+kYvIADfG3/P4yUbO0x64Omi/Z0z5y50wbBatWsnTg+1+x1vHiBJkiRtor+OftAcQmXV0OGji/LZ3+uQU/N6ljE397n3S4rR4iUryu7Z607Z3xkLVGD79Nwr5FJplUkPd+oa2vlcShXfGVvv+JN/H3bruY/XppWrytTtaEckAABA/uxsBojFpWAA0ceZDh0HiMEvB0CssaZDxwGic+g4gPVzAOvnANbPAayfAwBgfm5+DmB+DlC4sab97QDR2d8OAABUhuqaA3u6UCRZzZj9lml9kfXa48jY79Pjz83ywgHwgwOGnFmScUPnnQ4JK1d9W5S/sbGpOYy7/2WXC6tVO/L0UeYAkiRJ0iZq33tAuPbO580hVFaNuPnx0G7DZ7PQn//v/huLv/yqxc8zvlm1xvslxWjO/EVl9+x10NCzjQcqsC02NCfdMeRSaZVJ9d37+WxKFV73XgeE+f/h34Y9eu7ltWnteh+4ux2RAAAA+bOzGSAWl4IBRB9nOnQcIAa/HACxxpoOHQeIzqHjANbPAayfA1g/B7B+DgCA+bn5OYD5OUDhxpr2twNEZ387AABQGTbPHFjnQpFk9clnX5jWF1m/wSfHeo/6D/ljaG5u9sIB8L0PP/68ZOOGMy8YXbS/8/1PlrhYWK3aJTc+GlLbDzYHkCRJkjZ1cXm/o80hVJZts++wonwH7pr6dF7PNCY99rr3S4rYw8+/XXbPX08860rjgQrtts6ZkEulVSY93LFraOdzKVV84zv1+tG/Dfv22NPr0tpl6va3IxIAACB/djcDxOJSMIDo40yHjgPE4JcDINZY06HjANE5dBzA+jmA9XMA6+cA1s8BADA/Nz8HMD8HKNxY0/52gOjsbwcAACpDdSZ7igtFktMWtQPD+vWNpvVFNvi4cyK/R+16Dwivzn3XiwbADy6+ZnzJxg6z33inaH/n1GfecrGwWrVdDvqDOYAkSZIUob6DTzOHUFl26O8vL8p34LgzR+T1TGPm3IXeLyliN0+ZGZqbm8vq+esFI8cZD1RoJ3fdOeRSaZVRh3Tr57MpVXiHdd/tR/8uHNBjT69L63eQHZEAAAD5s7sZIBaXggFEH2c6dBwgBr8cALHGmg4dB4jOoeMA1s8BrJ8DWD8HsH4OAID5ufk5gPk5QOHGmva3A0RnfzsAAFAZqjLZUS4TSU7b7jvUlL4Ejh8e/eLPk84e6QUD4AeNTU2hdp9jSjJu2HXgiUX7O79e8a1LhdWqnXjuzcb/kiRJUsQOOv4i8wiVZeeNuq8o34Gtdj4srF/f2OLnGp99udz7JcXoH1+vLKtnsGPGTzUeqNB27LVvyKXSKqOe6NA1tK/J+nxKFdyWG/4NeCXd6Yd/F+p67O51aeXa9coeYUckAABA/uxwBojFpWAA0ceZDh0HiMEvB0CssaZDxwGic+g4gPVzAOvnANbPAayfAwBgfm5+DmB+DlC4sab97QDR2d8OAABUhuqa7FQXiiSnQcf82ZS+BE47/5pI70/HHQ4Ony3+hxcMgB9MmzGnZOOG62+/v2h/54tzPnShsFqtK299OnTe6TDjf0mSJClivzvnJnMJlW1d+w4pyvdg1mtvt/i5RlNTc7h5yizvlxSxubnPy+oZ7NTHXjAeqNDabWhGhy4hl0qrjDqkez+fT6nCG7HVtj/8m3CQfxNavc0zdUPtiAQAAMifHc4AsbgUDCD6ONOh4wAx+OUAiDXWdOg4QHQOHQewfg5g/RzA+jmA9XMAAMzPzc8BzM8BCjfWtL8dIDr72wEAgMpQXZN9w4Uiyenkc64ypS+B4RdeH+n9uWasZ7QA/NhJf76yJGOGLbcZFL5c8nVR/sb1jU1h7L0unlbrtd+Qs439JUmSpBidM+pecwmVbdljzi/K9+Diq2/P6/nGY9Pf8X5JEXvsxXfK6hnszFfnGQ9UcKO71IZcKq0y6pGO3UI7n02potut5z4//JtwSLd+XpNWbvOaA39vRyQAAED+7HAGiMWlYADRx5kOHQeIwS8HQKyxpgNtAKJz6DiA9XMA6+cA1s8BrJ8DAGB+bn4OYH4OULixpv3tANHZ3w4AAFSGqprsMheKJKfLr59oSl8C5464eZPvzQ79h4W169Z5sQD4wTcrV4eOOxxckjHDUadcWLS/850Pv3CZsFqt4SPuCu16DzD2lyRJkiL23fh51PjnzCdUtp1+8R1F+S7sefCpeT3fmLdgsfdLitjY+14uq+ewH378uTFBBffbbn1DLpVWmTWg+x4+n1KF90jHbt//e3DEhn+nvR6tW1Wm7kw7IgEAAPJnlzNALC4FA4g+znToOEAMfjkAYo01HToOEJ1DxwGsnwNYPwewfg5g/RwAAPNz83MA83OAwo017W8HiM7+dgAAIPm27FX3f7lMJFnddf9TpvQlcMHIcZt8bx5/bpYXCoAfmXDfkyUbMzz6zMyi/Z1TnpzrMmG1SlffMS1073e0cb8kSZIUo279jjKfUFl3zR3Ph19vN7go34e/f/FVi59vrFy91vslxWjp8tVl8xx21eo1xgQVXM9e+4dcKq0y6/5O3X0+pQrv5K47f//vwVHddvV6tHJVNdlz7YoEAADIn13OALG4FAwg+jjToeMAMfjlAIg11nToOEB0Dh0HsH4OYP0cwPo5gPVzAADMz83PAczPAQo31rS/HSA6+9sBAIDkq+qZrXGZSLJ6YdYbpvQlcMm1d2z0ffnN7y/wIgHwEwN+e1ZJxgvdd/tNaGhYX5S/ccmyVS4RVqs1+HeXGPNLkiRJMdut/gzzCZV9uw0+vSjfh4n3PZnXc46Jj7zm/ZIiNm/B4rJ6Fttlp0ONCyq4Jzt2DblUWmXWfj329PmUKrite/UP81IdwtBuu3o9Wr8L7IoEAADIn13OALG4FAwg+jjToeMAMfjlAIg11nToOEB0Dh0HsH4OYP0cwPo5gPVzAADMz83PAczPAQo31rS/HSA6+9sBAIDkq645cJCLRJLVR598bkpfAhddffsvvicd+tSHTz77wosEwI98vGhxaNd7QEnGC+dednPR/s5psxe4RFit0vnXTg3tawca80uSJEkxG3zCpeYUKvuOGX5dUb4Px54xIq/nHC/O+cj7JUXsqRm5snoeu+vAE40LKrgRW20bcqm0yqwJnXr5fEoV3tjOmTCs6y5ei1auqiZ7sV2RAAAA+bPTGSAWl4IBRB9nOnQcIAa/HACxxpoOHQeIzqHjANbPAayfA1g/B7B+DgCA+bn5OYD5OUDhxpr2twNEZ387AACQfFU12dNdJpKc2vUeENauW2dKXwLnXHrTL74v14z1XBaAnxp546SSjRneeveDovyNDQ2N4aYpM10irLwbPXF62O6AE4z5JUmSpBZ0wrk3mVeo7LtozKNF+T502enQ0NCwvsXPOj5dvMz7JUXs9gdml9Xz2Pph5xoXVHD13fuFXCqtMmz3nnv7jEoV3OAN/z6f1HVnr0Xrd7ldkQAAAPmz0xkg3nKcXw6AyONMh44DxOCXAyDWWNPhNgDROXQcwPo5gPVzAOvnANbPAQAwPzc/BzA/ByjcWNP+doDo7G8HAACSryqTvdZFIsmp996/NZ0vkTP+Ovpn35NdBpwQ1q1r8AIB8CPNzc1hxwOPL8l4Yff6k4v2d857/+8uEFardNQZVxvvS5IkSS3svKvvM69Qm6jXnr8tyndi5qvzWvyso7GxKdw4eYb3S4rYytVry+aZ7O/Pucq4oILrlDkwzE91CLlUWmXW2M4Zn1GpgttiQ0O67ea1aOWqMtlRdkUCAADkz25ngFhcCgYQfZzp0HGAGPxyAMQaazp0HCA6h44DWD8HsH4OYP0cwPo5AADm5+bnAObnAIUba9rfDhCd/e0AAEDyVWeyD7lMJDlljxpuOl8iJ/35yp+8H+16DwgzZr/lxQHgJ155452SjRdunvBg0f7OyY+/4fJg5d3FNz4aUtsPNt6XJEmSWlD73gPC1XdMM7dQm2jgcRcW5Xtx0dW35/W84+Fpb3u/pIi9/8mSsnkm+7erxhkbVHj3dewecqm0yqx3N7Rzz318RqUKrmPNgV6H1i5Td51dkQAAAPmz2xkgFpeCAUQfZzp0HCAGvxwAscaaDh0HiM6h4wDWzwGsnwNYPwewfg4AgPm5+TmA+TlA4caa9rcDRGd/OwAAkHxVmexbLhNJTif9+UrT+RIZevolP3k/zvjraC8MAD/rjxdeX5KxwpbbDgpLli4vyt+4eMkKFwerVeo7+DRjfUmSJKmFdd/9aPMKtZnOvHRiUb4Xu9efnNczjzff+9z7JUVs+msfls0z2Rtuv9/YoMI7e+s+IZdKqwy7vnNvn1FJasWqMtmb7IoEAADIn93OALG4FAwg+jjToeMAMfjlAIg11nToOEB0Dh0HsH4OYP0cwPo5gPVzAADMz83PAczPAQo31rS/HSA6+9sBAIDkq87UfeMykeR06eg7TedLZMBvz/rRe1Gz19Fh+YqVXhgAfmLtunVh610PL8lY4ZjTLina3/n0rPdcHKy8O/EvtxjnS5IkSXnU7+AzzC3UZrr2zudDerv6onw3Fv39Hy1+5rHsm2+9X1LE7nnijbJ5Ljvl4eeMDSq8/XrsGXKptMqw+ekOYbte+/mcSlJrlam71a5IAACA/NnxDBCLS8EAoo8zHToOEINfDoBYY02HjgNE59BxAOvnANbPAayfA1g/BwDA/Nz8HMD8HKBwY0372wGis78dAABIts1r+/8PF4kkqzvvfcJ0vkT6HHDcj96Lx5+b5UUB4Gc99NRLJRsrPP7cy0X5G9euWx9unDzDxcHKqytvfTp03vlw43xJkiQpj+pPuNT8Qm2q3erPKMp3Y8J9T+b17OPOh171fkkRumHSS6FhfWNZPJedNmOOsUGFt2VNNryR6hhyqbTKsJFdtvE5laRWqiqTvcPOSAAAgPzZ8QwQi0vBAKKPMx06DhCDXw6AWGNNh44DROfQcQDr5wDWzwGsnwNYPwcAwPzc/BzA/BygcGNN+9sBorO/HQAASLb2NdltXCSSrL67DI7ia25uDqntB//wPvxu+OVeFAB+0VGnXFiScULP3YeEhob1Rfkb33j3M5cGK+/2P/JcY3xJkiQpz0447xbzC7Wphv7puqJ8N4aefklezz6ef/UD75cUsc++XF4Wz2XnvfuhsYHC+E69Qi6VVhk2P9Uh1PTa3+dUklqjTN0kOyMBAADyZ8czQCwuBQOIPs506DhADH45AGKNNR06DhCdQ8cBrJ8DWD8HsH4OYP0cAADzc/NzAPNzgMKNNe1vB4jO/nYAACDZqjPZwS4SSVYLFi4ynS+Br75e8cN70H2334QlS5d7UQD4Wd/9Rmy57aCSjBP+csXYov2ddz06x4XByqvhI+4K7XoPMMaXJEmS8p0LXnO/OYbaVBff+GhRvhtb7XxYWN/Y2OJnHx99ttT7JUXstbc/LYtns1/8Y6mxgcIfuu4Ucqm0yrRLt9rW51SSWqGqTPZeOyMBAADyZ9czQCwuBQOIPs506DhADH45AGKNNR06DhCdQ8cBrJ8DWD8HsH4OYP0cAADzc/NzAPNzgMKNNe1vB4jO/nYAACDZqjJ1Z7pIJDm16z0grFm7znS+BN7OffTD+zD18eleEAB+0diJD5VsrPDd71UxLPpimcuClVfX3vl86LXnMcb4kiRJUp61rx0YrrnjefMMtbl67TW0KN+RV+e+2+LnHw3rG8OYu2d4v6QIPfz8/LJ4Nrt+w/f2u/VUY4TKbrce+4RcKq0y7c10x9A9c4DPqiTlW6buQTsjAQAA8mfXM0AsLgUDiD7OdOg4QAx+OQBijTUdOg4QnUPHAayfA1g/B7B+DmD9HAAA83PzcwDzc4DCjTXtbweIzv52AAAg2aozdde5SCQ5ZfY8ylS+RKY+9sL378GxZ4zwYgCwUfsednpJxgn7HHZa0f7GJ15612XByqsjTrnC+F6SJElqhXrucYw5htpkg4ZdWJTvyFU33Z3XM5AHnp3n/ZIidMu9s0Jzc3k8n+2+22+MESq89jXZ8Fq6U8il0irTzt9qe59VScqzqprso3ZGAgAA5M+uZ4BYXAoGEH2c6dBxgBj8cgDEGms6dBwgOoeOA1g/B7B+DmD9HMD6OQAA5ufm5wDm5wCFG2va3w4Qnf3tAABAsn13gYaLRJJT/yF/NJUvkUuuvSPU7HV0+Hr5N14MAH7Rex9+WrJxwq13PVyUv3H1mnVhzN0vuSxYLe6SGx8Nv95usPG9JEmS1ArtfsiZ5hlqk5156cSifEcGHfPnvJ6DvP7OIu+XFLGvV6wui2e0uw06yRhB4dbOvUIulVaZNifdMXTJ9PdZlaT8esrOSAAAgPzZ+QwQi0vBAKKPMx06DhCDXw6AWGNNh44DROfQcQDr5wDWzwGsnwNYPwcAwPzc/BzA/BygcGNN+9sBorO/HQAASLbqmrr5LhFJTr8bfrmpfIkMOflv4dkXX/NCALBRF18zviRjhF9vd1D46usVRfkbX337U5cEK692qz/D2F6SJElqpQ45aYR5htpk1975fEhvV1/w78iW2wwK36xa3eLnIF8tW+X9kiI2/4MvyuIZ7eDjzjFGUDi1604hl0qrjDuz644+q5KUR1U12Wl2RgIAAOTPzmeAWFwKBhB9nOnQcYAY/HIAxBprOnQcIDqHjgNYPwewfg5g/RzA+jkAAObn5ucA5ucAhRtr2t8OEJ397QAAQLJV19StcpFIcrr46ttN5Uvk6lsmexEA2Kimpuaw7b5DSzJGOPaMEUX5G5ubQxj/4KsuCVaLO+VvtxnXS5IkSa3YSeePNddQm61f/RlF+Z48M/3VvJ6H3P7AbO+XFKFnX36/LJ7TnvCnK4wRFPr23DvkUmmVcbPSnUMqk/V5laSWlsm+aGckAABA/ux+BojFpWAA0ceZDh0HiMEvB0CssaZDxwGic+g4gPVzAOvnANbPAayfAwBgfm5+DmB+DlC4sab97QDR2d8OAAAk17/2HPj/uEQkWd0++TFT+RJoamoOq1av8UIAsFHTX55bsjHCk8+/UpS/8ePPl7ogWC1u1PjnQte+Q4zrJUmSpFbs/Gummm+ozTb0T9cV5XvylyvG5vU85LlX3vd+SRG669E5ZfGc9tzLbjZGUGhfkw2zO3QKuVRaZdzQbrv6vEpSC6uqyb5idyQAAED+7H4GiMWlYADRx5kOHQeIwS8HQKyxpkPHAaJz6DiA9XMA6+cA1s8BrJ8DAGB+bn4OYH4OULixpv3tANHZ3w4AACRXdW12e5eIJKtnX3zNVB4AytCSZavCoOPOL8n4oNceR4b16xuL8nc+8sJ8FwSrxR10/MXG9JIkSVIr1r52YLj2zufNN9Rmu+iGh4vyXek3+OS8nocs+GSJ90uK0PWTXgzrGhpL/qz2mrH3GCfo+8Z2zoRcKq0y7qmOW4f2NVmfV0lqSZm6OXZHAgAA5M8OaIBYXAoGEH2c6dBxgBj8cgDEGms6dBwgOoeOA1g/B7B+DmD9HMD6OQAA5ufm5wDm5wCFG2va3w4Qnf3tAABAclXV1B3iEpFk9d4Hn5jKA0AZ+WbV2jBt9oIwavy0kNp+cEnGBxeMHFeUv3Xl6rXh+kkvuSBYLeqvox8I7WsHGtNLkiRJrVivPY8x31Cbr9tuRxb8u9Ku94DwxT+WtviZyJq168P1k7xXUpQWfbGs5M9sJ973pHGCvu/krjuHXCqtMm9Qj919XiWpBVVlsm/ZHQkAAJA/O6EBYnEpGED0caZDxwFi8MsBEGus6dBxgOgcOg5g/RzA+jmA9XMA6+cAAJifm58DmJ8DFG6saX87QHT2twMAAMlVncme5RKRZLVy1bem8gBQBtasbQgz5y4MY+6eqtefxQAAIABJREFU8f1lscefc2PJxgfvvL+wKH/zy2997GJgtajRE6eHHetONp6XJEmSWrk9Dh1uzqE23wFHnVeU78u9j0zL67nI3Y+97v2SIvTa/EUlf3b7+HOzjBP0fbv03CfkUmmVeXd36uHzKkktKVP3rt2RAAAA+bMjGiAWl4IBRB9nOnQcIAa/HACxxpoOHQeIzqHjANbPAayfA1g/B7B+DgCA+bn5OYD5OUDhxpr2twNEZ387AACQXFWZ7E0uEUlOPfoNMY0HgBJrWN8Y5sxfFG6eMvNHl8XuNOCUkowP9jv89KL83U3NzeG2qa+4GFgt6vhzbjSelyRJkgrQISddZs6hNt/vzx9blO/LKeeOyuvZyItzPvJ+SRF6bPo7JX+G+/Lr840T9H3tNvRKulPIpdIq8/bouZfPrCTFrCpTt8DuSAAAgPzZGQ0Qi0vBAKKPMx06DhCDXw6AWGNNh44DROfQcQDr5wDWzwGsnwNYPwcAwPzc/BzA/BygcGNN+9sBorO/HQAASK7qmrqnXCKSnPY74gzTeAAokcam5vD2gsXh1vtf/slFsZfe9Fho33tAScYH4+5+pCh//wefLnEpsFrUleOeDp13Osx4XpIkSSpAp/ztNvMOtfmuGPdUaFeE5yqZPY8Ozc3NLX42svCzpd4vKULjpr5S8me57334qXGCfmhs50zIpdIq827oUuPzKklxy2Q/tjsSAAAgf3ZIA8TiUjCA6ONMh44DxOCXAyDWWNOh4wDROXQcwPo5gPVzAOvnANbPAQAwPzc/BzA/ByjcWNP+doDo7G8HAACSqyqT/cAlIsnpuDNHmMYDQJF9d9fygk+WhDseevUXL4o94tQrSzI2+PV2B4Wly1YU5XV48Ll5LgVWi+p/9F+M5SVJkqQCddGYR807lIhq9zu+KN+Z9z74pMXPRhoaGsMNk17yfkkRWrl6bUmf6S5Zutw4QT90UtedQy6VVpk3P90hbNNzP59ZSYpRVabuc7sjAQAA8menNEAsLgUDiD7OdOg4QAx+OQBijTUdOg4QnUPHAayfA1g/B7B+DmD9HAAA83PzcwDzc4DCjTXtbweIzv52AAAgoerrf1VVk13nEpHk9LerxpnGA0ARfbp4WZj02OubvCQ2s/fQkowNjh9+eVFeh+Ur14TrJ7kMWPE796opoV3vAcbykiRJUgFK9zk4jJ443dxDiWjw7y4pyvdm7MSH8npGMuXJud4vKUIffLqkpM91G5uaQvtaz6T0/7VTr31CLpVWG+jirbfzmZWkWGX/YYMkAABA/uyWBojFpWAA0ceZDh0HiMEvB0CssaZDxwGic+g4gPVzAOvnANbPAayfAwBgfm5+DmB+DlC4sab97QDR2d8OAAAk0+a1/bdweUiyGjfpEdN4ACiCv/9jRbjv6TcjXRB7zqh7SzY2eGb6q0V5PWa8/pHLgBW7aydOD7X7DjOOlyRJkgrUDtmTzD2UmP44YmJRvjdHnnJhXs9IZr35sfdLitDMNxaW/Blv175HGC/o+9ptaFa6c8il0irz5qY7hq179fe5laSIVdXUfW2HJAAAQP7smgaIxaVgANHHmQ4dB4jBLwdArLGmQ8cBonPoOID1cwDr5wDWzwGsnwMAYH5ufg5gfg5QuLGm/e0A0dnfDgAAJFO7zIC+LhBJVk8+/4ppPAAU0JdfrQwPPjcv1gWxdcdeUJJxQWbPo8L6xsaCvyaNTU1h7H0vuwxYsTv6jGuM4SVJkqQCNuDYv5l7KDFde+fz4dfbDS7496bTjoeEhob1LX5OsuiLZd4vKUJTn3mr5M96d647wXhBP3RT55qQS6XVBjqz644+s5IUsapMdrkdkgAAAPmzexogFpeCAUQfZzp0HCAGvxwAscaaDh0HiM6h4wDWzwGsnwNYPwewfg4AgPm5+TmA+TlA4caa9rcDRGd/OwAAkExVveqOdoFIsnrn/YWm8QBQAMtWfBueeOnd+Bc+T3ghdN758JKMCy6++vaivDa5hV+6CFixu+yWJ0K6z8HG8JIkSVIBG3b2jeYfSlS7DDq1KN+dl1+f3+LnJI2NTWHM5BneL2kT3XTPzNDU3FzSZ77Zo4YbL+iHTuy2c8il0moDzUp3DqlM1udWkqKUqVthhyQAAED+7KIGiMWlYADRx5kOHQeIwS8HQKyxpkPHAaJz6DiA9XMA6+cA1s8BrJ8DAGB+bn4OYH4OULixpv3tANHZ3w4AACRTdU3dBS4QSVbfrFxtGg8ArWjVt+vCtNkLwg2TXmrR5bCnXnh7ycYF7334aVFeo/ueftNFwIrdXof9yfhdkiRJKnDnjrrX/EOJasgfrirKd+eKGybm9axk6jNveb+kCH21bFVJn/0edcqFxgv6oZ167htyqbTaSMd229XnVpKilKn7xg5JAACA/NlNDRCLS8EAoo8zHToOEINfDoBYY02HjgNE59BxAOvnANbPAayfA1g/BwDA/Nz8HMD8HKBwY0372wGis78dAABIpqpM9g4XiCSnrn2PMIUHgFayZu36MOP1j8KNk2fkdTHsHocOL8m44IAhZxbldVq6fLULgBW7My+dYPwuSZIkFbj2tQPDNXc8bw6iRPWXq+8vyvdn0DF/zut5yavzPvV+SRGa/8EXJX0GfNr51xgz6IfabWhWh84hl0qrDfRUx61D+5qsz64kbbLsSjskAQAA8mdXNUAsLgUDiD7OdOg4QAx+OQBijTUdOg4QnUPHAayfA1g/B7B+DmD9HAAA83PzcwDzc4DCjTXtbweIzv52AAAgmaoz2RddHpKc9jnsNFN4AMhTw/rG8Orbn4abp8zK+1LYkbc9G7bc9qCSjAvG3/N4UV6vF179wAXAitW1dz4feu5xjPG7JEmSVOBq9jnWHESJa/TE6aHzzocX/Pvz6+0OCt+uWdvi5yV//8cK75cUoednLyjps+ALR91mzKAfNaZLTcil0mojDeqxu8+tJG26VXZIAgAA5M/uaoBYXAoGEH2c6dBxgBj8cgDEGms6dBwgOoeOA1g/B7B+DmD9HMD6OQAA5ufm5wDm5wCFG2va3w4Qnf3tAABAMlXV1H3m8pDkdOwZI0zhAaCFmpqaw9sLFodxU19ptUthh/7pupKMCdLb14flK1YW/DVb39gUbrl3lguAFatDf3+5sbskSZJUhPYdco45iBLZ3of/qSjfoRmz32r5c6bm5nDTlJneL2kTTXlybkmfCV837l5jBv2oE7rtHHKptNpIkzr18LmVpE2VqVtthyQAAED+7LIGiMWlYADRx5kOHQeIwS8HQKyxpkPHAaJz6DiA9XMA6+cA1s8BrJ8DAGB+bn4OYH4OULixpv3tANHZ3w4AACRPx477/nN1TbbJBSLJ6YKR40zhAaAFFnyyJEx4+LVWvxS2T/8TS3Px55+uKMrrNv+DxS7/VawuuuHhsOW2Bxm7S5IkSUXoyNNHmYcokQ07e0xRvkNXjrkrr+cmD0972/slbaIxk2eEpqbmkj0Xvuv+p4wZ9KN26rVPyKXSakPt0nMfn11J2khVmbo1dkkCAADkz05rgFhcCgYQfZzp0HGAGPxyAMQaazp0HCA6h44DWD8HsH4OYP0cwPo5AADm5+bnAObnAIUba9rfDhCd/e0AAEDyVPXIdnF5SLIaN+kRU3gAiOHTxcvC5CfeKMiFsBfd8HBo13tAScYE02bMKcrrV6jXTsltl4P+YNwuSZIkFak/jphoHqJEdslNjxXlOzRo6Nl5PTd5/Z1F3i8pQkuWrSrZ8+FHn5lpzKAf1W5Dszt0CrlUWm2kkV228dmVpI1UVVO31i5JAACA/NlxDRCLS8EAoo8zHToOEINfDoBYY02HjgNE59BxAOvnANbPAayfA1g/BwDA/Nz8HMD8HKBwY0372wGis78dAABInnY1B+7r8pBk9fT0V03hASCCL79aGR54dl5BL4M99PeXlWQ8ULvPMaGxqakor6FLfxWn359/qzG7JEmSVMQuv/UpcxEltm79jir4dyi1/eCwZu26Fj87+cdSz06kKL3z4Rcle0780uw3jRn0k27rnAm5VFptpDfTHcPWvfr77ErSL1RVk11nlyQAAED+7LwGiMWlYADRx5kOHQeIwS8HQKyxpkPHAaJz6DiA9XMA6+cA1s8BrJ8DAGB+bn4OYH4OULixpv3tANHZ3w4AACRPVWbACS4PSVa5BZ+YwgPARixb8W144qV3C34R7OiJ04tyufPPdenoO4vyWj73yvsu/VXkRt7+bNhq1yOM2SVJkqQitXXfIeYiSnT7H3luUb5LM1+d1+JnJ83NIYy972Xvl7SJnn/1g5I9L5737ofGDfpJp3fdKeRSabWhzth6R59dSfqFqjLZBrskAQAA8mcHNkAsLgUDiD7OdOg4QAx+OQBijTUdOg4QnUPHAayfA1g/B7B+DmD9HAAA83PzcwDzc4DCjTXtbweIzv52AAAgeapr6i53eUiyWrV6jSk8APyMVd+uC9NmLwg3THqpKBfB/umKu0s2HliwcFHBX891DevDTffMdOmvIjfwuAuN1yVJkqQitlv9GeYiSnQnnHtTUb5LI2+clNczlMdefMf7JW2iKU/NLdlz408++8K4QT9pzx57hVwqrTbU9A5dwhY+u5L082Xq1tslCQAAkD87sQFicSkYQPRxpkPHAWLwywEQa6zp0HGA6Bw6DmD9HMD6OYD1cwDr5wAAmJ+bnwOYnwMUbqxpfztAdPa3AwAAyVNVUzfF5SHJqefuQ0zfAeA/WLtufZg5d2G4cfKMol4Ee8BR55VkPJA9anhRXtc33/vchb+K3PnXTA3tawcas0uSJElF7JATR5iPKNGNuPnxonyX6oedm9czlLfe+7v3S9pEYybPCE1NzSV5frzim1XGDfpJW9Rkw5vpjiGXSqsNdWj33Xx+JennymQb7ZIEAADInx3ZALG4FAwg+jjToeMAMfjlAIg11nToOEB0Dh0HsH4OYP0cwPo5gPVzAADMz83PAczPAQo31rS/HSA6+9sBAIDkqc5kX3N5SHLa/zdnmr4DwP+yvrEpzJm/KNxy76yiXwJ79Z3TQrrPwSUZD0y478mivL53PTrHhb+K1OiJ08P2/U8wXpckSZKK3Ml/HWdOosTXvd/RBf8upbevD2vXrWvxM5Sly1d7r6QIfbVsVUmeIzc1NYctagcaO+gn3d2pR8il0mpD3dOpp8+uJP1s2Sa7JAEAAPJnZzZALC4FA4g+znToOEAMfjkAYo01HToOEJ1DxwGsnwNYPwewfg5g/RwAAPNz83MA83OAwo017W8HiM7+dgAAIHmqM9mvXBySnI4ffrnpOwAVr6m5Oby9YHG4beorJbsA9vfnjy3JWKBDn/rwzcrVBX+NP/9yuYt+FblhZ48xVpcSWFVNdml1TXas10KSpPLtwhseMidR4jvg6POK8n2a9drbeT1LKeVzKqmt9O6HX5TsmXLXvkcYO+gnnb11n5BLpdXG6tdzb59fSfppzXZJAgAA5M8ObYBYXAoGEH2c6dBxgBj8cgDEGms6dBwgOoeOA1g/B7B+DmD9HMD6OQAA5ufm5wDm5wCFG2va3w4Qnf3tAABAsqRr6/9Pl4Ykq4uvGW/6DkBFW/DJkjDh4ddKfgHsboNPL8lY4KSzRxbldX5qRs5Fv4rUyNufCV12PtxYXUpc2abqzID9vnu2sHlmwGEb/mervCaSJJVX6e0PDqMnTjcvUeI74dybivKduuqmu/N7ljLTsxRpU01/7cOSPVfeof8w4wf9pGyPPUIulVYba1SXWp9fSfqZ7JQEAADIn13aALG4FAwg+jjToeMAMfjlAIg11nToOEB0Dh0HsH4OYP0cwPo5gPVzAADMz83PAczPAQo31rS/HSA6+9sBAIBkqepVl3FpSLK6Y8rjpu8AVKRPFy8L9zzxRllc/nr52KdC+9qBJRkLvDDrjYK/1mvWNoQxk2e46FeRqjv2AuN0KYFVZbLn//vnC5vX9t9qw/98vtdGkqTyqU//E81JVBGNuOWJonynDh52Xl7PU95esNj7JW2ie596s2TPl/c97HTjB/2kDpkDw/xUh5BLpdWGmrfhPeueOcBnWJL+Q5ttttl/slsSAAAgP3ZrA8TiUjCA6ONMh44DxOCXAyDWWNOh4wDROXQcwPo5gPVzAOvnANbPAQAwPzc/BzA/ByjcWNP+doDo7G8HAACSpV3v7ECXhiSraTPmmL4DUFG+XLoyPPjcvLK6/PXoM64uyTigdp9jQmNTU8Ff89ffWeSSX0Xqr6MfCO1rBxqnS8nr6c3q63/1H58x/N9dsv97dSY72esjSVJ5VHfMBeYlqpi67350wb9THfrUh3XrGlr8PGXp8tXeK2kT3XTPzNDc3FyS58yHHH+e8YN+tgc7dgu5VFptrD923cHnV5L+Q5ttdv5/tlsSAAAgP3ZtA8TiUjCA6ONMh44DxOCXAyDWWNOh4wDROXQcwPo5gPVzAOvnANbPAQAwPzc/BzA/ByjcWNP+doDo7G8HAACSpaome7pLQ5LVBws/M30HoCJ8s2pNmDZ7Qbh+Uvld/rrNvsNKMg647LoJRXntJzz8mkt+Fakd6042RpeSVqbuk81r+/+PjT1rqO49YFhVJtvg9ZIkqbQdd9YN5iWqmA446ryifK9eeeOdvJ6pjL1vlvdL2kRfr/i2JM+bh/3xMuMH/WwXbrVdyKXSamPN6NAlbFGT9RmWpH/XZvX1v7JbEgAAID92bwPE4lIwgOjjTIeOA8TglwMg1ljToeMA0Tl0HMD6OYD1cwDr5wDWzwEAMD83PwcwPwco3FjT/naA6OxvBwAAkqU6UzfapSHJqV3vAWHN2nWm7wAk2rdrG8LMuQvDmLtfKstLX/86+oGSjQU+WPhZwV//Txcvc7mvInXSX24xRpcSVlVN3dr2Ndltojxv2Lx33S5VmezfvW6SJJWuc6+aYm6iiunEc28uyvfq6lsm5/Vc5ZEX5nu/pE30/idLSvLc+cy/XWf8oJ/tkO79Qi6VVhvsiG59fYYl6d+1Wd++/2S3JAAAQH7s4gaIxaVgANHHmQ4dB4jBLwdArLGmQ8cBonPoOID1cwDr5wDWzwGsnwMAYH5ufg5gfg5QuLGm/e0A0dnfDgAAJEtVTd0jLg1JTjV7HW3qDkBiNTQ0hjnzF4Wbpsws60tfDzr+4pKMAwb+9qyivA+PTX/H5b7aZKPGPxe69h1ijC4lrV7Z4+I8c/i3TP3/rM5kn/HaSZJU/NrXDgxX3znN/EQV04hbnijKd+vQ3/0lr+cqc95Z5P2SNtGsuQtL8vz5oqtvN4bQz9Y10z+8m0qHnNpcUzr18BmWpH9Xbe2w/2K3JAAAQH7s5gaIxaVgANHHmQ4dB4jBLwdArLGmQ8cBonPoOID1cwDr5wDWzwGsnwMAYH5ufg5gfg5QuLGm/e0A0dnfDgAAJEtVTd3bLg1JTtmjhpu6A5A4jU3N4e0Fi8Ot979c9he+jp44PWy16xElGQfcNfXpgr8Xq79dF264+yWX+2qT1Z9wifG5lLiyt7XowUPfvv+04X/3yg3/N5q9hpIkFa9eex5jbqKKq+cevy34d6vjDgeHhob1LX62snjJCu+VtIkefv7tkjyHvmbsPcYQ+sWe7Ng15FJptcH69dzbZ1iS/v/5TMd9/9luSQAAgPzY1Q0Qi0vBAKKPMx06DhCDXw6AWGNNh44DROfQcQDr5wDWzwGsnwNYPwcAwPzc/BzA/BygcGNN+9sBorO/HQAASJT/VJ2pW+3SkOR00tkjTd0BSIym5uYw/4PF4fYHZreZC1/PvHRCaS5A2+Hg8M2q1QV/T2bP+8TFvtpkF97wUNhi20HG51Kiyr7Rrk/9f83nAcSG/zsHVWfqVngtJUkqTrsMOtX8RBVX/6P/UpTv15y3ci1+ttLY1BTGTJ7h/ZI20m1TXynJ8+hxkx4xhtAvNnKrbUIulVYb7JoutT7DkvS/2rJv33+xXRIAACA/dncDxOJSMIDo40yHjgPE4JcDINZY06HjANE5dBzA+jmA9XMA6+cA1s8BADA/Nz8HMD8HKNxY0/52gOjsbwcAAJJjy233/zcXhiSry66bYOoOQCJ8unhZmPTY623uwtd9f3N2ScYAp5w7quDvSXNzcxj/4GwX+2qT9R18mrG5lKCqarLL2tcO6NAazyGqMwd0qspk3/K6SpJU+Nr1HhDOG3WfOYoqqhP/cktRvl833vFAXs9Y7n/mLe+XtIm+XdNQ9GfSkx981hhCv9hR3XYNuVRabbC30h1C10x/n2NJ2tCWffv+ix2TAAAA+bHDGyAWl4IBRB9nOnQcIAa/HACxxpoOHQeIzqHjANbPAayfA1g/B7B+DgCA+bn5OYD5OUDhxpr2twNEZ387AACQHNW9D+zjwpBkNfG+J03dAWjTFi9ZEe5/+s02edHrqPHPhdT2g0syBnjxlTcL/t58tOgrF/pqk/3hwvHG5VKyaq6qqTuwNZ9F/GvPvf5bVU12otdWkqTCt/PAU81TVFFddssTRfluDT390ryescx682Pvl7SJFn2xrOjPph97dqbxg36x3r32C7lUWm2007ru6HMsSRvavLb//2bHJAAAQH7s9AaIxaVgANHHmQ4dB4jBLwdArLGmQ8cBonPoOID1cwDr5wDWzwGsnwMAYH5ufg5gfg5QuLGm/e0A0dnfDgAAJEe7TN3hLgxJVtNfnmvqDkCbtHT56vDES++26Ytejz/nxpL8/m+//7Ghqam54O/Rw9PedqGvNtq1dz4feuxxtHG5lKQydRcV6plEde8Bw6pqsuu8zpIkFbbTL77TfEUVVfd+hZ+X9trjyLyesXz8+dfeK2kTvfHuZ0V/Rv3CrDeMHbTxtfgOXUIulVYb7LkOW4V2PsOSFNr1qf+vdkwCAADkx45vgFhcCgYQfZzp0HGAGPxyAMQaazp0HCA6h44DWD8HsH4OYP0cwPo5AADm5+bnAObnAIUba9rfDhCd/e0AAEByVNVkz3FhSLL6eNFiU3cA2pRvVq0N02YvCNdPavsXve404JSS/P5fOeauorxP1096yYW+2miHn3KFMbmUoKoydc9uVl//q0I+l2hfk92muia70OstSVLhqtn72DB64nRzFlVM+w05u+zXY9Y1rPecRdpET896r+jPql+f956xgzbaDZ17h1wqrTZatscePseSKr6OHff9ZzsmAQAA8mPnN0AsLgUDiD7OdOg4QAx+OQBijTUdOg4QnUPHAayfA1g/B7B+DmD9HAAA83PzcwDzc4DCjTXtbweIzv52AAAgOapqsre4MCQ5ta8dEBoa1pu6A9AmrFnbEGbOXRjG3D0jEZe8XnrTY6F97wFF//1vt+G/mc8lzlF99165zFcb65IN34FfbzfYuFxKSpnsp/+Wqf+fxXg28d1/Z8N/82mvuyRJhev4s8eYt6hiOu6sG4ryvZry8HN5PWu5+7HXvV/SRvruO1Js73+0yLhBG+2krjuHXCqtNtpNnWt8jiVVfLW1w/6LHZMAAAD5sQMcIBaXggFEH2c6dBwgBr8cALHGmg4dB4jOoeMA1s8BrJ8DWD8HsH4OAID5ufk5gPk5QOHGmva3A0RnfzsAAJAcVZm6Z10Ykpy23XeoaTsAZa9hfWOYM39RuHnKzERd8vqbP4wsye//QceeXfD3rLGpOYy7/2WX+Wqj7XnocGNyKSFVZbINm/c6cKeiPqCor//Vhv/uCK+/JEmFaatdfxNGjX/O3EUV0QXXPVCU79XwC6/P63nLC69+4P2SNtKYu1/6/rlkMf39i6+MG7TRduuxT8il0mqjzd9Qz177+yxLqug22+z8/2zHJAAAQH7sBAeIxaVgANHHmQ4dB4jBLwdArLGmQ8cBonPoOID1cwDr5wDWzwGsnwMAYH5ufg5gfg5QuLGm/e0A0dnfDgAAJEd1Td1HLgxJToOGnm3aDkDZ+u4C1LcXLA633v9yIi95zew1tCS//5MffLbg7937H//DRb7aaH+6fFJo13uAMbmUkKoydSeW6jlFu0zd4VWZ7LfeB0mSWr8jTrnC/EUV0eiJ00OnnQ4t+Heq3+CTPW+RCtxXy1YV9Rn2N6tWGzNoo22xoTdSHUMulVYbbfjWO/gsS6ro7JYEAADInx3hALG4FAwg+jjToeMAMfjlAIg11nToOEB0Dh0HsH4OYP0cwPo5gPVzAADMz83PAczPAQo31rS/HSA6+9sBAICE6Nv3n6oy2QYXhiSnU8+72rQdgLLT3Nwc3vnwizD+gdmJvdz13FH3luS3v9OOh4RVq9cU/D2c+sxbLvHVL3bthBdCZu+hxuNSQqqqqZtQ6scVVTUDdqjK1C32fkiS1Lql+9SHy8c+ZR6jiqhf/RkF/061rx0Qlq9Y2eLnLStXr/VeSZsot/DLoj7Lbmpq/v67bdygjTW5U4+QS6XVRpveoUvYIpP1WZZUoWWbbJgEAADIn53hALG4FAwg+jjToeMAMfjlAIg11nToOEB0Dh0HsH4OYP0cwPo5gPVzAADMz83PAczPAQo31rS/HSA6+9sBAIBk+Ndedb92WUiyGnnjJNN2AMrKp4uXhUmPvZ74y13rjv1bSX77Tz3v6oK/h1+v+NYFvtpoR59xtbG4lJCqMtm3/rXnXv+tHJ5ZtOt1QHVVTd1s74skSa1bduhfzWNUEf3mD1cV5Tv17Iuv5fXcZfyDs71f0kaaOXdh0Z9pd9npUGMGbbTzt9o+5FJpteEG9djdZ1lSpa4BNNgxCQAAkD+7wwFicSkYQPRxpkPHAWLwywEQa6zp0HGA6Bw6DmD9HMD6OYD1cwDr5wAAmJ+bnwOYnwMUbqxpfztAdPa3AwAAyVDd+8DdXRiSrCY/+KxpOwBlYfGSb8L9z7xVERe7XjvhhdB558NL8tv/4itvFvy9fHHOhy7w1S922dgnQ7rPwcbiUhLK1H2zeW3/rcrpucWWffv+S1VN3XjO4axsAAAgAElEQVTvjyRJrVf72oHhwusfMp9R4vvzlZOL8p267LoJeT13eWpmzvslbaRHp79T9GfbtfscY8ygjTa4e7+QS6XVhhvXOeOzLKkiq6qpW2vHJAAAQP7sEgeIxaVgANHHmQ4dB4jBLwdArLGmQ8cBonPoOID1cwDr5wDWzwGsnwMAYH5ufg5gfg5QuLGm/e0A0dnfDgAAJMPmmbqhLgxJVjNfnWfaDkBJLV2+Ojzx0rsVdbHrqRfeXpLf/e8ud21sairo+7m+sSmMvXeWC3z1i+035BzjcCkZNW/ooHJ9flGdyZ5aXZNt8j5JktQ67X7ImeYzSnzXTngh/Hq7wQX/Pg0+7py8nr3MW7DY+yVtpAkPv1b0Z9x9B55kvKCN1jXTP7ybSoec2mzz0x1C7177+TxLqriqMtlv7ZgEAADIn93iALG4FAwg+jjToeMAMfjlAIg11nToOEB0Dh0HsH4OYP0cwPo5gPVzAADMz83PAczPAQo31rS/HSA6+9sBAIBkqM7UXejCkGT16edfmrYDUBLfrF4bps1eEK6f9FLFXey656HDS/K7P+K6Owv+vr774Rcu79UvdvbIe0K73gOMw6VkdHm5P8Ooqqk7sDpTt8J7JUlS/n03jj/risnmNUp8fQ48qeDfp447HBzWr29s8bOXpctXe6+kjfTd8+bGpqaiPus+YMiZxgvaZM922CrkUmm14c7euo/PsqRKbJUdkwAAAPmzaxwgFpeCAUQfZzp0HCAGvxwAscaaDh0HiM6h4wDWzwGsnwNYPwewfg4AgPm5+TmA+TlA4caa9rcDRGd/OwAAkAxVNdmJLgtJTltuMyisb2w0bQegqNasbQgz5y4MY+6eUZGXuo687dmw5bYHleS3f8HCRQV/f6c8OdflvfrZRk+cHrbd/3fG4VICqqrJTtusb99/ahPPMXoO6FydqXvX+yZJUv59N57/blxvfqMkV3/CJUX5Ps19+/28nr+MvXeW90vaSEuXry7qM+/Bx51jrKBNdm2X3iGXSqsNN7NDl7BFTdbnWVJllalbYcckAABA/uweB4jFpWAA0ceZDh0HiMEvB0CssaZDxwGic+g4gPVzAOvnANbPAayfAwBgfm5+DmB+DlC4sab97QDR2d8OAAAkQ3UmO9OFIclph/7DTNkBKJqG9Y1hzvxF4eYpMyv6Qtdjz7q+JL/7/Yf8seDv8ZJlq1zaq1/suLNuMAaXElBVpm7xFrUDN29LzzLada3/7xv+f3/a+ydJUv6d/Ndx5jdKdKddNL4o36VbJj6U1zOYR16Y7/2SNtKCT5YU9dn3kadcaJygTfa7rruEXCqtNt4h3fr5PEuqrDWBmrqv7ZgEAADIn13kALG4FAwg+jjToeMAMfjlAIg11nToOEB0Dh0HsH4OYP0cwPo5gPVzAADMz83PAczPAQo31rS/HSA6+9sBAIBk+O7ybBeGJKeDh51nyg5AwTU2NYe3FywO4+5/2YWuG+pz4Ekl+d0ff8/jBX+vp81e4D3Wz3bluKdDp50ONQaX2vrlmZlsw+a963Zpkw806ut/teH//xHeR0mS8qvbbkeGa+983jxHiW3kbc+Edr0HFPy7NOyPl+X1DGbO/EXeL2kjzZ73SVGfgR8//HLjBG2yXXvuHXKptNp4Ezr38nmWVFllsl/ZMQkAAJA/u8kBYnEpGED0caZDxwFi8MsBEGus6dBxgOgcOg5g/RzA+jmA9XMA6+cAAJifm58DmJ8DFG6saX87QHT2twMAAP8ve3ceJUV5KPxfb+7+u+ee++YuCT0DZhpcAHG6Z3BfcEncAt0jOO56YyQYd+MS14gRNbigBkVcESOIiGLcUVSUACqKioqM4oYbKioKIutM/TD3vnmNQVNFT/V0VX8+53z/uss5TlWfepainuSr3ar5n2ryxTYHhqSnE8++3JQdgNi0tQXB3Nc/CG68c6aDXP+3c0feW5aDmb9e3ZZ7B4s+XRLr9V65cnVw9YQZrrPWWuGws42/pXQcnnlc0tc2OuWKh2XyhRWupyRJ696hJw03z1Gqy/3osNh/Rw27HlrSOsx7H37mWknf0gPTW8q6Fv6Lwb81RtBfrXO+EMzKdgta6rJKcHPXtHn9Hu5pSVVU4UNvTQIAAJTOW+UAkTgUDCD8ONNHxwEi8OQAiDTW9NFxgPB8dBzA/jmA/XMA++cA9s8BADA/Nz8HMD8HiG+s6f12gPC83w4AACTf9/NN3R0Ukq4uvWa8KTsAsXhrwaLglvufcYDr1zrg2Is65Jk/6OQLYr/mL7zynmustXb28DuCzo17GX9LSS9XuCUt6xuZXHGbNS1wXSVJWrc23Ha/YNjoh813lNr6HXpWWX5L8995f53XYVatbg2uvGWa6yV9Q7fc90xZ18PP+M3VxggK1c0bbha01GWV8AZvsqX7WVLV9OVaurcmAQAASufNcoBIHAoGEH6c6aPjABF4cgBEGmv66DhAeD46DmD/HMD+OYD9cwD75wAAmJ+bnwOYnwPEN9b0fjtAeN5vBwAAkq8mV9zTYSHp6rZ7ppiyA9CuFixcHEx86HkHt35D9T/8aYc88x949MnYr/34+591jfUXXT52arB14Shjbyn5zfnPHs3/kqY1jk6Nfbus+e96xrWVJGndOvDYi8x5lNqOOPPqsvyO7rh/qrUYKaZGjp8etLW1lW1d/LzLRhsfKFRndt8yaKnLKuE9nt0o6JIvuKclVUWZXPFdb00CAACUzhvmAJE4FAwg/DjTR8cBIvDkAIg01vTRcYDwfHQcwP45gP1zAPvnAPbPAQAwPzc/BzA/B4hvrOn9doDwvN8OAAAkX6ahcJTDQtLVk8++ZMoOQLv4+NOlwaRpcx3Y+i2deeltHfK8r9/lkGDVqtWxXv8FCxe7xlprR551rXG3lPRyxcXfzzd1T+M6R6fGvv9ckyuMd50lSYpe1633DYbd8JB5j1LZuSPvKcvvaPBF15W0HvPozHmul/QtfbZkWdnWx4ddNc74QKHq32vnoKUuqxS0z6Y7u6clVUWZfOFtb00CAACUzpvmAJE4FAwg/DjTR8cBIvDkAIg01vTRcYDwfHQcwP45gP1zAPvnAPbPAQAwPzc/BzA/B4hvrOn9doDwvN8OAAAkX02uOMxhIelqwQcfmbIDUJIlS5cHU2bOC0aMm+ag1r/SXj87p0Oe96Ue0BzG5Mdfdo31F1164yNB9z4HG3dLST8ws6Fpn5Qvd6y/5r/z7DW1ud6SJEVr3yOHmvsotW203QGx/4aKPzmlpPWYl15737WSvqU33/24bOvkV46eaGygUG2c6xu8VNc1aKnLKuFdv1G9e1pSdZQrvOmtSQAAgNJ54xwgEoeCAYQfZ/roOEAEnhwAkcaaPjoOEJ6PjgPYPwewfw5g/xzA/jkAAObn5ucA5ucA8Y01vd8OEJ732wEAgOTL5IoTHRaSnn6wxYCgtbXNlB2AdbJs+apgxnNvBCPHT3dAa4guHzs12GSHgzrkmf/C3NdivReWr1gVXOU+0Fra++fnG3dLiT8sszisatY88sV9M7niMtddkqTw1W25d3DBdQ+Y/yiV9Rnwi9h/Q9ktm4NVq1av85rMx58uda2kb+mZue+Ubb189Pj7jA0Uuge7dQ9a6rJKeHPW1Kt+T/e0pGrodW9NAgAAlM6b5wCROBQMIPw400fHASLw5ACINNb00XGA8Hx0HMD+OYD9cwD75wD2zwEAMD83PwcwPweIb6zp/XaA8LzfDgAAJF9NvviMg0LS03bFI0zXAYhs5arVwcwX5gdXT5jhYNYInXDeTR3yvN+l+djY74nnWt5xjfUXDbnyrqDL5v2Nu6Uklyv8obFx0N9V07pHbb6ww5r/7o9cf0mSwtf/8HPNgZTKDjj2orL8hp6f++o6r8m0tQXW6KRv6eEnXinfG8J3PWxcoNBdtnFj0FKXVQr6RY9t3NOSUl8mV3jVW5MAAACl8wY6QCQOBQMIP8700XGACDw5ACKNNX10HCDCPynw5ACwfw5g/xzA/jmA/XMAAMzPzc8BzM8BYhtrer8dIDzvtwMAAMmXyRcWOSwkPR1w5GDTdQBCa21tC16ctyAYNfFJB7KuQ7sddFqHPO9H3nhH7PfGzffOco31F+3YfKIxt5Ts3q+t/3FNNa59dG5s6lqTK851D0iSFK4Neg8IfnP1feZBSl0n/WZMWX5Dv5twf0nrMnc8/LzrJX1Dtz34XNnWz+9+cJpxgUI3qOf2QUtdViloctfu7mlJVVDhZW9NAgAAlM6b6ACROBQMIPw400fHASLw5ACINNb00XGA8Hx0HMD+OYD9cwD75wD2zwEAMD83PwcwPweIb6zp/XaA8LzfDgAAJFuXXj/+Pw4JSVe/HDLCdB2Av6qtLQjmzV8Y3HTXUw5iXccuvfGRoG7Lvcv+rO/SuFfwwcJPYr0/3n5/kWusv+jkoWONt6Uklyuuqs019anmNZDaHs3fzeQLU9wPkiSFq/DTs82FlLqGjX4oqG1oiv33c+LZl5e0NjPjuTdcL+kbuva2x8u2jv7wH542JlDotqnfPWipyyol/bDXj9zXktK+ZzDXm5MAAACl80Y6QCQOBQMIP8700XGACDw5ACKNNX10HCA8Hx0HsH8OYP8cwP45gP1zAADMz83PAczPAeIba3q/HSA877cDAADJ1qmxb4ODQtLV5ddPMF0H4Fu9+e4nwbj7nnEAa4kdeeY1HfKsP+joX8d+j0yaNtc11p81fOzUIL/rQONtKcFlcsWTrIKst16PHs1/n8kXb3RPSJL01+vcu39w7sh7zYmUuup/+NPYfz87Nx9T0trMa2995FpJ39LSL1aUZS19xlMvGBMo/NgpXwhmZTcMWuqySkHDNuntvpaU9ubYMQAAACidt9IBInEoGED4caaPjgNE4MkBEGms6aPjAOH56DiA/XMA++cA9s8B7J8DAGB+bn4OYH4OEN9Y0/vtAOF5vx0AAEi2mnxxgENC0tXvJ001XQdgrd7/aHFwx8PPO3S1ndp+wPGpfNYvXbYiGHnLNNdYf9Zhv7zcWFtKdr9fb7311rcK8pX1kFzhuJp8odW9IUnSt7fnIWeaEyl1fXlfx/3b6dzYFCz+fOk6r88sWbrctZK+pXfe/7Qsa+qznm8xHlCkbt5ws6ClLqsUNCvbLcjm+rmvJaW2TK7wvJ0CAACA0nk7HSASh4IBhB9n+ug4QASeHACRxpo+Og4Qno+OA9g/B7B/DmD/HMD+OQAA5ufm5wDm5wDxjTW93w4QnvfbAQCAZMvkiic5KCRdfXm4GwB81aLPvggmTZvrsNV27ILrHgg6N+5V9uf8JtvvHyxbviLW++WpF99yjfVnDbvh4WCjbfc31pYSW+Hl726x+79aAflLtbniAZl8YYV7RJKkb+7Lue+vr7jT3EipauCpI8ry+5nx1AslrdHccMeTrpf0Db3wyntlWVt/seV14wFFavAmWwYtdVmlpJ/03MF9LSm1ZfKF5+wSAAAAlM5b6gCROBQMIPw400fHASLw5ACINNb00XGA8Hx0HMD+OYD9cwD75wD2zwEAMD83PwcwPweIb6zp/XaA8LzfDgAAJFtNvnClg0LS1YcfLTJdB+CPPv9iRfDIk/OCK8dNc9BqO/eTE3/bIc/5k4eMiPWeaWsLghvvfMo11p/Vf9AQ42wpuX3eub5fT6sf3yyTK25Tkyt85F6RJOmb2/WAU8yNlKrOumxiWX47I0ZPLGmd5r6pL7le0jf02FOvlmWNfd4bbxsLKFL79twpaKnLKiXdsmEv97Wk1JbJF2faIQAAACidt9UBInEoGED4caaPjgNE4MkBEGms6aPjAOH56DiA/XMA++cA9s8B7J8DAGB+bn4OYH4OEN9Y0/vtAOF5vx0AAEi2TK54v4NC0lPXrZqDtrY203WAKrdy5ergyefnB1eNn+6A1ZjqvefhHfKsf/LZl2K9d95892PXV3/WuVfeHXTZvL+xtpTUcoVDrHz8dd/PFXqs+Vu96Z6RJGnt1TY0BWddNtEcSalp+NipQd2We8f+2xl08gUlrdM8Pedt10v6hu6a8mJZ1trnv/O+sYAiVV//46ClLquUNHdNm9fv4d6WlNam2R0AAAAonbfWASJxKBhA+HGmj44DRODJARBprOmj4wDh+eg4gP1zAPvnAPbPAeyfAwBgfm5+DmB+DhDfWNP77QDheb8dAABItpp8scUhIelpx/5HmaoDVLHVrW3Bi/MWBNdPfMLBqjE25Mq7/nigeLmf81v3HRS0tbXFeg/d89gc11h/1k7NJxpnSwktkysMt+oRXpfGvTrV5Iqz3DuSJK29L+cG5khKU1sXj479d7P57oeVtE7z9vuLXCvpG7rprqfKsub+wcJPjAMUueldNw5a6rJKSad338p9LSmdewj54iN2BgAAAErn7XWASBwKBhB+nOmj4wAReHIARBpr+ug4QHg+Og5g/xzA/jmA/XMA++cAAJifm58DmJ8DxDfW9H47QHjebwcAABJt/UyuuMxBIenp4GPOMVUHqEJtbUEwb/7C4Hd3PeVA1TK071FDO+Q5f8nVt8R6Hy1ZujwYMW6aa6w/dfLQscbYUlIPw8wVn+jRo/nvLXtE8589mv8lky/e4x6SJGntnT7sVnMlpaYBh59Xlt/N+x9+vM5rNStXrg5GjHOtpLV15bhpQWtrW+xr74s+XWIMoMhdv1F90FKXVUr6Q3bjoEuu4N6WlMJ9hMIkuwIAAACl8xY7QCQOBQMIP8700XGACDw5ACKNNX10HCA8Hx0HsH8OYP8cwP45gP1zAADMz83PAczPAeIba3q/HSA877cDAADJ1TlfyDgkJGWHmv7mKlN1gCrz1oJFwbj7nnGQahnbdOeflP0ZX9vQFMx/5/1Y76Unnn/T9dWfGj52apDfdaAxtpTICh/U9Nqr1qrHOmpu/k5NrjjSfSRJ0l+2ff/jzJeUmo799aiy/G4mTXmipPWam++d5XpJ39CnS5bFvv7+xbLlxgCK3C+7bx201GWVogq9dnFvS0pfucJdNgQAAABK5012gEgcCgYQfpzpo+MAEXhyAEQaa/roOEB4PjoOYP8cwP45gP1zAPvnAACYn5ufA5ifA8Q31vR+O0B43m8HAACSq1N9v20dEpKurhw90VQdoEosWLg4mPjQ8w5PLXOnXTy+Q57x/Q87Pdb7qbWtLbjhjiddY/2pgaeOML6WknkI5upMvriLFY/SZXKFs9b8TdvcV5Ik/XmnXDjOnEmpaOi1k8rym7ngijElrdk89MQrrpf0Db21YFHs6/CtrW2e/4pcodcuQUtdVinqyo0a3NuSUlcmV7zdTgAAAEDpvNEOEIlDwQDCjzN9dBwgAk8OgEhjTR8dBwjPR8cB7J8D2D8HsH8OYP8cAADzc/NzAPNzgPjGmt5vBwjP++0AAEBy1eT7HeSQkHR194PTTNUBUu6Tz5YGk6bNdWhqB1X46eAOecbffMfkWO+rV99a6PrqTw274eFgo233N76Wkliu32lWO9pPJl/4aU2uuMq9JUnS/2v7/seZNyk1de9zcOy/mf2PGFzSms0Lr7znWknf0Je/j3LYYPP+xgCK1Ea5vsHcumzQotT0fLZrsPGa6+r+lpSu/YTiOLsAAAAApfNmO0AkDgUDCD/O9NFxgAg8OQAijTV9dBwgPB8dB7B/DmD/HMD+OYD9cwAAzM/NzwHMzwHiG2t6vx0gPO+3AwAAyZXJFX/lkJB0NXvOPFN1gJRasnR5MGXmvGDEuGkOTO2gho95LNhwm/3K/nzvtvU+weLPl8Z6f935yAuusf5U/8PPNbaWknkA5p1rpvrrW+1o57WTfKGQyRW+cI9JkvT/On3YreZOSkW77Hdy7L+X7jscELS1ta3zms2HHy9xraRvaNozr5dlbX7jbffz/FfkHuraPWipyypF/bzH9u5tSakqky/eaAcAAACgdN5wB4jEoWAA4ceZPjoOEIEnB0CksaaPjgOE56PjAPbPAeyfA9g/B7B/DgCA+bn5OYD5OUB8Y03vtwOE5/12AAAguWpyxVEOCUlXHy/6zFQdIGWWrVgVzHjujWDk+OkOSu3gjhsyukOe70edPizWe+zTJcuCEeNcX/1PQ668K+jcu7+xtZS0wy9zxXkb1Bf/zUpHPGrzhR0y+cIi95okSf/TjnufYP6kVHTgcReX5Tfz2pvvrvO6TWtrW3CVdUFprd079aWyrNFvtvPBnv+K3IiNGoKWuqxS1IQNe7m3JaWswnVW/wEAAErnTXeASBwKBhB+nOmj4wAReHIARBpr+ug4QHg+Og5g/xzA/jmA/XMA++cAAJifm58DmJ8DxDfW9H47QHjebwcAAJIrky886oCQ9LTxtvuZpgOkyKrVrcGsOW8H1972uANSK6Qf7vfLDnnGPzrj2VjvtenPvO766k/t1HyisbWUsDK54rJOjX0brHLEq3N9v56ZfPEd95wkSf/TGZfeZg6lxHfi+TeV5fdy5wN/KGnt5rYHZ7te0lq6+d5ZZVmr7737Tz37FbljemwXtNRllaLmrql3/R7ub0kpqjDCyj8AAEDpvPEOEIlDwQDCjzN9dBwgAk8OgEhjTR8dBwjPR8cB7J8D2D8HsH8OYP8cAADzc/NzAPNzgPjGmt5vBwjP++0AAEBy1eSK8x0Qkp52aT7WNB0gBVrb2oIX5y0IbrjjSQejVlDDRj8UbLD5gLI/3xt2PTRY3doa2/325f/v629/wjXWHzt56FjjaimBZeqLP7HCUR7fqy/+oCZfeNl9J0lSMdhlv5PNo5T4Lr5+clDb0BT77+W8395Y0vrNH2a95npJa+mq8dPLsma/Tb/DPfsVuR/1+lHQUpdVyvpl963d35LSs7eQK1xq1R8AAKB03nwHiMShYADhx5k+Og4QgScHQKSxpo+OA4Tno+MA9s8B7J8D2D8HsH8OAID5ufk5gPk5QHxjTe+3A4Tn/XYAACCZGhsH/V1NrrDaISHp6SfHnWuaDpBwr761MBhz99MORK3ABp0+skOe7+ddNjrWe+7lNz50ffXHho+dGuR3G2hcLSXv0MurrHCU139t2u97a/72z7j/JEnVXm1DU3D25b83n1Li67njIbH/Xg44crD1GymmPv9iRezr9jsNONqzX5GryxWCOXVdg5a6rFLUg926u78lpakLrfgDAACUztvvAJE4FAwg/DjTR8cBIvDkAIg01vTRcYDwfHQcwP45gP1zAPvnAPbPAQAwPzc/BzA/B4hvrOn9doDwvN8OAAAkU+fGpq4OB0lXv7rwWtN0gIRasPCz4PbJsx2CWsFtUzymQ57vc+e9Geu9577T/+2wU64wppYSViZfnNmt2+7/YIWj/P6zR/O/rLkGD7oPJUnV3q4HnmY+pcS3874nxf5b2XTHg0pav/n406WulfQNvfvBp7Gv3/9wn+M897VO3b1hj6ClLquUtWOv3dzfktJRrjjEaj8AAEDpvAUPEIlDwQDCjzN9dBwgAk8OgEhjTR8dBwjPR8cB7J8D2D8HsH8OYP8cAADzc/NzAPNzgPjGmt5vBwjP++0AAEAyZXKFHzogJF1dM+ZO03SAhPnyQNxJ0+Y6/LTCG3rN/UHnhqayP9v3OPDE2O8/11dfNmz0w8FG2x1gTC0lqEy+8PH3NutXZ3Wj43Trtvs/rLkWt7ofJUnV3Jdz5XOuuMu8SonuwGMvKsvv5b33P1rnNZy2trbgqvHTXS9pLb302vuxr+PvccAJnvtapy7apHfQUpdVyhqyyRbub0np2GfIFc6y0g8AAFA6b8MDROJQMIDw40wfHQeIwJMDINJY00fHAcLz0XEA++cA9s8B7J8D2D8HAMD83PwcwPwcIL6xpvfbAcLzfjsAAJBMNfWFnzkgJF3d/8gTpukACbF46fJgysx5wYhx0xx8moAOOv6SDnm2jxp3T6z34WNPver66o/1P/xc42kpURVaa/P9dreyUQGam7+TyRWuck9Kkqq5PQ8507xKie6E824qy2/lgUefLGkdZ8IDz7le0lp6Yvabsa/n9z34ZM98rVMDe+4QtNRllbJmdN046JIruMclJb9c4VSL/AAAAKXzVjxAJA4FAwg/zvTRcYAIPDkAIo01fXQcIDwfHQewfw5g/xzA/jmA/XMAAMzPzc8BzM8B4htrer8dIDzvtwMAAMmUyRfPd0BIuprz8hum6QAVbtnyVcGM594IRt4y3YGnCSq/68CyP9c32Lx/8NEnn8V2L65a3Rpce9vjrq+Cc0feE3RZc78ZT0vJKZMr/sqqRmVZc11OcW9Kkqq1zo17rZlX3Gt+pcR28fWTg9qGpth/K8OuGlfSWs6UmfNcL2ktPTC9JfZ1/b0OPdUzX+vUdpvtFrTUZZXCCr12cY9LSv5eQ75wgtV9AACA0nk7HiASh4IBhB9n+ug4QASeHACRxpo+Og4Qno+OA9g/B7B/DmD/HMD+OQAA5ufm5wDm5wDxjTW93w4QnvfbAQCAZKrJFcc5ICRdLV6y1DQdoEKtXLU6mDXn7eCaCY876DRhnT38jg55rh92wvmx3pNzXl3g+uqP7bTPicbSUqIOuSzes956g//GqkblyTQUjqrJF1rdp5KkaqzfoWeZXynR9dzx4Nh/Jz/9RWlrPS+88p5rJa2lWyc9G/v6fvOgMz3vtU51zheCZ+q6BS11WaWs4Rs3uMclJb5O+X5HW9kHAAAonbfkAaJtvXlyAIQeZ/roOEAEnhwAkcaaPjoOEJ6PjgPYPwewfw5g/xzA/jkAAObn5ucA5ucA8Y01vd8OEJ732wEAgGTK5AtPOiAkPfXoc6ApOkAFam1tC16ctyAYNfFJB5wmtAGHn9shz/b7H3k81ntz/KRnXV8FJw8daywtJalc4c3M5k3/bkWjctXmigdkcoWV7ldJUrXVZfP+wW+uvs88S4lt531Piv13ssUeA0tay1mwcLFrJa2la297PPUO7qUAACAASURBVPZ1/v2PGOx5r3Xu1g17BS11WaWsZ+q6BdlcP/e4pGTX0DTIqj4AAEDpvC0PEIlDwQDCjzN9dBwgAk8OgEhjTR8dBwjPR8cB7J8D2D8HsH8OYP8cAADzc/NzAPNzgPjGmt5vBwjP++0AAEAy1eQLHzogJD3tvv8JpugAFWbe/IXBTXc/5WDTBHf52KlB9x0OKvtzveeOBwYrVqyM7d784KMlrq+C4Wvu7/yuA42lpYSUyRWXdWpoarSaUfky+eIuNbniYvetJKnaahp4jrmWEtuBx15Ult/Jx4s+W+f1nFWrW4MR46a5XtJaWrZiVaxr/Qcfc45nvda5czbZMmipyyqFHdxzR/e4pGTvO+QLh1rRBwAAKJ035gEicSgYQPhxpo+OA0TgyQEQaazpo+MA4fnoOID9cwD75wD2zwHsnwMAYH5ufg5gfg4Q31jT++0A4Xm/HQAASJ7vbfaj/8/hIOlq4IlDTdEBKsRbCxYF4+9/1mGmKejkoWM75Ll+5tBrYr1HH3nyFddXwWGnXGEcLSWoTrniYVYzkqM213fzmnzhQ/euJKma2qD3gGDotZPMt5TITjjvprL8TqY+8VxJazpj73na9ZLW0gcfLYl1PfXQ48/zrNc6d3DPHYOWuqxS2OiNcu5xVU+5wtNretPfIl3V1hcOtJoPAABQOm/OA0TiUDCA8ONMHx0HiMCTAyDSWNNHxwHC89FxAPvnAPbPAeyfA9g/BwDA/Nz8HMD8HCC+sab32wHC8347AACQPLWb7bWpw0HS1TmXjDJFB+hgH368JPj9wy84xDRF7XnImR3yXJ89Z15s9+nyFauCq2+d4fpWecNGPxxstN0BxtFSQsrkC9dayUie7+ebutfkivPdw5KkamrA4eeZcymRXTTqwbL8RkaMnljSus4D01tcL2ktvfLmh7Gu/f/spKGe81rntqzfPWipyyqFzVnTprkfu89VLb1e09Bvq0y+sMLfIkXlCj7ADAAA0A68QQ8QiTUpgPDjTB8dB4jAkwMg0ljTR8cBwvPRcQD75wD2zwHsnwPYPwcAwPzc/BzA/BwgvrGm99sBwvN+OwAAkDyZfLGfw0HS1ahx95iiA3SQxUuXB1NmzgtGjHN4aZq67KYpQXar5rI/03fsf1Ss9+vsl991fRUMOPxcY2gpMYdaFmdt0KfPP1rJSKbv5/tvkMkVXnUvS5KqpewWzcHF108271Ii69Hn4Nh/I0eeenFJ6zqz5rztWklr6ek1v404ffnb9ZzXula7plnZbkFLXVYp7Kge27nPVSXr1IXV3brt/g+ZXPFEf4/01CnXr2gVHwAAoHTepAeIxKFgAOHHmT46DhCBJwdApLGmj44DhOej4wD2zwHsnwPYPwewfw4AgPm5+TmA+TlAfGNN77cDhOf9dgAAIHlqcoVjHQ6SriZPfcoUHaDMli1fFcx47o1g5C3THVyawo4efF2HPNNH3HB7rPftzffOcn2rvHNH3hN02by/MbSUgDL54iddevfPWsVItg023/P7mXzhBfe0JKla2u+YC829lMh23ufk2H8fO+x1ZEnrOvPf+8S1ktbSo0+9Guua6jFnXOIZr5K6dcNeQUtdVils4oabusdVNXVq7LvJeuutt34mV7zd3yMl5Zr2sIIPAABQOm/UA0TiUDCA8ONMHx0HiMCTAyDSWNNHxwHC89FxAPvnAPbPAeyfA9g/BwDA/Nz8HMD8HCC+sab32wHC8347AACQPJlc4VKHg6SrlnnzTdEBymTV6tZg1py3g2smPO7A0hS3U/OJZX+ed2ncK3jv/Y9iu3ff/eBT11bBTvucZPwsJaJCa0194cdWMNLhvzbt971MrvC8+1qSVA1ttO3+wWW/m2L+pcR1wLEXx/776NzYFHy+dNk6r+18sWylayWtpXsemxPrnsAJg4d7xqukzt9k86ClLquUtkX9Hu5zVUWZfLHfl2udG9QX/y2TK7zmb5KKa7qL1XsAAIDSebMeIBKHggGEH2f66DhABJ4cAJHGmj46DhCej44D2D8HsH8OYP8cwP45AADm5+bnAObnAPGNNb3fDhCe99sBAIDkqckXf+9wkHRVyiGMAITT2tYWvDhvQTDqjicdVJryLhr1YNC5d/+yP8/3P2JwrPfwg9NbXN8q7+ShY42dpcRUOMfqRbpkNm/695pc4Wn3tiSpGjrslCvMwZS4jh9yY1l+HzOffamk9Z0brE1Kf9G4+56JdV31l0NGeL6rpA7t2SdoqcsqpZ3SfRv3uaqiTL5wwv9d6+zU2Lchkysu83dJdp0aittbuQcAACidN+wBInEoGED4caaPjgNE4MkBEGms6aPjAOH56DiA/XMA++cA9s8B7J8DAGB+bn4OYH4OEN9Y0/vtAOF5vx0AAEieTK442+Eg6al+l0NMzwFi9taCRcHN985yQGmVdNgvL++QZ/rt906J7R5etnxlMHL8dNe3ihs+dmqQ322g8bOUiAoPrLfe4L+xepE+G9QX/60mV5jhHpckpb1eu/wkuHzNHMRcTEnqN1ffX5bfx6hb7ilpjefuR190vaSvde1tj8e6P3DqeSM931VS2222W9BSl1VKu69bD/e5qmXd+sqvrnXW1Bd+5m+S7DrnC72t2gMAAJTOW/YAkTgUDCD8ONNHxwEi8OQAiDTW9NFxgPB8dBzA/jmA/XMA++cA9s8BADA/Nz8HMD8HiG+s6f12gPC83w4AACRPTa642OEg6anvwSebngPEZMHCxcHEybMdTFplbdn3yLI/zzfedr/gi2XLY7uXZ730tmtb5Q08ZYSxs5SEcsX5nRr7/oeVi/T6zx7N/5LJFx51v0uS0t6xv77BXEyJq9vW+8X+2zjx7MtLWuN5fPabrpW0llauXB3b2upp54/0bFdJdVnT7Gy3oKUuq5S2zWa7uddVDU3++lpnJle4yt8luXWu79fTij0AAEDpvG0PEIlDwQDCjzN9dBwgAk8OgEhjTR8dBwjPR8cB7J8D2D8HsH8OYP8cAADzc/NzAPNzgPjGmt5vBwjP++0AAECyfHk4t4NB0tVRp11seg7Qzj75bGkwadpch5FWYeeOvCeobWgq+/P8hMHDY72nx9z9tOtbxV0y+pFgo+0OMHaWKrxMvri8tr5pCysXVbE28881+cID7ntJUprbsu+R5mNKXNsUj4n9t7HHgSeWtMYzb/5C10paSx9/ujS2tdUzfnO1Z7tK7vfdNg1a6rJKaad139p9riqo8MbX1zl79Gj++zX/s2n+Nsnse5v1q7NaDwAAUDpv3QNE4lAwgPDjTB8dB4jAkwMg0ljTR8cBwvPRcQD75wD2zwHsnwPYPwcAwPzc/BzA/BwgvrGm99sBwvN+OwAAkCw1jYUtHQySri64YozpOUA7WbJ0eTBl5rxgxLhpDiKt0vY75sIOeZ4//vSLsd3Xby1Y5NpWefseOdS4WUpGh1u1qB7/c+Bs4Q73vSQpzZ160XhzMiWqpoHnxP676Lb1PkFra9s6r/MsWvyFayWtpfnvfRLb+uqZQ6/xXFfJXbxJ76ClLquUNqlrD/e5qqBC6wZ9+vzj19c5/2vTft/L5Atv+/skry+vnZV6AACA0nn7HiASh4IBhB9n+ug4QASeHACRxpo+Og4Qno+OA9g/B7B/DmD/HMD+OQAA5ufm5wDm5wDxjTW93w4QnvfbAQCAZOmUa9rfwSDp6uY7JpueA5Ro5crVwZPPzw+uGj/dAaRV3ma7/LTsz/It9xxY0mHKf819U19ybau4odfcH/xgi72Nm6UKL5MvjLViUX0aGwf9XSZfnOA3IElKazvtc5J5mRLVoNOvKstv44233itpreeaCTNcL+lrzXl1QWzrq7+68FrPdZXc4T22D1rqskpx2262u3tdqe/7+abua30XrbFvQyZX+MLfKFl9d4vd/9UqPQAAQOm8hQ8QiUPBAMKPM310HCACTw6ASGNNHx0HCM9HxwHsnwPYPwewfw5g/xwAAPNz83MA83OA+Maa3m8HCM/77QAAQLJk8oUzHAySrqbPfN70HGAdrW5tC16ctyC4/vYnHDyq4MxLJnTIs/yiK8fGdo8v/WJFcOUt01zfKm7PQ840ZpYqvEyuOLtTY99/tmJRpfr0+dtMvjjGb0GSlMZqG5qCISPuMjdTctaGLr2tLL+N+x95vKT1ntsnz3a9pK/1xPNvxrbGOvii6zzXVXI7b7Zr0FKXVYo7vfvW7nWlfy27oanvt7yPdqi/UbJqbBz0dxboAQAASudtfIBIHAoGEH6c6aPjABF4cgBEGmv66DhAeD46DmD/HMD+OYD9cwD75wAAmJ+bnwOYnwPEN9b0fjtAeN5vBwAAkqUmV7zewSDp6u33PjQ9B4iorS0I5s1fGPzurqccOKo/VRx4Toc8y199453Y7vWZL8x3bau4s347Mejc0GTMLFVyueLiTo19N7FaUfXWr8kXRvhNSJLSWN9DB5ufKTH99nePBp0b94r9d3HpNeNLWu957OlXXS/paz30xCuxrbGeffH1nukquR/kC8Gcuq5BS11WKe3Bbt3d60p9tfniMX/lnbTL/Z0SszexyrI8AABA+/BWPkAkDgUDCD/O9NFxgAg8OQAijTV9dBwgPB8dB7B/DmD/HMD+OYD9cwAAzM/NzwHMzwHiG2t6vx0gPO+3AwAAyZLJF6Y4HCQ9bbB5/2B1a6vpOUAEby1YFNxy/zMOGtWfNXzMY8FG2x1Q9md506Gnxnavt7W1BTfeOdP1reK273+cMbNU2bXV5Pv1t1LB/1o/ky9e5nchSUrdGnbvAcEF104yR1Niqv/RYbH/Ln7+ywtLWvOZ8+r7rpX0tX7/8AuxrbP+etgoz3S1S/d16xG01GWV4rap3929rnSXKw771hXOPn3+1ntpibmWiy3JAwAAtA9v5gNE4lAwgPDjTB8dB4jAkwMg0ljTR8cBwvPRcQD75wD2zwHsnwPYPwcAwPzc/BzA/BwgvrGm99sBwvN+OwAAkCw1ueJ8h4Okp20LPzc1Bwjpg4+W/PFgTQeMam2dcO7vOuRZPub2B2K7519/+yPXtoo7eehY42Wpwsvki+dbpWAt6zZD/D4kSWlr36OGmqcpMf3owFNj/03sNODoktZ8Pvx4iWslfa0xdz8d2zrrkEtv8DxXu/TbjRuDlrqsUtxp3bdyryvda9q54sS/tr6Z2bzp39f8777u71XxvW81HgAAoH14Qx8gEoeCAYQfZ/roOEAEnhwAkcaaPjoOEJ6PjgPYPwewfw5g/xzA/jkAAObn5ucA5ucA8Y01vd8OEJ732wEAgOTo1m33f6jJF1odDJKe9j9isKk5wF+xaPEXwaRpcx0sqm9t1wNPK/tzPLtlc/DZ4s9ju/fvnvKia1ulDR87NcjvOtB4Warsw0cfXq+5+TtWKlibmlxxiN+JJClNbbjNfsGlNz5ivqZEdNDxl8T+m9igd/9gxYqV67zms3p1azBi3DTXS/pKV42fHts663mXjfY8V7t0dI/tgpa6rFLcg926u9eV8grPhlnf7NTQ1JjJFb7w96roa/mGlXgAAID24U19gEgcCgYQfpzpo+MAEXhyAEQaa/roOEB4PjoOYP8cwP45gP1zAPvnAACYn5ufA5ifA8Q31vR+O0B43m8HAACSI9OrsLFDQdLVqeeNNDUH+AbLlq8MZjz3RjDylukOFdW39uXB3nVb7l325/gRp1wU2/2/eOlyhytXcT877UpjZamCy+SKC7o07tXJKgXfZs29corfiyQpTR168nDzNSWiE8+/qSy/iTkvv1HS2s+Yu592vaSv9cWylbGstZ732xs9y9Uu7d7rh0FLXVYpb9v63dzvSvHaduHTsOubtfWFA/3NKrhc4SWr8AAAAO3DG/sAkTgUDCD8ONNHxwEi8OQAiDTW9NFxgPB8dBzA/jmA/XMA++cA9s8BADA/Nz8HMD8HiG+s6f12gPC83w4AACRHbb7f7g4GSVcjbrjd1Bzga1auWh3MmvN2cM2EGQ4SVaiOOPPqDnmOP/yHp2P7Hcx47g3Xtkq79MZHgk12OMhYWarcQ0dXdqrvt60VCsLI1BdO9ruRJKWlnjv9dzB87FTzNlV8Q6+dVJbfxO33Tilp7ee+qS+5XtLX+vDjJbGstf7m8ps8y9Uudcv3C16q6xq01GWV4k7vvpX7Xamutkfzd0Ovb+aKl/ibVWi54iwr8AAAAO3Dm/sAkTgUDCD8ONNHxwEi8OQAiDTW9NFxgPB8dBzA/jmA/XMA++cA9s8BADA/Nz8HMD8HiG+s6f12gPC83w4AACRHJlc80sEg6eruB6eZmgP8r9bWtuDFeQuCUROfdICoIrV9/+PL/gzP/fC/g1WrV8fyW1i95rcwauITrm2Vtv8xFxonS5VcQ/F4qxNEUZMrnu63I0lKS0cPvt68TYloo233j/33cN5vbyxp/eeJ2W+6VtLXeu3tj2JZbx16xU2e42q3JnftHrTUZZXivrzG7nWluU6NfRtCL2726fO3a/5vJvu7VWC5wh+svgMAALQPb/ADROJQMIDw40wfHQeIwJMDINJY00fHAcLz0XEA++cA9s8B7J8D2D8HAMD83PwcwPwcIL6xpvfbAcLzfjsAAJAcNbniMAeDpKvZL71qag6wxhvvfByMuftpB4cqchdcOyno3LhX2Z/hZ110XWy/h1fe/NC1reL7ObtFs3GyVLmHVI63MsG6yOQKg/2GJElpaPM9f27upkS03V7Hxf57OOTYISWt/7xs/Uf6i2a//G4s660XXDHGc1zt1pUb54OWuqxS3nab7eZ+V5obEGVts7ZH83czucKr/m4V14NW3gEAANqHt/gBInEoGED4caaPjgNE4MkBEGms6aPjAOH56DiA/XMA++cA9s8B7J8DAGB+bn4OYH4OEN9Y0/vtAOF5vx0AAEiOmnzhDoeCpKtPP1tiag5UtXc++DSY8MBzDgzVOnfICZd1yDP8+bmvxva7uOOh513bKq3vT84yRpYqtsLL391i93+1MsE6r+nkikP8jiRJaej0Ybeav6ni6z9oSOy/hS32GFjS+s/CRZ+7VtLXmv7M67Gst54//Hee4Wq3Tuy+TdBSl1XKO6P7Vu53pbZMrnhi1LXNTo19N8nkCp/6+1VUv7fqDgAA0D68zQ8QiUPBAMKPM310HCACTw6ASGNNHx0HCM9HxwHsnwPYPwewfw5g/xwAAPNz83MA83OA+Maa3m8HCM/77QAAQHJkcsXZDgVJT913OMC0HKhaHy36PLj70RcdFKqSa9zj8LI/w3cacHRsv41PPvvCda3Szr78zqBz417GyVJl9nnn+n49rUpQqppc4QK/J0lS0tv1wNPM4VTxHX7GVbH/FmobmoLFS5au8xrQ6tWtwYhx01wv6Ss9MG1uLGuu51022jNc7Vah1y5BS11WKe+hrt3d70pvueIV6/TOWr7YryZfaPU3rJjrOM6KOwAAQPvwVj9AJA4FAwg/zvTRcYAIPDkAIo01fXQcIDwfHQewfw5g/xzA/jmA/XMAAMzPzc8BzM8B4htrer8dIDzvtwMAAMlRkysudjBIetp9/xNMy4Gq8/kXK4IpM+c5MFbt0q+v+H2HPMOvGHVbbL+RP8x6zbWt0voM+IUxslSxh1MWDrEiQXvJ5ApD/a4kSUmuc+/+wQXXTjKPU0V3xrBby/J7eOq5uSWtA425+2nXS/pKEyfPjmXN9ZxLRnmGq93qXt83aKnLqgrabrPd3PNK63r3Xev+3lq/0/wNK+U6Fq+32g4AANA+vN0PEIlDwQDCjzN9dBwgAk8OgEhjTR8dBwjPR8cB7J8D2D8HsH8OYP8cAADzc/NzAPNzgPjGmt5vBwjP++0AAEAy/Nem/b7nUJB0NejkC0zLgaqxctXqYNact4OrJ8xwOKjarX2OHFr253dtQ1Pw1rsfxPI7WbW6Nbjutsdd2yrslxeMMz6WKrRMrjDcigTtbP2aXPFyvy9JUpLb7+gLzeVU0V164yN/XMOJ+7dw022TSloLum/qS66X9JXG3P10LOuuZ198vee32rVpXTcKWuqySnmndd/a/a609kwpa5uZfGGsv2EFlCteYakdAACgfXjLHyASh4IBhB9n+ug4QASeHACRxpo+Og4Qno+OA9g/B7B/DmD/HMD+OQAA5ufm5wDm5wDxjTW93w4QnvfbAQCAZKhp6LeVQ0HS1bmXjTYtB1KvtbUteHHegmDUxCccCqp27fKxU4OeOx5S9ud386AzY/u9zH3tfde2Su/l3rsPMj6WKrBMrvhEjx7Nf29FghisX5MrjvQ7kyQltY23PzAYPuYxczpVdD13PDj238KZQ68paS3o8dlvulbSV7p6woxY1l3Puug6z2+1a7/bqD5oqcsq5d29YQ/3u9JZrriwlIXN2q2a/6kmV3ja37KjK1xkmR0AAKB9eNsfIBKHggGEH2f66DhABJ4cAJHGmj46DhCej44D2D8HsH8OYP8cwP45AADm5+bnAObnAPGNNb3fDhCe99sBAIBkqK0vHOhAkHR14633m5YDqfbWgkXBzffOchioYunUi27pkOf3LXc+FNtvZsIDz7m2VdjPz7ja2FiqwDL5wsffqy/+wGoEMVq/Jlcc6fcmSUpqR551rTmdKrodBvwi9t/B3j87o6S1oJff/NC1kr7WylWr233d9cyh13h2q107u/uWQUtdVlVQ7/o93PNKY221WzX/UykLm10a9+qUyRff8bfs0H5tiR0AAKB9eOMfIBKHggGEH2f66DhABJ4cAJHGmj46DhCej44D2D8HsH8OYP8cwP45AADm5+bnAObnAPGNNb3fDhCe99sBAIBkyOSKv3IgSLp6dMYzpuVAKr3/0eJg4kPPOwBUsVb46dllf3Z33ao5WPz50lh+NwsXfe66VmGX3TQl6NHnYGNjqeIqtHbK9fuRlQjiN/hv1txzo/3mJElJbMu+R5jXqaIbcPi5sf8ONtv54NLWgz6xHiR9vU+XLGv3tdfTf3OVZ7fatf/uuUPQUpdVFXR0j+3c80pltfl+3drhPbZtMvnicn/PDirX7zTr6wAAAO3Dm/8AkTgUDCD8ONNHxwEi8OQAiDTW9NFxgPB8dBzA/jmA/XMA++cA9s8BADA/Nz8HMD8HiG+s6f12gPC83w4AACRDTb5wg0NB0tXr8981LQdSZfHny4PJM1528Kdib/iYx4KNtjug7M/uI0+9OLbfz5SZ81zbKuzA4y42LpYqsEy+cKZVCMqmufk7mVzhJr89SVISO/OSCeZ2qtgGnX5VWX4Hn3y6eJ3Xg1avbg1GjJvmeklfacHCz9p97fWUc6/03Fa7tv1muwUtdVlVQeM27OWeVzqrL+7YLu+y5QqH+Ht2ULnCcRbXAQAA2od/AQAQiUPBAMKPM310HCACTw6ASGNNHx0HCM9HxwHsnwPYPwewfw5g/xwAAPNz83MA83OA+Maa3m8HCM/77QAAQDJkcsXHHAqSnjo3NgUrVqw0LQdSYdmKVcGM594IRt4y3aGfKksnnPu7Dnl+P/yHp2P5Da1ctTq4ZsIM17bKuvD6B4PsVs3GxlKFlckX7l1vvcF/YxWCsmpu/s6ae2+s36AkKWntcfDp5neq2M4YNqEsv4OZz75U0rrQmLufdr2kr/TaWx+1+/rryUNGeG6rXeuSLwQv1nUNWuqySnlzsl2D7vV93fdKYf0Oar/32QqX+nt2QA1NgyysAwAAtA//EgAgEoeCAYQfZ/roOEAEnhwAkcaaPjoOEJ6PjgPYPwewfw5g/xzA/jkAAObn5ucA5ucA8Y01vd8OEJ732wEAgGTI5IvvOBQkPW2xx0BTciDxVre2Bc+1vBtce9vjDvtUWdv1wFPL/uyu3+WQYNWq1bH8ll545T3XtQorHHa2cbFUaeWK8zs19v0PKxB0iObm76y5B8f5LUqSklSXzfsHF1z3gDmeKrJLRj8S1DY0xf47uPmOySWtC9079SXXS/pKX66VtrcTz77cc1vt3n3degQtdVlVQT/puYN7XilcC+93Wnuua2byhXv9Xctdv4MsqgMAALQP/yIAIBKHggGEH2f66DhABJ4cAJHGmj46DhCej44D2D8HsH8OYP8cwP45AADm5+bnAObnAPGNNb3fDhCe99sBAIDKt0GfPv9Yky+0OhAkPQ0YeLopOZBYbW1BMG/+wuDGO59yyKfK3qU3PhJkt2gu+7P7rIuui+03Nf7+Z13bKmvIiLuCzo17GRdLFVQmX1zeOV/obQWCjtTYOOjvanLFO/0mJUlJ6sBjLzLPU8XWo8/Bsf8Gzr1sdEnrQo/PftO1kr7Sk8/Pb/f1118M/q1nttq9KzZuCFrqsqqCrt0o755XCiuMaM91zS69fvx/MvniK/6uZW2AFXUAAID24V8GAETiUDCA8ONMHx0HiMCTAyDSWNNHxwHC89FxAPvnAPbPAeyfA9g/BwDA/Nz8HMD8HCC+sab32wHC8347AABQ+b6fb+ruMJB0deLZl5uSA4n01oJFwfj7n3W4pzqsI8+6tkOe3bNfejWW39SChYtd1ypsp31OMiaWKq2GpkFWH6gEPXo0/31NrnCX36UkKSltssNBwfAxj5nrqSLbfsDxsf8GDj3+vJLWhl5+40PXSvpKU2bOa/c12ON+dZlnttp/v7/7NkFLXVZV0OxstyCb6+e+V7rKFe9s73XNTK/Cxpl8YZG/b3mqbSjuZjUdAACgffjXAQCROBQMIPw400fHASLw5ACINNb00XGA8Hx0HMD+OYD9cwD75wD2zwEAMD83PwcwPweIb6zp/XaA8LzfDgAAVL6a+sKPHQiSri67drwpOZAoH3+6NJg0ba5DPdXh7dh8Ytmf2zv2Pyq239bkx192XausUy+6xXhYqrAy+eKNVh6oJBv06fOPNfnCA36fkqSkdMzZo8z3VJH1P/zc2O//7YpHlLQ2tPCTz10r6Svd+9icdl+DFU/IFwAAIABJREFUPfqMSzyv1e41bbpL0FKXVZW096Y7ue+VrnLFWfG931Zo9Tcuw75GrriNlXQAAID24V8JAETiUDCA8ONMHx0HiMCTAyDSWNNHxwHC89FxAPvnAPbPAeyfA9g/BwDA/Nz8HMD8HCC+sab32wHC8347AABQ+WpyhWMdCJKuJt77qCk5kAiff7EimDJzXjBi3DQHeqrDu3jU5KDL5v3L/ty+/PoJsfy+lq9YFVw1frprW0VdPnZqsGXfI4yHpYo6eLLwfKfGvv9s5YFKU7tV8z9lcsXH/E4lSUlo68JR5nyqyH522pWx3/8b9O4frFixcp3Xh1avbrX2Kn2lCQ881+7rsEeddrHntdq9zer3DFrqsqqSLtm4t/teKavwQWzvuOWLp/j7xl9tY7GXVXQAAID24V8LAETiUDCA8ONMHx0HiMCTAyDSWNNHxwHC89FxAPvnAPbPAeyfA9g/BwDA/Nz8HMD8HCC+sab32wHC8347AABQ+TK5wqUOBElXT89uMSUHKtrKVauDJ5+fH1w1frqDPFUxHXbKFeU/kKyhKXjr3Q9i+Z09O/cd17XKOuqsa42FpUoqV1zcqbHvJlYdqFTf3WL3f83kik/5vUqSktBZv51o3qeK6/Rht5bl/n/5tbdKWiO66e6nXC/pf7vxzpntvg77819e6FmtWHoiu1HQUpdVFfRkdsOgS67gvleaatugT59/jGtdsyZXHOVvHG/fqy/+wAo6AABA+/CvBgAicSgYQPhxpo+OA0TgyQEQaazpo+MA4fnoOID9cwD75wD2zwHsnwMAYH5ufg5gfg4Q31jT++0A4Xm/HQAAqHw1ueKdDgRJVx9+9IkpOVCRWlvbghfnLQhGTXzCAZ6quLYuHFX2Z/bePzsjtt/bzffOcl2rqOE3PRr03PEQY2Gpgg4NrW0o7GXFgUr3/Vzzf9bkCi/5zUqSKr0f/+RX5n6quIaNfjiobWiK/f6/7+EZJa0R3Tv1JddL+t9G3jK93ddhB518gWe1Ymnchr2ClrqsqqQ9ev3Qfa9U1aV3/2xca5q1WzX/UyZfnOnvHF+dGvv+h9VzAACA9uFfDwBE4lAwgPDjTB8dB4jAkwMg0ljTR8cBwvPRcQD75wD2zwHsnwPYPwcAwPzc/BzA/BwgvrGm99sBwvN+OwAAUPky+cILDgRJTxtus2/Q1tZmSg5UnDfe+TgYc/fTDu5URXb+1feV5RDkvzgU8/eTY/m9vf3+Ite1yjrkhMuMhaXK6kKrDSRFbf2Pa9bcs6/73UqSKrkfbLF3cPGoyeZ/qri69zk49vt/+HUTSlonevy5N1wr6SstX7GqXddiB5441LNasXRe9y2ClrqsqqQhm2zpvleq6lTfb9u41zQzucJ7/tbx1K3b7v9g5RwAAKB9+BcEAJE4FAwg/DjTR8cBIvDkAIg01vTRcYDwfHQcwP45gP1zAPvnAPbPAQAwPzc/BzA/B4hvrOn9doDwvN8OAABUvPVrcsWlDgRJTzs3H2M6DlSUBQs/C257cLbDOlXRHXT8JWV/ZnfdqjlYvGRpLL+7SdPmuq5V1JcHy3fdZl9jYalCyuQLj67Xp8/fWm4gSTo3NnV1CK0kqdI79KTh5oCquLbvf3zs9/5xv7qspHWil9/40LWSvtInn7XvmuxPf3G+57RiaWDPHYKWuqyqpEe6buK+V6qqbSjsFfeaZk1Dv60y+eJyf+923+NYYcUcAACg/fiXBACROBQMIPw400fHASLw5ACINNb00XGA8Hx0HMD+OYD9cwD75wD2zwEAMD83PwcwPweIb6zp/XaA8LzfDgAAVLYujXt1ciBIyg4WPf4803GgIiz+fFkwadpch3QqETXs9rOyP7OPOOWiWH57/z979x0mR3kg+hqvz+4er8/Zu+vds1g9I/A0QiAhabpnEBI5iihVjwRDtEDkHGyiCUZgDDJGBBEFIhlEEMmACSYjQOScGkwGkYMBERS/O7DsXp/rQNVMV6d63+f5/XWes7ZV3fOl6qrPvpgbTr/kbtc1Q43d8RfmwVL99Hb/YpSz20Ajah02dkhLIXrf91iSVK8VRm1vDai6q7TDkal/9keP379Pe0XvfvipayX9SW+8/ceK7sdO2Pso47RSac1h64ZyW14ZauX29Xz21TTlitEu1djT7PnPGu/fu8IVovftlgMAAFSOXxQAJOKlYADx55keOg6QgJEDINFc00PHAeLz0HEA5+cAzs8BnJ8DOD8HAMD63PocwPocIL25pvvbAeJzfzsAAFDf+rWPWdkLQZqrn/96muU4UFPz5i8I9z/xajj90nu8oFMN0cSTr67JmH3zzAdT+Q4+9NRrrmuGOur034Ulho8zD5bq4kWTpfmtxWg1Ow00stbC6OE9n+VPfKclSfXazyZfai2oumrb/U9O/XO/7Kpb9G2/dt4C10r6k55/5d2K7sduvdcvjNFKpXxhTHg6v1Qot+WVkQ4ctJLPvpqmXCE6vFp7mi3F6Dj/5pU864hesVMOAABQOX5ZAJCIl4IBxJ9neug4QAJGDoBEc00PHQeIz0PHAZyfAzg/B3B+DuD8HAAA63PrcwDrc4D05prubweIz/3tAABAfWsplsZ7IUhzdfZF11qOAzWxaFEI5ZfeCedceb8Xc6qh2nS3SVUfr9vX3jrMn78gle/h+Vc/6LpmqFFbHGgOLNXNS0JL+9lloCn2itpLa/R8nr/wvZYk1WMbjD/EWlB11X7HXFiVz/47733Ypz2jc668z/WSvumx8uyK7slusevhxmil1k0DBoVyW14Z6cqlh/jcq4mKTqvahmZ393dzhehG/+YVOusoRk/aJQcAAKgcvzAASMRLwQDizzM9dBwgASMHQKK5poeOA8TnoeMAzs8BnJ8DOD8HcH4OAID1ufU5gPU5QHpzTfe3A8Tn/nYAAKC+tRRLE70QpMlerHXnA5bjQNW9/vZH4ZLrH/FCTjVkQ9aaUPXx+rBjz0rlu/jK7A9d0wx1yOTLQmtHlzmwVA8VSlf3LLG/Y5eBZpErlsb0fK7n+35LkuqtJYdvHCafe4s1oeqmo8+4riqf/XseeKJPe0ZX3Py46yV906zHXq7onuy47Q82Riu1zlimI5Tb8spIz7QtFYYUNvLZV1OUK5SuqOZ+5g9WWP+fe/5zn/ZvX4nzjmiWHXIAAIDK8SsDgES8FAwg/jzTQ8cBEjByACSaa3roOEB8HjoO4PwcwPk5gPNzAOfnAABYn1ufA1ifA6Q313R/O0B87m8HAADqW65YOt8LQZqr51541XIcqJqPPvk8XHfn017EqYbtZ5Mvrcl4/dhTz6fynfyd72OmGjlmd/NfqR5eDlosPf/VCzvtMNB8e0bRdj2f8UW+55Kkemu7A06xJlTddPL0meFHK2yS+uf+/Bk39GnP6Nb7nne9pG+67f7K7s2OHr+/8VmpdeCglUK5La8MtfWQ1X321RwVoruqvp85NFomV4w+8u/f16Lf2x0HAACoHL82AEjES8EA4s8zPXQcIAEjB0CiuaaHjgPE56HjAM7PAZyfAzg/B3B+DgCA9bn1OYD1OUB6c033twPE5/52AACgvrUUS3d7GUjz1NrRFT7/4kvLcSB18+YvCPc88lI47ZK7vYRTDV20/cSqj9erdu2ayvfy08++DKde7DuZlfY56nzzX6kOyhVKX+SGRUW7CzTxvtGBvuuSpHqruO4O1oWqq776TKb9uf/5r6f1ad/ooadfd62kb7p+5jMV3Zddd/N9jM9Kre4ha4ZyW14Z6rSBHT77ao6982Lp+VrsZ/Zr71q3pRAtcA36cu4RXW5nHAAAoHL86gAgES8FA4g/z/TQcYAEjBwAieaaHjoOEJ+HjgM4Pwdwfg7g/BzA+TkAANbn1ucA1ucA6c013d8OEJ/72wEAgPqWK5RmeyFI81RYZ4KlOJC6l9/4IJz/2we8fFMN35TpM8PAVbas+ng9ZdplqXw373viFdc1I53c89ktjNre/Feqj8bbWaDZtRRKk33XJUn11iGTZ1gfqm5ae/P9U//Mb7nbxD7tG/3h1fdcK+mbrrrliYruy6658R7GZqVWZ/sGodyWV4Z6YKmlwxKFyOdfjV+h9HHN7oVrj/Z3DfrUeXbFAQAAKscvDwAS8VIwgPjzTA8dB0jAyAGQaK7poeMA8XnoOIDzcwDn5wDOzwGcnwMAYH1ufQ5gfQ6Q3lzT/e0A8bm/HQAAqF+tI7u/11IsLfIykOapNOFAS3EgNX/85Itwze1PeemmmqZ9j76g6mN1a0dXePWNtyv+/Vy4aFE496r7XdeMtPMhZ5j7SnVRdJqdBTLiOy2F0tm+85KkemqjbQ6zPlTd1L3r0al/5lcas3Of9o7e+3COayV908XXP1LRvdkVR+9kbFZ6Zwo9Pdo2IJTb8spQ6w4b5fOv5vgbNrL7e7Xa0GwpRtNcg96VK0RTbIkDAABUjl8gACTipWAA8eeZHjoOkICRAyDRXNNDxwHi89BxAOfnAM7PAZyfAzg/BwDA+tz6HMD6HCC9uab72wHic387AABQv/q3j1nOy0Caqz0POd5SHKi4RYsWhfufeDWcfsndXrippmr98YdUfazeeIeDU/mevvDae65pRppywR1huTW2NveVal70aC1fCApV19393VyhdKXvviSpXmobsUmYfN4t1omqi3Y++PTUP/NLLj8uzJ+/oNd7R/N6/v+6VtJ/du5V91d0b7Zzve2MzUq1awYsF8pteWWoQweN8NlXU/TD4rgla7WdueTqq//PXKF0n+uQvFwx+qUNcQAAgMrxSwSARLwUDCD+PNNDxwESMHIAJJpreug4QHweOg7g/BzA+TmA83MA5+cAAFifW58DWJ8DpDfXdH87QHzubwcAAOpXrlga42UgzdVxp19kKQ5U1Jdz54erb3vSizbVdJ14we0hP7K76mP1RVfdnMp31fc0O22z74nmvVLNXyhZ+nDxYWPa7CqQNa0ju7/XUohm+jsgSaqXdjjoVOtE1UU/O+7SqnzmX33j7T7tH51z1f2ul9TTGZfeU9G92aFrjjcuK9WmLNMRym15ZahrBwz22VdT1NretUIt9zOXHL7hD3PF6HXXImGFMT+zGw4AAFA5fo0AkIiXggHEn2d66DhAAkYOgERzTQ8dB4jPQ8cBnJ8DOD8HcH4O4PwcAADrc+tzAOtzgPTmmu5vB4jP/e0AAED9ailEe3sZSHN16dW3WooDFTN33vww48ZHvWRTTdkeh0+r+jidH9EdPvn0s4p/V//46Rfh1Itd0yw0+bxbwtIrb27eK9W0aGFLoWsDOwpk1RJDN/rXXDF60t8CSVI91LnBztaKqouOO/vmqnzm75j1aJ/2kK68+XHXS/qmBQsWVmx/dtlVtjAuK9X2G7xSKLfllaGe7am9fSOffzV8uWJpTK33M1vbu1bIFUpfuB7x61ccs4edcAAAgMrxiwSARLwUDCD+PNNDxwESMHIAJJpreug4QHweOg7g/BzA+TmA83MA5+cAAFifW58DWJ8DpDfXdH87QHzubwcAAOpXrlg6yctAmqt7H3rKUhyoiLnzFoTLfv+Yl2uqaVtz032rPk7vcsCxqXxf73nkJdc0I2222yRzXqn2TbSbQNb1L0a5lkL0ir8HkqR66NATLrdeVF00YMXNU/+8nz/jhj7tId163/OulfRNcz6fW7H92R+tsLExWanWPWTNUG7LK2PtuNyqPv9q+FoLpR3qYT+zpTjmx65H/HKFMdvYBQcAAKgcv0oASMRLwQDizzM9dBwgASMHQKK5poeOA8TnoeMAzs8BnJ8DOD8HcH4OAID1ufU5gPU5QHpzTfe3A8Tn/nYAAKB+5Yql33kZSHM1++33LMWBPlu0aFH43Z1Pe7GmmrbJ594Slhg+rurj9M0zH6z493XBwoXh7Cvuc10z0LHTbgr5FbrNeaVaVohuWay7+7t2E2CxxX5YiAbniqUP/W2QJNW6Mdv+3JpRddGI0bum/nk/8vhz+rSP9NDTr7tW0jd98MfPKnae0trRZUxWqg1v3yCU2/LKWGcNLPr8q+HLFaND6mU/s+e/z7GuSdzGjLMDDgAAUDl+mQCQiJeCAcSfZ3roOEACRg6ARHNNDx0HiM9DxwGcnwM4Pwdwfg7g/BwAAOtz63MA63OA9Oaa7m8HiM/97QAAQP1qKUTPeBFI89Q2YpOwcOEiS3Ggz+586AUv1VRTt+NBp1V9nB621vgwf/6Cin9fyy+/45pmpGi7iea8Ui0rRK/16xz973YS4P/TWoxWyxVKX/gbIUmqZfkVusPx591m3aiat8H4g1P/vG//06P7tI/0wmvvuVbSN81+548V2Z+dO3ee8Vipt0QhCo/nB4RyW14Z6uGea75kMfIdUEOXK0RT6mc38/C/aylE17ou316/wphRdr8BAAAqxy8TABLxUjCA+PNMDx0HSMDIAZBorumh4wDxeeg4gPNzAOfnAM7PAZyfAwBgfW59DmB9DpDeXNP97QDxub8dAACoW9/JFaLPvQykeVq1a1fLcKDPnn7hLS/UVNO3UmnPqo/Th/7qzFS+s1fc/LhrmoGOOu3a0H/5cea8Uq1e/FmM5rZ0RiNsI8Cfy3V0bdpSjBb6WyFJqmU7/uw0a0fVvK32+nXqn/W1u/fq0z7Sex/Nca2kb3rx9fcrsj/7yZzPjMWqStcNWC6U2/LKWBsNXcfnX41dIbqknvYy853d/09LofSsa/NtZyJdK9r5BgAAqBy/TgBIxEvBAOLPMz10HCABIwdAormmh44DxOeh4wDOzwGcnwM4Pwdwfg4AgPW59TmA9TlAenNN97cDxOf+dgAAoD61tm/U4kUgzdWWu020DAf65P2P5oQzLr3HCzXV1E0684bQ2tFV9XH6saeer/h39sOPP3NNM9KorQ4y35Vq+QLJjmh3uwjw17V0lPbxt0KSVMtW2GhXa0fVvD0nnpP6Z33plTYLixYt6vVe0rz5C1wr6ZueefHtypyrfPixsVhV6bSBHaHcllfGOnLZET7/avRurre9zNywroG5YvSRa/PXax02dohdbwAAgMrxCwWARLwUDCD+PNNDxwESMHIAJJpreug4QHweOg7g/BzA+TmA83MA5+cAAFifW58DWJ8DpDfXdH87QHzubwcAAOpTv47Sql4E0lz97OjTLcOBXps3b0G48HcPeZmmmr6tf3pC1cfo1cfunsr39s4HX3BNM9BhJ14RWju6zHelGpUrRtPtIMC3aylGx/mbIUmqZUeeco01pGraz0+6siqf9Xfe+7BP+0nnXnW/6yX19Mizb1Rkj/bNt983DqsqHTRoxVBuyytj3ThgkM+/GrtC9FBd3jPX3rVuz3+3Ba7RX27x9tKP7HgDAABUjl8pACTipWAA8eeZHjoOkICRAyDRXNNDxwHi89BxAOfnAM7PAZyfAzg/BwDA+tz6HMD6HCC9uab72wHic387AABQn3LtpQleBNJcnX7+VZbhQK/9/p6yF2kqEy2//k5VH6NPmlb5s7V58xeEMy+71zXNQKuM3dtcV6pd5X9bJvrfdhAglu/kCtFv/N2QJNWqTXebZA2pmnb8ebdV5bP+wKPP9GlP6cpbnnC9pJ7ufezliuzTvvL6W8ZhVaXNh6wRym15ZbDlh23gO6CGLVeIXqzXzcyWjtI+rtFfrnVw9w9sdwMAAFSOXykAJOKlYADx55keOg6QgJEDINFc00PHAeLz0HEA5+cAzs8BnJ8DOD8HAMD63PocwPocIL25pvvbAeJzfzsAAFCfWoqlI7wIpLm67pZZluFArzz/yrteoqlMdMQpV1f/pWMdXeG12e9U/Hv79AtvuaYZaP9J081zpVpVKH2SGxotY/cA4hswYP1/zBVLt/kbIkmqRYNXHx9Onj7TWlI1beDKW6T+WZ9xza192lO67f7nXSuppzse+ENF9mmfe/E147Cq0krD1gvltrwy2G7LreI7oIYtV4w+qut75wqls12nP6+zc6e/t9sNAABQOX6pAJCIl4IBxJ9neug4QAJGDoBEc00PHQeIz0PHAZyfAzg/B3B+DuD8HAAA63PrcwDrc4D05prubweIz/3tAABAfcoVSxd6EUhz9eSzL1qGA4l9/sW8cPaV93mJpjLRZrtPqvr4PG77g1P57l5646OuaQZaYaNdzXOlWlWIPFgAeuEHK6z/z7lC9IS/I5KkWnTApIusJVXThm+4S+qf8+NOv6hPe0oPP/26ayX1dOPdz1Zkn/ar81ljsKrREsUoPNW2VCi35ZWxzh1Y8B1QAxctXKy7+7v1upfZ2bnT3+eK0R2u05+ejZQ+scsNAABQWX6tAJCIe3cB4s8zPXQcIAEjB0CiuaaHjgPE56HjAM7PAZyfAzg/B3B+DgCA9bn1OYD1OUB6c033twPE5/52AACgPrUUolleBtJcffzJHMtwILHrZz7jBZrKTEPXnlD18fmiK2+q+Pf2nfc/dT0z0J4TzzHHlWr30sjJdg2g9xZvL/0oVyi95e+JJKnabTD+EOtJ1bR1tzww9c/5Hocc36d9pRdfe9+1knq6+rYnK7JX+/ATZWOwqtbvlxoUym15ZaxH2gaEJYqR74AattbB3T+o573Mfp2j/z1XiF50rf7rfCR6zQ43AABAZfm1AkAiXgoGEH+e6aHjAAkYOQASzTU9dBwgPg8dB3B+DuD8HMD5OYDzcwAArM+tzwGszwHSm2u6vx0gPve3AwAA9amlWHrby0CapyFr/NgSHEjs6Rfe9vJMZaZDJl9W9fE5P6I7fPzJnIp/d2+7/3nXtMmbMn1maF9nW/NcqTYvjJw1eHD3P9g1gL7p19HV2fOdmuPviiSpmrWN2CQcf95t1pWqWd27HpP653zM1gf0aV/p/Y/muFZST5fe8GhF9mrvfegpY7Cq1pkDi6HcllcGW2/YKN8BNWz9O7uWqvt76Apj2+1l/me5QvSE3W0AAIDK8osFgES8FAwg/jzTQ8cBEjByACSaa3roOEB8HjoO4PwcwPk5gPNzAOfnAABYn1ufA1ifA6Q313R/O0B87m8HAADqz+LDRn2/pVha5GUgzdMGW+1rCQ4k8ulnX4azLr/XyzOVmbp2OLLq4/POBxxb8e/u3Hnzw9QZs1zTJm+HA081x5Vq09v9i1HOrgFURr/CmFJLIVrgb4skqZrteuhU60rVrB1/dlrqn/Gha47v097S/AULXSupp/OvfrAi+7V3zHrU+KuqdfCgkaHcllcGO3jQir4DathaC6OHN8JeZs9/143dS9dTIbrLzjYAAEBl+dUCQCJeCgYQf57poeMACRg5ABLNNT10HCA+Dx0HcH4O4PwcwPk5gPNzAACsz63PAazPAdKba7q/HSA+97cDAAD1p7WzNNSLW5qrXQ441hIcSOS3tz7pxZnKTCdPnxmWXe3HVR+fb7rzgYp/dx9/brZr2uSdeMHtYVANPq+SF0VGC/oVxoyyYwCV1fPd2tvfGElSNVt13N7WlqpZ+0+aXpXP+Sefftan/aVzr7rf9VLmO/OyWRXZr73+1lnGX1Wt8cutEcpteWWwy5Ye6jughq1fe9e6DbOXWSxNdFZSutquNgAAQGX51QJAIl4KBhB/numh4wAJGDkAEs01PXQcID4PHQdwfg7g/BzA+TmA83MAAKzPrc8BrM8B0ptrur8dID73twMAAPWnX3upy4tbmqujp/zGEhyI7Ynn3vTSTGWq/Y65sOpj85A1fhzmzZtf8e/vRdc97Jo2eVvtfZz5rVSbDrRbAOnIFUsn+RsjSapWrR1d4ZipN1hfqib98ozrqvI5f/LZF/u0v3TFzY+7Xsp8p158V1i0qO/7tZdde5vxV1Vr1WHrhXJbXhns6Z4GFsb4HqghyxWjzRtoK/M7LYXokmxfr9L5drQBAAAqyy8XABLxUjCA+PNMDx0HSMDIAZBorumh4wDxeeg4gPNzAOfnAM7PAZyfAwBgfW59DmB9DpDeXNP97QDxub8dAACoPy3F6Cde3NJcXXjF7y3BgVg+/ezLMHXGLC/NVKbacOtDqz42HzrpzIp/f2e/80fXs8k77pybw1IrbmZ+K1W7QunqnqXyd+wWQEq6u7/71ffM3xtJUrX68T7HW2OqJk2ZPjP0X35c6p/x626Z1ac9pt/fU3a9pJ7mzV/Q5z3b82fcYOxV1fpRMQpPt+VDWZls4yFr+h6oIcsVunZtpK3MxYeN+n5LMXo0u9crmmJDGwAAoLL8egEgES8FA4g/z/TQcYAEjBwAieaaHjoOEJ+HjgM4Pwdwfg7g/BzA+TkAANbn1ucA1ucA6c013d8OEJ/72wEAgPrTUiid4sUtzdXM+x6zBAdiuX7mM16WqUx14gW3h/zITas+Nj/65PMV//7e5IXHTd/GOx9lbitVvejl1sHdP7BTAOlqHdn9vVyhdK+/OZKkatS+znbWmKpZQ9aakPpnfOoFv+3THtOsx152raSePvtibp/3bE8770pjr6raLUsNCuW2vDLY0csO9x1QY1YoHdxoe5n9Okcv0fPf/e2MXrOJdrMBAAAqy68XABLxUjCA+PNMDx0HSMDIAZBorumh4wDxeeg4gPNzAOfnAM7PAZyfAwBgfW59DmB9DpDeXNP97QDxub8dAACoP7lidJ0XtzRXr7z+liU48K1effNDL8pU5tpz4jlVH5dXG7tbxb+/X3w5L5x+6T2uaRN3zNTrw5LDNza3lapYrhB9nmsvFewSQHUs0Tm2X64Yve7vjySpGh16/GXWmqpJq4zdO/XP989/Pa1P+0xP/uEt10rq6aNPPu/zvu3kMy427qqqTRtYCOW2vDLYjQMG+Q6oQYuOa8S9zH7tY1bOFUtfZvB6/cRONgAAQGX5BQNAIl4KBhB/numh4wAJGDkAEs01PXQcID4PHQdwfg7g/BzA+TmA83MAAKzPrc8BrM8B0ptrur8dID73twMAAPWnpVgqe2lL87RE59g5Gw3LAAAgAElEQVQwf/4CS3Dgb5q/YGH4zTUPelGmMtdam+1X9bH5pGmVP0t7+JnXXc8mb8OtDzW3lapcrhhtZ4cAqis3LCr2fP/m+BskSUq70g5HWGuqJo3Z9uepf763/+kxfdpneuXND10rqad3P/y0z/u2Rx5/jnFXVe3ny44M5ba8MlqhsKHvgRqvQunshr2/rhBtnblzk/bSBLvYAAAAleVXDACJeCkYQPx5poeOAyRg5ABINNf00HGA+Dx0HMD5OYDzcwDn5wDOzwEAsD63PgewPgdIb67p/naA+NzfDgAA1JvD/y5XLH3pxS3N08iNdrT8Br7VvY+97CWZylyTz701LLn8xlUdl1s7usJrs9+p+Hf4wmsf+u//XSdPnxmOO/vmcNTpvwuHnHB52O+YC8Meh08LOxx4avjxPseHTXY5Ooye8POwzhYHhjU33Tes3LXX13VusHNYfv2dQvs624bl1tg6DFrtx2GpFTf7uq/+e/+l/z3/9f/+/2/plTb/+v/GV/+3vvq/OXLM7l//Z6y12X5f/+dutM1hobTdEV//d/nqv9OOB50W9px4Tth/0vRw2IlXhKPPuC5MPu9Wn9NvOuKU34b+nWPNbaVqvhiyGJ1lfwBqo6UQdfd8Dxf5WyRJSrOlV948TLnwTmtOVb2v9kHS/nyvv8VP+7TP9MEfP3OtpJ5mv/txn/dtDzzqNOOuqto2y60Wym15ZbRtl1vd90CNtxdfKF3ZyHuZPf/9j8/S9WrtiMbawQYAAKgsv2IASMRLwQDizzM9dBwgASMHQKK5poeOA8TnoeMAzs8BnJ8DOD8HcH4OAID1ufU5gPU5QHpzTfe3A8Tn/nYAAKC+5JYv9ffSluZq050Os/wG/qaPPvk8nH7JPV6Sqcy108GnV31cHrfdz3r9XZ07d154bfY74YFHnwnX3HR3mDb9mvCLE84N2/10Uhg5ZvcwdO0JIT9y06aax/TvHBsGrrxFaF9nu7BSac+w7lYHhXE7HxW22ffEsOthZ4UDj704HHHK1eGE829r6s/qWpvtZ14rVbNC6eElV1/9f9ohgBruTxWiw/09kiSl3V5Hnmt/RFVvz4nnpP7ZHrrm+D7tF8+bv8C1knp6ZfaHfT5/2eOQ4425qmprDVs3lNvyymgnL9Ppe6CGK1eMbm/ojczu7u/mCtGNmblm7aU17F4DAABUll8yACTipWAA8eeZHjoOkICRAyDRXNNDxwHi89BxAOfnAM7PAZyfAzg/BwDA+tz6HMD6HCC9uab72wHic387AABQX1oLXat7aUtztd8RJ1t+A3/Tb2990gsylclW7tqr6uPy9Ct+/1e/i/PnLwgvvjI73DLzwXDmhVeHnx19eth6r1+EdTbdO7SvvbV5zbfUNmKT0D5q+7D6xj8Jpe2OCON/csLXL6o+5ITLw3Fn39ywn9ODJ88IrR1drrFUtRd4lj5cYvlxebsDUHPf6flOzvB3SZKUZmtttp/9EVW9w064oiqf788+/6JPe8bTrrjX9VLm+8Or7/X5/GX7nx5tzFVVG1gYHcpteWW0e5caGFp9D9Roe/KF0uONvpG5ZHvpX3r+t5Qzcb3aSwVb1wAAAJXllwwAiXgpGED8eaaHjgMkYOQASDTX9NBxgPg8dBzA+TmA83MA5+cAzs8BALA+tz4HsD4HSG+u6f52gPjc3w4AANSXXDHa1ktbmqsp0y6z/Ab+qvLL73g5pjLZpLNuDP07uqo6JudHdIcP//hJePWNt8Mdsx4N5156XTjs2LPCj/c4Iqwc7RKWXH6cuUuq//6bhuJ6O4R1Nj8gbLbbpLDrYWeFQ064PBx/3m11/VldqbSn6ydVr0W5jq7RdgagPvTrHP1PLYXoIX+bJElptcTwceG4c262T6KqNvncW6vy+X7+pdf7tG986Q2Pul7KfM+8+Hafz2A23+XnxlxVvXvzA0O5La+MtnL7er4HaqwK0WtNcb/d0GiZXDH6qNmv1+LtpR/ZuQYAAKgsv2YASMRLwQDizzM9dBwgASMHQKK5poeOA8TnoeMAzs8BnJ8DOD8HcH4OAID1ufU5gPU5QHpzTfe3A8Tn/nYAAKC+tBRKv/DSlubqqhtmWn4Df9HcefPDOVfd7+WYymTb7Hti1cfkJYePC20jNjE/qcMGrfbjsHLXXqG03RFhh4NODQdPnhFOOP+2mn9Of/rL37g+UhXLFaNf2hWAOtunGjq2NVeI3vQ3SpKUVjv+7DT7JKp6+ZGbpv7Zvv2eh/u0d3z9Xc+4Vsp8j5Vn9/kcZszWBxhvVfVmLD00lNvyymh7DVrZ90ANVvRps+xltnaU1mspRAua+Xot2V76F7vWAAAAleUXDQCJeCkYQPx5poeOAyRg5ABINNf00HGA+Dx0HMD5OYDzcwDn5wDOzwEAsD63PgewPgdIb67p/naA+NzfDgAA1JdcMZruhS3N1SNPPmf5DfxFdzz4ghdjKrMtv+HO5gn6m7V2dIUha00Ia2++f9hiz2PD3keeG46Zen3VPqMnT58ZOtbb0bWQqlUhumWx7u7v2hWA+tPa3rVCrlD6wt8qSVIarTpub/skqnrFdXdI/bN94RW/79Pe8V0Pv+RaKfM9+NRrfT6HWbt7L+Otqt4Jy3SGclteGe28pdt9D9RwdXbu9PfNspfZ0lHap3mvVbRwscUO/zs71gAAAJXlFw0AiXgpGED8eaaHjgMkYOQASDTX9NBxgPg8dBzA+TmA83MA5+cAzs8BALA+tz4HsD4HSG+u6f52gPjc3w4AANSXXKF0nxe2NFcffPSx5TfwZz7442fhtIvv9mJMZbLDp1xljqBet8yqW4U1N903bLXXr8P+k6aHyefdksrndLdDz/TvLVWpXDF6ffFhY//DjgDUr9ZCacue7+sif7MkSZWuf+fYcOy0m+yXqKqtvslPUv9s/+qUC/u0f/xYebZrpcw367GX+3wWs+LonYy3qnr7DV4plNvyymiP5QeEHxUj3wU1VK2Du3/QTHuZLYXS2c15llL60E41AABA5flVA0AiXgoGEH+e6aHjAAkYOQASzTU9dBwgPg8dB3B+DuD8HMD5OYDzcwAArM+tzwGszwHSm2u6vx0gPve3AwAA9aWlGL3rhS3N07KrbmHpDfxFV9/2pJdiKjOdPH1mOPSEy8Pmex4blt9w59Da0WWeoMq96K/n89S+znZhowmHhV0OmRp+ecZ1ff7MTrngjrDcGlv795Wq8RLIQjQvVyitZDcA6l+uGP3S3y1JUhptf8DJ9k9U1cZs+/PUP9d7HXpCn/aPX3z9fddKme/Oh17o81nMsLXGG2tV9TZbbs1Qbssrw20wdB3fBTXWPv3ypf7NtI85eHD3P/T877q7Ca/VS3apAQAAKs+vGgAS8VIwgPjzTA8dB0jAyAGQaK7poeMA8XnoOIDzcwDn5wDOzwGcnwMAYH1ufQ5gfQ6Q3lzT/e0A8bm/HQAAqB//tkz0v72spbnaYMufWnoDf8YLUZWFTjj/trDXEeeGDbc5NCyz6lbmBapqg1b7cVh3q4PCDgeeGo46/XeJP78T9j/Jv6NUrQrR3nYDoFEc/nctxegqf7skSZVuxdIe9lJU1bba69epf67HbX9wn/aQ3/3wU9dKme+We5/r83nMUiO7jbWqeiu3rxfKbXlluIMGrei7oIaqX+foZZttJ/M/hoxZvKVQerXJrtUj9qgBAAAqzy8bABLxUjCA+PNMDx0HSMDIAZBorumh4wDxeeg4gPNzAOfnAM7PAZyfAwBgfW59DmB9DpDeXNP97QDxub8dAACoHy2Fse1e1tJc7XLAsZbewP9lwcJF4cJrH/JCTDVlk868IUzY/6Sw6ri9wxLDx5kLqG4astaEEG13eNjryHPD5PNu/Zuf4+PPuy0MXGVL/25SNSpEl9gJgMbyfwZ3/69cMXrM3zBJUiVr7egKk8660d6Kqtauh05N/XM9cqMd+7SP/MXc+a6VMt8Ndz3bx/OYhV+PMcZaVbsfFaPwdH6pUG7LK6NNX3qY74Iaqn4dXZ3NuJeZay8Vev73zWmW65Qrlm6zQw0AAFB5ft0AkIiXggHEn2d66DhAAkYOgERzTQ8dB4jPQ8cBnJ8DOD8HcH4O4PwcAADrc+tzAOtzgPTmmu5vB4jP/e0AAED9aCmOGedlLc3VpFMusPQG/i+PPPO6l2GqqTr27JvCzoecEVbf+Cehf+dY47/qvv4dXWHE6N3ChH1PDMdMveHPPtOb7f4r/05SVYqe+8EK6/+znQBoPD8sjluy53v8tr9jkqRKNmHfk+yzqGodeOzFqX+mlxw+LixYuLBPe8lTL5vleinTXX3bk336Dn3y6WfGWNWsO5ZaNpTb8spoj+cHhCWLke+CGqbWYrRak9+Lt6gZrlOuEF1udxoAAKDy/LoBIBEvBQOIP8/00HGABIwcAInmmh46DhCfh44DOD8HcH4O4PwcwPk5AADW59bnANbnAOnNNd3fDhCf+9sBAID6kSuU9vWylubq4t/ebOkN/LfPv5wXzrzsXi/DVMM36cwbwrb7TQkjx+weWju6jPlq3JcE9nx+h2+4a5iw/0nh2LNvCsdOuynkR2zq30ZKvzk/LESD7QJA4+rXPmblXLH0pb9nkqRKNWL0rvZcVLWOOv26qnyuZ7/9Xp/2ky+67mHXS5nu8pse79N36O13PzDGqmZduHR7KLflleFGDR3lu6DGqVDasJn3Mnv+N05skut0tp1pAACAyvMLB4BEvBQMIP4800PHARIwcgAkmmt66DhAfB46DuD8HMD5OYDzcwDn5wAAWJ9bnwNYnwOkN9d0fztAfO5vBwAA6kdLMTrNy1qaq3sfesrSG/hvtz/wBy/CVMN27LSbwrb7TQkjR+8WWju6jPNquvp3jg1D1prg30KqQq3t0VZ2AKDx5QpjtvE3TZJUsTliR1c4+ozr7MGoKk258M7Qvwr7Ww88+kyf9pOvveMp10uZ7uLrH+nTd+jFV2YbY1WzJi07PJTb8spw+w1eyXdBjVMhavYH+X4nVyxd1vjXqTTZrjQAAEDl+YUDQCJeCgYQf57poeMACRg5ABLNNT10HCA+Dx0HcH4O4PwcwPk5gPNzAACsz63PAazPAdKba7q/HSA+97cDAAD1I1eIbvSylubqrXfet/QGvvbBHz8Lp118txdhqrFeMDx9ZtjvmAvD2psfEPovP87YLkmqQNGpVv/QPHq+07/2d02SVKnG73O8/RhVrWVX2yr1z/RVN8zs057yHQ++4Fop0/3mmgf79B164tkXjK+qWXsMXiWU2/LKcBcMHOa7oIYp116a0Oz7mK0ju7+XK5QebOjrVIwOtSMNAABQeX7lAJCIl4IBxJ9neug4QAJGDoBEc00PHQeIz0PHAZyfAzg/B3B+DuD8HAAA63PrcwDrc4D05prubweIz/3tAABA/cgVS897WUvztNTI7rBo0SJLb+BrV9/2pJdgqmE69ITLQ2mHI8LSK21uTJckVe6Fj4XSgwMGrP+PVv/QRLq7v5srln7nb5wkqRJ1brCzfRlVrRGjd039M33KOZf3aU/54adfd62U6c6+4r4+fYfufegp46tqVteQtUO5La8M92jbgLCE74IapH7FMXtkYSuzX+foJXr+977tOgEAAPCn/MoBIBEvBQOIP8/00HGABIwcAInmmh46DhCfh44DOD8HcH4O4PwcwPk5AADW59bnANbnAOnNNd3fDhCf+9sBAIA68fVLiKO5XtbSPK25yZ6W3cDXXnrjAy/AVN33q7NuDFv/9IRQGLW9cVySVPFyxdKHi7eXfmTxD81nyfbSv+QKpT/4WydJqkS/OO0a+zSqSqO2ODD1z/Ohk87s077y86+861op0029bFafvkM33n6fsVU1a/lhG4RyW14Zb61h6/o+qFE6MCt7mf3ax6ycK5a+bMTr1FoobWk3GgAAoPL80gEgES8FA4g/z/TQcYAEjBwAieaaHjoOEJ+HjgM4Pwdwfg7g/BzA+TkAANbn1ucA1ucA6c013d8OEJ/72wEAgPrw1cvFvaSludruJ0dbdgNhwcJF4cJrH/ICTNVt+0+aHtbefP/Qv3Os8VuSlFaLch1do638oXm1dpaG9nzX5/h7J0nqa1vudZz9GlWljXc+KvXP8077/6pPe8tvvfeJa6VMd/ol9/TpO3Tp1bcaW1Wz+hej8ER+qVBuyyvD/WTwSr4PaowKpV9kaS8zV4y2a8Tr1K+9a1070QAAAJXn1w4AiXgpGED8eaaHjgMkYOQASDTX9NBxgPg8dBzA+TmA83MA5+cAzs8BALA+tz4HsD4HSG+u6f52gPjc3w4AANSHXCFax4tamqsjJp9j2Q2Ex8qzvfxSddfk824N2+5/cmgftb0xW5KUerli6Rirfmh+rYXSlv7mSZL6WnHdHezdqCptu9+U1D/PpQkH9mlvec7nc10rZb6+OGv6NcZW1bQbBwwK5ba8Mtx5Awu+C2qMPfxC6fgM3qd3QqNdp36dozvsQgMAAFSeXzsAJOKlYADx55keOg6QgJEDINFc00PHAeLz0HEA5+cAzs8BnJ8DOD8HAMD63PocwPocIL25pvvbAeJzfzsAAFAfcsVoFy9qaa7On3GDZTdk3Lx5C8LZV97nxZeqm4485Zqw8c6/DEutuJmxWpJUnZdxFqPbF1t99f9h1Q9Z2d8qneRvnySpr008+bf2cZR6ex15buqf5fyI7vDFl3N7vb+8aNGicOrFrpWy3YKFi3r9HTru9IuMq6pp0wYWQrktrwz3cH7psEQh8n1Q/e/jF6KpmdvI7O7+bq5Y+l0jXad+naOXsAMNAABQeX7xAJCIl4IBxJ9neug4QAJGDoBEc00PHQeIz0PHAZyfAzg/B3B+DuD8HAAA63PrcwDrc4D05prubweIz/3tAABAfWgpRr/2opbm6o5Zj1p2Q8bd9/grXnqpmjdl+syw5xFnh5VKe4bWji5jtCSpmi/ifHPJ4Rv+0IofsqOzc6e/bylEd/kbKEnqS5vv8St7Okq9w064oiqf57sfeLxPe8zTLr/X9VKmmzdvQa+/P4cde5ZxVTVt4qARodyWV8ZbY9h6vg+q/738YjQ9i3uZS7aX/qXnf3+5Ua7T4sNGfd8ONAAAQOX5xQNAIl4KBhB/numh4wAJGDkAEs01PXQcID4PHQdwfg7g/BzA+TmA83MAAKzPrc8BrM8B0ptrur8dID73twMAAPWhpRhd5UUtzdUrr79l2Q0Z9tnnc8PUGbO89FI168Tf3B62O+CUsNwaWxuXJUnVr1Ca31roWt1qH7Jnic6x/XKF6E1/CyVJvW3Y2tvZ21HqHXf2zVX5PP/ihHP7tM98yfWPuF7KdF98Oa/X35+9DzvRuKqatuNyq4ZyW14Zb69BK/s+qBH6bVb3MnNDo2Vyxeijer9GuUL0uZ1nAACAdPjVA0AiXgoGEH+e6aHjAAkYOQASzTU9dBwgPg8dB3B+DuD8HMD5OYDzcwAArM+tzwGszwHSm2u6vx0gPve3AwAA9SFXjJ70kpbmacnlx4X58xdYdkOG3f7AH7zwUjVp8nm3hAn7nhiWWXUrY7IkqWb1K5YOsNKHLO9zda2YK0Zz/T2UJPW2I075rX0epd4yq2yZ+md56Jrjw9y58+wzS71szudze/39mbD3UcZU1bQNhq4Tym15ZbxpAwu+D2qEbs7yXma/wphRLYXS/Lq+RoXoNbvOAAAA6fCrB4BEvBQMIP4800PHARIwcgAkmmt66DhAfB46DuD8HMD5OYDzcwDn5wAAWJ9bnwNYnwOkN9d0fztAfO5vBwAA6sJ3Wgqlz7ykpXlaOdrFkhsy7KNPPg+nXXK3F16qqv3qrBvD5nv8KuRHbmosliTV+uWO1361zrXUh2zr+Vuwt7+JkqTettVev7bfo9RbZezeVfk8X3vT3b3eay6//I5rpUz38adf9Pr7M3bbg4ypqmlD2jcK5ba8Mt6D+YGhfzHynVC97+nPyvxeZjH6SZ1fp0fsOAMAAKTDLx8AEvFSMID480wPHQdIwMgBkGiu6aHjAPF56DiA83MA5+cAzs8BnJ8DAGB9bn0OYH0OkN5c0/3tAPG5vx0AAKi91vaNWrykpbnacreJltyQYTfc9ayXXapqTTz56rDB+ENC/+XHGYMlSfXQS0sM3ehfrfSBr7QUo4v8XZQk9ablN9zZvo9Sb9zOR1Xl89y17UG93mv+7Iu54dSL73a9lNk+/PjzXn9/1u7ey5iqmvdwfulQbssr460ybD3fB9V1uUL0hJ3MxRZrKZTOqePrdLMrBAAAkA6/fABIxEvBAOLPMz10HCABIwdAormmh44DxOeh4wDOzwGcnwM4Pwdwfg4AgPW59TmA9TlAenNN97cDxOf+dgAAoPZaC12re0lLc3XIMVMtuSGj3n7/Ey+6VFU64pSrwzpbHBhaO7qMvZKkOnnxZumLfh1dnVb5wH9ZfNio73/1Ul5/IyVJSftqv+OYqdfbA1Kq7Xro1Kp9pm+7++Fe7zlfc/tTrpcy23sfzen1d2f4+tsbU1XzrhmwXCi35ZXxdh+8iu+D6nxvP3rRTuZiiw0YsP4/9vx73F2X16kQXeIKAQAApMOvHwAS8VIwgPjzTA8dB0jAyAGQaK7poeMA8XnoOIDzcwDn5wDOzwGcnwMAYH1ufQ5gfQ6Q3lzT/e0A8bm/HQAAqL3WQmkHL2lprs688GpLbsio3976pBddKtWOPuO6sNE2h4X+nWONuZKk+qqjaycrfODP9r2KYwbkitFH/k5KkpK27f4n2wtSqk0668bQ2tFVlc/zBlv+NCxatKhXe87Pvfyu66XM9s77n/b6vGbplTYznqrmTR1YDOW2vDLeGct0+D6o3nvbLuZ/6tc5+t97/j1eqrtrVCid7OoAAACkw68fABLxUjCA+PNMDx0HSMDIAZBorumh4wDxeeg4gPNzAOfnALWfZ25i2ABINteUJEmSUmiyqTZAfHZ2AdzfDpAS97cDAAC1lyuWjvGClubqpjsfsOSGDHpl9gdecqn0XvJ75g0h2u7w0H/5ccZaSVLdlStEF1jdA3997yuKev5WLPL3UpKUpFXG7m1PSKlXXG+Hqn2mr7r+zl7tOy9YuDCce9X9rpcy2Zvvftyr7838BQtCa0eX8VQ1b+KgEaHcllfGm7nUMr4Pqvfm2MH8k73M9lLhq3+TOrtGE10ZAACAdPgFBEAiXgoGEH+e2W3YAIjPyAGQaK7poeMA8XnoOECyueZCQweA83OAFOaZ4wwbAAAAAEAjsbMLkOgs6BIjB0Bs7m8HAABqL1csXeYFLc3Vcy++ZskNGbNoUQiX3PCIl1yq4v36nJvCxjv/Miw5fGNjrCSpLssVoycXHzbq+1b3wN/SUigd5W+mJClJ/TvHhuPOudn+kFJt452PqtpnurDONuHjT+b0av/54Wded72UyV5/+6NefWfe//BjY6nqol0GrxrKbXkpFAob+k6onlu02GKH/50dzD/ZyyyOGffVv0u9XKN+xTF7uCoAAADp8CsIgES8FAwg/jyz27ABEJ+RAyDRXHOGkQMgNg8dB0g215xn6ABwfg6QwjyzZNgAAAAAABqJnV2ARGdB040cALG5vx0AAKi9lmLpES9oaaYXfXaFL+fOteSGjCm//I4XXKqiTT7v1rDZ7pNCfoVu46skqX4rlD7p1zl6WSt74Ft1d3+3pRj93t9OSVKSdj10qn0ipdoBky6q6mf6kGOm9mr/ed68BeGsy+91zZS5Xnnzw159Z156dbZxVHVRaehaodyWl8KWQ9bwnVBd169z9D/ZwPyz+/km1s31KXRt4YoAAACkw68gABLxUjCA+PPMbsMGQHxGDoBEc80ZRg6A2Dx0HCDZXPMLQweA83OAFOaZow0bAAAAAEAjsbMLkOgs6DdGDoDY3N8OAADU3lcvIfeCluZp+PrbW25DxixYuCj85poHveBSFenk6TPDTgefHgausqVxVZJU9+WKpc2s6oG4csO7/q2lGL3s76ckKW5rb76//SKlvhc3aLUfV+0z3b+zKzzw6DO92od+9Nk3XDNlrpdef79X35fHnnreOKr6uHegfYNQbstL4ahlV/CdUF23xNCN/tXu5Z/5Tq4QXV4P16dfYcwolwMAACAdfgkBkIiXggHEn2d2GzYA4jNyACSaa84wcgDE5qHjAMnmmnMMHQDOzwFSmGduYNgAAAAAABqJnV2ARGdB5xo5AGJzfzsAAFBb/zFkzOJeztJcde90qOU2ZMxj5dlebqmKdMjky8IKG+1qPJUkNUS5Yukkq3ogqZbC2PaWQukzf0clSXFqG7FJOPGC2+0bKdW6dz26qp/rFUfvFD6Z81nifegFCxeFC699yDVTpnr+1fd6dW5zx6xHjaOqi5YoRuHp/FKh3JZXxrtq6SG+E6rrvrp/zc7ln2sd2f29lkL0UM3PY4ZFRVcDAAAgHX4JAZCIl4IBxJ9ndhs2AOIzcgAkmmvOMHIAxOah4wDJ5pofGzoAnJ8DpDDPXNewAQAAAAA0Eju7AInOgqYZOQBic387AABQW/3ax6zs5SzN1X5HnGy5DRkyb/6CcPaV93m5pfrU0WdcF0ZtcWBo7egylkqSGqJcoXTf4MHd/2BVD/RGrhht52+pJClu+xx1vv0jpdqRp1xT9X25fSf27izp5Tc+cM2Uqcovv9Or78q1N91tDFXddOdSy4ZyW14Z78m2pUJbIfKdUN3Wr3P0EnYt/7LF20s/ailG77o+AAAAzcmvIQAS8VIwgPjzzG7DBkB8Rg6ARHPNGUYOgNg8dBwg2VzzQ0MHgPNzgBTmmWsbNgAAAACARmJnFyDRWdBUIwdAbO5vBwAAaqulEG3t5SzN1SnnXG65DRny8NOve7Glet0J598WNtt9Ulhy+MbGUElS41SI3vcCR6DPe2LF6Fx/UyVJcdpw60PtIyn1Rozereqf7WtvurtXe3Esl1sAACAASURBVNLX3/WMa6bM9PQLb/Xqe3LhFb83hqpuumTpoaHclpfCusNG+U6ojvf9N1rajuVf11qMVssVonm1uj79Okf/k6sAAACQDr+GAEjES8EA4s8zuw0bAPEZOQASzTVnGDkAYvPQcYBkc813DR0Azs8BUphnrmHYAAAAAAAaiZ1dgERnQacaOQBic387AABQWy3F6EgvZ2muevsSRKDxzJ03P0y7/F4vtlSv2u3QM8Oyq21l7JQkNVjRwpZC1wZW80BfLT5s1Pd7/q487e+qJOnbGrjyFmHK9Jn2k5Rqexw+rQaf7c3Ccy+8mnhf+vMv54Wzr7jPdVMmevL5N3t1fnPqeVcaQ1U3Hb/M8qHclpfCPoNX8p1Q3dY6bOwQO5bfdo9faedaXJtcIfrcvz4AAEB6/CICIBEvBQOIP8/sNmwAxGfkAEg015xh5ACIzUPHAZLNNd8ydAA4PwdIYZ65imEDAAAAAGgkdnYBEp0FTTFyAMTm/nYAAKC2WorRRV7O0lw9+eyLltuQEfc/8aqXWipxR53+u7DK2L2NmZKkxqxQ+oWVPFAp/dvHLNfzt2WOv6+SpG/rwGMvtq+kVJsyfWYYstaEqn+2V+3aNXzy6WeJ96afe/ld102Z6LHy7F6d3xw95TfGT9VNBwxaMZTb8lI4a2DRd0J1W7/O0R12K2Pd53dq9c9lotf8ywMAAKTHLyIAEvFSMID488xuwwZAfEYOgERzzRlGDoDYPHQcINlc81VDB4Dzc4AU5pkjDBsAAAAAQCOxswuQ6CxospEDIDb3twMAALWVK5Ye8HKW5uqTOZ9ZbkMGfDl3fjjr8nu91FKxO3n6zLDDQaeGthGbGC8lSQ1Zz/r1tsW6u79rJQ9UdG+svTTB31hJ0rc1dsdf2F9S6n21d1eLz/eEvY8KCxcuSrxHfdM9ZddNTd9j5Td6dYaz78STjZ+qm8YPWT2U2/JSmLXUMr4Tqt86xoy0UxnD6qv/j1yhdGtVr02h9LB/eAAAgPT4VQRAIl4KBhB/ntlt2ACIz8gBkGiuOcPIARCbh44DJJtrlg0dAM7PAVKYZw4zbAAAAAAAjcTOLkCis6BfGDkAYnN/OwAAUFu5YvSBl7M0T8PWGm+pDRkx67GXvdBSsTvsxCtC5wY7GyslSQ1brlh6Y/FhY//DKh5IQ0sxOtffWknS32q5Nba2x6TUO/GC28PAVbasyWf8+KmXJN6jnjtvQbjgmgddOzV1jz77Rq/OcLbd55fGT9VN6wwdFcpteenrOto38L1QXdZa6FrdLmU8/TpH/3vPv9lLVbw+N/tXBwAASI9fRQAk4qVgAPHnmd2GDYD4jBwAieaaM4wcALF56DhAsrnmI4YOAOfnACnMMwcYNgAAAACARmJnFyDRWdDBRg6A2NzfDgAA1E7r4O4feDFLcxVtc4ClNmTA51/OC1Mvm+WFlvr2F/H+5vawyS5Hh/6dY42TkqSGLVeI5vXr7FrFKh5Iy+LDRn2/5+/N0/7mSpL+Vj8/6Ur7TUq9CfufVJPPd//OrnDrXQ8l3qt+94NPw+mX3O3aqWl79Nk3enWO89WZrbFT9dKQwkah3JaXvm78cmv4Xqgu69feta5dygT3/HWWhrYUo0+rcn0KpYv9iwMAAKTHLyMAEvFSMID488xuwwZAfEYOgERzzRlGDoDYPHQcINlc825DB4Dzc4AU5pk5wwYAAAAA0Ejs7AIkOgvax8gBEJv72wEAgNppbe9awYtZmqs9DzneUhsy4K6HX/QyS31r+0+aHoasNcH4KElq+HKF0r5W8EDa+rePWa7nb84cf3clSX+trfb6tT0npd6UC++s2Z7e4NW3Ci+9OjvxfvUTz7/p2qlpe+TZN3p1jrNytIuxU3XVI20DQrktL4Vjlh3uO6H6PAcolsbYoUymX3upq6UYLUz9+hRKJ/vXBgAASI9fRgAk4qVgAPHnmd2GDYD4jBwAieaaM4wcALF56DhAsrnmTYYOAOfnACnMM//FsAEAAAAANBI7uwD/L3t3AiVVeSd+P/4zb+adzDvLOzP/OFRDsAtBRJaqbkEkRNxXqGqWEkVRXIlL3HdiJIqCKFExLO5LJGC7a1ziigT3fcG0+27c17iA0M8fmXd8h0Dk3u6u7lu3Pp9zvufMcmZOTlddfs99blU9sZ4F7WtyAETm8+0AAEDH6ZwrjnEwS7qaNnuuW21Iuc+/WBxmX36Pwyz1NzvjkjvDDrsfHzrXNZiNkqTKP0gzV7x6+e3rWu7ggfaQ6Vcc599eSdLfauDQ/e09qV068IQLOux9/pPCz8IHH30Se9/6zgee99oplT36zOstepbT86c7m51KVDet2ys01WalcP26G7gmlNRG2p1swX5mrnh8O7w2E/2lAQAAyse3IwBicSgYQPR1ZsnYAIjO5ACItdZsNDkAIvOj4wDx1prXGR0Anp8DlGGd+QNjAwAAAACoJHZ2AWI9C9rV5ACIzOfbAQCAjpPJFX7pUJZ0ddWNd7nVhpSb/9ALDrLU32zCtMbQe/NxZqIkKRVlcsXns/Wlf3H3DrSn5f/+XOzfYEnS6upSPzycfuFt9qBU9s6esyD0336/DnuvF3Y/Knz51eJY+9bLljWHq29/0uun1PXIM6/Hfo6zePESc1OJ6/weudBUm5XCotpuIZsb5rpQ4uqcK46xM9kiay3/+zWW87XplB92oD8zAABA+fh2BEAsDgUDiL7OLBkbANGZHACx1pqNJgdAZH50HCDeWnOu0QHg+TlAmdaaXxsdAAAAAEClsKsLEOs50EiTAyAyn28HAAA6TiZXuNTBLOnqkSeb3GpDin36ly/DrHkLHWSp1R60O+7wM0OXDUeYh5KkVJTJFb/sVD+0zp070N7W7rvVPy7/d6jJv8WSpNV1wAnn24tSu/SLX18RutQ1dNh7fdzBk8LSZcti7V9//sXicMl1D3r9lKoeWfR67Gc5b739vpmpxHVSzwGhqTYrrWi7Plu6LpTExtqZbJnOA0v/kMkVHyrba5Mr+KFlAACAMvINCYBY7FUBRF9nlowNgOhMDoBYa81GkwMgMj86DhBvrXmB0QHg+TlAmdaanxodAAAAAEClsKsLEOs50HYmB0BkPt8OAAB0nJpc4V6HsqSr9z/8xK02pNgd9z/nEEut0smzbwwDhx1gDkqSUlWnXHEvd+1AR+lUP7Quky9+5d9jSdJft93Y4+xHqd0q7vmrDn2/Tzw9/m9Qfvzpl+GCq+/3+ik1PbLo9djXwVN/etHMVOI6oNfg0FSblVZ0+PqDXBdKXJl8YQ+7kq3az/xxTb7wTjlem875wib+wgAAAOXjGxIAsTgUDCD6OrNkbABEZ3IAxFprNpocAJH50XGAeGvNs40OAM/PAcq01vyz0QEAAAAAVAq7ugCxngNtYnIARObz7QAAQMcp12Ea6ph6Dt7ZbTak2EeffhFmzl3oEEut1IEnnB+6bTzaHJQkpezwzOJl7tiBjpbJFw7zb7Ik6a/r8ZOdw9lzFtiXUrs07eLbQ89Ndu3Q9/z5c66PvZf99vufhnMa7/UaKhU9vOj12NfA/HsfMzOVuEb22Tw01WalFZ3bI++6UPLqV9jHjmQr9zNzxUGZfPGrNn9m07ehh78uAABA+fiWBEAsDgUDiL7OLBkbANGZHACx1pqNJgdAZH50HCDeWnOS0QHg+TlAmdaazxodAAAAAEClsKsLEOs5UM7kAIjM59sBAICO8W8Dtv1nh7Kkq213PsxtNqTYrfc0OcBS//+BuhfdEbbe5RjzT5KUujK5wpOd6of+0F07kABr1eQK1/u3WZL0100440r7U2q3Djzhgg59v3epbwg33XFv7P3sV978IMycu9BrqIrv4adfi/3+v/rG+ealEtegvtuEptqstKL53Xq6LpS8ZwP5ws9sR7Zepl9xXFu/Ntn60r/4ywIAAJSPb0kAxOJQMIDo68ySsQEQnckBEGut2WhyAETmR8cB4q01jzA6ADw/ByjTWvMBowMAAAAAqBR2dQFiPQfqanIARObz7QAAQMfoVD+0zqEs6Wr8UVPdZkNKffDx52HGXIdX6r869vTLw/qb7Gr2SZLSV674SaZvQw937EBSrN13+I8yucJb/o2WJP3Pdvr5VHtUatc23/HIDn3PdxtYCg889kzsfe1FL/zZ66eK76GnX4v93j9vzvXmpRJXba4QnqntFppqs9KKNsjt4NpQouqUH3ag3ci2kckVprfV65LJF79a/v9yLX9VAACA8vFNCYBYHAoGEH2dWTI2AKIzOQBirTUbTQ6AyPzoOEC8tebeRgeA5+cAZVpr3mJ0AAAAAACVwq4uQKznQP9icgBE5vPtAABAx8jUNezoUJZ0Nfns37rNhpT6wz1NDq/UivY+ZkbosuEIc0+SlM5yhVHu1oGkqelX3HT5v09L/TstSfrvBuywn30qtWtTL7g19Bg8pkPf9z1/unN4uuml2HvbDz71qtdQFd1DT78W+33/zTNb81JJbGG3HqGpNiutqKH3Fq4LJau64iF2ItvIkCF/V5Mr3N42z22Kr/qDAgAAlJdvSgDE4lAwgOjrzJKxARCdyQEQa63ZaHIAROZHxwHirTVHGR0Anp8DlGmtOc/oAAAAAAAqhV1dgFjPgdZa3lLTAyASn28HAAA6Rk1u2LEOZUlXv7v6VrfZkEIfffJFmDF3ocMrq7wzLrkzbLPrseadJCm1ZXKFM9ypA0mVyRcn+7dakvTfdalrCFMvuNWeldq1QyZd0uHv/bqt9wivvvF27D3u+Q8+7zVUxfbQU6/Ffs8fedIM81KJrLF7n9BUm5VWdNT6G7sulLBnBMXD7UK24X5m/4Z/z+QKL7TB6/KQvyYAAEB5+bYEQCwOBQOIvs4sGRsA0ZkcALHWmo0mB0BkfnQcIN5acwujA8Dzc4AyrTVnGx0AAAAAQKWwqwsQ+1nQh6YHQCQ+3w4AAHSMmlzxQoeypKt7H3rKbTak0G33PuvgyirvlNk3hvrtxpt1kqQ0H5Z5f69epR+4UwcSa8iQv6vJFe71b7Yk6b/b/xfn2rdSu7f97r/o8Pf+oGHjw7vvx/+M+PwHn/caqiJ78KlXY7/f9zz0FLNSiezs9epDU21WWtH5PXKuCyWto21Ctq1O9UN7ZnKFj1v1uuQKN/hLAgAAlJdvSwDE4lAwgOjrzJKxARCdyQEQa63ZaHIAROZHxwHirTXrjQ4Az88ByrTWnGx0AAAAAACVwq4uQOxnQS+aHgCR+Hw7AADQMWryxYUOZElXb779nttsSJmPPv0izJi70MGVVdwhJ10Sum082pyTJKW4wrs1fYZ3dpcOJN2PNxyRrckVP/XvtiTpm7be5Vh7V2r3fn3xnaHvFnt0+Pt/250PC5/+5fNYe93NzSHcfv9zXkdVXA8+9WrsZzsNexxjViqRHb/+wNBUm5VWtKDbeq4LJapMvjDBDmTbW/53LdTkC8ta/Nrkihf4KwIAAJSXb0wAxOJQMIDo68ySsQEQnckBEGut2WhyAETmR8cB4q01uxkdAJ6fA5RprXmM0QEAAAAAVAq7ugCxnwU9YnoAROLz7QAAQMdYcXC5Q1lSU3ajUli2rNltNqTM7fc969DKKu3sOQvCrodMC53rGsw5SVKKKyzrXFfcxh06UCky/Yrj/NstSfqm7oN2CtPnLLCPpXbvhLOuCesMGNXh18CofSaErxYvjr3nfdeDz3sdVVE9+NSrsd/ng4v7mZVKZON7/TQ01Walb+vdbwfXhhJTJlf4pd3HMu1p5gsTWvy65Asn+wsCAACUl29MAMTiUDCA6OvMkrEBEJ3JARBrrdlocgBE5kfHAeKtNf/N6ADw/BygTGvN8UYHAAAAAFAp7OoCxH4WdIfpARCJz7cDAADtL1tf+hcHsqSrzUYe6BYbUuaTz74MM+cudGhlFXb6BbeFn448xHyTJFVDE92hA5Vm+b9djf79liR907HTLreXpQ5pn2NmJuIa2OeIKWHpsmWx9r2bm0O4/b5nvY6qmB548tXYz3d6DdnFnFQiG95789BUm5W+bWSfzV0bSlCFE+08ls1aNbnCvBa9LrnCwf58AAAA5eVbEwCxOBQMIPo6s2RsAERncgDEWms2mhwAkfnRcYB4a83vL2+p8QHg+TmAZ+gAAAAAQDWzqwsQ+1nQFaYHQCQ+3w4AALS/zrmh/R3Gkq72OORkt9iQMnc+8JwDK6uwSbN+H/pusafZJklKf7nC7d8rlb7vDh2oNF37Ff+1Jld81b/lkqTRB0yxn6UOa9tdj0vEdXDUSTNi7303N4dw+33Peh1VET3w5Kux3t9ff700dK5rMCeVyAb12zY01Walbzt2/Y1dG0pMmXzhZDuPZfys4MDSP2TyxQfjvy7F0f56AAAA5eVbEwCxOBQMIPo604FgADGYHACx1pqNJgdAZH50HCD+evMd4wPA83OAMqwzNzE6AAAAAIBKYVcXIPazoN+YHgCR+Hw7AADQ/jrnimMcyJKuJp5+gVtsSJFP//JlmDlvoQMrq6xjp10euv9kJ3NNklQNh2O+3ql+6H+4OwcqVSZf3KImX1jm33RJqu7qtxtvT0sd1hmX3BlyW++ViGth6ow5sffAm5ubw233Puu1VOK7/4lXYr2333nvQzNSia17blhoqs1K33Zhj5xrQ8kpVzjVrmOZ9zQ3LHZZ/rd+O9br0q+wmb8cAABAefnmBEAsDgUDiL7OLBkbANGZHACx1pqNJgdAZH50HCD+evNJ4wPA83OAMqwz1zM6AAAAAIBKYVcXIPazoONND4BIfL4dAABofzX54kQHsqSriy6/0S02pMhdDz7vsMoq6+cTLwxd+4800yRJqS+TKyzJ5Bs2dmcOVP7+WuF0/65LUnXXua4hnHreLfa21GFNmnlD6DZodCKuhwvn/T72Pnhzc3O44/7nvJZKdPc/+Uqs9/WiZ182I5XoHs52D021WWlF93Xr4bpQcsoVTrXjWH6ZXHFQJl/8Kurr8p+5Qi9/NQAAgPLyzQmAWBwKBhB9nVkyNgCiMzkAYq01G00OgMj86DhA/PXmbcYHgOfnAGVYZ/6r0QEAAAAAVAq7ugCxnwXta3oAROLz7QAAQPvL5AtzHMiSrubf+6hbbEiJzz7/Ksyat9BhlVXUuMPPXHEIs3kmSaqSgzEPdlcOpMG662779zX5wmP+bZek6m7/X5xrf0sd2hGTLwtd6od3+LXwzf5m4/V3tGhP/J5HX/JaKrE99NRrsd7Pd93ziPmoRHfTur1CU21W+ra+/bZ3bSgpzw5OtePYPpb/rXeL+rr8uM8O/6+/GAAAQHn59gRALA4FA4i+ziwZGwDRmRwAsdaajSYHQGR+dBwg/nrzMuMDwPNzgDKtNb80PgAAAACASmBHFyD2c6Ci6QEQic+3AwAA7S+TKz7kQJZ09fJrb7nFhpSY/9ALDqqskqbPWRAKe040xyRJ1dS1y29J13JXDqTFf+YKvTK5whf+fZek6m373X5hn0sd3thDfp2I66Fr/xHhrnseadG++COLXvdaKpF9896MY+61t5mPSnQXd+8Xmmqz0reVem/m2lAyyhVOtdvYjp8dzBfPXNNrkskXFnumAwAAUH6+PQEQi0PBAKKvM0vGBkB0JgdArLVmo8kBEJkfHQeIv96cZnwAeH4OUKa15mvGBwAAAABQCezoAsR+DjTQ9ACIxOfbAQCA9pfJFT52IEt66rrhiPD110vdYkMKfPb5V2HWvHscVFkF/friO8MmIw81xyRJVVTh2X8bsO0/uyMH0qZzvvhz/8ZLUvW2/pCx9rqUiLbZ9dhEXBM9fjI6PPbUcy3aH3/qubfCjLleSyWrR//0Rqz38fTzrzAfleimrtc/NNVmpW87bv2Brg0lpal2GtvRkCF/t/xvfut3vSaZfPENfygAAIDy8w0KgFgcCgYQfZ1ZMjYAojM5AGKtNRtNDoDI/Og4QPz15lHGB4Dn5wBlWms+ZHwAAAAAAJXAji5A7OdAtaYHQCQ+3w4AALSvtfsO/5GDWNLVxkP3dXsNKXH3wy84pLIKmnLuzaFu233MMElS9ZQrfl6TH9bXHTmQUmvV5At/8O+9JFVvJ8243p6XOryzLp0fBg47IBHXRN/Nx4ZXXv9zi/bIn3vl3TBz3kKvqRLTE8++Ges9PGHyOWajEt0RvQaFptqs9G0Xd+/n2lBSmmqbsX117lX6t0yu+Px3PNt5xF8JAACg/HyDAiAWh4IBRF9nlowNgOhMDoBYa81GkwMgMj86DhB/vbm78QHg+TlAmdaavzc+AAAAAIBKYEcXIPZzoB+aHgCR+Hw7AADQvjrVNwx2EEu6GrP/CW6vIQU+/3JxmH35PQ6pTHknz74x9N5snPklSaqqMv2K49yNA2nWJV/IZPKFD/ybL0nV2V5H/8a+lxLRaRfeGvpskYy9x0HDxof3P/ykRXvlr7z5ob1yJaannnsr1vt3r8Mmm41KdLv1HhKaarPSt92f7eHaUDLKFU61y9gRnyMc2jOTK3y82mc7+cKN/kIAAADl51sUALE4FAwg+jqzZGwARGdyAMRaazaaHACR+dFxgPjrzW2NDwDPzwHKtNa8wPgAAAAAACqBHV2AFj0L+tQEAVgjn28HAADaVyZf2NNhLOnquMmz3V5DCvzxkRcdUJnyfvWb60LPTXYxuyRJVVUmXzzXnThQDTr3K+zi331Jqs622Okoe19KTJNm3hC6/2SnRFwbw/c4Jny1eHGL9svffPeTcN6V93lN1eEteuHPsd67Q8ceaTYq0W3XZ8vQVJuVViqX2971oSQ01Q5jB+1r1hW3qckVlq7ymuSKF/rrAAAAlJ9vUQDE4lAwgOjrzJKxARCdyQEQa63ZaHIAROZHxwHirzd7Gx8Anp8DlGmtOdH4AAAAAAAqgR1dgBY9C3rGBAFYI59vBwAA2lcmX5zsIJZ0dc5vr3V7DRXu8y+XhNmX3+OAyhR3wvRrQo/BY8wtSVKVVXis88DSP7gTB6po3+0K//ZLUvXVfdBO4ew5C+yBKTEdderc0HXDkYm4Pn521NSwbFlzi/bNP/j483DJtQ96TdWhPfPi27HetwO229tsVKKr77ddaKrNSis1ss/mrg8loal2FztOTa5wzF+/JplcYYq/DAAAQPn5JgVALA4FA4i+ziwZGwDRmRwAsdaajSYHQGR+dBwg/nrzn4wPAM/PAcq01tzL+AAAAAAAKoEdXYAWPQv6gwkCsEY+3w4AALSvTK5wpYNY0tUtd93v9hoq3L2Pv+xwyhT3izOuXHG4spklSaqqcsVPM30K67kLB6pJp/qh/5HJFf9sDkhS9XX8GVfZB1OiOvjEi0KX+uGJuD5OPvPiFu+df/7F4nD5zY95TdVhPfvyu5Hfr8uWNYeu/UeYi0p0P84XwqJst9BUm5W+7Yheg1wfSkJT7S528GcK84U5K70mdcVD/FUAAADKzzcpAGJxKBhA9HVmydgAiM7kAIi11mw0OQAi86PjAC1bc35ihAB4fg5QhnXm1sYHAAAAAFAJ7OgCtOhZ0PkmCMAa+Xw7AADQvjK5wpMOYklXz77wqttrqGCLl3wdzr3iPodTprQJ0xpDt0GjzStJUrXVXJMfNsIdOFCNOtcVt/mvfwfNA0mqpsYe8mt7YUpc4yfMDp3rGhJxjVx0+Y0t3kNf8vXScMP8RV5TdUjPv/pe5Pfqex98bCaqIlrYrUdoqs1K3zZzvbxrQ0loqp3FjtV1yJD/O5MvPPDfr8ny/3onfxUAAIDy820KgFgcCgYQfZ1ZMjYAojM5AGKtNRtNDoDI/Og4QMvWnE8ZIQCenwOUYZ25vvEBAAAAAFQCO7oALXoWdIIJArBGPt8OAAC0q7VqcsXPHcSSnr45DPHLrxa7vYYK9tBTrzmYMqUdOWVOqN1olHklSarCCqe7/Qaq2fJ/B883CySpuvrpiEPshymRjTnotERcI103HBFuvP3eFu+jNzc3h/kPPu81Vbv34mvvR36fLnr2ZTNRFdHV3XuHptqs9G23rLu+a0NJeK5wml3FBOxr9hneOZMrvPXNa5LJF7fwFwEAACg/36YAiMWhYADR15klYwMgOpMDINZas9HkAIjMj44DtGzNeZMRAuD5OUAZ1pn/aHwAAAAAAJXAji5Ai54F7WGCAKyRz7cDAADtp1P90B87hCVdDdhub7fWUMG+XrosXHDV/Q6mTGGHTbo0dO0/0qySJFVfucK99fX7/l/uwIFqtnbfrf4xkys+by5IUvW0zoBR4axL59sXUyIbvs+JibhOflw/PFx7y4JW7ak/3vSm11Tt2stvfBD5/XnHHx82E1URzVovH5pqs9K3LVpeba7g+lBHN9WuYjLU1A0bmMkXv/rPXKGXvwYAAED5+UYFQCwOBQOIvs4sGRsA0ZkcALHWmo0mB0BkfnQcoGVrztlGCIDn5wBlWmt+YIQAAAAAAElnNxegRc+BtjRBANbI59sBAID2U1M3bHOHsKSr0eOPd2sNFezxpjccSpnCDj7xotBlwxHmlCSpCiu807nfDjXuvgG+973OuYYhy/9dXGY2SFL1dPTUufbGlMjOnrMgbLXLMYm4Trr2HxFuvvO+Vu2rN730Tpg5b6HXVu3Sq299GPm9+btrbjMPVRGd2HOj0FSblVZq0z7buD7U0c8XTrOjmByZfsVxneqH/oe/BAAAQPn5RgVALA4FA4i+ziwZGwDRmRwAsdaajSYHQGR+dBygZWvOCUYIgOfnAGVaaz5uhAAAAAAASWc3F6BFz4F6mCAAa+Tz7QAAQPvJ5As/cwhLujr2lFluraFCLVvWHC659kGHUqasIyZfFn7cf4QZJUmqvnKFpZl8cQt33gD/cy+ueKYZIUnV0+gDptgfU2KbftndYfDwgxNxrXTtPyLcfOf9rdpff+WtD8Osefd4bVX2Xn/7o8jvyzPPu9w8VEV0YK/Boak2K63UXhts1ECriwAAIABJREFU4vpQB1c4zW4iAAAA1ci3KgBicSgYQPR1ZsnYAIjO5ACItdZsNDkAIvOj4wAtW3PuZoQAeH4OUKa15g1GCAAAAACQdHZzAVr0HOiHJgjAGvl8OwAA0H4yueKvHcKSrs697Dq31lChFr3wZwdSpqzjpjWG2o1GmU+SpKosky9McNcNsLJO9UN/mMkXnzMnJKk6Gjh0f3tkSnRnXHJn2Gj5+zQJ10vX/iPCzXfe36o99lfe/DDMmneP11Zl7c13Po78njzm5FnmoSqi0b03C021WWmlJvUc4PpQBz9jKE62mwgAAEA18q0KgFgcCgYQfZ1ZMjYAojM5AGKtNRtNDoDI/Og4QMvWnJsYIQCenwOUaa053QgBAAAAAJLObi5Ai58FvW2KAHwnn28HAADaT02ucIODWNLV7QsecmsNFai5uTlcdsPDDqRMUcefeVXIDtzRbJIkVelhl4Wbvve9E/6Xu26AVXXOFzapyReWmReSlP661A8P0y6+w16ZEt1pF94a+m25ZyKumXUGjAx/mP9Aq/baX3z9/TBz3kKvrcrWn9/7JPL7cc9DTzEPVRFt2meb0FSblVZqbvc+rg91bLniJDuJAAAAVCPfrACIxaFgANHXmSVjAyA6kwMg1lqz0eQAiMyPjgO0bM2ZMUIAPD8HKNNa82AjBAAAAABIOru5AC1+FrTQFAH4Tj7fDgAAtJ+afOFZB7Gkq5defdOtNVSg515512GUKeqkGdeHHoPHmEuSpCqt8G7X/tv/pztugL8tky+eZV5IUnV06KRL7Jcp8Z163i2h7xZ7JuKaWWfAyHDLXfe3ar/9xdfeDzPnLfTaqiy98/5nkd+L2+96hFmoimiD3A6hqTYrrdSD3bq7PtTRTbSLCAAAQDXyzQqAWBwKBhB9nVkyNgCiMzkAYq01G00OgMj86DhAy9acay3vL8YIgOfnAGVYa+5ghAAAAAAASWc3F6DFz4IuNkUAvpPPtwMAAO1kyJC/y+QKSxzCkp669h8Rvv56qVtrqECX3/yYwyhT0inn3BR6DRlrLkmSqrXmTF3DUDfcAN+tU/3QH2ZyxefNDUlKf8P3OcmemSqiyefcHDbYdLdEXDfrDBgZ/jD/gVbtub/42vth5ryFXlu1ee99GP33V+u32dMsVMX0RHbd0FSblVaqb7/tXR/qsDK54vF2EQEAAKhGvlkBEItDwQCirzNLxgZAdCYHQKy1ZqPJARCZHx0HaPm68wljBMDzc4AyrDPXM0IAAAAAgKSzmwvQ4mdBx5siAN/J59sBAID20Tk/bF2HsKSrnzbs57YaKtDLb3zgIMqUdOp5t4Tem48zkyRJ1Vuu+Bt32wAR9+ZyDUNq8oVl5ockpbu6bfexb6aKadKs34eem+ySiGundqNR4fYFD7Vq7/2F194LM+ct9NqqTfvg488jvf+WLWsOXTccYRaqYrq92/qhqTYrrVRD7y1cH+qwMvnCBDuIAAAAVCPfrgCIxaFgANHXmSVjAyA6kwMg1lqz0eQAiMyPjgO0fN15lTEC4Pk5QBnWmT9Y3lJjBAAAAABIMru5AC1+FrSzKQLwnXy+HQAAaB81uYbtHMKSrnY76CS31VCBrrz1cQdRpqDTL7gt5LbayzySJFVzizoPLP2Du22AOPtzxbPND0lKd13qGsK0i+6wf6aK6cTfXB96DB6TiOundqNR4c6Fj7Rq//35V98LM+cu9Nqqzfroky8ivffeff9Dc1AV1eXd+4Sm2qy0UoevP8j1oY7saLuHAAAAVCPfrgCIxaFgANHXmSVjAyA6kwMg1lqz0eQAiMyPjgO0fN15qjEC4Pk5QJnWmi8ZIwAAAABAktnJBWjxc6ANTRGA7+Tz7QAAQPuoqSse4gCWdDXx9AvcVkOFeePtjx1CmYLOuOTO0H/7n5lFkqSqLZMvLM70LeTdaQPEs3bfrf4xkyu8aJZIUro7bNKl9tBUUU2cfk3o/pOdEnH9dBtYCgsffKJV+/AvvPZemDl3oddWbdKnn38V6X331J9eNANVUc3sUReaarPSSs1Y/r5wfajDnjvkikfYPQQAAKAa+YYFQCwOBQOIvs4sGRsA0ZkcALHWmo0mB0BkfnQcoOXrzn2MEQDPzwHKtNb8gzECAAAAACSZnVyAFj8H+ldTBOA7+Xw7AADQPjK5wmyHsKSrS6+42W01VJjr7nzKIZQV3tlzFoTNdjzcHOrAutQ1hPU32TUMHHZA2HbX48JOB54axh83Kxw9dW6YcMaVK5o06/crmjCtMRx28qVhv1+cE8YdflYYvs9JYcioQ0PvzceFLvXD/T0lqaWHW/YrHOkuG6BlavoVN13+b2mzeSJJ6a203yn20VRxHX/mVaHboNGJuIa6L//P8eBjz7RqL/6F194LM+cu9Nqq1X351ZJI77lb737QDFRFdVLPjUJTbVZaqVu69XJ9qAMrHGrnEAAAgGrkGxYAsTgUDCD6OrNkbABEZ3IAxFprNpocAJH50XGAlq87NzNGADw/ByjTWnOGMQIAAAAAJJmdXIBWPQt6zyQB+Jt8vh0AAGgfmVzxbgewpKs/PvCE22qoIO988JkDKFPQyPGTzKB2qMfgMWHADvuFrcccveIg6r2PnhGOmHxZOGnm9WH6b+e3yWs5/bK7w8Szrw3jJ8wOhT0nhvrtxocu9cP9/SVpDS2/t7zje9874X+5ywZouZpccZaZIknpbeCwA+yjqSKbMK0xZAeWEnEd9Ry8c3j86edatSf/7CvvhhlzF3pt1aq+Xros0vvtwnm/NwNVUR3Sa1Boqs1KK7VoeevkC64RdUy5wkF2DQEAAKhGvmUBEItDwQCirzNLxgZAdCYHQKy1ZqPJARCZHx0HaPm6s8YYAfD8HKBMa82DjREAAAAAIMns5AK06lnQPSYJwN/k8+0AAED7qMkX3nEIS7p68+333FZDBblpwTMOoKzw9jl2pvnTRnXdcGTot9VeYdPS4WH4PieGPY6cHg6ddEmYePZ14cxL7+qw1/jM394VjjltXtjpwKlh4ND9Q5f64V4vSfofZfKFD2r6DO/sDhugdbL1pX/J5ItvmC2SlN59j7MunW8/TRXZMaddHmo3GpWIa2mDTXcJi559uVX78s+8+LbXVS1uxtw/Rn6vTTrzYjNQFdXY3kNCU21WWqUhfbd2jahjnj/kivvbNQQAAKAa+ZYFQCwOBQOIvs4sGRsA0ZkcALHWmo0mB0BkfnQcoHVrzw+NEgDPzwHKsM7cyhgBAAAAAJLMTi5Aq54FnWeSAPxNPt8OAACUX6Z/w787gCVdrbvxjqG5udltNVSIDz/5fMXhiw6hrNyOnDIndKkfbgbFKDtwx7DhtvuGLXc+OpT2OyXsc+zMcNSpc8Pkc24OZ89ZUBGv+7SL7wgHn3hRKO75q7DBpmO9rpKUK/gyPUBb7dfli8PMFklKb0efNs+emiq2o6fODesMGJWIa6nv5mPDsy++1qr9+UUvvO11VYs6p/HeyO+z/Y4+zfxTRbV9ny1DU21WWqXdN9jENaKOarwdQwAAAKqRb1oAxOJzzADR15klYwMgOpMDINZas9HkAIjMj44DtG7teY9RAuD5OUAZ1pk1xggAAAAAkGR2cgFa9SzoUJME4G/y+XYAAKD8OtU3DHb4SrracseD3VJDBbn9vmcdQFnB/eo314ZuG482f1ZTj8FjwsBhB4Ttxh4Xdv751LDf8eeFCdOuCKddeGsq3wu/OOPKUNpvcui35R5ef0lVWOEid9cAbasmV5xrvkhSOtvl4NPtq6miO+rUuWGdAaMScT3ltxoXXn7trVbt0T/2pze8rordBVfdH/k9Nmy3o8w/VVQD+20bmmqz0ir9sudA14g6pM654t52CwEAAKhGvmkBEItDwQCirzNLxgZAdCYHQKy1ZqPJARCZHx0HaN3a8zyjBMDzc4AyrTU/NEoAAAAAgKSyiwvQqudAW5skAH+Tz7cDAADlV9OvsI8DWNLVvkee6pYaKsRfvlgcZs1b6ADKCm3qBbeG3puNq+qZ8+P+I0Ju673C5qOPCKX9TgnjJ8wOE6ZdEaZddHtVvzcmnn1d2PnnU0PfLfawNpGU+jK5wov/vl7hn9xdA7SttfsO/1FNrvC+WSNJ6WvIqEPtraniO2rK78I6A0Yl4poasN3e4fW33m3VXv1DT73mdVWsLrnuocjvr/xW48w/VVQ9csNCU21WWqXz18u5RtQxzyHyhT3sFgIAAFCNfNsCIBaHggFEX2eWjA2A6EwOgFhrzUaTAyAyPzoO0Lq15yFGCYDn5wBlWmveY5QAAAAAAEllFxegVc+BakwSgL/J59sBAIDyq8kVpzmAJV1N+c1v3VJDhVj46EsOn6zQzrp0fhg47IDqOUBx8JiwcfHAsMPux4fdDjsjHDrpkjBp5g1h+pwF3g9r6Nhpl4fCnieEboNGW6dISmGFZZ3qGwa7swYo175dYTezRpLSV3bgjuFseypKQUdN+V1YZ8CoRFxXg4aND39+5/1W7dff98QrXldF7nc3PhLpfbV48ZLQpb7B/FPF9VjtuqGpNiut1K3rru/6UEc11k4hAAAA1ci3LQBicSgYQPR1ZsnYAIjO5ACItdZsNDkAIvOj4wCtW3tubZQAeH4OUKa15rlGCQAAAACQVHZxAVr9LOgj0wRgtXy+HQAAKL9MvnCTw1fS1eXX3eGWGirA4iVLw7lX3OfwyQrsm0OPt9n12NTNj851DWGDzXYPm+94ZBi13+QwfsLsMGHaFWHaRbd73dugsy6dH34+8cKw6ajDQpc6h6hKSkm5wqnuqgHKvHeXK9xi5khS+vrlmVfbL1EqOnLKnLDOgFGJuK6GDD8gvPfBx63at7/nsZe9ropU4y2PRXpPvfzaW+aeKrI7uvUMTbVZaaUW1XYLXfMF14javUy+ONouIQAAANXINy4AYnEoGED0dWbJ2ACIzuQAiLXWbDQ5ACLzo+MArVt71hglAJ6fA5RprXmIUQIAAAAAJJVdXIBWPwu61zQBWC2fbwcAAMqvJl942QEs6eqhx//klhoqwCOLXnfwZIW26yG/rvhZ0W3Q6LBx8cBQ2Gti2PvoGeG4aY3hjEvu9Pq2U6fMvjGU9jsl9Bg8xtpFUuUeYpkrPrHuutv+vbtqgPJau19xnZp84TOzR5LS1R5HTrdHotR05JQ5YZ0BoxJxbW035rDw2V++aNXe/fyHXvC6ao1dc/uTkd5PCx98wtxTRdbYvU9oqs1KqzSo7zauEbV7nfoVG+wSAgAAUI184wIgFoeCAURfZ5aMDYDoTA6AWGvNRpMDIDI/Og7Q+vXnh8YJgOfnAGVYZ25llAAAAAAASWUXF6DVz4LOM00AVsvn2wEAgPLqVD/0hzX5wjIHsKSr9z/8xC01JNzSZcvCRdc84ODJCuyoU+eGLvXDK2YmfPOfNb/13mGrXY4Jux4yLRw26dIw+ZybvZYJafpv54f9jj8vDBy6vzWMpIoqky8srskN7+euGqB91OQKB5s/kpSuttr5aHsjSlVHTpkT1hkwKhHX1877nRCWLPm6VXv4dz7wvNdV39kN85+O9F6ad93t5p4qslnr5UNTbVZapdG9N3ONqP3LFbe3QwgAAEA18q0LgFgcCgYQfZ1ZMjYAojM5AGKtNRtNDoDI/Og4QOvXnwuNEwDPzwHKsM7sZJQAAAAAAEllFxeg1c+CDjZNAFbL59sBAIDyyvQt5B2+kq56DdnF7TRUgEUvvO3QyQrs1PNuCesNHpPYGdBj+X+2n444JIwcPyns94tzwi/PujpMv+xur12F9M3rtd3Y40KXDUdY00iqgAMsC8e4owZoR6XS9zP5wgNmkCSlp56b7Go/RKnriMlzQtf+IxNxjR1w3LTQ3Nzc4j38b/5vb1n4J6+r/mY3//FPkd5L02bPNfdUkU3qOSA01WalVTpq/Y1dI2r3MvniFjYIAQAAqEa+dQEQi0PBAKKvM0vGBkB0JgdArLVmo8kBEJkfHQdo/frzbOMEwPNzgDKtNf9snAAAAAAASWQHF6DVz4E2MU0AVsvn2wEAgPLqnCuOcfhKuho69ki305Bw35zjOef3jzh0ssKaPmdB2Lh4YGL+ve8+aKfw0xGHhB33nxIO+tVFYfI5N3udUtKUc28OI8dPCtmBJWsbSUlt4fdKpe+7owZoX5m+hXxNrvi1OSRJ6WnSrN/bC1HqOurUuaHbxqMTcY39atqFrdrLX7psWbjmjie9rlptt933bKT30eETzzbzVJEd1usnoak2K63SjB51rhG1e53qGwbbHQQAAKAa+eYFQCwOBQOIvs4sGRsA0ZkcALHWmo0mB0BkfnQcoPXrzz2NEwDPzwHKtNa8yTgBAAAAAJLIDi5Aq58D/fPylpkoAKvw+XYAAKC8avKFEx2+kq5+PuHXbqch4V56/X0HTlZgo/ab3GH/tnftPzIMHHZAGDn+5PDziReGSbNu9JpUQdMuvj2MPfSMsP4mu1rjSEpQhc+61Dd0czcN0GF7eaebRZKUnsZPmG0PRKls4tnXhl5DxibiOpt1yTWt2s9fvGRpuPzmx7yuWqX5D70Q6T00evzxZp4qst032CQ01WalVbqhey/XiNq9zrmh/e0MAgAAUI188wIgFoeCAURfZ5aMDYDoTA6AWGvNRpMDIDI/Og7Q+vVnzjgB8PwcoExrzZONEwAAAAAgiezgArTJs6DnTRSAVfh8OwAAUF6ZfPEKh6+kqzPOvdztNCTcVbc94cDJCuuQSZeEznUN7fZv+fqb7Bq23PnoMO7wM8OEaVeE6Zfd7XWo4r55/fc9bnbovdk4ax1JHV9dw77upAE6zv/uVfp/anLFV80kSUpHO4w73t6HUtuU824Jddvu0+HX2Tf7ulfdeFer9vS/+GpJuOyGh72uWql7Hn0p0vvnJ4WfmXmqyIb22TI01WalVXoiu27oki+4TtS+5Yb3szMIAABANfLNC4BYHAoGEH2dWTI2AKIzOQBirTUbTQ6AyPzoOEDr158/WN5XRgqA5+cAZVhrjjJOAAAAAIAksoML0CbPghz2C7Aqn28HAADKK5MvPu3wlXR13R/+6HYaEuzt9z912GSFNWnWjaHboNFl/be735Z7hGF7/DIc8MvzwuRzbvZ312qbftndYfxxs0LvzcZZ80jqkDL5wo3LbyPXcicN0OH7ecPMJUlKR3232NOeh1LdtIvvCIOHH9zh11rX/iPC/HsfbdXe/seffRkuvPp+r6u+7YEnX13j+6a5uTnUbjTKzFNFNqjvNqGpNiuttrp+27lO1K51qh/a064gAAAA1ci3LwBicSgYQPR1ZsnYAIjO5ACItdZsNDkAIvOj4wBtswZ9xEgB8PwcoAzrzKxxAgAAAAAkkR1cgDZ5FnSMiQKwCp9vBwAAymjIkL/L5ItfOXwlXS169mW305BgNy54xmGTFdRZl84P9duNb/N/qzfYdLewza7Hhr2PmRFOOecmf2vF6uw5C8KBJ5wf+mwxztpHUvuVK7734/rhndxIAyRDJle8ynySpMqvc11DOP3C2+x3KNVNn7MgDN3jhA6/3tbdeMfw8BNNrdrff+eDz8I5jfd6XbWiRxa9vub3zHsfmneq2NbLDQ1NtVlptTX03sJ1onZt7b7Dau0IAgAAUI18+wIgFoeCAURfZ5aMDYDoTA6AWGvNRpMDIDI/Og7QNmvQ84wUAM/PAcqwzlxreR8aKQAAAABA0tjBBWiTZ0HbmCgAq/D5dgAAoHwyfRt6OHglXXWpbwhffrXY7TQk1EeffBFmzHXQZCVV2LNtDnvttvHosOXOR4fxx80KU8692d9WbXMg8WV3r3hPbbDpWOsgSWUvU9ewo7togOTo3G+Hmppc8RMzSpIqv8NP+a19DlVFOx04NXSua+jQ663v5mPDS6++2ap9/tff/ijMmrfQa6rw5LNvrfH98uhTz5p1quieyK4bmmqz0iod3OsnrhG1a9/shdkRBAAAoBr5BgZALA4FA4i+ziwZGwDRmRwAsdaajSYHQGR+dBygbdag+xspAJ6fA5RprXmXkQIAAAAAJI3dW4A2eQ70HyYKwCp8vh0AACifTrlhRQevpKuNh+7rVhoS7M4HnnfQZAW1/y/Pa/mhXnUNoW6bfcKo/SaHo0+bF6bPWeBvqrJ11qXzw+6Hnxm6D9rJekhSWcrki1e4gwZIns754s/NKUmq/MYcdJr9DVVN+x43K3SpH96h19zg4n7ho48/a9Vef9NL73g9FZ558e01vleuv3WhWaeK7s5uPUNTbVZapWnrbegaUbvWqX7of9gNBAAAoBr5BgZALA4FA4i+ziwZGwDRmRwAsdaajSYHQGR+dBygbdagA40UAM/PAcq01pxmpAAAAAAASWP3FqDNngW9bqoArMTn2wEAgPKpyRePdvBKutrlgF+5lYaE+vzLxWHWvHscNFkhnTz7xpAdWIr1b3CXuobwk4aDwl5H/yZMOfdmf0e1e9MuuiOU9jslrDNglHWRpDas8O7afYf/yB00QAKVSt/P5IsPmlWSVNltWjrcvoaqqoN+dVHouuHIDr3udtz3+PD110tbtef/yDOvez2rvOdefW+N75NZl1xj1qmiu6J7n9BUm5VW6Zv3hmtE7dm/r1f4J5uBAAAAVCPfwgCIxaFgANHXmSVjAyA6kwMg1lqz0eQAiMyPjgO0zRr075f3lbEC4Pk5QBnWmqONFAAAAAAgaezeArTZs6ArTRWAlfh8OwAAUD41+eLFDl5JVyecdr5baUio+x5/2SGTFdL0OQvCwGEHRPp3t0v98DB4+MFh72NmhKkX3Orvp0Q05dybww7jjl/x/rQ+ktTaMnUNO7p7BkiuTnUN9TW5wlIzS5Iqtx6Dx9jPUNV15JQ5oXajUR167R1z8qxW7/v/8ZEXvZ5V3KtvfbjG98gvppxr1qmiO6dHPjTVZqVVerBbd9eI2rVevUo/sBMIAABANfItDIBYHAoGEH2dWTI2AKIzOQBirTUbTQ6AyPzoOEDbrUMfMFYAPD8HKMM6s6uRAgAAAAAkjd1bgDZ7FnSkqQKwEp9vBwAAyqcmV3jYwSvp6rdX3uJWGhJoyZKl4bwr73PIZIW0y0GnrfHf2/7b/yzsfcyMcNqFt/qbKbFNPPu68NMRB1sjSWpxmXzxCnfOAJWwx1f8jbklSZXdKbNvtJehqmvCtCvCuhvv1KHX3oVzf9+qvf/m5hB+f/cir2eV9vb7n67xPbL7QSeZc6rsNUrP/qGpNiuttt65HVwnaq+av/e9761lFxAAAIBq5JsYALE4FAwg+jqzZGwARGdyAMRaazaaHACR+dFxgLZbh55lrAB4fg5QprXmm8YKAAAAAJAkdm4B2uw50E9NFYCV+Hw7AABQJqXS9zO5whcOXklX9z38tFtpSKDH/vSGAyYr5SDXM64MXTYcsdp/Y7MDdwzFPX8VfnnW1f5WqqgOPvGisMFmu1srSYpZ4d21+w7/kZtngOTr2q/4r8v/3X7H7JKkyu3AE863h6GqbOL0a8J6P92lw669rhuOCHff91ir9v+XLFka5t70qNezCvvo0y/W+P7YbOSB5pwqusPXHxSaarPSatum71auE7VLmVzxSzuAAAAAVCvfxACIxaFgANHXmSVjAyA6kwMg1lqz0eQAiMyPjgO03Tp0jLEC4Pk5QJnWmlcbKwAAAABAkti5BWiz50D/sLwlJgvAt3y+HQAAKI9O9UN7Onglfb37/kdupSFhli1rDhdf+6ADJiugMy+9K/TdYs9V/m3tv/3Pws8mnLPif+/vpErtrEvnh10OOi3UbjTKmklStEMq6xp2dOcMUDlqcoXdzC9JqtxGjJ9k/0JV26RZvw8bbLZ7h11/fTYbG15/691WPQf45LMvwwVX3e/1rLI+/3LJGp8PZTcqmXOq6PbYYEhoqs1Kq+2b94frRO3yvCJf+MDuHwAAANXKtzEAYnEoGED0dWbJ2ACIzuQAiLXWbDQ5ACLzo+MAbbcOzRorAJ6fA5RprXm0sQIAAAAAJImdW4A2fRb0sMkC8C2fbwcAAMrjmwPSHbySrtbfZIzbaEigppffcbhkhTR8n5NW+nd1o6H7h4NPutjfRqlqynm3hB12Pz50rmuwfpL0XV3rrhmg4qyVyRfuMsMkqTIbOOwA+xaq6k4975aQ32bvDrsGt97pkPDlV4tb9SzgrXc/CbPm3eP1rKKWLlv2ne+JN99+z4xTxTe89+ahqTYrrbYJ6w90nahdyuQLr9v6AwAAoFr5NgZALA4FA4i+ziwZGwDRmRwAsdaajSYHQGR+dBygbdeibxstAJ6fA5RhnTnEWAEAAAAAksTOLUCbPgv6jckC8C2fbwcAAMqjJl840cEr6WrYbke5je5gzc3N/gis4vJbHnO4ZAV0zGmXhy51DaHz8jYZeeiK/97fRWnu6NPmhX5b7WUNJWk1Fd5du+/wH7lrBqg8neuLfWpyxa/NMkmqvNYZMCpMn7PAnoWqutMvvC1suO2+HXYdHnFi6z+/vuiFP3stq6TZl9+zxvfDfQ8/bcap4tus79ahqTYrrbaZPepcJ2qv5xbP2vkDAACgWvk2BkAsDgUDiL7OLBkbANGZHACx1pqNJgdAZH50HKBt16LXGS0Anp8DlGGd+cPlfW20AAAAAABJYecWoE2fBY01WQC+5fPtAABAedTkC9c4dCVdHXrCWW6jO9iyZc1h4aMvheZmfwv+yxvvfOxwyQrozEvvCn232CP022qvcPTUuf4mqpqmX3Z3GHPQ6aFr/5HWUpK+LVPXsKM7ZoAK3vPLFaeZZ5JUmf3yrKvtV6jqO/3C28KG2+7bYdfh7665rdXPBe584DmvZRV00TUPrPG98M37yXxTpVfXb7vQVJuVVtu16/Z2nai9etSuHwAAANXKNzIAYnEoGED0dWbJ2ACIzuQAiLXWbDQ5ACLzo+MAbbsWPdZoAfD8HKBMa83nKXtkAAAgAElEQVRHjRYAAAAAICns2gK06XOgdU0WgG/5fDsAAFAemVzhRYeupKsZF13lNjoBrr79yXDTgmfC0mXL/DEIN969yOGSFdDo/aeEXQ4+PUy/7G5/D1VlJ828PgwefrD1lKSQyRevcLcMUNn+fb3CP2VyxTfNNUmqvPY5ZqZ9Cml5p194W6jfdt8OuQ6zG5XCM8+93KrnAkuXLguNtzzmtUx5v7vxkTW+Fyaf/VvzTRVfNjcsNNVmpdX2YLfurhO1Vwvt+gEAAFCtfCMDIBaHggFEX2eWjA2A6EwOgFhrzUaTAyAyPzoO0LZr0cFGC4Dn5wBlWmueZbQAAAAAAElh1xagzZ8FvWm6AKzg8+0AAEDb+7cB2/5zTb7Y7NCVdHXLXfe7jU6A+594ZcVhetff9XT4eukyf5Aq9tGnX4QZcx0smfTOunR+OGX2jf4W0vL2+8U5ocdPdraukqq0TL7wwY96D1vbHTNA5cvki6PNNkmqvHYYd7z9Cen/6/QLbgv12+7bIdfiZqN+Hr78anGrng98+pcvw/lX3ee1THFX3vr4Gt8HPztqqvmmVPR4dt3QVJuVVtt6uaGuE7VHt9rxAwAAoFr5VgZALA4FA4i+ziwZGwDRmRwAsdaajSYHQGR+dBygbdeiP1je58YLgOfnAGVYa440WgAAAACApLBrC9Dmz4LmmS4AK/h8OwAA0PY65xqGOHAlfb3w8htuoxPglTc//PZAvatvfzIsWbLUH6VK3f3QCw6WlFSRBxZvN3aCtZVUhWXyhT3cLQOkRyZXvMN8k6TKKr/N3vYmpL/ap6rbdp8OuR6Pmzy71c8IXn3rwzBjrtcxrd1w19NrfA9sN+Yw802paH63nqGpNiutts36bu06UXt0rd0+AAAAqpVvZQDE4lAwgOjrzJKxARCdyQEQa63ZaHIAROZHxwHafj16l/EC4Pk5QBnWmf97ec3GCwAAAACQBHZtAdr8WdD+pgvACj7fDgAAtL1MrniEA1fSVdf+I8LXXy91G50AXy3+eqVDEhtveSx8ufx/RvW9D85pvNfBkpIqtsNP+W1Yf5NdrbOkKimTL8xffqu4lrtlgPT4z1yhVyZXWGLOSVLl1KWuIZxxyZ32JaT/0bSLbg/1243vkGvyD/MfaPWzgvsef9nrmNJuvbdpja//+puMMd+Uiq5bd4PQVJuVVtvYDTZ1nag9nmHMsdsHAABAtfLNDIBYHAoGEH2dWTI2AKIzOQBirTUbTQ6AyPzoOEDbr0cnGi8Anp8DlGmtuch4AQAAAACSwI4tQJs/B9rAdAFYwefbAQCAtleTL/zOoSvpatMRB7iFTpDf3fjISgfrXX7zY+HLr5b4w1SRh59+zaGSklJxaPG2YydYa0lpP4wyV/iiJrdDd3fKAOmTyRfPMuskqbI6eupcexLSX3XahbeGum32affrse/mY8M7733YqmcFy5qbwxW3Pu51TGF3P/TCd772H378qbmm1HRx936hqTYrrbaj1t/YdaLyP8fIF86z0wcAAEC18s0MgP/D3n1HSVXmif/XCTu7s7vf+e7ub8exG3S7xISEasA4KobRMVEFaolxRsesY54ZcXSMmMWAI8bBLNKmMStmQAURFQyUYmKMGECSpKafb6P7211Xur3VXbf7Vt3X65z3OfvHptOXO5/n3qeqnpI4FAwg+jqzYGwARGdyAJS01mwwOQAi86PjAOVfj25pvADYPweIaa05wngBAAAAAJLAG1uAsu8DrdzcTBMGwOfbAQCAGNTW51536Ep1tf+xZ3mETpAnnpv+rcP1Rj3wQvhy4RJ/nBRoXNYUrr1rokMlJVVNRw+9Pqy96Z7WXFK1lh1wgqdkgOq0Ws8d/6W2PveJeSdJldM+x1zkXYS0gs77y5jQa+vfVOT+2xdzF4Yrb3vGdayynp3ybqvX/cWX3zDXVDVdsnbfUKzLSCvs4uZ/H+4TxV1Nff4Sb/oAAABIK9/OACiJQ8EAoq8zC8YGQHQmB0BJa80GkwMgMj86DlD+9ejfN7fQiAGwfw4Qw1pzsPECAAAAACSBN7YAsewF3WHCAPh8OwAAUGaZvoWf1Nbnmxy6Ul2dNfwGj9AJUnxn5goP2Lv5vufD/C8X+wOl9PpLUiV3wchHwrZ7DbHukqrtIMpsfkrfvgf90JMyQPWq7TPwIDNPkiqnbfY43nsIqYXOuuL+sM7me3f4fXnvmPHt3jeY9tbHrmGV9cJr77V6ze96cKy5pqrptHU2CMW6jLTCGtbs6T5R/HsZ9fmzveUDAAAgrXw7A6AkDgUDiL7OLBgbANGZHAAlrTUbTA6AyPzoOEA8a9JxRgyA/XOAGNaZPzNeAAAAAIAk8MYWIJa9oCNNGACfbwcAAMqsNjtweweuVF8N9zzmETpB5sxb2OIhezfd+3yYt2CRP1IVG/3giw6UlFS1HXnatWHNTXa3/pKqoWyusUvvgRt4Sgaodqd8rzabn2z2SVJl1Gvr33j/ILXSKZfcFdbYeHCH3pfZX/w6zP5iXrv3Dh4aP801rKJeffOjVq/3xVePNtdUNR3b/eehWJeRVtjTa6ztPlHs1dTnTvKODwAAgLTy7QyAkjgUDCD6OrNgbABEZ3IAlLTWbDA5ACLzo+MA8axJzzBiAOyfA8S01iwaMQAAAABAZ/O2FiCWfaDeJgyAz7cDAABlVpvND3PgSvX1wsuve4ROmJF3TWzxoL0b7pkU5s5f6I9Uhd6f+YXDJCVVfede/VDYbJejrcGkij+EMn+xJ2SAdKipH7hx83/2N5l/kpT8uvQZGC687nHvH6RWOmHY6PAfG+zaoffm0Sdf0u79gy8XLgnX3DHBNaySps/4tNXrfcwpl5hrqpp+s97moViXkVbYtObWyA5wryjm/Yzcsd7wAQAAkFa+oQFQEoeCAURfZxaMDYDoTA6AktaaDSYHQGR+dBwgnjXpFkYMgP1zgJjWmpcZMQAAAABAZ/O2FiCWfaCVm/vIlAFSzufbAQCA8qrJ5qc4cKX6DtmcO2+BR+iEeXDctFYP27v+r8+FufMX+kNVmfueetVhkpJS0aU3jw17H31h6NpvZ+sxqRLL5mf8e/fCP3lCBkjTO8HcjWagJFVGJwwb7d2D9B0defq1oWufgR16b46bOKXdewjFd2a6flXS3z6a3eq13vk3J5hpqpp26blVKNZlpBbbtNcv3SuKtZr63CHe7gEAAJBWvqEBUBKHggFEX2cWjA2A6EwOgJLWmg0mB0BkfnQcIJ416d81N8+YAeyfAxDDWnOgEQMAAAAAdDZvawFi2wu62ZQBUs7n2wEAgPL5aY8Bq9TW55scuFJdbbD9AR6fE+il4gffeeDejfdOCvO/XOyPVSVmz/0yXDbKQZKS0tWJF90eem69rzWZVGn1zu3oCRkgXbrW52pq63PzzEFJSn77/+FS7xykCB1w/GUdem9uXTgyNC5b1u69hPufetX1q4Jmft7676r22XY/M01V09a9tgnFuozUYoPX29K9orjbx9s9AAAA0sq3NABK4lAwgOjrzIKxARCdyQFQ0lqzweQAiMyPjgPEty69z5gB7J8DEMM685+bW2LMAAAAAACdydtagNj2gvY1ZYCU8/l2AACgfLr0zu3loJXqa58jTvf4nEAzP5sX6dC9m++bHL5c6PPw1eDJSW86SFJSKrvwusfDDr86ybpMqpSyuVs9HQOkU/MMGGIWSlLy22nfk71vkCK2+xHndej9edMdD7d7L2HugkXhytuecf0qvNlzv2zxGn+5cFHo0megmaaqqW/v7UOxLiO12DHdN3GvKNa69MkN8mYPAACAtPItDYCSOBQMIPo6s2BsAERncgCUtNZsMDkAIvOj4wDxrUuPMmYA++cAxLTWHG/MAAAAAACdyZtagNj2gWqaazJpgBTz+XYAAKB8arP5UQ5bqb7OvPg6j88JtGxZU7iyIdqhiKMeeCEsXLTUH62CLb9+V4x+2kGSklLd4adcEzIb7mZ9JiW5bH7Oan0HrerpGCCdVu/f/++b58HbZqIkJbv1dzjEewaphHb41Ukddn/23vpXYe78Be3eU3hx2vuuXYW3cHHL+3rF6TPMM1VV3eoHhGJdRmqxC9bp515RrNXU57f2Zg8AAIC08k0NgJI4FAwg+jqzYGwARGdyAJS01mwwOQAi86PjAPGtS7sbM4D9cwBiWmueYswAAAAAAJ3Jm1qAWPeCXjFpgBTz+XYAAKA8Vu27049r63PzHLZSfd1+3xMenxPqrsemRj58b/RDL4ZFrRzAR7I9/8rfHCIpSc2dcdk9oX7bA6zRpMSWO8bTMUC61WZzBfNQkpLd6uvvEobfPNZ7Biliw296KmycO7zD7tEzL76u3XsKjcuawk33Pu/6VWgjbh3f6vV96IkJ5pmqrimZbqFYl5FW2I1r9XKfKNa61uf6easHAABAWvmmBkBJHAoGEH2dWTA2AKIzOQBKWms2mBwAkfnRcYB416Z/M2oA++cAxLDO3NiYAQAAAAA6kze1ALHuBV1k0gAp5vPtAABAedTWD9jZQSvV2dRpb3p8TqgJU94t6RC+28a8FJYsbfSHqzDLljWF6/76nIMkJek/u+j6x8N2+5xonSYlrJpsbupK/fv/wNMxQOqtXJvNjTMbJSnZnXrp3d4xSCV07jUPh3X779Mh92dmw0KY+emsdu8tvPXeZ65dhXbtXRNbvbZX3PBXs0xV19g11g7Fuoy0wh7qtq77RPHub/TMre2VHgAAAGnl2xoAJXEoGED0dWbB2ACIzuQAKGmt2WByAETmR8cB4l2bjjRqAPvnAMSwzvx+c7OMGgAAAACgs3hTCxDrXtAOJg2QYj7fDgAAlEdtNj/KQSvV12p9B4WFixZ7fE6oGR/OKvkgvvueejUsW9bkj1dBpr090yGSkrSCDhwyIqzebxdrNikZNXWpz23uyRiA5bpkd1p/+WwwHyUpuR36p6u9W5BK7E8X3xFWX79j3kWdfmF5fk/z7sdfdu0qsFsffKHV6/q70/9slqnquqfbeqFYl5FW2It13dwnivuzUat6owcAAEBa+bYGQEkcCgYQfZ1ZMDYAojM5AEpaazaYHACR+dFxgHjXprsbNYD9cwBiWmveYdQAAAAAAJ3FW1qAWPeB/rG5RaYNkFI+3w4AALRfl40K/1Bbn5vnoJXqa/NBh3l0TrBFi5eGy0aVfhjfI8+87o9XQUY/+KJDJCWplcOM19vy19ZtUidXk83d4MkYgP9p+WwwIyUpue1y8FDvFaQ2dOAJIzrkHl1zk8Hhs1lz2r2/8Oms+W3aR1LndvfjL7d6XQftN8QsU9V1w1q9Q7EuI7XYOtkd3SuKrVX77vRjb/MAAABIK9/WACiJQ8EAoq8zC8YGQHQmB0BJa80GkwMgMj86DhDv2vQnzS0xbgD75wDEsNb8jVEDAAAAAHQWb2kBYt8LetC0AVLK59sBAID2q60fsLNDVqqzA447x6Nzwo164IU2Hcg3bvJb/ngV4IOZXzhAUpK+o2HXPhq2KBxn7SZ1UjXZ3Berr7/DzzwZA/CN94U9B3WpzeYXmJWSlMw22/ko7xSkNrb9Pn/skPv03D/fVJZ9hgfHTXPdKqwxTxdbvaY9t9zHLFPVNXztPqFYl5FarH+vbd0riqdsfulKK620srd5AAAApJVvbACUxKFgANHXmQVjAyA6kwOgpLVmg8kBEJkfHQeIf336pHED2D8HIIZ15k+bW2bcAAAAAACdwVtagNj3gg43bYCU8vl2AACg/WqzuXsctFKdXXD5LR6dE+7J56a3+VC+Sa/8zR8w4Rx2KUnRuvTmsWHw4eeGLn0GWsNJHX7gZO4oT8UArPCdYX3+VLNSkpLZWj/fw/sEqY1ddP3jIbvt/rHfp+tstkeYO39Bu/cZPp0133WrsMZNfrvF6/n57DnmmKqyM9bZMBTrMlKLFXps6V5RLNXU52d5iwcAAECa+cYGQEkcCgYQfZ1ZMDYAojM5AEpaazaYHACR+dFxgPjXp8cZN4D9cwBiWmtOMG4AAAAAgM7gDS1A7PtAqzXXZOIAKeTz7QAAQPv8tMeAVWqyuSUOWqnO7h0z3qNzwhXfmdmug/lemf6RP2JCzV2wKIwYNd4BkpJUQkcPvT5kNtzNOk7qsMMmcy/37XvQDz0ZA7AiXTYq/ENtNj/DzJSkZHbOVQ96lyC1sVMv/WtYvd8usd+nN93xcFn2G+598lXXrYJ6/tX3WryWE1541QxTVXbcupuEYl1GarHDu2/qXlFM5d7xFg8AAIA0860NgJI4FAwg+jqzYGwARGdyAJS01mwwOQAi86PjAPGvT9c2bgD75wDEtNY8ybgBAAAAADqDN7QAHbIXNMXEAVLI59sBAID2WbU+/wcHrFRvb7z9nkfnhJszb2G7DuYbMWp8ePeDz/0hE+iZl95xeKQktaGTL74zrLfFPtZyUvw1rdp34KaeigFoTW029yszU5KS2TFDr/ceQWpHex99Yez36Q57/64s+w0ffTrXNaugXn3zoxav5S13jjHDVJUdsN7moViXkVrstHU2cK8olmqyuane4AEAAJBmvrUBUBKHggFEX2cWjA2A6EwOgJLWmg0mB0BkfnQcoGPWqK8bOYD9cwBiWGf2Nm4AAAAAgM7gDS1Ah+wFnWniACnk8+0AAED71GZzrzlkpTqr23DXsLSx0aNzBRh518R2Hc53ZcMz4ZNZ8/whE2Rp47JwzR3POjxSktrY+SPHhE3yR1jTSfF2nSdiACJYuTabe97clKTkteeR53uHILWjS28eGzbOHR77vfpK8e2y7Dvc+ehU161Cevv9z1u8jqdfONIMU1W2a48tQ7EuI7XYFWv3ca8onrK5cV7fAQAAkGa+uQFQEoeCAURfZxaMDYDoTA6AktaaDSYHQGR+dBygY9aow4wcwP45ADGtNd8xcgAAAACAjubtLECH7ANtZOIAKeTz7QAAQNut2nvAzx2wUr1tM/goj80V4sFx09p9QN/IuyaGufMX+WMmxKtvfuTgSElqZ8NveirstO/J1nVSDNVkc1/8tMeAVTwVAxBFTX1+a/NTkpLX1rv/wfsDqZ2dMeKesHq/XWK9V08696qy7DsU35npmlVIH306t8Xr+KsjzzDDVJX9stc2oViXkVrszjV7uFcUz35Hfe4Bb+8AAABIM9/cACiJQ8EAoq8zC8YGQHQmB0BJa80GkwMgMj86DtAxa9QtjBzA/jkAMa01LzNyAAAAAICO5u0sQIfsA32vuY9MHSBlfL4dAABou9ps/i8OWKnefnvihR6bK8RLxQ/KckjfLfdPDosWL/UHTYBRD7zg4EhJKlP7/f7S0LXvIOs7qZyHTPbO/d4TMQClWH5AsRkqScmqx1b7em8glaHBh58T673ac8t9QuOyZe3ed1jauCxcffuzrlkF9MW8hS1ex00GHGyGqSrbpPd2oViXkVrs6TXWdq8onrK5W725AwAAIM18cwOgJA4FA4i+ziwYGwDRmRwAJa01G0wOgMj86DhAx6xRf9jcLGMHsH8OQAxrze2MHAAAAACgo3k7C9Bhe0EjTR0gZXy+HQAAaJvVe+f/b219fr4DVqq3S/9ym8fmCjHzs3llO6jvzkenluVwRtru/Y+/cGikJJW54866MWQ23M0aTypPb3frtt2PPBUDUIouffM9a7O5RnNUkpJT1z4Dw8U3POG9gdTOlt9H623xq1jv18lTi2XZf3hq0puuWQW0ZGnjCq/f4sVLwmp9B5lhqsp69d4hFOsyUou9VrdGWL0+535R2avJ5q705g4AAIA08+0NgJI4FAwg+jqzYGwARGdyAJS01mwwOQAi86PjAB23Tr3O2AHsnwMQwzrzh83NMnYAAAAAgI7k7SxAh+0F7WjqACnj8+0AAEDb1GZzRzlcpbp7ZOwkj80VYtmypnDF6KfLdljfw08X/VE70QNjX3NopCTF0J8uuiOsveme1nlSew+Y7DNwN0/EALTtfWJ+pFkqScnqTxff4Z2BVIaOPO3aWO/V80fcXJb9h89mz3e9Et7y/b6WTJv+rtmlqi2THRCKdRmp1fr12t79ohjKXeCtHQAAAGnm2xsAJXEoGED0dWbB2ACIzuQAKGmt2WByAETmR8cBOm6dOsDYAeyfAxDTWvMGYwcAAAAA6EjezAJ02D7Qj5r7wuQBUsTn2wEAgDZZubY+97qDVaq7jz/53GNzBbnr0allPbRv4tQZ/qidYO78heGyUeMdHClJMXXWFfeH3tvsb60ntf1wyaeXPw96JAagLWp7DupSm80vME8lKTkddtJV3hdIZejSm8eGftsfEtu9uv2ex5ZtH+Kme593zRLc9X99rsVrd++Y8WaXqrqX69YIxbqM1GI79PyFe0VlryabO9lbOwAAANLMNzgASuJQMIDo68yCsQEQnckBUNJas8HkAIjMj44DdNw6dfkBN3OMHsD+OQAxrDXzxg4AAAAA0JG8mQXo0L2gm0weIEV8vh0AAChdlz75XzpYpbrrs+1+HpkrzIQp75b94L43ZnzqD9vBnn7hbYdGSlLMDbv20bBJ/ghrPqn0mmr7DNjIEzEA7VFTnzvTTJWk5LTbYed4VyCVqWOGXh/bvdqlz8DwyWezy7IPMW7yW65Xgmt46MUWr91FV402u1TVPZtZKxTrMlKL7bdef/eKyl82d6Q3dgAAAKSZb3AAlMShYADR15kFYwMgOpMDoKS1ZoPJARCZHx0H6Ni16i1GD2D/HIAY1pk/am6O0QMAAAAAdBRvZgE6dC9okMkDpIjPtwMAAKWrzebucbBKdbfvUUM9MleYdz+cVfaD+64Y/XSY+fk8f9wOsrRxWbjm9mcdGilJHdDwG58M2+41xLpPKulgyfwoT8MAtNe/brDd/6mtz31itkpSMtpqt997TyCVsX7bHxLb/frwkxPLshcxI4b9JJWve598pcVr99sTLzS7VNWN6bZuKNZlpBYbsu7G7hXF0IC9vbEDAAAgzXyLA6AkDgUDiL7OLBgbANGZHAAlrTUbTA6AyPzoOEDHrlV3MXoA++cAxLTWvNXoAQAAAAA6ireyAB26D/QPzc03fYCU8Pl2AACgNKv0zv9HbTbX6FCV6u7CK31WutIsWrw0XDaq/If3XX/3c+HLhUv8gTvAK9M/cmCkJHVgl948NhQOPdvaT4pQTTa/cPmzoCdiAMqhS33+CPNVkpJRr61/4x2BVMYO+uPlsd2vl1xTnt9/b2xcFq5seMb1SmiPPvt6i9duuz2ONbtU1d25Zo9QrMtILTZs7X7uFZW/bH4Hb+sAAABIM9/iACiJQ8EAoq8zC8YGQHQmB0BJa80GkwMgMj86DtCxa9UfBwfcAPbPAYhnrWkPHgAAAADoMN7KAnT4XpDPyANp4fPtAABAaWqzuXMdqlL9PTbueY/MFeiW+yfHcoDfnY9MCY3LmvyBK/T6SZJab7/fDQ9d+gy0BpRaPVQyd66nYQDKpW/fg35Yk829acZKUufXte+gMPzGJ70fkMrURdc/HjIb7hbL/XrIH84r237EvU++4noltKdfeHuF16ypqSms9fPBZpequhvW6h2KdRmpxW5q/jfiXlG5q6kfuLG3dQAAAKSZb3EAlMShYADR15kO9AIogckBUNJa0w+GA0TnR8cBOn69ervxA9g/ByCGdeaPm5tv/AAAAAAAHcFbWYAO3wsabPoAKeHz7QAAQHSr9NrmH2vqc587VKX6+/TzLzwyV6Annpse2yF+y/93E5/3Pp7tsEhJ6sQOPvGKrw4Stw6UVlTuk0zfwk88EQNQTl2y+T3NWElKRqdccpd3A1IZ2+HXJ8Vyr26x8+Fl25OYMOVd1yqhvTDt/RVesw8+/tTMUtU3Yq0+oViXkVrsoTW6u1dU9mp65tb2pg4AAIA0800OgJI4FAwg+jqzYGwARGdyAJS01mwwOQAi86PjAB2/XnXADWD/HIC41pq3GT8AAAAAQEfwRhagw/eB/qm5BSYQkAI+3w4AAES3av2A3zpQpfrbYPsDPC5XqOI7M2M9yG/q6x/6I8fk/qdedVikJHVyR552bVht/Z2tB6X/faBkNn+Yp2EAyu+U79XU514yayWp8zv8lGu8F5DK2BGnjozlXl29385haWNjWfYkps/41LVKaG+8+8kKr9lTz75oZqnqO2ed9UOxLiO12HNrrOleUdn7Wbbw797TAQAAkGa+yQFQEoeCAURfZxaMDYDoTA6AktaaDSYHQGR+dByg49er/9DcHCMIsH8OQAxrzZ2NHwAAAACgI3gjC9Ape0G3mkBACvh8OwAAEFGh8P2abO5NB6pUf/sfe7bH5Qo1Z97CWA/yGzFqfHjv49n+0GU2d/7CcFnz39ZhkZLU+f3u7JtD3Ya7WhNK/3/Z3Gsr9e//Aw/EAMShtnduR/NWkjq/3X97rncCUhk7f+SY0KXPwFju189nl+f3NGfN+dK1SmgffLLiazxy1H1mlqq+P627USjWZaQWm9bc6vU594vKWVPfvgf90Fs6AAAA0sy3OQBK4lAwgOjrzIKxARCdyQFQ0lqzweQAiMyPjgN0zpr1BiMIsH8OQAzrzB8150fBAQAAAIDYeSML0Cl7QQNMICAFfL4dAACIprZ+wM4OU0lHw6+5zeNyBRt558RYD/O75o4JYd6CRf7QZTT+hbcdFClJCeqEYaPDGpsMti6UlpfN7eppGIBY3zlmc2PNXEnq3Lbe/Q/eB0hlrvcv9ovlfn3nbx+WZV+iqakpXDH6adcqgc2Zt3CF12zImZebWar6ju6+SSjWZaRWq++9g/tFZdwDyc/xdg4AAIC0820OgJI4FAwg+jqzYGwARGdyAJS01mwwOQAi86PjAJ2zZv2lEQTYPwcgprXmNUYQAAAAABA3b2MBOmUf6IfNfWoKAVXO59sBAIBoarO5Zxyoko6eevZFj8sV7MFx02I/0O+2MS+FxmVN/thlsGRpYzlljGEAACAASURBVLj69mcdFClJCevUS/8a1tl8b2tDpbqabG7qSiud8j1PwwDEadW+Azc1dyWpc8tuu793AVKZ22zno2K5X6e8Or1s+xO33D/ZtUpgjY3LVni9Bu43xMxS1XfAepuHYl1GarWte23jflEZy73j7RwAAABp5xsdACVxKBhA9HVmwdgAiM7kAChprdlgcgBE5kfHATpnzfr95j42hgD75wDEsNbcyggCAAAAAOLmbSxAp+0FXW4KAVXO59sBAIDvVttnwEYOUklHXfoMDLO+mOtxuYK9VHy/Qw71G/v8W/7YZfDyGx86JFKSEtoZI+4J6/bfxxpRqa2mz8CdPA0D0CHvHrO5e81eSeq8uvbbOQy/6SnvAqQytt3ef4zlfh03cUrZ9iduHzPFtUpYf7ljwgqvVVNTU1h38z3NLFV9g3tsGYp1GanVduuxlftF5ewFb+YAAABIO9/oACiJQ8EAoq8zC8YGQHQmB0BJa80GkwMgMj86DtB569bhxhBg/xyAGNaZ32vuPWMIAAAAAIiTt7EAnbYXtJkpBFQ5n28HAAC+W019/jYHqaSjjXY80KNyhfv4s7kddrjf9Bmf+oO30y33T3ZQpCQluKGX3xfW3Xxv60SlrppsfoInYQA6Sm12UO/a+twyM1iSOq9TL73bewCpjOV+c2os9+ojYyeVbX/i3idfca0S1q0PvrDCa/X+R5+YVUpFO/b8RSjWZaRWO6T7Zu4Xla9s7lFv5gAAAEg73+gAKIlDwQCirzMLxgZAdCYHQElrzQaTAyAyPzoO0Hnr1g2NIcD+OQAxrTUvMIYAAAAAgDh5EwvQaftAKzf3jkkEVDGfbwcAAFq3Wr+dM7XZXKPDVNLR/see7VG5wi1b1hSuGP10hxzud2XDM2HWnAX+6G30/sdfOCRSkiqgoSPuDetuvre1olLVqtkB23gaBqAj1dTnbzKDJanzOuLUkd4BSGVswH4nx3KvPj5+ctn2KMY8XXStEtZ9T726wmv12LjnzSqlov69tg3FuozUan9cdyP3i8pWTX3+Nm/lAAAASDvf6gAoiUPBAKKvMwvGBkB0JgdASWvNBpMDIDI/Og7QuWvX6UYRYP8cgBjWmfXGEAAAAAAQJ29iATp1L8hBwkA18/l2AACgdbX1uREOUklPF1012qNyFbjz0akddsDfLfdPDksbl/mjt8FD46c5JFKSKqShI+4N626+t/Wi0nGIZDb/lCdhADpa174D16jJ5paYxZLUOe1+xHme/6UytuOv/xTLvfrkMy+WbY/iyUlvulYJ64nnVvw7qZdde4dZpVTUt/f2oViXkVpt2Nr93C8q435I7kpv5QAAAEg73+oAKIlDwQCirzMLxgZAdCYHQElrzQaTAyAyPzoO0Llr15ONIsD+OQAxrTVfMooAAAAAgLh4CwvQqftAazfXZBoBVcrn2wEAgJb9tMeAVWqyuS8dpJKeHh07yaNyFXh2yrsdesjfw08X/dFLtODLxWHEreMdEilJFdSZV9wf1ttiH2tGVX1dsgP7exoGoDMsP8jYLJakzmnbPY/37C+VsR1+dVIs9+q4iVPKtk/x1PNvulYJa9Irf1vhtfrtiReaVUpFa2V3CsW6jNRq162Vdb+obNXU58/yRg4AAIC0880OgJI4FAwg+jqzYGwARGdyAJS01mwwOQAi86PjAJ27du3SXKNxBNg/ByCGteYxRhEAAAAAEBdvYQE6fS/oGdMIqFI+3w4AALSspj5/tkNU0tVHMz/zqFwF3v1gVocf9PfK9I/84UswceoMB0RKUgV2xoh7wjqb72XdqCou97AnYQA67V1kv3zXmvr8IvNYkjq+Ptsd6LlfKmPb7/PHWO7Vp5+bWrZ9iicnvelaJaxpb328wmu1zeCjzCqloi7NvZpZIxTrMlKL3dNtPfeLytaq9fk/eCMHAABA2vlmB0BJHAoGEH2dWTA2AKIzOQBKWms2mBwAkfnRcYDOX7+OMY4A++cAxLDO/LfmFhlHAAAAAEAcvIUF6PS9oANNI6BK+Xw7AACwYv+6wXb/p6Y+N9shKump99a/8phcJRYtXhouG9WxB/1dPvrp8Oms+f74ESxb1hSuvWuiAyIlqUIbevn9Yb0t9rF+VHXWN7ehp2EAOlNtNv9nM1mSOr66DXf1zC+VsV/ufUIs9+qEya+Uba/iieemu1YJ628fzf7WdVra2PjVf0abVUpLkzJrhWJdRmqxp9dY272isrVqNr+/t3EAAACknW93AJTEoWAA0deZBWMDIDqTA6CktWaDyQEQmR8dB+j89esexhFg/xyAmNaadxhHAAAAAEAcvIEF6PR9oH9qbp6JBFQhn28HAABWrDabG+IAlXS1zxGne0yuIrfcP7nDD/u7+b7JYWnjMn/87zB9xqcOh5SkCu+My+4Ja226pzWkqqts7h5PwgB0tq71uZqabO5Ls1mSOr5zr37IM79Uprbd64RY7tOJL75Wtr2KxydOd60S1udfLPjWdXr9rb+ZUUpVT3RbJxTrMlKLvdrcatmc+0VlqUuf3CBv4wAAAEg73+4AKIlDwQCirzMLxgZAdCYHQElrzQaTAyAyPzoO0Pnr179vbpaRBNg/ByCGteZOxhEAAAAAEAdvYAESsRd0vYkEVCGfbwcAAL5t9f79/74mm//IASrp6s8jb/eYXEUen/hGpxz49+SkN/3xv8Odj051OKQkVUEnX3xnyGy0m3WkqqWmmt75rKdhAJKgJpu/0GyWpI7v+PNv9bwvlalt9jg+lvv0+SnFsu1VPDbhDdcqYS1e0vit63T3w+PMKKWqe7qtF4p1GanVemR3dL+oLK3ad+Cm3sQBAACQdr7dAVASh4IBRF9nFowNgOhMDoCS1poNJgdAZH50HCAZa9g/G0mA/XMAYlhn/qC5D4wkAAAAAKDcvIEFSMRe0BYmElCFfL4dAAD4tprswEMdnpK+Jr00zWNyFXn1zY867dC/t9//3AVowedfLHAwpCRVUScMGx3qNtzVWlKVXzZ3rydhAJJi1b47/X+19bl5ZrQkdWwH//Fyz/pSmdp69z/Ecp+++PIbZduvePTZ112rBHXlbc+s8Dqd++ebzCilqpvX7BWKdRmp1Tbvta37RWWpptfAtbyJAwAAIO18wwOgJA4FA4i+ziwYGwDRmRwAJa01G0wOgMj86DhAMtawfY0kwP45ADGtNc82kgAAAACAcvP2FSAR+0ArNzfdVAKqjM+3AwAA/0v//j+oyebecnhKulpjo0JYvHiJx+Qq8vkXCzrt4L9r7pgQFny52EVYgScnvelwSEmqso4984bQtd/O1pSq6Fbtk9/MwzAASVKTzZ1jRktSx1Y49GzP+VKZ2mq338dyn055tXyfY3/kmdddqwR1832TV3idfnPMWWaUUtWVa9WHYl1GarWBPbZ2v6gsrdZzx3/xFg4AAIC08w0PgJI4FAwg+jqzYGwARGdyAJS01mwwOQAi86PjAMlZx75oLAH2zwGIYZ25VnNNxhIAAAAAUE7evgIkZi/oRFMJqDI+3w4AAHxTTe/8vg5OSV+7Hui9VzW6+vZnO+3wv7sff9kF+F+WLGkMV932jMMhJakKO/K0kaFrn4HWlarIaupzEz0JA5C4d5TrD/y32mx+jlktSR3XNnsc7xlfKlNbFo6L5T59pfh22fYsxjxddK0SVEv7ahvvdJAZpVR14dr9QrEuI7Xa/utt7n5ROfZGFq+00korewsHAABA2vmWB0BJHAoGEH2dWTA2AKIzOQBKWms2mBwAkfnRcYDkrGMPMZYA++cAxLTWfMxYAgAAAADKyZtXgMTsA/2suSUmE1BFfL4dAAD4HwqF79fW5153eEr6On/EzR6Rq9DyA/g68wDAl4ofuAj/w9Q3PnQwpCRVcQf98YrQpc9Aa0tVXKtmB+Q9DAOQRLXZ/BlmtSR1XH23P9jzvVSm+u9yTCz36WtvvFO2PYuHx09zrRLUoxPe+NY1mr9gofeNSl1nrrtBKNZlpFb7ffeN3S9qdzX1+fe9fQMAAICvfkQHgOgcCgYQfZ1ZMDYAojM5AEpaazaYHACR+dFxgOSsY/+puTlGE2D/HIAY1pq7GksAAAAAQDl58wqQqL2g0SYTUEV8vh0AAPhvtfX5fRycks7GTnjJI3IVmjh1RqceAHj5rU+HT2fPdyH+06gHXnAwpCRVeXsddYG1pSqrbH7aSiud8j1PwwAk0Wo9d/yXmmzuCzNbkjqmzEYFz/ZSmdp8l2NiuU+L02eUbc/iwXHTXKsENWHKu9+6Ri+8/Lr5pNR14robhWJdRmq1oets4H5RGcq96O0bAAAAfPUDOgBE51AwgOjrzIKxARCdyQFQ0lqzweQAiMyPjgMkay17mdEE2D8HIIZ15g+ae99oAgAAAADKxZtXgETtBW1hMgFVxOfbAQCA/1QofL+2Pl90aEr66rbxbmHR4sUekavQjA9ndfohgLfcPzksbVyW+mvxwcwvHAopSSlp54POsMZUxbRqNr+/h2EAkqy2Pne6mS1JHdd514zxbC+VoU0HHRXLPfrG2++Vbd/igXGvuVYJ6uU3PvzWNbrlzjFmk1LXcetuEop1GanVhq/dx/2icjTGmzcAAAD46gd0AIjOoWAA0deZBWMDIDqTA6CktWaDyQEQmR8dB0jWWrZ7c03GE2D/HIAY1pqnGU0AAAAAQLl46wqQuL2gV0wnoEr4fDsAAPC1Ltn8ng5MSWe/OvIMj8dVatHipYk4CHDs82+l/lo8NH6aQyElKSVdevPYsO2ex1tnKvHVZPMfrd6//997GgYg0e8suxf+tTabn2t2S1LHdMKw0Z7tpTL084FHxnKPvvXuB2Xbt7h/7GuuVYJ694NZ37pGfzrvarNJqevw7puGYl1GarXr1+ztflEZ9khyN3rzBgAAAF/9eA4A0TkUDCD6OrNgbABEZ3IAlLTWbDA5ACLzo+MAyVvPjjOeAPvnAMSwzqxpbonxBAAAAACUg7euAInbCzrSdAKqhM+3AwAAy53yvZr63MsOTUln146+3+NxFbv5vucTcRjg3z6andprsODLxWHEreMdCilJKeriG54IG+x4qLWmkn1gZO/c7z0LA1AJaurzZ5ndktQxHXLilZ7rpTK0Sf6IWO7Rd9/7qGx7F/c99aprlaBmzfnyW9eocNBJZpNS137r9Q/FuozUan/t1sP9ovaXzQ/z1g0AAAC++vEcAKJzKBhA9HVmwdgAiM7kAChprdlgcgBE5kfHAZK3nt3TeALsnwMQ01rzLuMJAAAAACgHb1wBErcP9JPm5ptQQBXw+XYAAOCrg2kHOzAlvZXzAD6S57EJbyTiMMDr754UlixtTOU1mDh1hgMhJSmFnfeXMaHHlvtabyqph0XOyfQt/MTTMAAV8e5y/YH/1jy75prhkhR/u//2XM/0UhnaaMDhsdyjf/tgZtn2Lu594hXXKkEtbVz2rWvUa6t9zCalrsE9tgzFuozUao+vsY77RWXYJ8kN8dYNAAAAvvrxHACicygYQPR1ZsHYAIjO5AAoaa3ZYHIAROZHxwGSt579u+Y+NqIA++cAxLDW3NZ4AgAAAADKwRtXgETuBV1tQgFVwOfbAQCAlVauyeamOjAlnW028FCPxlXulekfJeZAwHGT30rd339ZU1O49q6JDoSUpJR22p//GtbYeLB1pxJX8zPgOR6FAagkzfPrPDNckuJv271O8DwvlaENdzoslnv0g48/Ldv+xT1PvOJaJaSRd0381vX5aOZn5pJSWb7nVqFYl5FabXJmTfeL2t2q2fz+3rgBAADAVz+cA0B0DgUDiL7OLBgbANGZHAAlrTUbTA6AyPzoOEAy17RDjSjA/jkAMawzV25umhEFAAAAALSXN64AidwLyppQQBXw+XYAAEi72vr8Lg5LSW9/Ou9qj8ZV7rPZ8xNzKOBlo8aFDz+Zk6q///QZnzoQUpJS3h/OuSV07beztacSU019flHX+lyNp2EAKskqvQb9tDabX2CWS1K89dvhYM/yUhnaYMdDY7lHP/z4s7LtX9z9+MuuVUK6fcyUb12fR8dOMpeUyrbpuU0o1mWkVpvW3Or1OfeM2rlXkst54wYAAABf/XAOANE5FAwg+jqzYGwARGdyAJS01mwwOQAi86PjAMlc09Y0t9iYAuyfAxDDWvNQIwoAAAAAaC9vWwESuxf0hCkFVDifbwcAgJRbuaY+95LDUtLb+OemeDSuck1NIVx127OJORjwpvueD42Ny1Lz97/r0akOhJQkhcNOvjp06TPQ+lMJOSgyf71HYQAqUU02f6FZLknxtsYmgz3HS2Wo3w4Hx3KPfvLZrPLtXzxm/yIpPfLM69+6Phdeeau5pFS2aa9fhmJdRvrOevTe0T2j9tVnwEbetgEAAMBXP5oDQHQOBQOIvs4sGBsA0ZkcACWtNRtMDoDI/Og4QHLXtTcaU4D9cwBiWGf+uLnPjCkAAAAAoD28bQVI7F5Q3pQCKpzPtwMAQJp16ZMb5KCU9NZji73D0sZGj8YpcPfjLyfqcMBnX3onFX/3WXMWOAxSkvRfDT78XGtQJaIu2Z3W9zQMQCVaff0dflaTzX1pnktSvF3wl0c8x0vtrN92B8Vyf342a07Z9jDufHSqa5WQJkx991vXZ/9jzzKTlMr69d4+FOsy0ne2Se/t3DNqV6v12znjbRsAAAB89aM5AETnUDCA6OvMgrEBEJ3JAVDSWrPB5ACIzI+OAyR3XdvHmALsnwMQ01rzHGMKAAAAAGgPb1oBErsP9L3miiYVUMF8vh0AAFJs5dpsfrKDUtLb70671GNxSkyY8m6iDgccMWp8+GTWvKr/u499/i2HQUqS/qtLbx4bfrHH8dah6tRqsvkJHoUBqGQ19flLzHRJircTh93mOV5qZ322OzCW+/Pz2XPKtodx5yNTXKuE9NpbH3/r+my4wwFmklJZ9+xOoViXkb6z7Xtu7Z5Ru/q3tXP/7E0bAAAAfPWjOQBE51AwgOjrzIKxARCdyQFQ0lqzweQAiMyPjgMke2071qgC7J8DEMM6s7a5JUYVAAAAANBW3rQCJHov6EiTCqhgPt8OAABpVVOfH+CQlHT32LjnPRanxLsfzErcAYGjHnghNC5rqtq/+dLGZeHq2591GKQk6RtddP3joX5bB+KqMxuwt6dhACpZbc9BXWrqc4vNdEmKr8NPucYzvNTO4nr/88WceWXbx7h9zEuuVUJ6f+YX37g2s76Yax4ptdVlc6FYl5G+s917bOGeUZuryeYXessGAAAAX/NtG4CSOBQMIPo6s2BsAERncgCUtNZsMDkAIvOj4wDJXtvuYlQB9s8BiGmtOcqoAgAAAADayltWgETvA/1zc1+YVkCF8vl2AABIq5psfpKDUtLbOpvtEZYsWeqxOCUWLlqayEMCJ738t6r9m097e6aDICVJK2zo5feFNTYZbE2qzujjbt22+5GnYQAqXW197hpzXZLia5+jL/T8LrWz3tvsH8v9OXf+grLtY9z28EuuVUKaO3/hN67N2AkvmUdKda/WZUJR+o4O6r6Z+0VtL5uf4Q0bAAAAfM23bQBK4lAwgOjrzIKxARCdyQFQ0lqzweQAiMyPjgMke237/ebeMq4A++cAxLDW7GdUAQAAAABt5S0rQOL3goaZVkCF8vl2AABIo9psfgeHpKS7I0680CNxytx07/OJOyTw8lvHh8+/WFCVf+/bxjiMUpLUcseeeWPo2megdak6+pDIoZ6GAaiOd5s7rlmbzTWa75IUT7n9T/XsLrWzHlvuG8v9ueDLheX75OhDL7pWCWjEreNDU1PTN67NiOvuNI+U6p7PrBmKdRmp1X7ffWP3i9pcTTY/wRs2AAAA+Jpv2gCUxKFgANHXmQVjAyA6kwOgpLVmg8kBEP2rIyYHQOLXt0cbV4D9cwBiWms+bVwBAAAAAG3hDStA4veB/qO5pSYWUIF8vh0AANJo+eEgDklJdw89McEjcco8+uzriTws8PYxU6rub/3Z7PkOgpQkfWd7H32hdak6sNyyVXoNqPM0DEC1qM3mbjXfJSmetiwc57ldamfrbL5XLPfn0qWNZdvLGP3gi65VArrhnknfujaHDbnAPFKqG5dZOxTrMlKrnbHOBu4XtbmabP5Ob9cAAADga75pA1ASh4IBRF9nFowNgOhMDoCS1poNJgdAZH50HCD569t/bO5TIwuwfw5ADGvNvHEFAAAAALSFN6wAFbEXdJOJBVQgn28HAIC06dIn/0sHpKS79bbYKyxevMQjccq8/MaHiT0wcNrbM6vqb/3UpDcdBClJ+s4uvXls+MUex1ufqoPKPexpGIBqUtM7n22ecU1mvCSVvz7bHei5XWpn3Tbevez35mp9B5V1L+PWB15wrRLQXx97+VvXZvNBh5lHSnUPd+seinUZqdWGr93H/aL27Jlc5u0aAAAAfM03bQBK4lAwgOjrzIKxARCdyQFQ0lqzweQAiMyPjgNUxhr3NCMLsH8OQAzrzJWbe9nIAgAAAABK5Q0rQEXsBfVsrsnUAiqMz7cDAEDKrFxTn5vocJR0N+TMyz0Op9Ann89L7IGBI++cEBYtXloVf+eljcvCVbc96yBIqUobdu1jYejl94UTL7o9/O7sm77RkaddG357yjX/1eEnXx0OGHLZVy3/r488beRX/31Dzh/91f/8GSPuCWddcX+4YOQj4ZIbnvT3TWkXXf94qN/2AGtUxV8250voAFSdmvrc/ea8JJW/bhvv7pldamf/scGuZb8319xkcFn3M265f7JrlYAenzj9G9dl3vwvQ9e+A80jpbq7u60XinUZqdWuW7O3+0VtrqY+d5I3awAAAPA137QBKInPYwNEX2cWjA2A6EwOgJLWmg0mB0BkfnQcoDLWuP+2/GtlxhZg/xyAGNaavzayAAAAAIBSebsKUDF7QfeZWkCF8fl2AABIk5r6XM7hKHruxdc8DqfQsmVN4YrRTyf20MCxz79VFX/n19762CGQUgU1/KanwtDL7wt/OOeWcPAfLw+DDz835PY/NWy71wlhs12ODuvvcGjoufW+Yc1Ndg9d+8R/kOny/zu9f7Ff2GjA4WHL3X4XBux38lf/Px14wohw7Jk3hlMvvTtcdP3jrl2Vtfzf4BqbDLZOVYzlZnbvXvg7T8QAVJtV+w7c1JyXpHjy/kFqX3G8S+y55T5l3c+48d5JrlUCev7V975xXSa++Jo5pNR365o9Q7EuI7XaXWv2cL+oza2aze/vzRoAAAB8zTdtAEriUDCA6OvMgrEBEJ3JAVDSWrPB5ACIzI+OA1TOOvcSYwuwfw5ADOvMHzb3rrEFAAAAAJTC21WAitkL2szUAiqMz7cDAECKrFxTn3vJ4SjpbpMBB4empiaPwyl1+5gpiT008LJR48Ons+dX/N/4todfcgiklLDOuerBcNxZN4YDh4wIux12Tvjl3ieEjXY6LKy7+d6xHG7bEXXbePew/g6HhG33GhJ2/+154dA/XR1OuvC2cPENT7jmFdrRQ68PXSr036Mqodz5HocBqFa12dxYs16Syt+pl97teV1qY8NvfDKW+7Lfdr8p637GdX99zvVKQG+8+8k3rsvIUfeZQ0p9I9fKhmJdRmq1x9dYx/2itpcduL23agAAAPA137IBKIlDwQCirzMLxgZAdCYHQElrzQaTAyAyPzoOUDnr3K7NLTa6APvnAMSw1jzK2AIAAAAASuHNKkBF7QWNN7mACuLz7QAAkBa12VzBwSgadsUoj8IpNm7y24k+OPCOR6ZU9N/3s9nzHQApdWIXXf94OHHYbeHAISNC/oDTwib5I0K3jXdP1Zzv2mdg6Ln1vmHr3X8fBh9+bjjytGvD2Vc+4N9HhTTowNOtVxVLP8vmunsiBqB633kO3N68l6Tyd9xZN3pWl9rYsOsejeW+/HnukLLuaVxzxwTXKwF9/Nncb1yXY065xBxS6huxVp9QrMtIrfZsZi33i9pcTe981ls1AAAA+Jpv2QCUxKFgANHXmQVjAyA6kwOgpLVmg8kBEJkfHQeorLXu9UYXYP8cgBjWmT9u7hOjCwAAAACIyptVgIraCxpgcgEVxOfbAQAgFQqF79dmc685GCXddekzMLw94wOPwin2xrufJP7wwOI7Myv27/vkpDcdACl11MG01z4Wjh16Q9j9t+eGrXb7feix5b5fzTnzfsWtvdleYcvCcWHPIy8Ivzv75nDR9Y/7d5TAht/4ZOi7/cH+zaq8ZXPPeyAGoMqt3DzzXjD3Jam8HTDkMs/qUhs79+qHYrkvtyocUdY9jSsbnnG9EtCXC5d847psM/goc0ipb9g6/UKxLiO12tTMGu4Xtbmf9hiwildqAAAA8DXfsgEoiUPBAKKvMwvGBkB0JgdASWvNBpMDIDI/Og5QWWvd9ZprMr4A++cAxLDWPNnoAgAAAACi8lYVoKL2gVZu7mXTC6gQPt8OAABpUFuf38ehKMrve7zH4JSbM29h4g8PHHnnhLBo8dKK+9suWdoYrrrNAZRSXJ115QPhsJOuCrnfnBrqtz0gdOkz0GxvR137Dgob7nRo2OvI88MfhzWE4Tc95d9ZQho64t6Q2XA3/05VvrK5ozwRA1DtVs0O3MPcl6Tyttth53hOl9rYmVfcH8t9uf1ex5V1X2PEqPGuVyd3ZcMz37gmixYvDquvv7M5pNR3xjobhGJdRvrOVq/PuWfUhn2T/NKVVjrle96oAQAAwNd8ywagJA4FA4i+ziwYGwDRmRwAJa01G0wOgMj86DhA5a13bze+APvnAMSwzvxJc7ONLwAAAAAgCm9VASpuL2h30wuoED7fDgAA1a5v34N+WJPNvelgFN1696Megwl/uWNC4g8RHDf5rYr7u7765scOgJTK1KU3jw2nDL8r7Pf74WGbvYaEdTff2xxvoa59B4V1++8TNtrpsLDV4N+FAfud/NWh1/sed3E49KQrJG7rpwAAIABJREFUw7Fn3hBOuvC2MPTy+8K51zwcLhj5SBh23WP+nSW8w0++2r9vle1gyFV6Dfqpp2IAql7//j+orc+9Y/5LUvnabu8/ekaX2thpf747lvty0H5DyransaypybVKQKMeeOEb12XKq9PNIKm5E9bdKBTrMtJ31j27k3tGJVdTn3vPyzQAAAD4b75hA1ASh4IBRF9nFowNgOhMDoCS1poNJgdAZH50HKDy1rvrLf/6nxEG2D8HIIa15unGFwAAAAAQhTeqABW3D/S95l42wYAK4PPtAABQ7Wp75w50KIrW2XSPsODLhR6DCfc++WriDxEcMWp8+Gz2/Mp6w/LQiw6AlNrRRdc/Ho48/dqw475/CutsvrfZ/T9aa9M9wyb5I8IOvz4p7H7EeeGQE68Mx583Kpx5xf1h+E1P+fdTpS2/F/z7V/sPhszf54kYgNS8A83mjjL/Jal8bZz/redzqY396eI7Yrkvdz/k5LLtaSxZ2uhaJaAHx037xnW56Y6HzSCpuWO7/zwU6zLSd7Z+7+3dM2rL3slz3qQBAADAf/MNG4CSOBQMIPo6s2BsAERncgCUtNZsMDkAov8klskBUJFr3juMMMD+OQAxrDP/b3OzjTAAAAAA4Lt4owpQkXtBe5hgQAXw+XYAAKhm3bpt96PabH6GQ1E05MzLPQLzledenlERBwne8ciUivmbfjp7vsMfpTY09PL7wn6/Gx42HXRUWL3fLqme0136DAzrbfGrsPkux4SdDx4aDjxhRBhy/uhwwchH/FtJaRff8ETIbru/dazaezDkYE/FAKTFv3cv/FPz7JtlDSBJ5Wn5ewrP51LbOmHY6Fjuy18feUbZ9jUWLlriWiWgCVPe/cZ1Wb6fawZJ+XBI981CsS4jfWdb9Pqle0all83f7U0aAAAA/DffsAEoiUPBAKKvMwvGBkB0JgdASWvNBpMDIDI/Og5QmWveHs0tM8YA++cAxLDWPN0IAwAAAAC+i7epABW5D/S95l42xYCE8/l2AACoZqvWD/itA1G0vKnT3vQIzFdmfDirYg4TnD7j04r4mz7x3HSHP0oRuvTmsWHI+aPDzgcPDb1/sV9qZ3LXvoNCdpv9w3Z7/zH8+riLwx/OHRWGXfuYfyP6VqcOvyv8xwa7WsuqrYdCLlil1zb/6KkYgDSpqc+daR3w/9i7Eyipyjvh/yaZzMw7eeed/Cc5MTYY062iUZRqGre4a4xLoArQEve4J2pwixvGDXeDRiPiEhFxQaXdEMUNBUVAFFEQ0QZRFFAURQTZ6e7nX5CoIDR1q6nbXVX9+ZzzPWfOmZyZULdv/Z57b1U9kpSn+xcduq68l+P6XMq9c66+L5bz8sSzr8nbc42vFi5xrAqgmmmfrnZcfnfkWWaQlOnorXcLNeUVUtb232Zv54xyriyRvNVdNAAAAPiWb9gA5MSmYADR15lpYwMgOpMDIKe1ZrXJARCZHx0HKN517yPGGOD5OQAxrDN/nGmuMQYAAAAArIu7qQBF+yzoUFMMKHA+3w4AAKVqo6qO/1WWSH5sQxTtf9iZLn/5xuKly4tmM8G7B48NtXV1Bf16LlteG/7x4GibP0rr6NKbBoduJ18dtt7jqBY5h9vudXTY74jzw7Hn3BT+cl11uOGe4f4uFLnjzultPavGbQpZmXrQVTEALc0m2x3w88wMXGItIEn56arbnnRtLjWiMy+/O5Zzsvtf/pa3Zxtfzl/sWBVAn3w+/9vnTcuWh/IdDjJ/pEyHtd0j1JRXSFk7qO2ezhnl/vwkkbzIXTQAAAD4lm/YAOTEpmAA0deZaWMDIDqTAyCntWa1yQEQmR8dByjedW/bTHVGGeD5OQAxrDUvM8YAAAAAgHVxJxWgaJ8DfT/TRJMMKGA+3w4AAKWqLJE6y2YoWtE9Dz3t8pfV3Pv4a0WzoeD4mpkF/VpOmjrLxo/SWrqm7zPh6D//PXQ44A8tauau2PR0z/Tp4YRzrg9X3/JwGPjk2PDYsInhoWcnhIFPvxHuGTw29B/0avjHgy/7O1Gkeg8YEXbtepo1rXLfFLJ954NdFQPQIu+JViZvtxaQpPzU49qBrs2lRnRqz36xnJNnXXpT3p5tzPlyoWNVAC1ZuvybYzL+rSlmj/Sv0m33DDXlFVLWjmq7u3NGudcueYI7aAAAAPAt364ByIlNwQCirzPTxgZAdCYHQE5rzWqTAyAyPzoOUNxr30eMMsDzcwBiWGf+ONNcowwAAAAAaIg7qQBF/SzoMJMMKGA+3w4AAKXoJ1sk/7tVZXK2zVDUZuduYf6ChS5/Wc3Q0ZOLZkPBvg+9vNqmggV3Z+XpN2z8KP2r6+8aFk6+4B9htwPPCBtXdWkRc3bzX3cLh518cbix74Nh7Ph3wvLltZHfP2rr6sOCRUvD53MXhOmz5obJH8wOEyZ/FMZM+GDl+/TDQyeEOx99xd+WwpW3PRkqdkxb2yp6idTCDbfd50eujAFoiTaq6rhlq8pknTWBJK1/p1zc13W51IhW3CON45y84Op/5O3ZxqdzvnKsmrl+j4xZ7ZjcOXCI2SP9q9Q2e4Wa8gopaydvvYtzRjlX1r5zR3fQAAAA4Fu+XQOQE5uCAURfZ6aNDYDoTA6AnNaa1SYHQGR+dByguNe+22aqM84Az88BiGGteYlRBgAAAAA0xF1UgKJ+DvSDTG+ZZkCB8vl2AAAoRWWVyb/YCEUrOv+qW136soYJkz8qqo0FR77+fkG+jrNtOimtrOdNg0Lq+J6hYseDS36uVuyQDof88aJwY98Hw9jx74Tly2tjf6+prasLc+cvCtNnzQ1vvTsrvDTuvTDo+Ymh70Mv+/trQZ14/q3Wtoq+IWRl6kFXxQC0ZK0SqcesCSRp/Tv6zze4Jpca0Qk9bo7lnLzs+jvzds/x49nzHKtm7pHn3lztmJx24Q1mj/Sv9t/mN6GmvELK2llb/do5o5zbqH3nKnfPAAAA4Fu+XQOQE5uCAURfZ6aNDYDoTA6AnNaa1SYHQGR+dByg+Ne/9xpngOfnAMSwzvy/mT41zgAAAACAtXEXFaDonwWlTDOgQPl8OwAAlJpN2qV+XFaZ+sJGKGrdvnOY/N50l76s4ZPP5xfVxoK3PDAqzPtqccG9jsNffdfGj2qx3ThgROh+Sb/w61T3lfOmlOfpngd1D5dce0cYPmpcWLR4SUG9Dy1YtDR88PEXYdykGeGZUTXh3ide8/dZwu1x0JnWuIpUWWXyEFfGALRkG7VP7WpNIEnr30F/vNL1uNSIjjm7dyzn5F/7DMjbfcXps+Y6Vs3csFfeXe2Y7N7lFLNH+le/2WafUFNeIWXtoi13dM4o537WttOG7p4BAADAt3y7BiAnNgUDiL7OTBsbANGZHAA5rTWrTQ6AyPzoOEDxr39/mWmpkQZ4fg5ADGvNM40zAAAAAGBt3EEFKIlnQaNMNKAA+Xw7AACUmlaJ1GU2QdGKuv3hQpe9rFVtXV245YFRRbW54NDRkwvqNVy2rDbcVj3axo9qcV1/17BwzFk3hq33OKpk52ebnbuF4/98dbh/0NDw8SefF917/KLFy8J70z8PL417Lwx86o3Q5/6R/nZLpGtufzpsttMh1rlaZ2WJ5LKKqvT/uDIGoKUrS6TGWhtI0vq1/5Hnux6XGtGRZ1wfyzn59775+/33aTPnOFbN3OvvzPzmeMybvyC0bt/Z7JH+1W7b/jbUlFdIWbt6y+2cM8rxGUpq8QYbbPA9d84AAADgW75dA5ATm4IBRF9npo0NgOhMDoCc1prVJgdAZH50HKA01sB9jDTA83MAYlhn/memD400AAAAAOC73EEFKIlnQbuaaEAB8vl2AAAoJRtVdfxpq0Rqvo1QtKKnho1x2UuDHnxmfFFtLtjn/pfCnC8XFszrN2nqLJs+qkV1Td9nQvqkq8Kmv+5WkjOzat9jw3lX3BKGjRwXlixdWlLv98uW1YYPP/4ivDx+Wnjgydf9PRd5J190u3Wu1l0i+ZwrYwDYYIPW7ZKHWxtI0vq1S5fTXItLjeiwU3vFck7eevegvN0znDr9M8eqmZs2c843x+PFl98wd6RV2mnb/UJNeYWUtd5bVDlnlFNlidS77poBAADA6nyzBiAnNgUDiL7OTBsbANGZHAA5rTWrTQ6AyPzoOEBprIF/lmm+sQZ4fg5ADGvN44w0AAAAAOC73D0FKJlnQU+bakCB8fl2AAAoJa0qk71sgqIV7XDA8aG2rs5lLw0a8dp7RbfB4JARbxfM6/fgM+Nt+qgW0V/7PhsO+dM1oWKHg0tuVu554J/CFX+/K7zyxtuhvr6+xbz/z1+wOEyY/FEY9PzEcPMDI/2dF2G/OeQc6101XCJ5qitjANhgg6qqE39YVpmcYX0gSY2vct/jXYdLjSh90lWxnJN3DhySt3uENdM+dayaubnzFn1zPG64faC5I61SVbv9Q015hZS1O9q0c84o12coz7lrBgAAAKvzzRqAnNgUDCD6OjNtbABEZ3IA5LTWrDY5ACLzo+MApbMOvtJYAzw/ByCGdeYPMr1trAEAAAAAq3L3FKBkngW1y2QzY6CQ+Hw7AACUil9UddmoVSK10CYoWlGf/o+45GWdinXDxE8+n9/sr92cLxfa8FEl3zW3Px1Sx18aNtnuwJKZjb/c/sBw6EkXh34PPBFmfDzbIMhYsnR5mPLB7PDMyHfCbdWj/e0XSX+949nQZpfDrHm11n7RoWuFq2MA+KdWidT51geS1PhWXHu6Dpdyr+uJl8VyTt736NC83RecNPUTx6oZu/mBkaGurv6b43HM6VeYO9IqtW33u1BTXiFl7YHNt3HOKNf6u2MGAAAAq/NpaoCc2BQMIPo6M21sAERncgDktNasNjkAIvOj4wClsw7+caY5Rhvg+TkAMaw1DzLWAAAAAIBVuXMKUFLPggaabEAB8fl2AAAoFa0qk31sfqIVbbpjOnzx5XyXvKzT3PmLinKjwUeee7PZX7uXxr1v00eVbNf1fz50O/nq8MvtDyqJmbhJh67hsJMvCQ889lyYN3+BN/91WLasNtS8/2l4bNhE50IRdNIFt1n3ao3KKlNvuTIGgG9tVNXxp2WJ5CLrBElqXK3bdw433vui63Apx5LHXhLLOfnIkBfydi/wzckfO1bN2L1PvLba8Uj85mhzR1qlLRIdQ015hZS1wZtt7ZxRjiUvdccMAAAAVucT1AA5sSkYQPR1ZtrYAIjO5ADIaa1ZbXIAROZHxwFKay18ltEGeH4OQAzrzO9lGmO0AQAAAABfc+cUoKSeBW2eaZnpBhQIn28HAIBS8IsOXSvKKpNLbX6iFZ1zWR+Xu0Ry+0MvF+VmgzM+mdtsr1ltXX244+ExNn1UybVig+RjzroxtNn50KKfgxtXdQ4HnfCXcPeDT4U5c+d5s2+EL+YtDKNefz/0e8T7XSG3c+dTrX313c0ge7k6BoDVlSWSt1kjSFLju/ofT7kGl3Js/yP/Esv5OOS50Xm7//fGOzMdq2bsiRcnfXMsZs6abd5I36ki0SnUlFdIWXt+0y2dM8qtdskT3C0DAACA1fnUNEBObAoGEH2dmTY2AKIzOQByWmtWmxwAkfnRcYDSWgv/e6Z3jTfA83MAYlhr7pip3ngDAAAAAFZw1xSg5J4F3WC6AQXC59sBAKAUlCWSd9v8RCtq3b5zmPL+DJe7RPLYsIlFudngw0MnNNtrNnX6ZzZ8VMl19tUDQrt9jiv6GbjngX8Kfe58OHwye443+Dypq6sP7834vGjnRal3WZ/BYZMOB1oD65s2atf5t66OAeA79023SW6RmZP11gqS1LguuP4h1+BSju3V7axYzsfnRozN232/sW9Nd6yasVGvv//NsRj87EjzRvpOG1cmQ015hZS1lyq2cM4ox89UpfZ1twwAAABW59PSADmxKRhA9HVm2tgAiM7kAMhprVltcgBE5kfHAUpvPXyw8QZ4fg6Ae68AAAAAQJzcMQUouedA/1+mz004oAD4fDsAABS7jdt12rpVIllr8xOt6KhTL3OpS2Qvj59WtBsOzvhkbrO8ZoOHv2XDR5VMl9/yRNjz4D8X9dzb4YDjw3W33h8+nPmJN/WYfT53QRj+6rvhloGjnD8FVLdTrrEG1srKKlNLNqrq+F+ukAFgTWWJ5NPWC5LUuE6/7C7X31KO7dLltFjOx5GvTsjbvb4xEz5wrJqxSVNnfXMsLrv+TvNGWktvlW8aasorpHX26qabO1+UUz9PJLdypwwAAABW5xPSADmxKRhA9HVm2tgAiM7kAMhprWljV4Do/Og4QGmuiV8y4gDPzwGIYZ1ZnmmJEQcAAAAAuGMKUJLPgs4w4YAC4PPtAABQ7FpVJh+18Ym+btSrb7rUJbKp0z8r2g0HH3mu6f/Wv1q4JPS5f6QNH1X03Xjvi+Hw064Nm2x3YFHOuk13TIfuf/lbeOmVCaGurn7Nc3XBojBz1uzw9pRpYcLbU1f+50aMGR+eHj4mPP7syPDIkBfCfY8OXfk/f91Tw15e+Z9Z0eixE8OkydNW/t9Y8X+L1S1YtDSMeO29cMvAUc6nAujvd78Qttn7aOtghbJE6nlXxwCwdq0rO+1nvSBJjeuEHje7/pZybLsDTorlfJww6d283eMb9fr7jlUz9tHsed8ci67HnW/eSGvp9fLNQk15hbTOJlRs5nxRTv1ki+R/u1MGAAAAq/PJaICc2BQMIPo6M21sAERncgDktNasNjkAIvOj4wCluSbeIVO9MQd4fg5ADGvNXkYcAAAAAOBuKUBJPgf690xTTDmgmfl8OwAAFLPW7Tpv36oyVW/jE61o30PPcJlLTuYvWFLcmw5++mWTvl5jJ0632aOKvguvfzi03++Eopxze6W7hx5X3hLuHzQ03Hr3oHBxr77h5POuDV2P7RF27XxS2HavI8MmHbrm/f/vJtt1De32Pirs1uXk0Omoc8KR3S9d+d+jT/9HwuBnR4bxb00Jn38xr8XNkAWLloYRr70Xbhk4yrnVzJ111QBrYYVWiU49XCEDQIO+1yqReseaQZJy77BTe7n2lnKs3W+OjeV8nDptZt7u7b342lTHqhlbuHjZyuNQW1cX2uzczbyR1tKYijahprxCWmdvl28aWjtfFLGyytQXbpEBAADAmnyrBiAnNgUDiL7OTBsbANGZHAA5rTWrTQ6AyPzoOEDprovvN+YAz88BiGGd+eNMnxlzAAAAANCyuVsKULLPgrqackAz8/l2AAAoZq0SyedsfKKve3jIcJe55OyOh8cU7aaDg56f2GSvU319CHcPHmuzRxVtN977YkifdGXYuKpLUc641u07F/x/x81/3S3sle4efn/qZaHndf3C/YOGhgmT3g2LFi8p6Tkyf8GS8OzoGudZM/fbw3tYD7fwWic6bucKGQAatlFlpz9ZM0hS7iWPvcR1t5RjW+52eCzn4yez5+Ttnt7zY6Y4Vs1U34de/uY4vD1lmlkjNdCITbcINeUVUtZ+WZl0zihSZZXJ8e6QAQAAwJp8owYgJzYFA4i+zkwbGwDRmRwAOa01q00OgMj86DhA6a6LN860yKgDPD8HIIa1ZndjDgAAAABaNndKAUr6WdAIkw5oRj7fDgAAxaqsMrW3TU/0dVX7HhuWL691mUvOBg9/q6g3H/x49rwmeZ2mz5prs0cVbT1vGhQ67HeiedlMbVzVOeza+aTwp7/8LfS7/4nwxsQpYdmy5SU3T2bP+So88tybzrlm6prbnw6b7tTNOddSS6Tmb5BO/8BVMgA07CdbJP97xcy0dpCk3Nqr21muu6Ucq9jh4FjOxwULF+ftXt5TL73jWDVTK+6hfu2+R541a6QGGrbplqGmvELK2haJjs4ZRXyWknzcHTIAAABYk2/UAOTEpmAA0deZaWMDIDqTAyCntWa1yQEQmR8dByjttfGVRh3g+TkAMawzf5jpbaMOAAAAAFoud0oBSvpZUFWmOtMOaCY+3w4AAEXqe2WJ1Bibnujr+vR/xCUujTLmzQ+KevPBx4e/1SSv0zOjamz2qKKr94AR4bhzeodfbn+QWVlgle9wUOhyzHmh180DwuixE8OSpUtLZq5Mmzkn9B/0qnOwGVpxvju/WmrJZ1wiA0B2rRKp3tYNkpRbO3Q8yTW3lOM92dbtO+f9XNy4qnOor6/P2z28x4ZNdLyaqRfHTv3mOJx9WR+zRmqgpzfdKtSUV0hZ26bdAc4ZRX2W0sfdMQAAAFiTb9QA5MSmYADR15lpYwMgOpMDIKe1ZrXJARCZHx0HKO218X9l+sC4Azw/ByCGtebeRh0AAAAAtFzukgKU/LOg20w7oJn4fDsAABSjjdqlOtvsRF+31e6Hh/kLFrrEpVHen/F50W9A+PncBbG+RouXLg+3DBxls0cVVdf1fz7sfcg55mSRtOmO6dDtDxeG2+4ZFKZN/7joZ8vSZctXbg7b537nYlN244ARIbHPcc6pFlhZInmRq2QAyO7nlZ1/lZmd9dYPkhS9rfc4yjW3lNN92ediORe33OXQvN6/e+jZ8Y5XMzVxyrf3f/fpdppZIzXQ4M22DjXlFVLWOmy7v3NG0Uokz3N3DAAAANbkGzUAObEpGED0dWba2ACIzuQAyGmtWW1yAETmR8cBSn993M24Azw/ByCmteZDxh0AAAAAtEzukAKU/HOg/830uYkHNAOfbwcAgOJz8ffLKlNv2fBEX9fr5gEub2m0BYuWFv0GhENHT471NZow+SMbPaqouqT3Y6Hdb44xI4u4PbqeEq64oX8Y92ZNqK+vL9oZ89HseeGewWOdl03YmVfc4xxqibXvtJfrZACIJjM7h1o/SFL0frn9Qa63pRy66ranYjkXO+x3bF7v2903ZJzj1Ux9PHveP5/PLVwcNunQ1ayRGuihzdqGmvIKKWu/brefc0aRat0uebg7YwAAALAm36gByIlNwQCirzPTxgZAdCYHQE5rzWqTAyAyPzoO0DLWyMOMPMDzcwBiWGdunGmBkQcAAAAALY87pAAt4lnQKSYe0Ax8vh0AAIpNq8rUkTY70ddt/utuYc7ceS5vWS/9HnmlqDcgvPmBkWH+giWxvT4PPPm6jR5VNJ3as1+o2D5tRpZQO3U8Mfy1z4Aw+b3pRTljli2vDS++NtX52YTteuDpzp0WVFkiuWzDbff5kStlAIhmo0SnlDWEJOXW3/oPc70tReyS3oNiOQ/36Jrfz5jfNehVx6uZWrJ0+cpjMGLMeDNGWkf3bb5tqCmvkLK257a/dc4oUhu1T+3qzhgAAACsybdpAHJiUzCA6OvMtLEBEJ3JAZDTWrPa5ACIzI+OA7SMNfJWK37my9gDPD8HIIa15oVGHgAAAAC0PO6OArSI50DfzzTW1AOamM+3AwBAMamqOvGHZYnkezY70dddcu0dLm1Zb0+8OKnoNyF8adx7sbw2s+d8ZZNHFU1HnP630Lp9Z/OxhPvtIaeHfg88EeZ/tbDoZs30WXNDv0deca42xebNNz4aNq7q4pxpIZVVpl51pQwAOUinf9AqkfzAOkKSonfFrUNcb0sR63HdwFjOw45Hnp3Xe3W3P/Sy49UM9R/06jfH4Lpb7zdjpHV01+btQk15hZS1/bf5jXNGkdqwXeqXbowBAADAmnybBiAnNgUDiL7OTBsbANGZHAA5rTWrTQ6AyPzoOEDLWSdfb+wBnp8DEMM68z8yTTb2AAAAAKBlcXcUoMU8C/p1pnqTD2hCPt8OAADFpCyROtlGJ/q68h0OCrM+/dylLevtlTc/LPqNCG8dOCosXrIs76/NC2On2uhRBd+N974YksdebDa2oCp2SIdTL7g+THznvaKaNwsXLwuPDZvovG2COh7jPaHllOzjShkAcpOZoedaQ0hS9C64/iHX2lLEzrzinljOw0P+eFFe79PdfP9Ix6sZenz4W98cgxXH1IyRGq5vm0SoKa+QspbcZm/njLKXSC2vqjrxh+6KAQAAwJp8mwYgJzYFA4i+zkwbGwDRmRwAOa01q00OgMj86DhAy1kn/79MHxt9gOfnAMSw1uxk7AEAAABAy+LOKECLehZ0t8kHNCGfbwcAgGKxUVXH/ypLJD+22Ym+7pzL+risJS8++GhOSWxGOPat6Xl9XZbX1oXbH3rZRo8q6K6/a1jYtevp5mILLnX0ueGZF14J9fX1RTFzVvz3HD1+mvM35q7p+0yo2OFg50gLqHUidbyrZQDI+T7rT8sSqcXWEpIUrbOuute1thSx7pf0i+U8PO7Mq/L67MOxap5GvTFt5TGorasLW+x8iBkjraOb27QPNeUVUtbSbfd0zihK77sjBgAAAGvn2zQAObEpGED0dWba2ACIzuQAyGmtWW1yAETmR8cBWtZa+UijD/D8HICY1pqPGX0AAAAA0HK4KwrQop4D/TzTXNMPaCI+3w4AAMWiVWXqXJuc6Ot+UdUlfDBjlsta8mLh4mUlsRlhv0dfCbV19Xl7XWqmfWqTRxV01/V/PuzY6RRzUSvbK909PDxkeFheW1sUs2fKh5+FWweOci7H2OGnXevcaAGVbZusdLUMAI2515q801pCkqJ1ykW3u86WInbi+bfEch6eftHfPRMqgVY8d1ph4jvvmS9Slm7YoirUlFdIWTti6z2cM8peIvmcu2EAAACwdr5NA5ATm4IBRF9npo0NgOhMDoCc1prVJgdAZH50HKDlrZeHGn+A5+cAxLDO/EWmr4w/AAAAAGgZ3BUFaHHPgv5o+gFNxOfbAQCgGGzSLvXjssrkHBud6JtNLM+/ziUtedV/0KslsSHh5A9m5+01efS5N23yqILt2juGhg4H/MFM1Brt1PHEMPCx50NdXX3Bz55PP/8q3PnoK87pmLrhnuFhq92PdF6UcGWVqSVbbZX+d1fMAJC7Vu077Wg9IUnROubs3q6zpYgd/ecbYjkPL7j6H3m7J/fl/MWOVTM1+4t//k5UvweeMF+kLP11i+1CTXmC9Db3AAAgAElEQVSFlLXjtt7NOaMIz1OSt7sbBgAAAGvnmzQAObEpGED0dWba2ACIzuQAyGmtWW1yAETmR8cBWt56ebNMi41AwPNzAGJYa55p/AEAAABAy+COKECLew70/UwjTUCgCfh8OwAAFINWidRlNjnR17Vu3znUvPuhS1ry6skRb5fEhoQPPjM+L6+HTSVVyF3bb2io2u9EM1HrbO/0qWHYyHEFP3/mL1wSBjwxzrkdUydf8A/nQylvAplIjXW1DACNV1aZHG9NIUnZO6T7X11jSxFbcb7EcR5e1fuevN2Pm/3FV45VM9Tn/pGhtrZu5TE4+bxrzRcpS1dvuV2oKa+QsnbS1rs4Z5S9RKce7oQBAADA2vkmDUBObAoGEH2dmTY2AKIzOQByWmtWmxwAkfnRcYCWuWa+0AgEPD8HIIZ15g8yjTMCAQAAAKD0uSMK0CKfBbXNtMwUBGLm8+0AAFDoNty2y89aVSa/ssmJvu7YM650OUvejX1reslsTDjrs/nr/Xq8PH6aTR5VkF135/Ohw/5/NA8VuYNPvDC8+c7Ugp5BS5YuDw8PneAcj6HeA0aEyt8e71wo0coqU/9wxQwAjVdWmfyjNYUkZa/z8Ze6xpYi1vUPl8dyHt7U76G83Yub+emXjlUzNOCJ1745Btvtd5z5ImXpyi23CzXlFVLWTt9qZ+eMIjxPSR7iThgAAACsnW/SAOTEpmAA0deZaWMDIDqTAyCntWa1yQEQmR8dB2iZa+Z/zzTJGAQ8PwcghrVmh0y1xiAAAAAAlDZ3QwFa7LOgq0xBIGY+3w4AAIWurDJ1gw1OtGqvT5zscpa8+/DjL0pmY8JnRtWs12tRX18f7nz0FZs8quC6rv/zYfvfnWQWKud+UdUlXNSrb/hqwaKCnUPLa+vC4OFvOddjqHvPO5wHpVoieZorZgBovP/dfr//16oy+ZV1hSStu32P6OH6WorY735/YSzn4Z0Dh+TtPty0mXMcq2boqZfeWfn6z5w122yRInTZljuEmvIKKWtnb7WTc0ZZa92u8/buhAEAAMDa+SYNQE5sCgYQfZ2ZNjYAojM5AHJaa1abHACR+dFxgJa7bt41U71RCHh+DkAMa82/G4MAAAAAUNrcCQVosc+B/k+mqSYhECOfbwcAgEL288qum5RVppbY4ERfd8gfL3IpSywWL1lWMhsT3vzAyLBg0dJGvxbTZ821waMKrt4DRoTdDzrDLNR6VbnP0eHBx4cV7Cyqra0Ljw9/yzkfw/tH+31PcA6UYBslOu3jqhkA1k9ZInmbdYUkrbvdDjzD9bUUsX0OPTeW8/ChJ4bn7R7c5A9mO1bN0KsTP1z5+j/65ItmixShnltuH2rKK6Ss9fjVTs4ZZX+eUtXxp+6CAQAAwNr5Jg1ATmwKBhB9nZk2NgCiMzkAclprVpscAJH50XGAlr127msUAp6fAxDDOvO/M80wCgEAAACgdLkTCtCinwXtaxICMfL5dgAAKGStEql+NjfRqo18dYJLWWJz12NjS25zwsZ4ZlSNDR5VcB188tXmoPLWcWdeGT6b82VBzqLauvrwxIuTnPd57tSed/rbL8Fat/tdK1fNALB+Nqrq2N66QpLW3XYHnOTaWorYbgeeEct5+NSwMXm7/zbx3VmOVTP03vTPV77+f7nqNrNFitDFW+4QasorpKyd/6sdnTNad4nUfHfAAAAAoGG+RQOQE5uCAURfZ6aNDYDoTA6AnNaa1SYHQGR+dBygZa+d/yfTDOMQ8PwcgBjWmr8zCgEAAACgdLkLCtDinwXdbRoCMfH5dgAAKFRl2yS3aJVILbfBib7ud0ee5TK2icxfsLBF/rufeumdktmcsP+gV0N9fX3Or8HSZbXh1oGjbPCoguq0S+8Mrdt3NguV19rtfVR4bsTYgpxHtbV14bFhE53/eaz3gBGhw/5/9LdfQpUlkl+6agaAPN2HrUy9an0hSQ3Xdq+jXVtLEdux48mxnIcjX52Qt3tvr78z07FqhubOX7Ty9d+n22lmixShC3+1Y6gpr5CydtGWOzpntO7nKZXJ8e5+AQAAQMN8ewggJzYFA4i+zkwbGwDRmRwAOa01q00OgMj86DiA9XNH4xDw/ByAmNaa9xiHAAAAAFCa3AEFaPHPgX6caaaJCMTA59sBAKBQlSWSD9ncRKv2zAuvuIxtAnO//Co8/9JrLfLfPm7SjJLaoHDazDk5vwaTps6yuaMKqstvfjxU7HCwOahYat2+c7i4V9+wdOmygptJy2vrwoPPjvc+kMdOu/ROf/elVCI52lUzAOTHRonUcdYXktRwm/66m+tqKWKVvz0+lvNw/FtT8nbfbcybHzhWTdytA0eF+vr6MH/BwvCLqi5mixSh83+1Y6gpr5CydsmvdnDOKEvJR939AgAAgIb5BhFATmwKBhB9nZk2NgCiMzkAclprVpscAJH50XEAVqyhBxiJgOfnAMSwzrSZIgAAAACUKHdAAciMg04mIhADn28HAIBCtHFlskOrylS9jU30dXunT1252Rrx63HlLWHK+zNa5L99+qy5JbVJ4RMvTsr5NXhk6AQbPKpg6j1gRNgpeYo5qNjbp9tp4YMZswpuLi1cvCzcM3is94M8vqd02O9Ef/Olswnkna6cASA/Ntx2nx+VJZJfWl9I0tpr3b5zuDFzTenaWsre1nscFct5+O60/D23emnce45VEzfw6TdWvvYvjH7DXJEi1uNXO4Wa8gopa5dtuYNzRusukbrO3S8AAABomG8QAeTEpmAA0deZaWMDIDqTAyCntWa1yQEQmR8dB2DFGvonmT4xFgHPzwGIYa1pM0UAAAAAKEHufgLwr2dB95uKQJ75fDsAABSiVpXJZ2xsolV7/NmRLmGbwJT3Z4Rf7XZYqK2ra5H//sVLl5fUJoV97h8Z5i9cEvnf/+VXi23uqILqmLNvNAPVZG29x+HhpVcmFNxsWvHe3PfhMd4T8tTpl9/l771EKkskL3LlDAB5vB+bSN1kjSFJDder37Ouq6UIVeyYjuUc/GT2nLzdbxv2yhTHqol7bsyUla/9tbfcZ6ZIETvnVzuFmvIKKWtXbrmdc0brbKPKTn9y5wsAAAAa5ltEADmxKRhA9HVm2tgAiM7kAMhprVltcgBE5kfHAfh6HZ00FgHPzwGIaa35gLEIAAAAAKXFnU8A/vUc6CeZPjEZgTzy+XYAACg0rSuTu9nURKu250HdQ11dvUvYJnD4KT1D12N7tOjX4K7HXi2pjQpfefPDyP/2Ff9ZmzuqULri1iGhYvu0Oagm7RdVXUKfOx8uuNn08ex54ZYHRnpvyFMdDviDv/fS6EhXzwCQP60qO21rfSFJDXfpTYNdU0tZuvHeF0Pr9p1jOQcXLFyct3ttT498x/Fq4t6c/PHK1z594gVmihSxs7b6dagpr5CydvWW2zlntO4SqQPc+QIAAICG+RYRQE5sCgYQfZ2ZNjYAojM5AHJaa1abHACR+dFxAKylAc/PAYh7nfnTYDNFAAAAACgp7nwCsMqzIN8VBfLJ59sBAKDQlCVSL9vURKv2xNBRLl+bwLCR41a+3hf36tuiX4cnR7xdUhsV9h/0aqivr4/0b7978FibO6pg2vXA081ANVvnXNYnLF9eW1DzacXGs94b8tPpl9/l77wE2qh9aldXzwCQX60SqXHWGZK09npcN9A1tZSla25/Opbzb+OqzqGurj5v99kGD3/L8WriPp49LyyvrQ2b/7qbmSJF7Mytdg415RVS1npt2cE5o3U/T6nquKW7XgAAANAw3yQCyIlNwQCirzP9UCJADkwOgJzWmtUmB0BkfnQcgFXX0j/LNNt4BDw/ByCGtabPCAAAAABACXHXE4DvPAt60HQE8sTn2wEAoJBslOiUsqGJVu03B58W6uvrXb7GrLauLuyV7r7yNX94yPAW/Vq8OvHDktus8MOPv8j67/7o0y9t7KiC6cwr7jED1ewdc/oVYenSZQU1o54fM8V7RB7qPWBEaPebY/ydF3llHVIbu4IGgPwqS6ROts6QpLV3+mV3uaaWsnTJjY/Gcv5ttfvheb3H9vDQCY5XE9bn/pFh2fLaMGHSu+aJlMvaY6udQ015hZS1v23RwTmjdVW/ye67/6e7XgAAANAw3yYCyIlNwQCirzNtmAWQA5MDIKe1ZrXJARCZHx0H4Lvr6ZTxCHh+DkBMa80BxiMAAAAAlAZ3PAH4znOgn2b62IQE8sDn2wEAoHBc/P2yRPJNG5po1Z58frRL1yZw58Ah37zmU96f0aJfi/dnzim5DQufHVWT9d/9/JgpNndUQdR7wIhQue/xZqAKom5/uDAsXLS4YGZUbW1deODJ171X5KHjz+vjb7yIK6tMLl1x/egaGgDya5N2qR+XJZKLrDckac1OvuAfrqelLJ371/tjOf92Tv4xr/fY7nd/rUm7b8i4la973wGDzRMph7pvtUuoKa+Qsvb3LaqcM1rH85TUTHe8AAAAYN18mwggJzYFA4i+zkwbGwDRmRwAOa01q00OgMj86DgAa1tT32lEAp6fAxDDOvN/Mn1oRAIAAABA8XPHE4C1PAv6baZ6UxJYTz7fDgAAhaJVZacjbGiiVdun22mhvt79n7jNm78gbLPnkStf8zY7dwu1dXUt+vX4auGSktuw8NaBo8LSZbUN/puXLa8Ntz042uaOKohOPP9WM1AFVeroc1fOykIx58uFK9/XvV+sXzfcPTxsvvMh/saLtuQ0V9AAEI+yRPJuaw1JWrPjzr3J9bSUpe4974jl/Ot45Nl5vb9212OvOl5N2NDRk1e+7sf/+WrzRMqhU7baJdSUV0hZ671FlXNGDZdIvuRuFwAAAKybbxQB5MSmYADR15lpYwMgOpMDIKe1ZrXJARCZHx0HYG1r6v+b6V1jEvD8HIAY1pp7B5spAgAAAEDRc7cTgAaeBd1qSgLryefbAQCgEFRVnfjDskTyPRuaaNWeGvayy9Ym0PO6ft+85l2P7eEFyej78JiS27Tw7fc+afDfWzPtUxs7qiC64Z7hYcvdDjcDVXDte+gZYd78BQUzp956d5b3jDx0yJ+u8fddpJUlUmNcRQNAPFonOu9uvSFJa3bk6X9zLS1l6fhz+8Rz/nW/NK/31m6rHu14NWHjaz4KdXX1oe0eR5gnUg6dtPUuoaa8QsrazW3aO2fU8POUytRd7nYBAADAuvn2DEBObAoGEH2dmTY2AKIzOQByWmtWmxwAkfnRcQAaWlfvnKnWqAQ8PwcghrXm341JAAAAAChu7nQC0MBzoB9lmmxSAuvB59sBAKAQlCVSJ9vMRKu276FnhPr6epetMftw5iehfIeDvnndL+7V14uS8diwiSW3aeEjz73Zov69Ks6OPecmM1AFW6ejzgkLFy0umFk1ZMTb3jfWs2v6PhM22e5Af9/F2SBX0QAQm++VVaamWG9I0up1O+Vq19JSlg479dpYzr9TL7g+b/fUauvqHasm7qNPvwyTJk8zS6QcO3GrXUNNeYWUtdvaVDpn1GBllckL3OoCAACAdfPtGYCc2BQMIPo6M21sAERncgDktNasNjkAIvOj4wCsa239V6MS8PwcgBjWmf+ZaaJRCQAAAADFy51OANbxLKhDpmWmJdBIPt8OAADNrfWO6f9TVpmaaTMTrdrTw8e4ZG0Cx5155Wqv+8NDhntRMka9Ma0kNy6c99XiNf6tCxYtDX3uH2ljRzV7Nw4YEdruebQZqILu96deFpbX1hbErFqYef++/aGXvX+sZwf8/gJ/28W4CWQieZsraQCIT6tEpx7WHJK0el1OuNR1tJSlLidcFsv5d3Gvvnm9p+ZYNW1Lly0PfQcMNkukHDth611DTXmFlLW+bRLOGTX8PKV954Pd6QIAAIB18+0ZgJzYFAwg+jozbWwARGdyAOS01qw2OQAi86PjAKxrbf0fmcYbl4Dn5wDEsNaszLTUuAQAAACA4uQuJwBZngVdZloCjeTz7QAA0NxaJZLn2chEq7bvoWeE+vp6l6wxGz124hqv/ZT3Z3hhMiZ/MLskNy4cO3H6Gv/W1ybNsKmjCqKTLrjNDFRR1P0vfwt1dYWxTnn7vU+8f6xnPW96LLRu39nfdvHV05U0AMRnk+0O+HlZIrnMmkOSvu2A31/gOlrK0n5H/iWW8++G2wfm7X7anC8XOlZN2L2Pv7bydT/uzKvMEinHjt16t1BTXiFlrV+bhHNGDVbWLpVwpwsAAADWzbdnAHJiUzCA6OvMtLEBEJ3JAZDTWrPa5ACIzI+OA5Btfb1NpsVGJuD5OQAxrDXPNy4BAAAAoDi5wwlAludAP8z0qokJNILPtwMAQHPapF3qx2WVyTk2MtGqPfPCKy5XY1ZXVx/2P+zM1V73Njt3C7V1dV6cjC/mleamivcNGbfGv/XeJ16zsaOavd4DRoTEPseZgSqarup9T8HMrMeGTfQ+sp7teuDp/q6LbRPI9slTXE0DQLxaJZKDrTsk6dt+c8g5rqGlLO1+4BmxnH/9Bz6Zt3tpH336pWPVhD0zqmblM8m2exxhlkg5dvTWu4Wa8gopa3dt3s45o4aq33DbfX7kLhcAAACsm2/PAOTEpmAA0deZaWMDIDqTAyCntWa1yQEQmR8dByDKGvtkIxPw/ByAGNaZ38801MgEAAAAgOLjDicAEZ4FVWSaZ2oCOfL5dgAAaE6tEqnLbWKiVdv/sDNDfX29y9WY3T9o6Bqvfddje3hh/mXF3+Bt1aNLcgPDOV8u/ObfOeuz+TZ1VEH05yvvMQNVVLVu3zk8/uzIgphZX361ONzywCjvJevRWVfd6++6yNoo0flQV9MAEPN928rUgdYdkvRtux54umtoKUvb/+6kWM6/QU+PyNu9tPdmfO5YNWGvvzMzTJo8zRyRGtGRbXcPNeUVUtbubdPOOaO1VlaZmukOFwAAAGTn2zMAObEpGED0dWba2ACIzuQAyGmtWW1yAETmR8cBiLrOfsTYBDw/ByCGdeaGmWYZmwAAAABQXNzdBCDis6CDTU0gRz7fDgAAzeVnbTtt2KoytcBGJlq1oSPGulSN2YKFi0PlPkev8dpf3KuvF2cVDz47viQ3MHzlzQ+/+Te+8Oq7NnVUQbTnwWeZgSq62uzcLUye+mFBzKzRb0zzXrKetdvnOH/XxbQRZPvOHV1RA0C8Nttsv/8oq0zOsfaQpH+2Y8eTXT9LWdpm76NjOf9efPmNvN1HmzR1lmPVhM34ZG7oO2CwOSI1oiO23iPUlFdIWbtv822dM1r7s5TK1DB3uAAAACA735wByIlNwQCirzPTxgZAdCYHQE5rzWqTAyAyPzoOQNR19o8zfWB0Ap6fAxDDWnO/TPVGJwAAAAAUD3c2AcjhWdCdJieQA59vBwCA5tIqkeptExOt2v6HnRnq633GN27X3HTvWl//h4cM9+Ks4oWxU0tyA8N7n3ht5b+vtq4+9H34ZZs6qtm7+vanw8ZVXcxBFWW7pE4K8+YvaPaZtWxZbbjz0Ve8p6xHv//zDf6mi6jWlcndXFEDQBPcv61M9rH2kKR/Vrnv8a6fpSxtulO3WM6/ie+8l7f7aOMmzXCsmrDFS5eH48680hyRGtGhbfcINeUVUtYGbL6tc0ZrL5G6xd0tAAAAyM43ZwByYlMwgOjrzLSxARCdyQGQ01qz2uQAiMyPjgOQy1p7l0zLjU/A83MAYlhr/s3oBAAAAIDi4a4mADk8B/pRpndMTyAin28HAIDmsGG71C/LKpNLbWKiVXtuxFiXqTH7+JPPw2Y7HbzW13/K+zO8QKuYNHVWyW5i+NncBeHdDz+zoaMKokO7/9UMVFF3zOlXhPr6+mafW++894n3lPWoV79nwy+26+pvukgq2zZZ6aoaAOLXul3n7a09JOmfbb3HUa6fpXV044ARoXX7zrGcfzM+np23e2ij35jmeDVRdw8eG+rq6jPvn4ebI1Ij6rb1nqGmvELK2r1t2jlntPZnKZXJM93dAgAAgOx8cwYgJzYFA4i+zkwbGwDRmRwAOa01q00OgMj86DgAua63LzI+Ac/PAYhhnfnDTGOMTwAAAAAoDu5qApDjs6BtMi0yQYEIfL4dAACaQ6vKVH8bmGjV9j/szFBfX+8yNWan9Lh2ra9/m527hdq6Oi/QKj79/KuS3cjw5QkfhMdfmGRTRzV7vQeMCFvtfqQ5qKKv/8Anm31urVhG3TdknPeW9WifQ8/191wkta7stJmragBoovu4idQ71h+SlAqb73yIa2dpHf2177OxnX8LFy3O2z20Ya+863g1UU+99E54q+Z9M0RqZOm2e4aa8gopa/e02dY5o7VW1r5zR3e2AAAAIDvfnAHIiU3BAKKvM9PGBkB0JgdATmvNapMDIDI/Og5AruvtH2QaboQCnp8DEMNac7NM841QAAAAACh87mgC0IhnQd1NUCACn28HAICm9vNEcqtWiWStDUy0asNGjnOJGrPXJ04Ordt3Xuvr3/XYHl6g76itrQs33z+yJDcyvPPRV0r236bi6swr7jEDVRK12blb+HDmJ80+u6ZO/8x7y3p01lUD/D0XST9r22lDV9YA0DRaJZLnWX9IUir8Yruurp2lddTzpkGxnHu/3P7AvN4/e3LE245XE/XapBmh74DBZojUyA7cZq9QU14hZe2uzds5Z7TWyrZJbuHOFgAAAGTnmzMAObEpGED0dWba2ACIzuQAyGmtWW1yAETmR8cBaMyae8NMHxmjgOfnAMSw1kxlqjdGAQAAAKCwuZsJQCOfBfmsP5CNz7cDAEBTK0ukHrZ5iVat45FnuzyNWX19feh8zHkNHoOLe/X1Iq3FfUPG2fhQirH9jzzfHFTJ1PW480NdXfN/P2ngU294f2lkvQeMCFvv+Xt/z0VQRVX6f1xZA0DTaLVNl9atKpN11iCSlAo33vOC62epgc7r9UAs513lPkfn9d7ZI0MnOF5N1PRZc8NxZ15pfkiNrHPbvUNNeYWUtf5tEs4ZrVkitbyq6sQfurMFAAAA2fnWDEBObAoGEH2dmTY2AKIzOQByWmv6oW2A6PzoOACNXXfvnmm5UQp4fg5ADGvNG4xRAAAAAChs7mQC0MjnQP8309smKbAOPt8OAABNaePKZIdWlal6G5ho1V58+Q2XpzF79KkR6zwGDw8Z7kVai6GjJ9v4UIqpG+4ZHip2TJuDKqluHzC42WfXtJlzvMesR4edeq2/5SJow233+ZGrawBoOpn5O9QaRJJS4do7hrp2lhro1J53xnLe7ZXuntd7Z/cNGed4NVELFi0Nbfc4wvyQGllym71DTXmFlLU72yScM1qjssrUFHe0AAAAIBrfmgHIiU3BAKKvM9PGBkB0JgdATmvNapMDIDI/Og7A+qy9zzVKAc/PAYhhnfnDTC8ZpQAAAABQuNzJBGA9ngW1zbTANAUa4PPtAADQlGzAqu924PHnuzSN2ZKlS8MOBxy/zuMw5f0ZXqi1GF8z08aHUkx173mHOaiSa7OdDg7Tpn/c7PPr/idf9z7TyK7+x1Nh46ou/p4LvE123/0/XV0DQFPe0+10hDWIJKXC5bcMce0sNdAJPW6O5bzrelx+nyP2e/QVx6sJumvQq+GtmvfNDmk9SrXdK9SUV0hZu6NNO+eM1qisMjnEHS0AAACIxrdmAHJiUzCA6OvMtLEBEJ3JAZDTWrPa5ACIzI+OA7A+a+/vZXrYOAU8PwcghrVm60yzjVMAAAAAKEzuYgKwns+CDjVNgQb4fDsAADSVssrU3jYu0Xd75Y23XZrG7O99q9d5DNrs3C3U1tV5odZi5qdf2vxQiqm9DznHHFRJdvRplzf7/Hrn/U+9z6xHe6T/7G+5wNtg993/zRU2ADSdjao6/lerRGq+dYiklt7FNz7qullqoCNO/1ss591xZ16V1/tmtzww0vFqgp4Z+U64fcBgs0Naj7q03SvUlFdIWevbJuGc0RqVJZLXu6MFAAAA0fjWDEBObAoGEH2dmTY2AKIzOQByWmtWmxwAkfnRcQDWd/3940xTjVTA83MAYlhr7pWp1kgFAAAAgMLjDiYAeXgWdKuJCqyFz7cDAEAT+V5ZIjXGxiVatSP+1NNlacxmfz43bLnLoes8Dl2P7eGFasCSpcttfijF0N/6DwubbHegWaiS7cWX32jW+VVXVx/6D3rV+00jO+2y/v6OC7wV15cusQGgaZUlkndbh0hq6Z3Xa6DrZqmBDvzD5bGcd2f17J23e2bLltU6Vk3U+JqZ4dgzrjQ7pPXowG32CjXlFVLW+rZJOGe0RmWJzie5mwUAAADR+NYMQE5sCgYQfZ2ZNjYAojM5AHJaa1abHACR+dFxAPKxBt820yJjFfD8HIAY1poXGakAAAAAUHjcvQQgD8+B/iPTWFMV+A6fbwcAgKawUbtUZ5uWaNVat+8cJrw91WVpzFZsNpjtWFzUq68Xah3uemysDRClPHdqz35moUq6vdLdw/La2madX+MmzfB+08huvPfFsMUuh/lbLtQSyVpX2ADQ9Fq3T+1rLSKppXf21QNcN0sNdMBRF8Ry3l1xQ/+83S+bv2CxY9VEffTpvLD1HoebHdJ6dGDbPUNNeYWUtX+0qXTOaI3KKlN7u5sFAAAA0fjGDEBObAoGEH2dmTY2AKIzOQByWmtWmxwAkfnRcQDytQ4/xlgFPD8HIIZ15vczPWGsAgAAAEBhcfcSgDw9C/plps9MVmAVPt8OAACxS6d/UFaZesumJVq1E8662iVpzCZNnhZ+UdUl67F4eMhwL9Y6PDnibRsgSnlu/yP/YhbmUPkOB4VdUieFrsedH045/7rQ87p+4fYBg8O9Dz8Tqgc/Hx5/duTKRowZv7Inho5a+d6+4n9/y12PhhtuHxgu6tU3nHj2NSF19Lmhw37Hhk06dPXaxlz/gU826/xasnR5uHXgKO85jSx1fE9/xwVbss5FNgA0g913/7fMLP7EWkRSS5+KdY4AACAASURBVO6My+9yzSw10B7pP8dy3vXp/0je7pfN/uIrx6oJuuWBkeHNt6eaG9J6lm67Z6gpr5CydlubSueM1qisQ2pjN7MAAAAgGt+YAciJTcEAoq8z08YGQHQmB0BOa81qkwMgMj86DkA+1+I3Gq2A5+cAxLDO/O9Mk4xWAAAAACgc7lwCkMdnQbtkWma6Av/i8+0AABC3VonkUTYs0ar9oqpLmPzedJekMTv0pIsjHY8p78/wYq3D2InTbYIo5bHeA0aENjsfah420CbbdQ2djzkvXPjX20P14OfDO+9+EJbX1ub9va22ri58MntOGPP6pNB/4JPhnMv6hE5HnZM5Nt0chzy1zZ5HhnnzFzTrDBs6erL3nUZ2Xq8H/B0XcFVVJ/7QlTYANL2yRPJGaxFJLblTe/ZzzSw1UIcD/hDLeXffo0Pzdq9s+qy5jlUT9OAz48Nt9wwyN6T1rFvbPUNNeYWUtVu2qHTOaPUSqYUbbLDB99zJAgAAgGh8YwYgJzYFA4i+zkwbGwDRmRwAOa01q00OgMj86DgA+VyL/1umYcYr4Pk5ADGsNbfINNd4BQAAAIDC4K4lAHl+FnSa6Qr8i8+3AwBAnLbaKv3vrSpT79u0RKttPHnB9S5HYzZ0xNhIx6LNzt1CbV2dF2wd3p/xuU0QpTzW49qBZuF32riqczj8lJ7hsWdeCvPmL2jW97z6+vrwwYxZYfCzI0OPK28Je3Q9xTFaj3rdPKBZj+dHn37pfaeR9R4wImy52+H+jgu0Dbfd50eutgGg6bVq32lHaxFJLbmTLrzdNbPUQL/a7YhYzrunhr2ct3tlUz6Y7Vg1QS+Ne2/l/W5zQ1q/urXdM9SUV0hZu3mLSueMVqusMjneXSwAAACIzjdmAHJiUzCA6OvMtLEBEJ3JAZDTWrPa5ACIzI+OA5Dv9fhPMr1nxAKenwMQw1pz30y1RiwAAAAAND93LAGI4VlQXxMWCD7fDgAA8dqostOfbFiiVdtku67hgxmzXI7GaHltbdjzoO6RjkfXY3t4wbL48qvFNkGU8thBJ11lHn49Ezt0DWdefGP4cOYnBf0++OlnX4RHn3wxnH1Zn7BTxxMduxzactdDw5fzvmrW4zfgiXHeexpZlxMu9XdcoLXeKv2/rrYBoFl8ryyRnGo9IqmlduL5t7peltZS7wEjwsZVXWI578aMeytv98nenPKx49UETXr347DZTgebG9J6dmjbPUJNeYWUtZvbtHfOaPUSqfvdwgIAAIDofGMGICc2BQOIvs5MGxsA0ZkcADmtNatNDoDI/Og4AHGsydtlWmjMgufn3hEBiGGteaERCwAAAADNz91KAGJ4DvSfmV4xZaHF8/l2AACIy4bb7vOjskRqlg1LtGrnXn6zS9GY3TlwSOTjcXGvvl6wLOrrQ7iterSNEKU81X7fE8zDTF2POz9MeX9GUb4vvjFxSuh5Xb//n7078ZOiPBD/H5Lvfnf3t7k2+eZwBmNmNNxCDyCoCKLEBA+6B7RFUYzigWg8YvBAMXjFCzVGPCPeGOIoXgl4SySKeIAHHiMGLzTxVuRQjpn6lVndnbgKVTNV3T3d7/fr9fkDqJqq53mqin6CvkPHOJcRmnzhtUU9XwuefdW9p5VNOPs6f8Ml2kab7fB9K24AKI7quuxJ5iOSKrV9j5pivSx9TmdOvTO16y7JZ6iPLHzF+SpAd973iDFDSqBRPQYHjTW10no7v3Nv14z+qapM7nhPsAAAACA6/2MGIBabggFEn2fmDRsA0Rk5AGLNNRuMHACR+dFxANKal+8c1myoBe/PASDheWaHsOsMswAAAABQXJ5WApDSu6ANwl4z0kJF8307AACkpTozbILNStSy2v754G+vv20pmqJly1cGmR//LPI5mTFztoMWwfV3PG4jRCmhzVU79q6v+LHw8j/8KWhubv//H7qpqTmYt+Dp4NjTLg56DdnLXOcL6jJw9+D9pcuKdp6Wr1wVXDDd/ac1Tbl2TtBt69H+jkuw79eN2MiKGwCKY4M+O3UxH5FUqe39y3Otl6XP6Ve/vTG16y7J52pzHl3sfKXcZTfOC06bco0xQ0qgPbsPDhpraqX1NqVzH9eMPtvOnmABAABAdP63DEAsNgUDiD7PzBs2AKIzcgDEmms2GDkAIvOj4wCkOTc/w1AL3p8DQArzzK+GPWGoBQAAAIDi8aQSgBTfBQ0I+8hoCxXL9+0AAJCGH2y6439W1eXetVGJWjZp8lTL0JSdcu6Vsc7JoheWOGgR3PvQ8zZDlBLo4F9dWtHj4GZD9w0WPru4LO+Tq1evCW6+fU4wfJ9jzHk+p8kXXlvU83PjXU+4B7WyEQec7G+4BPt+JtvNqhsAiqc6k33UnERSJbbn4WdbK0uf0y9PvSaVa662fz5obm5O7BnZXXOfc75SbuZ9Twfb7/FLY4aUQKN7bB001tRK6+28zr1dM/rndyh19V09vQIAAIDo/G8ZgFhsCgYQfZ6ZN2wARGfkAIg112wwcgBE5kfHAUhzbv7lj3/ay3AL3p8DQApzzeqwVw23AAAAAFAcnlICkPK7oJFhzUZcqEi+bwcAgDRU1eVOtVGJWtZpwMjgrXfetwxN0cuvvv6PDQbjnJO1TU0OXASPN75mM0QpgXb42cSKHQd/vOthwetvvlMR98yFzy4Oxh51ZrBhn3pzoE/qMnD34IPlK4p2Tp587m/uQa3suLOv9zdcgm3Qa9gAq24AKOaz3+wR5iSSKrHdfn6mtbL0OR1w7MWpXHP9d9gv0Wdkt9y70PlKudkPNXouLCXU6B5bB401tdJ6O7dzH9eM/ruquuyqPn0O+BdPrwAAACA6/1sGIBabggFEn2fmDRsA0Rk5AGLNNRuMHACR+dFxANKen/972EOGXPD+HABSmGv2CVthyAUAAACAwvOEEoACvAs62YgLFcn37QAAkLQf9Bm+QXVdbrnNStSy08+/xhI0ZQcedWasczJizAQHLaIlr79nM0QpgboP3qsix8BBww8K3n53acXdOxe/9FpwyHHn2ET1ky655uainYsVH64KLph+v/tQK5py7ZyKvXeVdL2yO1p5A0DxVPXNbRiOyc3mJZIqrV3GnWatLH1Oexw6OZVrbtheRyX6jGz6rAXOV8pdef2dxgspoX7WfVDQWFMrrbfJXfq6ZvTfVdXlnvLkCgAAAOLxv2UAYrEpGED0eWbesAEQnZEDINZcs8HIARCZHx0HoBBz9A3CXjHsgvfnAJDCXHOXsCbDLgAAAAAUlqeTABTgPVCHsGuNulBxfN8OAABJq87kzrdRiVrWddCo4P2lyyxBUzT/ycagY+/6WOdl0uSpDlxEKz9abTNEqY2dcuEfK3IM7L/DfsFrr79V0ffQpxpfCEYddELFz4f6bb9fsGbt2qKdh5vuftK9qJXtPPYUc/qSa9ieVt4AUORnwHW5+81JJFVaw/c/yTpZ+pyy+6bz7G/fI05N9PnYZTfOc75S7ILp9we/PPF844WUUPt03zporKmV1tupXTZzzahl/nMMAAAAxOR/ywDEYlMwgOjzzLxhAyA6IwdArLlmg5EDIDLfVQJQqHl6XdhyQy94fw4AKcw1Jxp2AQAAAKCwPJkEoEDvgf4t7EEjL1QU37cDAECSvtdzWE1VXXaVTUrUst9O9XsMaWpubg7q9zkm9nmZMXO2gxfD5TZblNrU/hMurLjxr9eQvYLFL73mBvqJO/78UNB/h/0qek5006z7inb8FzyzxL2olU046zpz+hJrg7phP7f6BoDiqs5kDzUvkVRpZcdMsk6WPqchux2ZyjV3zK8vSuzZWFNzc3DBdOcqzf4wa0Gw+Y77Gy+khBrTfVDQWFMrrbcTuvZ3zahlJ3hqBQAAAPH4whsgFpuCAUSfZ+YNGwDRGTkAYs01/YgTQHR+dByAQs7Vdwxba/gF788BIOF5Zoewqw29AAAAAFA4nkwCUMB3Qd8Pe8noCxXD9+0AAJCkqrrcVTYoUct6DdkrWL7iQ8vPFN18+5xWnZtFLyxx8GK45d6FNkWU2tAOe02sqPFvwz71wZx5j7t5fsaKlR8GJ51z+T+OTyXOi4bufkTRjv07769wL2pl5107J9h4y5Hm9iVUVSZ3vNU3ABTXhnXZquq6bJO5iaRK6uPnW9bJ0v+u/04HpXLNnX3x9MSejS1fucq5Srnpf5prrJASbL/ug4LGmlppvR3XdXPXjP7n/Unv+l09tQIAAIB4fN0NEItNwQCizzPzhg2A6IwcALHmmg1GDoDI/Og4AIWer483/IL35wCQwjzzX8PuM/wCAAAAQGF4KglAgd8FbRq21AgMFcH37QAAkJQNew3rXp3JrrVJiVr2u2m3WHqmaPXqNcGWw8bGPi+dBowM1jY1OYAx/GX+CzZFlNpQzyH7VNT4d/r517hxrsODjz4V9N9hv4qcG338by+Wq2552P2olW23+9Hm9qW0KWQme54VOAAUX1Umd5+5iaRK6id7TLBGlj6n7oP3SuWamzbjjsSei73xzjLnKuVOv+A6Y4WUYPt3Hxg01tRK6+2orlu4ZvTfdew5vIcnVgAAABCPr7oBYrEpGED0eWbesAEQnZEDINZcs8HIARCZHx0HoBhz9nMNweD9OQCkMM/8RtgThmAAAAAASJ8nkgAU4V3Q4LCPjMJQ9nzfDgAASanK5G60QYla1nfomOCjVassPVN0wRUzWnVuRoyZ4ODF9Mzi122KKLWyM6feGXTsXV8x41/9PscEa9audeNcjw+WrQj2PeK0ipsfHTzhrKId89kPP++e1MrGHnuR+X0JFa49Z1iBA0AJPA/unT3Y3ERSJbXtyPHWyNLntNFmO6dyzd3x54cSey724qvvOFcpt9ehJxsrpAQ7oPvAoLGmVlpvv+i2pWtGn7w7ya7u1i3/fz2xAgAAgHh80Q0Qi03BAKLPM/OGDYDojBwAseaaDUYOgMj86DgAxZizfznsesMweH8OACnMNavDXjEMAwAAAEC6PI0EoEjvgnYLazISQ1nzfTsAACRhg971farrcs02KVHLrrnhdsvOFL397tKgy8DdW3VuJk2e6gDG9MY7y2yKKLWyQ0+6omLGvk222DV45bU33DQjam5uDn7zu+uCDfvUV8zfSE3/Xf4xhhfD4iVvuye1sjMuvT3o2LveHL9kNobMzbMKB4Di22izHb5fncmuNT+RVCltvfMvrJGlz3T2FXends09tnBRYs/Fnv7r685Xil3S8ECr31lK+vzGdhsYNNbUSuvt4G5buWb0X2Wyz3haBQAAAPH5mhsgFpuCAUSfZ+YNGwDRGTkAYs01G4wcAJH50XEAijVv/7ewOYZi8P4cAFKYa/YIe89QDAAAAADp8SQSgCK+CzrKSAxlzfftAACQhKq67CwblKhlWw4bG6xZs9ayM0UTTr2o1ednxszZDmBMa9Y2BRdMv9/miFIr2nnsKRUz/p176XVumK0w6565QU3/XSrm7+SCK28synH+8KM17kltqPfQ/c3zS6Rw/bnEKhwASuW5cO5e8xNJldKA+kOtj6XPdMKUW1K75l79+5uJPRd75KlXnK8UO/eK24wTUsKN675V0FhTK623A7oNdM3ov96dZLI3eFIFAAAA8fmKGyAWm4IBRJ9n5g0bANEZOQBizTUbjBwAkfnRcQCKOXf/RtiThmPw/hwAUphrDg77yHAMAAAAAOnwFBKAIr8LOtdoDGXL9+0AANBWG/QaNsDmJPpsN/xptiVnip5/cUmwUd8RrT4/i15Y4iC2wrQ/PmpzRKkVbT7s4IoY+7bY6YDgo1Wr3Cxb6f6Hnwg6D9itMjbhzh4YNDc3F+U4/37mfPelVpYfd6p5fqmUya35Uj7/FatxACi+qrrsgeYnkiqlj59xWR9L/9yRp1+byvXWsXd9sHr1msSeid33yF+drxQbf/Ilxgkp4Q7utlXQWFMrrbd9um/tmtEnZU/ypAoAAADi8wU3QCw2BQOIPs/MGzYAojNyAMSaazYYOQAi86PjABR7/t4x7BVDMnh/DgApzDV3C2syJAMAAABA8jyBBKDI74G+HHaDERnKku/bAQCgrarqcvfamEQt22bnnwdrm3xTm6bRh5zU6vPTacBI56eVZv3lGZsjSjE779o5QU3/XSpi/Lvjzw+5UbbR/Ccb/zFOVcLfy/0PP1GUY/xnGwi3uqPPnG6uX0JtWJetshoHgOL7Xs/h363O5NaYn0iqhDbf6SDrY+kzjZt4SSrXW4/Be3q/047acc8jjRNSwh3cbaugsaZWWm+juw92zegfVdVld/OkCgAAAOLz9TZALDYFA4g+z8wbNgCiM3IAxJprNhg5ACLzo+MAlMIcPhP2vmEZvD8HgBTmmkcakgEAAAAgeZ4+AlAC74H+PewvRmUoO75vBwCAtqiqyw2xMYk+28y751pupuj+h59o0/kZMWaCg9hKDz35ss0RpZhN+u1NFTH27bL/cW6SCZkz7/Ggpv8uZf83M/7EKUU5voteetO9qZWdN+2+oHbzvPl+qdQn29+KHABK5hnxveYnkiqh/juNsz6WPtPow89J5XrbZpdDEn0mdsOdTzhfKXXu1bODjTYbYZyQEu7n3bYKGmtqpfU2svs2rhl90rCenlIBAABAfL7cBojFpmAA0eeZecMGQHRGDoBYc80GIwdAZH50HIBSmcdvEbbc0AzenwNACnPN0w3LAAAAAJAsTx4BKJH3QF8Pm29khrLi+3YAAGiL6kx2rk1J1LKhux8RNDc3W26mpKmp+R/HuC3naNLkqQ5kK/31lbdskCjFbOyxF1XE+Hf/w0+4SSboj3feH3TsXV/WfzNdB40KPlq1quDHdtmKj9yb2tC2I8eb85dIHXtl97AiB4DSsEHdsJ+bn0iqhDbbYZy1sfSZRhxwcirX28ixxyf6TOyaWx9xvlLqxPOuN0ZIKXRo1wFBY02ttN5GbLqta0ZBdSa7dqOtt/43T6kAAAAgPl9tA8RiUzCA6PPMvGEDIDojB0CsuWaDkQMgMj86DkApzeW3C/vI8AzenwNAwvPMDmEXG5oBAAAAIDmePAJQQu+CvhP2rNEZyobv2wEAoLWqe2V3tDGJPtu998+31EzR72+8s83naMbM2Q5kK723dKUNEqWYZcecUPZjX27vo90gU3D6+deU/d/OrHvmFuXYXn7jQ+5PrWz/Yy405y+RqjLZX1mVA0Bp6Nhrx+pwfG42R5FU7vXd/kBrY+kzbbfHMalcbz8/7pxEn4ddfN0Dzldaz8uOPNsYIaXQ4d0GBI01tdJ6G7bpENeMwrLPeUIFAAAAreOLbYBYbAoGEH2emTdsAERn5ACINddsMHIAROZHxwEotfn8iLC1hmjw/hwAEp5nfjlsuuEZAAAAAJLhqSMAJfYuqGPYS0ZoKAu+bwcAgFbqUJ3JzbcpiVpWv88xlpkpWr7iw6Buu73bfJ4WvbDEwWyl5uZmGy9KMdtshwPLfvy79/75bpApWNvUFIw66ISy/tvZf/zpRTm2f5z9lPtTKxt/2jTz/hKpKpO92rIcAEpHVSb3oDmKpHKv79ADrI2lz7Rl7pBUrreTf3NFYs/CVq1e41yl+Q5g+/2MEVIKHd5ty6CxplZab0M3/bFrRmHZmzydAgAAgNbxxTZALDYFA4g+z8wbNgCiM3IAxJprNhg5ACLzo+MAlOKc/kBDNHh/DgApzDP/JWymIRoAAAAA2s4TRwBK8F3Qj8JeN0pDu+f7dgAAaI3qumEjbEiiz/bgo09ZZqbozAuubfM56jRgZLC2qcnBbIPrbnvMJolSxM6bdl+wUd+dy3rs+8luh7sxpuiNt94Nug/eo2z/fmr754MVKz8s+HGd98RL7lGtbPxp08z7S2eDyAeszAGgdFT1yh5pfiKp3Os9dH9rY+kz9RwyJpXr7eKrb07sWdh7S1c6Vyl18vm3Gh+klDqi24CgsaZWWm9Dem7nmlFQncmd7OkUAAAAtI6vtQFisSkYQPR5Zt6wARCdkQMg1lyzwcgBEJkfHQegVOf1xxqmwftzAEhhnvnvYXMM0wAAAADQNp42AlCi74J6hb1npIZ2zfftAAAQ36QvV2VyT9iURC3bfdwkS8wU/f2Nt4MfbTmyzedpxJgJDmYb3f3gczZKlCI26bc3lf34d80Nt7sxpuyGP80u67+h2+6dV/Bj+tdX3nKPamXjT5tm7l86vW5tDgCl43s9h9WYn0gq9+p+up+1sfSZavvlU7nebpp1X2LPwl57433nKqUOnnih8UFKqaO6bhE01tRK621gz5+6ZvRxO3s6BQAAAK3jS22AWGwKBhB9npk3bABEZ+QAiDXXbDByAETmR8cBKOW5/RmGavD+HABSmGd+M2y+oRoAAAAAWs+TRgBK+F3QoLAVRmtot3zfDgAAcXXM5EbZjEQt69i7Pnhs4SJLzBQdOvE3iZyrSZOnOpht9Nizr9ooUYrYuOMvLevxr/OA3YJly1e6MRbAqIMmle3f0fgTpxT8eC5d9qF7VCsbf9o08/8S6tuds1+zQgeA0lFVl33cHEVSOZfZbl9rY6lFZ195T2rX218eeiKxZ2GLXnrT+Uqp7fc40vggpdSxXTcPGmtqpfW2ea+hrhkFVT3rO3kyBQAAAK3jK22AWGwKBhB9npk3bABEZ+QAiDXXbDByAETmR8cBKPX5/RmGa/D+HABSmGd+M2y+4RoAAAAAWsdTRgBK/F3QkDAbZ0L75Pt2AACIJZ//SnVdrtGGJGrZmF+canmZooXPLg427FOfyLmaMXO2A9pGr/z9PRslShHbeeyvy3r8O/qUC90UC+TZ519KbCwstXoN2Stoamou+DG95Pq57lOtaPxp08z/S6iOPYf3sEgHgNJRlcn+yhxFUjnXa7t9rY2lFk367U2pXW+LXliS2HOwxxtfc75S6DdX3Rv8sN8uxgcppSZ16R801tRK6613r+1dM1r+pS9N+rInUwAAANA6vtIGiMWmYADR55l5wwZAdEYOgFhzzQYjB0BkfnQcgFKf33cIO9+QDd6fA0AKc83vhC00ZAMAAABAfJ4wAtAO3gVtF/ahURvaHd+3AwBAHFV12TE2I1HLNuxTHzz7/EuWlykaOfb4ktyEsFKtWLnKZolSxAbt/IuyHgOffPavbooFdNjx55bt39JjCxcV/Hhed9tj7lOt6KgzplsDlFAd64YNtUoHgNLRsefwHuYoksq5nkPGWBtLLfrFKVeldr299/6yxJ6DzX38RecrhQ496Qpjg5Rip3TpFzTW1ErrrWuvnVwzFV5VJvegp1IAAADQer7QBojFpmAA0eeZecMGQHRGDoBYc80GIwdAZH50HID2MMfvEHahYRu8PweAFOaa3w172rANAAAAAPF4ughAO3kXNDTsIyM3tCu+bwcAgKj69DngX6rrci/YkEQtO3jCWZaWKbrt3gcTO1edBowM1jY1OagJmHrDgzZMlCLUZdCeZTv+bT38YDfDAnvh5deCDfvUl+Xf02+nFv63q+54oNF9qhWdeP7N1gClVK/s/lbqAFBawjG60TxFUrnWc8g+1sZSi8YcdX4q11pN/12C5ubmxJ6D3T1vkfOVQjuPPcnYIKXYGZ03CxpraqX19sO6rGumwqvKZC/2RAoAAABazxfaALHYFAwg+jwzb9gAiM7IARBrrtlg5ACIzI+OA9Be5vkdwi4xdIP35wCQwlzze2HPGroBAAAAIDpPFgFoR++C6sNWG72h3fB9OwAARFWVyR1kMxK1bKO+I4LFL71maZmSNWvWBgPrxyV2vkaMmeCgJuSGO5+wYaK0ns667K6yHgN/87vr3AyLYM+fn1iWf0+7j5tU8GP50JMvu1e1orOvuNs6oLQ60UodAErtGXL2dHMUSeVaj232tjaWWrTLgaemcq3132G/RJ+D3Tr7KecrhXpu+zNjg5Ri53TuGzTW1Err7OmajV0vCj7+ns8TKQAAAGg9X2cDxGJTMIDo88y8YQMgOiMHQKy5ZoORAyAyPzoOQHua63857BrDN3h/DgApzDU7hi02fAMAAABANJ4qAtDO3gXtHLbGCA7tgu/bAQAgio6b5/+9KpN7zWYkatn4E6dYVqbo0mtvTfR8TZo81UFNyD3zFtkwUVpPR585vazHwMUvveZmWASzH5hfln9PnQaMDNasWVvQY7nopTfdq1rZRpvtbC1QKmVyl1mtA0BpqcrktjRPkVSudR+8l3Wx1KLt9jgmlWttxJgJiT4Hmz5rgfOVcJN+e5NxQUq5KZ37BI01tdI6e6S2k+tFwQZ96rfyRAoAAABaz9fZALHYFAwg+jwzb9gAiM7IARBrrtlg5ACIzI+OA9De5vtfCZtmCAfvzwEghbnmRmGLDeEAAAAAsH6eKALQDt8FjQxbYxSHkuf7dgAAiKIqk/uljUjUsh/22zl4+dXXLStT8v7SZUGPwXsmes5mzJztwCZkwbOv2jRRWk/7H3Nh2Y6B2486wo2wSJqamoO67fYuy7+rBQufK+ixfPPdZe5VrezjTdStB0ql7B1W6wBQaiZ9ORynXzdPkVSOdR882rpYalH/ncalcq0dctw5iT4Hu/zGec5Xwu15+NnGBSnlLupcFzTW1ErrbM7GnV0vav5Wv6Ff9zwKAAAAWs/X2QCx2BQMIPo8M2/YAIjOyAEQa67ZYOQAiMyPjgPQHuf8X/74v0UaxsH7cwBIYa75/bCnDeMAAAAAsG6eJgLQTt8F7RT2kZEcSprv2wEAYH2+0y3/1eq67Js2IlHLJp7xO0vKFE2aPDXxc7bohSUObEJefPUdmyZK62nE2FPKdgycctn1boRFdPQpF5bl39UFV95Y0OP44ao17lWt3jD6IOuB0ulpK3YAKD3Vmdzl5imSyrGug/a0LpZa9PE1kca1dup5Vyf2DKypqTm4YLpzlXQDhx9iXJBSbmqnTNBYUyuts9s36ep60QueRAEAAEDb+DIbIBabCLdlKgAAIABJREFUggFEn2fmDRsA0Rk5AGLNNRuMHACR+dFxANrrvL9D2PmGcvD+HABSmGt+L2yhoRwAAAAAvpgniQC043dBO4R9aDSHkuX7dgAAWJ/qTO5Ym5CoZZtssWvw5tvvWlKm5OVXXw9q+u+S6DnrNGBksLapycFNyPsffGjTRGk9Dd7liLIdB59Z9KIbYRH9ee5jZfl3deBRZxb8WF7SMNf9qhUN2e1Ia4JSKZN7y4odAErPBr1y9eYqksqxLoP2tC6WPum8afcFG/auT+Vau/K6WYk9/1q6zPucpDv7inuCH/QdblyQUu7qTr2CxppaaZ3dvEkP10vFl73JkygAAABoG19mA8RiUzCA6PPMvGEDIDojB0CsuWaDkQMgMj86DkB7nvt3CPut4Ry8PweAFOaa3w170nAOAAAAAJ/PU0QA2vm7oKFhK43oUJJ83w4AAOuyUa/cN6vqcu/ahEQt+/W5V1pOpmjfI05L/JyNGDPBgU1Qc3NzcNF1D9g8UVpHmw7ZuyzHwL5Dx/zjHkDxfPjRquCH/XYuu7+tgfXjCn4sp/3xUferVpTd9wRrgtLZLLLpS/n8V6zcAaC0fK/ndv9Rlcl9aK4iqdzqvNUo62Lpk065aGZq19pdcx5J7PnXq2+873wl3M8nXWZMkArQ73/UM2isqZXW2cd/J66Xiu8ET6IAAACgbXyZDRCLTcEAos8z84YNgOiMHACx5poNRg6AyPzoOADtff7fIewcQzp4fw4AKcw1/zPsEUM6AAAAAPxvniACUAbvgrYOW2ZUh5Lj+3YAAFiX6rrciTYgUcu6DNw9ePf9DywnU/LI488GHXvXJ37eJk2e6uAm7Pcz59s8UfqCzpt2X7Bhn+FlOQ4edfIFboAlYMfR48vub2vDPvXB8hUfFvQ43nTPk+5ZrWjUoZOtC0qo7/Uc/l0rdwAoPVV1uT+Zq0gqtzoP3MO6WPqko86Yntq19syiFxN7/tX44hvOV8LtsNdEY4JUgK7/0aZBY02ttM4u69TL9VLxDRvhKRQAAAC0ja+yAWKxKRhA9Hlm3rABEJ2RAyDWXLPByAEQmR8dB6Bc1gFnGNbB+3MASGGe+a2wRwzrAAAAAPDPPD0EoEzeBQ0OW2Zkh5Li+3YAAPgiG/XKfbMqk33fBiRq2dkXT7eUTElzc3Oww57jUzlvM2bOdoATdttfnrV5ovQFnXj+zWU7Dt4+e54bYAk44azLyvLv69EnGgt6HO+a+5x7VivaZ/x51gUl1Ia9hnW3egeA0lPdu/4AcxVJ5VbXQXtaF0ufNPa4i1O71pZ+sDyx51+PPPWK85VgU66dE3QZtIcxQSpAN2/SI2isqZXW2QWderteKv0dSZ/6jT2FAgAAgLbxVTZALDYFA4g+z8wbNgCiM3IAxJprNhg5ACLzo+MAlNNa4OiwZsM7eH8OAAnPM78adpehHQAAAAD+hyeHAJTRu6C+YW8Z3aFk+L4dAAC+SHVd7gQbkKhlm24zOvhg+QpLyZTc8KfZqZ27RS8scYATNu/Jl2ygKH1Bh550RVmOgxv1HWEcLBF/uOXusvwb+/2Ndxb0OD74+IvuWa3ogGMvsjYopXrlBlu9A0Dp2bAuWxWO1c3mK5LKqe6DR1sXS5+0+yFnpnKdddlq90Sff81++HnnK8Em/uYG44FUoGZu0j1orKmV1tlZXfq6Xiq5TO6DL33pSx08hQIAAIC28VU2QCw2BQOIPs/MGzYAojNyAMSaazYYOQAi86PjAJTbeuDAsCZDPHh/DgAJzzP/NWyG4R0AAAAA/ounhgCU2bugrmE2MobS4Pt2AAD4PBv1yn2zqi77nk1I1LILr7zRMjIlH360Kui3/X6pnLdOA0YGa5v8/7ekPffimzZQlL6gPQ8/pyzHwR1Hj3fzKxFzH1lYln9jp025pqDH8fHGV92zWtHPJ021NiipTSOz/nM5AJSoqrrcw+Yrksqp7tv8zLpY+qQd9z4+lets2/whiT7/unX2U85Xgo06dLLxQCpQd2zSLWisqZXW2Uld+rteKrrsA54+AQAAQNv5KhsgFt9tA0SfZ+YNGwDRGTkAYs01G4wcAJH50XEAynFNsFvYasM8eH8OAAnPM78SdrkhHgAAAAB83w5AWb4L+mHYIqM8FJ3v2wEA4PNUZbKTbD6ilmV+vHew8sOPLCNTcu6l16V27kaMmeAAp+DNd5bZQFH6gnbYa2JZjoW/PvdKN78S8erf3yzLv7GDjjmroMfx2RfecM9qRb845SrrgxKqqi57oBU8AJToM+a67ETzFUnl1KZD9rYulj5p4IjDUrnORh9yUqLPv34/c77zlWD9dxpnPJAK1OxNugSNNbXSOpvQdXPXS0WXvdDTJwAAAGg7X2UDxGJTMIDo88y8YQMgOiMHQKy5ZoORAyAyPzoOQLmuC3YIW2GoB+/PASDheWaHsHMM8wAAAABUOk8LASjTd0HfD3vcSA9F5ft2AAD4rNo++W9U1WXfs/mIWnbZ7/9oCZmSt955P+iy1e6pnbtJk6c6yClYvWatDRSlL9xY86CyHAvvvX++m1+JWNvUFHTsXV92f2M7jT6yoMfxxVffcc9qRUefOd36oITaoC53lFU8AJSmDfrs1Nt8RVI51evHY6yLpU/qOWRMKtfZMb++KNHnX7+7fq7zlVBnXnZnsGEZPpOVSrW/1HYOGmtqpXX2i25bul4quKq67IGePgEAAEDb+SobIBabggFEn2fmDRsA0Rk5AGLNNRuMHACR+dFxAMp5bTAw7H3DPXh/DgApzDWPNtQDAAAAUMk8JQSgjN8DfTPsAaM9FI3v2wEA4LOqMtlf2XxELes7dEzw0apVlpApGX/S+amevxkzZzvIKbnq5odtpCh9Tj/acreyGws36jsiWLZ8pRtfCdlki13L7u8s8+OfFfQY/v2tpe5ZrWjib26wRiilMrlTrOIBoGR1qMpk/2bOIqls1u3b7WtdLIVNuXZO8MN+u6RynZ039frEnn19tGqN85VgY4+9yFggFbB5tZ2CxppaaZ2N7TbQ9VLBVdXVb+HREwAAALSdL7IBYrEpGED0eWbesAEQnZEDINZcs8HIARCZHx0HoNzXB5mw1wz54P05AKQw1zwkrMmQDwAAAEAl8oQQgDJ/D/QfYTON+FAUvm8HAICWavvkv1FVl3vX5iNq2dXX32b5mJLnFr8SbNR3RKrnb9ELSxzolNxy70IbKUqfafLld5blWPiT3Q530ysxPbcdXXZ/Zx/PCZqbmwt2DN9dutJ9qxWdeP4t1giltGlkJnuelTwAlK7qTO5ycxZJ5VLvn+5vXSyFnTk1vWfAM2bOTuzZ19vvLXe+EmybXccbC6QCNr/2R0FjTa20zvbqsbXrpWLLNn2nW/6rnjwBAABA2/kiGyAWm4IBRJ9n5g0bANEZOQBizTUbjBwAkfnRcQAqYY1QHfaEYR+8PweAFOaa9WErDfsAAAAAVBpPBwGogPdAXwm72KgPBef7dgAAaKkqkzvexiNq2RY7HRCsXr3G8jElow6alOr56zRgZLC2qcmBTsmcRxfbSFH6TMdMvq4sx8OjT7nQTa/EbL7j/mX5t/bB8hUFO4YrP1ztvtWKTrvkNuuE0upKK3kAKF3VmWzefEVSudR36AHWxVLYxHOuT+06mzf/qcSefb346jvOV0Kde/XsoKbfLsYCqYA9Wbtx0FhTK62zXXts63qp3Bo9dQIAAIBk+CIbIBabggFEn2fmDRsA0Rk5AGLNNRuMHACR+dFxACplnfCfYfcZ+sH7cwBIYa65edhbhn4AAAAAKokngwBU0Lugo8Oajf5QML5vBwCAT32r39CvV9Vl37HxiFp23S33WDqm5J6/PJr6+RsxZoIDnaKFz//dZorSZxo38RLjIQWx2dB9y/Jvbcnf3izYMVzb1OS+1YpOu2SWdUIJVZXJ3Wg1DwClq7ZP/htVmexq8xZJ5dBmOxxoXSyFHXLC5e3i2djCRX9zvhLqsJOvNA5IBe6Zmo2DxppaaZ3ttOmPXS+V+m6kLjfNUycAAABIhi+yAWKxKRhA9Hlm3rABEJ2RAyDWXLPByAEQmR8dB6CS1gr/GvYHwz94fw4AKcw1Nwl73vAPAAAAQKXwVBCACnsXtHfYajMAKAjftwMAwKeqMrnjbTyilg2sHxesWbvW0jEFa5uagm3zh6R+DidNnupgp+jV19+3maL0mUYdOrksx8TnFr/ipldiem47uiz/1p5qfKGgx/GC6e5bcTvtktusFUpp48hM7h6reQAo+efO95m3SCqH+u80zrpYCtvriHNTucZ+0Gd4sGZNcu8l5z7+ovOVUDv8bKJxQCpgP6jLBo01tdJ6G9TzJ66ZSn03Upc9whMnAAAASIYvsgFisSkYQPR5Zt6wARCdkQMg1lyzwcgBEJkfHQeg0tYLHcLONAUA788BIIW55vfD5psCAAAAAFAJPBEEoALfBW0X9oFZAKTO9+0AAPCxb/Ub+vWquuw7Nh5Ry26adZ9lY0quaritIOdwxszZDnaKVny4ymaKUgVsrtlpwMigqanZTa/EfHxeynH+Nf/JxoIex4uve8C9K2anXjLLWqGUymTnWtEDQGkLx+yjzVsklUObDzvYulgKq9/vpFSusT4/HZPoc687Hmh0vhJoyrVzgk5bjTIOSAVs48ywoLGmVlpvdb12cM1UaB0z9Vt74gQAAADJ8EU2QCw2BQOIPs/MGzYAojNyAMSaazYYOQAi86PjAFTqumF8WJOpAHh/DgAJzzO/HnaHaQAAAAAA5c7TQAAq9F3QZmF/NxOAVPm+HQAAPlZVl51o0xG1bJtdDgmampotG1OwbPnKIPPjvQtyHhe9sMQBT9mlNzxoU0WpRQPqDy27MTH7s6Pc7ErM6tVrgo6968tyDvbI488W9FhONY7F7tcXz7ReKKUyuflW9ABQ2qrrhvU0b5FUDm2R+7l1sRS2za7j28Vz2Bl3PeF8JdAxk68zBkgFrktmx6CxplZab5vUDXPNVGTZpm/1G/p1T5wAAAAgGb7KBojFpmAA0eeZecMGQHRGDoBYc80GIwdAZH50HIBKXjtsH7bUdAC8PweAhOeZXwk7z1QAAAAAgHLmSSAAFfwuqDpsvtkApMb37QAA8PFGG1V12XdsOqKWzbx7riVjSn7926sKcg47DRgZrG1qcsBTdv2dj9tUUWpRj232Lrsx8ehTLnSzKzGvvPZG2c7BHn7smYIeyytuesi9K2anXPQn64USqqou95RVPQCUvA5Vddkl5i6S2nsD6g+xLpbC+gw9IJVrbNzRkxN97nXVzQ87Xwm089hfGwOkAtej145BY02ttM6ertnY9VK5NXrUBAAAAMnxVTZALDYFA4g+z8wbNgCiM3IAxJprNhg5ACLzo+MAVPr6oWfYy6YE4P05AKQw1zwgbI0pAQAAAADlyBNAACr8PdBXw24xI4BU+L4dAACq6rITbTiilg3JHxo0NTVbMqbgtdffCjbZYteCnMcRYyY44AVw97xFNlWUPmnKtXOCH2w2ouzGxSuvm+VmV2IefuyZsp2HPRT+2wrpmlsfcf+K2SkX/tGaoYSqyuSet6oHgPbwDDr3O3MXSe29rYYfZl0shdVunk/lGvv1uVcm9syrqbk5uHD6/c5XAvUcso8xQCpwvXttHzTW1Err7MHaTq6XSn0vUpeb5kkTAAAAJMdX2QCx2BQMIPo8M2/YAIjOyAEQa67ZYOQAiMyPjgNgDREEVWGPmBaA9+cAkMJc86dh75sWAAAAAFBuPP0DwHug4Cthp5sVQOJ83w4AQGX7dufs16oz2bdtOqKW3Xnfw5aLKTnomLMKdh4nTZ7qgBfA/GeW2FRR+qTTLplVluPiQ48942ZXYmbMnF2287BHn2gs6LH8/cz57l8xO/nCW60ZSqlM9hUrewAofdV1w0aYu0hq7w3a+RfWxar4zpx6Z2rX2OXT/5TYM68PVnzkfCXQieff4v4vFaF+vbYPGmtqpXV2xybdXC8VWlVd9ghPmgAAACA5vsoGiMWmYADR55l5wwZAdEYOgFhzzQYjB0BkfnQcAP5rHfEfYTeaGoD35wCQwlyzR9iLpgYAAAAAlBNP/gDgv98F7Re22uwAEuP7dgAAKlt1JnesDUfUsp1GH2mpmJIFC58LOvauL9i5nDFztoNeAC8sedvGitInHTP5D2U3Ln583/5g2Qo3uxJzyrlXlu1c7LnFrxT0WE6ftcD9K2YnnX+rdUNJlX3Dyh4ASt9GvXLfrM7k1pi7SGrPDd7lCOtiVXwTzroutWvs9tnzEnvm9dqbS52vBNrz8HPc/6UiNLDnT4PGmlppnc3YpIfrpULrmKnf2pMmAAAASI6vsgFisSkYQPR5Zt6wARCdkQMg1lyzwcgBEJkfHQeA/1lLfDnsdNMD8P4cAFKYa34v7EHTAwAAAADKhad+APBP74K2C3vXDAES4ft2AAAq17c7Z79Wncm+bcMRtWzOvMctFVMyfJ9jCnouF72wxEEvgPc+WGljRemTxk28pOzGxc133N+NrgSNOmhS2c7F/v7G2wU9ltNnLXD/itnxv5lh3VBCVdVl37O6B4D2oTqTnWv+Iqk9t82uv7QuVsV34HHpPQNe+OzixJ55Pffim85XAvXf6SD3f6kI/aTndkFjTa20zq7slHG9VGTZpm/1G/p1T5kAAAAgOb7KBojFpmAA0eeZecMGQHRGDoBYc80GIwdAZH50HAD+95piZNhy0wTw/hwAEp5n/mvYpaYIAAAAAJQDT/wA4H+9C9okbKFZArSZ79sBAKhc1ZlhE2w2opaNHHu8ZWJKbr3z/oKey04DRgZrm5oc+AJoam4OLvrD/TZXlMJGHTq57MbGfQ7/tRtdqd13m5qDHoP3LNv52PIVHxb0eE6ftcD9K2ZHnf57a4cSqiqTfd/qHgDayfPoutyJ5i+S2nM/3v1o62JVfCMPPj21a+y995cl9sxr/tNLnK82dsbUO4KOvevd/6UilN10SNBYUyuts/M693a9VGaNnjABAABAsnyZDRCLTcEAos8z84YNgOiMHACx5poNRg6AyPzoOAB8/rqiV9gLpgrg/TkApDDXPCBslakCAAAAAO2ZJ30A8Lnvgb4adoOZArSJ79sBAKhM3+6c/Vp1Jvu2zUb0aR9virZg4XOWiSlYvXpNMCB7YEHP54gxExz4Apr2x0dtsCiF7bj38WU3Pp55wbVuciVm4bOLy3Y+Vts/HzQ3Nxf0eE6ftcD9K2aHnXSF9UMplckttcIHgPZhg17DBpi/SGrPbT/6WOtiVXzb7XFMKtdX10GjEn3m9edH/up8tbH9J1zo3i8VqZHdtwkaa2qldfbrrv1cLxVYVV32Wk+YAAAAIFm+zAaIxaZgANHnmXnDBkB0Rg6AWHPNBiMHQGR+dBwAvnht8e2wu0wXwPtzAEhhrjkg7O+mCwAAAAC0V57yAcAXvgfqEHZ0WJMZA7SK79sBAKhM1ZnsMTYbUcv2PeJUS8SUXHjljQU/n5MmT3XgC+iPf37KBotS2FbDDyu78fHm2+e4yZWYS665uWznYwPrxxX8eE6ftcD9K2bjJl5i/VBKZXJLrfABoJ3Yeuv/8/HYbQ4jqb220z6TrItV8fXdYWwq19f2o45I9JnXn+572vlqY4Pzv3Tvl4rUz7oPChpraqV1NqHrFq6XCqyqLnuEB0wAAACQLF9mA8RiUzCA6PPMvGEDIDojB0CsuWaDkQMgMj86DgDrXl98Jex0Uwbw/hwAUphrVoc9ZMoAAAAAQHvkCR8ArPdd0A5h75k1QGy+bwcAoPJs0Gen/6+6LvumzUb0aRv2qQ+efu5FS8QUvPf+sqD74D0Kfk5nzJzt4BfQnEcX22BRCuux7d5lN0Y++exf3eRKzIh9jy3bOdmogyYV/HhOn7XA/Stm+xx5njVEKZXJLbXKB4D2Ixy/bzaHkdReG77/SdbFqvg23nJkKtfXQcec5ZlXCfWbq+4NfthvF/d+qUgd2G1g0FhTK62zg7tt5XqpwDbonRvo6RIAAAAky5fZALHYFAwg+jwzb9gAiM7IARBrrtlg5ACIzI+OA0C0dcbPwlaaOoD35wCQ8Dzz38OuNm0AAAAAoL3xdA8AIr0L6hrWaOYAsfi+HQCAylOdyR5qoxG17LDjz7U8TMnE039XlHP63OJXHPwCeuK512yyqIpvyrVzgo367lx2Y+Sy5f6fbyl54613gw371JftnOyoky8o+DH9/cz57mEx2+PQydYQpVQmt9QqHwDaj6re2YPNYSS11/LjTrUuVkV31uV3pXZ9nXH+tESfeV3SMNc5a0OHnni5+75UxA7vtmXQWFMrrbO9emzteqm4sk3f7pz9mqdLAAAAkCxfZwPEYlMwgOjzzLxhAyA6IwdArLlmg5EDIDI/Og4A0dcambDnTR/A+3MASGGuuVeYH3cGAAAAoN3wVA8AIr8H+lrYH8weIDLftwMAUFn69DngX6ozuZdtNKJP+2G/nYOXX33d8jAFi196LdhosxEFP6edBowM1jY1OQEF9NLf3rXJoiq+0y+9vezGyN4/2ccNrsT8btotZT0vu+DKGwt+TK+59RH3sJjtMu4064hSKpP7wEofANqP6syOPzKHkdRe2+2QM62LVdEdd/b1qV1ff7jl7sSedy1fucr5amPbjz7WfV8qYsd23SJorKmV1tnwHtu6XirvfcizniwBAABA8nydDRCLTcEAos8z84YNgOiMHACx5poNRg6AyPzoOADEW298Pex6Uwjw/hwAUphr9g5bbAoBAAAAQHvgiR4AxH4XdEDYKrMIWC/ftwMAUFmqeuX2ttGIWnbcaZdYGqZk3yNOLco5HTFmgoNfYO99sNImi6r4Jp5zfdmNkbvsf5wbXAlpbm4OBg0/qKznZX+e+1jBj+sVNz3kHhazYfv8yjqihKqqy75npQ8A7Us4hr9gHiOpPbbn4edYF6uiO2ji71K7vuYteDqx512vvbnU+WpD5027L/jRlru570tF7MQu/YLGmlppnf140+1cLxX3PiQ3zVMlAAAASJ4vtAFisSkYQPR5Zt6wARCdkQMg1lyzwcgBEJkfHQeA+GuODmGHha02lQDvzwEg4bnmN8JuNI0AAAAAoNR5mgcArXoX1DfsRTMJWCfftwMAUEkmfbk6k33GRiP6tE222DV44613LQ1T8OgTjUHH3vVFOa+TJk91Agqsqbk5uPAP99tsURXdoSddUXbj5FEnX+AGV0L+PHdB2c/N3n53acGP66U3POgeFrNtdh1vLVFSZd+w1geA9qUqk73EHEZSe2yf8edZF6ui2+3nZ6Z2fb3+5juJPe96ZvHrzlcbGn/ate75UpE7s/NmQWNNrbTO+vXa3vVSee9DfuGpEgAAACTPF9oAsdgUDCD6PDNv2ACIzsgBEGuu2WDkAIjMj44DQOvXHgPD/mY6Ad6fA0DC88wOYUeHrTWdAAAAAKBUeZIHAK1+F/T/wm43m4Av5Pt2AAAqR3XdsBE2GFHLTj3vasvCFDQ3Nwe5vY8u2nmdMXO2k1AE19z6iM0WVdHtc+SUshsnL776Zje3ErL7uEllPS/rO3RMUY7rRX94wD0sZn13GGstUUplsq9Y7QNA+1JVlxtpHiOpPbb/MRdaF6ui++meE1K5tjbZYtd/vFtLyrwnXnK+2tBO+0xyz5eK3HmdeweNNbXSOuuW2cn1UmF1rMsO8lQJAAAAkucLbYBYbAoGEH2emTdsAERn5ACINddsMHIAROZHxwGgbeuP74fda0oB3p8DQApzzSFhr5tSAAAAAFCKPMEDgDa9B/pK2Ilha80q4H/xfTsAAJWjKpN7xCYj+rSug0YF7y9dZlmYgptum1PUc7vohSVOQhHcOvspmy2qosuPO7Xsxso773vYza1EzJv/VPlvzD3+9IIf14/3Knb/il+XQXtaT5RQ4Tr3eat9AGhfvttj2PfCcbzZXEZSe2vcxEusi1XR9dtxXCrX1pD8oYk+87rj/medr1Z23rVzgk5bjXLPl4rcpZ3qgsaaWukLe6Zm4+AHrpUKK9v07c7Zr3mqBAAAAMnzlTZALDYFA4g+z8wbNgCiM3IAxJprNhg5ACLzo+MA0PY1SIeww8JWm1qA9+cAkPBc8zthM00rAAAAACg1nt4BQCLvggaHvWpmAf/E9+0AAFSGqkz2xzYYUct+O9VvJKRh9eo1wZbDxhbtvHYaMDJY29TkRBTBfY/81YaLquiGjj6u7MbKxudfdnMrESPGTCj7udkV1xX+//KsXrPW/SvuxsLT7gs27F1vPVFaPW3FDwDt8Hl1Xe4p8xhJ7a1DTrjc2lgV3Y8G7JbKtbXvEacm+0Xo7Y85X63sqDOmu99LJdC0Tr2Cxppa6Qt7sLaTa6XSymSf8TQJAAAA0uErbYBYbAoGEH2emTdsAERn5ACINdf0g1EAMf6LiZEDABJbi/QLW2x6Ad6fA0DC88wOYYeFrTK9AAAAAKBUeHIHAIm9C/p/YbeaXcB/8307AACVoaoud69NRvRpPbcdHSxbvtKSMAUXXXVTUc/tiDETnIQiebzxNRsuqqLbMndI2Y2XHyxf4eZWAm66bU5FzM+ef3FJwY/tBys+cv+K2WmX3GY9UXotsOIHgPanOpObYh4jqb31i1OusjZWxXb2Ffekdm2dcu6ViT7zuvSGB52zVpYdc4L7vVQC3bBJj6Cxplb6wm7bpJtrpdLK5C7zNAkAAADS4UttgFhsCgYQfZ6ZN2wARGfkAIg112wwcgBE5kfHASDZ9cjXw6abYoD35wCQwlyzb9jzphgAAAAAlAJP7AAg0fdAHcIOCLN5Nvi+HQCASlDdJ9vfBiNq2eXT/2Q5mIL3ly4Lug/eo6jndtLkqU5Ekbz46js2XFRF13PImLIaK7tstbsbWwlYtnxl0Psn+5T93Ozjf2Mx/O3Npe5fMTv27AbriRKrKpN70KpcXpRQAAAgAElEQVQfANqfjr2zw81lJLW3jjz9WmtjVWzH/eaG1K6ta264PbHnXR9+tMb5amVTrp0TdB64h/u9VALN3KR70FhTK31h1/6op2ul0updf4CnSQAAAJAOX2sDxGJTMIDo88y8YQMgOiMHQKy5ZoORAyAyPzoOAOmsS/YKW2GqgffnAEDC88yvhU0zzQAAAACg2DytA4BU3gV1D1topkGF8307AADlr7oud7MNRvRpm++4f7Bq1WrLwRSccNZlRT+/M2bOdiKK5N2lK2y6qIqutl++rMbLbXY5xI2tBBx9yoUVMT8bf9L5RTm+i15+y/0rZoeceJk1Rel1l1U/ALQ/Hbvlv1Vdl20yl5HUnjpm8nXWxqrYDv7VpaldW3PmPZ7Y867X3/7A+Wplx0z+g3u9VCLdu3GXoLGmVvrCLujU27VScQ3r6WkSAAAApMPX2gCx2BQMIPo8M2/YAIjOyAEQa67ZYOQAiMyPjgNAemuTHmGPm27g/TkAkMJc82dhS003AAAAACgWT+kAILX3QF8Nu9Rsgwrm+3YAAMrbhr2Gda+uyzXbXESfdt0t91gKpuDlV18PavrvUvTzu+iFJU5GkaxZ22TTRVVsZ195d9mNlyPHHu/GVmR33vdwxczP/jx3QVGO8YJnlriHxWzvX55rTVFiVWVyN1r5A0D7VJ3JzTefkdSemvibG6yNVbGNOnRyatfWK6+9kdjzrudeetP5amX1+53kXi+VSA9u3ClorKmVvrBTuvRzrVRSmdwHX8rnv+JJEgAAAKTDF9sAsdgUDCD6PDNv2ACIzsgBEGuu2WDkAIjMj44DQLrrk38JOyFsrWkH3p8DAAnPNTcKm23KAQAAAEAxeEIHAKm/Cxoa9jezDiqQ79sBAChvVZns1TYY0acNHnFwsLapyVIwBWOPOrPo57fTgJHOb5FdfuM8Gy+qIjthyi1lN2aOO3qym1oR/e31t4NeQ/aqiPlZ98F7BGvWFOf/hM95dLF7WMyyYyZZV5ReV1r5A0D7VF2XPctcRlJ76uNnYNbGqtS2H31sKtfVD/vtnOi7rYcXvux8taIp184Jug7a071eKpEW1GwSNNbUSl/YL7tu6VqpoKoyuXs8RQIAAID0+GobIBabggFEn2fmDRsA0Rk5AGLNNRuMHACR+dFxACjMOmWLsOdNPfD+HABIeJ7ZIeywsI9MPQAAAAAoJE/nAKAg74K+E3aTmQcVxvftAACUr+/1yv2wKpNdbYMRfdrMu+daBqZgwcLngo6964t+fkeMmeBkFNn1dz5u80VVZONPm1Z2Y+axp13splYkq1atDnYafWTFzM9+ecKUoh3rWX95xj0sZgPqD7GuKLUyuSlW/wDQPlX3yu5oPiOpPXXKRX+yNlbFtvlOB6VyXQ0aflCiz7vuevA556sVHXt2g/u8VCJ1DHumZuOgsaZW+sLGdB/keqmgqupyp3qKBAAAAOnx5TZALDYFA4g+z8wbNgCiM3IAxJprNhg5ACLzo+MAULi1ytfCLjH9wPtzACCFuWb3sMdMPwAAAAAoFE/lAKCg74L2CvvADIQK4ft2AADKV3Umd77NRfRp2+/xy6C5udkyMAXD9zmmJM7xpMlTnYwiu+OBRpsvqiIbe+xFZTdunnXR793UiuDjucovJv22ouZo8xY8XbTjPX3WAvewmHUZtKe1hc0kAYCEfKvf0K9XZ3JrzGkktZfOuPR2a2NVbJ22GpXKdTX6kJMSfd41464nnK9WNGLsKe7zUolUmxkWNNbUSutseI9tXS8V9R4km/UUCQAAANLj622AWGwKBhB9npk3bABEZ+QAiDXXbDByAETmR8cBoPBrluFhb5qG4P05AJDwPPNfwyaHNZmGAAAAAJA2T+QAoODvgmrD7jcLoQL4vh0AgPL03R7DvleVya60uYg+7c9zF1gCpmDm3XNL5hzPmDnbCSmyB5/4/9m7EzepqgPhw9FsM18mM5P5ZpLYgKZbBGWRatqNoKIRjRvVgDQiClFREuKuUdxxi+KCCwQURUUUlXaLGiXugor7ioZ2F1dUUBSRrbvPd0jM9yQjahVUdd+69b7P8/sDoO4959xzq+u84fBFlWWDDz4ndfPmpVffalBrBaeed3lZrc+23e3AVvu/bmxsChOufdAYlkdjJt8T2nbv69kiaWWyR9sBAIDSVVGdfdSaRlKpdN4V93o+VtnuiRTrvjrhrEsKuud12Y2P+MzybNzUmaHzNkON81JC6pLZJTRUVklf2zZdf+l+KaN+snG/H9tBAgAAgOLx7W2AvDgUDCD3dWadaQMgd2YOgLzWmvVmDoCc+dFxAGid55YfxSZaiuD9OQBQhLVmj9gcSxEAAAAAislOHAC0ynugtWLDY4usRkgx328HACCdKqprz3CwiP7ebvsd6/GvCFasaAxb1o5IzOf80mtv+VBa2QuvvOcARpVl2X1HpW7uvP5P9xnUWtjYSdeV3Rpt0tRbWu3/e978T41feXb8udd5tkhgFZm+I+wAAEDpalOdPceaRlIp1K6mn2djle+eyHnXF+3euvTqWwu237V8RaPPazU6roifr6T826TbTqGhskr62rp128X9UjbvQLKv2j0CAACA4vINboC8OBQMIPd1Zp1pAyB3Zg6AvNaa9WYOgJz50XEAaN3nl11jb1uS4P05AFDgdea/xEbHGi1JAAAAACgGu3AA0Krvgipj91iRkFK+3w4AQPpU1dT9R0Umu9DhIvp7jz8zx+NfEaw86C8pn3GHnruHxqYmH0ore/O9jx3AqLJs24FHpG7uvOP+Rw1qLWjytNvLbn3WvsfA8PHCRa32fz775feMX3k24viJni2SWCY7wC4AAJSuiups1ppGUim0/s9392wseyJF6J4HnijYfteHH33m81qNBvzmdOO8lKC23PiXoaGySvrK5sTWq866X8qkiursVLtHAAAAUFy+xQ2QF4eCAeS+zqwzbQDkzswBkNdas97MAZAzPzoOAK3/DPOfsYmWJXh/DgAUYa2ZiT1tWQIAAABAodl9A4BWfw+0Vmx47FMrE1LG99sBAEifNpk+xzhYRH/vVwef6tGvCD759LPQddshifmc++97jA8lARYuWuIARpVlm+48InXz56zHZxvUWmqH9pZ7QruavmW3Rjvx7Emt+v9+32MvG7/ybPffjvZ8kcS61W5jFwAASlfFpn3/b5zTm61rJCW9ztsM8Wyssq1uxOlFu7deef3tgu13vfLmhz6v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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+jz04EAAAAAAA8n9tBFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVPpCbxwAADYFJREFUVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVZX24EAAAAAAQJC/9QQbVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHACWH6cFeOLUKMAAAAASUVORK5CYII=" + }, + "paraswap": { + "color": "#0058D4", + "title": "Paraswap", + "icon": "data:image/svg+xml,%3csvg width='75' height='31' viewBox='0 0 75 31' fill='none' xmlns='http://www.w3.org/2000/svg'%3e %3cg clip-path='url(%23clip0)'%3e %3cpath d='M18.5198 20.2395L13.209 10.2522L7.89786 20.2395H18.5198ZM9.49768 14.7701L11.9002 10.2522H7.09521L9.49768 14.7701ZM57.8444 18.255C58.0989 18.255 58.3473 18.2456 58.5897 18.2267C58.8321 18.2081 59.0523 18.1836 59.2514 18.1538C59.4499 18.1236 59.6243 18.0956 59.7759 18.0693C59.9263 18.0431 60.0417 18.0186 60.1217 17.9961V14.3272C60.1217 14.0198 60.082 13.7349 60.002 13.4722C59.9226 13.2096 59.7951 12.9826 59.6213 12.7913C59.4457 12.5997 59.2171 12.4497 58.9356 12.341C58.6535 12.2323 58.3094 12.1777 57.9046 12.1777C57.507 12.1777 57.1672 12.2042 56.885 12.2565C56.6029 12.3091 56.3942 12.3652 56.2595 12.4252L56.3666 13.0667C56.47 13.0292 56.633 12.9808 56.855 12.9206C57.0781 12.8606 57.4156 12.8305 57.8685 12.8305C58.1861 12.8305 58.4423 12.8772 58.6372 12.9711C58.8321 13.0652 58.9831 13.189 59.0908 13.3428C59.1972 13.4964 59.267 13.6688 59.2989 13.8604C59.326 14.0239 59.3392 14.1925 59.3434 14.3645H59.3464V14.4433C59.3464 14.4461 59.347 14.4484 59.347 14.4512V14.8114H59.3464V15.4528H59.347V17.501C59.1876 17.5311 58.9951 17.5556 58.7684 17.5742C58.5422 17.593 58.2775 17.6022 57.9756 17.6022C57.7296 17.6022 57.5088 17.5815 57.3139 17.5402C57.1196 17.4992 56.9524 17.4336 56.8135 17.3436C56.6745 17.2535 56.5669 17.1336 56.4917 16.9831C56.4159 16.8331 56.3786 16.6497 56.3786 16.4318C56.3786 16.1841 56.4339 15.9857 56.5452 15.8354C56.6565 15.6854 56.7996 15.567 56.9747 15.4808C57.1491 15.3946 57.3398 15.3385 57.5467 15.3119C57.7536 15.2859 57.9521 15.2729 58.1428 15.2729C58.2926 15.2729 58.4261 15.2775 58.547 15.2859V14.6629C58.5368 14.6622 58.5278 14.6604 58.5181 14.6594C58.3948 14.6479 58.2775 14.6422 58.1663 14.6422C57.7933 14.6422 57.4475 14.6762 57.1293 14.7438C56.8117 14.8114 56.5374 14.9183 56.307 15.0644C56.0766 15.2109 55.8974 15.3963 55.7705 15.6216C55.6435 15.8466 55.5798 16.1165 55.5798 16.4318C55.5798 16.7621 55.6375 17.0415 55.7524 17.2701C55.8673 17.4992 56.0267 17.6867 56.2294 17.8331C56.4321 17.9793 56.6703 18.0862 56.9446 18.1538C57.2189 18.2211 57.519 18.255 57.8444 18.255ZM38.5987 18.255C38.8526 18.255 39.101 18.2456 39.3434 18.2267C39.5858 18.2081 39.8066 18.1836 40.0051 18.1538C40.2035 18.1236 40.3786 18.0956 40.5296 18.0693C40.6805 18.0431 40.796 18.0186 40.8754 17.9961V14.3272C40.8754 14.0198 40.8357 13.7349 40.7563 13.4722C40.6769 13.2096 40.5494 12.9826 40.375 12.7913C40.1999 12.5997 39.9714 12.4497 39.6893 12.341C39.4072 12.2323 39.0637 12.1777 38.6583 12.1777C38.2607 12.1777 37.9208 12.2042 37.6389 12.2565C37.3568 12.3091 37.1483 12.3652 37.0132 12.4252L37.1204 13.0667C37.2235 13.0292 37.3866 12.9808 37.6093 12.9206C37.8316 12.8606 38.1693 12.8305 38.6222 12.8305C38.9404 12.8305 39.196 12.8772 39.3915 12.9711C39.5858 13.0652 39.7368 13.189 39.8444 13.3428C39.9515 13.4964 40.0207 13.6688 40.0532 13.8604C40.0802 14.0239 40.0929 14.1925 40.0971 14.3645H40.1007V17.501C39.9413 17.5311 39.7494 17.5556 39.5226 17.5742C39.2959 17.593 39.0318 17.6022 38.7299 17.6022C38.4832 17.6022 38.2625 17.5815 38.0682 17.5402C37.8733 17.4992 37.7063 17.4336 37.5673 17.3436C37.4281 17.2535 37.321 17.1336 37.2456 16.9831C37.1702 16.8331 37.1326 16.6497 37.1326 16.4318C37.1326 16.1841 37.188 15.9857 37.2994 15.8354C37.4103 15.6854 37.5534 15.567 37.7284 15.4808C37.9034 15.3946 38.0941 15.3385 38.3004 15.3119C38.5073 15.2859 38.7058 15.2729 38.8965 15.2729C39.0463 15.2729 39.1792 15.2775 39.3007 15.2859V14.6629C39.2905 14.6622 39.282 14.6604 39.2718 14.6594C39.1485 14.6479 39.0318 14.6422 38.9205 14.6422C38.547 14.6422 38.2011 14.6762 37.8835 14.7438C37.5656 14.8114 37.2914 14.9183 37.0609 15.0644C36.8302 15.2109 36.6514 15.3963 36.5243 15.6216C36.3972 15.8466 36.3337 16.1165 36.3337 16.4318C36.3337 16.7621 36.3915 17.0415 36.5064 17.2701C36.6218 17.4992 36.7806 17.6867 36.9832 17.8331C37.1859 17.9793 37.4247 18.0862 37.6983 18.1538C37.9726 18.2211 38.2727 18.255 38.5987 18.255ZM29.279 18.255C29.5329 18.255 29.7813 18.2456 30.0238 18.2267C30.266 18.2081 30.4867 18.1836 30.6855 18.1538C30.8837 18.1236 31.0591 18.0956 31.2099 18.0693C31.3607 18.0431 31.4761 18.0186 31.5555 17.9961V14.3272C31.5555 14.0198 31.5158 13.7349 31.4366 13.4722C31.357 13.2096 31.2296 12.9826 31.055 12.7913C30.8802 12.5997 30.6516 12.4497 30.3694 12.341C30.0872 12.2323 29.7437 12.1777 29.3384 12.1777C28.9409 12.1777 28.6013 12.2042 28.3192 12.2565C28.0369 12.3091 27.8285 12.3652 27.6934 12.4252L27.8008 13.0667C27.9039 13.0292 28.0668 12.9808 28.2896 12.9206C28.5118 12.8606 28.8497 12.8305 29.3027 12.8305C29.6204 12.8305 29.8767 12.8772 30.0715 12.9711C30.266 13.0652 30.4174 13.189 30.5245 13.3428C30.6319 13.4964 30.7012 13.6688 30.7332 13.8604C30.7602 14.0239 30.7731 14.1925 30.7776 14.3645H30.7806L30.7807 14.4473L30.7809 14.4512V14.8114H30.7806V15.4528H30.7809V17.501C30.6218 17.5311 30.4293 17.5556 30.2026 17.5742C29.9764 17.593 29.712 17.6022 29.41 17.6022C29.1636 17.6022 28.943 17.5815 28.7484 17.5402C28.5536 17.4992 28.3866 17.4336 28.2477 17.3436C28.1086 17.2535 28.0013 17.1336 27.9261 16.9831C27.8504 16.8331 27.8128 16.6497 27.8128 16.4318C27.8128 16.1841 27.8683 15.9857 27.9796 15.8354C28.0905 15.6854 28.2336 15.567 28.4087 15.4808C28.5835 15.3946 28.774 15.3385 28.9808 15.3119C29.1873 15.2859 29.3863 15.2729 29.5769 15.2729C29.7263 15.2729 29.8595 15.2775 29.9808 15.2859V14.6629C29.9709 14.6622 29.9622 14.6604 29.9524 14.6594C29.829 14.6479 29.712 14.6422 29.6006 14.6422C29.227 14.6422 28.8814 14.6762 28.5637 14.7438C28.2458 14.8114 27.9716 14.9183 27.7411 15.0644C27.5104 15.2109 27.3316 15.3963 27.2044 15.6216C27.0776 15.8466 27.014 16.1165 27.014 16.4318C27.014 16.7621 27.0717 17.0415 27.1866 17.2701C27.302 17.4992 27.4608 17.6867 27.6633 17.8331C27.8663 17.9793 28.1048 18.0862 28.3791 18.1538C28.6532 18.2211 28.9528 18.255 29.279 18.255ZM62.1993 20.2129V17.7935C62.3347 17.8912 62.5512 17.9943 62.849 18.1033C63.1473 18.2117 63.4992 18.2663 63.904 18.2663C64.3491 18.2663 64.7443 18.1912 65.0902 18.0412C65.436 17.8912 65.7278 17.6831 65.9665 17.4165C66.2047 17.1502 66.3858 16.8316 66.5085 16.4599C66.6318 16.0884 66.6938 15.6816 66.6938 15.2389C66.6938 14.7663 66.6198 14.3426 66.473 13.9673C66.3257 13.5923 66.1193 13.2734 65.8535 13.0106C65.587 12.7482 65.2688 12.5476 64.8995 12.4086C64.5302 12.2698 64.1187 12.2002 63.6658 12.2002C63.1172 12.2002 62.6643 12.2341 62.307 12.3017C61.9491 12.3691 61.655 12.4405 61.4246 12.5155V20.2129H62.1993ZM33.6117 18.1313V13.0331C33.6754 13.0033 33.8085 12.9658 34.0111 12.9206C34.2136 12.8757 34.4817 12.853 34.8159 12.853C35.1335 12.853 35.3897 12.8701 35.5847 12.9037C35.7792 12.9377 35.9082 12.9693 35.9718 12.9991L36.1267 12.3691C36.0393 12.3316 35.8826 12.2943 35.6561 12.2565C35.4296 12.2191 35.1892 12.2002 34.9347 12.2002C34.4343 12.2002 34.009 12.2435 33.6591 12.3298C33.3095 12.416 33.0353 12.5007 32.837 12.5831V18.1313H33.6117ZM21.6589 20.2129V17.7935C21.7937 17.8912 22.0104 17.9943 22.3083 18.1033C22.6065 18.2117 22.958 18.2663 23.3633 18.2663C23.8084 18.2663 24.2038 18.1912 24.5494 18.0412C24.8953 17.8912 25.1873 17.6831 25.4256 17.4165C25.6641 17.1502 25.8447 16.8316 25.9679 16.4599C26.0912 16.0884 26.1528 15.6816 26.1528 15.2389C26.1528 14.7663 26.0792 14.3426 25.9324 13.9673C25.7851 13.5923 25.5785 13.2734 25.3125 13.0106C25.0461 12.7482 24.7284 12.5476 24.3589 12.4086C23.989 12.2698 23.578 12.2002 23.125 12.2002C22.5767 12.2002 22.1237 12.2341 21.766 12.3017C21.4084 12.3691 21.1145 12.4405 20.884 12.5155V20.2129H21.6589ZM43.8378 18.2663C44.5608 18.2663 45.1311 18.1313 45.5485 17.8612C45.9653 17.591 46.1741 17.1936 46.1741 16.668C46.1741 16.3908 46.1223 16.1602 46.0195 15.9759C45.9154 15.792 45.7807 15.6349 45.6141 15.5035C45.4469 15.3721 45.2538 15.2596 45.036 15.1663C44.8171 15.0731 44.5885 14.9816 44.3503 14.892C44.1199 14.8022 43.9154 14.7204 43.7362 14.6453C43.5575 14.5709 43.4066 14.4902 43.2832 14.404C43.1599 14.3173 43.0667 14.2178 43.0035 14.1048C42.9392 13.992 42.9079 13.8568 42.9079 13.6986C42.9079 13.6898 42.9088 12.6496 42.9094 12.3593L42.9097 12.2849H42.126C42.1243 12.3141 42.1217 13.486 42.1212 13.7236L42.1211 13.7647C42.1211 14.0122 42.1687 14.2224 42.2643 14.3948C42.3599 14.5675 42.4863 14.7157 42.6457 14.8395C42.8044 14.9632 42.9873 15.0719 43.1936 15.1657C43.4005 15.2596 43.6189 15.3515 43.8499 15.4415C44.1356 15.554 44.3762 15.6515 44.5711 15.7341C44.7654 15.8165 44.9223 15.903 45.0414 15.993C45.1611 16.0831 45.246 16.1841 45.2983 16.2968C45.3494 16.4094 45.3753 16.5445 45.3753 16.702C45.3753 17.0321 45.2303 17.2665 44.9404 17.4053C44.6505 17.5443 44.2829 17.6135 43.8378 17.6135C43.5912 17.6135 43.3747 17.5987 43.1882 17.5685C43.0011 17.5387 42.8405 17.5027 42.7052 17.4616C42.5699 17.4206 42.4628 17.3826 42.3834 17.3492C42.304 17.3152 42.2523 17.291 42.2282 17.276L42.0255 17.9397C42.1211 17.9851 42.3118 18.0507 42.5981 18.1366C42.8838 18.2232 43.2971 18.2663 43.8378 18.2663ZM49.1894 18.1313C49.3079 17.8701 49.433 17.5764 49.5648 17.2499C49.6959 16.9236 49.8318 16.5749 49.9708 16.2038C50.1103 15.8323 50.2457 15.442 50.3756 15.0323C50.5067 14.6232 50.6312 14.2042 50.7497 13.7757C50.8688 14.2033 50.9939 14.6211 51.125 15.0298C51.2562 15.4382 51.3915 15.828 51.5317 16.1989C51.6718 16.5701 51.8078 16.9186 51.9401 17.2446C52.0718 17.5706 52.1987 17.8663 52.319 18.1313H53.0372C53.4438 17.2841 53.8174 16.3885 54.156 15.4438C54.4953 14.4994 54.8081 13.4556 55.095 12.3127H54.3311C54.2438 12.7111 54.1344 13.1412 54.0026 13.6032C53.8715 14.0653 53.7296 14.5234 53.5786 14.9767C53.4264 15.4303 53.2754 15.8612 53.1238 16.2695C52.9723 16.6782 52.8285 17.0247 52.6932 17.3096C52.5332 16.9344 52.3756 16.5329 52.221 16.1048C52.0652 15.677 51.9184 15.2436 51.7801 14.8051C51.6417 14.366 51.5148 13.9348 51.3999 13.5111C51.285 13.0872 51.1924 12.688 51.1214 12.3127H50.4538C50.3593 12.6874 50.2529 13.0867 50.1344 13.5109C50.0153 13.9351 49.889 14.3647 49.7548 14.8C49.6207 15.2354 49.4769 15.6673 49.3242 16.0956C49.1714 16.5242 49.0186 16.925 48.8664 17.2981C48.7311 17.0132 48.5855 16.6678 48.4303 16.2622C48.2745 15.8568 48.1211 15.4272 47.9696 14.9734C47.818 14.5198 47.676 14.0625 47.5449 13.6009C47.4132 13.14 47.3031 12.7106 47.2153 12.3127H46.393C46.6781 13.4535 46.9891 14.4969 47.3272 15.4422C47.6646 16.3874 48.0369 17.2839 48.4448 18.1313H49.1894ZM63.8324 17.6022C63.6496 17.6022 63.4751 17.5851 63.3085 17.5517C63.1413 17.5181 62.9861 17.4747 62.8429 17.4221C62.6998 17.3698 62.5747 17.3137 62.4676 17.2535C62.3605 17.1936 62.2709 17.1372 62.1993 17.0846V13.0219C62.3184 12.9844 62.4959 12.9487 62.7299 12.9147C62.9644 12.8811 63.2724 12.8642 63.6538 12.8642C64.3214 12.8642 64.8574 13.0688 65.2628 13.4777C65.6688 13.8867 65.8709 14.4736 65.8709 15.2389C65.8709 15.5614 65.8354 15.8675 65.7638 16.156C65.6923 16.4451 65.5768 16.6961 65.418 16.9101C65.2592 17.1239 65.0505 17.2928 64.7924 17.4165C64.5338 17.5402 64.2144 17.6022 63.8324 17.6022ZM23.2919 17.6022C23.1089 17.6022 22.9343 17.5851 22.7675 17.5517C22.6004 17.5181 22.4455 17.4747 22.3024 17.4221C22.1593 17.3698 22.0341 17.3137 21.927 17.2535C21.8198 17.1936 21.7303 17.1372 21.6589 17.0846V13.0219C21.7778 12.9844 21.9549 12.9487 22.1892 12.9147C22.4237 12.8811 22.7317 12.8642 23.1128 12.8642C23.7806 12.8642 24.317 13.0688 24.7221 13.4777C25.1276 13.8867 25.3304 14.4736 25.3304 15.2389C25.3304 15.5614 25.2947 15.8675 25.223 16.156C25.1516 16.4451 25.0363 16.6961 24.8774 16.9101C24.7181 17.1239 24.5097 17.2928 24.2515 17.4165C23.993 17.5402 23.6732 17.6022 23.2919 17.6022ZM16.3509 18.9175H10.067L13.209 13.0089L16.3509 18.9175Z' fill='%23FDFDFD'/%3e %3c/g%3e %3cdefs%3e %3cclipPath id='clip0'%3e %3crect width='60' height='10.2857' fill='white' transform='translate(7.09521 10.2522)'/%3e %3c/clipPath%3e %3c/defs%3e %3c/svg%3e", + "iconPng": "data:image/png;base64,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" + }, + "uniswap": { + "color": "#FFE9F4", + "title": "Uniswap", + "icon": "data:image/svg+xml,%3csvg width='75' height='30' viewBox='0 0 75 30' fill='none' xmlns='http://www.w3.org/2000/svg'%3e %3cpath fill-rule='evenodd' clip-rule='evenodd' d='M43.8413 12.1956C42.7398 12.4731 42.2236 13.3368 42.5366 14.378C42.6707 14.8242 43.0833 15.2743 43.6667 15.6109C44.7182 16.2175 45.0278 16.4631 45.2076 16.8332C45.3576 17.142 45.3707 17.2452 45.295 17.5251C45.1175 18.1821 44.6539 18.5444 43.9907 18.5444C43.3138 18.5444 42.8384 18.1647 42.7323 17.5392C42.6898 17.2877 42.6372 17.2074 42.5157 17.2074C42.3706 17.2074 42.3554 17.2739 42.3554 17.911V18.6145L42.7957 18.7641C43.4832 18.9976 44.4611 18.9697 45.0446 18.6999C46.1813 18.1744 46.617 17.1313 46.1068 16.1565C45.916 15.7919 45.4371 15.385 44.6167 14.8901C43.7545 14.3699 43.3702 13.9915 43.3139 13.607C43.2273 13.016 43.7588 12.5269 44.4853 12.529C45.0543 12.5306 45.2985 12.6653 45.5002 13.0888C45.6265 13.3539 45.7169 13.4416 45.8664 13.4439C46.0318 13.4464 46.0565 13.4156 46.0143 13.2589C45.9865 13.1555 45.9632 12.8963 45.9627 12.6829C45.9618 12.4119 45.9226 12.28 45.8326 12.2457C45.5876 12.1519 44.1572 12.116 43.8413 12.1956ZM21.7253 12.4442C21.7253 12.5644 21.7813 12.6113 21.9248 12.6113C22.3297 12.6113 22.3514 12.7281 22.3962 15.1517C22.4354 17.269 22.4499 17.438 22.6191 17.7506C22.8616 18.1982 23.1904 18.4961 23.6961 18.7263C24.0425 18.884 24.2612 18.9174 24.954 18.9189C25.7056 18.9203 25.8425 18.896 26.2732 18.6853C26.5374 18.556 26.8666 18.3137 27.0046 18.1468C27.4832 17.5683 27.5339 17.2887 27.5881 14.9271C27.6404 12.6529 27.6475 12.616 28.036 12.6125C28.1264 12.6118 28.1827 12.5471 28.1827 12.4442C28.1827 12.2863 28.1268 12.277 27.1764 12.277C26.237 12.277 26.17 12.2878 26.17 12.4389C26.17 12.5601 26.238 12.6073 26.4407 12.6269C26.886 12.6699 26.9222 12.8411 26.9236 14.915C26.925 17.0176 26.8531 17.4221 26.4029 17.8479C25.9843 18.2439 25.6511 18.3773 25.0807 18.3773C24.2613 18.3773 23.6807 17.9959 23.4903 17.3327C23.4262 17.1097 23.4027 16.2895 23.4194 14.8675L23.4445 12.7366L23.738 12.6423C23.8995 12.5904 24.0437 12.487 24.0586 12.4125C24.0826 12.2927 23.949 12.277 22.9055 12.277C21.7813 12.277 21.7253 12.285 21.7253 12.4442ZM29.5245 12.4442C29.5245 12.5735 29.5804 12.6113 29.7721 12.6113C30.1992 12.6113 30.4397 12.7754 30.5362 13.1327C30.5912 13.3358 30.6148 14.306 30.5987 15.6926C30.5699 18.1684 30.536 18.3303 30.0239 18.4324C29.8551 18.4661 29.7761 18.5317 29.7761 18.6384C29.7761 18.7842 29.8581 18.7951 30.9502 18.7951C32.023 18.7951 32.1242 18.7822 32.1242 18.6453C32.1242 18.5386 32.0168 18.4669 31.7512 18.3961C31.4214 18.3082 31.368 18.2602 31.2904 17.9819C31.1909 17.6246 31.1673 13.8609 31.2646 13.8718C31.2992 13.8756 31.6245 14.2235 31.9875 14.6448C32.3505 15.066 33.3436 16.1722 34.1944 17.1029C35.526 18.5596 35.7751 18.7951 35.9843 18.7951H36.2274L36.2514 15.8326C36.2684 13.7292 36.3036 12.8422 36.3724 12.7736C36.4258 12.7204 36.5957 12.6512 36.7498 12.6198C36.9134 12.5865 37.0302 12.5118 37.0302 12.4407C37.0302 12.3409 36.8211 12.3146 35.877 12.2956C34.7668 12.2732 34.724 12.2786 34.724 12.4418C34.724 12.5658 34.7789 12.6113 34.9289 12.6113C35.0417 12.6113 35.2398 12.702 35.3692 12.8128L35.6045 13.0144L35.6309 15.0273C35.6459 16.1638 35.625 17.0403 35.5829 17.0403C35.542 17.0403 35.286 16.7865 35.0139 16.4762C34.742 16.1659 33.9674 15.3104 33.2927 14.5751C32.6181 13.8397 31.881 13.0248 31.6549 12.7644L31.2437 12.2907L30.3841 12.2839C29.5781 12.2774 29.5245 12.2875 29.5245 12.4442ZM38.33 12.4442C38.33 12.5716 38.386 12.6113 38.5656 12.6113C38.6952 12.6113 38.8744 12.6646 38.964 12.7298C39.1175 12.8417 39.1282 12.9859 39.1529 15.2994C39.1839 18.1883 39.1585 18.3502 38.6623 18.4293C38.4124 18.4691 38.33 18.521 38.33 18.6387C38.33 18.7846 38.4146 18.7951 39.5879 18.7951C40.7899 18.7951 40.8459 18.7877 40.8459 18.628C40.8459 18.5091 40.7899 18.4608 40.6522 18.4608C40.5458 18.4608 40.3854 18.4075 40.2958 18.3423C40.1416 18.2301 40.1318 18.0856 40.1087 15.5881C40.0851 13.0296 40.0893 12.9473 40.2555 12.7818C40.3496 12.688 40.5209 12.6113 40.6362 12.6113C40.7899 12.6113 40.8459 12.5667 40.8459 12.4442C40.8459 12.2845 40.7899 12.277 39.5879 12.277C38.386 12.277 38.33 12.2845 38.33 12.4442ZM47.1112 12.4442C47.1384 12.5477 47.2256 12.6113 47.3403 12.6113C47.4422 12.6113 47.6081 12.6988 47.709 12.8058C47.8115 12.9145 48.3848 14.2882 49.0083 15.9186L50.1242 18.8369L50.4168 18.8619L50.7094 18.8869L51.4933 16.8145C51.9245 15.6748 52.3226 14.652 52.3779 14.5417C52.4728 14.3529 52.4939 14.3816 52.7459 15.0431C52.8929 15.4292 53.2844 16.4501 53.6157 17.3118L54.2181 18.8787H54.4835C54.6296 18.8787 54.7682 18.8287 54.7918 18.7676C54.8153 18.7066 55.2006 17.7195 55.648 16.574C56.0955 15.4287 56.5911 14.1597 56.7494 13.7543C57.1101 12.831 57.1823 12.717 57.4698 12.6171C57.5976 12.5728 57.7021 12.4781 57.7021 12.4067C57.7021 12.2967 57.5494 12.277 56.6958 12.277C55.7454 12.277 55.6894 12.2863 55.6894 12.4442C55.6894 12.5652 55.7454 12.6113 55.8922 12.6113C56.2182 12.6113 56.3603 12.6995 56.3603 12.902C56.3603 13.071 54.763 17.4063 54.6646 17.5043C54.6041 17.5646 53.1618 13.5374 53.1096 13.1627C53.0589 12.7986 53.2144 12.6113 53.567 12.6113C53.7047 12.6113 53.7606 12.5631 53.7606 12.4442C53.7606 12.2842 53.7047 12.277 52.4607 12.277C51.2168 12.277 51.1609 12.2842 51.1609 12.4442C51.1609 12.5394 51.2168 12.6113 51.2909 12.6113C51.5527 12.6113 51.8997 12.8633 51.9889 13.1184C52.117 13.4843 52.0191 13.8553 51.265 15.8617L50.6245 17.5662L50.4866 17.2405C50.4107 17.0615 50.0157 16.0047 49.6091 14.8923C48.8101 12.7069 48.7983 12.6113 49.3262 12.6113C49.5116 12.6113 49.5675 12.5726 49.5675 12.4442C49.5675 12.2845 49.5116 12.277 48.3175 12.277C47.1087 12.277 47.0689 12.2825 47.1112 12.4442ZM64.0946 12.5018C64.0946 12.5018 64.0945 12.6159 64.1086 12.6477C64.1226 12.6794 64.2128 12.6913 64.2128 12.6913C64.2688 12.7064 64.322 12.7195 64.3723 12.732C64.6258 12.7948 64.8038 12.8388 64.875 13.0052C64.923 13.1176 64.926 13.5085 64.9266 15.6037C64.9272 17.8131 64.9268 18.0839 64.8677 18.2299C64.7944 18.4109 64.6541 18.5071 64.3303 18.598C64.3303 18.598 64.1871 18.6378 64.1485 18.6734C64.11 18.709 64.1027 18.7886 64.1027 18.7886C64.1027 18.7886 64.0997 18.8625 64.1327 18.898C64.1657 18.9334 64.2538 18.9165 64.2538 18.9165L65.093 18.9187L66.485 18.93C66.485 18.93 66.5419 18.9375 66.5714 18.8999C66.6009 18.8622 66.5933 18.7884 66.5933 18.7884C66.5933 18.7884 66.5933 18.7095 66.5566 18.674C66.52 18.6384 66.3778 18.6051 66.3778 18.6051C66.0634 18.5278 65.9021 18.4269 65.8308 18.2632C65.7778 18.1415 65.7721 17.8131 65.7641 17.129V16.126C65.7993 16.1458 65.8314 16.1683 65.8653 16.1921C66.0258 16.3043 66.2267 16.4449 66.9772 16.4666C67.8865 16.493 68.4335 16.0884 68.7588 15.6184C69.0841 15.1485 69.2103 14.4102 68.9716 13.6238C68.733 12.8373 68.0326 12.3614 67.0481 12.3122C66.5349 12.2865 65.7883 12.3119 65.371 12.3308L65.2541 12.336C64.875 12.3526 64.4206 12.3888 64.1943 12.4104L64.1936 12.4104C64.132 12.4163 64.1259 12.4169 64.1086 12.4387C64.0914 12.4607 64.0946 12.5018 64.0946 12.5018ZM67.7897 15.5826C68.1554 15.2388 68.1615 14.7009 68.1615 14.3573C68.1256 13.8186 67.9085 12.7825 66.6788 12.7825C66.3913 12.7677 65.8031 12.8173 65.7868 13.2161C65.769 13.2866 65.761 13.7794 65.7656 14.5357L65.7729 15.7428L65.898 15.8087L65.9048 15.8123C65.9727 15.8482 66.0608 15.8947 66.2149 15.9249C66.7037 16.0206 67.4239 15.9265 67.7897 15.5826ZM60.0957 12.3824C60.1868 12.3479 60.2468 12.3249 60.2468 12.3249C60.2468 12.3249 60.3829 12.2689 60.4269 12.3249C60.4405 12.3421 60.4898 12.4695 60.6121 12.7852C60.6361 12.8472 60.6629 12.9163 60.6929 12.9934C60.8752 13.463 61.1371 14.1372 61.2749 14.4915C61.4127 14.8458 61.6853 15.547 61.8807 16.0496C62.076 16.5522 62.3268 17.1971 62.4378 17.4825C62.549 17.768 62.691 18.0648 62.7307 18.1189C62.7502 18.1455 62.7702 18.1786 62.792 18.2148C62.8778 18.357 62.9929 18.5477 63.2241 18.5851C63.2241 18.5851 63.4051 18.615 63.4319 18.6434C63.4587 18.6718 63.4648 18.7233 63.4648 18.7233V18.8202C63.4648 18.8202 63.4617 18.8449 63.4468 18.866C63.4319 18.887 63.3772 18.8811 63.3772 18.8811L61.9816 18.8812L60.9887 18.8884C60.9887 18.8884 60.954 18.8926 60.9336 18.8757C60.9131 18.8588 60.9025 18.816 60.9025 18.816V18.7431C60.9025 18.7431 60.894 18.6883 60.9336 18.6405C60.9733 18.5928 61.1327 18.5873 61.1327 18.5873C61.4333 18.5612 61.5526 18.3052 61.614 18.1734C61.6186 18.1635 61.6228 18.1544 61.6268 18.1461C61.6923 18.0098 61.6686 17.921 61.3729 17.1927C61.1778 16.7119 61.1113 16.5769 61.0639 16.5649C61.0306 16.5565 60.5112 16.5534 59.9096 16.558L58.8158 16.5663L58.7504 16.7461C58.5613 17.2662 58.3933 17.7828 58.368 17.9224C58.3164 18.2066 58.3883 18.5226 58.8063 18.5776C58.8063 18.5776 58.9612 18.5989 59.0026 18.6301C59.0439 18.6613 59.0584 18.7412 59.0584 18.7412V18.8148C59.0584 18.8148 59.0505 18.8499 59.022 18.8735C58.9936 18.8971 58.9198 18.8885 58.9198 18.8885H57.8759L56.8659 18.9C56.8659 18.9 56.8228 18.899 56.7909 18.8821C56.759 18.8652 56.754 18.8313 56.754 18.8313V18.7613C56.754 18.7613 56.7485 18.7159 56.8047 18.6603C56.861 18.6047 57.0128 18.5899 57.0128 18.5899C57.2889 18.5454 57.4452 18.2516 57.5352 18.0825C57.5419 18.07 57.5481 18.0582 57.5541 18.0472C57.5897 17.9814 57.7506 17.5971 57.9115 17.1934C58.0725 16.7896 58.2532 16.3379 58.313 16.1896C58.5164 15.6853 58.7097 15.2021 59.0024 14.4667C59.163 14.0629 59.4009 13.467 59.5309 13.1423L59.7674 12.552L60.0957 12.3824ZM60.0096 13.8173C60.0602 13.945 60.1378 14.1371 60.1818 14.2442C60.2259 14.3513 60.3494 14.6547 60.4561 14.9184C60.5628 15.182 60.6939 15.5029 60.7475 15.6314C60.801 15.76 60.8449 15.8712 60.8449 15.8786C60.8449 15.8861 60.4429 15.8922 59.9516 15.8922C59.3876 15.8922 59.0584 15.8814 59.0584 15.8628C59.0584 15.8467 59.0773 15.7826 59.1004 15.7205C59.1371 15.6217 59.3204 15.0971 59.7252 13.9322C59.7876 13.7523 59.8457 13.5936 59.854 13.5796C59.8825 13.5316 59.9175 13.5851 60.0096 13.8173Z' fill='%23FF006E'/%3e %3cpath d='M10.7128 12.6593C11.0026 13.1718 10.3544 13.3307 10.0501 13.36C9.5892 13.405 9.49377 13.1381 9.5838 12.8028C9.61338 12.6828 9.67894 12.5748 9.77165 12.4935C9.8644 12.4122 9.97976 12.3615 10.1021 12.3483C10.2227 12.3372 10.344 12.3605 10.452 12.4155C10.56 12.4705 10.6504 12.555 10.7128 12.6593Z' fill='%23FF006E'/%3e %3cpath d='M12.5223 11.7109C12.1854 14.2995 16.7271 13.7609 16.6406 15.8211C17.0886 15.236 17.2813 13.6465 15.9624 12.8284C14.7873 12.0989 13.2561 12.498 12.5223 11.7109Z' fill='%23FF006E'/%3e %3cpath d='M16.1937 12.6219L16.191 12.6179C16.15 12.5413 16.1033 12.4681 16.0512 12.3987C15.8981 12.1903 15.6785 12.041 15.429 11.9756C15.2629 11.9326 15.0931 11.9058 14.9219 11.8956C14.7485 11.8829 14.5715 11.8757 14.3928 11.8663C14.0344 11.8465 13.6675 11.8096 13.3091 11.707C13.2195 11.6813 13.1299 11.6534 13.0434 11.6197C12.9987 11.6035 12.957 11.5859 12.9127 11.567C12.8683 11.5481 12.8231 11.5265 12.7782 11.5036C12.6097 11.4109 12.4536 11.297 12.3137 11.1647C12.0377 10.9068 11.8209 10.6143 11.6036 10.3308C11.3988 10.0462 11.1789 9.77277 10.9451 9.51173C10.7143 9.256 10.4415 9.04198 10.1387 8.87899C9.82509 8.72031 9.48447 8.62259 9.13477 8.59096C9.49756 8.55139 9.86457 8.59636 10.2072 8.72237C10.553 8.85723 10.8691 9.0589 11.1377 9.31597C11.313 9.48115 11.4777 9.65747 11.6305 9.84385C12.7684 9.61884 13.6912 9.81865 14.4004 10.2066L14.4166 10.2147C14.6423 10.3377 14.8538 10.4853 15.0473 10.6548C15.0782 10.6818 15.1087 10.7088 15.1369 10.7363C15.2879 10.8757 15.4285 11.0261 15.5576 11.1863L15.5674 11.1993C15.9863 11.7322 16.1933 12.2862 16.1937 12.6219Z' fill='%23FF006E'/%3e %3cpath d='M9.19254 8.92444C9.48285 8.96674 9.77898 9.08285 9.9698 9.30427C10.1607 9.52568 10.231 9.8137 10.2861 10.0878C10.3309 10.3002 10.3663 10.5167 10.4496 10.7178C10.4899 10.8159 10.5491 10.9019 10.5983 10.9946C10.6391 11.0715 10.7135 11.1409 10.7421 11.2232C10.7473 11.235 10.7492 11.248 10.7477 11.2608C10.7462 11.2736 10.7414 11.2858 10.7336 11.2961C10.6324 11.4086 10.3591 11.2835 10.2561 11.2331C10.0779 11.1444 9.91842 11.0222 9.78615 10.8731C9.37265 10.4118 9.15895 9.748 9.17195 9.1436C9.17481 9.07023 9.18169 8.99706 9.19254 8.92444Z' fill='%23FF006E'/%3e %3cpath d='M14.0477 14.1259C13.4205 15.8841 16.2652 17.0637 15.1995 18.8512C16.293 18.3976 16.8122 17.0272 16.3584 15.9399C15.9615 14.9854 14.7878 14.6376 14.0477 14.1259Z' fill='%23FF006E'/%3e %3cpath d='M10.2852 16.4254C10.456 16.296 10.6429 16.1894 10.8411 16.1082C11.0416 16.0276 11.2496 15.9673 11.462 15.9282C11.8836 15.8476 12.3007 15.8278 12.651 15.686C12.8241 15.6181 12.9833 15.519 13.1209 15.3935C13.2541 15.2692 13.356 15.115 13.4184 14.9435C13.4822 14.7625 13.5082 14.5702 13.4945 14.3787C13.4787 14.173 13.4324 13.9708 13.357 13.7788C13.5132 13.942 13.6269 14.1413 13.6881 14.3591C13.7492 14.5769 13.756 14.8066 13.7078 15.0276C13.653 15.2617 13.5347 15.4759 13.366 15.6464C13.199 15.8117 12.9976 15.9377 12.7764 16.0155C12.5653 16.0898 12.3451 16.1353 12.1219 16.1505C11.9069 16.1685 11.699 16.1734 11.4947 16.1855C11.0817 16.203 10.6738 16.2838 10.2852 16.4254Z' fill='%23FF006E'/%3e %3cpath d='M14.2981 19.5159C14.2349 19.5663 14.1717 19.6198 14.1023 19.6666C14.0324 19.7129 13.9592 19.7538 13.8832 19.7891C13.7251 19.8666 13.5512 19.9061 13.3752 19.9047C12.8985 19.8957 12.5616 19.5393 12.3646 19.1365C12.2301 18.862 12.1374 18.5654 11.9779 18.3039C11.7499 17.93 11.3597 17.6289 10.9028 17.6847C10.7164 17.7081 10.5417 17.7922 10.4382 17.9547C10.1658 18.3791 10.5569 18.9736 11.0555 18.8894C11.0979 18.8829 11.1394 18.8715 11.1792 18.8552C11.2188 18.8383 11.2557 18.8157 11.2889 18.7882C11.3586 18.7299 11.4111 18.6537 11.4408 18.5677C11.4735 18.478 11.4808 18.3809 11.4618 18.2873C11.4414 18.1894 11.3839 18.1034 11.3015 18.0474C11.3973 18.0925 11.472 18.1732 11.5098 18.2725C11.549 18.3746 11.5591 18.4857 11.5389 18.5933C11.5193 18.7054 11.4701 18.8102 11.3965 18.8966C11.3573 18.9411 11.3121 18.9797 11.262 19.0114C11.2125 19.0427 11.1594 19.0679 11.1039 19.0865C10.9914 19.1252 10.8716 19.1376 10.7536 19.123C10.5879 19.0993 10.4316 19.0312 10.3011 18.9259C10.147 18.8035 10.0323 18.6433 9.89298 18.5056C9.73328 18.3372 9.54486 18.199 9.3366 18.0974C9.193 18.034 9.04271 17.9872 8.8886 17.9579C8.81109 17.9417 8.73272 17.93 8.6543 17.9201C8.61846 17.9165 8.44285 17.8773 8.41821 17.9002C8.66051 17.6762 8.92468 17.4772 9.20667 17.3062C9.49621 17.1336 9.80711 17 10.1313 16.9089C10.4675 16.8138 10.8191 16.7867 11.1657 16.8292C11.3442 16.8507 11.5189 16.8961 11.6854 16.9642C11.8598 17.0342 12.0208 17.1341 12.1611 17.2594C12.3001 17.3909 12.4124 17.5481 12.4918 17.7225C12.5635 17.8857 12.617 18.0564 12.6512 18.2315C12.7534 18.7549 12.7158 19.5663 13.3981 19.686C13.4336 19.6929 13.4695 19.698 13.5056 19.7013L13.6171 19.704C13.6938 19.6985 13.77 19.6875 13.8451 19.6711C14.0008 19.6344 14.1525 19.5823 14.2981 19.5159Z' fill='%23FF006E'/%3e %3cpath d='M9.7211 11.5589C9.69625 11.6548 9.65286 11.7448 9.59342 11.8239C9.48279 11.9682 9.33632 12.0807 9.16873 12.1502C9.01801 12.2154 8.85841 12.2576 8.69521 12.2753C8.6598 12.2798 8.62309 12.2825 8.5877 12.2852C8.48435 12.2891 8.38497 12.3262 8.30412 12.391C8.22326 12.4558 8.16518 12.5449 8.13837 12.6452C8.12609 12.6952 8.11696 12.7458 8.11104 12.7969C8.09491 12.9292 8.09223 13.0669 8.07789 13.2334C8.04279 13.5168 7.96119 13.7923 7.83642 14.0489C7.67425 14.3918 7.49237 14.6681 7.53448 15.0633C7.56225 15.3198 7.69307 15.4917 7.86689 15.669C8.18048 15.9912 8.88249 16.1352 8.7257 16.9291C8.63116 17.4029 7.84897 17.9003 6.7496 18.074C6.85891 18.0573 6.60938 17.6347 6.5937 17.6077C6.47588 17.4223 6.34686 17.2477 6.25323 17.0466C6.06956 16.6564 5.98444 16.205 6.0597 15.7774C6.13899 15.3274 6.47051 14.9827 6.74602 14.6389C7.07395 14.2298 7.418 13.6938 7.49416 13.1628C7.51208 13.0341 7.52462 12.8729 7.55329 12.7127C7.58063 12.5352 7.63598 12.3632 7.71726 12.2033C7.77274 12.0984 7.84578 12.0038 7.93319 11.9238C7.97876 11.8814 8.00883 11.8247 8.01858 11.763C8.02832 11.7014 8.01719 11.6382 7.98695 11.5836L6.23442 8.41718L8.75165 11.5377C8.78032 11.5739 8.81655 11.6032 8.85779 11.6237C8.89903 11.6442 8.94428 11.6554 8.99025 11.6564C9.03627 11.6574 9.08191 11.6482 9.12401 11.6295C9.16606 11.6107 9.20352 11.5829 9.23372 11.5481C9.2656 11.5107 9.28366 11.4634 9.2849 11.4142C9.2861 11.3651 9.27042 11.317 9.24041 11.2781C9.07603 11.067 8.90218 10.8519 8.73373 10.6403L8.10029 9.85278L6.8289 8.28037L5.09521 6.09509L6.99197 8.13952L8.34534 9.64262L9.02045 10.396C9.24443 10.6493 9.46845 10.8946 9.69243 11.161L9.72918 11.206L9.73726 11.2758C9.74815 11.3704 9.7427 11.4661 9.7211 11.5589Z' fill='%23FF006E'/%3e %3c/svg%3e", + "iconPng": "data:image/png;base64,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" + }, + "zeroEx": { + "color": "#000", + "title": "0x API", + "icon": "data:image/svg+xml,%3csvg width='75' height='31' viewBox='0 0 75 31' fill='none' xmlns='http://www.w3.org/2000/svg'%3e %3cpath d='M18.1075 11.6529C18.7415 10.8075 19.5823 10.3848 20.6299 10.3848C21.6774 10.3848 22.5136 10.8075 23.1385 11.6529C23.7725 12.4891 24.0896 13.7388 24.0896 15.402C24.0896 17.0653 23.7725 18.315 23.1385 19.1512C22.5136 19.9874 21.6774 20.4055 20.6299 20.4055C19.5823 20.4055 18.7415 19.9874 18.1075 19.1512C17.4826 18.315 17.1702 17.0653 17.1702 15.402C17.1702 13.7388 17.4826 12.4891 18.1075 11.6529ZM18.0661 15.402C18.0661 16.7436 18.2729 17.7728 18.6864 18.4896L21.9945 11.6391C21.6269 11.3358 21.172 11.1842 20.6299 11.1842C19.7937 11.1842 19.155 11.5472 18.7139 12.2731C18.282 12.9899 18.0661 14.0328 18.0661 15.402ZM20.6299 19.606C21.4661 19.606 22.1001 19.2477 22.532 18.5309C22.9731 17.8142 23.1936 16.7712 23.1936 15.402C23.1936 14.0604 22.9869 13.0358 22.5734 12.3283L19.2653 19.165C19.642 19.459 20.0969 19.606 20.6299 19.606ZM30.7317 20.2263L28.8847 17.1801H28.3885L26.4725 20.2263H25.5077L27.7406 16.6977L25.742 13.3345H26.6793L28.3885 16.2153H28.8847L30.6214 13.3345H31.5587L29.5325 16.6563L31.7517 20.2263H30.7317ZM41.5873 10.3848L45.1159 20.2263H44.1373L43.0208 17.0423H38.486L37.3695 20.2263H36.4184L39.9333 10.3848H41.5873ZM40.4846 11.3496L38.7754 16.2153H42.7314L41.0222 11.3496H40.4846ZM46.699 10.3848H50.7376C51.7759 10.3848 52.5754 10.6375 53.1359 11.1429C53.6965 11.6483 53.9767 12.3512 53.9767 13.2518C53.9767 14.1523 53.6965 14.8553 53.1359 15.3607C52.5754 15.8661 51.7759 16.1188 50.7376 16.1188H47.6088V20.2263H46.699V10.3848ZM47.6088 15.2918H50.5859C52.24 15.2918 53.067 14.6118 53.067 13.2518C53.067 11.8918 52.24 11.2118 50.5859 11.2118H47.6088V15.2918ZM56.1104 10.3848H57.0202V20.2263H56.1104V10.3848Z' fill='%23FDFDFD'/%3e %3c/svg%3e", + "iconPng": "data:image/png;base64,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" + } +} diff --git a/test/e2e/mock-response-data/token-blocklist.json b/test/e2e/mock-response-data/token-blocklist.json new file mode 100644 index 000000000000..e86383472d6f --- /dev/null +++ b/test/e2e/mock-response-data/token-blocklist.json @@ -0,0 +1,582 @@ +[ + "0x1a95b271b0535d15fa49932daba31ba612b52946", + "0xd4d1c6857d994f9af768b67a6a6e9c279dae1303", + "0x985dd3d42de1e256d09e1c10f112bccb8015ad41", + "0x7afebbb46fdb47ed17b22ed075cde2447694fb9e", + "0x07597255910a51509ca469568b048f2597e72504", + "0x84a854d5019edba68eaf8220856cb85a2c054586", + "0x995de3d961b40ec6cdee0009059d48768ccbdd48", + "0x86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0", + "0xae31b85bfe62747d0836b82608b4830361a3d37a", + "0x954b890704693af242613edef1b603825afcd708", + "0x9ea4c67c314db0ec8fa13eaba4dc7ed1b320fd35", + "0x03fb52d4ee633ab0d06c833e32efdd8d388f3e6a", + "0xea319e87cf06203dae107dd8e5672175e3ee976c", + "0x4f3afec4e5a3f2a6a1a411def7d7dfe50ee057bf", + "0x79ba92dda26fce15e1e9af47d5cfdfd2a093e000", + "0x1da01e84f3d4e6716f274c987ae4bee5dc3c8288", + "0xa866f0198208eb07c83081d5136be7f775c2399e", + "0xb48e0f69e6a3064f5498d495f77ad83e0874ab28", + "0xaa19673aa1b483a5c4f73b446b4f851629a7e7d6", + "0x892f5a0b08bb7b1eecccc63ef3916ff201c93664", + "0xd1afbccc9a2c2187ea544363b986ea0ab6ef08b5", + "0xe1f8cd01ab04b51d02c6fb2bca61b03fb5e33b99", + "0x1443e7c1cce72662545d94779120c59251447e91", + "0x62359ed7505efc61ff1d56fef82158ccaffa23d7", + "0x88ef27e69108b2633f8e1c184cc37940a075cc02", + "0x0e3c91ed7d966ff1f7b58ab739a55e3c4473cd27", + "0x0417912b3a7af768051765040a55bb0925d4ddcf", + "0x73f8406eaace2ce69ba49a67551464fda1d11f14", + "0x78571accaf24052795f98b11f093b488a2d9eaa4", + "0x2129ff6000b95a973236020bcd2b2006b0d8e019", + "0x73fa9181cd0752a18ddfa285033df0323a804457", + "0x1ad606adde97c0c28bd6ac85554176bc55783c01", + "0x6d6506e6f438ede269877a0a720026559110b7d5", + "0x610c67be018a5c5bdc70acd8dc19688a11421073", + "0x12b28e6fffa7ff813b15b597d894d5ef5b0b7428", + "0xa1afffe3f4d611d252010e3eaf6f4d77088b0cd7", + "0xac00797df10e825589d8b53e715393be4e617459", + "0xe5868468cb6dd5d6d7056bd93f084816c6ef075f", + "0x98cc695d0c6e40239ea9c2411b71a17b6a85d5ea", + "0xd04785c4d8195e4a54d9dec3a9043872875ae9e2", + "0xc32cc5b70bee4bd54aa62b9aefb91346d18821c4", + "0x320583dd12ea9ad31e751feab1efae7b7a95c6d7", + "0xe95e4440493e5b96e79d63e8dc43ab676dd44e4c", + "0xf0b47ee3d3bdbef94999b2b8f4b81a52fbe2e3ed", + "0xc14a00033080eca5bea2bcd3d0645fa7825142da", + "0xa7de087329bfcda5639247f96140f9dabe3deed1", + "0x69692d3345010a207b759a7d1af6fc7f38b35c5e", + "0xea3cb156745a8d281a5fc174186c976f2dd04c2e", + "0x12d102f06da35cc0111eb58017fd2cd28537d0e1", + "0x14d1c83df4decee9deb14ee851f109f0101a6631", + "0x53f64be99da00fec224eaf9f8ce2012149d2fc88", + "0xd0d3ebcad6a20ce69bc3bc0e1ec964075425e533", + "0x3863ea7577fc91bfbaeae6a6a3e403524afcf787", + "0x32c868f6318d6334b2250f323d914bc2239e4eee", + "0x7a3d5d49d64e57dbd6fbb21df7202bd3ee7a2253", + "0xe8b251822d003a2b2466ee0e38391c2db2048739", + "0x8d5db0c1f0681071cb38a382ae6704588d9da587", + "0x36c6b0e43e43717890197a1d49d05eb3e5bed329", + "0xbb0a009ba1eb20c5062c790432f080f6597662af", + "0x2e2364966267b5d7d2ce6cd9a9b5bd19d9c7c6a9", + "0x45804880de22913dafe09f4980848ece6ecbaf78", + "0xbae5f2d8a1299e5c4963eaff3312399253f27ccb", + "0x91383a15c391c142b80045d8b4730c1c37ac0378", + "0x4bae380b5d762d543d426331b8437926443ae9ec", + "0x88930072f583936f506ce1f1d5fe69290c2d6a2a", + "0xeeee2a622330e6d2036691e983dee87330588603", + "0x239119c43e3cac84c8a2d45bcba0e46f528e5f77", + "0x4ba6ddd7b89ed838fed25d208d4f644106e34279", + "0xbf494f02ee3fde1f20bee6242bce2d1ed0c15e47", + "0xb6ee603933e024d8d53dde3faa0bf98fe2a3d6f1", + "0xa0bb0027c28ade4ac628b7f81e7b93ec71b4e020", + "0xa5959e9412d27041194c3c3bcbe855face2864f7", + "0x9af15d7b8776fa296019979e70a5be53c714a7ec", + "0xde9d41a01bb11a9f41e709242824e54c3917084e", + "0xed36482c7f8e5850e91ac0cf6bf2130a1aa2df92", + "0x389999216860ab8e0175387a0c90e5c52522c945", + "0xc981ca09a4d42961b57f299d70bbdd7ee1caf14b", + "0xeb1c63cc494970981a6e3367e6b6c6f6f9879d7d", + "0x521fd6d4b9e0e98a8074302fc8d703971b7eb43a", + "0x9b370397604e165c681ae2c02d4619616fdc5403", + "0xf6de69ce2803b5adb762986ed3dcf39e5dbfddb2", + "0x426ca1ea2406c07d75db9585f22781c096e3d0e0", + "0x967da4048cd07ab37855c090aaf366e4ce1b9f48", + "0xdfac0158449296b7c6b2537a6c2fbbe7c5cef328", + "0x10bae51262490b4f4af41e12ed52a0e744c1137a", + "0xbbc455cb4f1b9e4bfc4b73970d360c8f032efee6", + "0x658bbe318260ab879af701043b18f7e8c4daf448", + "0xe95a203b1a91a908f9b9ce46459d101078c2c3cb", + "0x3a3a65aab0dd2a17e3f1947ba16138cd37d08c04", + "0x78b039921e84e726eb72e7b1212bb35504c645ca", + "0x5e74c9036fb86bd7ecdcb084a0673efc32ea31cb", + "0x6d45640f5d0b75280647f2f37ccd19c1167f833c", + "0x0d7dea5922535087078dd3d7c554ea9f2655d4cb", + "0x32d5730fb85763281d459b9022cb247d8e10e0ef", + "0xd82bb924a1707950903e2c0a619824024e254cd1", + "0x23b4db3a435517fd5f2661a9c5a16f78311201c1", + "0xf013406a0b1d544238083df0b93ad0d2cbe0f65f", + "0x76a034e76aa835363056dd418611e4f81870f16e", + "0x14be9bde94102e13971e8f98acecac823cb7fd30", + "0x704135ecbb0bea17fd3daad8e3583ccc6f6f7f0e", + "0x33c2da7fd5b125e629b3950f3c38d7f721d7b30d", + "0xd7b3669c7d3e38ab5a441383d41f25e003e02148", + "0x90c88ccd74e57e016acae8ad1eaa12ecf4c06f33", + "0xd6014ea05bde904448b743833ddf07c3c7837481", + "0x5963fd7ca9b17b85768476019f81cb43d9d1818e", + "0x40ce0a1d8f4999807b92ec266a025f071814b15d", + "0xe95ebf4f50d0084c1ea62fcfa8a2bdd707254d3f", + "0x8fd68af8c21d99c442a5d9d2a0dde6b441ea51ee", + "0x6c1af18a949c293ad4bfc0dc455b463498463705", + "0x846d152216146c77c81af3a1657790ed8ba69281", + "0x063f94a725d4bfa66746d665782a1b137195860d", + "0xe307bcaa460d83baa6452784461593d7a537a047", + "0xcfc56009ab5217f70b86220c315f9c0532f18cdf", + "0xf9e9e69a9a13450c098c6591e57372c7876e6cbc", + "0x0a472678b927640ee14cb5ec618fd29f1014fed1", + "0x5506861bbb104baa8d8575e88e22084627b192d8", + "0xf4fb54c667fe525cf4811df291b2a2892261c3d7", + "0x105bf3675d3b380687ecf80d8f7f451707de6739", + "0x819ab68104dcf01189bb87a2a9129a19556c77d0", + "0x8db6fcc2bae3e63bdd9db520a46bb39a379847c6", + "0x912b38134f395d1bfab4c6f9db632c31667acf98", + "0xdf5e0e81dff6faf3a7e52ba697820c5e32d806a8", + "0x096d4552fe0066dca557d932426071835928284b", + "0x2512bbe0b3ba612b3d861e1fc682b17fa0b54d74", + "0xa54c67bd320da4f9725a6f585b7635a0c09b122e", + "0xdc58b6eb1c945568e34b7cf2b806636715f1762d", + "0x694cc203ae4e8223c220a0f8d72c26bf2c437c69", + "0xa7ed29b253d8b4e3109ce07c80fc570f81b63696", + "0x0391d2021f89dc339f60fff84546ea23e337750f", + "0x3d4a076a01b303259046b548c8d759a1c77c32fa", + "0x5c9adb28f0c7b35157a0c6ab5c55729f301c9b70", + "0x9cd9a927013075b0d39b1fb5f307560af471cc70", + "0x692eb773e0b5b7a79efac5a015c8b36a2577f65c", + "0x584bc13c7d411c00c01a62e8019472de68768430", + "0x776ca7ded9474829ea20ad4a5ab7a6ffdb64c796", + "0x559cce70236df3876f63731211ede1de35323a0f", + "0xebd888168161d67b2e35051c063de0212d05436a", + "0x80fb784b7ed66730e8b1dbd9820afd29931aab03", + "0xe7bc894cbeefb1d60f0401903a8377cbf52803c4", + "0x72630b1e3b42874bf335020ba0249e3e9e47bafc", + "0xf979d80a1aa41530424b9862db13900fd49e86fb", + "0x1c95b093d6c236d3ef7c796fe33f9cc6b8606714", + "0xc84f7abe4904ee4f20a8c5dfa3cc4bf1829330ab", + "0xe0e4839e0c7b2773c58764f9ec3b9622d01a0428", + "0xbbb38be7c6d954320c0297c06ab3265a950cdf89", + "0x910524678c0b1b23ffb9285a81f99c29c11cbaed", + "0x8da25b8ed753a5910013167945a676921e864436", + "0x02e578a87851670839d351d9372b10e2a580aec3", + "0x5e989c649e9cbabc7abca847d8909d73fac20399", + "0x13be79c25290c639794d75b9890d17acff7c0d95", + "0x976f972191ef68506368d2d52c7bc8d0ced1619f", + "0x6e10aacb89a28d6fa0fe68790777fec7e7f01890", + "0xbbff862d906e348e9946bfb2132ecb157da3d4b4", + "0xbe3547a464d03b226cf4be2c48629694450e3773", + "0xc12d1c73ee7dc3615ba4e37e4abfdbddfa38907e", + "0x4c81d9341c527b695298e4f08df9750b5ee055d8", + "0x595643d83b35df38e29058976c04000acfa31570", + "0x27f938d01231832cb11a56300aaa724d9f3bc961", + "0x969c736577b7cfaad322abbbd6db9bd057f6afca", + "0x0000a5050a8036d29afa9bf36546efe225ed51e9", + "0xc634108996f8a3876cc34f83f6453ae19e4ecfb3", + "0xc6a74a98f6202b47752c35a992a73d4c2284ee43", + "0x97880c1dd3b7f12f9117d234fa1cebe48fcdbd04", + "0x6e90f510d389688132f50acfb812a6a1f4d3317b", + "0x7d85e23014f84e6e21d5663acd8751bef3562352", + "0x85e076361cc813a908ff672f9bad1541474402b2", + "0x0b94cd8499a950cfd31c04247c293f2f95093f9b", + "0x2b42dc7ad5dd7d28a8b8ecd2d2a3e365ad12478b", + "0x123ab195dd38b1b40510d467a6a359b201af056f", + "0xbeb9ef514a379b997e0798fdcc901ee474b6d9a1", + "0xc75f15ada581219c95485c578e124df3985e4ce0", + "0x5d8d9f5b96f4438195be9b99eee6118ed4304286", + "0x48be867b240d2ffaff69e0746130f2c027d8d3d2", + "0x9f86f40999522ca55df01b2f3bce93615846c47a", + "0xd29fabc16cb57511844ae9cbda3cddf601e1489b", + "0xbe434a1b376ee521dd4c318d5ae5726efd4a69a1", + "0x4b3a0c6d668b43f3f07904e124328659b90bb4ca", + "0x1b22c32cd936cb97c28c5690a0695a82abf688e6", + "0x9d9200af83ad0cc3c95ce553a135602ac1aa5919", + "0xe0b7927c4af23765cb51314a0e0521a9645f0e2a", + "0xb5a5f22694352c15b00323844ad545abb2b11028", + "0x45128cb743951121fb70cb570c0784492732778a", + "0x960b236a07cf122663c4303350609a66a7b288c0", + "0x4fe83213d56308330ec302a8bd641f1d0113a4cc", + "0xb8c77482e45f1f44de1745f52c74426c631bdd52", + "0xb5a73f5fc8bbdbce59bfd01ca8d35062e0dad801", + "0x419d0d8bdd9af5e606ae2232ed285aff190e711b", + "0x884a5b1438588239bc4ec652538b12d620f8f083", + "0xf4727665f750c2764f16180efdbe85b106d1f0ad", + "0x5f3d5f3cd36592abb51dbfbfdb3e7716eb30610d", + "0x39bb259f66e1c59d5abef88375979b4d20d98022", + "0xebbdf302c940c6bfd49c6b165f457fdb324649bc", + "0x915044526758533dfb918eceb6e44bc21632060d", + "0xa4e8c3ec456107ea67d3075bf9e3df3a75823db0", + "0x80a7e048f37a50500351c204cb407766fa3bae7f", + "0x41ab1b6fcbb2fa9dced81acbdec13ea6315f2bf2", + "0x56a980328aee33aabb540a02e002c8323326bf36", + "0x882d911c2fdce3cfa37c6ebbae7d8d3beeb6d17f", + "0x8bef82e549c29affcefdb73214ea436fcb98e9fa", + "0x27dce1ec4d3f72c3e457cc50354f1f975ddef488", + "0x4c218ac55d53e9de63214f7dde5b4db2a5d48ed3", + "0xbb8a43af111b59c7742f36e9cd245357d04059fd", + "0x0cd7ca934c174f43b2c69683ed302db0f5cf199e", + "0xf76da36fe74bb8b36d56cb96f4866ada345b65fa", + "0x8a1e3930fde1f151471c368fdbb39f3f63a65b55", + "0x6b963f7b38980f5fbbd129fe98059eb2144076a7", + "0xdf347911910b6c9a4286ba8e2ee5ea4a39eb2134", + "0xe83e098eedb43b33d340d4757529e5a2c4ee3230", + "0xf0f8b0b8dbb1124261fc8d778e2287e3fd2cf4f5", + "0x0a9c5b451dd8a467e80671380a875085fe053e30", + "0x1234567461d3f8db7496581774bd869c83d51c93", + "0x96a65609a7b84e8842732deb08f56c3e21ac6f8a", + "0xfdff4c1ad7712cc11725ac4aa1eed5fb687595f4", + "0x4672bad527107471cb5067a887f4656d585a8a31", + "0xf0ee6b27b759c9893ce4f094b49ad28fd15a23e4", + "0x92a5b04d0ed5d94d7a193d1d334d3d16996f4e13", + "0x17fd666fa0784885fa1afec8ac624d9b7e72b752", + "0x9dc1ce41ca15d5f500f50ea7da15da21e4f80a1a", + "0x71d01db8d6a2fbea7f8d434599c237980c234e4c", + "0x014b50466590340d41307cc54dcee990c8d58aa8", + "0x9c23d67aea7b95d80942e3836bcdf7e708a747c2", + "0x8844d0ccf85bc11d4d9b9c98c60a26762d43f216", + "0xfd0df7b58bd53d1dd4835ecd69a703b4b26f7816", + "0x8ef7c0cf8fe68076446803bb9035bd2a3a5e1581", + "0xb3203db25a01fa7950a860b42b899ad7da52ddd6", + "0x7728dfef5abd468669eb7f9b48a7f70a501ed29d", + "0x1844b21593262668b7248d0f57a220caaba46ab9", + "0xfc3f409be8d8325d419cb80d68b0f571c6da8f67", + "0xc029ba3dc12e1834571e821d94a07de0a01138ea", + "0x160383dfbe5b0c17068991daf8d4570711c354d1", + "0x4156d3342d5c385a87d264f90653733592000581", + "0xe25b0bba01dc5630312b6a21927e578061a13f55", + "0x6175f6f85339f1e56affac5a68cbf8297969004d", + "0xd5f788ca0de8f17cbde1d1e35aa8f005a87fa00b", + "0xa2b0fde6d710e201d0d608e924a484d1a5fed57c", + "0xee8bd1502c3e9f6c543781467c01592ac51cfbb8", + "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", + "0x08f5a9235b08173b7569f83645d2c7fb55e8ccd8", + "0x24692791bc444c5cd0b81e3cbcaba4b04acd1f3b", + "0x8f3470a7388c05ee4e7af3d01d8c722b0ff52374", + "0x24dcc881e7dd730546834452f21872d5cb4b5293", + "0x26ce25148832c04f3d7f26f32478a9fe55197166", + "0xb5a4ac5b04e777230ba3381195eff6a60c3934f2", + "0x2baecdf43734f22fd5c152db08e3c27233f0c7d2", + "0x71fc860f7d3a592a4a98740e39db31d25db65ae8", + "0xcdcfc0f66c522fd086a1b725ea3c0eeb9f9e8814", + "0xed30dd7e50edf3581ad970efc5d9379ce2614adb", + "0xdd974d5c2e2928dea5f71b9825b8b646686bd200", + "0xfb62ae373aca027177d1c18ee0862817f9080d08", + "0xad4f86a25bbc20ffb751f2fac312a0b4d8f88c64", + "0x91dfbee3965baaee32784c2d546b7a0c62f268c9", + "0xf5d669627376ebd411e34b98f19c868c8aba5ada", + "0x82dfdb2ec1aa6003ed4acba663403d7c2127ff67", + "0x62a6738d887f47e297676fab05b902709b106c64", + "0x43f11c02439e2736800433b4594994bd43cd066d", + "0x7ff4169a6b5122b664c51c95727d87750ec07c84", + "0xc1bfccd4c29813ede019d00d2179eea838a67703", + "0x777e2ae845272a2f540ebf6a3d03734a5a8f618e", + "0x8b3192f5eebd8579568a2ed41e6feb402f93f73f", + "0x4688a8b1f292fdab17e9a90c8bc379dc1dbd8713", + "0x2aeccb42482cc64e087b6d2e5da39f5a7a7001f8", + "0x1412eca9dc7daef60451e3155bb8dbf9da349933", + "0x2de72ada48bdf7bac276256d3f016fe058490c34", + "0x4922a015c4407f87432b179bb209e125432e4a2a", + "0x93b2fff814fcaeffb01406e80b4ecd89ca6a021b", + "0xfa5e27893aee4805283d86e4283da64f8c72dd56", + "0xc6b11850241c5127eab73af4b6c68bc267cbbff4", + "0x452b421be5b30f0c6ad8c3f03c06bdaab4f5c56c", + "0x0578779e746d7186253a36cf651ea786acfcf087", + "0xf9aba2e43fb19184408ea3b572a0fd672946f87b", + "0xdb0991dfc7e828b5a2837dc82d68e16490562c8d", + "0xe951ebe6b4420ab3f4844cf36dedd263d095b416", + "0x9215bd49b59748419eac6bad9dbe247df06ebdb9", + "0xe3a2c34fa2f59ffa95c4acd1e5663633d45bc3ad", + "0x05977ebc26825c0cd6097e0ad7204721516711eb", + "0x31f88266301b08631f9f0e33fd5c43c2a5d1e5b2", + "0xd1cec2f67fdc4c60e0963515dfc3343f31e32e47", + "0x15844029b2c2bf24506e9937739a9a912f1e4354", + "0x5562c33c383f6386be4f6dcdbd35a3a99bbcfde6", + "0x3cbfc1397def0602c2d211c70a1c0c38cedb5448", + "0x98cc3bd6af1880fcfda17ac477b2f612980e5e33", + "0x8ed9f862363ffdfd3a07546e618214b6d59f03d4", + "0x176c674ee533c6139b0dc8b458d72a93dcb3e705", + "0x8a8079c7149b8a1611e5c5d978dca3be16545f83", + "0xafd870f32ce54efdbf677466b612bf8ad164454b", + "0x336213e1ddfc69f4701fc3f86f4ef4a160c1159d", + "0x6345728b1cce16e6f8c509950b5c84fff88530d9", + "0xcb98f42221b2c251a4e74a1609722ee09f0cc08e", + "0x14d10003807ac60d07bb0ba82caeac8d2087c157", + "0x46a97629c9c1f58de6ec18c7f536e7e6d6a6ecde", + "0xf4eebdd0704021ef2a6bbe993fdf93030cd784b4", + "0xd50c1746d835d2770dda3703b69187bffeb14126", + "0xa9859874e1743a32409f75bb11549892138bba1e", + "0x2d7ac061fc3db53c39fe1607fb8cec1b2c162b01", + "0x79da1431150c9b82d2e5dfc1c68b33216846851e", + "0xa5a5df41883cdc00c4ccc6e8097130535399d9a3", + "0x0fed38108bdb8e62ef7b5680e8e0726e2f29e0de", + "0xc5807183a9661a533cb08cbc297594a0b864dc12", + "0x36a00ff9072570ef4b9292117850b8fe08d96cce", + "0x4adf728e2df4945082cdd6053869f51278fae196", + "0x27269b3e45a4d3e79a3d6bfee0c8fb13d0d711a6", + "0x8deef89058090ac5655a99eeb451a4f9183d1678", + "0x592244301cea952d6dab2fdc1fe6bd9e53917306", + "0xcd39b5434a0a92cf47d1f567a7df84be356814f0", + "0x7537aae01f3b218dae75e10d952473823f961b87", + "0xd2df355c19471c8bd7d8a3aa27ff4e26a21b4076", + "0xe36e2d3c7c34281fa3bc737950a68571736880a1", + "0x9cf7e61853ea30a41b02169391b393b901eac457", + "0xf48e200eaf9906362bb1442fca31e0835773b8b4", + "0x617aecb6137b5108d1e7d4918e3725c8cebdb848", + "0xfe18be6b3bd88a2d2a7f928d00292e7a9963cfc6", + "0xeabacd844a196d7faf3ce596edebf9900341b420", + "0x0f83287ff768d1c1e17a42f44d644d7f22e8ee1d", + "0x9eef4ca7ab9fa8bc0650127341c2d3f707a40f8a", + "0xeb029507d3e043dd6c87f2917c4e82b902c35618", + "0xd38aeb759891882e78e957c80656572503d8c1b1", + "0xfe33ae95a9f0da8a845af33516edc240dcd711d6", + "0xe1afe1fd76fd88f78cbf599ea1846231b8ba3b6b", + "0x1715ac0743102bf5cd58efbb6cf2dc2685d967b6", + "0x88c8cf3a212c0369698d13fe98fcb76620389841", + "0x22602469d704bffb0936c7a7cfcd18f7aa269375", + "0xd71ecff9342a5ced620049e616c5035f1db98620", + "0xf50b5e535f62a56a9bd2d8e2434204e726c027fa", + "0x23348160d7f5aca21195df2b70f28fce2b0be9fc", + "0x97fe22e7341a0cd8db6f6c021a24dc8f4dad855f", + "0xc63b8ecce56ab9c46184ec6ab85e4771fea4c8ad", + "0xf6b1c627e95bfc3c1b4c9b825a032ff0fbf3e07d", + "0x269895a3df4d73b077fc823dd6da1b95f72aaf9b", + "0xc14103c2141e842e228fbac594579e798616ce7a", + "0x745a824d6abbd236aa794b5530062778a6ad7523", + "0x5a7e3c07604eb515c16b36cd51906a65f021f609", + "0x757de3ac6b830a931ef178c6634c5c551773155c", + "0x6d16cf3ec5f763d4d99cb0b0b110eefd93b11b56", + "0xd31533e8d0f3df62060e94b3f1318137bb6e3525", + "0x0352557b007a4aae1511c114409b932f06f9e2f4", + "0xf2e08356588ec5cd9e437552da87c0076b4970b0", + "0x918da91ccbc32b7a6a0cc4ecd5987bbab6e31e6d", + "0x30635297e450b930f8693297eba160d9e6c8ebcf", + "0x6a22e5e94388464181578aa7a6b869e00fe27846", + "0x261efcdd24cea98652b9700800a13dfbca4103ff", + "0x5299d6f7472dcc137d7f3c4bcfbbb514babf341a", + "0x2e59005c5c0f0a4d77cca82653d48b46322ee5cd", + "0x992058b7db08f9734d84485bfbc243c4ee6954a7", + "0x81ab848898b5ffd3354dbbefb333d5d183eedcb5", + "0xb2fdd60ad80ca7ba89b9bab3b5336c2601c020b4", + "0x208d174775dc39fe18b1b374972f77ddec6c0f73", + "0xf06ddacf71e2992e2122a1a0168c6967afdf63ce", + "0xd16c79c8a39d44b2f3eb45d2019cd6a42b03e2a9", + "0x3d995510f8d82c2ea341845932b5ddde0bead9a3", + "0x90f802c7e8fb5d40b0de583e34c065a3bd2020d8", + "0x002f0b1a71c5730cf2f4da1970a889207bdb6d0d", + "0x1062ad0e59fa67fa0b27369113098cc941dd0d5f", + "0xf93340b1a3adf7eedcaec25fae8171d4b736e89f", + "0x84bd083b1c8bf929f39c98bc17cf518f40154f58", + "0x81fab276aec924fbde190cf379783526d413cf70", + "0x4e110603e70b0b5f1c403ee543b37e1f1244cf28", + "0xcf55a7f92d5e0c6683debbc1fc20c0a6e056df13", + "0x654eebac62240e6c56bab5f6adf7cfa74a894510", + "0xa48920cc1ad85d8ea13af5d7be180c0338c306dd", + "0x249a198d59b57fda5dda90630febc86fd8c7594c", + "0x5ed1406873c9eb91f6f9a67ac4e152387c1132e7", + "0x8104c9f13118320eefe5fbea8a44d600b85981ef", + "0x69746c719e59674b147df25f50e7cfa0673cb625", + "0x6b1257641d18791141f025eab36fb567c4b564ff", + "0x4e83b6287588a96321b2661c5e041845ff7814af", + "0x59fec83ec709c893aedd1a144cf1828eb04127cd", + "0x89337bfb7938804c3776c9fb921eccaf5ab76758", + "0xec58d3aefc9aaa2e0036fa65f70d569f49d9d1ed", + "0xa6b9d7e3d76cf23549293fb22c488e0ea591a44e", + "0xe813b65da6c38a04591aed3f082d32db7d53c382", + "0x4b606e9eb2228c70f44453afe5a73e1fea258ce1", + "0x5247c0db4044fb6f97f32c7e1b48758019a5a912", + "0x56fb1acaff95c0b6ebcd17c8361a63d98b1a5a11", + "0xd49fa405dce086c65d66ca1ca41f8e98583812b4", + "0x29dddacba3b231ee8d673dd0f0fa759ea145561b", + "0xcbe430927370e95b4b10cfc702c6017ec7abefc3", + "0x4b7fb448df91c8ed973494f8c8c4f12daf3a8521", + "0x3108c33b6fb38efedaefd8b5f7ca01d5f5c7372d", + "0x0cae9e4d663793c2a2a0b211c1cf4bbca2b9caa7", + "0x31c63146a635eb7465e5853020b39713ac356991", + "0x59a921db27dd6d4d974745b7ffc5c33932653442", + "0xf72fcd9dcf0190923fadd44811e240ef4533fc86", + "0x56aa298a19c93c6801fdde870fa63ef75cc0af72", + "0x0e99cc0535bb6251f6679fa6e65d6d3b430e840b", + "0x13b02c8de71680e71f0820c996e4be43c2f57d15", + "0x41bbedd7286daab5910a1f15d12cbda839852bd7", + "0x9d1555d8cb3c846bb4f7d5b1b1080872c3166676", + "0x21ca39943e91d704678f5d00b6616650f066fd63", + "0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359", + "0xc76fb75950536d98fa62ea968e1d6b45ffea2a55", + "0x3c9d6c1c73b31c837832c72e04d3152f051fc1a9", + "0xed91879919b71bb6905f23af0a68d231ecf87b14", + "0xf0fac7104aac544e4a7ce1a55adf2b5a25c65bd1", + "0xd341d1680eeee3255b8c4c75bcce7eb57f144dae", + "0xa89ac6e529acf391cfbbd377f3ac9d93eae9664e", + "0x28cb7e841ee97947a86b06fa4090c8451f64c0be", + "0xf29e46887ffae92f1ff87dfe39713875da541373", + "0x39eae99e685906ff1c11a962a743440d0a1a6e09", + "0x7b123f53421b1bf8533339bfbdc7c98aa94163db", + "0xd2dda223b2617cb616c1580db421e4cfae6a8a85", + "0x4b4701f3f827e1331fb22ff8e2beac24b17eb055", + "0x34612903db071e888a4dadcaa416d3ee263a87b9", + "0x1f3f9d3068568f8040775be2e8c03c103c61f3af", + "0x8eef5a82e6aa222a60f009ac18c24ee12dbf4b41", + "0x4639cd8cd52ec1cf2e496a606ce28d8afb1c792f", + "0x0f51bb10119727a7e5ea3538074fb341f56b09ad", + "0x5ca9a71b1d01849c0a95490cc00559717fcf0d1d", + "0x0bf6261297198d91d4fa460242c69232146a5703", + "0x7ef1081ecc8b5b5b130656a41d4ce4f89dbbcc8c", + "0xe54f9e6ab80ebc28515af8b8233c1aee6506a15e", + "0x2f3e054d233c93c59140c0905227c7c607c70cbb", + "0x98e0438d3ee1404fea48e38e92853bb08cfa68bd", + "0xba745513acebcbb977497c569d4f7d340f2a936b", + "0xea004e8fa3701b8e58e41b78d50996e0f7176cbd", + "0x2dbd330bc9b7f3a822a9173ab52172bdddcace2a", + "0xbf4a9a37ecfc21825011285222c36ab35de51f14", + "0xb97d5cf2864fb0d08b34a484ff48d5492b2324a0", + "0xd8c82fbc4d8ed0644a7ec04cf973e84c6153c1d7", + "0x6f3009663470475f0749a6b76195375f95495fcb", + "0xe6410569602124506658ff992f258616ea2d4a3d", + "0x4b4f5286e0f93e965292b922b9cd1677512f1222", + "0x0501e7a02c285b9b520fdbf1badc74ae931ad75d", + "0x90d702f071d2af33032943137ad0ab4280705817", + "0xb944b46bbd4ccca90c962ef225e2804e46691ccf", + "0xc89b4a8a121dd3e726fe7515e703936cf83e3350", + "0x3c4030839708a20fd2fb379cf11810dde4888d93", + "0xd4ca5c2aff1eefb0bea9e9eab16f88db2990c183", + "0xc8ce75f643ecad864fc625902a6a07371f38320d", + "0xee9801669c6138e84bd50deb500827b776777d28", + "0x05462671c05adc39a6521fa60d5e9443e9e9d2b9", + "0x738865301a9b7dd80dc3666dd48cf034ec42bdda", + "0x4ff5253e2304e3f5ed6547ac5d9952a62b91e3e8", + "0xbd0793332e9fb844a52a205a233ef27a5b34b927", + "0x41933422dc4a1cb8c822e06f12f7b52fa5e7e094", + "0x122f96d596384885b54bccdddf2125018c421d83", + "0xd123575d94a7ad9bff3ad037ae9d4d52f41a7518", + "0x3fa729b4548becbad4eab6ef18413470e6d5324c", + "0x40897c872214303b6f479a37e549ee1516b264a2", + "0xcc665390b03c5d324d8faf81c15ecee29a73bcb4", + "0x171d750d42d661b62c277a6b486adb82348c3eca", + "0x17e347aad89b30b96557bcbfbff8a14e75cc88a1", + "0x375a08ce3a460f20bbafd282be1e3579a2c31f41", + "0x7a8ca2f815a260660158a38c34ca321a3605ecfe", + "0x8c9e4cf756b9d01d791b95bc2d0913ef2bf03784", + "0x78a52e12c7b63d05c12f9608307587cf654ec3d0", + "0x6944d3e38973c4831da24e954fbd790c7e688bdd", + "0x87f5e8c3425218837f3cb67db941af0c01323e56", + "0x5a7092cf86a6790113c4d3fa83f48fd6efa71b0d", + "0xc87e2b27f7477668cc7b97e929953802590049f7", + "0x5c743a35e903f6c584514ec617acee0611cf44f3", + "0x5c3a228510d246b78a3765c20221cbf3082b44a4", + "0x48c276e8d03813224bb1e55f953adb6d02fd3e02", + "0xab6e163cbeb3959b68b90bec722f5a9eef82ba72", + "0x714599f7604144a3fe1737c440a70fc0fd6503ea", + "0x8848812bd31aeee33313c10a840ffc3169078c5b", + "0x545290b71402e8ca677edf6296f1448edf95abe7", + "0xe0f2544d3483e454755d245f92d5bdef474ce16d", + "0xb264455716277d6d1445a4b875efab6de8931f4a", + "0x1644fa222aa3fddf9ee5c8a3876d59d2f1cab8ba", + "0x963fc20c82650d28402f703a84cde25a5b2c4a5f", + "0xd59623cfe3dbe4f63e02e6add0f25d3b532b21ce", + "0x42237ac5aed08d64feae4817fa1f0282087447f7", + "0x08f9862424e2a8f7d7bdcd2c8c33c12d6cfbd43e", + "0x7c947c432a8b47fed452dbe026cc6648ad6a2cc6", + "0x4115454c188acfb9cb67c6d795214055381b53b5", + "0x58f43dc7968012f4db78ec97a36c9998658ffccc", + "0xbdb5f6d15ce744dd4f86c26e134077debfb69d6b", + "0x0c048e6bee9570427b0617806eb6244cdcd30295", + "0xbbd7c868b6b9f53068e0abb5b05868d6dfbdf82e", + "0xb7fc05dc3bf10628b008e36c079d2a85621dab7a", + "0xcdca7042bc49ea2aa25c021bc970566b48ad594e", + "0x54655b64235ee8ff4509a95e80b2359dc94991b4", + "0x19e8e359c65e794578df4284c10cb943ab6b087c", + "0x7bde93c2480750654ad2291af7424b794cfa31c2", + "0x2d706c835281d330e7fd40187286f67bce06ff72", + "0x9a58e231de6a0349cf7262400819c21a2267d09c", + "0x353d991a87f935af6b8e6fef4e73372322d1fb9f", + "0x559cc0850361afe1973c0ba5d0a3446c8a5ad678", + "0xf71a2d1303d2798d2c134597bce1f95928b62fca", + "0xcecdd3fac0cbd4733d0fa2ca161885174d5dcbde", + "0x5870700f1272a1adbb87c3140bd770880a95e55d", + "0xc3cc3076cb304494775b3193ef1aa080ba6bf962", + "0xb62e45c3df611dce236a6ddc7a493d79f9dfadef", + "0xe2f12bf6fdb06d717c5d4ee6afe29c401250e663", + "0x3b010020bb3d901e0d2e1986213ea8057a728ebf", + "0xd32c6bace4f8313c9672ace2799c78d732d5c13b", + "0xce87a9d2f96b4e41ade825ba56dc24699c8cf26d", + "0xb697adf526a4899c48390087946d790572837819", + "0x37da9de38c4094e090c014325f6ef4baeb302626", + "0x3f73108cfd890b3495dde34f7c236352cf2d9969", + "0x3ef9181c9b96baaafb3717a553e808ccc72be37d", + "0xb0ad00f5fd367bb384c22b11f539aa4d3009767e", + "0x83306cfd5fc8cb4a9e1ea265dce59f9e016f49c1", + "0x18084fba666a33d37592fa2633fd49a74dd93a88", + "0x9b73a367d09cd83e94e81e615af10e9ed7930858", + "0x46b91d7e028ebdb17d3fbc245f5eba3da9003aec", + "0x077493a615f2e903c30b4da919c738de1fb815e5", + "0x593a3e0037c18237e153f9d00797926866ee923d", + "0x167b3658750dcb1d56690cf94d09410d5d980bda", + "0x8965349fb649a33a30cbfda057d8ec2c48abe2a2", + "0x35e049f9ef07b452570c227afa6640cf42a75d96", + "0x2df54842cd85c60f21b4871e09bcc6047b2dcc4d", + "0x3a880652f47bfaa771908c07dd8673a787daed3a", + "0xd291e7a03283640fdc51b121ac401383a46cc623", + "0x3af33bef05c2dcb3c7288b77fe1c8d2aeba4d789", + "0x418d75f65a02b3d53b2418fb8e1fe493759c7605", + "0x097242a5cad85f62b12830754f1062587e13c18a", + "0x7452e3fc2fe611c6b7761c6c393bece059881ac7", + "0x037a54aab062628c9bbae1fdb1583c195585fe41", + "0x55296f69f40ea6d20e478533c15a6b08b654e758", + "0xff20817765cb7f73d4bde2e66e067e58d11095c2", + "0xe7804d91dfcde7f776c90043e03eaa6df87e6395", + "0x7e43d25ead96b1058f671f6690ea705ba2c7e5b9", + "0xcf39b7793512f03f2893c16459fd72e65d2ed00c", + "0x595832f8fc6bf59c85c527fec3740a1b7a361269", + "0xf1f955016ecbcd7321c7266bccfb96c68ea5e49b", + "0xf5832512cfda8083e5b2dd0aa7c1b9265c03ba1f", + "0xa3d58c4e56fedcae3a7c43a725aee9a71f0ece4e", + "0x533ba8a236c6b7dd2cf8e49fe8cefa30cef0c4bd", + "0x2f9a8b57b29e12a226590ff36c4b9729d4f779bf", + "0x6b60ee11b73230045cf9095e6e43ae9ea638e172", + "0x7277a44d1325d81ac58893002a1b40a41bea43fe", + "0x76175599887730786bda1545d0d7ace8737febb1", + "0xa82aa729ae2f0d78e961d66db53949e27a9e866d", + "0x322a46e88fa3c78f9c9e3dbb0254b61664a06109", + "0x8290d7a64f25e6b5002d98367e8367c1b532b534", + "0x26de40bffafe73ff4e37089b2c71e35fd02eb1a7", + "0x3d1ba9be9f66b8ee101911bc36d3fb562eac2244", + "0x10b35b348fd49966f2baf81df35a511c18bd1f80", + "0x47bc01597798dcd7506dcca36ac4302fc93a8cfb", + "0xc96df921009b790dffca412375251ed1a2b75c60", + "0xd6bd97a26232ba02172ff86b055d5d7be789335b", + "0x0ec72cd6690db40b16be166858299f19d4f8e5b0", + "0x15d4c048f83bd7e37d49ea4c83a07267ec4203da", + "0xeb3c8fc829d6afef0c3710aa22860c28c50755fe", + "0x8e00615469d759a0df6855dfb0963948888827a1", + "0x6b432d4aca9268fbf282c32143e9328ceb9190b8", + "0x221abee39e205a597acd80abc9d026d57108f5bf", + "0x58be0185356ad7cc59950d13ad2cd43c69de2e04", + "0xe574c0c33a7a67d9b09f9f0addbb3dca71a8f3e0", + "0x2b591e99afe9f32eaa6214f7b7629768c40eeb39", + "0x40eb49c971bceda8ea9998256aa7375f6bf05e90", + "0x3434d708ee9802125a24277326eeeea824a53e11", + "0xaaaebe6fe48e54f431b0c390cfaf0b017d09d42d", + "0x3c4b6e6e1ea3d4863700d7f76b36b7f3d3f13e3d", + "0xf04f22b39bf419fdec8eae7c69c5e89872915f53", + "0x85f17cf997934a597031b2e18a9ab6ebd4b9f6a4", + "0x7a1b3b2bfb687a26328e623441edaea69df3def5", + "0xc6e64729931f60d2c8bc70a27d66d9e0c28d1bf9", + "0x3506424f91fd33084466f402d5d97f05f8e3b4af", + "0x4fabb145d64652a948d72533023f6e7a623c7c53", + "0x6ae5f164d006b2fcfae195436345f0aa833d4830", + "0x8d983cb9388eac77af0474fa441c4815500cb7bb", + "0xbb0e17ef65f82ab018d8edd776e8dd940327b28b", + "0xddb3422497e61e13543bea06989c0789117555c5", + "0x0f5d2fb29fb7d3cfee444a200298f468908cc942", + "0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0", + "0xb62132e35a6c13ee1ee0f84dc5d40bad8d815206", + "0x3845badade8e6dff049820680d1f14bd3903a5d0", + "0x9bf1d7d63dd7a4ce167cf4866388226eeefa702e", + "0x107c4504cd79c5d2696ea0030a8dd4e92601b82e", + "0x827d53c8170af52625f414bde00326fc8a085e86", + "0xda605fd5e003e6de0f33f6474080623fa6483e3e", + "0x888888435fde8e7d4c54cab67f206e4199454c60", + "0xaf446174961cd544e51b89310581669e8fc00d16", + "0x419c4db4b9e25d6db2ad9691ccb832c8d9fda05e", + "0x15874d65e649880c2614e7a480cb7c9a55787ff6", + "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", + "0x108caf59641fc5d27502a87e641872b62d606ae2", + "0xbae73d6dfa362f1774930100269dd98e755d05ea", + "0xeda8b016efa8b1161208cf041cd86972eee0f31e", + "0xb1979ec52cdf54f680dbddbbd619bb566ffed1f3", + "0xd2877702675e6ceb975b4a1dff9fb7baf4c91ea9", + "0x335e14d18d8a903b782a39059dc35d61b94e1c1b", + "0xd11c37cc93042acab222a881068211ee2254e465", + "0x72dd4b6bd852a3aa172be4d6c5a6dbec588cf131", + "0xd26114cd6ee289accf82350c8d8487fedb8a0c07", + "0x971d048e737619884f2df75e31c7eb6412392328", + "0xaaaf91d9b90df800df4f55c205fd6989c977e73a", + "0xa47c8bf37f92abed4a126bda807a7b7498661acd" +] diff --git a/test/e2e/mv3-perf-stats/bundle-size.js b/test/e2e/mv3-perf-stats/bundle-size.js index 9c1f78b37be1..d37ec561bde5 100755 --- a/test/e2e/mv3-perf-stats/bundle-size.js +++ b/test/e2e/mv3-perf-stats/bundle-size.js @@ -17,17 +17,17 @@ const { exitWithError } = require('../../../development/lib/exit-with-error'); */ const backgroundFiles = [ - 'runtime-lavamoat.js', - 'lockdown-more.js', - 'sentry-install.js', - 'policy-load.js', + 'scripts/runtime-lavamoat.js', + 'scripts/lockdown-more.js', + 'scripts/sentry-install.js', + 'scripts/policy-load.js', ]; const uiFiles = [ - 'sentry-install.js', - 'runtime-lavamoat.js', - 'lockdown-more.js', - 'policy-load.js', + 'scripts/sentry-install.js', + 'scripts/runtime-lavamoat.js', + 'scripts/lockdown-more.js', + 'scripts/policy-load.js', ]; const BackgroundFileRegex = /background-[0-9]*.js/u; diff --git a/test/e2e/restore/MetaMaskUserData.json b/test/e2e/restore/MetaMaskUserData.json index 4ff35c60dcf6..380efd5c5205 100644 --- a/test/e2e/restore/MetaMaskUserData.json +++ b/test/e2e/restore/MetaMaskUserData.json @@ -36,11 +36,13 @@ "showExtensionInFullSizeView": false, "showFiatInTestnets": false, "showTestNetworks": false, - "useNativeCurrencyAsPrimaryCurrency": true + "smartTransactionsOptInStatus": false, + "useNativeCurrencyAsPrimaryCurrency": true, + "showTokenAutodetectModal": "boolean" }, "theme": "light", "useBlockie": false, - "useRequestQueue": false, + "useRequestQueue": true, "useNftDetection": false, "useNonceField": false, "usePhishDetect": true, diff --git a/test/e2e/run-all.js b/test/e2e/run-all.js index c3cd39ec6ffc..0ff043261a7b 100644 --- a/test/e2e/run-all.js +++ b/test/e2e/run-all.js @@ -8,11 +8,7 @@ const { exitWithError } = require('../../development/lib/exit-with-error'); const { loadBuildTypesConfig } = require('../../development/lib/build-type'); // These tests should only be run on Flask for now. -const FLASK_ONLY_TESTS = [ - 'test-snap-txinsights-v2.spec.js', - 'test-snap-namelookup.spec.js', - 'test-snap-siginsights.spec.js', -]; +const FLASK_ONLY_TESTS = ['test-snap-namelookup.spec.js']; const getTestPathsForTestDir = async (testDir) => { const testFilenames = await fs.promises.readdir(testDir, { @@ -80,7 +76,7 @@ async function main() { choices: ['chrome', 'firefox'], }) .option('debug', { - default: process.env.E2E_DEBUG === 'true', + default: true, description: 'Run tests in debug mode, logging each driver interaction', type: 'boolean', @@ -192,8 +188,8 @@ async function main() { if (retries) { args.push('--retries', retries); } - if (debug) { - args.push('--debug'); + if (!debug) { + args.push('--debug=false'); } if (updateSnapshot) { args.push('--update-snapshot'); diff --git a/test/e2e/run-e2e-test.js b/test/e2e/run-e2e-test.js index 93b436fd15da..a4c0496dbda6 100644 --- a/test/e2e/run-e2e-test.js +++ b/test/e2e/run-e2e-test.js @@ -14,13 +14,13 @@ async function main() { (_yargs) => _yargs .option('browser', { - default: process.env.SELENIUM_BROWSER, - description: `Set the browser used; either 'chrome' or 'firefox'.`, + default: process.env.SELENIUM_BROWSER || 'all', + description: `Set the browser to be used; specify 'chrome', 'firefox', 'all' or leave unset to run on 'all' by default.`, type: 'string', - choices: ['chrome', 'firefox'], + choices: ['chrome', 'firefox', 'all'], }) .option('debug', { - default: process.env.E2E_DEBUG === 'true', + default: true, description: 'Run tests in debug mode, logging each driver interaction', type: 'boolean', @@ -79,81 +79,105 @@ async function main() { updatePrivacySnapshot, } = argv; - if (!browser) { - exitWithError( - `"The browser must be set, via the '--browser' flag or the SELENIUM_BROWSER environment variable`, - ); - return; - } else if (browser !== process.env.SELENIUM_BROWSER) { - process.env.SELENIUM_BROWSER = browser; - } - - try { - const stat = await fs.stat(e2eTestPath); - if (!stat.isFile()) { - exitWithError('Test path must be a file'); - return; - } - } catch (error) { - if (error.code === 'ENOENT') { - exitWithError('Test path specified does not exist'); - return; - } else if (error.code === 'EACCES') { + const runTestsOnSingleBrowser = async (selectedBrowserForRun) => { + if (!selectedBrowserForRun) { exitWithError( - 'Access to test path is forbidden by file access permissions', + `"The browser must be set, via the '--browser' flag or the SELENIUM_BROWSER environment variable`, ); return; + } else if (selectedBrowserForRun !== process.env.SELENIUM_BROWSER) { + process.env.SELENIUM_BROWSER = selectedBrowserForRun; + } + try { + const stat = await fs.stat(e2eTestPath); + if (!stat.isFile()) { + exitWithError('Test path must be a file'); + return; + } + } catch (error) { + if (error.code === 'ENOENT') { + exitWithError('Test path specified does not exist'); + return; + } else if (error.code === 'EACCES') { + exitWithError( + 'Access to test path is forbidden by file access permissions', + ); + return; + } + throw error; } - throw error; - } - if (debug) { - process.env.E2E_DEBUG = 'true'; - } + if (debug) { + process.env.E2E_DEBUG = 'true'; + } - let testTimeoutInMilliseconds = 80 * 1000; - let exit = '--exit'; + let testTimeoutInMilliseconds = 80 * 1000; + let exit = '--exit'; - if (leaveRunning) { - process.env.E2E_LEAVE_RUNNING = 'true'; - testTimeoutInMilliseconds = 0; - exit = '--no-exit'; - } + if (leaveRunning) { + process.env.E2E_LEAVE_RUNNING = 'true'; + testTimeoutInMilliseconds = 0; + exit = '--no-exit'; + } - if (updateSnapshot) { - process.env.UPDATE_SNAPSHOTS = 'true'; - } + if (updateSnapshot) { + process.env.UPDATE_SNAPSHOTS = 'true'; + } - if (updatePrivacySnapshot) { - process.env.UPDATE_PRIVACY_SNAPSHOT = 'true'; - } + if (updatePrivacySnapshot) { + process.env.UPDATE_PRIVACY_SNAPSHOT = 'true'; + } - const configFile = path.join(__dirname, '.mocharc.js'); - const extraArgs = process.env.E2E_ARGS?.split(' ') || []; + const configFile = path.join(__dirname, '.mocharc.js'); + const extraArgs = process.env.E2E_ARGS?.split(' ') || []; - // If mmi flag is passed - if (mmi) { - // Tests that contains `@no-mmi` will be grep (-g) and inverted (-i) - // meaning that all tests with @no-mmi in the title will be ignored - extraArgs.push('-g', '@no-mmi', '-i'); - } + // If mmi flag is passed + if (mmi) { + // Tests that contains `@no-mmi` will be grep (-g) and inverted (-i) + // meaning that all tests with @no-mmi in the title will be ignored + extraArgs.push('-g', '@no-mmi', '-i'); + } + + const dir = 'test/test-results/e2e'; + fs.mkdir(dir, { recursive: true }); - const dir = 'test/test-results/e2e'; - fs.mkdir(dir, { recursive: true }); + await retry({ retries, retryUntilFailure }, async () => { + await runInShell('yarn', [ + 'mocha', + `--config=${configFile}`, + `--timeout=${testTimeoutInMilliseconds}`, + '--reporter=mocha-junit-reporter', + '--reporter-options', + `mochaFile=test/test-results/e2e/[hash].xml,toConsole=true`, + ...extraArgs, + e2eTestPath, + exit, + ]); + }); + }; - await retry({ retries, retryUntilFailure }, async () => { - await runInShell('yarn', [ - 'mocha', - `--config=${configFile}`, - `--timeout=${testTimeoutInMilliseconds}`, - '--reporter=mocha-junit-reporter', - '--reporter-options', - `mochaFile=test/test-results/e2e/[hash].xml,toConsole=true`, - ...extraArgs, - e2eTestPath, - exit, - ]); - }); + const allBrowsers = ['chrome', 'firefox']; + if (browser === 'all') { + for (const currentBrowser of allBrowsers) { + console.log(`Running tests on ${currentBrowser}`); + try { + await runTestsOnSingleBrowser(currentBrowser); + } catch (error) { + exitWithError( + `Error occurred while running tests on ${currentBrowser}: ${error}`, + ); + } + } + } else { + console.log(`Running tests on ${browser}`); + try { + await runTestsOnSingleBrowser(browser); + } catch (error) { + exitWithError( + `Error occurred while running tests on ${browser}: ${error}`, + ); + } + } } main().catch((error) => { diff --git a/test/e2e/run-openrpc-api-test-coverage.ts b/test/e2e/run-openrpc-api-test-coverage.ts new file mode 100644 index 000000000000..f192f6088954 --- /dev/null +++ b/test/e2e/run-openrpc-api-test-coverage.ts @@ -0,0 +1,410 @@ +import testCoverage from '@open-rpc/test-coverage'; +import { parseOpenRPCDocument } from '@open-rpc/schema-utils-js'; +import HtmlReporter from '@open-rpc/test-coverage/build/reporters/html-reporter'; +import ExamplesRule from '@open-rpc/test-coverage/build/rules/examples-rule'; +import JsonSchemaFakerRule from '@open-rpc/test-coverage/build/rules/json-schema-faker-rule'; + +import { + ExampleObject, + ExamplePairingObject, + MethodObject, +} from '@open-rpc/meta-schema'; +import openrpcDocument from '@metamask/api-specs'; +import { ConfirmationsRejectRule } from './api-specs/ConfirmationRejectionRule'; + +import { Driver, PAGES } from './webdriver/driver'; + +import { createDriverTransport } from './api-specs/helpers'; + +import FixtureBuilder from './fixture-builder'; +import { + withFixtures, + openDapp, + unlockWallet, + DAPP_URL, + ACCOUNT_1, +} from './helpers'; + +// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires +const mockServer = require('@open-rpc/mock-server/build/index').default; + +async function main() { + const port = 8545; + const chainId = 1337; + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder().build(), + disableGanache: true, + title: 'api-specs coverage', + }, + async ({ driver }: { driver: Driver }) => { + await unlockWallet(driver); + + // Navigate to extension home screen + await driver.navigate(PAGES.HOME); + + // Open Dapp + await openDapp(driver, undefined, DAPP_URL); + + const transport = createDriverTransport(driver); + + const transaction = + openrpcDocument.components?.schemas?.TransactionInfo?.allOf?.[0]; + + if (transaction) { + delete transaction.unevaluatedProperties; + } + + const chainIdMethod = openrpcDocument.methods.find( + (m) => (m as MethodObject).name === 'eth_chainId', + ); + (chainIdMethod as MethodObject).examples = [ + { + name: 'chainIdExample', + description: 'Example of a chainId request', + params: [], + result: { + name: 'chainIdResult', + value: `0x${chainId.toString(16)}`, + }, + }, + ]; + + const getBalanceMethod = openrpcDocument.methods.find( + (m) => (m as MethodObject).name === 'eth_getBalance', + ); + + (getBalanceMethod as MethodObject).examples = [ + { + name: 'getBalanceExample', + description: 'Example of a getBalance request', + params: [ + { + name: 'address', + value: ACCOUNT_1, + }, + { + name: 'tag', + value: 'latest', + }, + ], + result: { + name: 'getBalanceResult', + value: '0x1a8819e0c9bab700', // can we get this from a variable too + }, + }, + ]; + + const blockNumber = openrpcDocument.methods.find( + (m) => (m as MethodObject).name === 'eth_blockNumber', + ); + + (blockNumber as MethodObject).examples = [ + { + name: 'blockNumberExample', + description: 'Example of a blockNumber request', + params: [], + result: { + name: 'blockNumberResult', + value: '0x1', + }, + }, + ]; + + const personalSign = openrpcDocument.methods.find( + (m) => (m as MethodObject).name === 'personal_sign', + ); + + (personalSign as MethodObject).examples = [ + { + name: 'personalSignExample', + description: 'Example of a personalSign request', + params: [ + { + name: 'data', + value: '0xdeadbeef', + }, + { + name: 'address', + value: ACCOUNT_1, + }, + ], + result: { + name: 'personalSignResult', + value: '0x1a8819e0c9bab700', + }, + }, + ]; + + const switchEthereumChain = openrpcDocument.methods.find( + (m) => (m as MethodObject).name === 'wallet_switchEthereumChain', + ); + (switchEthereumChain as MethodObject).examples = [ + { + name: 'wallet_switchEthereumChain', + description: + 'Example of a wallet_switchEthereumChain request to sepolia', + params: [ + { + name: 'SwitchEthereumChainParameter', + value: { + chainId: '0xaa36a7', + }, + }, + ], + result: { + name: 'wallet_switchEthereumChain', + value: null, + }, + }, + ]; + + const signTypedData4 = openrpcDocument.methods.find( + (m) => (m as MethodObject).name === 'eth_signTypedData_v4', + ); + + const signTypedData4Example = (signTypedData4 as MethodObject) + .examples?.[0] as ExamplePairingObject; + + // just update address for signTypedData + (signTypedData4Example.params[0] as ExampleObject).value = ACCOUNT_1; + + // update chainId for signTypedData + ( + signTypedData4Example.params[1] as ExampleObject + ).value.domain.chainId = 1337; + + // net_version missing from execution-apis. see here: https://github.com/ethereum/execution-apis/issues/540 + const netVersion: MethodObject = { + name: 'net_version', + summary: 'Returns the current network ID.', + params: [], + result: { + description: 'Returns the current network ID.', + name: 'net_version', + schema: { + type: 'string', + }, + }, + description: 'Returns the current network ID.', + examples: [ + { + name: 'net_version', + description: 'Example of a net_version request', + params: [], + result: { + name: 'net_version', + description: 'The current network ID', + value: '0x1', + }, + }, + ], + }; + // add net_version + (openrpcDocument.methods as MethodObject[]).push( + netVersion as unknown as MethodObject, + ); + + const getEncryptionPublicKey = openrpcDocument.methods.find( + (m) => (m as MethodObject).name === 'eth_getEncryptionPublicKey', + ); + + (getEncryptionPublicKey as MethodObject).examples = [ + { + name: 'getEncryptionPublicKeyExample', + description: 'Example of a getEncryptionPublicKey request', + params: [ + { + name: 'address', + value: ACCOUNT_1, + }, + ], + result: { + name: 'getEncryptionPublicKeyResult', + value: '0x1a8819e0c9bab700', + }, + }, + ]; + + const getTransactionCount = openrpcDocument.methods.find( + (m) => (m as MethodObject).name === 'eth_getTransactionCount', + ); + (getTransactionCount as MethodObject).examples = [ + { + name: 'getTransactionCountExampleEarliest', + description: 'Example of a pending getTransactionCount request', + params: [ + { + name: 'address', + value: ACCOUNT_1, + }, + { + name: 'tag', + value: 'earliest', + }, + ], + result: { + name: 'getTransactionCountResult', + value: '0x0', + }, + }, + { + name: 'getTransactionCountExampleFinalized', + description: 'Example of a pending getTransactionCount request', + params: [ + { + name: 'address', + value: ACCOUNT_1, + }, + { + name: 'tag', + value: 'finalized', + }, + ], + result: { + name: 'getTransactionCountResult', + value: '0x0', + }, + }, + { + name: 'getTransactionCountExampleSafe', + description: 'Example of a pending getTransactionCount request', + params: [ + { + name: 'address', + value: ACCOUNT_1, + }, + { + name: 'tag', + value: 'safe', + }, + ], + result: { + name: 'getTransactionCountResult', + value: '0x0', + }, + }, + { + name: 'getTransactionCountExample', + description: 'Example of a getTransactionCount request', + params: [ + { + name: 'address', + value: ACCOUNT_1, + }, + { + name: 'tag', + value: 'latest', + }, + ], + result: { + name: 'getTransactionCountResult', + value: '0x0', + }, + }, + // returns a number right now. see here: https://github.com/MetaMask/metamask-extension/pull/14822 + // { + // name: 'getTransactionCountExamplePending', + // description: 'Example of a pending getTransactionCount request', + // params: [ + // { + // name: 'address', + // value: ACCOUNT_1, + // }, + // { + // name: 'tag', + // value: 'pending', + // }, + // ], + // result: { + // name: 'getTransactionCountResult', + // value: '0x0', + // }, + // }, + ]; + + const server = mockServer(port, openrpcDocument); + server.start(); + + // TODO: move these to a "Confirmation" tag in api-specs + const methodsWithConfirmations = [ + 'wallet_requestPermissions', + 'eth_requestAccounts', + 'wallet_watchAsset', + 'personal_sign', // requires permissions for eth_accounts + 'wallet_addEthereumChain', + 'eth_signTypedData_v4', // requires permissions for eth_accounts + 'wallet_switchEthereumChain', + + // commented out because its not returning 4001 error. + // see here https://github.com/MetaMask/metamask-extension/issues/24227 + // 'eth_getEncryptionPublicKey', // requires permissions for eth_accounts + ]; + const filteredMethods = openrpcDocument.methods + .filter((_m: unknown) => { + const m = _m as MethodObject; + return ( + m.name.includes('snap') || + m.name.includes('Snap') || + m.name.toLowerCase().includes('account') || + m.name.includes('crypt') || + m.name.includes('blob') || + m.name.includes('sendTransaction') || + m.name.startsWith('wallet_scanQRCode') || + methodsWithConfirmations.includes(m.name) || + // filters are currently 0 prefixed for odd length on + // extension which doesn't pass spec + // see here: https://github.com/MetaMask/eth-json-rpc-filters/issues/152 + m.name.includes('filter') || + m.name.includes('Filter') + ); + }) + .map((m) => (m as MethodObject).name); + + const testCoverageResults = await testCoverage({ + openrpcDocument: (await parseOpenRPCDocument( + openrpcDocument as never, + )) as never, + transport, + reporters: [ + 'console-streaming', + new HtmlReporter({ autoOpen: !process.env.CI }), + ], + skip: [ + 'eth_coinbase', + // these 2 methods below are not supported by MetaMask extension yet and + // don't get passed through. See here: https://github.com/MetaMask/metamask-extension/issues/24225 + 'eth_getBlockReceipts', + 'eth_maxPriorityFeePerGas', + ], + rules: [ + new JsonSchemaFakerRule({ + only: [], + skip: filteredMethods, + numCalls: 2, + }), + new ExamplesRule({ + only: [], + skip: filteredMethods, + }), + new ConfirmationsRejectRule({ + driver, + only: methodsWithConfirmations, + }), + ], + }); + + await driver.quit(); + + // if any of the tests failed, exit with a non-zero code + if (testCoverageResults.every((r) => r.valid)) { + process.exit(0); + } else { + process.exit(1); + } + }, + ); +} + +main(); diff --git a/test/e2e/ganache.ts b/test/e2e/seeder/ganache.ts similarity index 87% rename from test/e2e/ganache.ts rename to test/e2e/seeder/ganache.ts index f838dcde028d..e7eab2461a86 100644 --- a/test/e2e/ganache.ts +++ b/test/e2e/seeder/ganache.ts @@ -14,6 +14,8 @@ const defaultOptions = { export class Ganache { #server: Server | undefined; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any async start(opts: any) { const options = { ...defaultOptions, ...opts }; @@ -36,7 +38,7 @@ export class Ganache { const accounts = await this.getAccounts(); const provider = await this.getProvider(); - if (!accounts || !accounts[0] || !provider) { + if (!accounts?.[0] || !provider) { console.log('No accounts found'); return 0; } @@ -67,6 +69,8 @@ export class Ganache { } try { await this.#server.close(); + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (e: any) { // We can safely ignore the EBUSY error if (e.code !== 'EBUSY') { diff --git a/test/e2e/snaps/enums.js b/test/e2e/snaps/enums.js index 3aa3b801b09d..daeaf9db924f 100644 --- a/test/e2e/snaps/enums.js +++ b/test/e2e/snaps/enums.js @@ -1,3 +1,3 @@ module.exports = { - TEST_SNAPS_WEBSITE_URL: 'https://metamask.github.io/snaps/test-snaps/2.4.0/', + TEST_SNAPS_WEBSITE_URL: 'https://metamask.github.io/snaps/test-snaps/2.9.0/', }; diff --git a/test/e2e/snaps/test-snap-bip-32.spec.js b/test/e2e/snaps/test-snap-bip-32.spec.js index 6a28418cd9ea..59a9c14833e8 100644 --- a/test/e2e/snaps/test-snap-bip-32.spec.js +++ b/test/e2e/snaps/test-snap-bip-32.spec.js @@ -45,22 +45,24 @@ describe('Test Snap bip-32', function () { tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); // wait for permissions popover, click checkboxes and confirm await driver.waitForSelector('.mm-checkbox__input'); await driver.clickElement('.mm-checkbox__input'); - await driver.clickElement({ - text: 'Confirm', - tag: 'button', - }); + await driver.waitForSelector( + '[data-testid="snap-install-warning-modal-confirm"]', + ); + await driver.clickElement( + '[data-testid="snap-install-warning-modal-confirm"]', + ); await driver.waitForSelector({ text: 'OK' }); await driver.clickElement({ diff --git a/test/e2e/snaps/test-snap-bip-44.spec.js b/test/e2e/snaps/test-snap-bip-44.spec.js index ef966610d384..ef70e6fc193a 100644 --- a/test/e2e/snaps/test-snap-bip-44.spec.js +++ b/test/e2e/snaps/test-snap-bip-44.spec.js @@ -40,22 +40,26 @@ describe('Test Snap bip-44', function () { text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); // deal with permissions popover await driver.waitForSelector('.mm-checkbox__input'); await driver.clickElement('.mm-checkbox__input'); - await driver.clickElement({ - text: 'Confirm', - tag: 'button', - }); + await driver.waitForSelector( + '[data-testid="snap-install-warning-modal-confirm"]', + ); + await driver.clickElement( + '[data-testid="snap-install-warning-modal-confirm"]', + ); + + // deal with OK button await driver.waitForSelector({ text: 'OK' }); await driver.clickElement({ text: 'OK', diff --git a/test/e2e/snaps/test-snap-clientstatus.spec.js b/test/e2e/snaps/test-snap-clientstatus.spec.js index c64908fc0a7c..edcc48b9b137 100644 --- a/test/e2e/snaps/test-snap-clientstatus.spec.js +++ b/test/e2e/snaps/test-snap-clientstatus.spec.js @@ -2,6 +2,7 @@ const { defaultGanacheOptions, withFixtures, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -33,24 +34,16 @@ describe('Test Snap Client Status', function () { await driver.clickElement('#connectclient-status'); // switch to metamask extension and click connect - const windowHandles = await driver.waitUntilXWindowHandles( - 3, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -62,7 +55,7 @@ describe('Test Snap Client Status', function () { }); // click send inputs on test snap page - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait for npm installation success await driver.waitForSelector({ @@ -80,8 +73,9 @@ describe('Test Snap Client Status', function () { }); // switch to the original MM tab - const extensionPage = windowHandles[0]; - await driver.switchToWindow(extensionPage); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); // click on the global action menu await driver.waitForSelector( @@ -98,7 +92,7 @@ describe('Test Snap Client Status', function () { }); // click send inputs on test snap page - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // find and click on submit await driver.clickElement('#sendClientStatusTest'); diff --git a/test/e2e/snaps/test-snap-cronjob.spec.js b/test/e2e/snaps/test-snap-cronjob.spec.js index 20ba94165b9b..feb3f539e96e 100644 --- a/test/e2e/snaps/test-snap-cronjob.spec.js +++ b/test/e2e/snaps/test-snap-cronjob.spec.js @@ -2,6 +2,7 @@ const { defaultGanacheOptions, withFixtures, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -33,24 +34,16 @@ describe('Test Snap Cronjob', function () { await driver.clickElement('#connectcronjobs'); // switch to metamask extension and click connect - let windowHandles = await driver.waitUntilXWindowHandles( - 3, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -62,7 +55,7 @@ describe('Test Snap Cronjob', function () { }); // click send inputs on test snap page - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait for npm installation success await driver.waitForSelector({ @@ -71,11 +64,7 @@ describe('Test Snap Cronjob', function () { }); // switch to dialog popup, wait for a maximum of 65 seconds - windowHandles = await driver.waitUntilXWindowHandles(3, 1000, 65000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); // look for the dialog popup to verify cronjob fired await driver.waitForSelector({ diff --git a/test/e2e/snaps/test-snap-dialog.spec.js b/test/e2e/snaps/test-snap-dialog.spec.js index e6d3673a1585..5f2700e5fd40 100644 --- a/test/e2e/snaps/test-snap-dialog.spec.js +++ b/test/e2e/snaps/test-snap-dialog.spec.js @@ -2,6 +2,7 @@ const { defaultGanacheOptions, withFixtures, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -33,24 +34,16 @@ describe('Test Snap Dialog', function () { await driver.clickElement('#connectdialogs'); // switch to metamask extension and click connect - let windowHandles = await driver.waitUntilXWindowHandles( - 3, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -62,7 +55,7 @@ describe('Test Snap Dialog', function () { }); // switch to test snaps tab - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait for npm installation success await driver.waitForSelector({ @@ -74,11 +67,7 @@ describe('Test Snap Dialog', function () { await driver.clickElement('#sendAlertButton'); // switch to dialog popup - windowHandles = await driver.waitUntilXWindowHandles(3, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); // check dialog contents const result = await driver.findElement('.snap-ui-renderer__panel'); @@ -95,8 +84,7 @@ describe('Test Snap Dialog', function () { }); // switch back to test snaps tab - windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // check result is null await driver.waitForSelector({ @@ -108,11 +96,7 @@ describe('Test Snap Dialog', function () { await driver.clickElement('#sendConfirmationButton'); // switch to dialog popup - windowHandles = await driver.waitUntilXWindowHandles(3, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); // click reject await driver.clickElement({ @@ -121,8 +105,7 @@ describe('Test Snap Dialog', function () { }); // switch back to test snaps tab - windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // check for false result await driver.waitForSelector({ @@ -134,11 +117,7 @@ describe('Test Snap Dialog', function () { await driver.clickElement('#sendConfirmationButton'); // switch to dialog popup - windowHandles = await driver.waitUntilXWindowHandles(3, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); // click accept await driver.clickElement({ @@ -147,8 +126,7 @@ describe('Test Snap Dialog', function () { }); // switch back to test snaps tab - windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // check for true result await driver.waitForSelector({ @@ -160,11 +138,7 @@ describe('Test Snap Dialog', function () { await driver.clickElement('#sendPromptButton'); // switch to dialog popup - windowHandles = await driver.waitUntilXWindowHandles(3, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); // click cancel button await driver.clickElement({ @@ -173,8 +147,7 @@ describe('Test Snap Dialog', function () { }); // switch back to test snaps tab - windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // check result is equal to 'null' await driver.waitForSelector({ @@ -186,11 +159,7 @@ describe('Test Snap Dialog', function () { await driver.clickElement('#sendPromptButton'); // switch to dialog popup - windowHandles = await driver.waitUntilXWindowHandles(3, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); // fill '2323' in form field await driver.pasteIntoField('.mm-input', '2323'); @@ -202,8 +171,7 @@ describe('Test Snap Dialog', function () { }); // switch back to test snaps tab - windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // check result is equal to '2323' await driver.waitForSelector({ diff --git a/test/e2e/snaps/test-snap-ethprovider.spec.js b/test/e2e/snaps/test-snap-ethprovider.spec.js index 644397931ba0..feee8c76783a 100644 --- a/test/e2e/snaps/test-snap-ethprovider.spec.js +++ b/test/e2e/snaps/test-snap-ethprovider.spec.js @@ -2,6 +2,7 @@ const { defaultGanacheOptions, withFixtures, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -35,24 +36,16 @@ describe('Test Snap ethereum_provider', function () { await driver.clickElement('#connectethereum-provider'); // switch to metamask extension and click connect - const windowHandles = await driver.waitUntilXWindowHandles( - 2, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver, 2); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -64,7 +57,7 @@ describe('Test Snap ethereum_provider', function () { }); // switch to test snap page - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait for npm installation success await driver.waitForSelector({ @@ -93,30 +86,22 @@ describe('Test Snap ethereum_provider', function () { await driver.clickElement('#sendEthproviderAccounts'); // switch to metamask window and click through confirmations - const windowHandles2 = await driver.waitUntilXWindowHandles( - 2, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles2, - ); + await switchToNotificationWindow(driver, 2); await driver.clickElement({ text: 'Next', tag: 'button', }); await driver.waitForSelector({ - text: 'Connect', + text: 'Confirm', tag: 'button', }); await driver.clickElement({ - text: 'Connect', + text: 'Confirm', tag: 'button', }); // switch to test snap page - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // check the results of the message signature using waitForSelector await driver.waitForSelector({ diff --git a/test/e2e/snaps/test-snap-get-file.spec.js b/test/e2e/snaps/test-snap-get-file.spec.js index 0c8795d7a654..ce7f29fe3bf2 100644 --- a/test/e2e/snaps/test-snap-get-file.spec.js +++ b/test/e2e/snaps/test-snap-get-file.spec.js @@ -2,6 +2,7 @@ const { defaultGanacheOptions, withFixtures, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -33,24 +34,16 @@ describe('Test Snap Get File', function () { await driver.clickElement('#connectgetfile'); // switch to metamask extension and click connect - const windowHandles = await driver.waitUntilXWindowHandles( - 3, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -62,7 +55,7 @@ describe('Test Snap Get File', function () { }); // switch to test snaps tab - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait for npm installation success await driver.waitForSelector({ diff --git a/test/e2e/snaps/test-snap-get-locale.spec.js b/test/e2e/snaps/test-snap-get-locale.spec.js index aeff38abd975..3c14dd462ee4 100644 --- a/test/e2e/snaps/test-snap-get-locale.spec.js +++ b/test/e2e/snaps/test-snap-get-locale.spec.js @@ -2,6 +2,7 @@ const { defaultGanacheOptions, withFixtures, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -33,26 +34,24 @@ describe('Test Snap Get Locale', function () { await driver.clickElement('#connectgetlocale'); // switch to metamask extension and click connect - let windowHandles = await driver.waitUntilXWindowHandles( - 3, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + // look for the snap name + await driver.waitForSelector({ + text: 'Localization Example Snap', + tag: 'p', + }); + + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -64,7 +63,7 @@ describe('Test Snap Get Locale', function () { }); // switch to test snaps tab - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait for npm installation success await driver.waitForSelector({ @@ -84,8 +83,9 @@ describe('Test Snap Get Locale', function () { // try switching language to dansk // // switch to the original MM tab - const extensionPage = windowHandles[0]; - await driver.switchToWindow(extensionPage); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); // click on the global action menu await driver.waitForSelector( @@ -115,9 +115,22 @@ describe('Test Snap Get Locale', function () { // try to select dansk from the list await driver.clickElement({ text: 'Dansk', tag: 'option' }); + // click on the global action menu + await driver.waitForSelector( + '[data-testid="account-options-menu-button"]', + ); + await driver.clickElement( + '[data-testid="account-options-menu-button"]', + ); + + // try to click on snaps + await driver.clickElement({ text: 'Snaps', tag: 'div' }); + + // check for localized snap title + await driver.waitForSelector({ text: 'Oversættelses Eksempel Snap' }); + // switch back to test snaps tab - windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // click on alert dialog await driver.clickElement('#sendGetLocaleHelloButton'); diff --git a/test/e2e/snaps/test-snap-getentropy.spec.js b/test/e2e/snaps/test-snap-getentropy.spec.js index 302afacaca06..7815f7329878 100644 --- a/test/e2e/snaps/test-snap-getentropy.spec.js +++ b/test/e2e/snaps/test-snap-getentropy.spec.js @@ -2,6 +2,7 @@ const { defaultGanacheOptions, withFixtures, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -33,26 +34,18 @@ describe('Test Snap getEntropy', function () { await driver.clickElement('#connectGetEntropySnap'); // switch to metamask extension and click connect - let windowHandles = await driver.waitUntilXWindowHandles( - 2, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver, 2); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -64,7 +57,7 @@ describe('Test Snap getEntropy', function () { }); // click send inputs on test snap page - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait for npm installation success await driver.waitForSelector({ @@ -80,19 +73,14 @@ describe('Test Snap getEntropy', function () { await driver.clickElement('#signEntropyMessage'); // Switch to approve signature message window and approve - windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver, 2); await driver.clickElement({ text: 'Approve', tag: 'button', }); // switch back to test-snaps page - windowHandles = await driver.waitUntilXWindowHandles(1, 1000, 10000); - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // check the results of the message signature using waitForSelector await driver.waitForSelector({ diff --git a/test/e2e/snaps/test-snap-homepage.spec.js b/test/e2e/snaps/test-snap-homepage.spec.js index bd714d218858..d02dd8852900 100644 --- a/test/e2e/snaps/test-snap-homepage.spec.js +++ b/test/e2e/snaps/test-snap-homepage.spec.js @@ -2,6 +2,7 @@ const { defaultGanacheOptions, withFixtures, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -34,24 +35,16 @@ describe('Test Snap Homepage', function () { await driver.clickElement('#connecthomepage'); // switch to metamask extension and click connect - const windowHandles = await driver.waitUntilXWindowHandles( - 3, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -65,7 +58,6 @@ describe('Test Snap Homepage', function () { // switch to metamask page and open the three dots menu await driver.switchToWindowWithTitle( WINDOW_TITLES.ExtensionInFullScreenView, - windowHandles, ); await driver.clickElement( '[data-testid="account-options-menu-button"]', diff --git a/test/e2e/snaps/test-snap-installed.spec.js b/test/e2e/snaps/test-snap-installed.spec.js index 24932fd0d49d..e9697fff806e 100644 --- a/test/e2e/snaps/test-snap-installed.spec.js +++ b/test/e2e/snaps/test-snap-installed.spec.js @@ -1,40 +1,13 @@ -const { strict: assert } = require('assert'); const { defaultGanacheOptions, withFixtures, unlockWallet, - getEventPayloads, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); const { TEST_SNAPS_WEBSITE_URL } = require('./enums'); -/** - * mocks the segment api multiple times for specific payloads that we expect to - * see when these tests are run. In this case we are looking for - * 'Snap Installed'. Do not use the constants from the metrics constants files, - * because if these change we want a strong indicator to our data team that the - * shape of data will change. - * - * @param {import('mockttp').Mockttp} mockServer - * @returns {Promise[]} - */ - -async function mockSegment(mockServer) { - return [ - await mockServer - .forPost('https://api.segment.io/v1/batch') - .withJsonBodyIncluding({ - batch: [{ type: 'track', event: 'Snap Installed' }], - }) - .thenCallback(() => { - return { - statusCode: 200, - }; - }), - ]; -} - describe('Test Snap Installed', function () { it('can tell if a snap is installed and metrics have been sent (mocked)', async function () { await withFixtures( @@ -47,9 +20,8 @@ describe('Test Snap Installed', function () { .build(), ganacheOptions: defaultGanacheOptions, title: this.test.fullTitle(), - testSpecificMock: mockSegment, }, - async ({ driver, mockedEndpoint: mockedEndpoints }) => { + async ({ driver }) => { await unlockWallet(driver); // navigate to test snaps page and connect to dialogs snap @@ -67,24 +39,16 @@ describe('Test Snap Installed', function () { await driver.clickElement('#connectdialogs'); // switch to metamask extension and click connect - let windowHandles = await driver.waitUntilXWindowHandles( - 3, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -96,7 +60,7 @@ describe('Test Snap Installed', function () { }); // click send inputs on test snap page - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait for npm installation success await driver.waitForSelector({ @@ -104,18 +68,6 @@ describe('Test Snap Installed', function () { text: 'Reconnect to Dialogs Snap', }); - // check that snap installed event metrics have been sent - const events = await getEventPayloads(driver, mockedEndpoints); - assert.deepStrictEqual(events[0].properties, { - snap_id: 'npm:@metamask/dialog-example-snap', - origin: 'https://metamask.github.io', - version: '2.2.0', - category: 'Snaps', - locale: 'en', - chain_id: '0x539', - environment_type: 'background', - }); - // click to connect to errors snap const errorButton = await driver.findElement('#connecterrors'); await driver.scrollToElement(errorButton); @@ -123,20 +75,16 @@ describe('Test Snap Installed', function () { await driver.clickElement('#connecterrors'); // switch to metamask extension and click connect - windowHandles = await driver.waitUntilXWindowHandles(3, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -147,7 +95,7 @@ describe('Test Snap Installed', function () { tag: 'button', }); - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait for npm installation success await driver.waitForSelector({ diff --git a/test/e2e/snaps/test-snap-interactive-ui.spec.js b/test/e2e/snaps/test-snap-interactive-ui.spec.js new file mode 100644 index 000000000000..ec4d47fee817 --- /dev/null +++ b/test/e2e/snaps/test-snap-interactive-ui.spec.js @@ -0,0 +1,99 @@ +const { + defaultGanacheOptions, + withFixtures, + unlockWallet, + switchToNotificationWindow, + WINDOW_TITLES, +} = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); +const { TEST_SNAPS_WEBSITE_URL } = require('./enums'); + +describe('Test Snap Interactive UI', function () { + it('test interactive ui elements', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: defaultGanacheOptions, + failOnConsoleError: false, + title: this.test.fullTitle(), + }, + async ({ driver }) => { + await unlockWallet(driver); + + // navigate to test snaps page and connect to interactive ui snap + await driver.openNewPage(TEST_SNAPS_WEBSITE_URL); + await driver.delay(1000); + const dialogButton = await driver.findElement('#connectinteractive-ui'); + await driver.scrollToElement(dialogButton); + await driver.delay(1000); + await driver.clickElement('#connectinteractive-ui'); + + // switch to metamask extension and click connect + await switchToNotificationWindow(driver); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); + + await driver.waitForSelector({ text: 'Confirm' }); + + await driver.clickElement({ + text: 'Confirm', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'OK' }); + + await driver.clickElement({ + text: 'OK', + tag: 'button', + }); + + // switch to test snaps tab + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); + + // wait for npm installation success + await driver.waitForSelector('#connectinteractive-ui'); + + // click create dialog button + await driver.clickElement('#createDialogButton'); + await driver.delay(500); + + // switch to dialog popup + await switchToNotificationWindow(driver); + await driver.delay(500); + + // fill in thr example input + await driver.fill('#example-input', 'foo bar'); + + // try to click on dropdown + await driver.waitForSelector('[data-testid="snaps-dropdown"]'); + await driver.clickElement('[data-testid="snaps-dropdown"]'); + + // try to select option 2 from the list + await driver.clickElement({ text: 'Option 2', tag: 'option' }); + + // try to click approve + await driver.clickElement('#submit'); + + // check for returned values + await driver.waitForSelector({ text: 'foo bar', tag: 'p' }); + await driver.waitForSelector({ text: 'option2', tag: 'p' }); + + // try to click on approve + await driver.clickElement('[data-testid="confirmation-submit-button"]'); + + // switch to test snaps tab + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); + + // look for returned true + await driver.waitForSelector({ + text: 'true', + css: '#interactiveUIResult', + }); + }, + ); + }); +}); diff --git a/test/e2e/snaps/test-snap-lifecycle.spec.js b/test/e2e/snaps/test-snap-lifecycle.spec.js index e793fd769cec..40387376557c 100644 --- a/test/e2e/snaps/test-snap-lifecycle.spec.js +++ b/test/e2e/snaps/test-snap-lifecycle.spec.js @@ -2,6 +2,7 @@ const { defaultGanacheOptions, withFixtures, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -33,24 +34,16 @@ describe('Test Snap Lifecycle Hooks', function () { await driver.clickElement('#connectlifecycle-hooks'); // switch to metamask extension and click connect - let windowHandles = await driver.waitUntilXWindowHandles( - 3, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -62,7 +55,7 @@ describe('Test Snap Lifecycle Hooks', function () { }); // click send inputs on test snap page - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait for npm installation success await driver.waitForSelector({ @@ -71,11 +64,7 @@ describe('Test Snap Lifecycle Hooks', function () { }); // switch to dialog popup - windowHandles = await driver.waitUntilXWindowHandles(3, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); // check dialog contents const result = await driver.findElement('.snap-ui-renderer__panel'); diff --git a/test/e2e/snaps/test-snap-management.spec.js b/test/e2e/snaps/test-snap-management.spec.js index 77089713bcc3..e2bef1c2663f 100644 --- a/test/e2e/snaps/test-snap-management.spec.js +++ b/test/e2e/snaps/test-snap-management.spec.js @@ -2,6 +2,7 @@ const { defaultGanacheOptions, withFixtures, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -34,24 +35,16 @@ describe('Test Snap Management', function () { await driver.clickElement('#connectnotifications'); // switch to metamask extension and click connect - let windowHandles = await driver.waitUntilXWindowHandles( - 3, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -63,8 +56,9 @@ describe('Test Snap Management', function () { }); // switch to the original MM tab - const extensionPage = windowHandles[0]; - await driver.switchToWindow(extensionPage); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); // click on the global action menu await driver.waitForSelector( @@ -92,8 +86,7 @@ describe('Test Snap Management', function () { await driver.clickElement('.toggle-button > div'); // switch back to test-snaps window - windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait then try the notification test await driver.waitForSelector('#sendInAppNotification'); @@ -104,21 +97,25 @@ describe('Test Snap Management', function () { await driver.closeAlertPopup(); // switch back to snaps page - await driver.switchToWindow(extensionPage); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); // try to re-enaable the snap await driver.waitForSelector('.toggle-button > div'); await driver.clickElement('.toggle-button > div'); // switch back to test snaps page - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait then try the notification test await driver.waitForSelector('#sendInAppNotification'); await driver.clickElement('#sendInAppNotification'); // check to see that there is one notification - await driver.switchToWindow(extensionPage); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); await driver.waitForSelector( '[data-testid="account-options-menu-button"]', ); diff --git a/test/e2e/snaps/test-snap-managestate.spec.js b/test/e2e/snaps/test-snap-managestate.spec.js index 5188ec001ab3..b7bfdb7678d4 100644 --- a/test/e2e/snaps/test-snap-managestate.spec.js +++ b/test/e2e/snaps/test-snap-managestate.spec.js @@ -2,6 +2,7 @@ const { defaultGanacheOptions, withFixtures, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -34,24 +35,16 @@ describe('Test Snap manageState', function () { await driver.clickElement('#connectmanage-state'); // switch to metamask extension and click connect - const windowHandles = await driver.waitUntilXWindowHandles( - 2, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver, 2); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -63,7 +56,7 @@ describe('Test Snap manageState', function () { }); // fill and click send inputs on test snap page - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait for npm installation success await driver.waitForSelector({ diff --git a/test/e2e/snaps/test-snap-metrics.spec.js b/test/e2e/snaps/test-snap-metrics.spec.js new file mode 100644 index 000000000000..8c5978f28609 --- /dev/null +++ b/test/e2e/snaps/test-snap-metrics.spec.js @@ -0,0 +1,941 @@ +const { strict: assert } = require('assert'); +const { + withFixtures, + switchToNotificationWindow, + unlockWallet, + getEventPayloads, + WINDOW_TITLES, +} = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); +const { TEST_SNAPS_WEBSITE_URL } = require('./enums'); + +/** + * mocks the segment api multiple times for specific payloads that we expect to + * see when these tests are run. In this case we are looking for + * Snap Metrics. Do not use the constants from the metrics constants files, + * because if these change we want a strong indicator to our data team that the + * shape of data will change. + * + * @param {import('mockttp').Mockttp} mockServer + * @returns {Promise[]} + */ + +async function mockedSnapInstall(mockServer) { + return await mockServer + .forPost('https://api.segment.io/v1/batch') + .withJsonBodyIncluding({ + batch: [{ type: 'track', event: 'Snap Installed' }], + }) + .thenCallback(() => { + return { + statusCode: 200, + }; + }); +} + +async function mockedSnapInstallStarted(mockServer) { + return await mockServer + .forPost('https://api.segment.io/v1/batch') + .withJsonBodyIncluding({ + batch: [{ type: 'track', event: 'Snap Install Started' }], + }) + .thenCallback(() => { + return { + statusCode: 200, + }; + }); +} + +async function mockedSnapInstallRejected(mockServer) { + return await mockServer + .forPost('https://api.segment.io/v1/batch') + .withJsonBodyIncluding({ + batch: [{ type: 'track', event: 'Snap Install Rejected' }], + }) + .thenCallback(() => { + return { + statusCode: 200, + }; + }); +} + +async function mockedSnapInstallFailed(mockServer) { + return await mockServer + .forPost('https://api.segment.io/v1/batch') + .withJsonBodyIncluding({ + batch: [{ type: 'track', event: 'Snap Install Failed' }], + }) + .thenCallback(() => { + return { + statusCode: 200, + }; + }); +} + +async function mockedSnapUninstall(mockServer) { + return await mockServer + .forPost('https://api.segment.io/v1/batch') + .withJsonBodyIncluding({ + batch: [{ type: 'track', event: 'Snap Uninstalled' }], + }) + .thenCallback(() => { + return { + statusCode: 200, + }; + }); +} + +async function mockedSnapUpdated(mockServer) { + return await mockServer + .forPost('https://api.segment.io/v1/batch') + .withJsonBodyIncluding({ + batch: [{ type: 'track', event: 'Snap Updated' }], + }) + .thenCallback(() => { + return { + statusCode: 200, + }; + }); +} + +async function mockedSnapUpdateStarted(mockServer) { + return await mockServer + .forPost('https://api.segment.io/v1/batch') + .withJsonBodyIncluding({ + batch: [{ type: 'track', event: 'Snap Update Started' }], + }) + .thenCallback(() => { + return { + statusCode: 200, + }; + }); +} + +async function mockedSnapUpdateRejected(mockServer) { + return await mockServer + .forPost('https://api.segment.io/v1/batch') + .withJsonBodyIncluding({ + batch: [{ type: 'track', event: 'Snap Update Rejected' }], + }) + .thenCallback(() => { + return { + statusCode: 200, + }; + }); +} + +async function mockedSnapUpdateFailed(mockServer) { + return await mockServer + .forPost('https://api.segment.io/v1/batch') + .withJsonBodyIncluding({ + batch: [{ type: 'track', event: 'Snap Update Failed' }], + }) + .thenCallback(() => { + return { + statusCode: 200, + }; + }); +} + +async function mockedNpmInstall(mockServer) { + return await mockServer + .forGet(/https:\/\/registry\.npmjs\.org/u) + .thenCallback(() => { + return { + statusCode: 429, + }; + }); +} + +async function mockedNpmUpdate(mockServer) { + return await mockServer + .forGet( + 'https://registry.npmjs.org/@metamask/bip32-example-snap/-/bip32-example-snap-0.35.2-flask.1.tgz', + ) + .thenCallback(() => { + return { + statusCode: 429, + }; + }); +} + +describe('Test Snap Metrics', function () { + it('tests snap install metric', async function () { + async function mockSegment(mockServer) { + return [ + await mockedSnapInstallStarted(mockServer), + await mockedSnapInstall(mockServer), + ]; + } + + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withMetaMetricsController({ + metaMetricsId: 'fake-metrics-id', + participateInMetaMetrics: true, + }) + .build(), + title: this.test.fullTitle(), + testSpecificMock: mockSegment, + }, + + async ({ driver, mockedEndpoint: mockedEndpoints }) => { + await unlockWallet(driver); + + // open a new tab and navigate to test snaps page and connect + await driver.openNewPage(TEST_SNAPS_WEBSITE_URL); + + // wait for page to load + await driver.waitForSelector({ + text: 'Installed Snaps', + tag: 'h2', + }); + + // find and scroll to the notifications card and click first + const snapButton = await driver.findElement('#connectnotifications'); + await driver.scrollToElement(snapButton); + await driver.delay(1000); + await driver.clickElement('#connectnotifications'); + + // switch to metamask extension and click connect + const windowHandles = await driver.waitUntilXWindowHandles( + 3, + 1000, + 10000, + ); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.Dialog, + windowHandles, + ); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'Confirm' }); + + await driver.clickElement({ + text: 'Confirm', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'OK' }); + + await driver.clickElement({ + text: 'OK', + tag: 'button', + }); + + // check that snap installed event metrics have been sent + const events = await getEventPayloads(driver, mockedEndpoints); + assert.deepStrictEqual(events[0].event, 'Snap Install Started'); + assert.deepStrictEqual(events[0].properties, { + snap_id: 'npm:@metamask/notification-example-snap', + origin: 'https://metamask.github.io', + category: 'Snaps', + locale: 'en', + chain_id: '0x539', + environment_type: 'background', + }); + assert.deepStrictEqual(events[1].event, 'Snap Installed'); + assert.deepStrictEqual(events[1].properties, { + snap_id: 'npm:@metamask/notification-example-snap', + origin: 'https://metamask.github.io', + version: '2.1.3', + category: 'Snaps', + locale: 'en', + chain_id: '0x539', + environment_type: 'background', + }); + }, + ); + }); + + it('tests snap install rejected metric', async function () { + async function mockSegment(mockServer) { + return [ + await mockedSnapInstallStarted(mockServer), + await mockedSnapInstallRejected(mockServer), + ]; + } + + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withMetaMetricsController({ + metaMetricsId: 'fake-metrics-id', + participateInMetaMetrics: true, + }) + .build(), + title: this.test.fullTitle(), + testSpecificMock: mockSegment, + }, + + async ({ driver, mockedEndpoint: mockedEndpoints }) => { + await unlockWallet(driver); + + // open a new tab and navigate to test snaps page and connect + await driver.openNewPage(TEST_SNAPS_WEBSITE_URL); + + // wait for page to load + await driver.waitForSelector({ + text: 'Installed Snaps', + tag: 'h2', + }); + + // find and scroll to the notifications card and click first + const snapButton = await driver.findElement('#connectnotifications'); + await driver.scrollToElement(snapButton); + await driver.delay(1000); + await driver.clickElement('#connectnotifications'); + + // switch to metamask extension and click connect + const windowHandles = await driver.waitUntilXWindowHandles( + 3, + 1000, + 10000, + ); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.Dialog, + windowHandles, + ); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'Confirm' }); + + await driver.clickElement({ + text: 'Cancel', + tag: 'button', + }); + + // check that snap installed event metrics have been sent + const events = await getEventPayloads(driver, mockedEndpoints); + assert.deepStrictEqual(events[0].event, 'Snap Install Started'); + assert.deepStrictEqual(events[0].properties, { + snap_id: 'npm:@metamask/notification-example-snap', + origin: 'https://metamask.github.io', + category: 'Snaps', + locale: 'en', + chain_id: '0x539', + environment_type: 'background', + }); + assert.deepStrictEqual(events[1].event, 'Snap Install Rejected'); + assert.deepStrictEqual(events[1].properties, { + snap_id: 'npm:@metamask/notification-example-snap', + origin: 'https://metamask.github.io', + category: 'Snaps', + locale: 'en', + chain_id: '0x539', + environment_type: 'background', + }); + }, + ); + }); + + it('tests snap install failed metric', async function () { + async function mockSegment(mockServer) { + return [ + await mockedSnapInstallStarted(mockServer), + await mockedSnapInstallFailed(mockServer), + await mockedNpmInstall(mockServer), + ]; + } + + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withMetaMetricsController({ + metaMetricsId: 'fake-metrics-id', + participateInMetaMetrics: true, + }) + .build(), + title: this.test.fullTitle(), + testSpecificMock: mockSegment, + }, + + async ({ driver, mockedEndpoint: mockedEndpoints }) => { + await unlockWallet(driver); + + // open a new tab and navigate to test snaps page and connect + await driver.openNewPage(TEST_SNAPS_WEBSITE_URL); + + // wait for page to load + await driver.waitForSelector({ + text: 'Installed Snaps', + tag: 'h2', + }); + + // find and scroll to the notifications card and click first + const snapButton = await driver.findElement('#connectnotifications'); + await driver.scrollToElement(snapButton); + await driver.delay(1000); + await driver.clickElement('#connectnotifications'); + + // switch to metamask extension and click connect + const windowHandles = await driver.waitUntilXWindowHandles( + 3, + 1000, + 10000, + ); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.Dialog, + windowHandles, + ); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'Connection failed' }); + + // check that snap installed event metrics have been sent + const events = await getEventPayloads(driver, mockedEndpoints); + assert.deepStrictEqual(events[0].event, 'Snap Install Started'); + assert.deepStrictEqual(events[0].properties, { + snap_id: 'npm:@metamask/notification-example-snap', + origin: 'https://metamask.github.io', + category: 'Snaps', + locale: 'en', + chain_id: '0x539', + environment_type: 'background', + }); + assert.deepStrictEqual(events[1].event, 'Snap Install Failed'); + assert.deepStrictEqual(events[1].properties, { + snap_id: 'npm:@metamask/notification-example-snap', + origin: 'https://metamask.github.io', + category: 'Snaps', + locale: 'en', + chain_id: '0x539', + environment_type: 'background', + }); + }, + ); + }); + + it('tests snap uninstall metric', async function () { + async function mockSegment(mockServer) { + return [await mockedSnapUninstall(mockServer)]; + } + + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withMetaMetricsController({ + metaMetricsId: 'fake-metrics-id', + participateInMetaMetrics: true, + }) + .build(), + title: this.test.fullTitle(), + testSpecificMock: mockSegment, + }, + + async ({ driver, mockedEndpoint: mockedEndpoints }) => { + await unlockWallet(driver); + + // open a new tab and navigate to test snaps page and connect + await driver.openNewPage(TEST_SNAPS_WEBSITE_URL); + + // wait for page to load + await driver.waitForSelector({ + text: 'Installed Snaps', + tag: 'h2', + }); + + // find and scroll to the notifications card and click first + const snapButton = await driver.findElement('#connectnotifications'); + await driver.scrollToElement(snapButton); + await driver.delay(1000); + await driver.clickElement('#connectnotifications'); + + // switch to metamask extension and click connect + const windowHandles = await driver.waitUntilXWindowHandles( + 3, + 1000, + 10000, + ); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.Dialog, + windowHandles, + ); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'Confirm' }); + + await driver.clickElement({ + text: 'Confirm', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'OK' }); + + await driver.clickElement({ + text: 'OK', + tag: 'button', + }); + + // switch to the original MM tab + const extensionPage = windowHandles[0]; + await driver.switchToWindow(extensionPage); + + // click on the global action menu + await driver.waitForSelector( + '[data-testid="account-options-menu-button"]', + ); + await driver.clickElement( + '[data-testid="account-options-menu-button"]', + ); + + // try to click on the snaps item + await driver.clickElement({ + text: 'Snaps', + tag: 'div', + }); + + // try to disable the snap + await driver.waitForSelector({ + text: 'Notifications Example Snap', + tag: 'p', + }); + await driver.clickElement({ + text: 'Notifications Example Snap', + tag: 'p', + }); + + // try to remove snap + await driver.clickElement({ + text: 'Remove Notifications Example Snap', + tag: 'p', + }); + + // try to click remove on popover + await driver.waitForSelector('#popoverRemoveSnapButton'); + await driver.clickElement('#popoverRemoveSnapButton'); + + // check the results of the removal + await driver.waitForSelector({ + css: '.mm-box', + text: "You don't have any snaps installed.", + tag: 'p', + }); + + // check that snap uninstalled event metrics have been sent + const events = await getEventPayloads(driver, mockedEndpoints); + assert.deepStrictEqual(events[0].properties, { + snap_id: 'npm:@metamask/notification-example-snap', + version: '2.1.3', + category: 'Snaps', + locale: 'en', + chain_id: '0x539', + environment_type: 'background', + }); + }, + ); + }); + + it('test snap update metric', async function () { + async function mockSegment(mockServer) { + return [ + await mockedSnapUpdateStarted(mockServer), + await mockedSnapUpdated(mockServer), + ]; + } + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withMetaMetricsController({ + metaMetricsId: 'fake-metrics-id', + participateInMetaMetrics: true, + }) + .build(), + title: this.test.fullTitle(), + testSpecificMock: mockSegment, + }, + async ({ driver, mockedEndpoint: mockedEndpoints }) => { + await unlockWallet(driver); + + // open a new tab and navigate to test snaps page and connect + await driver.driver.get(TEST_SNAPS_WEBSITE_URL); + + // wait for page to load + await driver.waitForSelector({ + text: 'Installed Snaps', + tag: 'h2', + }); + + // find and scroll to the correct card and connect to update snap + const snapButton = await driver.findElement('#connectUpdate'); + await driver.scrollToElement(snapButton); + await driver.delay(1000); + await driver.clickElement('#connectUpdate'); + + // switch to metamask extension and click connect + await switchToNotificationWindow(driver, 2); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'Confirm' }); + + await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); + + await driver.clickElement({ + text: 'Confirm', + tag: 'button', + }); + + // wait for permissions popover, click checkboxes and confirm + await driver.delay(500); + await driver.clickElement('.mm-checkbox__input'); + await driver.waitForSelector( + '[data-testid="snap-install-warning-modal-confirm"]', + ); + await driver.clickElement( + '[data-testid="snap-install-warning-modal-confirm"]', + ); + + await driver.waitForSelector({ text: 'OK' }); + + await driver.clickElement({ + text: 'OK', + tag: 'button', + }); + + // navigate to test snap page + const windowHandles = await driver.waitUntilXWindowHandles( + 1, + 1000, + 10000, + ); + await driver.switchToWindow(windowHandles[0]); + + // wait for npm installation success + await driver.waitForSelector({ + css: '#connectUpdate', + text: 'Reconnect to Update Snap', + }); + + // find and scroll to the correct card and click first + const snapButton2 = await driver.findElement('#connectUpdateNew'); + await driver.scrollToElement(snapButton2); + await driver.delay(1000); + await driver.clickElement('#connectUpdateNew'); + + // switch to metamask extension and update + await switchToNotificationWindow(driver, 2); + + await driver.waitForSelector({ text: 'Confirm' }); + + await driver.clickElementSafe('[data-testid="snap-update-scroll"]'); + + await driver.clickElement({ + text: 'Confirm', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'OK' }); + + await driver.clickElement({ + text: 'OK', + tag: 'button', + }); + + // navigate to test snap page + await driver.switchToWindow(windowHandles[0]); + + // look for the correct version text + await driver.waitForSelector({ + css: '#updateSnapVersion', + text: '"0.35.2-flask.1"', + }); + + // check that snap updated event metrics have been sent + const events = await getEventPayloads(driver, mockedEndpoints); + assert.deepStrictEqual(events[0].event, 'Snap Update Started'); + assert.deepStrictEqual(events[0].properties, { + snap_id: 'npm:@metamask/bip32-example-snap', + origin: 'https://metamask.github.io', + category: 'Snaps', + locale: 'en', + chain_id: '0x539', + environment_type: 'background', + }); + assert.deepStrictEqual(events[1].event, 'Snap Updated'); + assert.deepStrictEqual(events[1].properties, { + snap_id: 'npm:@metamask/bip32-example-snap', + new_version: '0.35.2-flask.1', + old_version: '0.35.0-flask.1', + origin: 'https://metamask.github.io', + category: 'Snaps', + locale: 'en', + chain_id: '0x539', + environment_type: 'background', + }); + }, + ); + }); + + it('test snap update rejected metric', async function () { + async function mockSegment(mockServer) { + return [ + await mockedSnapUpdateStarted(mockServer), + await mockedSnapUpdateRejected(mockServer), + ]; + } + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withMetaMetricsController({ + metaMetricsId: 'fake-metrics-id', + participateInMetaMetrics: true, + }) + .build(), + title: this.test.fullTitle(), + testSpecificMock: mockSegment, + }, + async ({ driver, mockedEndpoint: mockedEndpoints }) => { + await unlockWallet(driver); + + // open a new tab and navigate to test snaps page and connect + await driver.driver.get(TEST_SNAPS_WEBSITE_URL); + + // wait for page to load + await driver.waitForSelector({ + text: 'Installed Snaps', + tag: 'h2', + }); + + // find and scroll to the correct card and connect to update snap + const snapButton = await driver.findElement('#connectUpdate'); + await driver.scrollToElement(snapButton); + await driver.delay(1000); + await driver.clickElement('#connectUpdate'); + + // switch to metamask extension and click connect + await switchToNotificationWindow(driver, 2); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'Confirm' }); + + await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); + + await driver.clickElement({ + text: 'Confirm', + tag: 'button', + }); + + // wait for permissions popover, click checkboxes and confirm + await driver.delay(500); + await driver.clickElement('.mm-checkbox__input'); + await driver.waitForSelector( + '[data-testid="snap-install-warning-modal-confirm"]', + ); + await driver.clickElement( + '[data-testid="snap-install-warning-modal-confirm"]', + ); + + await driver.waitForSelector({ text: 'OK' }); + + await driver.clickElement({ + text: 'OK', + tag: 'button', + }); + + // navigate to test snap page + const windowHandles = await driver.waitUntilXWindowHandles( + 1, + 1000, + 10000, + ); + await driver.switchToWindow(windowHandles[0]); + + // wait for npm installation success + await driver.waitForSelector({ + css: '#connectUpdate', + text: 'Reconnect to Update Snap', + }); + + // find and scroll to the correct card and click first + const snapButton2 = await driver.findElement('#connectUpdateNew'); + await driver.scrollToElement(snapButton2); + await driver.delay(1000); + await driver.clickElement('#connectUpdateNew'); + + // switch to metamask extension and update + await switchToNotificationWindow(driver, 2); + + await driver.waitForSelector({ text: 'Confirm' }); + + await driver.clickElementSafe('[data-testid="snap-update-scroll"]'); + + await driver.clickElement({ + text: 'Cancel', + tag: 'button', + }); + + await driver.switchToWindow(windowHandles[0]); + + // check that snap updated event metrics have been sent + const events = await getEventPayloads(driver, mockedEndpoints); + assert.deepStrictEqual(events[0].event, 'Snap Update Started'); + assert.deepStrictEqual(events[0].properties, { + snap_id: 'npm:@metamask/bip32-example-snap', + origin: 'https://metamask.github.io', + category: 'Snaps', + locale: 'en', + chain_id: '0x539', + environment_type: 'background', + }); + assert.deepStrictEqual(events[1].event, 'Snap Update Rejected'); + assert.deepStrictEqual(events[1].properties, { + snap_id: 'npm:@metamask/bip32-example-snap', + origin: 'https://metamask.github.io', + category: 'Snaps', + locale: 'en', + chain_id: '0x539', + environment_type: 'background', + }); + }, + ); + }); + + it('test snap update failed metric', async function () { + async function mockSegment(mockServer) { + return [ + await mockedSnapUpdateStarted(mockServer), + await mockedSnapUpdateFailed(mockServer), + await mockedNpmUpdate(mockServer), + ]; + } + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withMetaMetricsController({ + metaMetricsId: 'fake-metrics-id', + participateInMetaMetrics: true, + }) + .build(), + title: this.test.fullTitle(), + testSpecificMock: mockSegment, + ignoredConsoleErrors: ['Object'], + }, + async ({ driver, mockedEndpoint: mockedEndpoints }) => { + await unlockWallet(driver); + + // open a new tab and navigate to test snaps page and connect + await driver.driver.get(TEST_SNAPS_WEBSITE_URL); + + // wait for page to load + await driver.waitForSelector({ + text: 'Installed Snaps', + tag: 'h2', + }); + + // find and scroll to the correct card and connect to update snap + const snapButton = await driver.findElement('#connectUpdate'); + await driver.scrollToElement(snapButton); + await driver.delay(1000); + await driver.clickElement('#connectUpdate'); + + // switch to metamask extension and click connect + await switchToNotificationWindow(driver, 2); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'Confirm' }); + + await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); + + await driver.clickElement({ + text: 'Confirm', + tag: 'button', + }); + + // wait for permissions popover, click checkboxes and confirm + await driver.delay(500); + await driver.clickElement('.mm-checkbox__input'); + await driver.waitForSelector( + '[data-testid="snap-install-warning-modal-confirm"]', + ); + await driver.clickElement( + '[data-testid="snap-install-warning-modal-confirm"]', + ); + + await driver.waitForSelector({ text: 'OK' }); + + await driver.clickElement({ + text: 'OK', + tag: 'button', + }); + + // navigate to test snap page + const windowHandles = await driver.waitUntilXWindowHandles( + 1, + 1000, + 10000, + ); + await driver.switchToWindow(windowHandles[0]); + + // wait for npm installation success + await driver.waitForSelector({ + css: '#connectUpdate', + text: 'Reconnect to Update Snap', + }); + + // find and scroll to the correct card and click first + const snapButton2 = await driver.findElement('#connectUpdateNew'); + await driver.scrollToElement(snapButton2); + await driver.delay(1000); + await driver.clickElement('#connectUpdateNew'); + + await driver.delay(1000); + await driver.closeAlertPopup(); + + // switch to metamask extension and update + await switchToNotificationWindow(driver, 2); + + await driver.waitForSelector({ text: 'Update failed' }); + + // check that snap updated event metrics have been sent + const events = await getEventPayloads(driver, mockedEndpoints); + assert.deepStrictEqual(events[0].event, 'Snap Update Started'); + assert.deepStrictEqual(events[0].properties, { + snap_id: 'npm:@metamask/bip32-example-snap', + origin: 'https://metamask.github.io', + category: 'Snaps', + locale: 'en', + chain_id: '0x539', + environment_type: 'background', + }); + assert.deepStrictEqual(events[1].event, 'Snap Update Failed'); + assert.deepStrictEqual(events[1].properties, { + snap_id: 'npm:@metamask/bip32-example-snap', + origin: 'https://metamask.github.io', + category: 'Snaps', + locale: 'en', + chain_id: '0x539', + environment_type: 'background', + }); + }, + ); + }); +}); diff --git a/test/e2e/snaps/test-snap-namelookup.spec.js b/test/e2e/snaps/test-snap-namelookup.spec.js index 55dccf602d8e..4e58231256dd 100644 --- a/test/e2e/snaps/test-snap-namelookup.spec.js +++ b/test/e2e/snaps/test-snap-namelookup.spec.js @@ -2,6 +2,7 @@ const { withFixtures, defaultGanacheOptions, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -16,7 +17,6 @@ describe('Test Snap Name Lookup', function () { title: this.test.fullTitle(), }, async ({ driver }) => { - await driver.navigate(); await unlockWallet(driver); // navigate to test snaps page and connect @@ -35,24 +35,16 @@ describe('Test Snap Name Lookup', function () { await driver.clickElement('#connectname-lookup'); // switch to metamask extension and click connect - const windowHandles = await driver.waitUntilXWindowHandles( - 3, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -66,7 +58,6 @@ describe('Test Snap Name Lookup', function () { // switch to fullscreen metamask tab await driver.switchToWindowWithTitle( WINDOW_TITLES.ExtensionInFullScreenView, - windowHandles, ); // switch network to ethereum-mainnet for name lookup to work diff --git a/test/e2e/snaps/test-snap-networkaccess.spec.js b/test/e2e/snaps/test-snap-networkaccess.spec.js index 57a036f50532..e3fa954a79c2 100644 --- a/test/e2e/snaps/test-snap-networkaccess.spec.js +++ b/test/e2e/snaps/test-snap-networkaccess.spec.js @@ -2,6 +2,7 @@ const { defaultGanacheOptions, withFixtures, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -33,24 +34,16 @@ describe('Test Snap networkAccess', function () { await driver.clickElement('#connectnetwork-access'); // switch to metamask extension and click connect - const windowHandles = await driver.waitUntilXWindowHandles( - 3, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -62,7 +55,7 @@ describe('Test Snap networkAccess', function () { }); // switch to test snaps tab - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait for npm installation success await driver.waitForSelector({ diff --git a/test/e2e/snaps/test-snap-notification.spec.js b/test/e2e/snaps/test-snap-notification.spec.js index a6a02f442359..7c9fdede898d 100644 --- a/test/e2e/snaps/test-snap-notification.spec.js +++ b/test/e2e/snaps/test-snap-notification.spec.js @@ -2,6 +2,7 @@ const { defaultGanacheOptions, withFixtures, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -34,25 +35,16 @@ describe('Test Snap Notification', function () { await driver.clickElement('#connectnotifications'); // switch to metamask extension and click connect - const windowHandles = await driver.waitUntilXWindowHandles( - 3, - 1000, - 10000, - ); - const extensionPage = windowHandles[0]; - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -64,7 +56,7 @@ describe('Test Snap Notification', function () { }); // click send inputs on test snap page - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait for npm installation success await driver.waitForSelector({ @@ -75,7 +67,9 @@ describe('Test Snap Notification', function () { await driver.clickElement('#sendInAppNotification'); // switch back to the extension page - await driver.switchToWindow(extensionPage); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); // check to see that there is one notification await driver.waitForSelector( @@ -110,11 +104,11 @@ describe('Test Snap Notification', function () { // look for the correct text in notifications (via xpath) await driver.waitForSelector({ - css: '.notifications__item__details__message', + css: '.snap-notifications__item__details__message', text: 'Hello from within MetaMask!', }); await driver.findElement({ - css: '.notifications__item__details__message', + css: '.snap-notifications__item__details__message', text: 'Hello from within MetaMask!', }); }, diff --git a/test/e2e/snaps/test-snap-revoke-perm.spec.js b/test/e2e/snaps/test-snap-revoke-perm.spec.js index c6ea20aa4a99..b70cc3ab4cc1 100644 --- a/test/e2e/snaps/test-snap-revoke-perm.spec.js +++ b/test/e2e/snaps/test-snap-revoke-perm.spec.js @@ -42,10 +42,10 @@ describe('Test Snap revoke permission', function () { tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -81,7 +81,7 @@ describe('Test Snap revoke permission', function () { }); await driver.delay(500); await driver.clickElement({ - text: 'Connect', + text: 'Confirm', tag: 'button', }); @@ -146,7 +146,7 @@ describe('Test Snap revoke permission', function () { }); await driver.delay(500); await driver.clickElement({ - text: 'Connect', + text: 'Confirm', tag: 'button', }); diff --git a/test/e2e/snaps/test-snap-rpc.spec.js b/test/e2e/snaps/test-snap-rpc.spec.js index a5dcac9fb562..b6ad95c89c65 100644 --- a/test/e2e/snaps/test-snap-rpc.spec.js +++ b/test/e2e/snaps/test-snap-rpc.spec.js @@ -3,6 +3,7 @@ const { withFixtures, switchToNotificationWindow, unlockWallet, + WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); const { TEST_SNAPS_WEBSITE_URL } = require('./enums'); @@ -40,23 +41,26 @@ describe('Test Snap RPC', function () { tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); // wait for permissions popover, click checkboxes and confirm await driver.waitForSelector('.mm-checkbox__input'); await driver.clickElement('.mm-checkbox__input'); - await driver.clickElement({ - text: 'Confirm', - tag: 'button', - }); - + await driver.waitForSelector( + '[data-testid="snap-install-warning-modal-confirm"]', + ); + await driver.clickElement( + '[data-testid="snap-install-warning-modal-confirm"]', + ); + + // deal with OK button await driver.waitForSelector({ text: 'OK' }); await driver.clickElement({ @@ -65,7 +69,7 @@ describe('Test Snap RPC', function () { }); // switch back to test-snaps window - await driver.switchToWindowWithTitle('Test Snaps'); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); const snapButton2 = await driver.findElement('#connectjson-rpc'); await driver.scrollToElement(snapButton2); @@ -78,10 +82,10 @@ describe('Test Snap RPC', function () { tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -92,7 +96,7 @@ describe('Test Snap RPC', function () { tag: 'button', }); - await driver.switchToWindowWithTitle('Test Snaps'); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait for npm installation success await driver.waitForSelector({ diff --git a/test/e2e/snaps/test-snap-siginsights.spec.js b/test/e2e/snaps/test-snap-siginsights.spec.js index cb04d15e0ba2..6b43551ac182 100644 --- a/test/e2e/snaps/test-snap-siginsights.spec.js +++ b/test/e2e/snaps/test-snap-siginsights.spec.js @@ -1,8 +1,10 @@ const { withFixtures, + clickSignOnSignatureConfirmation, defaultGanacheOptions, openDapp, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -13,13 +15,19 @@ describe('Test Snap Signature Insights', function () { await withFixtures( { dapp: true, - fixtures: new FixtureBuilder().build(), + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .withPreferencesController({ + disabledRpcMethodPreferences: { + eth_sign: true, + }, + }) + .build(), ganacheOptions: defaultGanacheOptions, failOnConsoleError: false, title: this.test.fullTitle(), }, async ({ driver }) => { - await driver.navigate(); await unlockWallet(driver); // navigate to test snaps page and connect @@ -33,27 +41,18 @@ describe('Test Snap Signature Insights', function () { await driver.scrollToElement(snapButton1); await driver.delay(1000); await driver.clickElement('#connectsignature-insights'); - await driver.delay(1000); // switch to metamask extension and click connect - let windowHandles = await driver.waitUntilXWindowHandles( - 3, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -65,55 +64,12 @@ describe('Test Snap Signature Insights', function () { }); // switch to test-snaps page - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // open the test-dapp page await openDapp(driver); // poll windowHandles and switch to test-dapp - windowHandles = await driver.waitUntilXWindowHandles(3, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.TestDApp, - windowHandles, - ); - - // wait for and click use flask - await driver.waitForSelector({ - text: 'Use MetaMask Flask', - tag: 'button', - }); - await driver.clickElement({ - text: 'Use MetaMask Flask', - tag: 'button', - }); - - // find and scroll to basic actions and click connect - const connectButton1 = await driver.findElement('#connectButton'); - await driver.scrollToElement(connectButton1); - await driver.clickElement('#connectButton'); - - // switch back to MetaMask window and deal with dialogs - windowHandles = await driver.waitUntilXWindowHandles(4, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); - await driver.clickElement({ - text: 'Next', - tag: 'button', - }); - await driver.delay(1000); - await driver.clickElement({ - text: 'Connect', - tag: 'button', - }); - - // switch to test-dapp page and send tx - windowHandles = await driver.waitUntilXWindowHandles(3, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.TestDApp, - windowHandles, - ); // TEST ONE: personal sign // find and scroll to personal sign and click sign @@ -122,20 +78,12 @@ describe('Test Snap Signature Insights', function () { await driver.clickElement('#personalSign'); // switch back to MetaMask window and switch to tx insights pane - windowHandles = await driver.waitUntilXWindowHandles(4, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver, 4); // wait for and click sign - await driver.waitForSelector({ - text: 'Sign', - tag: 'button', - }); - await driver.clickElement({ - text: 'Sign', - tag: 'button', + await clickSignOnSignatureConfirmation({ + driver, + snapSigInsights: true, }); // look for returned signature insights data @@ -151,10 +99,7 @@ describe('Test Snap Signature Insights', function () { await driver.clickElement('[data-testid="snapInsightsButtonConfirm"]'); // switch back to test-dapp window - await driver.switchToWindowWithTitle( - WINDOW_TITLES.TestDApp, - windowHandles, - ); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); // check result of test await driver.waitForSelector({ @@ -169,20 +114,12 @@ describe('Test Snap Signature Insights', function () { await driver.clickElement('#signTypedData'); // switch back to MetaMask window and switch to tx insights pane - windowHandles = await driver.waitUntilXWindowHandles(4, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver, 4); // wait for and click sign - await driver.waitForSelector({ - text: 'Sign', - tag: 'button', - }); - await driver.clickElement({ - text: 'Sign', - tag: 'button', + await clickSignOnSignatureConfirmation({ + driver, + snapSigInsights: true, }); // look for returned signature insights data @@ -198,10 +135,7 @@ describe('Test Snap Signature Insights', function () { await driver.clickElement('[data-testid="snapInsightsButtonConfirm"]'); // switch back to test-dapp window - await driver.switchToWindowWithTitle( - WINDOW_TITLES.TestDApp, - windowHandles, - ); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); // check result of test await driver.waitForSelector({ @@ -216,24 +150,16 @@ describe('Test Snap Signature Insights', function () { await driver.clickElement('#signTypedDataV3'); // switch back to MetaMask window and switch to tx insights pane - windowHandles = await driver.waitUntilXWindowHandles(4, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver, 4); // click down arrow await driver.waitForSelector('.fa-arrow-down'); await driver.clickElement('.fa-arrow-down'); // wait for and click sign - await driver.waitForSelector({ - text: 'Sign', - tag: 'button', - }); - await driver.clickElement({ - text: 'Sign', - tag: 'button', + await clickSignOnSignatureConfirmation({ + driver, + snapSigInsights: true, }); // look for returned signature insights data @@ -249,10 +175,7 @@ describe('Test Snap Signature Insights', function () { await driver.clickElement('[data-testid="snapInsightsButtonConfirm"]'); // switch back to test-dapp window - await driver.switchToWindowWithTitle( - WINDOW_TITLES.TestDApp, - windowHandles, - ); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); // check result of test await driver.waitForSelector({ @@ -267,24 +190,16 @@ describe('Test Snap Signature Insights', function () { await driver.clickElement('#signTypedDataV4'); // switch back to MetaMask window and switch to tx insights pane - windowHandles = await driver.waitUntilXWindowHandles(4, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver, 4); // click down arrow await driver.waitForSelector('.fa-arrow-down'); await driver.clickElement('.fa-arrow-down'); // wait for and click sign - await driver.waitForSelector({ - text: 'Sign', - tag: 'button', - }); - await driver.clickElement({ - text: 'Sign', - tag: 'button', + await clickSignOnSignatureConfirmation({ + driver, + snapSigInsights: true, }); // look for returned signature insights data @@ -300,10 +215,7 @@ describe('Test Snap Signature Insights', function () { await driver.clickElement('[data-testid="snapInsightsButtonConfirm"]'); // switch back to test-dapp window - await driver.switchToWindowWithTitle( - WINDOW_TITLES.TestDApp, - windowHandles, - ); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); // check results of test await driver.waitForSelector({ @@ -312,59 +224,6 @@ describe('Test Snap Signature Insights', function () { }); // TEST FIVE: eth_sign - // switch to metamask window - const extensionPage = windowHandles[0]; - await driver.switchToWindow(extensionPage); - - // click on the global action menu - await driver.waitForSelector( - '[data-testid="account-options-menu-button"]', - ); - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); - - // try to click on the settings item - await driver.clickElement({ - text: 'Settings', - tag: 'div', - }); - - // try to click on the advanced item - await driver.clickElement({ - text: 'Advanced', - tag: 'div', - }); - - // scroll to and click on Eth_sign requests toggle - const ethSignToggle1 = await driver.findElement('.eth-sign-toggle'); - await driver.scrollToElement(ethSignToggle1); - await driver.clickElement('.eth-sign-toggle'); - - // wait for and click checkbox on modal and click continue - await driver.waitForSelector('#eth-sign-checkbox'); - await driver.clickElement('#eth-sign-checkbox'); - await driver.clickElement({ - text: 'Continue', - tag: 'button', - }); - - // fill in annoyance field and click enable - await driver.waitForSelector('#enter-eth-sign-text'); - await driver.fill( - '#enter-eth-sign-text', - 'I only sign what I understand', - ); - await driver.clickElement({ - text: 'Enable', - tag: 'button', - }); - - // switch back to test-dapp window - await driver.switchToWindowWithTitle( - WINDOW_TITLES.TestDApp, - windowHandles, - ); // scroll to and click eth sign button const ethSignButton1 = await driver.findElement('#ethSign'); @@ -372,30 +231,16 @@ describe('Test Snap Signature Insights', function () { await driver.clickElement('#ethSign'); // switch back to MetaMask window and switch to tx insights pane - windowHandles = await driver.waitUntilXWindowHandles(4, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver, 4); // wait for and click sign - await driver.waitForSelector({ - text: 'Sign', - tag: 'button', - }); - await driver.clickElement({ - text: 'Sign', - tag: 'button', + await clickSignOnSignatureConfirmation({ + driver, + snapSigInsights: true, + locatorID: '#ethSign', }); // wait for and click signature warning sign button - await driver.waitForSelector( - '[data-testid="signature-warning-sign-button"]', - ); - await driver.clickElement( - '[data-testid="signature-warning-sign-button"]', - ); - // click checkbox to authorize signing await driver.clickElement('.mm-checkbox__input-wrapper'); @@ -403,10 +248,7 @@ describe('Test Snap Signature Insights', function () { await driver.clickElement('[data-testid="snapInsightsButtonConfirm"]'); // switch back to test-dapp window - await driver.switchToWindowWithTitle( - WINDOW_TITLES.TestDApp, - windowHandles, - ); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); // check results of test await driver.waitForSelector({ diff --git a/test/e2e/snaps/test-snap-txinsights-v2.spec.js b/test/e2e/snaps/test-snap-txinsights-v2.spec.js index de8b9a148e1c..0b43dca40ffc 100644 --- a/test/e2e/snaps/test-snap-txinsights-v2.spec.js +++ b/test/e2e/snaps/test-snap-txinsights-v2.spec.js @@ -1,7 +1,8 @@ const { - withFixtures, defaultGanacheOptions, + withFixtures, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -16,7 +17,6 @@ describe('Test Snap TxInsights-v2', function () { title: this.test.fullTitle(), }, async ({ driver }) => { - await driver.navigate(); await unlockWallet(driver); // navigate to test snaps page and connect @@ -37,24 +37,16 @@ describe('Test Snap TxInsights-v2', function () { await driver.clickElement('#connecttransaction-insights'); // switch to metamask extension and click connect - let windowHandles = await driver.waitUntilXWindowHandles( - 3, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -66,39 +58,31 @@ describe('Test Snap TxInsights-v2', function () { }); // switch to test-snaps page and get accounts - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); await driver.clickElement('#getAccounts'); // switch back to MetaMask window and deal with dialogs - windowHandles = await driver.waitUntilXWindowHandles(3, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); await driver.clickElement({ text: 'Next', tag: 'button', }); await driver.waitForSelector({ - text: 'Connect', + text: 'Confirm', tag: 'button', }); await driver.clickElement({ - text: 'Connect', + text: 'Confirm', tag: 'button', }); // switch to test-snaps page and send tx - windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); await driver.clickElement('#sendInsights'); // switch back to MetaMask window and switch to tx insights pane - windowHandles = await driver.waitUntilXWindowHandles(3, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await driver.delay(2000); + await switchToNotificationWindow(driver); await driver.findClickableElement({ text: 'Confirm', @@ -134,7 +118,7 @@ describe('Test Snap TxInsights-v2', function () { // check info in warning await driver.waitForSelector({ - css: '.snap-ui-markdown__text', + css: '.snap-ui-renderer__text', text: 'ERC-20', }); @@ -149,8 +133,9 @@ describe('Test Snap TxInsights-v2', function () { }); // switch back to MetaMask tab and switch to activity pane - windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); - await driver.switchToWindowWithTitle('MetaMask', windowHandles); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); await driver.clickElement({ tag: 'button', text: 'Activity', diff --git a/test/e2e/snaps/test-snap-txinsights.spec.js b/test/e2e/snaps/test-snap-txinsights.spec.js index 2442274e8d61..ff93a2ea910b 100644 --- a/test/e2e/snaps/test-snap-txinsights.spec.js +++ b/test/e2e/snaps/test-snap-txinsights.spec.js @@ -2,6 +2,7 @@ const { defaultGanacheOptions, withFixtures, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -36,24 +37,16 @@ describe('Test Snap TxInsights', function () { await driver.clickElement('#connecttransaction-insights'); // switch to metamask extension and click connect - let windowHandles = await driver.waitUntilXWindowHandles( - 2, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver, 2); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -65,39 +58,31 @@ describe('Test Snap TxInsights', function () { }); // switch to test-snaps page and get accounts - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); await driver.clickElement('#getAccounts'); // switch back to MetaMask window and deal with dialogs - windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver, 2); await driver.clickElement({ text: 'Next', tag: 'button', }); await driver.waitForSelector({ - text: 'Connect', + text: 'Confirm', tag: 'button', }); await driver.clickElement({ - text: 'Connect', + text: 'Confirm', tag: 'button', }); // switch to test-snaps page and send tx - windowHandles = await driver.waitUntilXWindowHandles(1, 1000, 10000); - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); await driver.clickElement('#sendInsights'); // switch back to MetaMask window and switch to tx insights pane - windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await driver.delay(2000); + await switchToNotificationWindow(driver, 2); await driver.waitForSelector({ text: 'Insights Example Snap', tag: 'button', diff --git a/test/e2e/snaps/test-snap-ui-imgs.spec.js b/test/e2e/snaps/test-snap-ui-imgs.spec.js new file mode 100644 index 000000000000..d8bb8af1e1d8 --- /dev/null +++ b/test/e2e/snaps/test-snap-ui-imgs.spec.js @@ -0,0 +1,101 @@ +const { + defaultGanacheOptions, + withFixtures, + unlockWallet, + switchToNotificationWindow, + WINDOW_TITLES, +} = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); +const { TEST_SNAPS_WEBSITE_URL } = require('./enums'); + +describe('Test Snap Images', function () { + it('can display images in snap ui', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: defaultGanacheOptions, + title: this.test.fullTitle(), + }, + async ({ driver }) => { + await unlockWallet(driver); + + // navigate to test snaps page and connect + await driver.driver.get(TEST_SNAPS_WEBSITE_URL); + + // wait for page to load + await driver.waitForSelector({ + text: 'Installed Snaps', + tag: 'h2', + }); + + // find and scroll to the images test and connect + const snapButton1 = await driver.findElement('#connectimages'); + await driver.scrollToElement(snapButton1); + await driver.delay(1000); + await driver.waitForSelector('#connectimages'); + await driver.clickElement('#connectimages'); + + // switch to metamask extension and click connect and approve + await switchToNotificationWindow(driver, 2); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + await driver.waitForSelector({ text: 'Confirm' }); + + await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); + + await driver.clickElement({ + text: 'Confirm', + tag: 'button', + }); + + // deal with OK button + await driver.waitForSelector({ text: 'OK' }); + await driver.clickElement({ + text: 'OK', + tag: 'button', + }); + + // switch back to test-snaps window + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); + + // wait for npm installation success + await driver.waitForSelector({ + css: '#connectimages', + text: 'Reconnect to Images Snap', + }); + + // find and click svg image test + await driver.clickElement('#showSVGImage'); + + // switch to notification window + await switchToNotificationWindow(driver, 2); + + // check snaps ui image using waitForSelector + await driver.waitForSelector('[data-testid="snaps-ui-image"]'); + + // click ok to close window + await driver.clickElement('[data-testid="confirmation-submit-button"]'); + + // switch back to test-snaps window + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); + + // find and click cat image test + await driver.clickElement('#showPNGImage'); + + // switch to notification window + await switchToNotificationWindow(driver, 2); + + // check snaps ui image using waitForSelector + await driver.waitForSelector('[data-testid="snaps-ui-image"]'); + + // click ok to close window + await driver.clickElement('[data-testid="confirmation-submit-button"]'); + + // switch back to test-snaps window + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); + }, + ); + }); +}); diff --git a/test/e2e/snaps/test-snap-uilinks.spec.js b/test/e2e/snaps/test-snap-uilinks.spec.js new file mode 100644 index 000000000000..4e75765cbac6 --- /dev/null +++ b/test/e2e/snaps/test-snap-uilinks.spec.js @@ -0,0 +1,128 @@ +const { + defaultGanacheOptions, + withFixtures, + unlockWallet, + switchToNotificationWindow, + WINDOW_TITLES, +} = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); +const { TEST_SNAPS_WEBSITE_URL } = require('./enums'); + +describe('Test Snap UI Links', function () { + it('test link in confirmation snap_dialog type', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: defaultGanacheOptions, + failOnConsoleError: false, + title: this.test.fullTitle(), + }, + async ({ driver }) => { + await unlockWallet(driver); + + // navigate to test snaps page and connect to dialog snap + await driver.openNewPage(TEST_SNAPS_WEBSITE_URL); + await driver.delay(1000); + const dialogButton = await driver.findElement('#connectdialogs'); + await driver.scrollToElement(dialogButton); + await driver.delay(1000); + await driver.clickElement('#connectdialogs'); + + // switch to metamask extension and click connect + await switchToNotificationWindow(driver); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'Confirm' }); + + await driver.clickElement({ + text: 'Confirm', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'OK' }); + + await driver.clickElement({ + text: 'OK', + tag: 'button', + }); + + // switch to test snaps tab + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); + + // wait for npm installation success + await driver.waitForSelector({ + css: '#connectdialogs', + text: 'Reconnect to Dialogs Snap', + }); + + // click conf button + await driver.clickElement('#sendConfirmationButton'); + await driver.delay(500); + + // switch to dialog popup + await switchToNotificationWindow(driver); + await driver.delay(500); + + // wait for link to appear and click it + await driver.waitForSelector({ + text: 'That', + tag: 'span', + }); + await driver.clickElement({ + text: 'That', + tag: 'span', + }); + + // wait for the link to be provided + await driver.waitForSelector({ + text: 'snaps.metamask.io', + tag: 'b', + }); + + // wait for and click visit site button + await driver.waitForSelector({ + text: 'Visit site', + tag: 'a', + }); + await driver.clickElement({ + text: 'Visit site', + tag: 'a', + }); + + // switch to new tab + await driver.switchToWindowWithTitle('MetaMask Snaps Directory'); + + // check that the correct page has been opened + await driver.waitForSelector({ + text: 'Most Popular', + tag: 'h2', + }); + + // switch back to metamask window + await switchToNotificationWindow(driver, 4); + + // wait for and click approve button + await driver.waitForSelector({ + text: 'Approve', + tag: 'button', + }); + await driver.clickElement({ + text: 'Approve', + tag: 'button', + }); + + // switch back to test snaps tab + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); + + // check for false result + await driver.waitForSelector({ + css: '#dialogResult', + text: 'true', + }); + }, + ); + }); +}); diff --git a/test/e2e/snaps/test-snap-update-component.spec.js b/test/e2e/snaps/test-snap-update-component.spec.js index 221c1f153609..e471c76ad6e8 100644 --- a/test/e2e/snaps/test-snap-update-component.spec.js +++ b/test/e2e/snaps/test-snap-update-component.spec.js @@ -2,6 +2,7 @@ const { withFixtures, switchToNotificationWindow, unlockWallet, + WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); const { TEST_SNAPS_WEBSITE_URL } = require('./enums'); @@ -48,23 +49,26 @@ describe('Test Snap update via snaps component', function () { tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); // wait for permissions popover, click checkboxes and confirm await driver.waitForSelector('.mm-checkbox__input'); await driver.clickElement('.mm-checkbox__input'); - await driver.clickElement({ - text: 'Confirm', - tag: 'button', - }); + await driver.waitForSelector( + '[data-testid="snap-install-warning-modal-confirm"]', + ); + await driver.clickElement( + '[data-testid="snap-install-warning-modal-confirm"]', + ); + // deal with OK button await driver.waitForSelector({ text: 'OK' }); await driver.clickElement({ @@ -73,12 +77,7 @@ describe('Test Snap update via snaps component', function () { }); // navigate to test snap page - const windowHandles = await driver.waitUntilXWindowHandles( - 2, - 1000, - 10000, - ); - await driver.switchToWindow(windowHandles[1]); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait for npm installation success await driver.waitForSelector({ @@ -87,8 +86,9 @@ describe('Test Snap update via snaps component', function () { }); // switch to the original MM tab - const extensionPage = windowHandles[0]; - await driver.switchToWindow(extensionPage); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); // click on the global action menu await driver.waitForSelector( @@ -127,10 +127,15 @@ describe('Test Snap update via snaps component', function () { await driver.clickElementSafe('[data-testid="snap-update-scroll"]'); await driver.clickElement({ - text: 'Update', + text: 'Confirm', tag: 'button', }); + await driver.clickElement('.mm-checkbox__input'); + await driver.clickElement( + '[data-testid="snap-install-warning-modal-confirm"]', + ); + await driver.waitForSelector({ text: 'OK' }); await driver.clickElement({ diff --git a/test/e2e/snaps/test-snap-update.spec.js b/test/e2e/snaps/test-snap-update.spec.js index cbf174624474..6f5500d593a4 100644 --- a/test/e2e/snaps/test-snap-update.spec.js +++ b/test/e2e/snaps/test-snap-update.spec.js @@ -3,6 +3,7 @@ const { withFixtures, switchToNotificationWindow, unlockWallet, + WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); const { TEST_SNAPS_WEBSITE_URL } = require('./enums'); @@ -40,37 +41,32 @@ describe('Test Snap update', function () { tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); + // scroll to bottom await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); // wait for permissions popover, click checkboxes and confirm - await driver.delay(500); + const permissionsConfirmButtonSelector = + '[data-testid="snap-install-warning-modal-confirm"]'; + await driver.waitForSelector(permissionsConfirmButtonSelector); await driver.clickElement('.mm-checkbox__input'); - await driver.clickElement({ - text: 'Confirm', - tag: 'button', - }); - await driver.waitForSelector({ text: 'OK' }); + await driver.findClickableElement(permissionsConfirmButtonSelector); + await driver.clickElementAndWaitToDisappear( + permissionsConfirmButtonSelector, + ); - await driver.clickElement({ - text: 'OK', - tag: 'button', - }); + // finish the permission with OK button + await driver.clickElement('[data-testid="page-container-footer-next"]'); // navigate to test snap page - let windowHandles = await driver.waitUntilXWindowHandles( - 1, - 1000, - 10000, - ); - await driver.switchToWindow(windowHandles[0]); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait for npm installation success await driver.waitForSelector({ @@ -86,26 +82,20 @@ describe('Test Snap update', function () { // switch to metamask extension and update await switchToNotificationWindow(driver, 2); + await driver.waitForSelector({ text: 'Update request' }); - await driver.waitForSelector({ text: 'Update' }); - + // Scroll to bottom of dialog await driver.clickElementSafe('[data-testid="snap-update-scroll"]'); - - await driver.clickElement({ - text: 'Update', - tag: 'button', - }); - + // Click confirm button + await driver.clickElementAndWaitToDisappear( + '[data-testid="page-container-footer-next"]', + ); + // When it is confirmed, click okay button await driver.waitForSelector({ text: 'OK' }); - - await driver.clickElement({ - text: 'OK', - tag: 'button', - }); + await driver.clickElement('[data-testid="page-container-footer-next"]'); // navigate to test snap page - windowHandles = await driver.waitUntilXWindowHandles(1, 1000, 10000); - await driver.switchToWindow(windowHandles[0]); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // look for the correct version text await driver.waitForSelector({ diff --git a/test/e2e/snaps/test-snap-wasm.spec.js b/test/e2e/snaps/test-snap-wasm.spec.js index 2f63e7414cb7..ada7d604d97a 100644 --- a/test/e2e/snaps/test-snap-wasm.spec.js +++ b/test/e2e/snaps/test-snap-wasm.spec.js @@ -2,6 +2,7 @@ const { defaultGanacheOptions, withFixtures, unlockWallet, + switchToNotificationWindow, WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -33,25 +34,16 @@ describe('Test Snap WASM', function () { await driver.clickElement('#connectwasm'); // switch to metamask extension and click connect - const windowHandles = await driver.waitUntilXWindowHandles( - 3, - 1000, - 10000, - ); - // const extensionPage = windowHandles[0]; - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); + await switchToNotificationWindow(driver); await driver.clickElement({ text: 'Connect', tag: 'button', }); - await driver.waitForSelector({ text: 'Install' }); + await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -63,7 +55,7 @@ describe('Test Snap WASM', function () { }); // click send inputs on test snap page - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); // wait for npm installation success await driver.waitForSelector({ diff --git a/test/e2e/tests/account-menu/account-details.spec.js b/test/e2e/tests/account/account-details.spec.js similarity index 100% rename from test/e2e/tests/account-menu/account-details.spec.js rename to test/e2e/tests/account/account-details.spec.js diff --git a/test/e2e/tests/account-menu/account-hide-unhide.spec.js b/test/e2e/tests/account/account-hide-unhide.spec.js similarity index 100% rename from test/e2e/tests/account-menu/account-hide-unhide.spec.js rename to test/e2e/tests/account/account-hide-unhide.spec.js diff --git a/test/e2e/tests/account-menu/account-pin-unpin.spec.js b/test/e2e/tests/account/account-pin-unpin.spec.js similarity index 100% rename from test/e2e/tests/account-menu/account-pin-unpin.spec.js rename to test/e2e/tests/account/account-pin-unpin.spec.js diff --git a/test/e2e/tests/account-menu/add-account.spec.js b/test/e2e/tests/account/add-account.spec.js similarity index 93% rename from test/e2e/tests/account-menu/add-account.spec.js rename to test/e2e/tests/account/add-account.spec.js index cc456bb381a7..1c66d7334d98 100644 --- a/test/e2e/tests/account-menu/add-account.spec.js +++ b/test/e2e/tests/account/add-account.spec.js @@ -5,7 +5,8 @@ const { completeImportSRPOnboardingFlow, sendTransaction, findAnotherAccountFromAccountList, - waitForAccountRendered, + locateAccountBalanceDOM, + logInWithBalanceValidation, regularDelayMs, unlockWallet, WALLET_PASSWORD, @@ -51,16 +52,13 @@ describe('Add account', function () { }); it('should not affect public address when using secret recovery phrase to recover account with non-zero balance @no-mmi', async function () { - if (process.env.MULTICHAIN) { - return; - } await withFixtures( { fixtures: new FixtureBuilder({ onboarding: true }).build(), ganacheOptions, title: this.test.fullTitle(), }, - async ({ driver }) => { + async ({ driver, ganacheServer }) => { await driver.navigate(); // On boarding with 1st account @@ -70,8 +68,8 @@ describe('Add account', function () { WALLET_PASSWORD, ); - // Check address of 1st account - await waitForAccountRendered(driver); + // Check address of 1st accoun + await locateAccountBalanceDOM(driver, ganacheServer); await driver.findElement('[data-testid="app-header-copy-button"]'); // Create 2nd account @@ -86,7 +84,7 @@ describe('Add account', function () { await driver.clickElement({ text: 'Create', tag: 'button' }); // Check address of 2nd account - await waitForAccountRendered(driver); + await locateAccountBalanceDOM(driver); await driver.findElement('[data-testid="app-header-copy-button"]'); // Log into the account with balance(account 1) @@ -97,7 +95,7 @@ describe('Add account', function () { 1, 'Account 1', ); - await waitForAccountRendered(driver); + await locateAccountBalanceDOM(driver); await driver.clickElement(accountOneSelector); await sendTransaction(driver, secondAccount, '2.8'); @@ -130,10 +128,7 @@ describe('Add account', function () { // Land in 1st account home page await driver.findElement('.home__main-view'); - - if (!process.env.MULTICHAIN) { - await waitForAccountRendered(driver); - } + await locateAccountBalanceDOM(driver); // Check address of 1st account await driver.findElement('[data-testid="app-header-copy-button"]'); @@ -161,7 +156,7 @@ describe('Add account', function () { title: this.test.fullTitle(), }, async ({ driver }) => { - await unlockWallet(driver); + await logInWithBalanceValidation(driver); await driver.clickElement('[data-testid="account-menu-icon"]'); await driver.clickElement( @@ -174,7 +169,7 @@ describe('Add account', function () { await driver.clickElement({ text: 'Create', tag: 'button' }); // Wait for 2nd account to be created - await waitForAccountRendered(driver); + await locateAccountBalanceDOM(driver); await driver.findElement({ css: '[data-testid="account-menu-icon"]', text: '2nd account', @@ -207,7 +202,7 @@ describe('Add account', function () { ); // Wait for 3rd account to be created - await waitForAccountRendered(driver); + await locateAccountBalanceDOM(driver); await driver.findElement({ css: '[data-testid="account-menu-icon"]', text: 'Account 3', diff --git a/test/e2e/tests/account-menu/import-flow.spec.js b/test/e2e/tests/account/import-flow.spec.js similarity index 92% rename from test/e2e/tests/account-menu/import-flow.spec.js rename to test/e2e/tests/account/import-flow.spec.js index 4c0a7b0fd973..e25174cfa249 100644 --- a/test/e2e/tests/account-menu/import-flow.spec.js +++ b/test/e2e/tests/account/import-flow.spec.js @@ -10,8 +10,9 @@ const { completeImportSRPOnboardingFlowWordByWord, openActionMenuAndStartSendFlow, unlockWallet, + logInWithBalanceValidation, + locateAccountBalanceDOM, WALLET_PASSWORD, - waitForAccountRendered, } = require('../../helpers'); const FixtureBuilder = require('../../fixture-builder'); const { emptyHtmlPage } = require('../../mock-e2e'); @@ -39,9 +40,6 @@ async function mockTrezor(mockServer) { describe('Import flow @no-mmi', function () { it('Import wallet using Secret Recovery Phrase', async function () { - if (process.env.MULTICHAIN) { - return; - } await withFixtures( { fixtures: new FixtureBuilder({ onboarding: true }).build(), @@ -87,6 +85,7 @@ describe('Import flow @no-mmi', function () { // accepts the account password after lock await unlockWallet(driver, { + navigate: false, waitLoginSuccess: false, }); @@ -131,15 +130,17 @@ describe('Import flow @no-mmi', function () { 'input[placeholder="Enter public address (0x) or ENS name"]', '0x2f318C334780961FB129D2a6c30D0763d9a5C970', ); - await driver.fill('.unit-input__input', '1'); + await driver.fill('input[placeholder="0"]', '1'); // Continue to next screen - await driver.clickElement({ text: 'Next', tag: 'button' }); + await driver.clickElement({ text: 'Continue', tag: 'button' }); // confirms the transaction await driver.clickElement({ text: 'Confirm', tag: 'button' }); // finds the transaction in the transactions list - await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.clickElement( + '[data-testid="account-overview__activity-tab"]', + ); await driver.wait(async () => { const confirmedTxes = await driver.findElements( '.transaction-list__completed-transactions .activity-list-item', @@ -287,9 +288,8 @@ describe('Import flow @no-mmi', function () { ganacheOptions, title: this.test.fullTitle(), }, - async ({ driver }) => { - await unlockWallet(driver); - await waitForAccountRendered(driver); + async ({ driver, ganacheServer }) => { + await logInWithBalanceValidation(driver, ganacheServer); // Imports an account with JSON file await driver.clickElement('[data-testid="account-menu-icon"]'); await driver.clickElement( @@ -316,7 +316,7 @@ describe('Import flow @no-mmi', function () { '[data-testid="import-account-confirm-button"]', ); - await waitForAccountRendered(driver); + await locateAccountBalanceDOM(driver, ganacheServer); // New imported account has correct name and label await driver.findClickableElement({ css: '[data-testid="account-menu-icon"]', @@ -377,11 +377,7 @@ describe('Import flow @no-mmi', function () { ); }); - it('Connects to a Hardware wallet for trezor', async function () { - if (process.env.ENABLE_MV3) { - // Hardware wallets not supported in MV3 build yet - this.skip(); - } + it('Connects to a Hardware wallet for lattice', async function () { await withFixtures( { fixtures: new FixtureBuilder().build(), @@ -401,15 +397,24 @@ describe('Import flow @no-mmi', function () { text: 'Add hardware wallet', tag: 'button', }); - await driver.delay(regularDelayMs); + await driver.findClickableElement( + '[data-testid="hardware-connect-close-btn"]', + ); + await driver.clickElement('[data-testid="connect-lattice-btn"]'); + await driver.findClickableElement({ + text: 'Continue', + tag: 'button', + }); - // should open the TREZOR Connect popup - await driver.clickElement('.hw-connect__btn:nth-of-type(2)'); - await driver.delay(largeDelayMs * 2); await driver.clickElement({ text: 'Continue', tag: 'button' }); const allWindows = await driver.waitUntilXWindowHandles(2); - assert.equal(allWindows.length, 2); + + const isMv3Enabled = + process.env.ENABLE_MV3 === 'true' || + process.env.ENABLE_MV3 === undefined; + + assert.equal(allWindows.length, isMv3Enabled ? 3 : 2); }, ); }); diff --git a/test/e2e/tests/incremental-security.spec.js b/test/e2e/tests/account/incremental-security.spec.js similarity index 96% rename from test/e2e/tests/incremental-security.spec.js rename to test/e2e/tests/account/incremental-security.spec.js index 709ce1c36f03..bdbde3b26101 100644 --- a/test/e2e/tests/incremental-security.spec.js +++ b/test/e2e/tests/account/incremental-security.spec.js @@ -1,6 +1,6 @@ const { strict: assert } = require('assert'); -const { convertToHexValue, withFixtures, openDapp } = require('../helpers'); -const FixtureBuilder = require('../fixture-builder'); +const { convertToHexValue, withFixtures, openDapp } = require('../../helpers'); +const FixtureBuilder = require('../../fixture-builder'); const WALLET_PASSWORD = 'correct horse battery staple'; @@ -112,10 +112,10 @@ describe('Incremental Security', function () { // should have the correct amount of eth let currencyDisplay = await driver.waitForSelector({ css: '.currency-display-component__text', - text: '$1,700.00', + text: '1', }); let balance = await currencyDisplay.getText(); - assert.strictEqual(balance, '$1,700.00'); + assert.strictEqual(balance, '1'); // backs up the Secret Recovery Phrase // should show a backup reminder @@ -163,11 +163,11 @@ describe('Incremental Security', function () { // should have the correct amount of eth currencyDisplay = await driver.waitForSelector({ css: '.currency-display-component__text', - text: '$1,700.00', + text: '1', }); balance = await currencyDisplay.getText(); - assert.strictEqual(balance, '$1,700.00'); + assert.strictEqual(balance, '1'); // The previous currencyDisplay wait already serves as the guard here for the assertElementNotPresent await driver.assertElementNotPresent('.backup-notification'); diff --git a/test/e2e/tests/lock-account.spec.js b/test/e2e/tests/account/lock-account.spec.js similarity index 85% rename from test/e2e/tests/lock-account.spec.js rename to test/e2e/tests/account/lock-account.spec.js index 9ef084b17a7c..d384ff0020ae 100644 --- a/test/e2e/tests/lock-account.spec.js +++ b/test/e2e/tests/account/lock-account.spec.js @@ -3,8 +3,8 @@ const { defaultGanacheOptions, withFixtures, unlockWallet, -} = require('../helpers'); -const FixtureBuilder = require('../fixture-builder'); +} = require('../../helpers'); +const FixtureBuilder = require('../../fixture-builder'); describe('Lock and unlock', function () { it('successfully unlocks after lock', async function () { @@ -30,7 +30,7 @@ describe('Lock and unlock', function () { const walletBalance = await driver.findElement( '.eth-overview__primary-balance', ); - assert.equal(await walletBalance.getText(), '$42,500.00\nUSD'); + assert.equal(/^25\s*ETH$/u.test(await walletBalance.getText()), true); }, ); }); diff --git a/test/e2e/tests/lockdown.spec.js b/test/e2e/tests/account/lockdown.spec.js similarity index 69% rename from test/e2e/tests/lockdown.spec.js rename to test/e2e/tests/account/lockdown.spec.js index 988463bc13ae..9a9dbab12ff1 100644 --- a/test/e2e/tests/lockdown.spec.js +++ b/test/e2e/tests/account/lockdown.spec.js @@ -3,10 +3,10 @@ const { Browser } = require('selenium-webdriver'); const { getGlobalProperties, testIntrinsic, -} = require('../../helpers/protect-intrinsics-helpers'); -const { convertToHexValue, withFixtures } = require('../helpers'); -const { PAGES } = require('../webdriver/driver'); -const FixtureBuilder = require('../fixture-builder'); +} = require('../../../helpers/protect-intrinsics-helpers'); +const { convertToHexValue, withFixtures } = require('../../helpers'); +const { PAGES } = require('../../webdriver/driver'); +const FixtureBuilder = require('../../fixture-builder'); const isFirefox = process.env.SELENIUM_BROWSER === Browser.FIREFOX; @@ -62,7 +62,7 @@ describe('lockdown', function () { ], }; - it('the UI and background environments are locked down', async function () { + it('the UI environment is locked down', async function () { await withFixtures( { // The fixtures used here is arbitrary. Any fixture would do. @@ -77,8 +77,26 @@ describe('lockdown', function () { true, 'The UI environment should be locked down.', ); + }, + ); + }); - await driver.navigate(PAGES.BACKGROUND); + it('the background environment is locked down', async function () { + await withFixtures( + { + // The fixtures used here is arbitrary. Any fixture would do. + fixtures: new FixtureBuilder().build(), + ganacheOptions, + title: this.test.fullTitle(), + }, + async ({ driver }) => { + if (process.env.ENABLE_MV3 === 'false') { + await driver.navigate(PAGES.BACKGROUND); + } else { + // TODO: add logic for testing the Service-Worker on MV3 + await driver.navigate(PAGES.OFFSCREEN); + } + await driver.delay(1000); assert.equal( await driver.executeScript(lockdownTestScript), true, diff --git a/test/e2e/tests/metamask-responsive-ui.spec.js b/test/e2e/tests/account/metamask-responsive-ui.spec.js similarity index 90% rename from test/e2e/tests/metamask-responsive-ui.spec.js rename to test/e2e/tests/account/metamask-responsive-ui.spec.js index ece480115603..b13390288b16 100644 --- a/test/e2e/tests/metamask-responsive-ui.spec.js +++ b/test/e2e/tests/account/metamask-responsive-ui.spec.js @@ -6,8 +6,8 @@ const { locateAccountBalanceDOM, openActionMenuAndStartSendFlow, unlockWallet, -} = require('../helpers'); -const FixtureBuilder = require('../fixture-builder'); +} = require('../../helpers'); +const FixtureBuilder = require('../../fixture-builder'); describe('MetaMask Responsive UI', function () { it('Creating a new wallet @no-mmi', async function () { @@ -72,10 +72,10 @@ describe('MetaMask Responsive UI', function () { await driver.clickElement('[data-testid="pin-extension-done"]'); await driver.assertElementNotPresent('.loading-overlay__spinner'); // assert balance - await driver.findElement({ - css: '[data-testid="eth-overview__primary-currency"]', - text: `$ 0.00 USD`, - }); + const balance = await driver.findElement( + '[data-testid="eth-overview__primary-currency"]', + ); + assert.ok(/^0\sETH$/u.test(await balance.getText())); }, ); }); @@ -115,10 +115,6 @@ describe('MetaMask Responsive UI', function () { }); it('Send Transaction from responsive window', async function () { - // TODO: Update Test when Multichain Send Flow is added - if (process.env.MULTICHAIN) { - return; - } const driverOptions = { openDevToolsForTabs: true }; await withFixtures( { @@ -140,17 +136,19 @@ describe('MetaMask Responsive UI', function () { '0x2f318C334780961FB129D2a6c30D0763d9a5C970', ); - const inputAmount = await driver.fill('.unit-input__input', '1'); + const inputAmount = await driver.fill('input[placeholder="0"]', '1'); const inputValue = await inputAmount.getProperty('value'); assert.equal(inputValue, '1'); // confirming transcation - await driver.clickElement({ text: 'Next', tag: 'button' }); + await driver.clickElement({ text: 'Continue', tag: 'button' }); await driver.clickElement({ text: 'Confirm', tag: 'button' }); // finds the transaction in the transactions list - await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.clickElement( + '[data-testid="account-overview__activity-tab"]', + ); await driver.wait(async () => { const confirmedTxes = await driver.findElements( '.transaction-list__completed-transactions .activity-list-item', diff --git a/test/e2e/tests/migrate-old-vault.spec.js b/test/e2e/tests/account/migrate-old-vault.spec.js similarity index 83% rename from test/e2e/tests/migrate-old-vault.spec.js rename to test/e2e/tests/account/migrate-old-vault.spec.js index 82b6c846b2d9..610a2afebec3 100644 --- a/test/e2e/tests/migrate-old-vault.spec.js +++ b/test/e2e/tests/account/migrate-old-vault.spec.js @@ -1,6 +1,6 @@ const { strict: assert } = require('assert'); -const { defaultGanacheOptions, withFixtures } = require('../helpers'); -const FixtureBuilder = require('../fixture-builder'); +const { defaultGanacheOptions, withFixtures } = require('../../helpers'); +const FixtureBuilder = require('../../fixture-builder'); const lock = async (driver) => { await driver.clickElement('[data-testid="account-options-menu-button"]'); @@ -32,7 +32,7 @@ describe('Migrate vault with old encryption', function () { const walletBalance = await driver.findElement( '.eth-overview__primary-balance', ); - assert.equal(await walletBalance.getText(), '$42,500.00\nUSD'); + assert.equal(/^25\s*ETH$/u.test(await walletBalance.getText()), true); }, ); }); diff --git a/test/e2e/tests/confirmations/contract-interaction-redesign.spec.js b/test/e2e/tests/confirmations/contract-interaction-redesign.spec.js new file mode 100644 index 000000000000..96b0c2602476 --- /dev/null +++ b/test/e2e/tests/confirmations/contract-interaction-redesign.spec.js @@ -0,0 +1,194 @@ +const { + defaultGanacheOptions, + openDapp, + unlockWallet, + WINDOW_TITLES, + withFixtures, +} = require('../../helpers'); +const FixtureBuilder = require('../../fixture-builder'); +const { scrollAndConfirmAndAssertConfirm } = require('./helpers'); + +describe('Confirmation Redesign Contract Interaction Component', function () { + if (!process.env.ENABLE_CONFIRMATION_REDESIGN) { + return; + } + + it('Sends a contract interaction type 0 transaction without custom nonce editing', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .withPreferencesController({ + preferences: { redesignedConfirmationsEnabled: true }, + }) + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + }, + async ({ driver }) => { + await unlockWallet(driver); + await openDapp(driver); + + await createContractDeploymentTransaction(driver); + await confirmContractDeploymentTransaction(driver); + + await createDepositTransaction(driver); + await confirmDepositTransaction(driver); + }, + ); + }); + + it('Sends a contract interaction type 0 transaction with custom nonce editing', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .withPreferencesController({ + preferences: { redesignedConfirmationsEnabled: true }, + }) + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + }, + async ({ driver }) => { + await unlockWallet(driver); + await openDapp(driver); + + await toggleOnCustomNonce(driver); + + await createContractDeploymentTransaction(driver); + await confirmContractDeploymentTransaction(driver); + + await createDepositTransaction(driver); + await confirmDepositTransactionWithCustomNonce(driver, '10'); + }, + ); + }); +}); + +async function toggleOnCustomNonce(driver) { + // switch to metamask page and open the three dots menu + await driver.switchToWindowWithTitle(WINDOW_TITLES.ExtensionInFullScreenView); + + // Open settings menu button + const accountOptionsMenuSelector = + '[data-testid="account-options-menu-button"]'; + await driver.waitForSelector(accountOptionsMenuSelector); + await driver.clickElement(accountOptionsMenuSelector); + + // Click settings from dropdown menu + const globalMenuSettingsSelector = '[data-testid="global-menu-settings"]'; + await driver.waitForSelector(globalMenuSettingsSelector); + await driver.clickElement(globalMenuSettingsSelector); + + // Click Advanced tab + const advancedTabRawLocator = { + text: 'Advanced', + tag: 'div', + }; + await driver.clickElement(advancedTabRawLocator); + + // Toggle on custom toggle setting (off by default) + await driver.clickElement('.custom-nonce-toggle'); + + // Close settings + await driver.clickElement( + '.settings-page__header__title-container__close-button', + ); +} + +async function createContractDeploymentTransaction(driver) { + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await driver.clickElement(`#deployButton`); +} + +async function confirmContractDeploymentTransaction(driver) { + await driver.delay(2000); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + + await driver.waitForSelector({ + css: '.confirm-page-container-summary__action__name', + text: 'Contract deployment', + }); + + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindowWithTitle(WINDOW_TITLES.ExtensionInFullScreenView); + await driver.clickElement({ text: 'Activity', tag: 'button' }); + await driver.waitForSelector( + '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', + ); +} + +async function createDepositTransaction(driver) { + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await driver.clickElement(`#depositButton`); +} + +async function confirmDepositTransaction(driver) { + await driver.delay(2000); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + + await driver.waitForSelector({ + css: 'h2', + text: 'Transaction request', + }); + + await toggleAdvancedDetails(driver); + + await driver.waitForSelector({ + css: 'p', + text: 'Nonce', + }); + + await scrollAndConfirmAndAssertConfirm(driver); +} + +async function confirmDepositTransactionWithCustomNonce(driver, customNonce) { + await driver.delay(2000); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + + await driver.waitForSelector({ + css: 'h2', + text: 'Transaction request', + }); + + await toggleAdvancedDetails(driver); + + await driver.waitForSelector({ + css: 'p', + text: 'Nonce', + }); + + await driver.clickElement('.edit-nonce-btn'); + await driver.fill('[data-testid="custom-nonce-input"]', customNonce); + await driver.clickElement({ + text: 'Save', + tag: 'button', + }); + await scrollAndConfirmAndAssertConfirm(driver); + + // Confirm tx was submitted with the higher nonce + await driver.switchToWindowWithTitle(WINDOW_TITLES.ExtensionInFullScreenView); + + await driver.delay(500); + + const sendTransactionListItem = await driver.findElement( + '.transaction-list__pending-transactions .activity-list-item', + ); + await sendTransactionListItem.click(); + + await driver.waitForSelector({ + css: '.transaction-breakdown__value', + text: customNonce, + }); +} + +async function toggleAdvancedDetails(driver) { + // TODO - Scroll button not shown in Firefox if advanced details enabled too fast. + await driver.delay(1000); + + await driver.clickElement(`[data-testid="header-advanced-details-button"]`); +} diff --git a/test/e2e/tests/confirmations/header.spec.js b/test/e2e/tests/confirmations/header.spec.js new file mode 100644 index 000000000000..c829958f8b5e --- /dev/null +++ b/test/e2e/tests/confirmations/header.spec.js @@ -0,0 +1,112 @@ +const { strict: assert } = require('assert'); +const { + defaultGanacheOptions, + openDapp, + unlockWallet, + WINDOW_TITLES, + withFixtures, +} = require('../../helpers'); +const FixtureBuilder = require('../../fixture-builder'); + +const SIGNATURE_CONFIRMATIONS = [ + { name: 'Personal Sign signature', testDAppBtnId: 'personalSign' }, + { name: 'Sign Typed Data signature', testDAppBtnId: 'signTypedData' }, + { name: 'Sign Typed Data v3 signature', testDAppBtnId: 'signTypedDataV3' }, + { name: 'Sign Typed Data v4 signature', testDAppBtnId: 'signTypedDataV4' }, + { name: 'Sign Permit signature', testDAppBtnId: 'signPermit' }, +]; + +const WALLET_ADDRESS = '0x5CfE73b6021E818B776b421B1c4Db2474086a7e1'; +const WALLET_ETH_BALANCE = '25'; + +describe('Confirmation Header Component', function () { + SIGNATURE_CONFIRMATIONS.forEach((confirmation) => { + it(`${confirmation.name} component includes header with balance`, async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .withPreferencesController({ + preferences: { redesignedConfirmationsEnabled: true }, + }) + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + }, + async ({ driver }) => { + await unlockWallet(driver); + await openDapp(driver); + + await clickConfirmationBtnOnTestDapp( + driver, + confirmation.testDAppBtnId, + ); + await clickHeaderInfoBtn(driver); + + await assertHeaderInfoBalance(driver, WALLET_ETH_BALANCE); + }, + ); + }); + + it(`${confirmation.name} component includes copyable address element`, async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .withPreferencesController({ + preferences: { redesignedConfirmationsEnabled: true }, + }) + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + }, + async ({ driver }) => { + await unlockWallet(driver); + await openDapp(driver); + + await clickConfirmationBtnOnTestDapp( + driver, + confirmation.testDAppBtnId, + ); + await clickHeaderInfoBtn(driver); + await copyAddressAndPasteWalletAddress(driver); + + await assertPastedAddress(driver, WALLET_ADDRESS); + }, + ); + }); + + async function clickConfirmationBtnOnTestDapp(driver, btnId) { + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await driver.clickElement(`#${btnId}`); + await driver.delay(2000); + } + + async function clickHeaderInfoBtn(driver) { + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + await driver.clickElement('button[data-testid="header-info-button"]'); + } + + async function assertHeaderInfoBalance(driver, walletEthBalance) { + const headerBalanceEl = await driver.findElement( + '[data-testid="header-balance"]', + ); + await driver.waitForNonEmptyElement(headerBalanceEl); + assert.equal(await headerBalanceEl.getText(), `${walletEthBalance}\nETH`); + } + + async function copyAddressAndPasteWalletAddress(driver) { + await driver.clickElement('[data-testid="address-copy-button-text"]'); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await driver.findElement('#eip747ContractAddress'); + await driver.pasteFromClipboardIntoField('#eip747ContractAddress'); + } + + async function assertPastedAddress(driver, walletAddress) { + const formFieldEl = await driver.findElement('#eip747ContractAddress'); + assert.equal(await formFieldEl.getProperty('value'), walletAddress); + } + }); +}); diff --git a/test/e2e/tests/confirmations/helpers.ts b/test/e2e/tests/confirmations/helpers.ts new file mode 100644 index 000000000000..b6a19a6b95a9 --- /dev/null +++ b/test/e2e/tests/confirmations/helpers.ts @@ -0,0 +1,37 @@ +import FixtureBuilder from '../../fixture-builder'; +import { defaultGanacheOptions, withFixtures } from '../../helpers'; +import { Driver } from '../../webdriver/driver'; + +export async function scrollAndConfirmAndAssertConfirm(driver: Driver) { + await driver.clickElement('.confirm-scroll-to-bottom__button'); + await driver.clickElement('[data-testid="confirm-footer-button"]'); +} + +export function withRedesignConfirmationFixtures( + // Default params first is discouraged because it makes it hard to call the function without the + // optional parameters. But it doesn't apply here because we're always passing in a variable for + // title. It's optional because it's sometimes unset. + // eslint-disable-next-line @typescript-eslint/default-param-last + title: string = '', + testFunction: Parameters[1], +) { + return withFixtures( + { + dapp: true, + driverOptions: { + timeOut: 20000, + }, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .withPreferencesController({ + preferences: { + redesignedConfirmationsEnabled: true, + }, + }) + .build(), + ganacheOptions: defaultGanacheOptions, + title, + }, + testFunction, + ); +} diff --git a/test/e2e/tests/confirmations/signatures/permit.spec.ts b/test/e2e/tests/confirmations/signatures/permit.spec.ts new file mode 100644 index 000000000000..8320fd748f63 --- /dev/null +++ b/test/e2e/tests/confirmations/signatures/permit.spec.ts @@ -0,0 +1,132 @@ +import { strict as assert } from 'assert'; +import { Suite } from 'mocha'; +import { + scrollAndConfirmAndAssertConfirm, + withRedesignConfirmationFixtures, +} from '../helpers'; +import { + DAPP_HOST_ADDRESS, + WINDOW_TITLES, + openDapp, + switchToNotificationWindow, + unlockWallet, +} from '../../../helpers'; +import { Ganache } from '../../../seeder/ganache'; +import { Driver } from '../../../webdriver/driver'; + +describe('Confirmation Signature - Permit', function (this: Suite) { + if (!process.env.ENABLE_CONFIRMATION_REDESIGN) { + return; + } + + it('initiates and confirms', async function () { + await withRedesignConfirmationFixtures( + this.test?.fullTitle(), + async ({ + driver, + ganacheServer, + }: { + driver: Driver; + ganacheServer: Ganache; + }) => { + const addresses = await ganacheServer.getAccounts(); + const publicAddress = addresses?.[0] as string; + + await unlockWallet(driver); + await openDapp(driver); + await driver.clickElement('#signPermit'); + await switchToNotificationWindow(driver); + + await assertInfoValues(driver); + await scrollAndConfirmAndAssertConfirm(driver); + await assertVerifiedResults(driver, publicAddress); + }, + ); + }); + + it('initiates and rejects', async function () { + await withRedesignConfirmationFixtures( + this.test?.fullTitle(), + async ({ driver }: { driver: Driver }) => { + await unlockWallet(driver); + await openDapp(driver); + await driver.clickElement('#signPermit'); + await switchToNotificationWindow(driver); + + await driver.clickElement( + '[data-testid="confirm-footer-cancel-button"]', + ); + + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + + const rejectionResult = await driver.waitForSelector({ + css: '#signPermitResult', + text: 'Error: User rejected the request.', + }); + assert.ok(rejectionResult); + }, + ); + }); +}); + +async function assertInfoValues(driver: Driver) { + const origin = driver.findElement({ text: DAPP_HOST_ADDRESS }); + const contractPetName = driver.findElement({ + css: '.name__value', + text: '0xCcCCc...ccccC', + }); + + const primaryType = driver.findElement({ text: 'Permit' }); + const owner = driver.findElement({ css: '.name__name', text: 'Account 1' }); + const spender = driver.findElement({ + css: '.name__value', + text: '0x5B38D...eddC4', + }); + const value = driver.findElement({ text: '3000' }); + const nonce = driver.findElement({ text: '0' }); + const deadline = driver.findElement({ text: '02 August 1971, 16:53' }); + + assert.ok(await origin, 'origin'); + assert.ok(await contractPetName, 'contractPetName'); + assert.ok(await primaryType, 'primaryType'); + assert.ok(await owner, 'owner'); + assert.ok(await spender, 'spender'); + assert.ok(await value, 'value'); + assert.ok(await nonce, 'nonce'); + assert.ok(await deadline, 'deadline'); +} + +async function assertVerifiedResults(driver: Driver, publicAddress: string) { + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await driver.clickElement('#signPermitVerify'); + + const verifyResult = await driver.findElement('#signPermitResult'); + const verifyResultR = await driver.findElement('#signPermitResultR'); + const verifyResultS = await driver.findElement('#signPermitResultS'); + const verifyResultV = await driver.findElement('#signPermitResultV'); + + await driver.waitForSelector({ + css: '#signPermitVerifyResult', + text: publicAddress, + }); + const verifyRecoverAddress = await driver.findElement( + '#signPermitVerifyResult', + ); + + assert.equal( + await verifyResult.getText(), + '0x0a396f89ee073214f7e055e700048abd7b4aba6ecca0352937d6a2ebb7176f2f43c63097ad7597632e34d6a801695702ba603d5872a33ee7d7562fcdb9e816ee1c', + ); + assert.equal( + await verifyResultR.getText(), + 'r: 0x0a396f89ee073214f7e055e700048abd7b4aba6ecca0352937d6a2ebb7176f2f', + ); + assert.equal( + await verifyResultS.getText(), + 's: 0x43c63097ad7597632e34d6a801695702ba603d5872a33ee7d7562fcdb9e816ee', + ); + assert.equal(await verifyResultV.getText(), 'v: 28'); + assert.equal(await verifyRecoverAddress.getText(), publicAddress); +} diff --git a/test/e2e/tests/confirmations/signatures/personal-sign.spec.ts b/test/e2e/tests/confirmations/signatures/personal-sign.spec.ts new file mode 100644 index 000000000000..175f7459d467 --- /dev/null +++ b/test/e2e/tests/confirmations/signatures/personal-sign.spec.ts @@ -0,0 +1,103 @@ +import { strict as assert } from 'assert'; +import { Suite } from 'mocha'; +import { withRedesignConfirmationFixtures } from '../helpers'; +import { + DAPP_HOST_ADDRESS, + WINDOW_TITLES, + openDapp, + switchToNotificationWindow, + unlockWallet, +} from '../../../helpers'; +import { Ganache } from '../../../seeder/ganache'; +import { Driver } from '../../../webdriver/driver'; + +describe('Confirmation Signature - Personal Sign', function (this: Suite) { + if (!process.env.ENABLE_CONFIRMATION_REDESIGN) { + return; + } + + it('initiates and confirms', async function () { + await withRedesignConfirmationFixtures( + this.test?.fullTitle(), + async ({ + driver, + ganacheServer, + }: { + driver: Driver; + ganacheServer: Ganache; + }) => { + const addresses = await ganacheServer.getAccounts(); + const publicAddress = addresses?.[0] as string; + + await unlockWallet(driver); + await openDapp(driver); + await driver.clickElement('#personalSign'); + await switchToNotificationWindow(driver); + + await assertInfoValues(driver); + + await driver.clickElement('[data-testid="confirm-footer-button"]'); + + await assertVerifiedPersonalMessage(driver, publicAddress); + }, + ); + }); + + it('initiates and rejects', async function () { + await withRedesignConfirmationFixtures( + this.test?.fullTitle(), + async ({ driver }: { driver: Driver }) => { + await unlockWallet(driver); + await openDapp(driver); + await driver.clickElement('#personalSign'); + await switchToNotificationWindow(driver); + + await driver.clickElement( + '[data-testid="confirm-footer-cancel-button"]', + ); + + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + + const rejectionResult = await driver.waitForSelector({ + css: '#personalSign', + text: 'Error: User rejected the request.', + }); + assert.ok(rejectionResult); + }, + ); + }); +}); + +async function assertInfoValues(driver: Driver) { + const origin = driver.findElement({ text: DAPP_HOST_ADDRESS }); + const message = driver.findElement({ + text: 'Example `personal_sign` message', + }); + + assert.ok(await origin); + assert.ok(await message); +} + +async function assertVerifiedPersonalMessage( + driver: Driver, + publicAddress: string, +) { + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await driver.clickElement('#personalSignVerify'); + + const verifySigUtil = await driver.findElement( + '#personalSignVerifySigUtilResult', + ); + await driver.waitForSelector({ + css: '#personalSignVerifyECRecoverResult', + text: publicAddress, + }); + const verifyECRecover = await driver.findElement( + '#personalSignVerifyECRecoverResult', + ); + + assert.equal(await verifySigUtil.getText(), publicAddress); + assert.equal(await verifyECRecover.getText(), publicAddress); +} diff --git a/test/e2e/tests/confirmations/signatures/sign-typed-data-v3.spec.ts b/test/e2e/tests/confirmations/signatures/sign-typed-data-v3.spec.ts new file mode 100644 index 000000000000..4dfdb9851b2a --- /dev/null +++ b/test/e2e/tests/confirmations/signatures/sign-typed-data-v3.spec.ts @@ -0,0 +1,122 @@ +import { strict as assert } from 'assert'; +import { Suite } from 'mocha'; +import { + scrollAndConfirmAndAssertConfirm, + withRedesignConfirmationFixtures, +} from '../helpers'; +import { + DAPP_HOST_ADDRESS, + WINDOW_TITLES, + openDapp, + switchToNotificationWindow, + unlockWallet, +} from '../../../helpers'; +import { Ganache } from '../../../seeder/ganache'; +import { Driver } from '../../../webdriver/driver'; + +describe('Confirmation Signature - Sign Typed Data V3', function (this: Suite) { + if (!process.env.ENABLE_CONFIRMATION_REDESIGN) { + return; + } + + it('initiates and confirms', async function () { + await withRedesignConfirmationFixtures( + this.test?.fullTitle(), + async ({ + driver, + ganacheServer, + }: { + driver: Driver; + ganacheServer: Ganache; + }) => { + const addresses = await ganacheServer.getAccounts(); + const publicAddress = addresses?.[0] as string; + + await unlockWallet(driver); + await openDapp(driver); + await driver.clickElement('#signTypedDataV3'); + await switchToNotificationWindow(driver); + + await assertInfoValues(driver); + await scrollAndConfirmAndAssertConfirm(driver); + await assertVerifiedResults(driver, publicAddress); + }, + ); + }); + + it('initiates and rejects', async function () { + await withRedesignConfirmationFixtures( + this.test?.fullTitle(), + async ({ driver }: { driver: Driver }) => { + await unlockWallet(driver); + await openDapp(driver); + await driver.clickElement('#signTypedDataV3'); + await switchToNotificationWindow(driver); + + await driver.clickElement( + '[data-testid="confirm-footer-cancel-button"]', + ); + + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + + const rejectionResult = await driver.waitForSelector({ + css: '#signTypedDataV3Result', + text: 'Error: User rejected the request.', + }); + assert.ok(rejectionResult); + }, + ); + }); +}); + +async function assertInfoValues(driver: Driver) { + const origin = driver.findElement({ text: DAPP_HOST_ADDRESS }); + const contractPetName = driver.findElement({ + css: '.name__value', + text: '0xCcCCc...ccccC', + }); + + const primaryType = driver.findElement({ text: 'Mail' }); + const fromName = driver.findElement({ text: 'Cow' }); + const fromAddress = driver.findElement({ + css: '.name__value', + text: '0xCD2a3...DD826', + }); + const toName = driver.findElement({ text: 'Bob' }); + const toAddress = driver.findElement({ + css: '.name__value', + text: '0xbBbBB...bBBbB', + }); + const contents = driver.findElement({ text: 'Hello, Bob!' }); + + assert.ok(await origin, 'origin'); + assert.ok(await contractPetName, 'contractPetName'); + assert.ok(await primaryType, 'primaryType'); + assert.ok(await fromName, 'fromName'); + assert.ok(await fromAddress, 'fromAddress'); + assert.ok(await toName, 'toName'); + assert.ok(await toAddress, 'toAddress'); + assert.ok(await contents, 'contents'); +} + +async function assertVerifiedResults(driver: Driver, publicAddress: string) { + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await driver.clickElement('#signTypedDataV3Verify'); + + const verifyResult = await driver.findElement('#signTypedDataV3Result'); + await driver.waitForSelector({ + css: '#signTypedDataV3VerifyResult', + text: publicAddress, + }); + const verifyRecoverAddress = await driver.findElement( + '#signTypedDataV3VerifyResult', + ); + + assert.equal( + await verifyResult.getText(), + '0x0a22f7796a2a70c8dc918e7e6eb8452c8f2999d1a1eb5ad714473d36270a40d6724472e5609948c778a07216bd082b60b6f6853d6354c731fd8ccdd3a2f4af261b', + ); + assert.equal(await verifyRecoverAddress.getText(), publicAddress); +} diff --git a/test/e2e/tests/confirmations/signatures/sign-typed-data-v4.spec.ts b/test/e2e/tests/confirmations/signatures/sign-typed-data-v4.spec.ts new file mode 100644 index 000000000000..5c5101d5e018 --- /dev/null +++ b/test/e2e/tests/confirmations/signatures/sign-typed-data-v4.spec.ts @@ -0,0 +1,124 @@ +import { strict as assert } from 'assert'; +import { Suite } from 'mocha'; +import { + scrollAndConfirmAndAssertConfirm, + withRedesignConfirmationFixtures, +} from '../helpers'; +import { + DAPP_HOST_ADDRESS, + WINDOW_TITLES, + openDapp, + switchToNotificationWindow, + unlockWallet, +} from '../../../helpers'; +import { Ganache } from '../../../seeder/ganache'; +import { Driver } from '../../../webdriver/driver'; + +describe('Confirmation Signature - Sign Typed Data V4', function (this: Suite) { + if (!process.env.ENABLE_CONFIRMATION_REDESIGN) { + return; + } + + it('initiates and confirms', async function () { + await withRedesignConfirmationFixtures( + this.test?.fullTitle(), + async ({ + driver, + ganacheServer, + }: { + driver: Driver; + ganacheServer: Ganache; + }) => { + const addresses = await ganacheServer.getAccounts(); + const publicAddress = addresses?.[0] as string; + + await unlockWallet(driver); + await openDapp(driver); + await driver.clickElement('#signTypedDataV4'); + await switchToNotificationWindow(driver); + + await assertInfoValues(driver); + await scrollAndConfirmAndAssertConfirm(driver); + await assertVerifiedResults(driver, publicAddress); + }, + ); + }); + + it('initiates and rejects', async function () { + await withRedesignConfirmationFixtures( + this.test?.fullTitle(), + async ({ driver }: { driver: Driver }) => { + await unlockWallet(driver); + await openDapp(driver); + await driver.clickElement('#signTypedDataV4'); + await switchToNotificationWindow(driver); + + await driver.clickElement( + '[data-testid="confirm-footer-cancel-button"]', + ); + + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + + const rejectionResult = await driver.waitForSelector({ + css: '#signTypedDataV4Result', + text: 'Error: User rejected the request.', + }); + assert.ok(rejectionResult); + }, + ); + }); +}); + +async function assertInfoValues(driver: Driver) { + const origin = driver.findElement({ text: DAPP_HOST_ADDRESS }); + const contractPetName = driver.findElement({ + css: '.name__value', + text: '0xCcCCc...ccccC', + }); + + const primaryType = driver.findElement({ text: 'Mail' }); + const contents = driver.findElement({ text: 'Hello, Bob!' }); + const fromName = driver.findElement({ text: 'Cow' }); + const fromAddressNum0 = driver.findElement({ + css: '.name__value', + text: '0xCD2a3...DD826', + }); + const toName = driver.findElement({ text: 'Bob' }); + const toAddressNum2 = driver.findElement({ + css: '.name__value', + text: '0xB0B0b...00000', + }); + const attachment = driver.findElement({ text: '0x' }); + + assert.ok(await origin, 'origin'); + assert.ok(await contractPetName, 'contractPetName'); + assert.ok(await primaryType, 'primaryType'); + assert.ok(await contents, 'contents'); + assert.ok(await fromName, 'fromName'); + assert.ok(await fromAddressNum0, 'fromAddressNum0'); + assert.ok(await toName, 'toName'); + assert.ok(await toAddressNum2, 'toAddressNum2'); + assert.ok(await attachment, 'attachment'); +} + +async function assertVerifiedResults(driver: Driver, publicAddress: string) { + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await driver.clickElement('#signTypedDataV4Verify'); + + const verifyResult = await driver.findElement('#signTypedDataV4Result'); + await driver.waitForSelector({ + css: '#signTypedDataV4VerifyResult', + text: publicAddress, + }); + const verifyRecoverAddress = await driver.findElement( + '#signTypedDataV4VerifyResult', + ); + + assert.equal( + await verifyResult.getText(), + '0xcd2f9c55840f5e1bcf61812e93c1932485b524ca673b36355482a4fbdf52f692684f92b4f4ab6f6c8572dacce46bd107da154be1c06939b855ecce57a1616ba71b', + ); + assert.equal(await verifyRecoverAddress.getText(), publicAddress); +} diff --git a/test/e2e/tests/confirmations/signatures/sign-typed-data.spec.ts b/test/e2e/tests/confirmations/signatures/sign-typed-data.spec.ts new file mode 100644 index 000000000000..01f807397a97 --- /dev/null +++ b/test/e2e/tests/confirmations/signatures/sign-typed-data.spec.ts @@ -0,0 +1,99 @@ +import { strict as assert } from 'assert'; +import { Suite } from 'mocha'; +import { withRedesignConfirmationFixtures } from '../helpers'; +import { + DAPP_HOST_ADDRESS, + WINDOW_TITLES, + openDapp, + switchToNotificationWindow, + unlockWallet, +} from '../../../helpers'; +import { Ganache } from '../../../seeder/ganache'; +import { Driver } from '../../../webdriver/driver'; + +describe('Confirmation Signature - Sign Typed Data', function (this: Suite) { + if (!process.env.ENABLE_CONFIRMATION_REDESIGN) { + return; + } + + it('initiates and confirms', async function () { + await withRedesignConfirmationFixtures( + this.test?.fullTitle(), + async ({ + driver, + ganacheServer, + }: { + driver: Driver; + ganacheServer: Ganache; + }) => { + const addresses = await ganacheServer.getAccounts(); + const publicAddress = addresses?.[0] as string; + + await unlockWallet(driver); + await openDapp(driver); + await driver.clickElement('#signTypedData'); + await switchToNotificationWindow(driver); + + await assertInfoValues(driver); + + await driver.clickElement('[data-testid="confirm-footer-button"]'); + + await assertVerifiedResults(driver, publicAddress); + }, + ); + }); + + it('initiates and rejects', async function () { + await withRedesignConfirmationFixtures( + this.test?.fullTitle(), + async ({ driver }: { driver: Driver }) => { + await unlockWallet(driver); + await openDapp(driver); + await driver.clickElement('#signTypedData'); + await switchToNotificationWindow(driver); + + await driver.clickElement( + '[data-testid="confirm-footer-cancel-button"]', + ); + + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + + const rejectionResult = await driver.waitForSelector({ + css: '#signTypedDataResult', + text: 'Error: User rejected the request.', + }); + assert.ok(rejectionResult); + }, + ); + }); +}); + +async function assertInfoValues(driver: Driver) { + const origin = driver.findElement({ text: DAPP_HOST_ADDRESS }); + const message = driver.findElement({ text: 'Hi, Alice!' }); + + assert.ok(await origin); + assert.ok(await message); +} + +async function assertVerifiedResults(driver: Driver, publicAddress: string) { + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await driver.clickElement('#signTypedDataVerify'); + + const result = await driver.findElement('#signTypedDataResult'); + await driver.waitForSelector({ + css: '#signTypedDataVerifyResult', + text: publicAddress, + }); + const verifyRecoverAddress = await driver.findElement( + '#signTypedDataVerifyResult', + ); + + assert.equal( + await result.getText(), + '0x32791e3c41d40dd5bbfb42e66cf80ca354b0869ae503ad61cd19ba68e11d4f0d2e42a5835b0bfd633596b6a7834ef7d36033633a2479dacfdb96bda360d51f451b', + ); + assert.equal(await verifyRecoverAddress.getText(), publicAddress); +} diff --git a/test/e2e/tests/dapp-interactions/block-explorer.spec.js b/test/e2e/tests/dapp-interactions/block-explorer.spec.js index a42b1c4ede8b..a94e0518c6d4 100644 --- a/test/e2e/tests/dapp-interactions/block-explorer.spec.js +++ b/test/e2e/tests/dapp-interactions/block-explorer.spec.js @@ -69,7 +69,9 @@ describe('Block Explorer', function () { await unlockWallet(driver); // View TST token in block explorer - await driver.clickElement('[data-testid="home__asset-tab"]'); + await driver.clickElement( + '[data-testid="account-overview__asset-tab"]', + ); const [, tst] = await driver.findElements( '[data-testid="multichain-token-list-button"]', ); @@ -116,7 +118,9 @@ describe('Block Explorer', function () { await unlockWallet(driver); // View transaction on block explorer - await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.clickElement( + '[data-testid="account-overview__activity-tab"]', + ); await driver.clickElement('[data-testid="activity-list-item-action"]'); await driver.clickElement({ text: 'View on block explorer', diff --git a/test/e2e/tests/contract-interactions.spec.js b/test/e2e/tests/dapp-interactions/contract-interactions.spec.js similarity index 85% rename from test/e2e/tests/contract-interactions.spec.js rename to test/e2e/tests/dapp-interactions/contract-interactions.spec.js index 3f87e112a21e..e7de105e0112 100644 --- a/test/e2e/tests/contract-interactions.spec.js +++ b/test/e2e/tests/dapp-interactions/contract-interactions.spec.js @@ -1,4 +1,3 @@ -const { strict: assert } = require('assert'); const { defaultGanacheOptions, withFixtures, @@ -6,10 +5,12 @@ const { unlockWallet, largeDelayMs, WINDOW_TITLES, -} = require('../helpers'); + locateAccountBalanceDOM, + clickNestedButton, +} = require('../../helpers'); -const { SMART_CONTRACTS } = require('../seeder/smart-contracts'); -const FixtureBuilder = require('../fixture-builder'); +const { SMART_CONTRACTS } = require('../../seeder/smart-contracts'); +const FixtureBuilder = require('../../fixture-builder'); describe('Deploy contract and call contract methods', function () { const smartContract = SMART_CONTRACTS.PIGGYBANK; @@ -25,7 +26,7 @@ describe('Deploy contract and call contract methods', function () { smartContract, title: this.test.fullTitle(), }, - async ({ driver, contractRegistry }) => { + async ({ driver, contractRegistry, ganacheServer }) => { const contractAddress = await contractRegistry.getContractAddress( smartContract, ); @@ -55,7 +56,7 @@ describe('Deploy contract and call contract methods', function () { await driver.switchToWindowWithTitle( WINDOW_TITLES.ExtensionInFullScreenView, ); - await driver.clickElement({ text: 'Activity', tag: 'button' }); + await clickNestedButton(driver, 'Activity'); await driver.waitForSelector( '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', ); @@ -87,10 +88,7 @@ describe('Deploy contract and call contract methods', function () { await driver.switchToWindowWithTitle( WINDOW_TITLES.ExtensionInFullScreenView, ); - const balance = await driver.findElement( - '[data-testid="eth-overview__primary-currency"]', - ); - assert.equal(await balance.getText(), '$37,399.05\nUSD'); + await locateAccountBalanceDOM(driver, ganacheServer); }, ); }); diff --git a/test/e2e/tests/dapp-interactions/dapp-interactions.spec.js b/test/e2e/tests/dapp-interactions/dapp-interactions.spec.js index 1181e5856ffd..bd2b4a6b1aef 100644 --- a/test/e2e/tests/dapp-interactions/dapp-interactions.spec.js +++ b/test/e2e/tests/dapp-interactions/dapp-interactions.spec.js @@ -3,7 +3,6 @@ const { defaultGanacheOptions, withFixtures, openDapp, - DAPP_URL, DAPP_ONE_URL, unlockWallet, WINDOW_TITLES, @@ -18,7 +17,7 @@ describe('Dapp interactions', function () { dapp: true, fixtures: new FixtureBuilder().build(), ganacheOptions: generateGanacheOptions({ - concurrent: { port: 8546, chainId: 1338 }, + concurrent: [{ port: 8546, chainId: 1338 }], }), title: this.test.fullTitle(), }, @@ -67,7 +66,7 @@ describe('Dapp interactions', function () { }); await driver.clickElement({ text: 'Next', tag: 'button' }); - await driver.clickElement({ text: 'Connect', tag: 'button' }); + await driver.clickElement({ text: 'Confirm', tag: 'button' }); await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); await driver.waitForSelector({ css: '#accounts', @@ -84,17 +83,20 @@ describe('Dapp interactions', function () { '[data-testid ="account-options-menu-button"]', ); - await driver.clickElement({ text: 'Connected sites', tag: 'div' }); + await driver.clickElement({ text: 'All Permissions', tag: 'div' }); + await driver.clickElementAndWaitToDisappear({ + text: 'Got it', + tag: 'button', + }); const connectedDapp1 = await driver.isElementPresent({ - text: DAPP_URL, - tag: 'bdi', + text: '127.0.0.1:8080', + tag: 'p', }); const connectedDapp2 = await driver.isElementPresent({ - text: DAPP_ONE_URL, - tag: 'bdi', + text: '127.0.0.1:8081', + tag: 'p', }); - assert.ok(connectedDapp1, 'Account not connected to Dapp1'); assert.ok(connectedDapp2, 'Account not connected to Dapp2'); }, diff --git a/test/e2e/tests/dapp-interactions/dapp-tx-edit.spec.js b/test/e2e/tests/dapp-interactions/dapp-tx-edit.spec.js index 94e4b0084766..df98799a462d 100644 --- a/test/e2e/tests/dapp-interactions/dapp-tx-edit.spec.js +++ b/test/e2e/tests/dapp-interactions/dapp-tx-edit.spec.js @@ -56,7 +56,7 @@ describe('Editing confirmations of dapp initiated contract interactions', functi ); }); - it('should show an edit button on a simple ETH send initiated by a dapp', async function () { + it('should NOT show an edit button on a simple ETH send initiated by a dapp', async function () { await withFixtures( { dapp: true, @@ -88,8 +88,8 @@ describe('Editing confirmations of dapp initiated contract interactions', functi ); assert.equal( editTransactionButton, - true, - `Edit transaction button should be visible on a contract interaction created by a dapp`, + false, + `Edit transaction button should not be visible on a simple send transaction created by a dapp`, ); }, ); diff --git a/test/e2e/tests/encrypt-decrypt.spec.js b/test/e2e/tests/dapp-interactions/encrypt-decrypt.spec.js similarity index 98% rename from test/e2e/tests/encrypt-decrypt.spec.js rename to test/e2e/tests/dapp-interactions/encrypt-decrypt.spec.js index e9cac127315b..2f595138d0cf 100644 --- a/test/e2e/tests/encrypt-decrypt.spec.js +++ b/test/e2e/tests/dapp-interactions/encrypt-decrypt.spec.js @@ -5,8 +5,8 @@ const { openDapp, unlockWallet, WINDOW_TITLES, -} = require('../helpers'); -const FixtureBuilder = require('../fixture-builder'); +} = require('../../helpers'); +const FixtureBuilder = require('../../fixture-builder'); async function validateEncryptionKey(driver, encryptionKey) { await driver.clickElement('#getEncryptionKeyButton'); diff --git a/test/e2e/tests/eth-subscribe.spec.js b/test/e2e/tests/dapp-interactions/eth-subscribe.spec.js similarity index 96% rename from test/e2e/tests/eth-subscribe.spec.js rename to test/e2e/tests/dapp-interactions/eth-subscribe.spec.js index bbcb4db6a6dd..8ca8ec0cc74c 100644 --- a/test/e2e/tests/eth-subscribe.spec.js +++ b/test/e2e/tests/dapp-interactions/eth-subscribe.spec.js @@ -4,8 +4,8 @@ const { openDapp, DAPP_ONE_URL, unlockWallet, -} = require('../helpers'); -const FixtureBuilder = require('../fixture-builder'); +} = require('../../helpers'); +const FixtureBuilder = require('../../fixture-builder'); describe('eth_subscribe', function () { it('only broadcasts subscription notifications on the page that registered the subscription', async function () { diff --git a/test/e2e/tests/failing-contract.spec.js b/test/e2e/tests/dapp-interactions/failing-contract.spec.js similarity index 94% rename from test/e2e/tests/failing-contract.spec.js rename to test/e2e/tests/dapp-interactions/failing-contract.spec.js index ca96f6b971f7..f27768fb7e4c 100644 --- a/test/e2e/tests/failing-contract.spec.js +++ b/test/e2e/tests/dapp-interactions/failing-contract.spec.js @@ -5,9 +5,10 @@ const { unlockWallet, WINDOW_TITLES, generateGanacheOptions, -} = require('../helpers'); -const { SMART_CONTRACTS } = require('../seeder/smart-contracts'); -const FixtureBuilder = require('../fixture-builder'); + clickNestedButton, +} = require('../../helpers'); +const { SMART_CONTRACTS } = require('../../seeder/smart-contracts'); +const FixtureBuilder = require('../../fixture-builder'); describe('Failing contract interaction ', function () { const smartContract = SMART_CONTRACTS.FAILING; @@ -60,7 +61,7 @@ describe('Failing contract interaction ', function () { await driver.clickElement({ text: 'Confirm', tag: 'button' }); await driver.waitUntilXWindowHandles(2); await driver.switchToWindow(extension); - await driver.clickElement({ text: 'Activity', tag: 'button' }); + await clickNestedButton(driver, 'Activity'); await driver.findElement({ css: '.activity-list-item .transaction-status-label', @@ -127,7 +128,7 @@ describe('Failing contract interaction on non-EIP1559 network', function () { await driver.clickElement({ text: 'Confirm', tag: 'button' }); await driver.waitUntilXWindowHandles(2); await driver.switchToWindow(extension); - await driver.clickElement({ text: 'Activity', tag: 'button' }); + await clickNestedButton(driver, 'Activity'); await driver.waitForSelector( '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', ); diff --git a/test/e2e/tests/dapp-interactions/permissions.spec.js b/test/e2e/tests/dapp-interactions/permissions.spec.js index abf5344909c7..029a0a0661bc 100644 --- a/test/e2e/tests/dapp-interactions/permissions.spec.js +++ b/test/e2e/tests/dapp-interactions/permissions.spec.js @@ -40,7 +40,7 @@ describe('Permissions', function () { tag: 'button', }); await driver.clickElement({ - text: 'Connect', + text: 'Confirm', tag: 'button', }); @@ -50,18 +50,20 @@ describe('Permissions', function () { await driver.clickElement( '[data-testid="account-options-menu-button"]', ); - await driver.clickElement('.menu-item:nth-of-type(3)'); - - await driver.findElement({ - text: 'Connected sites', - tag: 'h2', + await driver.clickElement({ + text: 'All Permissions', + tag: 'div', + }); + await driver.clickElementAndWaitToDisappear({ + text: 'Got it', + tag: 'button', }); await driver.waitForSelector({ - css: '.connected-sites-list__subject-name', text: '127.0.0.1:8080', + tag: 'p', }); const domains = await driver.findClickableElements( - '.connected-sites-list__subject-name', + '[data-testid="connection-list-item"]', ); assert.equal(domains.length, 1); diff --git a/test/e2e/tests/provider-api.spec.js b/test/e2e/tests/dapp-interactions/provider-api.spec.js similarity index 53% rename from test/e2e/tests/provider-api.spec.js rename to test/e2e/tests/dapp-interactions/provider-api.spec.js index b2cd456d5f41..80cca60afb95 100644 --- a/test/e2e/tests/provider-api.spec.js +++ b/test/e2e/tests/dapp-interactions/provider-api.spec.js @@ -5,51 +5,10 @@ const { withFixtures, openDapp, unlockWallet, -} = require('../helpers'); -const FixtureBuilder = require('../fixture-builder'); +} = require('../../helpers'); +const FixtureBuilder = require('../../fixture-builder'); describe('MetaMask', function () { - it('provider should inform dapp when switching networks', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - ganacheOptions: defaultGanacheOptions, - title: this.test.fullTitle(), - }, - async ({ driver, ganacheServer }) => { - const addresses = await ganacheServer.getAccounts(); - const publicAddress = addresses[0]; - await unlockWallet(driver); - - await openDapp(driver); - const chainIdDiv = await driver.waitForSelector({ - css: '#chainId', - text: '0x539', - }); - assert.equal(await chainIdDiv.getText(), '0x539'); - - const windowHandles = await driver.getAllWindowHandles(); - await driver.switchToWindow(windowHandles[0]); - - await driver.clickElement('[data-testid="network-display"]'); - await driver.clickElement({ text: 'Ethereum Mainnet', tag: 'p' }); - - await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); - const switchedChainIdDiv = await driver.waitForSelector({ - css: '#chainId', - text: '0x1', - }); - const accountsDiv = await driver.findElement('#accounts'); - - assert.equal(await switchedChainIdDiv.getText(), '0x1'); - assert.equal(await accountsDiv.getText(), publicAddress); - }, - ); - }); - it('should reject unsupported methods', async function () { await withFixtures( { diff --git a/test/e2e/tests/signin-with-ethereum.spec.js b/test/e2e/tests/dapp-interactions/signin-with-ethereum.spec.js similarity index 97% rename from test/e2e/tests/signin-with-ethereum.spec.js rename to test/e2e/tests/dapp-interactions/signin-with-ethereum.spec.js index 251e45023147..5c6e3bb4803c 100644 --- a/test/e2e/tests/signin-with-ethereum.spec.js +++ b/test/e2e/tests/dapp-interactions/signin-with-ethereum.spec.js @@ -6,8 +6,8 @@ const { DAPP_URL, unlockWallet, WINDOW_TITLES, -} = require('../helpers'); -const FixtureBuilder = require('../fixture-builder'); +} = require('../../helpers'); +const FixtureBuilder = require('../../fixture-builder'); describe('Sign in with ethereum', function () { it('user should be able to confirm sign in with ethereum', async function () { diff --git a/test/e2e/tests/metrics/app-installed.spec.js b/test/e2e/tests/metrics/app-installed.spec.js index 148bd09bc7d0..cb2ddde78198 100644 --- a/test/e2e/tests/metrics/app-installed.spec.js +++ b/test/e2e/tests/metrics/app-installed.spec.js @@ -5,6 +5,7 @@ const { onboardingBeginCreateNewWallet, onboardingChooseMetametricsOption, getEventPayloads, + tinyDelayMs, } = require('../../helpers'); const FixtureBuilder = require('../../fixture-builder'); @@ -49,7 +50,7 @@ describe('App Installed Events @no-mmi', function () { }, async ({ driver, mockedEndpoint: mockedEndpoints }) => { await driver.navigate(); - + await driver.delay(tinyDelayMs); await onboardingBeginCreateNewWallet(driver); await onboardingChooseMetametricsOption(driver, true); diff --git a/test/e2e/tests/metrics/dapp-viewed.spec.js b/test/e2e/tests/metrics/dapp-viewed.spec.js index e7a93f47e268..f88d7b754bf5 100644 --- a/test/e2e/tests/metrics/dapp-viewed.spec.js +++ b/test/e2e/tests/metrics/dapp-viewed.spec.js @@ -5,8 +5,9 @@ const { unlockWallet, getEventPayloads, openDapp, - waitForAccountRendered, + logInWithBalanceValidation, WINDOW_TITLES, + defaultGanacheOptions, } = require('../../helpers'); const FixtureBuilder = require('../../fixture-builder'); const { @@ -40,7 +41,6 @@ async function mockPermissionApprovedEndpoint(mockServer) { } async function createTwoAccounts(driver) { - await waitForAccountRendered(driver); await driver.clickElement('[data-testid="account-menu-icon"]'); await driver.clickElement( '[data-testid="multichain-account-menu-popover-action-button"]', @@ -64,7 +64,8 @@ const waitForDappConnected = async (driver) => { }; describe('Dapp viewed Event @no-mmi', function () { - it('is sent when navigating to dapp with no account connected', async function () { + const validFakeMetricsId = 'fake-metrics-fd20'; + it('is not sent when metametrics ID is not valid', async function () { async function mockSegment(mockServer) { return [await mockedDappViewedEndpoint(mockServer)]; } @@ -74,7 +75,7 @@ describe('Dapp viewed Event @no-mmi', function () { dapp: true, fixtures: new FixtureBuilder() .withMetaMetricsController({ - metaMetricsId: 'fake-metrics-id', + metaMetricsId: 'invalid-metrics-id', participateInMetaMetrics: true, }) .build(), @@ -82,9 +83,34 @@ describe('Dapp viewed Event @no-mmi', function () { testSpecificMock: mockSegment, }, async ({ driver, mockedEndpoint: mockedEndpoints }) => { - await driver.navigate(); await unlockWallet(driver); + await connectToDapp(driver); + const events = await getEventPayloads(driver, mockedEndpoints); + assert.equal(events.length, 0); + }, + ); + }); + + it('is sent when navigating to dapp with no account connected', async function () { + async function mockSegment(mockServer) { + return [await mockedDappViewedEndpoint(mockServer)]; + } + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withMetaMetricsController({ + metaMetricsId: validFakeMetricsId, // 1% sample rate for dapp viewed event + participateInMetaMetrics: true, + }) + .build(), + title: this.test.fullTitle(), + testSpecificMock: mockSegment, + ganacheOptions: defaultGanacheOptions, + }, + async ({ driver, mockedEndpoint: mockedEndpoints, ganacheServer }) => { + await logInWithBalanceValidation(driver, ganacheServer); await connectToDapp(driver); await waitForDappConnected(driver); const events = await getEventPayloads(driver, mockedEndpoints); @@ -110,17 +136,16 @@ describe('Dapp viewed Event @no-mmi', function () { dapp: true, fixtures: new FixtureBuilder() .withMetaMetricsController({ - metaMetricsId: 'fake-metrics-id', + metaMetricsId: validFakeMetricsId, participateInMetaMetrics: true, }) .build(), title: this.test.fullTitle(), testSpecificMock: mockSegment, + ganacheOptions: defaultGanacheOptions, }, - async ({ driver, mockedEndpoint: mockedEndpoints }) => { - await driver.navigate(); - await unlockWallet(driver); - await waitForAccountRendered(driver); + async ({ driver, mockedEndpoint: mockedEndpoints, ganacheServer }) => { + await logInWithBalanceValidation(driver, ganacheServer); await connectToDapp(driver); await waitForDappConnected(driver); // open dapp in a new page @@ -149,17 +174,16 @@ describe('Dapp viewed Event @no-mmi', function () { dapp: true, fixtures: new FixtureBuilder() .withMetaMetricsController({ - metaMetricsId: 'fake-metrics-id', + metaMetricsId: validFakeMetricsId, participateInMetaMetrics: true, }) .build(), title: this.test.fullTitle(), testSpecificMock: mockSegment, + ganacheOptions: defaultGanacheOptions, }, - async ({ driver, mockedEndpoint: mockedEndpoints }) => { - await driver.navigate(); - await unlockWallet(driver); - await waitForAccountRendered(driver); + async ({ driver, mockedEndpoint: mockedEndpoints, ganacheServer }) => { + await logInWithBalanceValidation(driver, ganacheServer); await connectToDapp(driver); await waitForDappConnected(driver); // refresh dapp @@ -193,17 +217,16 @@ describe('Dapp viewed Event @no-mmi', function () { dapp: true, fixtures: new FixtureBuilder() .withMetaMetricsController({ - metaMetricsId: 'fake-metrics-id', + metaMetricsId: validFakeMetricsId, participateInMetaMetrics: true, }) .build(), title: this.test.fullTitle(), testSpecificMock: mockSegment, + ganacheOptions: defaultGanacheOptions, }, - async ({ driver, mockedEndpoint: mockedEndpoints }) => { - await driver.navigate(); - await unlockWallet(driver); - await waitForAccountRendered(driver); + async ({ driver, mockedEndpoint: mockedEndpoints, ganacheServer }) => { + await logInWithBalanceValidation(driver, ganacheServer); await connectToDapp(driver); await waitForDappConnected(driver); // open dapp in a new page @@ -231,15 +254,16 @@ describe('Dapp viewed Event @no-mmi', function () { dapp: true, fixtures: new FixtureBuilder() .withMetaMetricsController({ - metaMetricsId: 'fake-metrics-id', + metaMetricsId: validFakeMetricsId, participateInMetaMetrics: true, }) .build(), title: this.test.fullTitle(), + ganacheOptions: defaultGanacheOptions, testSpecificMock: mockSegment, }, - async ({ driver, mockedEndpoint: mockedEndpoints }) => { - await unlockWallet(driver); + async ({ driver, mockedEndpoint: mockedEndpoints, ganacheServer }) => { + await logInWithBalanceValidation(driver, ganacheServer); // create 2nd account await createTwoAccounts(driver); // Connect to dapp with two accounts @@ -259,7 +283,7 @@ describe('Dapp viewed Event @no-mmi', function () { tag: 'button', }); await driver.clickElement({ - text: 'Connect', + text: 'Confirm', tag: 'button', }); @@ -271,4 +295,87 @@ describe('Dapp viewed Event @no-mmi', function () { }, ); }); + + it('is sent when reconnect to a dapp that has been connected before', async function () { + async function mockSegment(mockServer) { + return [ + await mockedDappViewedEndpoint(mockServer), + await mockedDappViewedEndpoint(mockServer), + ]; + } + + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withMetaMetricsController({ + metaMetricsId: validFakeMetricsId, + participateInMetaMetrics: true, + }) + .build(), + title: this.test.fullTitle(), + testSpecificMock: mockSegment, + ganacheOptions: defaultGanacheOptions, + }, + async ({ driver, mockedEndpoint: mockedEndpoints, ganacheServer }) => { + await logInWithBalanceValidation(driver, ganacheServer); + await connectToDapp(driver); + await waitForDappConnected(driver); + + // close test dapp window to avoid future confusion + const windowHandles = await driver.getAllWindowHandles(); + await driver.closeWindowHandle(windowHandles[1]); + // disconnect dapp in fullscreen view + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + await driver.clickElement( + '[data-testid ="account-options-menu-button"]', + ); + await driver.clickElement({ + text: 'All Permissions', + tag: 'div', + }); + await driver.clickElementAndWaitToDisappear({ + text: 'Got it', + tag: 'button', + }); + await driver.clickElement({ + text: '127.0.0.1:8080', + tag: 'p', + }); + await driver.clickElement( + '[data-testid ="account-list-item-menu-button"]', + ); + await driver.clickElement({ + text: 'Disconnect', + tag: 'button', + }); + await driver.clickElement('[data-testid ="disconnect-all"]'); + await driver.clickElement('button[aria-label="Back"]'); + await driver.clickElement('button[aria-label="Back"]'); + // validate dapp is not connected + await driver.clickElement( + '[data-testid ="account-options-menu-button"]', + ); + await driver.clickElement({ + text: 'All Permissions', + tag: 'div', + }); + await driver.findElement({ + text: 'Nothing to see here', + tag: 'p', + }); + // reconnect again + await connectToDapp(driver); + const events = await getEventPayloads(driver, mockedEndpoints); + assert.equal(events.length, 2); + // events are original dapp viewed, new dapp viewed when reconnected + const dappViewedEventProperties = events[1].properties; + assert.equal(dappViewedEventProperties.is_first_visit, false); + assert.equal(dappViewedEventProperties.number_of_accounts, 1); + assert.equal(dappViewedEventProperties.number_of_accounts_connected, 1); + }, + ); + }); }); diff --git a/test/e2e/tests/errors.spec.js b/test/e2e/tests/metrics/errors.spec.js similarity index 96% rename from test/e2e/tests/errors.spec.js rename to test/e2e/tests/metrics/errors.spec.js index 083e3c78e53a..d183d5842fed 100644 --- a/test/e2e/tests/errors.spec.js +++ b/test/e2e/tests/metrics/errors.spec.js @@ -1,13 +1,17 @@ const { resolve } = require('path'); const { promises: fs } = require('fs'); const { strict: assert } = require('assert'); -const { get, has, set, unset } = require('lodash'); +const { get, has, set, unset, cloneDeep } = require('lodash'); const { Browser } = require('selenium-webdriver'); const { format } = require('prettier'); const { isObject } = require('@metamask/utils'); -const { SENTRY_UI_STATE } = require('../../../app/scripts/lib/setupSentry'); -const FixtureBuilder = require('../fixture-builder'); -const { convertToHexValue, withFixtures } = require('../helpers'); +const { SENTRY_UI_STATE } = require('../../../../app/scripts/lib/setupSentry'); +const FixtureBuilder = require('../../fixture-builder'); +const { + convertToHexValue, + logInWithBalanceValidation, + withFixtures, +} = require('../../helpers'); /** * Derive a UI state field from a background state field. @@ -24,7 +28,6 @@ function backgroundToUiField(backgroundField) { } const maskedBackgroundFields = [ - 'CurrencyController.currencyRates.ETH.conversionDate', // This is a timestamp that changes each run // App metadata is masked so that we don't have to update the snapshot as // part of the release process 'AppMetadataController.currentAppVersion', @@ -35,6 +38,11 @@ const maskedBackgroundFields = [ 'AppStateController.surveyLinkLastClickedOrClosed', 'AppStateController.recoveryPhraseReminderLastShown', 'AppStateController.termsOfUseLastAgreed', + // The value in these properties may change each run + 'AppStateController.fullScreenGasPollTokens', + 'AppStateController.notificationGasPollTokens', + 'AppStateController.popupGasPollTokens', + 'CurrencyController.currencyRates.ETH.conversionDate', ]; const maskedUiFields = maskedBackgroundFields.map(backgroundToUiField); @@ -57,17 +65,18 @@ const removedUiFields = removedBackgroundFields.map(backgroundToUiField); * @param {unknown} data - The data to transform */ function transformBackgroundState(data) { + const clonedData = cloneDeep(data); for (const field of maskedBackgroundFields) { - if (has(data, field)) { - set(data, field, typeof get(data, field)); + if (has(clonedData, field)) { + set(clonedData, field, typeof get(clonedData, field)); } } for (const field of removedBackgroundFields) { - if (has(data, field)) { - unset(data, field); + if (has(clonedData, field)) { + unset(clonedData, field); } } - return data; + return clonedData; } /** @@ -644,9 +653,8 @@ describe('Sentry errors', function () { title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, }, - async ({ driver, mockedEndpoint }) => { - await driver.navigate(); - await driver.findElement('#password'); + async ({ driver, ganacheServer, mockedEndpoint }) => { + await logInWithBalanceValidation(driver, ganacheServer); // Trigger error await driver.executeScript( @@ -738,9 +746,8 @@ describe('Sentry errors', function () { title: this.test.fullTitle(), testSpecificMock: mockSentryTestError, }, - async ({ driver, mockedEndpoint }) => { - await driver.navigate(); - await driver.findElement('#password'); + async ({ driver, ganacheServer, mockedEndpoint }) => { + await logInWithBalanceValidation(driver, ganacheServer); // Trigger error await driver.executeScript('window.stateHooks.throwTestError()'); diff --git a/test/e2e/tests/metrics/permissions-approved.spec.js b/test/e2e/tests/metrics/permissions-approved.spec.js index 9db55604e081..94c82d34fabd 100644 --- a/test/e2e/tests/metrics/permissions-approved.spec.js +++ b/test/e2e/tests/metrics/permissions-approved.spec.js @@ -50,7 +50,7 @@ describe('Permissions Approved Event', function () { dapp: true, fixtures: new FixtureBuilder() .withMetaMetricsController({ - metaMetricsId: 'fake-metrics-id', + metaMetricsId: 'fake-metrics-fd20', participateInMetaMetrics: true, }) .build(), diff --git a/test/e2e/tests/metrics/signature-approved.spec.js b/test/e2e/tests/metrics/signature-approved.spec.js index 922d133fc3f3..c5b4a2ac1165 100644 --- a/test/e2e/tests/metrics/signature-approved.spec.js +++ b/test/e2e/tests/metrics/signature-approved.spec.js @@ -71,7 +71,7 @@ describe('Signature Approved Event @no-mmi', function () { await driver.clickElement('#signTypedDataV4'); await switchToNotificationWindow(driver); await validateContractDetails(driver); - await clickSignOnSignatureConfirmation(driver); + await clickSignOnSignatureConfirmation({ driver }); const events = await getEventPayloads(driver, mockedEndpoints); assert.deepStrictEqual(events[0].properties, { @@ -80,6 +80,7 @@ describe('Signature Approved Event @no-mmi', function () { category: 'inpage_provider', locale: 'en', chain_id: '0x539', + eip712_primary_type: 'Mail', environment_type: 'background', security_alert_reason: 'NotApplicable', security_alert_response: 'NotApplicable', @@ -91,6 +92,7 @@ describe('Signature Approved Event @no-mmi', function () { category: 'inpage_provider', locale: 'en', chain_id: '0x539', + eip712_primary_type: 'Mail', environment_type: 'background', security_alert_response: 'NotApplicable', }); @@ -120,7 +122,7 @@ describe('Signature Approved Event @no-mmi', function () { await driver.clickElement('#signTypedDataV3'); await switchToNotificationWindow(driver); await validateContractDetails(driver); - await clickSignOnSignatureConfirmation(driver); + await clickSignOnSignatureConfirmation({ driver }); const events = await getEventPayloads(driver, mockedEndpoints); assert.deepStrictEqual(events[0].properties, { account_type: 'MetaMask', @@ -166,7 +168,7 @@ describe('Signature Approved Event @no-mmi', function () { // creates a sign typed data signature request await driver.clickElement('#signTypedData'); await switchToNotificationWindow(driver); - await clickSignOnSignatureConfirmation(driver); + await clickSignOnSignatureConfirmation({ driver }); const events = await getEventPayloads(driver, mockedEndpoints); assert.deepStrictEqual(events[0].properties, { account_type: 'MetaMask', @@ -212,7 +214,7 @@ describe('Signature Approved Event @no-mmi', function () { // creates a sign typed data signature request await driver.clickElement('#personalSign'); await switchToNotificationWindow(driver); - await clickSignOnSignatureConfirmation(driver); + await clickSignOnSignatureConfirmation({ driver }); const events = await getEventPayloads(driver, mockedEndpoints); assert.deepStrictEqual(events[0].properties, { account_type: 'MetaMask', diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json similarity index 76% rename from test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json rename to test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json index 6b035e0a9168..534d5e4d606a 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json +++ b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json @@ -18,15 +18,16 @@ "currentAppVersion": "string", "previousAppVersion": "", "previousMigrationVersion": 0, - "currentMigrationVersion": "number" + "currentMigrationVersion": "number", + "showTokenAutodetectModalOnUpgrade": "object" }, "AppStateController": { "connectedStatusPopoverHasBeenShown": true, "defaultHomeActiveTabName": null, "browserEnvironment": { "os": "string", "browser": "string" }, - "popupGasPollTokens": [], - "notificationGasPollTokens": [], - "fullScreenGasPollTokens": [], + "popupGasPollTokens": "object", + "notificationGasPollTokens": "object", + "fullScreenGasPollTokens": "object", "recoveryPhraseReminderHasBeenShown": true, "recoveryPhraseReminderLastShown": "number", "outdatedBrowserWarningLastShown": "number", @@ -34,10 +35,12 @@ "showTestnetMessageInDropdown": true, "showBetaHeader": false, "showPermissionsTour": true, - "showProductTour": true, "showNetworkBanner": true, "showAccountBanner": true, "trezorModel": null, + "onboardingDate": "object", + "newPrivacyPolicyToastClickedOrClosed": "boolean", + "newPrivacyPolicyToastShownDate": "number", "hadAdvancedGasFeesSetPriorToMigration92_3": false, "nftsDropdownState": {}, "termsOfUseLastAgreed": "number", @@ -45,13 +48,17 @@ "usedNetworks": { "0x1": true, "0x5": true, "0x539": true }, "snapsInstallPrivacyWarningShown": true, "surveyLinkLastClickedOrClosed": "object", - "signatureSecurityAlertResponses": "object" + "signatureSecurityAlertResponses": "object", + "switchedNetworkDetails": "object", + "switchedNetworkNeverShowMessage": "boolean", + "currentExtensionPopupId": "number" }, "ApprovalController": { "pendingApprovals": "object", "pendingApprovalCount": "number", "approvalFlows": "object" }, + "AuthenticationController": { "isSignedIn": "boolean" }, "CronjobController": { "jobs": "object" }, "CurrencyController": { "currencyRates": { @@ -79,23 +86,45 @@ "gasFeeEstimatesByChainId": {}, "gasFeeEstimates": {}, "estimatedGasFeeTimeBounds": {}, - "gasEstimateType": "none" + "gasEstimateType": "none", + "nonRPCGasFeeApisDisabled": "boolean" }, "KeyringController": { - "isUnlocked": false, + "isUnlocked": true, "keyrings": "object", - "vault": "string" + "vault": "string", + "encryptionKey": "string", + "encryptionSalt": "string" }, "LoggingController": { "logs": "object" }, "MetaMetricsController": { "participateInMetaMetrics": true, "metaMetricsId": "fake-metrics-id", + "dataCollectionForMarketing": "boolean", "eventsBeforeMetricsOptIn": "object", "traits": "object", "previousUserTraits": "object", "fragments": "object", "segmentApiCalls": "object" }, + "MetamaskNotificationsController": { + "subscriptionAccountsSeen": "object", + "isMetamaskNotificationsFeatureSeen": "boolean", + "isMetamaskNotificationsEnabled": "boolean", + "isFeatureAnnouncementsEnabled": "boolean", + "metamaskNotificationsList": "object", + "metamaskNotificationsReadList": "object", + "isUpdatingMetamaskNotifications": "boolean", + "isFetchingMetamaskNotifications": "boolean", + "isUpdatingMetamaskNotificationsAccount": "object", + "isCheckingAccountsPresence": "boolean" + }, + "MultichainBalancesController": { "balances": "object" }, + "MultichainRatesController": { + "fiatCurrency": "usd", + "rates": { "btc": { "conversionDate": 0, "conversionRate": "0" } }, + "cryptocurrencies": ["btc"] + }, "NameController": { "names": "object", "nameSources": "object" }, "NetworkController": { "selectedNetworkClientId": "string", @@ -131,7 +160,7 @@ "completedOnboarding": true, "onboardingTabs": "object" }, - "PPOMController": { "storageMetadata": {}, "versionFileETag": "string" }, + "PPOMController": { "storageMetadata": {} }, "PermissionController": { "subjects": "object" }, "PermissionLogController": { "permissionHistory": "object", @@ -144,12 +173,13 @@ "dismissSeedBackUpReminder": true, "disabledRpcMethodPreferences": { "eth_sign": false }, "useMultiAccountBalanceChecker": true, + "hasDismissedOpenSeaToBlockaidBanner": false, "useSafeChainsListValidation": "boolean", "useTokenDetection": false, "useNftDetection": false, "use4ByteResolution": true, "useCurrencyRateCheck": true, - "useRequestQueue": false, + "useRequestQueue": true, "openSeaEnabled": false, "securityAlertsEnabled": "boolean", "addSnapAccountEnabled": "boolean", @@ -166,21 +196,28 @@ "showExtensionInFullSizeView": false, "showFiatInTestnets": false, "showTestNetworks": false, + "smartTransactionsOptInStatus": false, "useNativeCurrencyAsPrimaryCurrency": true, - "petnamesEnabled": true + "petnamesEnabled": true, + "showTokenAutodetectModal": "boolean" }, "ipfsGateway": "string", "isIpfsGatewayEnabled": "boolean", "useAddressBarEnsResolution": true, "ledgerTransportType": "webhid", "snapRegistryList": "object", - "transactionSecurityCheckEnabled": false, "theme": "light", "snapsAddSnapAccountModalDismissed": "boolean", - "isLineaMainnetReleased": true, "useExternalNameSources": "boolean", + "useTransactionSimulations": true, + "enableMV3TimestampSave": true, + "useExternalServices": "boolean", "selectedAddress": "string" }, + "PushPlatformNotificationsController": { "fcmToken": "string" }, + "QueuedRequestController": { + "queuedRequestCount": 0 + }, "SelectedNetworkController": { "domains": "object" }, "SignatureController": { "unapprovedMsgs": "object", @@ -240,12 +277,9 @@ "TokenListController": { "tokenList": "object", "tokensChainsCache": {}, - "preventPollingOnNetworkRestart": true - }, - "TokenRatesController": { - "contractExchangeRates": "object", - "contractExchangeRatesByChainId": "object" + "preventPollingOnNetworkRestart": false }, + "TokenRatesController": { "marketData": "object" }, "TokensController": { "tokens": "object", "ignoredTokens": "object", @@ -259,5 +293,9 @@ "transactions": "object", "lastFetchedBlockNumbers": "object" }, - "UserOperationController": { "userOperations": "object" } + "UserOperationController": { "userOperations": "object" }, + "UserStorageController": { + "isProfileSyncingEnabled": true, + "isProfileSyncingUpdateLoading": "boolean" + } } diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json similarity index 78% rename from test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json rename to test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json index 549531561501..7bcbd81bf539 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json +++ b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json @@ -3,6 +3,7 @@ "activeTab": "object", "appState": "object", "confirm": "object", + "confirmAlerts": "object", "confirmTransaction": "object", "gas": { "customData": { "price": null, "limit": null } }, "history": { "mostRecentOverviewPage": "/" }, @@ -10,15 +11,13 @@ "localeMessages": "object", "metamask": { "isInitialized": true, - "isUnlocked": false, + "isUnlocked": true, "isAccountMenuOpen": false, "isNetworkMenuOpen": false, - "identities": "object", "internalAccounts": { "accounts": "object", "selectedAccount": "string" }, "transactions": "object", "networkConfigurations": "object", "addressBook": "object", - "contractExchangeRates": "object", "confirmationExchangeRates": {}, "pendingTokens": "object", "customNonceValue": "", @@ -31,20 +30,23 @@ "showExtensionInFullSizeView": false, "showFiatInTestnets": false, "showTestNetworks": false, + "smartTransactionsOptInStatus": false, "useNativeCurrencyAsPrimaryCurrency": true, - "petnamesEnabled": true + "petnamesEnabled": true, + "showTokenAutodetectModal": "boolean" }, "firstTimeFlowType": "import", "completedOnboarding": true, "knownMethodData": "object", "use4ByteResolution": true, "participateInMetaMetrics": true, + "dataCollectionForMarketing": "boolean", "nextNonce": null, "currencyRates": { "ETH": { "conversionDate": "number", - "conversionRate": 1300, - "usdConversionRate": 1300 + "conversionRate": 1700, + "usdConversionRate": 1700 } }, "providerConfig": { @@ -59,9 +61,9 @@ "connectedStatusPopoverHasBeenShown": true, "defaultHomeActiveTabName": null, "browserEnvironment": { "os": "string", "browser": "string" }, - "popupGasPollTokens": [], - "notificationGasPollTokens": [], - "fullScreenGasPollTokens": [], + "popupGasPollTokens": "object", + "notificationGasPollTokens": "object", + "fullScreenGasPollTokens": "object", "recoveryPhraseReminderHasBeenShown": true, "recoveryPhraseReminderLastShown": "number", "outdatedBrowserWarningLastShown": "number", @@ -69,22 +71,30 @@ "showTestnetMessageInDropdown": true, "showBetaHeader": false, "showPermissionsTour": true, - "showProductTour": true, "showNetworkBanner": true, "showAccountBanner": true, "trezorModel": null, + "onboardingDate": "object", + "newPrivacyPolicyToastClickedOrClosed": "boolean", + "newPrivacyPolicyToastShownDate": "number", "hadAdvancedGasFeesSetPriorToMigration92_3": false, "nftsDropdownState": {}, "termsOfUseLastAgreed": "number", "qrHardware": {}, + "queuedRequestCount": 0, "usedNetworks": { "0x1": true, "0x5": true, "0x539": true }, "snapsInstallPrivacyWarningShown": true, "surveyLinkLastClickedOrClosed": "object", "signatureSecurityAlertResponses": "object", + "switchedNetworkDetails": "object", + "switchedNetworkNeverShowMessage": "boolean", + "currentExtensionPopupId": "number", "currentAppVersion": "string", "previousAppVersion": "", "previousMigrationVersion": 0, "currentMigrationVersion": "number", + "showTokenAutodetectModalOnUpgrade": "object", + "balances": "object", "selectedNetworkClientId": "string", "networksMetadata": { "networkConfigurationId": { @@ -98,16 +108,18 @@ "dismissSeedBackUpReminder": true, "disabledRpcMethodPreferences": { "eth_sign": false }, "useMultiAccountBalanceChecker": true, + "hasDismissedOpenSeaToBlockaidBanner": false, "useSafeChainsListValidation": true, "useTokenDetection": false, "useNftDetection": false, "useCurrencyRateCheck": true, - "useRequestQueue": false, + "useRequestQueue": true, "openSeaEnabled": false, "securityAlertsEnabled": "boolean", "addSnapAccountEnabled": "boolean", "advancedGasFee": {}, "incomingTransactionsPreferences": {}, + "identities": "object", "lostIdentities": "object", "forgottenPassword": false, "ipfsGateway": "string", @@ -115,11 +127,12 @@ "useAddressBarEnsResolution": true, "ledgerTransportType": "webhid", "snapRegistryList": "object", - "transactionSecurityCheckEnabled": false, "theme": "light", "snapsAddSnapAccountModalDismissed": "boolean", - "isLineaMainnetReleased": true, "useExternalNameSources": "boolean", + "useTransactionSimulations": true, + "enableMV3TimestampSave": true, + "useExternalServices": "boolean", "selectedAddress": "string", "metaMetricsId": "fake-metrics-id", "eventsBeforeMetricsOptIn": "object", @@ -145,9 +158,10 @@ "gasFeeEstimates": {}, "estimatedGasFeeTimeBounds": {}, "gasEstimateType": "none", + "nonRPCGasFeeApisDisabled": "boolean", "tokenList": "object", "tokensChainsCache": {}, - "preventPollingOnNetworkRestart": true, + "preventPollingOnNetworkRestart": false, "tokens": "object", "ignoredTokens": "object", "detectedTokens": "object", @@ -166,6 +180,9 @@ "logs": "object", "methodData": "object", "lastFetchedBlockNumbers": "object", + "fiatCurrency": "usd", + "rates": { "btc": { "conversionDate": 0, "conversionRate": "0" } }, + "cryptocurrencies": ["btc"], "snaps": "object", "snapStates": "object", "unencryptedSnapStates": "object", @@ -178,9 +195,23 @@ "names": "object", "nameSources": "object", "userOperations": "object", + "isSignedIn": "boolean", + "isProfileSyncingEnabled": true, + "isProfileSyncingUpdateLoading": "boolean", + "subscriptionAccountsSeen": "object", + "isMetamaskNotificationsFeatureSeen": "boolean", + "isMetamaskNotificationsEnabled": "boolean", + "isFeatureAnnouncementsEnabled": "boolean", + "metamaskNotificationsList": "object", + "metamaskNotificationsReadList": "object", + "isUpdatingMetamaskNotifications": "boolean", + "isFetchingMetamaskNotifications": "boolean", + "isUpdatingMetamaskNotificationsAccount": "object", + "isCheckingAccountsPresence": "boolean", + "fcmToken": "string", "accounts": "object", "accountsByChainId": "object", - "contractExchangeRatesByChainId": "object", + "marketData": "object", "unapprovedDecryptMsgs": "object", "unapprovedDecryptMsgCount": 0, "unapprovedEncryptionPublicKeyMsgs": "object", @@ -223,7 +254,8 @@ "pendingApprovalCount": "number", "approvalFlows": "object", "storageMetadata": {}, - "versionFileETag": "string" + "encryptionKey": "string", + "encryptionSalt": "string" }, "send": "object", "swaps": "object", diff --git a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json b/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-background-state.json similarity index 75% rename from test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json rename to test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-background-state.json index 1aeb78a50f28..2909bf1d3597 100644 --- a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json +++ b/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-background-state.json @@ -1,5 +1,15 @@ { "data": { + "AuthenticationController": { "isSignedIn": "boolean" }, + "UserStorageController": { "isProfileSyncingEnabled": true }, + "MetamaskNotificationsController": { + "subscriptionAccountsSeen": "object", + "isFeatureAnnouncementsEnabled": "boolean", + "isMetamaskNotificationsEnabled": "boolean", + "isMetamaskNotificationsFeatureSeen": "boolean", + "metamaskNotificationsList": "object", + "metamaskNotificationsReadList": "object" + }, "AccountsController": { "internalAccounts": { "selectedAccount": "string", "accounts": "object" } }, @@ -9,7 +19,9 @@ "web3ShimUsageOrigins": "object" }, "AnnouncementController": { "announcements": "object" }, - "NetworkOrderController": { "orderedNetworkList": {} }, + "NetworkOrderController": { + "orderedNetworkList": { "0": "object", "1": "object", "2": "object" } + }, "AccountOrderController": { "pinnedAccountList": {}, "hiddenAccountList": {} @@ -20,9 +32,9 @@ "connectedStatusPopoverHasBeenShown": true, "termsOfUseLastAgreed": "number", "defaultHomeActiveTabName": null, - "fullScreenGasPollTokens": [], - "notificationGasPollTokens": [], - "popupGasPollTokens": [], + "fullScreenGasPollTokens": "object", + "notificationGasPollTokens": "object", + "popupGasPollTokens": "object", "qrHardware": {}, "recoveryPhraseReminderHasBeenShown": true, "recoveryPhraseReminderLastShown": "number", @@ -34,6 +46,8 @@ "0x5": true, "0x539": true }, + "newPrivacyPolicyToastClickedOrClosed": "boolean", + "newPrivacyPolicyToastShownDate": "number", "snapsInstallPrivacyWarningShown": true }, "CurrencyController": { @@ -41,8 +55,8 @@ "currencyRates": { "ETH": { "conversionDate": "number", - "conversionRate": 1300, - "usdConversionRate": 1300 + "conversionRate": 1700, + "usdConversionRate": 1700 } } }, @@ -57,6 +71,7 @@ "fragments": "object", "metaMetricsId": "fake-metrics-id", "participateInMetaMetrics": true, + "dataCollectionForMarketing": "boolean", "traits": "object" }, "NetworkController": { @@ -85,6 +100,7 @@ "PreferencesController": { "advancedGasFee": null, "currentLocale": "en", + "useExternalServices": "boolean", "dismissSeedBackUpReminder": true, "featureFlags": {}, "forgottenPassword": false, @@ -99,8 +115,10 @@ "showExtensionInFullSizeView": false, "showFiatInTestnets": false, "showTestNetworks": false, + "smartTransactionsOptInStatus": false, "useNativeCurrencyAsPrimaryCurrency": true, - "petnamesEnabled": true + "petnamesEnabled": true, + "showTokenAutodetectModal": "boolean" }, "selectedAddress": "string", "theme": "light", @@ -111,11 +129,12 @@ "useTokenDetection": false, "useCurrencyRateCheck": true, "useMultiAccountBalanceChecker": true, - "useRequestQueue": false + "useRequestQueue": true }, - "SelectedNetworkController": { - "domains": "object" + "QueuedRequestController": { + "queuedRequestCount": 0 }, + "SelectedNetworkController": { "domains": "object" }, "SmartTransactionsController": { "smartTransactionsState": { "fees": {}, diff --git a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json b/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-ui-state.json similarity index 75% rename from test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json rename to test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-ui-state.json index 773f75a56fc3..b41e6d6333d1 100644 --- a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json +++ b/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-ui-state.json @@ -1,5 +1,15 @@ { "data": { + "AuthenticationController": { "isSignedIn": "boolean" }, + "UserStorageController": { "isProfileSyncingEnabled": true }, + "MetamaskNotificationsController": { + "subscriptionAccountsSeen": "object", + "isFeatureAnnouncementsEnabled": "boolean", + "isMetamaskNotificationsEnabled": "boolean", + "isMetamaskNotificationsFeatureSeen": "boolean", + "metamaskNotificationsList": "object", + "metamaskNotificationsReadList": "object" + }, "AccountsController": { "internalAccounts": { "selectedAccount": "string", "accounts": "object" } }, @@ -9,7 +19,9 @@ "web3ShimUsageOrigins": "object" }, "AnnouncementController": { "announcements": "object" }, - "NetworkOrderController": { "orderedNetworkList": {} }, + "NetworkOrderController": { + "orderedNetworkList": { "0": "object", "1": "object", "2": "object" } + }, "AccountOrderController": { "pinnedAccountList": {}, "hiddenAccountList": {} @@ -20,9 +32,9 @@ "connectedStatusPopoverHasBeenShown": true, "termsOfUseLastAgreed": "number", "defaultHomeActiveTabName": null, - "fullScreenGasPollTokens": [], - "notificationGasPollTokens": [], - "popupGasPollTokens": [], + "fullScreenGasPollTokens": "object", + "notificationGasPollTokens": "object", + "popupGasPollTokens": "object", "qrHardware": {}, "recoveryPhraseReminderHasBeenShown": true, "recoveryPhraseReminderLastShown": "number", @@ -34,6 +46,8 @@ "0x5": true, "0x539": true }, + "newPrivacyPolicyToastClickedOrClosed": "boolean", + "newPrivacyPolicyToastShownDate": "number", "snapsInstallPrivacyWarningShown": true }, "CurrencyController": { @@ -41,8 +55,8 @@ "currencyRates": { "ETH": { "conversionDate": "number", - "conversionRate": 1300, - "usdConversionRate": 1300 + "conversionRate": 1700, + "usdConversionRate": 1700 } } }, @@ -57,6 +71,7 @@ "fragments": "object", "metaMetricsId": "fake-metrics-id", "participateInMetaMetrics": true, + "dataCollectionForMarketing": "boolean", "traits": "object" }, "NetworkController": { @@ -85,6 +100,7 @@ "PreferencesController": { "advancedGasFee": null, "currentLocale": "en", + "useExternalServices": "boolean", "dismissSeedBackUpReminder": true, "featureFlags": {}, "forgottenPassword": false, @@ -99,8 +115,10 @@ "showExtensionInFullSizeView": false, "showFiatInTestnets": false, "showTestNetworks": false, + "smartTransactionsOptInStatus": false, "useNativeCurrencyAsPrimaryCurrency": true, - "petnamesEnabled": true + "petnamesEnabled": true, + "showTokenAutodetectModal": "boolean" }, "selectedAddress": "string", "theme": "light", @@ -111,11 +129,12 @@ "useTokenDetection": false, "useCurrencyRateCheck": true, "useMultiAccountBalanceChecker": true, - "useRequestQueue": false + "useRequestQueue": true }, - "SelectedNetworkController": { - "domains": "object" + "QueuedRequestController": { + "queuedRequestCount": 0 }, + "SelectedNetworkController": { "domains": "object" }, "SmartTransactionsController": { "smartTransactionsState": { "fees": {}, diff --git a/test/e2e/tests/metrics/swaps.spec.js b/test/e2e/tests/metrics/swaps.spec.js index 0102d2cd6d6b..6b73e3f400b7 100644 --- a/test/e2e/tests/metrics/swaps.spec.js +++ b/test/e2e/tests/metrics/swaps.spec.js @@ -29,7 +29,7 @@ const { FEATURE_FLAGS_API_MOCK_RESULT, TRADES_API_MOCK_RESULT, NETWORKS_2_API_MOCK_RESULT, -} = require('./mock-data'); +} = require('../../../data/mock-data'); const numberOfSegmentRequests = 19; @@ -43,18 +43,16 @@ async function mockSegmentAndMetaswapRequests(mockServer) { .times() .thenCallback(() => ({ statusCode: 200 })), await mockServer - .forGet('https://swap.metaswap.codefi.network/networks/1/tokens') + .forGet('https://swap.api.cx.metamask.io/networks/1/tokens') .thenCallback(() => ({ statusCode: 200, json: TOKENS_API_MOCK_RESULT })), await mockServer - .forGet('https://swap.metaswap.codefi.network/networks/1/topAssets') + .forGet('https://swap.api.cx.metamask.io/networks/1/topAssets') .thenCallback(() => ({ statusCode: 200, json: TOP_ASSETS_API_MOCK_RESULT, })), await mockServer - .forGet( - 'https://swap.metaswap.codefi.network/networks/1/aggregatorMetadata', - ) + .forGet('https://swap.api.cx.metamask.io/networks/1/aggregatorMetadata') .thenCallback(() => ({ statusCode: 200, json: AGGREGATOR_METADATA_API_MOCK_RESULT, @@ -66,25 +64,25 @@ async function mockSegmentAndMetaswapRequests(mockServer) { json: GAS_PRICE_API_MOCK_RESULT, })), await mockServer - .forGet('https://swap.metaswap.codefi.network/featureFlags') + .forGet('https://swap.api.cx.metamask.io/featureFlags') .thenCallback(() => ({ statusCode: 200, json: FEATURE_FLAGS_API_MOCK_RESULT, })), await mockServer - .forGet('https://swap.metaswap.codefi.network/networks/1/trades') + .forGet('https://swap.api.cx.metamask.io/networks/1/trades') .thenCallback(() => ({ statusCode: 200, json: TRADES_API_MOCK_RESULT, })), await mockServer - .forGet('https://swap.metaswap.codefi.network/networks/1') + .forGet('https://swap.api.cx.metamask.io/networks/1') .thenCallback(() => ({ statusCode: 200, json: NETWORKS_2_API_MOCK_RESULT, })), await mockServer - .forGet('https://token-api.metaswap.codefi.network/token/1337') + .forGet('https://token.api.cx.metamask.io/token/1337') .thenCallback(() => ({ statusCode: 200, json: {}, @@ -197,7 +195,7 @@ async function assertNavSwapButtonClickedEvent(reqs) { async function assertPrepareSwapPageLoadedEvents(reqs) { const assertionsReq1 = [ (req) => req.event === MetaMetricsEventName.PrepareSwapPageLoaded, - (req) => Object.keys(req.properties).length === 7, + (req) => Object.keys(req.properties).length === 8, (req) => req.properties?.category === MetaMetricsEventCategory.Swaps, (req) => req.properties?.chain_id === toHex(1337), @@ -228,7 +226,7 @@ async function assertPrepareSwapPageLoadedEvents(reqs) { async function assertQuotesRequestedEvents(reqs) { const assertionsReq3 = [ (req) => req.event === MetaMetricsEventName.QuotesRequested, - (req) => Object.keys(req.properties).length === 14, + (req) => Object.keys(req.properties).length === 15, (req) => req.properties?.category === MetaMetricsEventCategory.Swaps, (req) => req.properties?.chain_id === toHex(1337), @@ -266,7 +264,7 @@ async function assertQuotesRequestedEvents(reqs) { async function assertQuotesReceivedAndBestQuoteReviewedEvents(reqs) { const assertionsReq5 = [ (req) => req.event === MetaMetricsEventName.QuotesReceived, - (req) => Object.keys(req.properties).length === 18, + (req) => Object.keys(req.properties).length === 19, (req) => req.properties?.category === MetaMetricsEventCategory.Swaps, (req) => req.properties?.chain_id === toHex(1337), @@ -301,7 +299,7 @@ async function assertQuotesReceivedAndBestQuoteReviewedEvents(reqs) { const assertionsReq7 = [ (req) => req.event === MetaMetricsEventName.BestQuoteReviewed, - (req) => Object.keys(req.properties).length === 17, + (req) => Object.keys(req.properties).length === 18, (req) => req.properties?.category === MetaMetricsEventCategory.Swaps, (req) => req.properties?.chain_id === toHex(1337), @@ -348,7 +346,7 @@ async function assertQuotesReceivedAndBestQuoteReviewedEvents(reqs) { async function assertAllAvailableQuotesOpenedEvents(reqs) { const assertionsReq9 = [ (req) => req.event === MetaMetricsEventName.AllAvailableQuotesOpened, - (req) => Object.keys(req.properties).length === 18, + (req) => Object.keys(req.properties).length === 19, (req) => req.properties?.category === MetaMetricsEventCategory.Swaps, (req) => req.properties?.chain_id === toHex(1337), @@ -391,7 +389,7 @@ async function assertAllAvailableQuotesOpenedEvents(reqs) { async function assertSwapStartedEvents(reqs) { const assertionsReq11 = [ (req) => req.event === MetaMetricsEventName.SwapStarted, - (req) => Object.keys(req.properties).length === 24, + (req) => Object.keys(req.properties).length === 25, (req) => req.properties?.category === MetaMetricsEventCategory.Swaps, (req) => req.properties?.chain_id === toHex(1337), @@ -438,13 +436,11 @@ async function assertSwapStartedEvents(reqs) { async function assertSwapCompletedEvents(reqs) { const assertionsReq13 = [ (req) => req.event === MetaMetricsEventName.SwapCompleted, - (req) => Object.keys(req.properties).length === 30, - + (req) => Object.keys(req.properties).length === 31, (req) => req.properties?.category === MetaMetricsEventCategory.Swaps, (req) => req.properties?.chain_id === toHex(1337), (req) => req.properties?.environment_type === 'background', (req) => req.properties?.locale === 'en', - (req) => req.properties?.token_from === 'TESTETH', (req) => req.properties?.token_from_amount === '2', (req) => req.properties?.token_to === 'DAI', @@ -477,7 +473,6 @@ async function assertSwapCompletedEvents(reqs) { const assertionsReq14 = [ (req) => req.event === MetaMetricsEventName.SwapCompleted, (req) => Object.keys(req.properties).length === 4, - (req) => req.properties?.category === MetaMetricsEventCategory.Swaps, (req) => req.properties?.chain_id === toHex(1337), (req) => req.properties?.environment_type === 'background', @@ -493,7 +488,7 @@ async function assertSwapCompletedEvents(reqs) { async function assertExitedSwapsEvents(reqs) { const assertionsReq15 = [ (req) => req.event === MetaMetricsEventName.ExitedSwaps, - (req) => Object.keys(req.properties).length === 12, + (req) => Object.keys(req.properties).length === 13, (req) => req.properties?.category === MetaMetricsEventCategory.Swaps, (req) => req.properties?.chain_id === toHex(1337), @@ -527,7 +522,7 @@ async function assertExitedSwapsEvents(reqs) { const assertionsReq17 = [ (req) => req.event === MetaMetricsEventName.ExitedSwaps, - (req) => Object.keys(req.properties).length === 9, + (req) => Object.keys(req.properties).length === 10, (req) => req.properties?.category === MetaMetricsEventCategory.Swaps, (req) => req.properties?.chain_id === toHex(1337), diff --git a/test/e2e/tests/metrics/transaction-finalized.spec.js b/test/e2e/tests/metrics/transaction-finalized.spec.js index 5fe8518848d9..916144ba3f59 100644 --- a/test/e2e/tests/metrics/transaction-finalized.spec.js +++ b/test/e2e/tests/metrics/transaction-finalized.spec.js @@ -135,9 +135,6 @@ const eventHasZeroAddressAnonymousId = (payload) => describe('Transaction Finalized Event', function () { it('Successfully tracked when sending a transaction @no-mmi', async function () { - if (process.env.MULTICHAIN) { - return; - } await withFixtures( { fixtures: new FixtureBuilder() diff --git a/test/e2e/tests/metrics/unlock-wallet.spec.js b/test/e2e/tests/metrics/unlock-wallet.spec.js index 3961bb3a94ce..24b69c710667 100644 --- a/test/e2e/tests/metrics/unlock-wallet.spec.js +++ b/test/e2e/tests/metrics/unlock-wallet.spec.js @@ -1,8 +1,7 @@ const { strict: assert } = require('assert'); const { withFixtures, - unlockWallet, - waitForAccountRendered, + logInWithBalanceValidation, defaultGanacheOptions, getEventPayloads, } = require('../../helpers'); @@ -36,19 +35,29 @@ describe('Unlock wallet', function () { title: this.test.fullTitle(), testSpecificMock: mockSegment, }, - async ({ driver, mockedEndpoint }) => { - await unlockWallet(driver); - await waitForAccountRendered(driver); + async ({ driver, mockedEndpoint, ganacheServer }) => { + await logInWithBalanceValidation(driver, ganacheServer); const events = await getEventPayloads(driver, mockedEndpoint); - assert.equal(events.length, 3); - assertBatchValue(events[0], 'Home', '/'); - assertBatchValue(events[1], 'Unlock Page', '/unlock'); - assertBatchValue(events[2], 'Home', '/'); + const sortedEvents = sortEventsByTime(events); + await assert.equal(sortedEvents.length, 3); + assertBatchValue(sortedEvents[0], 'Home', '/'); + assertBatchValue(sortedEvents[1], 'Unlock Page', '/unlock'); + assertBatchValue(sortedEvents[2], 'Home', '/'); }, ); }); }); +function sortEventsByTime(events) { + events.sort((event1, event2) => { + const timestamp1 = new Date(event1.timestamp); + const timestamp2 = new Date(event2.timestamp); + // Compare timestamps, return -1 for earlier, 1 for later, 0 for equal + return timestamp1 - timestamp2; + }); + return events; +} + function assertBatchValue(event, assertedTitle, assertedPath) { const { title, path } = event.context.page; assert.equal(title, assertedTitle); diff --git a/test/e2e/tests/multichain/connection-page.spec.js b/test/e2e/tests/multichain/connection-page.spec.js new file mode 100644 index 000000000000..e5594de82840 --- /dev/null +++ b/test/e2e/tests/multichain/connection-page.spec.js @@ -0,0 +1,186 @@ +const { strict: assert } = require('assert'); +const { + withFixtures, + WINDOW_TITLES, + connectToDapp, + logInWithBalanceValidation, + locateAccountBalanceDOM, + defaultGanacheOptions, +} = require('../../helpers'); +const FixtureBuilder = require('../../fixture-builder'); + +const accountLabel2 = '2nd custom name'; +const accountLabel3 = '3rd custom name'; + +describe('Connections page', function () { + it('should disconnect when click on Disconnect button in connections page', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder().build(), + title: this.test.fullTitle(), + ganacheOptions: defaultGanacheOptions, + }, + async ({ driver, ganacheServer }) => { + await logInWithBalanceValidation(driver, ganacheServer); + await connectToDapp(driver); + + // It should render connected status for button if dapp is connected + const getConnectedStatus = await driver.waitForSelector({ + css: '#connectButton', + text: 'Connected', + }); + assert.ok(getConnectedStatus, 'Account is connected to Dapp'); + + // Switch to extension Tab + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + await driver.clickElement( + '[data-testid ="account-options-menu-button"]', + ); + await driver.clickElement({ text: 'All Permissions', tag: 'div' }); + await driver.clickElementAndWaitToDisappear({ + text: 'Got it', + tag: 'button', + }); + await driver.clickElement({ + text: '127.0.0.1:8080', + tag: 'p', + }); + await driver.clickElement('[data-testid ="connections-page"]'); + const connectionsPage = await driver.isElementPresent({ + text: '127.0.0.1:8080', + tag: 'span', + }); + assert.ok(connectionsPage, 'Connections Page is defined'); + await driver.clickElement( + '[data-testid ="account-list-item-menu-button"]', + ); + await driver.clickElement({ text: 'Disconnect', tag: 'button' }); + await driver.clickElement('[data-testid ="disconnect-all"]'); + await driver.clickElement('button[aria-label="Back"]'); + await driver.clickElement('button[aria-label="Back"]'); + // validate dapp is not connected + await driver.clickElement( + '[data-testid ="account-options-menu-button"]', + ); + await driver.clickElement({ text: 'All Permissions', tag: 'div' }); + const noAccountConnected = await driver.isElementPresent({ + text: 'Nothing to see here', + tag: 'p', + }); + assert.ok( + noAccountConnected, + 'Account disconected from connections page', + ); + + // Switch back to Dapp + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + + // Button should show Connect text if dapp is not connected + + const getConnectStatus = await driver.waitForSelector({ + css: '#connectButton', + text: 'Connect', + }); + + assert.ok( + getConnectStatus, + 'Account is not connected to Dapp and button has text connect', + ); + }, + ); + }); + + it('should connect more accounts when already connected to a dapp', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder().build(), + title: this.test.fullTitle(), + ganacheOptions: defaultGanacheOptions, + }, + async ({ driver, ganacheServer }) => { + await logInWithBalanceValidation(driver, ganacheServer); + await connectToDapp(driver); + + const account = await driver.findElement('#accounts'); + const accountAddress = await account.getText(); + + // Dapp should contain single connected account address + assert.strictEqual( + accountAddress, + '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', + ); + // disconnect dapp in fullscreen view + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + + // Add two new accounts with custom label + await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-add-account"]', + ); + await driver.fill('[placeholder="Account 2"]', accountLabel2); + await driver.clickElement({ text: 'Create', tag: 'button' }); + await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-add-account"]', + ); + await driver.fill('[placeholder="Account 3"]', accountLabel3); + await driver.clickElement({ text: 'Create', tag: 'button' }); + await locateAccountBalanceDOM(driver); + await driver.clickElement( + '[data-testid ="account-options-menu-button"]', + ); + await driver.clickElement({ text: 'All Permissions', tag: 'div' }); + await driver.clickElementAndWaitToDisappear({ + text: 'Got it', + tag: 'button', + }); + await driver.clickElement({ + text: '127.0.0.1:8080', + tag: 'p', + }); + + // Connect only second account and keep third account unconnected + await driver.clickElement({ + text: 'Connect more accounts', + tag: 'button', + }); + await driver.clickElement({ + text: '2nd custom name', + tag: 'button', + }); + await driver.clickElement( + '[data-testid ="connect-more-accounts-button"]', + ); + const newAccountConnected = await driver.isElementPresent({ + text: '2nd custom name', + tag: 'button', + }); + + assert.ok(newAccountConnected, 'Connected More Account Successfully'); + // Switch back to Dapp + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + // Find the span element that contains the account addresses + const accounts = await driver.findElement('#accounts'); + const accountAddresses = await accounts.getText(); + + // Dapp should contain both the connected account addresses + assert.strictEqual( + accountAddresses, + '0x09781764c08de8ca82e156bbf156a3ca217c7950,0x5cfe73b6021e818b776b421b1c4db2474086a7e1', + ); + }, + ); + }); +}); diff --git a/test/e2e/tests/multichain/permission-page.spec.js b/test/e2e/tests/multichain/permission-page.spec.js new file mode 100644 index 000000000000..5ae3f71b6046 --- /dev/null +++ b/test/e2e/tests/multichain/permission-page.spec.js @@ -0,0 +1,88 @@ +const { strict: assert } = require('assert'); +const { + withFixtures, + WINDOW_TITLES, + connectToDapp, + logInWithBalanceValidation, + defaultGanacheOptions, +} = require('../../helpers'); +const FixtureBuilder = require('../../fixture-builder'); + +describe('Permissions Page', function () { + it('should show connected site permissions when a single dapp is connected', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder().build(), + title: this.test.fullTitle(), + ganacheOptions: defaultGanacheOptions, + }, + async ({ driver, ganacheServer }) => { + await logInWithBalanceValidation(driver, ganacheServer); + await connectToDapp(driver); + + // close test dapp window to avoid future confusion + const windowHandles = await driver.getAllWindowHandles(); + await driver.closeWindowHandle(windowHandles[1]); + // disconnect dapp in fullscreen view + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + await driver.clickElement( + '[data-testid ="account-options-menu-button"]', + ); + await driver.clickElement({ text: 'All Permissions', tag: 'div' }); + await driver.clickElementAndWaitToDisappear({ + text: 'Got it', + tag: 'button', + }); + const connectedDapp = await driver.isElementPresent({ + text: '127.0.0.1:8080', + tag: 'p', + }); + assert.ok(connectedDapp, 'Account connected to Dapp1'); + }, + ); + }); + + it('should redirect users to connections page when users click on connected permission', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder().build(), + title: this.test.fullTitle(), + ganacheOptions: defaultGanacheOptions, + }, + async ({ driver, ganacheServer }) => { + await logInWithBalanceValidation(driver, ganacheServer); + await connectToDapp(driver); + + // close test dapp window to avoid future confusion + const windowHandles = await driver.getAllWindowHandles(); + await driver.closeWindowHandle(windowHandles[1]); + // disconnect dapp in fullscreen view + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + await driver.clickElement( + '[data-testid ="account-options-menu-button"]', + ); + await driver.clickElement({ text: 'All Permissions', tag: 'div' }); + await driver.clickElementAndWaitToDisappear({ + text: 'Got it', + tag: 'button', + }); + await driver.clickElement({ + text: '127.0.0.1:8080', + tag: 'p', + }); + await driver.clickElement('[data-testid ="connections-page"]'); + const connectionsPage = await driver.isElementPresent({ + text: '127.0.0.1:8080', + tag: 'span', + }); + assert.ok(connectionsPage, 'Connections Page is defined'); + }, + ); + }); +}); diff --git a/test/e2e/tests/network/add-custom-network.spec.js b/test/e2e/tests/network/add-custom-network.spec.js index 183679bc0998..0cd18c13a9bf 100644 --- a/test/e2e/tests/network/add-custom-network.spec.js +++ b/test/e2e/tests/network/add-custom-network.spec.js @@ -11,6 +11,7 @@ const { } = require('../../helpers'); const TEST_CHAIN_ID = toHex(100); +const TEST_COLLISION_CHAIN_ID = toHex(78); const MOCK_CHAINLIST_RESPONSE = [ { @@ -62,6 +63,61 @@ const MOCK_CHAINLIST_RESPONSE = [ }, ]; +const selectors = { + accountOptionsMenuButton: '[data-testid="account-options-menu-button"]', + informationSymbol: '[data-testid="info-tooltip"]', + settingsOption: { text: 'Settings', tag: 'div' }, + networkOption: { text: 'Networks', tag: 'div' }, + addNetwork: { text: 'Add a network', tag: 'button' }, + addNetworkManually: { text: 'Add a network manually', tag: 'h6' }, + generalOption: { text: 'General', tag: 'div' }, + generalTabHeader: { text: 'General', tag: 'h4' }, + ethereumNetwork: { text: 'Ethereum Mainnet', tag: 'div' }, + newUpdateNetwork: { text: 'Update Network', tag: 'div' }, + deleteButton: { text: 'Delete', tag: 'button' }, + cancelButton: { text: 'Cancel', tag: 'button' }, + saveButton: { text: 'Save', tag: 'button' }, + updatedNetworkDropDown: { tag: 'span', text: 'Update Network' }, + errorMessageInvalidUrl: { + tag: 'h6', + text: 'URLs require the appropriate HTTP/HTTPS prefix.', + }, + warningSymbol: { + tag: 'h6', + text: 'URLs require the appropriate HTTP/HTTPS prefix.', + }, + suggestedTicker: '[data-testid="network-form-ticker-suggestion"]', + tickerWarning: '[data-testid="network-form-ticker-warning"]', + tickerButton: { text: 'PETH', tag: 'button' }, + networkAdded: { text: 'Network added successfully!', tag: 'h4' }, + + networkNameInputField: '[data-testid="network-form-network-name"]', + networkNameInputFieldSetToEthereumMainnet: { + xpath: + "//input[@data-testid = 'network-form-network-name'][@value = 'Ethereum Mainnet']", + }, + rpcUrlInputField: '[data-testid="network-form-rpc-url"]', + chainIdInputField: '[data-testid="network-form-chain-id"]', + tickerInputField: '[data-testid="network-form-ticker-input"]', + explorerInputField: '[data-testid="network-form-block-explorer-url"]', + errorContainer: '.settings-tab__error', +}; + +async function navigateToAddNetwork(driver) { + await driver.clickElement(selectors.accountOptionsMenuButton); + await driver.clickElement(selectors.settingsOption); + await driver.clickElement(selectors.networkOption); + await driver.clickElement(selectors.addNetwork); + await driver.clickElement(selectors.addNetworkManually); +} + +const inputData = { + networkName: 'Collision network', + rpcUrl: 'https://responsive-rpc.test/', + chainId: '78', + ticker: 'TST', +}; + describe('Custom network', function () { const chainID = '42161'; const networkURL = 'https://arbitrum-mainnet.infura.io'; @@ -93,7 +149,7 @@ describe('Custom network', function () { symbol: "ETH", decimals: 18 }, - rpcUrls: ["https://customnetwork.com/api/customRPC"], + rpcUrls: ["https://customnetwork.test/api/customRPC"], blockExplorerUrls: [ "http://localhost:8080/api/customRPC" ] }] window.ethereum.request({ @@ -109,6 +165,22 @@ describe('Custom network', function () { windowHandles, ); + // To mitigate a race condition, we wait until the 3 callout warnings appear + await driver.waitForSelector({ + tag: 'span', + text: 'According to our record the network name may not correctly match this chain ID.', + }); + + await driver.waitForSelector({ + tag: 'span', + text: 'According to our records the submitted RPC URL value does not match a known provider for this chain ID.', + }); + + await driver.waitForSelector({ + tag: 'a', + text: 'verify the network details', + }); + await driver.clickElement({ tag: 'button', text: 'Approve', @@ -171,7 +243,7 @@ describe('Custom network', function () { symbol: "ANTANI", decimals: 18 }, - rpcUrls: ["https://customnetwork.com/api/customRPC"], + rpcUrls: ["https://customnetwork.test/api/customRPC"], blockExplorerUrls: [ "http://localhost:8080/api/customRPC" ] }] window.ethereum.request({ @@ -243,7 +315,7 @@ describe('Custom network', function () { async function mockRPCURLAndChainId(mockServer) { return [ await mockServer - .forPost('https://responsive-rpc.url/') + .forPost('https://responsive-rpc.test/') .thenCallback(() => ({ statusCode: 200, json: { @@ -278,7 +350,7 @@ describe('Custom network', function () { symbol: "ANTANI", decimals: 18 }, - rpcUrls: ["https://responsive-rpc.url/"], + rpcUrls: ["https://responsive-rpc.test/"], blockExplorerUrls: [ "http://localhost:8080/api/customRPC" ] }] window.ethereum.request({ @@ -331,7 +403,7 @@ describe('Custom network', function () { symbol: "ANTANI", decimals: 18 }, - rpcUrls: ["https://doesntexist.abc/customRPC"], + rpcUrls: ["https://doesntexist.test/customRPC"], blockExplorerUrls: [ "http://localhost:8080/api/customRPC" ] }] window.ethereum.request({ @@ -551,7 +623,7 @@ describe('Custom network', function () { async function mockRPCURLAndChainId(mockServer) { return [ await mockServer - .forPost('https://unresponsive-rpc.url/') + .forPost('https://unresponsive-rpc.test/') // 502 Error communicating with upstream server .thenCallback(() => ({ statusCode: 502 })), @@ -585,7 +657,7 @@ describe('Custom network', function () { async function mockRPCURLAndChainId(mockServer) { return [ await mockServer - .forPost('https://responsive-rpc.url/') + .forPost('https://responsive-rpc.test/') .thenCallback(() => ({ statusCode: 200, json: { @@ -621,6 +693,180 @@ describe('Custom network', function () { ); }); }); + + describe('customNetwork', function () { + it('should add mainnet network', async function () { + async function mockRPCURLAndChainId(mockServer) { + return [ + await mockServer + .forPost('https://responsive-rpc.test/') + .thenCallback(() => ({ + statusCode: 200, + json: { + id: '1694444405781', + jsonrpc: '2.0', + result: TEST_CHAIN_ID, + }, + })), + ]; + } + + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: defaultGanacheOptions, + title: this.test.fullTitle(), + testSpecificMock: mockRPCURLAndChainId, + }, + + async ({ driver }) => { + await unlockWallet(driver); + await navigateToAddNetwork(driver); + await driver.fill( + selectors.networkNameInputField, + 'Ethereum mainnet', + ); + await driver.fill( + selectors.rpcUrlInputField, + 'https://responsive-rpc.test', + ); + await driver.fill(selectors.chainIdInputField, TEST_CHAIN_ID); + await driver.fill(selectors.tickerInputField, 'XDAI'); + await driver.fill(selectors.explorerInputField, 'https://test.com'); + + const suggestedTicker = await driver.isElementPresent( + selectors.suggestedTicker, + ); + + const tickerWarning = await driver.isElementPresent( + selectors.tickerWarning, + ); + + assert.equal(suggestedTicker, false); + assert.equal(tickerWarning, false); + + driver.clickElement(selectors.tickerButton); + driver.clickElement(selectors.saveButton); + + // Validate the network was added + const networkAdded = await driver.isElementPresent( + selectors.networkAdded, + ); + assert.equal(networkAdded, true, 'Network added successfully!'); + }, + ); + }); + + it('should check symbol and show warnings', async function () { + async function mockRPCURLAndChainId(mockServer) { + return [ + await mockServer + .forPost('https://responsive-rpc.test/') + .thenCallback(() => ({ + statusCode: 200, + json: { + id: '1694444405781', + jsonrpc: '2.0', + result: TEST_CHAIN_ID, + }, + })), + ]; + } + + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: defaultGanacheOptions, + title: this.test.fullTitle(), + testSpecificMock: mockRPCURLAndChainId, + }, + + async ({ driver }) => { + await unlockWallet(driver); + await navigateToAddNetwork(driver); + await driver.fill( + selectors.networkNameInputField, + 'Ethereum mainnet', + ); + await driver.fill( + selectors.rpcUrlInputField, + 'https://responsive-rpc.test', + ); + await driver.fill(selectors.chainIdInputField, '1'); + await driver.fill(selectors.tickerInputField, 'TST'); + await driver.fill(selectors.explorerInputField, 'https://test.com'); + + const suggestedTicker = await driver.isElementPresent( + selectors.suggestedTicker, + ); + + const tickerWarning = await driver.isElementPresent( + selectors.tickerWarning, + ); + + // suggestion and warning ticker should be displayed + assert.equal(suggestedTicker, true); + assert.equal(tickerWarning, true); + }, + ); + }); + it('should add collision network', async function () { + async function mockRPCURLAndChainId(mockServer) { + return [ + await mockServer + .forPost('https://responsive-rpc.test/') + .thenCallback(() => ({ + statusCode: 200, + json: { + id: '1694444405781', + jsonrpc: '2.0', + result: TEST_COLLISION_CHAIN_ID, + }, + })), + ]; + } + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: defaultGanacheOptions, + title: this.test.fullTitle(), + testSpecificMock: mockRPCURLAndChainId, + }, + + async ({ driver }) => { + await unlockWallet(driver); + await navigateToAddNetwork(driver); + await driver.fill( + selectors.networkNameInputField, + inputData.networkName, + ); + await driver.fill(selectors.rpcUrlInputField, inputData.rpcUrl); + await driver.fill(selectors.chainIdInputField, inputData.chainId); + await driver.fill(selectors.tickerInputField, inputData.ticker); + + const suggestedTicker = await driver.isElementPresent( + selectors.suggestedTicker, + ); + + const tickerWarning = await driver.isElementPresent( + selectors.tickerWarning, + ); + + assert.equal(suggestedTicker, true); + assert.equal(tickerWarning, true); + + driver.clickElement(selectors.tickerButton); + driver.clickElement(selectors.saveButton); + + // Validate the network was added + const networkAdded = await driver.isElementPresent( + selectors.networkAdded, + ); + assert.equal(networkAdded, true, 'Network added successfully!'); + }, + ); + }); + }); }); async function checkThatSafeChainsListValidationToggleIsOn(driver) { @@ -684,7 +930,7 @@ async function failCandidateNetworkValidation(driver) { ] = await driver.findElements('input'); await networkNameInputEl.fill('cheapETH'); - await newRPCURLInputEl.fill('https://unresponsive-rpc.url'); + await newRPCURLInputEl.fill('https://unresponsive-rpc.test'); await chainIDInputEl.fill(toHex(777)); await driver.fill('[data-testid="network-form-ticker-input"]', 'cTH'); await blockExplorerURLInputEl.fill('https://block-explorer.url'); @@ -788,7 +1034,7 @@ async function candidateNetworkIsNotValidated(driver) { ] = await driver.findElements('input'); await networkNameInputEl.fill('cheapETH'); - await newRPCURLInputEl.fill('https://responsive-rpc.url/'); + await newRPCURLInputEl.fill('https://responsive-rpc.test/'); await chainIDInputEl.fill(TEST_CHAIN_ID); await driver.fill('[data-testid="network-form-ticker-input"]', 'cTH'); await blockExplorerURLInputEl.fill('https://block-explorer.url'); diff --git a/test/e2e/tests/network/chain-interactions.spec.js b/test/e2e/tests/network/chain-interactions.spec.js index b8d05a0bd86a..c03387c93155 100644 --- a/test/e2e/tests/network/chain-interactions.spec.js +++ b/test/e2e/tests/network/chain-interactions.spec.js @@ -12,7 +12,7 @@ describe('Chain Interactions', function () { const port = 8546; const chainId = 1338; const ganacheOptions = generateGanacheOptions({ - concurrent: { port, chainId }, + concurrent: [{ port, chainId }], }); it('should add the Ganache test chain and not switch the network', async function () { await withFixtures( diff --git a/test/e2e/tests/custom-rpc-history.spec.js b/test/e2e/tests/network/custom-rpc-history.spec.js similarity index 98% rename from test/e2e/tests/custom-rpc-history.spec.js rename to test/e2e/tests/network/custom-rpc-history.spec.js index ef6df367cdb6..7df8746a2e62 100644 --- a/test/e2e/tests/custom-rpc-history.spec.js +++ b/test/e2e/tests/network/custom-rpc-history.spec.js @@ -5,8 +5,8 @@ const { withFixtures, regularDelayMs, unlockWallet, -} = require('../helpers'); -const FixtureBuilder = require('../fixture-builder'); +} = require('../../helpers'); +const FixtureBuilder = require('../../fixture-builder'); describe('Custom RPC history', function () { it(`creates first custom RPC entry`, async function () { @@ -17,7 +17,7 @@ describe('Custom RPC history', function () { { fixtures: new FixtureBuilder().build(), ganacheOptions: generateGanacheOptions({ - concurrent: { port, chainId }, + concurrent: [{ port, chainId }], }), title: this.test.fullTitle(), }, diff --git a/test/e2e/tests/network/deprecated-networks.spec.js b/test/e2e/tests/network/deprecated-networks.spec.js index b1e6d2e2df5a..29587f53afff 100644 --- a/test/e2e/tests/network/deprecated-networks.spec.js +++ b/test/e2e/tests/network/deprecated-networks.spec.js @@ -35,7 +35,7 @@ describe('Deprecated networks', function () { async function mockRPCURLAndChainId(mockServer) { return [ await mockServer - .forPost('https://responsive-rpc.url/') + .forPost('https://responsive-rpc.test/') .thenCallback(() => ({ statusCode: 200, json: { @@ -70,7 +70,7 @@ describe('Deprecated networks', function () { symbol: "ETH", decimals: 18 }, - rpcUrls: ["https://responsive-rpc.url/"], + rpcUrls: ["https://responsive-rpc.test/"], blockExplorerUrls: [ "http://localhost:8080/api/customRPC" ] }] window.ethereum.request({ @@ -121,7 +121,7 @@ describe('Deprecated networks', function () { async function mockRPCURLAndChainId(mockServer) { return [ await mockServer - .forPost('https://responsive-rpc.url/') + .forPost('https://responsive-rpc.test/') .thenCallback(() => ({ statusCode: 200, json: { @@ -156,7 +156,7 @@ describe('Deprecated networks', function () { symbol: "ETH", decimals: 18 }, - rpcUrls: ["https://responsive-rpc.url/"], + rpcUrls: ["https://responsive-rpc.test/"], blockExplorerUrls: [ "http://localhost:8080/api/customRPC" ] }] window.ethereum.request({ @@ -201,4 +201,89 @@ describe('Deprecated networks', function () { }, ); }); + + it('Should show deprecation warning when switching to Polygon mumbai', async function () { + const TEST_CHAIN_ID = CHAIN_IDS.POLYGON_TESTNET; + async function mockRPCURLAndChainId(mockServer) { + return [ + await mockServer + .forPost('https://responsive-rpc.test/') + .thenCallback(() => ({ + statusCode: 200, + json: { + id: '1694444405781', + jsonrpc: '2.0', + result: TEST_CHAIN_ID, + }, + })), + ]; + } + + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .withPreferencesController({ useSafeChainsListValidation: false }) + .build(), + title: this.test.fullTitle(), + testSpecificMock: mockRPCURLAndChainId, + }, + async ({ driver }) => { + await unlockWallet(driver); + + await openDapp(driver); + await driver.executeScript(` + var params = [{ + chainId: "${TEST_CHAIN_ID}", + chainName: "Polygon Mumbai", + nativeCurrency: { + name: "", + symbol: "MATIC", + decimals: 18 + }, + rpcUrls: ["https://responsive-rpc.test/"], + blockExplorerUrls: [ "http://localhost:8080/api/customRPC" ] + }] + window.ethereum.request({ + method: 'wallet_addEthereumChain', + params + }) + `); + await driver.waitUntilXWindowHandles(3); + const windowHandles = await driver.getAllWindowHandles(); + const [extension] = windowHandles; + + await driver.switchToWindowWithTitle( + WINDOW_TITLES.Dialog, + windowHandles, + ); + + await driver.clickElement({ + tag: 'button', + text: 'Approve', + }); + + const switchNetworkBtn = await driver.findElement({ + tag: 'button', + text: 'Switch network', + }); + + await switchNetworkBtn.click(); + + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindow(extension); + const deprecationWarningText = 'This network is deprecated'; + const isDeprecationWarningDisplayed = await driver.isElementPresent({ + text: deprecationWarningText, + }); + + assert.equal( + isDeprecationWarningDisplayed, + true, + 'Goerli deprecation warning is not displayed', + ); + }, + ); + }); }); diff --git a/test/e2e/tests/network/network-error.spec.js b/test/e2e/tests/network/network-error.spec.js index 176f24005066..02514f19718c 100644 --- a/test/e2e/tests/network/network-error.spec.js +++ b/test/e2e/tests/network/network-error.spec.js @@ -48,9 +48,6 @@ describe('Gas API fallback', function () { } it('network error message is displayed if network is congested', async function () { - if (process.env.MULTICHAIN) { - return; - } await withFixtures( { fixtures: new FixtureBuilder().build(), @@ -67,16 +64,14 @@ describe('Gas API fallback', function () { '0x2f318C334780961FB129D2a6c30D0763d9a5C970', ); - const inputAmount = await driver.findElement('.unit-input__input'); + const inputAmount = await driver.findElement('input[placeholder="0"]'); await inputAmount.fill('1'); - await driver.clickElement({ text: 'Next', tag: 'button' }); + await driver.clickElement({ text: 'Continue', tag: 'button' }); - await driver.findElement('.transaction-alerts'); - - const error = await driver.isElementPresent({ - text: 'Network is busy. Gas prices are high and estimates are less accurate.', - }); + const error = await driver.isElementPresent( + '[data-testid="network-busy-tooltip"]', + ); assert.equal(error, true, 'Network error is present'); }, diff --git a/test/e2e/tests/network/switch-custom-network.spec.js b/test/e2e/tests/network/switch-custom-network.spec.js index 68c474d81f9e..694a8f309f01 100644 --- a/test/e2e/tests/network/switch-custom-network.spec.js +++ b/test/e2e/tests/network/switch-custom-network.spec.js @@ -17,11 +17,13 @@ describe('Switch ethereum chain', function () { .withPermissionControllerConnectedToTestDapp() .build(), ganacheOptions: generateGanacheOptions({ - concurrent: { - port: 8546, - chainId: 1338, - ganacheOptions2: {}, - }, + concurrent: [ + { + port: 8546, + chainId: 1338, + ganacheOptions2: {}, + }, + ], }), title: this.test.fullTitle(), }, diff --git a/test/e2e/tests/network/update-network.spec.ts b/test/e2e/tests/network/update-network.spec.ts index b21993683e2e..1c09b88a621d 100644 --- a/test/e2e/tests/network/update-network.spec.ts +++ b/test/e2e/tests/network/update-network.spec.ts @@ -38,7 +38,8 @@ const selectors = { const inputData = { networkName: 'Update Network', rpcUrl: 'test', - chainId: '0x539', + chainId_part1: '0x53', + chainId_part2: '9', }; async function navigateToEditNetwork(driver: Driver) { @@ -63,7 +64,14 @@ describe('Update Network:', function (this: Suite) { selectors.networkNameInputField, inputData.networkName, ); - await driver.fill(selectors.chainIdInputField, inputData.chainId); + + // We fill in the chain ID in two steps, allowing the error message time to disappear once the field is correctly completed. + await driver.fill(selectors.chainIdInputField, inputData.chainId_part1); + const chainIdInputField = await driver.findElement( + selectors.chainIdInputField, + ); + await chainIdInputField.sendKeys(inputData.chainId_part2); + await driver.clickElement(selectors.saveButton); // Validate the network name is updated diff --git a/test/e2e/tests/notifications/mocks.ts b/test/e2e/tests/notifications/mocks.ts new file mode 100644 index 000000000000..cb14382f8763 --- /dev/null +++ b/test/e2e/tests/notifications/mocks.ts @@ -0,0 +1,83 @@ +import { Mockttp, RequestRuleBuilder } from 'mockttp'; +import { + getMockAuthNonceResponse, + getMockAuthLoginResponse, + getMockAuthAccessTokenResponse, +} from '../../../../app/scripts/controllers/authentication/mocks/mockResponses'; +import { + getMockUserStorageGetResponse, + getMockUserStoragePutResponse, +} from '../../../../app/scripts/controllers/user-storage/mocks/mockResponses'; +import { + getMockFeatureAnnouncementResponse, + getMockBatchCreateTriggersResponse, + getMockBatchDeleteTriggersResponse, + getMockListNotificationsResponse, + getMockMarkNotificationsAsReadResponse, +} from '../../../../app/scripts/controllers/metamask-notifications/mocks/mockResponses'; +import { + getMockRetrievePushNotificationLinksResponse, + getMockUpdatePushNotificationLinksResponse, + getMockCreateFCMRegistrationTokenResponse, + getMockDeleteFCMRegistrationTokenResponse, +} from '../../../../app/scripts/controllers/push-platform-notifications/mocks/mockResponse'; + +type MockResponse = { + url: string | RegExp; + requestMethod: 'GET' | 'POST' | 'PUT' | 'DELETE'; + response: unknown; +}; + +/** + * E2E mock setup for notification APIs (Auth, Storage, Notifications, Push Notifications) + * + * @param server - server obj used to mock our endpoints + */ +export function mockNotificationServices(server: Mockttp) { + // Auth + mockAPICall(server, getMockAuthNonceResponse()); + mockAPICall(server, getMockAuthLoginResponse()); + mockAPICall(server, getMockAuthAccessTokenResponse()); + + // Storage + mockAPICall(server, getMockUserStorageGetResponse()); + mockAPICall(server, getMockUserStoragePutResponse()); + + // Notifications + mockAPICall(server, getMockFeatureAnnouncementResponse()); + mockAPICall(server, getMockBatchCreateTriggersResponse()); + mockAPICall(server, getMockBatchDeleteTriggersResponse()); + mockAPICall(server, getMockListNotificationsResponse()); + mockAPICall(server, getMockMarkNotificationsAsReadResponse()); + + // Push Notifications + mockAPICall(server, getMockRetrievePushNotificationLinksResponse()); + mockAPICall(server, getMockUpdatePushNotificationLinksResponse()); + mockAPICall(server, getMockCreateFCMRegistrationTokenResponse()); + mockAPICall(server, getMockDeleteFCMRegistrationTokenResponse()); +} + +function mockAPICall(server: Mockttp, response: MockResponse) { + let requestRuleBuilder: RequestRuleBuilder | undefined; + + if (response.requestMethod === 'GET') { + requestRuleBuilder = server.forGet(response.url); + } + + if (response.requestMethod === 'POST') { + requestRuleBuilder = server.forPost(response.url); + } + + if (response.requestMethod === 'PUT') { + requestRuleBuilder = server.forPut(response.url); + } + + if (response.requestMethod === 'DELETE') { + requestRuleBuilder = server.forDelete(response.url); + } + + requestRuleBuilder?.thenCallback(() => ({ + statusCode: 200, + json: response.response, + })); +} diff --git a/test/e2e/tests/onboarding/onboarding.spec.js b/test/e2e/tests/onboarding/onboarding.spec.js index bcad233470a9..de0939ac2282 100644 --- a/test/e2e/tests/onboarding/onboarding.spec.js +++ b/test/e2e/tests/onboarding/onboarding.spec.js @@ -12,8 +12,18 @@ const { locateAccountBalanceDOM, defaultGanacheOptions, WALLET_PASSWORD, + onboardingBeginCreateNewWallet, + onboardingChooseMetametricsOption, + onboardingCreatePassword, + onboardingRevealAndConfirmSRP, + onboardingCompleteWalletCreation, + regularDelayMs, + unlockWallet, } = require('../../helpers'); const FixtureBuilder = require('../../fixture-builder'); +const { + FirstTimeFlowType, +} = require('../../../../shared/constants/onboarding'); describe('MetaMask onboarding @no-mmi', function () { const wrongSeedPhrase = @@ -252,7 +262,7 @@ describe('MetaMask onboarding @no-mmi', function () { fixtures: new FixtureBuilder({ onboarding: true }).build(), ganacheOptions: { ...defaultGanacheOptions, - concurrent: { port, chainId, ganacheOptions2 }, + concurrent: [{ port, chainId, ganacheOptions2 }], }, title: this.test.fullTitle(), }, @@ -297,7 +307,356 @@ describe('MetaMask onboarding @no-mmi', function () { text: networkName, }); - await locateAccountBalanceDOM(driver, secondaryGanacheServer); + await locateAccountBalanceDOM(driver, secondaryGanacheServer[0]); + }, + ); + }); + + it('User can turn off basic functionality in advanced configurations', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + ganacheOptions: defaultGanacheOptions, + title: this.test.fullTitle(), + }, + async ({ driver }) => { + await driver.navigate(); + await importSRPOnboardingFlow( + driver, + TEST_SEED_PHRASE, + WALLET_PASSWORD, + ); + + await driver.clickElement({ text: 'Advanced configuration', tag: 'a' }); + await driver.clickElement( + '[data-testid="basic-functionality-toggle"] .toggle-button', + ); + await driver.clickElement('[id="basic-configuration-checkbox"]'); + await driver.clickElement({ text: 'Turn off', tag: 'button' }); + await driver.clickElement({ text: 'Done', tag: 'button' }); + // Check that the 'basic functionality is off' banner is displayed on the home screen after onboarding completion + await driver.waitForSelector({ + text: 'Basic functionality is off', + css: '.mm-banner-alert', + }); + }, + ); + }); + + it("doesn't make any network requests to infura before onboarding is completed", async function () { + async function mockInfura(mockServer) { + const infuraUrl = + 'https://mainnet.infura.io/v3/00000000000000000000000000000000'; + const sampleAddress = '1111111111111111111111111111111111111111'; + + return [ + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'eth_blockNumber' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: '1111111111111111', + result: '0x1', + }, + }; + }), + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'eth_getBalance' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: '1111111111111111', + result: '0x1', + }, + }; + }), + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'eth_getBlockByNumber' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: '1111111111111111', + result: {}, + }, + }; + }), + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'eth_call' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: '1111111111111111', + result: `0x000000000000000000000000${sampleAddress}`, + }, + }; + }), + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'net_version' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { id: 8262367391254633, jsonrpc: '2.0', result: '1337' }, + }; + }), + ]; + } + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }) + .withNetworkControllerOnMainnet() + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test.fullTitle(), + testSpecificMock: mockInfura, + }, + async ({ driver, mockedEndpoint: mockedEndpoints }) => { + const password = 'password'; + + await driver.navigate(); + + await onboardingBeginCreateNewWallet(driver); + await onboardingChooseMetametricsOption(driver, false); + await onboardingCreatePassword(driver, password); + await onboardingRevealAndConfirmSRP(driver); + await onboardingCompleteWalletCreation(driver); + + // pin extension walkthrough screen + await driver.clickElement('[data-testid="pin-extension-next"]'); + + await driver.delay(regularDelayMs); + + for (let i = 0; i < mockedEndpoints.length; i += 1) { + const mockedEndpoint = await mockedEndpoints[i]; + const isPending = await mockedEndpoint.isPending(); + assert.equal( + isPending, + true, + `${mockedEndpoints[i]} mock should still be pending before onboarding`, + ); + const requests = await mockedEndpoint.getSeenRequests(); + + assert.equal( + requests.length, + 0, + `${mockedEndpoints[i]} should make no requests before onboarding`, + ); + } + + await driver.clickElement('[data-testid="pin-extension-done"]'); + // requests happen here! + + for (let i = 0; i < mockedEndpoints.length; i += 1) { + const mockedEndpoint = await mockedEndpoints[i]; + + await driver.wait(async () => { + const isPending = await mockedEndpoint.isPending(); + return isPending === false; + }, driver.timeout); + + const requests = await mockedEndpoint.getSeenRequests(); + + assert.equal( + requests.length > 0, + true, + `${mockedEndpoints[i]} should make requests after onboarding`, + ); + } + }, + ); + }); + + it("doesn't make any network requests to infura before onboarding by import is completed", async function () { + async function mockInfura(mockServer) { + const infuraUrl = + 'https://mainnet.infura.io/v3/00000000000000000000000000000000'; + const sampleAddress = '1111111111111111111111111111111111111111'; + + return [ + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'eth_blockNumber' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: '1111111111111111', + result: '0x1', + }, + }; + }), + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'eth_getBalance' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: '1111111111111111', + result: '0x1', + }, + }; + }), + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'eth_getBlockByNumber' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: '1111111111111111', + result: {}, + }, + }; + }), + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'eth_call' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: '1111111111111111', + result: `0x000000000000000000000000${sampleAddress}`, + }, + }; + }), + await mockServer + .forPost(infuraUrl) + .withJsonBodyIncluding({ method: 'net_version' }) + .thenCallback(() => { + return { + statusCode: 200, + json: { id: 8262367391254633, jsonrpc: '2.0', result: '1337' }, + }; + }), + ]; + } + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }) + .withNetworkControllerOnMainnet() + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test.fullTitle(), + testSpecificMock: mockInfura, + }, + async ({ driver, mockedEndpoint: mockedEndpoints }) => { + const password = 'password'; + + await driver.navigate(); + + await importSRPOnboardingFlow(driver, TEST_SEED_PHRASE, password); + + await driver.delay(regularDelayMs); + + for (let i = 0; i < mockedEndpoints.length; i += 1) { + const mockedEndpoint = await mockedEndpoints[i]; + const requests = await mockedEndpoint.getSeenRequests(); + + assert.equal( + requests.length, + 0, + `${mockedEndpoints[i]} should make no requests before onboarding`, + ); + } + + // complete + await driver.clickElement('[data-testid="onboarding-complete-done"]'); + + // pin extension + await driver.clickElement('[data-testid="pin-extension-next"]'); + await driver.clickElement('[data-testid="pin-extension-done"]'); + + // pin extension walkthrough screen + await driver.findElement('[data-testid="account-menu-icon"]'); + // requests happen here! + + for (let i = 0; i < mockedEndpoints.length; i += 1) { + const mockedEndpoint = await mockedEndpoints[i]; + + await driver.wait(async () => { + const isPending = await mockedEndpoint.isPending(); + return isPending === false; + }, driver.timeout); + + const requests = await mockedEndpoint.getSeenRequests(); + + assert.equal( + requests.length > 0, + true, + `${mockedEndpoints[i]} should make requests after onboarding`, + ); + } + }, + ); + }); + + it('Provides an onboarding path for a user who has restored their account from state persistence failure', async function () { + // We don't use onboarding:true here because we want there to be a vault, + // simulating what will happen when a user eventually restores their vault + // during a state persistence failure. Instead, we set the + // firstTimeFlowType to 'restore' and completedOnboarding to false. as well + // as some other first time state options to get us into an onboarding + // state similar to a new state tree. + await withFixtures( + { + fixtures: new FixtureBuilder() + .withOnboardingController({ + completedOnboarding: false, + firstTimeFlowType: FirstTimeFlowType.restore, + seedPhraseBackedUp: null, + }) + .withMetaMetricsController({ + participateInMetaMetrics: null, + metaMetricsId: null, + }) + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test.fullTitle(), + }, + async ({ driver }) => { + await unlockWallet(driver); + + // First screen we should be on is MetaMetrics + assert.equal( + await driver.isElementPresent({ + text: 'Help us improve MetaMask', + tag: 'h2', + }), + true, + 'First screen should be MetaMetrics', + ); + + // select no thanks + await driver.clickElement('[data-testid="metametrics-no-thanks"]'); + + // Next should be Secure your wallet screen + assert.equal( + await driver.isElementPresent({ + text: 'Secure your wallet', + tag: 'h2', + }), + true, + ); }, ); }); diff --git a/test/e2e/tests/petnames/petnames-signatures.spec.js b/test/e2e/tests/petnames/petnames-signatures.spec.js index a9c3c91b1c47..ecc972ca9f6b 100644 --- a/test/e2e/tests/petnames/petnames-signatures.spec.js +++ b/test/e2e/tests/petnames/petnames-signatures.spec.js @@ -71,7 +71,10 @@ async function showThirdPartyDetails(driver) { } async function closeThirdPartyDetails(driver) { - await driver.clickElement({ text: 'Got it', tag: 'button' }); + await driver.clickElementAndWaitToDisappear({ + text: 'Got it', + tag: 'button', + }); } async function expectProposedNames(driver, value, options) { diff --git a/test/e2e/tests/petnames/petnames-transactions.spec.js b/test/e2e/tests/petnames/petnames-transactions.spec.js index f5cdb35838bd..ed8115da4a0c 100644 --- a/test/e2e/tests/petnames/petnames-transactions.spec.js +++ b/test/e2e/tests/petnames/petnames-transactions.spec.js @@ -26,8 +26,8 @@ async function createWalletSendTransaction(driver, recipientAddress) { recipientAddress, ); - await driver.findClickableElement({ text: 'Next', tag: 'button' }); - await driver.clickElement({ text: 'Next', tag: 'button' }); + await driver.findClickableElement({ text: 'Continue', tag: 'button' }); + await driver.clickElement({ text: 'Continue', tag: 'button' }); } const ADDRESS_MOCK = '0x0c54fccd2e384b4bb6f2e405bf5cbc15a017aafb'; @@ -79,10 +79,6 @@ describe('Petnames - Transactions', function () { }); it('can save petnames for addresses in wallet send transactions', async function () { - // TODO: Update Test when Multichain Send Flow is added. - if (process.env.MULTICHAIN) { - return; - } await withFixtures( { fixtures: new FixtureBuilder() diff --git a/test/e2e/mock-page-with-disallowed-iframe/index.html b/test/e2e/tests/phishing-controller/mock-page-with-disallowed-iframe/index.html similarity index 94% rename from test/e2e/mock-page-with-disallowed-iframe/index.html rename to test/e2e/tests/phishing-controller/mock-page-with-disallowed-iframe/index.html index ffadeeefa819..943fc6ccc48f 100644 --- a/test/e2e/mock-page-with-disallowed-iframe/index.html +++ b/test/e2e/tests/phishing-controller/mock-page-with-disallowed-iframe/index.html @@ -3,7 +3,7 @@ Mock E2E Phishing Page -